diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy index d90dc30fedf..edb6892eaf6 100644 --- a/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy +++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy @@ -51,7 +51,7 @@ import com.netgrif.application.engine.objects.workflow.service.InitValueExpressi import com.netgrif.application.engine.pdf.generator.config.PdfResource import com.netgrif.application.engine.pdf.generator.service.interfaces.IPdfGenerator import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService -import com.netgrif.application.engine.petrinet.service.interfaces.IUriService +import com.netgrif.application.engine.plugin.meta.PluginHolder import com.netgrif.application.engine.startup.ImportHelper import com.netgrif.application.engine.startup.runner.DefaultFiltersRunner import com.netgrif.application.engine.startup.runner.FilterRunner @@ -179,9 +179,6 @@ class ActionDelegate { @Autowired ExportConfiguration exportConfiguration - @Autowired - IUriService uriService - @Autowired IImpersonationService impersonationService @@ -195,6 +192,8 @@ class ActionDelegate { ModuleHolder NaeModule + PluginHolder Plugin + /** * Reference of case and task in which current action is taking place. */ @@ -217,6 +216,7 @@ class ActionDelegate { this.outcomes = new ArrayList<>() this.Frontend = new FrontendActionOutcome(this.useCase, this.task, this.outcomes) this.NaeModule = new ModuleHolder() + this.Plugin = new PluginHolder() } def initFieldsMap(Map fieldIds) { @@ -1468,18 +1468,6 @@ class ActionDelegate { return this.dataService.getFile(useCase, task, field, forPreview) } - def getUri(String uri) { - return uriService.findByUri(uri) - } - - def createUri(String uri, UriContentType type) { - return uriService.getOrCreate(uri, type) - } - - def moveUri(String uri, String dest) { - return uriService.move(uri, dest) - } - /** * Action API case search function using Elasticsearch database * @param requests the CaseSearchRequest list @@ -1702,12 +1690,6 @@ class ActionDelegate { def icon = cl() as String filter.setIcon(icon) workflowService.save(filter) - }, - uri : { cl -> - filter = workflowService.findOne(filter.stringId) - def uri = cl() as String - filter.setUriNodeId(uriService.findByUri(uri).stringId) - workflowService.save(filter) }] } @@ -1894,27 +1876,27 @@ class ActionDelegate { */ def changeMenuItem(Case item) { [allowedRoles : { cl -> - updateMenuItemRoles(item, cl as Closure, MenuItemConstants.PREFERENCE_ITEM_FIELD_ALLOWED_ROLES.attributeId) + updateMenuItemRoles(item, cl as Closure, MenuItemConstants.PREFERENCE_ITEM_FIELD_ALLOWED_ROLES.value) }, bannedRoles : { cl -> - updateMenuItemRoles(item, cl as Closure, MenuItemConstants.PREFERENCE_ITEM_FIELD_BANNED_ROLES.attributeId) + updateMenuItemRoles(item, cl as Closure, MenuItemConstants.PREFERENCE_ITEM_FIELD_BANNED_ROLES.value) }, caseDefaultHeaders : { cl -> String defaultHeaders = cl() as String - setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.attributeId, item, [ - (MenuItemConstants.PREFERENCE_ITEM_FIELD_CASE_DEFAULT_HEADERS.attributeId): ["type": "text", "value": defaultHeaders] + setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.value, item, [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_CASE_DEFAULT_HEADERS.value): ["type": "text", "value": defaultHeaders] ]) }, taskDefaultHeaders : { cl -> String defaultHeaders = cl() as String - setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.attributeId, item, [ - (MenuItemConstants.PREFERENCE_ITEM_FIELD_TASK_DEFAULT_HEADERS.attributeId): ["type": "text", "value": defaultHeaders] + setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.value, item, [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_TASK_DEFAULT_HEADERS.value): ["type": "text", "value": defaultHeaders] ]) }, filter : { cl -> def filter = cl() as Case setData("change_filter", item, [ - (MenuItemConstants.PREFERENCE_ITEM_FIELD_NEW_FILTER_ID.attributeId): ["type": "text", "value": filter.stringId] + (MenuItemConstants.PREFERENCE_ITEM_FIELD_NEW_FILTER_ID.value): ["type": "text", "value": filter.stringId] ]) }, uri : { cl -> @@ -1928,38 +1910,38 @@ class ActionDelegate { title : { cl -> def value = cl() I18nString newName = (value instanceof I18nString) ? value : new I18nString(value as String) - setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.attributeId, item, [ - (MenuItemConstants.PREFERENCE_ITEM_FIELD_MENU_NAME.attributeId): ["type": "i18n", "value": newName] + setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.value, item, [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_MENU_NAME.value): ["type": "i18n", "value": newName] ]) }, menuIcon : { cl -> def value = cl() - setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.attributeId, item, [ - (MenuItemConstants.PREFERENCE_ITEM_FIELD_MENU_ICON.attributeId): ["type": "text", "value": value] + setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.value, item, [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_MENU_ICON.value): ["type": "text", "value": value] ]) }, tabIcon : { cl -> def value = cl() - setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.attributeId, item, [ - (MenuItemConstants.PREFERENCE_ITEM_FIELD_TAB_ICON.attributeId): ["type": "text", "value": value] + setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.value, item, [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_TAB_ICON.value): ["type": "text", "value": value] ]) }, requireTitleInCreation: { cl -> def value = cl() - setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.attributeId, item, [ - (MenuItemConstants.PREFERENCE_ITEM_FIELD_REQUIRE_TITLE_IN_CREATION.attributeId): ["type": "boolean", "value": value] + setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.value, item, [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_REQUIRE_TITLE_IN_CREATION.value): ["type": "boolean", "value": value] ]) }, useCustomView : { cl -> def value = cl() - setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.attributeId, item, [ - (MenuItemConstants.PREFERENCE_ITEM_FIELD_USE_CUSTOM_VIEW.attributeId): ["type": "boolean", "value": value] + setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.value, item, [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_USE_CUSTOM_VIEW.value): ["type": "boolean", "value": value] ]) }, customViewSelector : { cl -> def value = cl() - setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.attributeId, item, [ - (MenuItemConstants.PREFERENCE_ITEM_FIELD_CUSTOM_VIEW_SELECTOR.attributeId): ["type": "text", "value": value] + setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.value, item, [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_CUSTOM_VIEW_SELECTOR.value): ["type": "text", "value": value] ]) }] @@ -2108,20 +2090,18 @@ class ActionDelegate { throw new IllegalArgumentException("Menu item identifier $sanitizedIdentifier is not unique!") } - Case parentItemCase = getOrCreateFolderItem(body.uri) + Case parentItemCase = getOrCreateFolderItem(body.path) I18nString newName = body.menuName ?: (body.filter?.dataSet[FILTER_FIELD_I18N_FILTER_NAME].value as I18nString) Case menuItemCase = createCase(FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER, newName?.defaultValue) - menuItemCase.setUriNodeId(uriService.findByUri(body.uri).stringId) - menuItemCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_ALLOWED_ROLES.attributeId].options = body.allowedRoles - menuItemCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_BANNED_ROLES.attributeId].options = body.bannedRoles + menuItemCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_ALLOWED_ROLES.value].options = body.allowedRoles + menuItemCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_BANNED_ROLES.value].options = body.bannedRoles if (parentItemCase != null) { parentItemCase = appendChildCaseIdAndSave(parentItemCase, menuItemCase.stringId) } menuItemCase = workflowService.save(menuItemCase) - Task newItemTask = taskService.findOne(menuItemCase.tasks.find { it.transition == MenuItemConstants.PREFERENCE_ITEM_FIELD_INIT_TRANS_ID.attributeId }.task) - String nodePath = createNodePath(body.uri, sanitizedIdentifier) - uriService.getOrCreate(nodePath, UriContentType.CASE) + Task newItemTask = taskService.findOne(menuItemCase.tasks.find { it.transition == MenuItemConstants.PREFERENCE_ITEM_FIELD_INIT_TRANS_ID.value }.task) + String nodePath = createNodePath(body.path, sanitizedIdentifier) newItemTask = assignTask(newItemTask) setData(newItemTask, body.toDataSet(parentItemCase.stringId, nodePath)) @@ -2138,22 +2118,21 @@ class ActionDelegate { .toLowerCase() } - protected String createNodePath(String uri, String identifier) { - if (uri == uriService.getUriSeparator()) { - return uri + identifier - } else { - return uri + uriService.getUriSeparator() + identifier - } + protected String createNodePath(String path, String identifier) { + String normalized = path.endsWith(MenuItemConstants.PATH_SEPARATOR.value) && path != MenuItemConstants.PATH_SEPARATOR.value + ? path.substring(0, path.length() - 1) + : path + return normalized + MenuItemConstants.PATH_SEPARATOR.value + identifier } - protected Case getOrCreateFolderItem(String uri) { - UriNode node = uriService.getOrCreate(uri, UriContentType.CASE) - MenuItemBody body = new MenuItemBody(new I18nString(node.name), "folder") - return getOrCreateFolderRecursive(node, body) + protected Case getOrCreateFolderItem(String path) { + String pathName = path.substring(path.lastIndexOf(MenuItemConstants.PATH_SEPARATOR.value) + 1); + MenuItemBody body = new MenuItemBody(new I18nString(pathName), "folder") + return getOrCreateFolderRecursive(path, body) } - protected Case getOrCreateFolderRecursive(UriNode node, MenuItemBody body, Case childFolderCase = null) { - Case folder = findFolderCase(node) + protected Case getOrCreateFolderRecursive(String path, MenuItemBody body, Case childFolderCase = null) { + Case folder = findFolderCase(path) if (folder != null) { if (childFolderCase != null) { folder = appendChildCaseIdAndSave(folder, childFolderCase.stringId) @@ -2163,29 +2142,51 @@ class ActionDelegate { } folder = createCase(FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER, body.menuName.toString()) - folder.setUriNodeId(node.parentId) if (childFolderCase != null) { folder = appendChildCaseIdAndSave(folder, childFolderCase.stringId) initializeParentId(childFolderCase, folder.stringId) } else { folder = workflowService.save(folder) } - Task newItemTask = taskService.findOne(folder.tasks.find { it.transition == MenuItemConstants.PREFERENCE_ITEM_FIELD_INIT_TRANS_ID.attributeId }.task) + Task newItemTask = taskService.findOne(folder.tasks.find { it.transition == MenuItemConstants.PREFERENCE_ITEM_FIELD_INIT_TRANS_ID.value }.task) assignTask(newItemTask) - setData(newItemTask, body.toDataSet(null, node.path)) + setData(newItemTask, body.toDataSet(null, path)) finishTask(newItemTask) folder = workflowService.findOne(folder.stringId) - if (node.parentId != null) { - UriNode parentNode = uriService.findById(node.parentId) - body = new MenuItemBody(new I18nString(parentNode.name), "folder") - - getOrCreateFolderRecursive(parentNode, body, folder) + if (hasParent(path)) { + body = new MenuItemBody(new I18nString(nameFromPath(path)), "folder") + String parentPath = parentPath(path) + getOrCreateFolderRecursive(parentPath, body, folder) } return folder } + protected String nameFromPath(String path) { + if (path == null || path == MenuItemConstants.PATH_SEPARATOR.value || path.length() == 0) { + return "" + } + if (path.lastIndexOf(MenuItemConstants.PATH_SEPARATOR.value) == 0) { + return path.replace(MenuItemConstants.PATH_SEPARATOR.value, "") + } + return path.substring(path.lastIndexOf(MenuItemConstants.PATH_SEPARATOR.value)) + } + + protected String parentPath(String path) { + if (path == null || path == MenuItemConstants.PATH_SEPARATOR.value || path.length() == 0 || path.lastIndexOf(MenuItemConstants.PATH_SEPARATOR.value) == 0) { + return MenuItemConstants.PATH_SEPARATOR.value + } + return path.substring(0, path.lastIndexOf(MenuItemConstants.PATH_SEPARATOR.value)) + } + + protected boolean hasParent(String path) { + if (path == null || path == MenuItemConstants.PATH_SEPARATOR.value || path.length() == 0) { + return false + } + return true + } + /** * Changes location of menu item. If non-existing location is provided, the new location is created and then the * item is moved. Cyclic destination path is forbidden (f.e. from "/my_node" to @@ -2201,24 +2202,22 @@ class ActionDelegate { List casesToSave = new ArrayList<>() - List parentIdList = item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.attributeId].value as ArrayList + List parentIdList = item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.value].value as ArrayList if (parentIdList != null && parentIdList.size() > 0) { Case oldParent = removeChildItemFromParent(parentIdList[0], item) casesToSave.add(oldParent) } - UriNode destNode = uriService.getOrCreate(destUri, UriContentType.CASE) - Case newParent = getOrCreateFolderItem(destNode.path) + Case newParent = getOrCreateFolderItem(destUri) if (newParent != null) { - item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.attributeId].value = [newParent.stringId] as ArrayList + item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.value].value = [newParent.stringId] as ArrayList newParent = appendChildCaseId(newParent, item.stringId) casesToSave.add(newParent) } else { - item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.attributeId].value = null + item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.value].value = null } - item.uriNodeId = destNode.stringId - item = resolveAndHandleNewNodePath(item, destNode.path) + item = resolveAndHandleNewNodePath(item, destUri) casesToSave.add(item) if (hasChildren(item)) { @@ -2256,39 +2255,36 @@ class ActionDelegate { } Case duplicated = createCase(FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER, newTitle.defaultValue) - duplicated.uriNodeId = originItem.uriNodeId duplicated.dataSet = originItem.dataSet duplicated.title = newTitle.defaultValue duplicated = workflowService.save(duplicated) - UriNode node = uriService.findById(originItem.uriNodeId) - String newNodePath = createNodePath(node.path, sanitizedIdentifier) - uriService.getOrCreate(newNodePath, UriContentType.CASE) + String newNodePath = createNodePath((String) originItem.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH].value, sanitizedIdentifier) - Task newItemTask = taskService.findOne(duplicated.tasks.find { it.transition == MenuItemConstants.PREFERENCE_ITEM_FIELD_INIT_TRANS_ID.attributeId }.task) + Task newItemTask = taskService.findOne(duplicated.tasks.find { it.transition == MenuItemConstants.PREFERENCE_ITEM_FIELD_INIT_TRANS_ID.value }.task) Map updatedDataSet = [ - (MenuItemConstants.PREFERENCE_ITEM_FIELD_DUPLICATE_TITLE.attributeId) : [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_DUPLICATE_TITLE.value) : [ "value": null, "type" : "text" ], - (MenuItemConstants.PREFERENCE_ITEM_FIELD_DUPLICATE_IDENTIFIER.attributeId) : [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_DUPLICATE_IDENTIFIER.value) : [ "value": null, "type" : "text" ], - (MenuItemConstants.PREFERENCE_ITEM_FIELD_MENU_NAME.attributeId) : [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_MENU_NAME.value) : [ "value": newTitle, "type" : "i18n" ], - (MenuItemConstants.PREFERENCE_ITEM_FIELD_TAB_NAME.attributeId) : [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_TAB_NAME.value) : [ "value": newTitle, "type" : "i18n" ], - (MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.attributeId) : [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.value) : [ "value": newNodePath, "type" : "text" ], // Must be reset by button, because we have the same dataSet reference between originItem and duplicated - (MenuItemConstants.PREFERENCE_ITEM_FIELD_DUPLICATE_RESET_CHILD_ITEM_IDS.attributeId): [ + (MenuItemConstants.PREFERENCE_ITEM_FIELD_DUPLICATE_RESET_CHILD_ITEM_IDS.value): [ "value": 0, "type" : "button" ], @@ -2297,7 +2293,7 @@ class ActionDelegate { dataService.setData(newItemTask, ImportHelper.populateDataset(updatedDataSet)) finishTask(newItemTask) - String parentId = (originItem.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.attributeId].value as ArrayList).get(0) + String parentId = (originItem.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.value].value as ArrayList).get(0) if (parentId) { Case parent = workflowService.findOne(parentId) appendChildCaseIdAndSave(parent, duplicated.stringId) @@ -2306,7 +2302,7 @@ class ActionDelegate { } private List updateNodeInChildrenFoldersRecursive(Case parentFolder) { - List childItemIds = parentFolder.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.attributeId].value as List + List childItemIds = parentFolder.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.value].value as List if (childItemIds == null || childItemIds.isEmpty()) { return new ArrayList() } @@ -2315,9 +2311,7 @@ class ActionDelegate { List casesToSave = new ArrayList<>() for (child in children) { - UriNode parentNode = uriService.getOrCreate(parentFolder.getFieldValue(MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.attributeId) as String, UriContentType.CASE) - child.uriNodeId = parentNode.stringId - child = resolveAndHandleNewNodePath(child, parentNode.path) + child = resolveAndHandleNewNodePath(child, (String) parentFolder.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH].value) casesToSave.add(child) casesToSave.addAll(updateNodeInChildrenFoldersRecursive(child)) @@ -2328,32 +2322,31 @@ class ActionDelegate { private Case resolveAndHandleNewNodePath(Case folderItem, String destUri) { String newNodePath = resolveNewNodePath(folderItem, destUri) - UriNode newNode = uriService.getOrCreate(newNodePath, UriContentType.CASE) - folderItem.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.attributeId].value = newNode.path + folderItem.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.value].value = newNodePath return folderItem } private String resolveNewNodePath(Case folderItem, String destUri) { return destUri + - uriService.getUriSeparator() + - folderItem.getFieldValue(MenuItemConstants.PREFERENCE_ITEM_FIELD_IDENTIFIER.attributeId) as String + MenuItemConstants.PATH_SEPARATOR.value + + folderItem.getFieldValue(MenuItemConstants.PREFERENCE_ITEM_FIELD_IDENTIFIER.value) as String } private Case removeChildItemFromParent(String folderId, Case childItem) { Case parentFolder = workflowService.findOne(folderId) - (parentFolder.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.attributeId].value as List).remove(childItem.stringId) - parentFolder.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_HAS_CHILDREN.attributeId].value = hasChildren(parentFolder) + (parentFolder.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.value].value as List).remove(childItem.stringId) + parentFolder.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_HAS_CHILDREN.value].value = hasChildren(parentFolder) workflowService.save(parentFolder) } private boolean isCyclicNodePath(Case folderItem, String destUri) { - String oldNodePath = folderItem.getFieldValue(MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.attributeId) + String oldNodePath = folderItem.getFieldValue(MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.value) return destUri.contains(oldNodePath) } private boolean hasChildren(Case folderItem) { - List children = folderItem.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.attributeId].value as List + List children = folderItem.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.value].value as List return children != null && children.size() > 0 } @@ -2363,25 +2356,25 @@ class ActionDelegate { } private Case appendChildCaseId(Case folderCase, String childItemCaseId) { - List childIds = folderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.attributeId].value as ArrayList + List childIds = folderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.value].value as ArrayList if (childIds == null) { - folderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.attributeId].value = [childItemCaseId] as ArrayList + folderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.value].value = [childItemCaseId] as ArrayList } else { - folderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.attributeId].value = childIds + [childItemCaseId] as ArrayList + folderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.value].value = childIds + [childItemCaseId] as ArrayList } - folderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_HAS_CHILDREN.attributeId].value = hasChildren(folderCase) + folderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_HAS_CHILDREN.value].value = hasChildren(folderCase) return folderCase } private Case initializeParentId(Case childFolderCase, String parentFolderCaseId) { - childFolderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.attributeId].value = [parentFolderCaseId] as ArrayList + childFolderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.value].value = [parentFolderCaseId] as ArrayList return workflowService.save(childFolderCase) } - protected Case findFolderCase(UriNode node) { - return findCaseElastic("processIdentifier:$FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER AND dataSet.nodePath.textValue.keyword:\"$node.path\"") + protected Case findFolderCase(String path) { + return findCaseElastic("processIdentifier:$FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER AND dataSet.nodePath.textValue.keyword:\"$path\"") } /** @@ -2423,14 +2416,13 @@ class ActionDelegate { * @param name * @return */ - Case findMenuItem(String uri, String name) { - UriNode uriNode = uriService.findByUri(uri) - return findCaseElastic("processIdentifier:\"$FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER\" AND title.keyword:\"$name\" AND uriNodeId:\"$uriNode.stringId\"") + Case findMenuItem(String path, String name) { + return findCaseElastic("processIdentifier:\"$FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER\" AND title.keyword:\"$name\" AND dataSet.nodePath.fulltextValue.keyword:\"$path\"") } Case findMenuItemByUriAndIdentifier(String uri, String identifier) { String nodePath = createNodePath(uri, identifier) - return findCaseElastic("processIdentifier:\"$FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER\" AND dataSet.${MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.attributeId}.textValue.keyword:\"$nodePath\"") + return findCaseElastic("processIdentifier:\"$FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER\" AND dataSet.${MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.value}.textValue.keyword:\"$nodePath\"") } /** @@ -2465,7 +2457,7 @@ class ActionDelegate { * @return found filter instance. If not found, null is returned */ Case getFilterFromMenuItem(Case item) { - String filterId = (item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_FILTER_CASE.attributeId].value as List)[0] as String + String filterId = (item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_FILTER_CASE.value].value as List)[0] as String return filterId ? workflowService.findOne(filterId) : null } @@ -2590,8 +2582,6 @@ class ActionDelegate { Case menuItem = findMenuItem(sanitize(id)) if (!menuItem) { Case filter = createFilter(title, query, type, allowedNets, icon, DefaultFiltersRunner.FILTER_VISIBILITY_PRIVATE, null) - createUri(uri, UriContentType.DEFAULT) - return createMenuItem(uri, id, title, icon, filter, roles, bannedRoles) } else { Case filter = getFilterFromMenuItem(menuItem) @@ -2785,7 +2775,7 @@ class ActionDelegate { * @return updated menu item instance * */ Case updateMenuItem(Case item, MenuItemBody body) { - def outcome = setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.attributeId, item, body.toDataSet()) + def outcome = setData(MenuItemConstants.PREFERENCE_ITEM_SETTINGS_TRANS_ID.value, item, body.toDataSet()) return outcome.case } @@ -2803,67 +2793,57 @@ class ActionDelegate { return "${publicViewUrl}/${Base64.getEncoder().encodeToString(identifier.bytes)}" as String } - void updateMultichoiceWithCurrentNode(MultichoiceMapField field, UriNode node) { - List splitPathList = splitUriPath(node.path) + void updateMultichoiceWithCurrentNode(MultichoiceMapField field, String path) { + List splitPathList = splitUriPath(path) - change field options { findOptionsBasedOnSelectedNode(node, splitPathList) } + change field options { findOptionsBasedOnSelectedNode(path, splitPathList) } change field value { splitPathList } } - List splitUriPath(String uri) { - String rootUri = uriService.getUriSeparator() - String[] splitPath = uri.split(uriService.getUriSeparator()) - if (splitPath.length == 0 && uri == rootUri) { - splitPath = [rootUri] + List splitUriPath(String path) { + String rootPath = MenuItemConstants.PATH_SEPARATOR.value + String[] splitPath = path.split(MenuItemConstants.PATH_SEPARATOR.value) + if (splitPath.length == 0 && path == rootPath) { + splitPath = [rootPath] } else if (splitPath.length == 0) { - throw new IllegalArgumentException("Wrong uri value: \"${uri}\"") + throw new IllegalArgumentException("Wrong path value: \"${path}\"") } else { - splitPath[0] = rootUri + splitPath[0] = rootPath } return splitPath as ArrayList } - Map findOptionsBasedOnSelectedNode(UriNode node) { - return findOptionsBasedOnSelectedNode(node, splitUriPath(node.path)) + Map findOptionsBasedOnSelectedNode(String path) { + return findOptionsBasedOnSelectedNode(path, splitUriPath(path)) } - Map findOptionsBasedOnSelectedNode(UriNode node, List splitPathList) { + Map findOptionsBasedOnSelectedNode(String path, List splitPathList) { Map options = new HashMap<>() options.putAll(splitPathList.collectEntries { [(it): new I18nString(it)] }) - Set childrenIds = node.getChildrenId() + Case caseByPath = findCaseElastic("processIdentifier:$FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER AND dataSet.nodePath.textValue.keyword:\"$path\"") + Set childrenIds = caseByPath.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.value].value as Set if (!childrenIds.isEmpty()) { for (String id : childrenIds) { - UriNode childNode = uriService.findById(id) - options.put(childNode.name, new I18nString(childNode.name)) + Case childFolderCase = workflowService.findOne(id) + options.put(childFolderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_NAME.value].value as String, new I18nString(childFolderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_NAME.value].value as String)) } } return options } - String getCorrectedUri(String uncheckedUri) { - String rootUri = uriService.getUriSeparator() - if (uncheckedUri == "") { - return rootUri + String getCorrectedUri(String uncheckedPath) { + String rootPath = MenuItemConstants.PATH_SEPARATOR.value + if (uncheckedPath == "") { + return rootPath } - - UriNode node = uriService.findByUri(uncheckedUri) - - while (node == null) { - int lastIdx = uncheckedUri.lastIndexOf(uriService.getUriSeparator()) - if (lastIdx == -1) { - return rootUri - } - uncheckedUri = uncheckedUri.substring(0, uncheckedUri.lastIndexOf(uriService.getUriSeparator())) - if (uncheckedUri == "") { - return rootUri - } - node = uriService.findByUri(uncheckedUri) + int lastIdx = uncheckedPath.lastIndexOf(MenuItemConstants.PATH_SEPARATOR.value) + if (lastIdx == -1) { + return rootPath } - - return node.path + return uncheckedPath } Field getFieldOfTask(String taskId, String fieldId) { diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/PluginInjector.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/PluginInjector.groovy new file mode 100644 index 00000000000..43fc1825e12 --- /dev/null +++ b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/PluginInjector.groovy @@ -0,0 +1,73 @@ +package com.netgrif.application.engine.plugin + +import com.netgrif.application.engine.adapter.spring.plugin.service.PluginService +import com.netgrif.application.engine.objects.plugin.domain.EntryPoint +import com.netgrif.application.engine.objects.plugin.domain.Method +import com.netgrif.application.engine.objects.plugin.domain.Plugin +import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.ActionDelegate +import com.netgrif.application.engine.plugin.meta.EntryPointMeta +import com.netgrif.application.engine.plugin.meta.PluginHolder +import com.netgrif.application.engine.plugin.meta.PluginMeta +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component + +/** + * Component responsible for injecting plugin entry points and methods into + * the application's meta-class system at runtime. Uses Groovy's metaClass + * mechanism to dynamically add closures that delegate calls to PluginService. + * + * @see ActionDelegate + * @see PluginService + */ +@Component +class PluginInjector { + + /** + * Service used to invoke methods on the injected plugins. + */ + @Autowired + protected PluginService pluginService + + /** + * Injects the provided plugin into the application's meta-class system. + * This will allow calls to plugin entry points and methods via dynamic + * properties on {@link PluginHolder}. + * + * @param plugin the Plugin instance to be injected + */ + void inject(Plugin plugin) { + updateMetaClasses(plugin) + } + + /** + * Updates meta-class definitions for the given plugin by registering + * each entry point and its methods as closures. Each generated closure + * delegates invocation to the {@link PluginService}. + * + * @param plugin the Plugin instance whose entry points and methods + * are to be exposed dynamically + */ + protected void updateMetaClasses(Plugin plugin) { + def pluginMeta = new PluginMeta() + + plugin.entryPoints.values().each { EntryPoint ep -> + def epMeta = new EntryPointMeta() + + ep.methods.values().each { Method method -> + /** + * Dynamically generated method closure for entry point invocation. + * + * @param args variable-length list of Serializable arguments + * @return the result returned by PluginService.call(...) + */ + epMeta.metaClass."${method.name}" = { Serializable... args -> + pluginService.call(plugin.identifier, ep.name, method.name, args) + } + } + + pluginMeta.metaClass."${ep.name}" = epMeta + } + + PluginHolder.metaClass."${plugin.name}" = pluginMeta + } +} diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/EntryPointMeta.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/EntryPointMeta.groovy new file mode 100644 index 00000000000..72e5e3a3b67 --- /dev/null +++ b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/EntryPointMeta.groovy @@ -0,0 +1,8 @@ +package com.netgrif.application.engine.plugin.meta + +/** + * Class, that has modified meta class and is injected into + * {@link com.netgrif.application.engine.petrinet.domain.dataset.logic.action.ActionDelegate}. No class-attributes needed. + * */ +class EntryPointMeta { +} diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/PluginHolder.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/PluginHolder.groovy new file mode 100644 index 00000000000..2c924869966 --- /dev/null +++ b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/PluginHolder.groovy @@ -0,0 +1,5 @@ +package com.netgrif.application.engine.plugin.meta; + + +class PluginHolder { +} diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/PluginMeta.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/PluginMeta.groovy new file mode 100644 index 00000000000..6cc368b21eb --- /dev/null +++ b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/PluginMeta.groovy @@ -0,0 +1,5 @@ +package com.netgrif.application.engine.plugin.meta + + +class PluginMeta { +} diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovy index e059f5b5bb2..8aaef7a58e1 100644 --- a/application-engine/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovy +++ b/application-engine/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovy @@ -5,7 +5,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService import com.netgrif.application.engine.petrinet.domain.repositories.PetriNetRepository import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService -import com.netgrif.application.engine.petrinet.service.interfaces.IUriService import com.netgrif.application.engine.startup.runner.SuperCreatorRunner import com.netgrif.application.engine.workflow.domain.repositories.CaseRepository import com.netgrif.application.engine.workflow.service.interfaces.IDataService @@ -91,9 +90,6 @@ class ImportHelper { @Autowired private ProcessRoleService processRoleService - @Autowired - private IUriService uriService - private final ClassLoader loader = ImportHelper.getClassLoader() @@ -113,14 +109,19 @@ class ImportHelper { return authorityService.getOrCreate(name) } - Optional createNet(String fileName, String release, LoggedUser author = userService.transformToLoggedUser(userService.getSystem()), String uriNodeId = uriService.getDefault().stringId) { - return createNet(fileName, VersionType.valueOf(release.trim().toUpperCase()), author, uriNodeId) + Optional createNet(String fileName, String release, LoggedUser author = userService.transformToLoggedUser(userService.getSystem())) { + return createNet(fileName, VersionType.valueOf(release.trim().toUpperCase()), author) } - Optional createNet(String fileName, VersionType release = VersionType.MAJOR, LoggedUser author = userService.transformToLoggedUser(userService.getSystem()), String uriNodeId = uriService.getDefault().stringId) { + Optional createNet(String fileName, VersionType release = VersionType.MAJOR, LoggedUser author = userService.transformToLoggedUser(userService.getSystem())) { InputStream netStream = new ClassPathResource("petriNets/$fileName" as String).inputStream - PetriNet petriNet = petriNetService.importPetriNet(netStream, release, author, uriNodeId).getNet() - log.info("Imported '${petriNet?.title?.defaultValue}' ['${petriNet?.identifier}', ${petriNet?.stringId}]") + def outcome = petriNetService.importPetriNet(netStream, release, author) + PetriNet petriNet = outcome.getNet() + if (petriNet == null) { + log.warn("Import of [$fileName] produced no PetriNet object") + return Optional.empty() + } + log.info("Imported '${petriNet.title?.defaultValue}' ['${petriNet.identifier}', ${petriNet.stringId}]") return Optional.of(petriNet) } diff --git a/application-engine/src/main/java/com/netgrif/application/engine/PluginServiceImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/PluginServiceImpl.java new file mode 100644 index 00000000000..d739d124a4f --- /dev/null +++ b/application-engine/src/main/java/com/netgrif/application/engine/PluginServiceImpl.java @@ -0,0 +1,81 @@ +package com.netgrif.application.engine; + +import com.netgrif.application.engine.adapter.spring.plugin.service.PluginService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; + +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class PluginServiceImpl implements PluginService { + + private final ApplicationContext applicationContext; + + @Override + public Object call(String pluginId, String entryPoint, String method, Serializable... args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { + log.info("Executing entry point [{}] with method [{}]...", entryPoint, method); + Class[] paramTypesFromRequest = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new); + Object bean = applicationContext.getBean(entryPoint); + Method methodToInvoke = findMethod(bean, method, paramTypesFromRequest); + return methodToInvoke.invoke(bean, Arrays.stream(args).toArray()); + } + + private Method findMethod(Object bean, String methodToExecute, Class[] requestParamTypes) + throws NoSuchMethodException, IllegalArgumentException { + try { + return bean.getClass().getMethod(methodToExecute, requestParamTypes); + } catch (NoSuchMethodException e) { + return findMethodWithSuperClassParams(bean, methodToExecute, requestParamTypes, e); + } + } + + private Method findMethodWithSuperClassParams(Object bean, String methodToExecute, Class[] requestParamTypes, + NoSuchMethodException caughtException) + throws NoSuchMethodException, IllegalArgumentException { + Class cls = bean.getClass(); + Method[] methods = cls.getMethods(); + Method methodToInvoke = null; + outerLoop: for (Method method : methods) { + if (!methodToExecute.equals(method.getName())) { + continue; + } + + Class[] paramTypes = method.getParameterTypes(); + int requestParamsLen = requestParamTypes.length; + int paramsLen = paramTypes.length; + + if (requestParamsLen == 0 && paramsLen == 0) { + methodToInvoke = method; + break; + } else if (paramsLen == 0 || paramsLen != requestParamsLen) { + continue; + } + + for (int i = 0; i < requestParamTypes.length; ++i) { + if (!paramTypes[i].isAssignableFrom(requestParamTypes[i])) { + continue outerLoop; + } + } + + if (methodToInvoke != null) { + throw new IllegalArgumentException(String.format("Method %s is ambiguous for the param types %s", + methodToExecute, Arrays.toString(requestParamTypes))); + } + methodToInvoke = method; + } + + if (methodToInvoke == null) { + throw caughtException; + } else { + return methodToInvoke; + } + } +} diff --git a/application-engine/src/main/java/com/netgrif/application/engine/configuration/UriServiceConfiguration.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/UriServiceConfiguration.java deleted file mode 100644 index 663bef1c32e..00000000000 --- a/application-engine/src/main/java/com/netgrif/application/engine/configuration/UriServiceConfiguration.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.netgrif.application.engine.configuration; - -import com.netgrif.application.engine.configuration.properties.UriProperties; -import com.netgrif.application.engine.petrinet.domain.repository.UriNodeRepository; -import com.netgrif.application.engine.petrinet.service.UriService; -import com.netgrif.application.engine.petrinet.service.interfaces.IUriService; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class UriServiceConfiguration { - - @Bean - @ConditionalOnMissingBean - public IUriService uriService(UriNodeRepository uriNodeRepository, UriProperties uriProperties) { - return new UriService(uriNodeRepository, uriProperties); - } -} diff --git a/application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java b/application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java index 3fd66f168c5..62c91cd1874 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java @@ -164,19 +164,6 @@ public long count(List requests, LoggedUser user, Locale loca } } - public String findUriNodeId(Case aCase) { - if (aCase == null) { - return null; - } - ElasticCase elasticCase = repository.findByStringId(aCase.getStringId()); - if (elasticCase == null) { - log.warn("[" + aCase.getStringId() + "] Case with id [" + aCase.getStringId() + "] is not indexed."); - return null; - } - - return elasticCase.getUriNodeId(); - } - protected NativeQuery buildQuery(List requests, LoggedUser user, Pageable pageable, Locale locale, Boolean isIntersection) { List singleQueries = requests.stream().map(request -> buildSingleQuery(request, user, locale)).collect(Collectors.toList()); diff --git a/application-engine/src/main/java/com/netgrif/application/engine/elastic/service/interfaces/IElasticCaseService.java b/application-engine/src/main/java/com/netgrif/application/engine/elastic/service/interfaces/IElasticCaseService.java index 4d4c11df2b9..8750dff1391 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/elastic/service/interfaces/IElasticCaseService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/elastic/service/interfaces/IElasticCaseService.java @@ -25,6 +25,4 @@ public interface IElasticCaseService { void remove(String caseId); void removeByPetriNetId(String processId); - - String findUriNodeId(Case aCase); } diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java index e6f3702ce53..bfb92d2be02 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java @@ -30,7 +30,6 @@ import com.netgrif.application.engine.objects.petrinet.domain.throwable.MissingPetriNetMetaDataException; import com.netgrif.application.engine.objects.petrinet.domain.version.Version; import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService; -import com.netgrif.application.engine.petrinet.service.interfaces.IUriService; import com.netgrif.application.engine.petrinet.web.responsebodies.*; import com.netgrif.application.engine.objects.workflow.domain.Case; import com.netgrif.application.engine.workflow.domain.FileStorageConfiguration; @@ -128,9 +127,6 @@ public class PetriNetService implements IPetriNetService { @Autowired protected IElasticPetriNetMappingService petriNetMappingService; - @Autowired - protected IUriService uriService; - protected ApplicationEventPublisher publisher; protected IElasticPetriNetService elasticPetriNetService; @@ -184,36 +180,19 @@ public List get(List petriNetIds) { return self.get(petriNetIds.stream().map(ObjectId::new).collect(Collectors.toList())); } - @Override @Deprecated public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, String releaseType, LoggedUser author) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException { - return importPetriNet(xmlFile, VersionType.valueOf(releaseType.trim().toUpperCase()), author, uriService.getDefault().getStringId()); - } - - @Override - @Deprecated - public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, String releaseType, LoggedUser author, String uriNodeId) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException { - return importPetriNet(xmlFile, VersionType.valueOf(releaseType.trim().toUpperCase()), author, uriNodeId); + return importPetriNet(xmlFile, VersionType.valueOf(releaseType.trim().toUpperCase()), author); } @Override public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser author) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException { - return importPetriNet(xmlFile, releaseType, author, uriService.getDefault().getStringId()); + return importPetriNet(xmlFile, releaseType, author, new HashMap<>()); } @Override public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser author, Map params) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException { - return importPetriNet(xmlFile, releaseType, author, uriService.getDefault().getStringId(), params); - } - - @Override - public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser author, String uriNodeId) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException { - return importPetriNet(xmlFile, releaseType, author, uriNodeId, new HashMap<>()); - } - - @Override - public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser author, String uriNodeId, Map params) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException { ImportPetriNetEventOutcome outcome = new ImportPetriNetEventOutcome(); ByteArrayOutputStream xmlCopy = new ByteArrayOutputStream(); IOUtils.copy(xmlFile, xmlCopy); @@ -222,7 +201,6 @@ public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionTyp return outcome; } PetriNet net = imported.get(); - net.setUriNodeId(uriNodeId); PetriNet existingNet = getNewestVersionByIdentifier(net.getIdentifier()); if (existingNet != null) { @@ -245,13 +223,6 @@ public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionTyp return outcome; } - private ImportPetriNetEventOutcome addMessageToOutcome(PetriNet net, ProcessEventType type, ImportPetriNetEventOutcome outcome) { - if (net.getProcessEvents().containsKey(type)) { - outcome.setMessage(net.getProcessEvents().get(type).getMessage()); - } - return outcome; - } - protected void evaluateRules(Event event) { publisher.publishEvent(event); @@ -301,16 +272,9 @@ public List getByIdentifier(String identifier) { return nets; } - @Override - public List findAllByUriNodeId(String uriNodeId) { - List nets = elasticPetriNetService.findAllByUriNodeId(uriNodeId); - nets.forEach(PetriNet::initializeArcs); - return nets; - } - @Override public List findAllById(List ids) { - return StreamSupport.stream(repository.findAllById(ids).spliterator(), false).collect(Collectors.toList()); + return new ArrayList<>(repository.findAllById(ids)); } @Override @@ -320,7 +284,7 @@ public PetriNet getNewestVersionByIdentifier(String identifier) { if (nets.isEmpty()) { return null; } - return nets.get(0); + return nets.getFirst(); } /** diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/UriService.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/UriService.java deleted file mode 100644 index 9076c410187..00000000000 --- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/UriService.java +++ /dev/null @@ -1,285 +0,0 @@ -package com.netgrif.application.engine.petrinet.service; - -import com.netgrif.application.engine.configuration.properties.UriProperties; -import com.netgrif.application.engine.objects.petrinet.domain.UriContentType; -import com.netgrif.application.engine.objects.petrinet.domain.UriNode; -import com.netgrif.application.engine.petrinet.domain.repository.UriNodeRepository; -import com.netgrif.application.engine.petrinet.service.interfaces.IUriService; -import lombok.Getter; -import org.apache.commons.lang3.StringUtils; - -import java.util.*; -import java.util.stream.Collectors; - -/** - * Service for managing UriNode objects - */ -//@Service -public class UriService implements IUriService { - - private static final int FIRST_LEVEL = 0; - - @Getter - private final UriNodeRepository uriNodeRepository; - - @Getter - private final UriProperties uriProperties; - - public UriService(UriNodeRepository uriNodeRepository, UriProperties uriProperties) { - this.uriNodeRepository = uriNodeRepository; - this.uriProperties = uriProperties; - } - - - /** - * Saves UriNode object to database - * - * @param uriNode to be saved - */ - @Override - public UriNode save(UriNode uriNode) { - return uriNodeRepository.save((com.netgrif.application.engine.adapter.spring.petrinet.domain.UriNode) uriNode); - } - - /** - * Retrieves all UriNode based on parent ID - * - * @param parentId ID of parent UriNode - * @return list of UriNode - */ - @Override - public List findAllByParent(String parentId) { - return uriNodeRepository.findAllByParentId(parentId).stream().map(UriNode.class::cast).toList(); - } - - /** - * Retrieves all UriNode that are root nodes - * - * @return list of UriNode - */ - @Override - public UriNode getRoot() { - List nodes = uriNodeRepository.findAllByLevel(FIRST_LEVEL).stream().map(UriNode.class::cast).toList(); - if (nodes.size() != 1) { - throw new IllegalStateException("Exactly one root uri node must exist!"); - } - return nodes.getFirst(); - } - - /** - * Retrieves all default uri node for app - * - * @return default uriNode - */ - @Override - public UriNode getDefault() { - return uriNodeRepository.findByPath(uriProperties.getSeparator() + uriProperties.getName()); - } - - /** - * Retrieves all UriNode based on level - * - * @param level of UriNodes - * @return list of UriNodes - */ - @Override - public List findByLevel(int level) { - return uriNodeRepository.findAllByLevel(level).stream().map(UriNode.class::cast).collect(Collectors.toList()); - } - - /** - * Retrieves UriNode based on ID - * - * @param id ID of UriNode - * @return UriNode - */ - @Override - public UriNode findById(String id) { - Optional navNodeOptional = uriNodeRepository.findById(id); - if (navNodeOptional.isEmpty()) { - throw new IllegalArgumentException("Could not find NavNode with id [" + id + "]"); - } - return navNodeOptional.get(); - } - - /** - * Retrieves UriNode based on uri - * - * @param uri ID of UriNode - * @return UriNode - */ - @Override - public UriNode findByUri(String uri) { - return uriNodeRepository.findByPath(uri); - } - - /** - * Collects direct relatives (parent and children) of input UriNode and returns filled object - * - * @param uriNode to be filled with relatives - * @return filled UriNode - */ - @Override - public UriNode populateDirectRelatives(UriNode uriNode) { - if (uriNode == null) { - return null; - } - if (uriNode.getLevel() != FIRST_LEVEL) { - UriNode parent = findById(uriNode.getParentId()); - uriNode.setParent(parent); - } - Set children = new HashSet<>(uriNodeRepository.findAllById(uriNode.getChildrenId())); - uriNode.setChildren(children); - return uriNode; - } - - /** - * Moves UriNode to other destination - * - * @param uri to be moved - * @param destUri the destination URI - * @return result UriNode object - */ - @Override - public UriNode move(String uri, String destUri) { - UriNode uriNode = findByUri(uri); - return move(uriNode, destUri); - } - - /** - * Moves UriNode to other destination - * - * @param node to be moved - * @param destUri the destination URI - * @return result UriNode object - */ - @Override - public UriNode move(UriNode node, String destUri) { - if (isPathCycle(node.getPath(), destUri)) { - throw new IllegalArgumentException("Uri node with path " + node.getPath() + " cannot be moved to path " + destUri + " due to cyclic paths"); - } - - UriNode newParent = getOrCreate(destUri, null); - UriNode oldParent = findById(node.getParentId()); - - if (destUri.indexOf(uriProperties.getSeparator()) != 0) { - destUri = uriProperties.getSeparator() + destUri; - } - String oldNodePath = node.getPath(); - String newNodePath = destUri + (destUri.equals(uriProperties.getSeparator()) ? "" : uriProperties.getSeparator()) + node.getName(); - node.setPath(newNodePath); - node.setParentId(newParent.getStringId()); - node.setLevel(newParent.getLevel() + 1); - - oldParent.getChildrenId().remove(oldNodePath); - newParent.getChildrenId().add(newNodePath); - uriNodeRepository.saveAll(List.of((com.netgrif.application.engine.adapter.spring.petrinet.domain.UriNode) oldParent, (com.netgrif.application.engine.adapter.spring.petrinet.domain.UriNode) newParent, (com.netgrif.application.engine.adapter.spring.petrinet.domain.UriNode) node)); - - List childrenToSave = new ArrayList<>(); - if (!node.getChildrenId().isEmpty()) { - node = populateDirectRelatives(node); - childrenToSave.addAll(moveChildrenRecursive(oldNodePath, newNodePath, node.getChildren())); - } - - uriNodeRepository.saveAll(List.of((com.netgrif.application.engine.adapter.spring.petrinet.domain.UriNode) oldParent, (com.netgrif.application.engine.adapter.spring.petrinet.domain.UriNode) newParent, (com.netgrif.application.engine.adapter.spring.petrinet.domain.UriNode) node)); - uriNodeRepository.saveAll(childrenToSave); - return node; - } - - private boolean isPathCycle(String picked, String dest) { - return dest.startsWith(picked); - } - - private List moveChildrenRecursive(String oldParentPath, String newParentPath, Set nodes) { - List updated = new ArrayList<>(); - - if (nodes == null || nodes.isEmpty()) { - return new ArrayList<>(); - } - - for (UriNode node : nodes) { - String oldPath = node.getPath(); - String diff = calcPathDifference(oldPath, oldParentPath); - String newPath = newParentPath + diff; - node.setPath(newPath); - node.setParentId(newParentPath); - updated.add((com.netgrif.application.engine.adapter.spring.petrinet.domain.UriNode) node); - - node = populateDirectRelatives(node); - - updated.addAll(moveChildrenRecursive(oldPath, newPath, node.getChildren())); - } - - return updated; - } - - private String calcPathDifference(String path1, String path2) { - return StringUtils.difference(path2, path1); - } - - /** - * Creates new UriNode from URI path, or retrieves existing one - * - * @param uri to be used for creating UriNode - * @param contentType to decide the content type of UriNode - * @return the UriNode that was created or modified /netgrif/process/test/all_data, /netgrif/process - */ - @Override - public UriNode getOrCreate(String uri, UriContentType contentType) { - if (!uri.startsWith(uriProperties.getSeparator())) { - uri = uriProperties.getSeparator() + uri; - } - - LinkedList uriNodeList = new LinkedList<>(); - String[] uriComponents = uri.split(uriProperties.getSeparator()); - if (uriComponents.length == 0) { - uriComponents = new String[]{uriProperties.getSeparator()}; - } else { - uriComponents[0] = uriProperties.getSeparator(); - } - StringBuilder uriBuilder = new StringBuilder(); - int pathLength = uriComponents.length; - UriNode parent = null; - - for (int i = 0; i < pathLength; i++) { - uriBuilder.append(uriComponents[i]); - UriNode uriNode = findByUri(uriBuilder.toString()); - if (uriNode == null) { - uriNode = new com.netgrif.application.engine.adapter.spring.petrinet.domain.UriNode(); - uriNode.setName(uriComponents[i]); - uriNode.setLevel(i); - uriNode.setPath(uriBuilder.toString()); - uriNode.setParentId(parent != null ? parent.getStringId() : null); - } - if (i == pathLength - 1 && contentType != null) { - uriNode.addContentType(contentType); - } - uriNode = uriNodeRepository.save((com.netgrif.application.engine.adapter.spring.petrinet.domain.UriNode) uriNode); - if (parent != null) { - parent.getChildrenId().add(uriNode.getStringId()); - uriNodeRepository.save((com.netgrif.application.engine.adapter.spring.petrinet.domain.UriNode) parent); - } - if (i > 0) { - uriBuilder.append(uriProperties.getSeparator()); - } - uriNodeList.add(uriNode); - parent = uriNode; - } - return uriNodeList.getLast(); - } - - /** - * Creates default UriNode - * - * @return the UriNode that was created or modified - */ - @Override - public UriNode createDefault() { - return getOrCreate(uriProperties.getSeparator() + uriProperties.getName(), UriContentType.DEFAULT); - } - - @Override - public String getUriSeparator() { - return uriProperties.getSeparator(); - } -} diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java index c11ff71c84b..606cce75c58 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java @@ -44,17 +44,10 @@ static DataFieldReference transformToReference(PetriNet net, Transition transiti @Deprecated ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, String releaseType, LoggedUser user) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException; - @Deprecated - ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, String releaseType, LoggedUser user, String uriNodeId) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException; - ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser user) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException; ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser user, Map params) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException; - ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser user, String uriNodeId) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException; - - ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser user, String uriNodeId, Map params) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException; - Optional save(PetriNet petriNet); PetriNet getPetriNet(String id); @@ -63,8 +56,6 @@ static DataFieldReference transformToReference(PetriNet net, Transition transiti List getByIdentifier(String identifier); - List findAllByUriNodeId(String uriNodeId); - List findAllById(List ids); PetriNet getNewestVersionByIdentifier(String identifier); diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IUriService.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IUriService.java deleted file mode 100644 index ec8d97183c9..00000000000 --- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IUriService.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.netgrif.application.engine.petrinet.service.interfaces; - -import com.netgrif.application.engine.objects.petrinet.domain.UriContentType; -import com.netgrif.application.engine.objects.petrinet.domain.UriNode; - -import java.util.List; - -public interface IUriService { - - /** - * Saves UriNode object to database - * - * @param uriNode to be saved - */ - UriNode save(UriNode uriNode); - - /** - * Retrieves all UriNode based on parent ID - * - * @param parentId ID of parent UriNode - * @return list of UriNode - */ - List findAllByParent(String parentId); - - /** - * Retrieves UriNode that is root node - * - * @return root UriNode - */ - UriNode getRoot(); - - UriNode getDefault(); - - /** - * Retrieves UriNode based on level - * - * @param level of UriNode - * @return UriNode - */ - List findByLevel(int level); - - /** - * Retrieves UriNode based on ID - * - * @param id ID of UriNode - * @return UriNode - */ - UriNode findById(String id); - - /** - * Retrieves UriNode based on uri - * - * @param path of UriNode - * @return UriNode - */ - UriNode findByUri(String path); - - /** - * Collects direct relatives (parent and children) of input UriNode and returns filled object - * - * @param uriNode to be filled with relatives - * @return filled UriNode - */ - UriNode populateDirectRelatives(UriNode uriNode); - - /** - * Moves UriNode to other destination - * - * @param uri to be moved - * @param destUri the destination URI - * @return result UriNode object - */ - UriNode move(String uri, String destUri); - - /** - * Moves UriNode to other destination - * - * @param node to be moved - * @param destUri the destination URI - * @return result UriNode object - */ - UriNode move(UriNode node, String destUri); - - /** - * Creates new UriNode from URI path, or retrieves existing one - * - * @param uri to be used for creating UriNode - * @param contentType to decide the content type of UriNode - * @return the UriNode that was created or modified - */ - UriNode getOrCreate(String uri, UriContentType contentType); - - /** - * Creates default UriNode - * - * @return the UriNode that was created or modified - */ - UriNode createDefault(); - - /** - * Returns configured uri separator - */ - String getUriSeparator(); -} diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/PetriNetController.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/PetriNetController.java index 46e23c8a33e..de7f2489a27 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/PetriNetController.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/PetriNetController.java @@ -105,16 +105,14 @@ public static String decodeUrl(String s1) { @PostMapping(value = "/import", produces = MediaTypes.HAL_JSON_VALUE) public EntityModel importPetriNet( @RequestParam(value = "file", required = true) MultipartFile multipartFile, - @RequestParam(value = "uriNodeId", required = true) String uriNodeId, @RequestParam(value = "meta", required = false) String releaseType, Authentication auth, Locale locale) throws MissingPetriNetMetaDataException, MissingIconKeyException { try { - String decodedUriNodeId = new String(Base64.decodeBase64(uriNodeId)); VersionType release = releaseType == null ? VersionType.MAJOR : VersionType.valueOf(releaseType.trim().toUpperCase()); - ImportPetriNetEventOutcome importPetriNetOutcome = service.importPetriNet(multipartFile.getInputStream(), release, (LoggedUser) auth.getPrincipal(), decodedUriNodeId); + ImportPetriNetEventOutcome importPetriNetOutcome = service.importPetriNet(multipartFile.getInputStream(), release, (LoggedUser) auth.getPrincipal()); return EventOutcomeWithMessageResource.successMessage("Petri net " + multipartFile.getOriginalFilename() + " imported successfully", LocalisedEventOutcomeFactory.from(importPetriNetOutcome, locale)); - } catch (IOException e) { + } catch (IOException | IllegalArgumentException e) { log.error("Importing Petri net failed: ", e); return EventOutcomeWithMessageResource.errorMessage("IO error while importing Petri net"); } catch (MissingPetriNetMetaDataException e) { diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/UriController.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/UriController.java deleted file mode 100644 index 07bd3de8e63..00000000000 --- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/UriController.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.netgrif.application.engine.petrinet.web; - -import com.netgrif.application.engine.objects.petrinet.domain.UriNode; -import com.netgrif.application.engine.petrinet.service.interfaces.IUriService; -import com.netgrif.application.engine.petrinet.web.responsebodies.UriNodeResource; -import com.netgrif.application.engine.petrinet.web.responsebodies.UriNodeResources; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.hateoas.CollectionModel; -import org.springframework.hateoas.EntityModel; -import org.springframework.hateoas.MediaTypes; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Base64; -import java.util.List; - -@RestController -@RequestMapping("/api/uri") -@Tag(name = "Process URI") -public class UriController { - - private final IUriService uriService; - - - public UriController(IUriService uriService) { - this.uriService = uriService; - } - - @Operation(summary = "Get root UriNodes", security = {@SecurityRequirement(name = "BasicAuth")}) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK"), - }) - @GetMapping(value = "/root", produces = MediaTypes.HAL_JSON_VALUE) - public EntityModel getRoot() { - UriNode uriNode = uriService.getRoot(); - uriService.populateDirectRelatives(uriNode); - return new UriNodeResource(uriNode); - } - - @Operation(summary = "Get one UriNode by URI path", security = {@SecurityRequirement(name = "BasicAuth")}) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK"), - }) - @GetMapping(value = "/{uri}", produces = MediaTypes.HAL_JSON_VALUE) - public EntityModel getOne(@PathVariable("uri") String uri) { - uri = new String(Base64.getDecoder().decode(uri)); - UriNode uriNode = uriService.findByUri(uri); - uriNode = uriService.populateDirectRelatives(uriNode); - return new UriNodeResource(uriNode); - } - - @Operation(summary = "Get UriNodes by parent id", security = {@SecurityRequirement(name = "BasicAuth")}) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK"), - }) - @GetMapping(value = "/parent/{parentId}", produces = MediaTypes.HAL_JSON_VALUE) - public CollectionModel getByParent(@PathVariable("parentId") String parentId) { - List uriNodes = uriService.findAllByParent(parentId); - uriNodes.forEach(uriService::populateDirectRelatives); - return new UriNodeResources(uriNodes); - } - - @Operation(summary = "Get UriNodes by on the same level", security = {@SecurityRequirement(name = "BasicAuth")}) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK"), - }) - @GetMapping(value = "/level/{level}", produces = MediaTypes.HAL_JSON_VALUE) - public CollectionModel getByLevel(@PathVariable("level") int level) { - List uriNodes = uriService.findByLevel(level); - uriNodes.forEach(uriService::populateDirectRelatives); - return new UriNodeResources(uriNodes); - } -} diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/responsebodies/UriNodeResource.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/responsebodies/UriNodeResource.java deleted file mode 100644 index cdf6e685150..00000000000 --- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/responsebodies/UriNodeResource.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.netgrif.application.engine.petrinet.web.responsebodies; - -import com.netgrif.application.engine.objects.petrinet.domain.UriNode; -import com.netgrif.application.engine.petrinet.web.UriController; -import org.springframework.hateoas.EntityModel; -import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; - -public class UriNodeResource extends EntityModel { - - public UriNodeResource(UriNode content) { - super(content); - buildLinks(); - } - - private void buildLinks() { - UriNode content = getContent(); - if (content != null) { - add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder - .methodOn(UriController.class).getRoot()) - .withSelfRel()); - - add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder - .methodOn(UriController.class).getOne(content.getPath())) - .withSelfRel()); - } - } -} diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/responsebodies/UriNodeResources.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/responsebodies/UriNodeResources.java deleted file mode 100644 index f6102fde6a2..00000000000 --- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/responsebodies/UriNodeResources.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.netgrif.application.engine.petrinet.web.responsebodies; - -import com.netgrif.application.engine.objects.petrinet.domain.UriNode; -import com.netgrif.application.engine.petrinet.web.UriController; -import org.springframework.hateoas.CollectionModel; -import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; - -public class UriNodeResources extends CollectionModel { - - public UriNodeResources(Iterable content) { - super(content); - buildLinks(); - } - - private void buildLinks() { - add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(UriController.class) - .getRoot()).withRel("root")); - } -} diff --git a/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/PluginRunner.java b/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/PluginRunner.java new file mode 100644 index 00000000000..b0088cf1917 --- /dev/null +++ b/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/PluginRunner.java @@ -0,0 +1,59 @@ +package com.netgrif.application.engine.startup.runner; + +import com.netgrif.application.engine.adapter.spring.plugin.config.PluginRegistrationConfiguration; +import com.netgrif.application.engine.objects.plugin.domain.Plugin; +import com.netgrif.application.engine.plugin.PluginInjector; +import com.netgrif.application.engine.startup.ApplicationEngineStartupRunner; +import com.netgrif.application.engine.startup.annotation.RunnerOrder; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Component +@RunnerOrder(85) +@ConditionalOnProperty( + value = "nae.plugin.enabled", + havingValue = "true", + matchIfMissing = true +) +public class PluginRunner implements ApplicationEngineStartupRunner { + + private final ApplicationContext applicationContext; + private final PluginInjector pluginInjector; + + public PluginRunner(ApplicationContext applicationContext, + PluginInjector pluginInjector) { + this.applicationContext = applicationContext; + this.pluginInjector = pluginInjector; + } + + @Override + public void run(ApplicationArguments args) throws Exception { + log.info("Registering plugins."); + Map pluginMap = new HashMap<>(); + + applicationContext.getBeansOfType(PluginRegistrationConfiguration.class).forEach((key, config) -> { + if (!pluginMap.containsKey(config.getPluginName())) { + Plugin plugin = Plugin.builder() + .identifier(config.getPluginName()) + .name(config.getPluginName()) + .version(config.getVersion()) + .description(StringUtils.EMPTY) + .entryPoints(config.getEntryPoints()) + .build(); + pluginMap.put(config.getPluginName(), plugin); + } + }); + pluginMap.values().forEach(pluginInjector::inject); + } + +} + diff --git a/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/UriRunner.java b/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/UriRunner.java deleted file mode 100644 index 40cf9c633e3..00000000000 --- a/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/UriRunner.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.netgrif.application.engine.startup.runner; - -import com.netgrif.application.engine.petrinet.service.interfaces.IUriService; -import com.netgrif.application.engine.startup.ApplicationEngineStartupRunner; -import com.netgrif.application.engine.startup.annotation.RunnerOrder; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.ApplicationArguments; -import org.springframework.stereotype.Component; - -@Slf4j -@Component -@RunnerOrder(80) -@RequiredArgsConstructor -public class UriRunner implements ApplicationEngineStartupRunner { - - private final IUriService uriService; - - @Override - public void run(ApplicationArguments args) throws Exception { - uriService.createDefault(); - } - -} diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/domain/repositories/CaseRepository.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/domain/repositories/CaseRepository.java index 875ba17451e..306bf0b83d4 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/domain/repositories/CaseRepository.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/domain/repositories/CaseRepository.java @@ -26,8 +26,6 @@ public interface CaseRepository extends MongoRepository, QuerydslP @Query("{ '_id.objectId': { $in: ?0 } }") List findAllByObjectIdsIn(List objectIds); - Page findAllByUriNodeId(String uri, Pageable pageable); - List findAllByPetriNetObjectId(ObjectId petriNetObjectId); void deleteAllByPetriNetObjectId(ObjectId petriNetObjectId); diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java index 9e533aac5ab..507d2ec96c4 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java @@ -194,14 +194,6 @@ public Page getAll(Pageable pageable) { return setImmediateDataFields(page); } - @Override - public Page findAllByUri(String uri, Pageable pageable) { - Page page = repository.findAllByUriNodeId(uri, pageable); - page.getContent().forEach(this::setPetriNet); - decryptDataSets(page.getContent()); - return setImmediateDataFields(page); - } - @Override public Page search(Predicate predicate, Pageable pageable) { Page page = repository.findAll(predicate, pageable); @@ -336,7 +328,6 @@ public CreateCaseEventOutcome createCase(String netId, Function ma useCase.setAuthor(loggedOrImpersonated.transformToAuthor()); useCase.setCreationDate(LocalDateTime.now()); useCase.setTitle(makeTitle.apply(useCase)); - useCase.setUriNodeId(petriNet.getUriNodeId()); CreateCaseEventOutcome outcome = new CreateCaseEventOutcome(); outcome.addOutcomes(eventService.runActions(petriNet.getPreCreateActions(), null, Optional.empty(), params)); diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java index 6b676a1b002..436a376bc4a 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java @@ -83,7 +83,5 @@ public interface IWorkflowService { Case decrypt(Case useCase); - Page findAllByUri(String uri, Pageable pageable); - Page search(Predicate predicate, Pageable pageable); } diff --git a/application-engine/src/main/resources/petriNets/engine-processes/preference_item.xml b/application-engine/src/main/resources/petriNets/engine-processes/preference_item.xml index b7ce81cef97..719c2bbe784 100644 --- a/application-engine/src/main/resources/petriNets/engine-processes/preference_item.xml +++ b/application-engine/src/main/resources/petriNets/engine-processes/preference_item.xml @@ -161,8 +161,7 @@ String corrected = getCorrectedUri(newUri) if (corrected == newUri) { - def node = uriService.findByUri(newUri) - change moveDestUri options { findOptionsBasedOnSelectedNode(node) } + change moveDestUri options { findOptionsBasedOnSelectedNode(newUri) } } else { change moveDestUri value { splitUriPath(corrected) } } @@ -191,7 +190,7 @@ String prefixUri = selectedUri.value.join("/") prefixUri = prefixUri.replace("//","/") - String newUri = prefixUri + uriService.getUriSeparator() + newNodeName.value + String newUri = prefixUri + "/" + newNodeName.value def newNode = uriService.getOrCreate(newUri, com.netgrif.application.engine.objects.petrinet.domain.UriContentType.CASE) change selectedUri value { splitUriPath(newNode.uriPath) } @@ -249,7 +248,7 @@ menu_item_identifier: f.menu_item_identifier; change menu_item_identifier value { - def idx = nodePath.value.lastIndexOf(uriService.getUriSeparator()) + def idx = nodePath.value.lastIndexOf("/") return nodePath.value.substring(idx + 1) } diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy index 028d315abae..aade9cdcd3c 100644 --- a/application-engine/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy +++ b/application-engine/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy @@ -71,9 +71,6 @@ class TestHelper { @Autowired private ImpersonationRunner impersonationRunner - @Autowired - private UriRunner uriRunner - @Autowired private ElasticsearchRunner elasticsearchRunner @@ -101,7 +98,6 @@ class TestHelper { defaultRealmRunner.run() anonymousRoleRunner.run() systemUserRunner.run() - uriRunner.run() groupRunner.run() filterRunner.run() impersonationRunner.run() diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/action/MenuItemApiTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/action/MenuItemApiTest.groovy index 3d5afeb0cb7..909a08a77f0 100644 --- a/application-engine/src/test/groovy/com/netgrif/application/engine/action/MenuItemApiTest.groovy +++ b/application-engine/src/test/groovy/com/netgrif/application/engine/action/MenuItemApiTest.groovy @@ -9,7 +9,6 @@ import com.netgrif.application.engine.elastic.web.requestbodies.CaseSearchReques import com.netgrif.application.engine.objects.petrinet.domain.I18nString import com.netgrif.application.engine.objects.petrinet.domain.UriContentType import com.netgrif.application.engine.objects.petrinet.domain.UriNode -import com.netgrif.application.engine.petrinet.service.interfaces.IUriService import com.netgrif.application.engine.startup.runner.FilterRunner import com.netgrif.application.engine.startup.ImportHelper import com.netgrif.application.engine.objects.workflow.domain.Case @@ -56,9 +55,6 @@ class MenuItemApiTest { @Autowired private IDataService dataService - @Autowired - private IUriService uriService - @Autowired private GroupService groupService @@ -81,8 +77,6 @@ class MenuItemApiTest { Case filter = getFilter(caze) Thread.sleep(4000) - UriNode leafNode = uriService.findByUri("/netgrif/test/new_menu_item") - assert item.uriNodeId == uriService.findByUri("/netgrif/test").stringId assert item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_MENU_ICON.attributeId].value == "device_hub" assert item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_MENU_NAME.attributeId].value == new I18nString("FILTER") assert item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_IDENTIFIER.attributeId].value.toString() == "new_menu_item" @@ -96,20 +90,16 @@ class MenuItemApiTest { assert filter.dataSet["filter"].allowedNets == ["filter", "preference_item"] assert filter.dataSet["filter"].value == "processIdentifier:filter OR processIdentifier:preference_item" assert filter.dataSet["filter_type"].value == "Case" - assert leafNode != null Case testFolder = findCasesElastic("processIdentifier:$FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER AND dataSet.${MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.attributeId}.textValue.keyword:\"/netgrif/test\"", PageRequest.of(0, 1))[0] Case netgrifFolder = findCasesElastic("processIdentifier:$FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER AND dataSet.${MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.attributeId}.textValue.keyword:\"/netgrif\"", PageRequest.of(0, 1))[0] - UriNode testNode = uriService.findByUri("/netgrif") - UriNode netgrifNode = uriService.getRoot() + Case rootFolder = findCasesElastic("processIdentifier:$FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER AND dataSet.${MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.attributeId}.textValue.keyword:\"/\"", PageRequest.of(0, 1))[0] - assert testFolder != null && testNode != null - assert testFolder.uriNodeId == testNode.stringId + assert testFolder.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.attributeId].value == [netgrifFolder.stringId] assert (testFolder.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.attributeId].value as ArrayList).contains(item.stringId) assert item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.attributeId].value == [testFolder.stringId] - assert netgrifFolder.uriNodeId == netgrifNode.stringId assert netgrifFolder.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.attributeId].value == [rootFolder.stringId] assert (netgrifFolder.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.attributeId].value as ArrayList).contains(testFolder.stringId) assert rootFolder.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_PARENT_ID.attributeId].value == [] @@ -120,9 +110,8 @@ class MenuItemApiTest { void testChangeFilterAndMenuItems() { Case caze = createMenuItem() Thread.sleep(3000) - def newUri = uriService.getOrCreate("/netgrif/test_new", UriContentType.DEFAULT) caze = setData(caze, [ - "uri": newUri.path, + "uri": "/netgrif/test_new", "title": "CHANGED FILTER", "allowed_nets": "filter", "query": "processIdentifier:filter", @@ -137,7 +126,6 @@ class MenuItemApiTest { assert item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_ALLOWED_ROLES.attributeId].options.entrySet()[0].key.contains("role_2") assert item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CASE_DEFAULT_HEADERS.attributeId].value == "meta-title,meta-title,meta-title" assert item.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_TASK_DEFAULT_HEADERS.attributeId].value == "meta-title,meta-title,meta-title" - assert item.uriNodeId == newUri.stringId assert filter.dataSet["filter"].allowedNets == ["filter"] assert filter.dataSet["filter"].filterMetadata["defaultSearchCategories"] == false @@ -176,10 +164,8 @@ class MenuItemApiTest { Case viewCase = workflowService.findOne(viewId) Thread.sleep(2000) - UriNode node = uriService.findByUri("/netgrif2") Case folderCase = findCasesElastic("processIdentifier:$FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER AND dataSet.${MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.attributeId}.textValue:\"/netgrif2\"", PageRequest.of(0, 1))[0] - assert viewCase.uriNodeId == node.stringId ArrayList childIds = folderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.attributeId].value as ArrayList assert childIds.contains(viewId) && childIds.size() == 2 @@ -210,22 +196,15 @@ class MenuItemApiTest { folderCase = findCasesElastic("processIdentifier:$FilterRunner.PREFERRED_ITEM_NET_IDENTIFIER AND dataSet.${MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.attributeId}.textValue:\"/netgrif/test3/netgrif2\"", PageRequest.of(0, 1))[0] assert folderCase != null - node = uriService.findByUri("/netgrif/test3") - assert node != null - assert folderCase.uriNodeId == node.stringId assert folderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.attributeId].value == "/netgrif/test3/netgrif2" childIds = folderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_CHILD_ITEM_IDS.attributeId].value as ArrayList assert childIds.size() == 2 folderCase = workflowService.findOne(childIds[0]) - node = uriService.findByUri("/netgrif/test3/netgrif2") assert folderCase.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_NODE_PATH.attributeId].value == "/netgrif/test3/netgrif2/test2" - assert folderCase.uriNodeId == node.stringId viewCase = workflowService.findOne(viewId2) - node = uriService.findByUri("/netgrif/test3/netgrif2/test2") - assert viewCase.uriNodeId == node.stringId } @Test @@ -264,10 +243,7 @@ class MenuItemApiTest { Case duplicated = workflowService.searchOne(QCase.case$.processIdentifier.eq("preference_item").and(QCase.case$.dataSet.get(MenuItemConstants.PREFERENCE_ITEM_FIELD_IDENTIFIER.attributeId).value.eq(newIdentifier))) assert duplicated != null - UriNode leafNode = uriService.findByUri("/netgrif/" + newIdentifier) - assert duplicated.uriNodeId == testFolder.uriNodeId - assert leafNode != null assert duplicated.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_DUPLICATE_TITLE.attributeId].value == null assert duplicated.dataSet[MenuItemConstants.PREFERENCE_ITEM_FIELD_DUPLICATE_IDENTIFIER.attributeId].value == null assert duplicated.title == newTitle diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovy index d05881f3f2f..088363f180d 100644 --- a/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovy +++ b/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovy @@ -75,9 +75,6 @@ class PetriNetServiceTest { @Autowired private PetriNetRepository petriNetRepository - @Autowired - private UriService uriService - @Autowired private CaseRepository caseRepository @@ -114,8 +111,6 @@ class PetriNetServiceTest { PetriNet testNet = testNetOptional.getNet() Thread.sleep(5000) ElasticPetriNet elasticTestNet = elasticPetriNetRepository.findByStringId(testNet.stringId) - assert elasticTestNet != null && elasticTestNet.getUriNodeId() == uriService.getRoot().id - assert testNet.getUriNodeId() == uriService.getRoot().id assert petriNetRepository.findById(testNet.stringId).get().uriNodeId == null importHelper.createCase("Case 1", testNet) @@ -154,18 +149,6 @@ class PetriNetServiceTest { assert exceptionThrown } - @Test - void findAllByUriNodeIdTest() { - UriNode myNode = uriService.getOrCreate("/test", UriContentType.DEFAULT) - petriNetService.importPetriNet(stream(NET_FILE), VersionType.MAJOR, superCreator.getLoggedSuper(), myNode.id) - petriNetService.importPetriNet(stream(NET_FILE), VersionType.MAJOR, superCreator.getLoggedSuper(), myNode.id) - - Thread.sleep(2000) - - List petriNets = petriNetService.findAllByUriNodeId(myNode.id) - assert petriNets.size() == 2 - } - @Test void processSearch() { long processCount = petriNetRepository.count() diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/UriServiceTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/UriServiceTest.groovy deleted file mode 100644 index 6d1f22a44d6..00000000000 --- a/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/UriServiceTest.groovy +++ /dev/null @@ -1,170 +0,0 @@ -package com.netgrif.application.engine.petrinet.service - -import com.netgrif.application.engine.TestHelper -import com.netgrif.application.engine.configuration.properties.UriProperties -import com.netgrif.application.engine.objects.petrinet.domain.UriContentType -import com.netgrif.application.engine.objects.petrinet.domain.UriNode -import com.netgrif.application.engine.petrinet.domain.repository.UriNodeRepository -import com.netgrif.application.engine.petrinet.service.interfaces.IUriService -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.ActiveProfiles -import org.springframework.test.context.junit.jupiter.SpringExtension - -import static org.junit.jupiter.api.Assertions.assertThrows - -@SpringBootTest -@ActiveProfiles(["test"]) -@ExtendWith(SpringExtension.class) -class UriServiceTest { - - private static final String testUri1 = "/test/uri/child1" - private static final String testUri2 = "/test/uri/child2" - private static final String testUri3 = "/test/uri/child1/grandchild" - private static final String testUri4 = "/test/uri/child1/grandchild" - private static final String testUri5wrong = "test/uri/child3/grandchild" - private static final String testUri5 = "/test/uri/child3/grandchild" - private static final String testUri5parent = "/test/uri/child3" - private static final String testUri6wrong = "" - private static final String testUri6 = "/" - private static final String destination = "destination/path" - - @Autowired - private IUriService uriService - - @Autowired - private UriProperties uriProperties - - @Autowired - private TestHelper testHelper - - @Autowired - UriNodeRepository uriNodeRepository - - @BeforeEach - void init() { - testHelper.truncateDbs() - uriService.getOrCreate(testUri1, UriContentType.DEFAULT) - uriService.getOrCreate(testUri2, UriContentType.DEFAULT) - uriService.getOrCreate(testUri3, UriContentType.DEFAULT) - uriService.getOrCreate(testUri4, UriContentType.DEFAULT) - } - - @Test - void getOrCreateTest() { - String[] splitUri = testUri3.split(uriProperties.separator) - splitUri[0] = "/" - UriNode uriNode = uriService.getOrCreate(testUri3, UriContentType.CASE) - assert uriNode != null && uriNode.getName() == splitUri[splitUri.length - 1] - assert uriNode.parentId == uriNodeRepository.findByPath(testUri1).stringId - assert uriNode.contentTypes.size() == 2 && uriNode.contentTypes.contains(UriContentType.DEFAULT) - assert uriNode.getChildrenId().isEmpty() - assert uriNode.level == 4 - - uriNode = uriService.getOrCreate(testUri1, UriContentType.CASE) - assert uriNode.getChildrenId().size() == 1 && uriNode.getChildrenId().contains(uriNodeRepository.findByPath(testUri3).stringId) - assert uriNode.containsCase() - - uriNode = uriService.getOrCreate(testUri5wrong, UriContentType.PROCESS) - assert uriNode != null && uriNode.stringId == uriNodeRepository.findByPath(testUri5).stringId - assert uriNode.parentId == uriNodeRepository.findByPath(testUri5parent).stringId - assert uriNode.containsNet() - - uriNode = uriService.getOrCreate(testUri6wrong, UriContentType.DEFAULT) - assert uriNode.stringId == uriNodeRepository.findByPath(testUri6).stringId - assert uriNode.parentId == null - assert uriNode.level == 0 - } - - @Test - void getRootsTest() { - UriNode root = uriService.getRoot() - assert root.getParentId() == null - - UriNode root2 = new com.netgrif.application.engine.adapter.spring.petrinet.domain.UriNode() - root2.setLevel(0) - uriService.save(root2) - - assertThrows(IllegalStateException.class, () -> { - uriService.getRoot() - }) - } - - @Test - void populateDirectRelativesTest() { - UriNode uriNode = uriService.getOrCreate(testUri1, UriContentType.DEFAULT) - uriNode = uriService.populateDirectRelatives(uriNode) - - assert uriNode.parent != null && uriNode.parent.stringId == uriNode.parentId - assert uriNode.children.size() == 1 && uriNode.children.find {it.stringId == uriNode.childrenId[0]} != null - } - - @Test - void moveTest() { - prepareDatabase(List.of("/a/b/c")) - UriNode cNode = uriService.move("/a/b/c", "/a") - UriNode aNode = uriService.findByUri("/a") - UriNode bNode = uriService.findByUri("/a/b") - assert cNode.parentId == aNode.stringId && bNode.childrenId.size() == 0 - - prepareDatabase(List.of("/a/b/c", "/a/b/d")) - bNode = uriService.move("/a/b", "/") - aNode = uriService.findByUri("/a") - cNode = uriService.findByUri("/b/c") - UriNode rootNode = uriService.findByUri("/") - assert aNode.childrenId.size() == 0 && bNode.childrenId.size() == 2 && cNode.parentId == bNode.stringId - assert rootNode.childrenId.size() == 2 - - prepareDatabase(List.of("/a/b/c")) - assertThrows(IllegalArgumentException.class, () -> { - uriService.move("/a/b", "/a/b/c/d") - }) - - prepareDatabase(List.of("/a/b/c")) - bNode = uriService.move("/a/b", "d") - aNode = uriService.findByUri("/a") - UriNode dNode = uriService.findByUri("/d") - assert aNode.childrenId.size() == 0 - assert dNode.childrenId.size() == 1 - assert bNode.childrenId.size() == 1 && bNode.parentId == dNode.stringId - } - - private prepareDatabase(List listOfUriPaths) { - uriNodeRepository.deleteAll() - listOfUriPaths.each {path -> - uriService.getOrCreate(path, UriContentType.DEFAULT) - } - } - - @Test - void findTest() { - UriNode uriNode = uriService.findByUri(testUri3) - assert uriNode != null - - assertThrows(IllegalArgumentException.class, () -> { - uriService.findById("notSavedId") - }) - } - - @Test - void createDefaultTest() { - UriNode uriNode = uriService.createDefault() - assert uriNode != null && uriNode.level == 1 - - uriNodeRepository.deleteById(uriNode.stringId) - - uriNode = uriService.createDefault() - assert uriNode != null && uriNode.level == 1 - } - - @Test - void getRootTest() { - UriNode uriNode = uriService.createDefault() - assert uriNode != null && uriNode.level == 1 - uriNode = uriService.getRoot() - assert uriNode != null && uriNode.level == 0 - } -} diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/workflow/WorkflowServiceTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/workflow/WorkflowServiceTest.groovy index 93b5942f9d8..c009207af15 100644 --- a/application-engine/src/test/groovy/com/netgrif/application/engine/workflow/WorkflowServiceTest.groovy +++ b/application-engine/src/test/groovy/com/netgrif/application/engine/workflow/WorkflowServiceTest.groovy @@ -102,7 +102,6 @@ class WorkflowServiceTest { def net = testNet.getNet() Case aCase = workflowService.createCase(net.stringId, null, null, superCreator.getLoggedSuper(), new Locale('sk')).getCase() assert aCase.title.equals("Slovenský preklad") - assert workflowService.findOne(aCase.stringId).uriNodeId == net.uriNodeId Case enCase = workflowService.createCase(net.stringId, null, null, superCreator.getLoggedSuper(), new Locale('en')).getCase() assert enCase.title.equals("English translation") diff --git a/application-engine/src/test/java/com/netgrif/application/engine/workflow/service/TaskServiceTest.java b/application-engine/src/test/java/com/netgrif/application/engine/workflow/service/TaskServiceTest.java index eaa7e5ba9e0..9b0e6986b04 100644 --- a/application-engine/src/test/java/com/netgrif/application/engine/workflow/service/TaskServiceTest.java +++ b/application-engine/src/test/java/com/netgrif/application/engine/workflow/service/TaskServiceTest.java @@ -17,7 +17,6 @@ import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService; import com.netgrif.application.engine.startup.runner.SuperCreatorRunner; import com.netgrif.application.engine.startup.runner.SystemUserRunner; -import com.netgrif.application.engine.startup.runner.UriRunner; import com.netgrif.application.engine.objects.workflow.domain.Case; import com.netgrif.application.engine.objects.workflow.domain.Task; import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.caseoutcomes.CreateCaseEventOutcome; @@ -71,9 +70,6 @@ public class TaskServiceTest { @Autowired private SystemUserRunner userRunner; - @Autowired - private UriRunner uriRunner; - @Autowired private IPetriNetService petriNetService; @@ -89,7 +85,6 @@ public void setUp() throws Exception { taskRepository.deleteAll(); realmRunner.run(null); userRunner.run(null); - uriRunner.run(null); petriNetService.importPetriNet(new FileInputStream("src/test/resources/prikladFM.xml"), VersionType.MAJOR, superCreator.getLoggedSuper()); PetriNet net = petriNetRepository.findAll().get(0); diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/ElasticCase.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/ElasticCase.java index f5c0d3246c6..53b16b2d14b 100644 --- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/ElasticCase.java +++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/ElasticCase.java @@ -31,8 +31,6 @@ public abstract class ElasticCase implements Serializable { private String id; - private String uriNodeId; - private Long version; private Long lastModified; @@ -92,7 +90,6 @@ public abstract class ElasticCase implements Serializable { public ElasticCase(Case useCase) { stringId = useCase.getStringId(); - uriNodeId = useCase.getUriNodeId(); mongoId = useCase.getStringId(); //TODO: Duplication lastModified = Timestamp.valueOf(useCase.getLastModified()).getTime(); processIdentifier = useCase.getProcessIdentifier(); @@ -121,9 +118,6 @@ public ElasticCase(Case useCase) { public void update(ElasticCase useCase) { version++; lastModified = useCase.getLastModified(); - if (useCase.getUriNodeId() != null) { - uriNodeId = useCase.getUriNodeId(); - } title = useCase.getTitle(); taskIds = useCase.getTaskIds(); taskMongoIds = useCase.getTaskMongoIds(); diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/plugin/domain/EntryPoint.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/plugin/domain/EntryPoint.java new file mode 100644 index 00000000000..cb24e307fb5 --- /dev/null +++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/plugin/domain/EntryPoint.java @@ -0,0 +1,40 @@ +package com.netgrif.application.engine.objects.plugin.domain; + +import lombok.Builder; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * Domain class for entry points. Entry points are beans annotated with {@link com.netgrif.plugin.core.annotations.EntryPoint} + * annotation. These beans contain methods, that can be run from server where the plugin is registered. + * */ +@Data +public class EntryPoint implements Serializable { + + @Serial + private static final long serialVersionUID = -4312516499873834830L; + + private String name; + + private String pluginName; + + /** + * Map of {@link Method}, key of the map is equivalent to {@link Method#getName()} + * */ + private Map methods; + + public EntryPoint() { + methods = new HashMap<>(); + } + + @Builder + public EntryPoint(String name, Map methods, String pluginName) { + this.name = name; + this.methods = methods; + this.pluginName = pluginName; + } +} diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/plugin/domain/ListenerFilter.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/plugin/domain/ListenerFilter.java new file mode 100644 index 00000000000..780ea1d4fb0 --- /dev/null +++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/plugin/domain/ListenerFilter.java @@ -0,0 +1,32 @@ +package com.netgrif.application.engine.objects.plugin.domain; + +import com.netgrif.application.engine.objects.event.dispatchers.common.AbstractDispatcher; +import lombok.Builder; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.EventObject; + +/** + * Domain class for listener filters. This filter define, which listener will call methods of this plugin. + * */ +@Data +public class ListenerFilter implements Serializable { + + @Serial + private static final long serialVersionUID = 892495676687111427L; + + private Class eventType; + + private AbstractDispatcher.DispatchMethod dispatchMethod; + + public ListenerFilter() { + } + + @Builder + public ListenerFilter(Class eventType, AbstractDispatcher.DispatchMethod dispatchMethod) { + this.eventType = eventType; + this.dispatchMethod = dispatchMethod; + } +} diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/plugin/domain/Method.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/plugin/domain/Method.java new file mode 100644 index 00000000000..555174ac5a4 --- /dev/null +++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/plugin/domain/Method.java @@ -0,0 +1,38 @@ +package com.netgrif.application.engine.objects.plugin.domain; + +import lombok.Builder; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * Domain class for plugin methods. This domain represents methods, that are implemented inside entry points + * and are annotated with {@code com.netgrif.application.engine.adapter.spring.plugin.annotations.EntryPointMethod} annotations. These methods + * can be run from server where the plugin is registered. + * */ +@Data +public class Method implements Serializable { + @Serial + private static final long serialVersionUID = -5007466888924505057L; + + private String name; + private List argTypes; + private String returnType; + private List listenerFilters; + + public Method() { + argTypes = new ArrayList<>(); + listenerFilters = new ArrayList<>(); + } + + @Builder + public Method(String name, List argTypes, String returnType, List listenerFilters) { + this.name = name; + this.argTypes = argTypes; + this.returnType = returnType; + this.listenerFilters = listenerFilters; + } +} diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/plugin/domain/Plugin.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/plugin/domain/Plugin.java new file mode 100644 index 00000000000..8aac391e067 --- /dev/null +++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/plugin/domain/Plugin.java @@ -0,0 +1,57 @@ +package com.netgrif.application.engine.objects.plugin.domain; + +import lombok.Builder; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * Domain class that represent the given plugin + * */ +@Data +public class Plugin implements Serializable { + + @Serial + private static final long serialVersionUID = -8675728293188640186L; + + private String identifier; + + private String name; + + private String version; + + private String description; + + private String url; + + private int restPort; + + private int grpcPort; + + private boolean active; + + /** + * Map of {@link EntryPoint}, key of the map is equivalent to {@link EntryPoint#getName()} + * */ + private Map entryPoints; + + public Plugin() { + entryPoints = new HashMap<>(); + } + + @Builder + public Plugin(String identifier, String name, String version, String description, String url, int restPort, int grpcPort, Map entryPoints, boolean active) { + this.identifier = identifier; + this.name = name; + this.version = version; + this.description = description; + this.url = url; + this.restPort = restPort; + this.grpcPort = grpcPort; + this.entryPoints = entryPoints; + this.active = active; + } +} diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/Case.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/Case.java index 51d11b58465..c6454cf8056 100644 --- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/Case.java +++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/Case.java @@ -30,9 +30,6 @@ public abstract class Case implements Serializable { @Setter private ProcessResourceId _id; - @Setter - private String uriNodeId; - @Setter private LocalDateTime lastModified; diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemBody.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemBody.java index 90369639070..f123d4af9e2 100644 --- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemBody.java +++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemBody.java @@ -4,6 +4,7 @@ import com.netgrif.application.engine.objects.petrinet.domain.dataset.FieldType; import com.netgrif.application.engine.objects.workflow.domain.Case; import lombok.Data; +import lombok.Getter; import lombok.NoArgsConstructor; import jakarta.annotation.Nullable; @@ -26,7 +27,8 @@ public class MenuItemBody { private I18nString tabName; private String menuIcon = "filter_none"; private String tabIcon; - private String uri; + @Getter + private String path; private String identifier; private Case filter; private Map allowedRoles; @@ -76,8 +78,8 @@ public MenuItemBody(I18nString menuName, I18nString tabName, String menuIcon, St this.tabIcon = tabIcon; } - public MenuItemBody(String uri, String identifier, I18nString name, String icon) { - this.uri = uri; + public MenuItemBody(String path, String identifier, I18nString name, String icon) { + this.path = path; this.identifier = identifier; this.menuName = name; this.tabName = name; @@ -85,8 +87,8 @@ public MenuItemBody(String uri, String identifier, I18nString name, String icon) this.tabIcon = icon; } - public MenuItemBody(String uri, String identifier, I18nString menuName, I18nString tabName, String menuIcon, String tabIcon) { - this.uri = uri; + public MenuItemBody(String path, String identifier, I18nString menuName, I18nString tabName, String menuIcon, String tabIcon) { + this.path = path; this.identifier = identifier; this.menuName = menuName; this.tabName = tabName; @@ -94,8 +96,8 @@ public MenuItemBody(String uri, String identifier, I18nString menuName, I18nStri this.tabIcon = tabIcon; } - public MenuItemBody(String uri, String identifier, String name, String icon) { - this.uri = uri; + public MenuItemBody(String path, String identifier, String name, String icon) { + this.path = path; this.identifier = identifier; this.menuName = new I18nString(name); this.tabName = new I18nString(name); @@ -103,8 +105,8 @@ public MenuItemBody(String uri, String identifier, String name, String icon) { this.tabIcon = icon; } - public MenuItemBody(String uri, String identifier, String menuName, String tabName, String menuIcon, String tabIcon) { - this.uri = uri; + public MenuItemBody(String path, String identifier, String menuName, String tabName, String menuIcon, String tabIcon) { + this.path = path; this.identifier = identifier; this.menuName = new I18nString(menuName); this.tabName = new I18nString(tabName); @@ -117,7 +119,7 @@ private static void putDataSetEntry(Map> dataSet, Me Map fieldMap = new LinkedHashMap<>(); fieldMap.put("type", fieldType.getName()); fieldMap.put("value", fieldValue); - dataSet.put(fieldId.getAttributeId(), fieldMap); + dataSet.put(fieldId.getValue(), fieldMap); } private static String sanitize(String input) { @@ -159,6 +161,10 @@ public Map> toDataSet(String parentId, String nodePa return toDataSet(parentId, nodePath, false); } + public void setPath(String path) { + this.path = path != null ? path.trim() : null; + } + private Map> toDataSet(String parentId, String nodePath, boolean ignoreParentId) { Map> dataSet = new LinkedHashMap<>(); diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemConstants.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemConstants.java index 1484b4847f1..d31b84d8f77 100644 --- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemConstants.java +++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemConstants.java @@ -55,11 +55,15 @@ public enum MenuItemConstants { // TRANSITIONS PREFERENCE_ITEM_SETTINGS_TRANS_ID("item_settings"), - PREFERENCE_ITEM_FIELD_INIT_TRANS_ID("initialize"); + PREFERENCE_ITEM_FIELD_INIT_TRANS_ID("initialize"), + + // SEPARATOR + PATH_SEPARATOR("/"); + @Getter - private final String attributeId; + private final String value; - MenuItemConstants(String attributeId) { - this.attributeId = attributeId; + MenuItemConstants(String value) { + this.value = value; } } diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/elastic/domain/ElasticCase.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/elastic/domain/ElasticCase.java index b67c0461773..52284d0a626 100644 --- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/elastic/domain/ElasticCase.java +++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/elastic/domain/ElasticCase.java @@ -33,11 +33,6 @@ public String getId() { return super.getId(); } - @Field(type = Keyword) - public String getUriNodeId() { - return super.getUriNodeId(); - } - @Version public Long getVersion() { return super.getVersion(); diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/annotations/EntryPoint.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/annotations/EntryPoint.java new file mode 100644 index 00000000000..e97e9ba96ee --- /dev/null +++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/annotations/EntryPoint.java @@ -0,0 +1,28 @@ +package com.netgrif.application.engine.adapter.spring.plugin.annotations; + +import org.springframework.core.annotation.AliasFor; +import org.springframework.stereotype.Service; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation is used in NAE Plugin library to mark classes as they are Spring Beans (kind of + * {@link Service}), that implement remotely callable plugin methods. These methods have + * to be marked with {@link EntryPointMethod}. + * */ +@Service +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface EntryPoint { + @AliasFor("name") + String value() default ""; + @AliasFor("value") + String name() default ""; + /** + * This is only considered when plugin is loaded as module. + * */ + String pluginName() default ""; +} diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/annotations/EntryPointMethod.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/annotations/EntryPointMethod.java new file mode 100644 index 00000000000..cb04c613499 --- /dev/null +++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/annotations/EntryPointMethod.java @@ -0,0 +1,19 @@ +package com.netgrif.application.engine.adapter.spring.plugin.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation is used in NAE Plugin library to mark methods, that can be called from NAE application, + * that the given plugin is attached to. These methods must be implemented as member of class, that is marked + * with {@link EntryPoint}. + * */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface EntryPointMethod { + String name() default ""; + String description() default ""; + ListenerFilter[] listeners() default {}; +} diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/annotations/ListenerFilter.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/annotations/ListenerFilter.java new file mode 100644 index 00000000000..22d513504d6 --- /dev/null +++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/annotations/ListenerFilter.java @@ -0,0 +1,16 @@ +package com.netgrif.application.engine.adapter.spring.plugin.annotations; + +import com.netgrif.application.engine.objects.event.dispatchers.common.AbstractDispatcher; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.EventObject; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ListenerFilter { + Class eventType(); + AbstractDispatcher.DispatchMethod dispatchMethod(); +} diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/config/PluginRegistrationConfiguration.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/config/PluginRegistrationConfiguration.java new file mode 100644 index 00000000000..43888adead3 --- /dev/null +++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/config/PluginRegistrationConfiguration.java @@ -0,0 +1,16 @@ +package com.netgrif.application.engine.adapter.spring.plugin.config; + +import com.netgrif.application.engine.objects.plugin.domain.EntryPoint; + +import java.util.Map; + +public interface PluginRegistrationConfiguration { + + String getPluginName(); + + String getVersion(); + + Map getEntryPoints(); + + Map getMetadata(); +} \ No newline at end of file diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/service/PluginService.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/service/PluginService.java new file mode 100644 index 00000000000..9f68c173fad --- /dev/null +++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/plugin/service/PluginService.java @@ -0,0 +1,8 @@ +package com.netgrif.application.engine.adapter.spring.plugin.service; + +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; + +public interface PluginService { + Object call(String pluginCaseId, String entryPoint, String method, Serializable... args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException; +}