diff --git a/config/alfresco/bootstrap/system.xml b/config/alfresco/bootstrap/system.xml index ea825f418e..9ac123b6ad 100644 --- a/config/alfresco/bootstrap/system.xml +++ b/config/alfresco/bootstrap/system.xml @@ -42,6 +42,7 @@ + diff --git a/config/alfresco/import-export-context.xml b/config/alfresco/import-export-context.xml index d2b6b474d7..e5b10d42ee 100644 --- a/config/alfresco/import-export-context.xml +++ b/config/alfresco/import-export-context.xml @@ -255,6 +255,7 @@ ${spaces.guest_home.childname} ${system.system_container.childname} ${system.people_container.childname} + ${system.workflow_container.childname} ${spaces.dictionary.childname} ${spaces.templates.childname} ${spaces.templates.content.childname} diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index 1ee0606d81..402fba27b9 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -74,4 +74,7 @@ patch.topLevelGroupParentChildAssociationTypePatch.err.sys_path_not_found=Requir patch.topLevelGroupParentChildAssociationTypePatch.err.auth_path_not_found=Required authority path not found: {0} patch.actionRuleDecouplingPatch.description=Migrate existing rules to the updated model where rules are decoupled from actions. -patch.actionRuleDecouplingPatch.result=Updated {0} rules. \ No newline at end of file +patch.actionRuleDecouplingPatch.result=Updated {0} rules. + +patch.systemWorkflowFolder.description=Ensures the existence of the system workflow container. +patch.systemWorkflowFolder.result.created=Created system workflow container {0}. \ No newline at end of file diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index 9cf5fd4909..5674a986cf 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -379,4 +379,14 @@ 15 + + patch.systemWorkflowFolderPatch + patch.systemWorkflowFolder.description + 0 + 15 + 16 + + + + diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index 95752d6830..bcfedefc8a 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -105,6 +105,10 @@ spaces.scripts.childname=app:scripts system.system_container.childname=sys:system system.people_container.childname=sys:people +# Folders for storing workflow related info + +system.workflow_container.childname=sys:workflow + # Are user names case sensitive? # ============================== # diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index 9069f83ce6..d309203a47 100644 --- a/config/alfresco/version.properties +++ b/config/alfresco/version.properties @@ -19,4 +19,4 @@ version.build=@build-number@ # Schema number -version.schema=15 +version.schema=16 diff --git a/config/alfresco/workflow-context.xml b/config/alfresco/workflow-context.xml index 1d3cd3e1a0..f6f8daf38f 100644 --- a/config/alfresco/workflow-context.xml +++ b/config/alfresco/workflow-context.xml @@ -28,6 +28,15 @@ + + + + + + + + + diff --git a/source/java/org/alfresco/repo/admin/patch/impl/SystemWorkflowFolderPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/SystemWorkflowFolderPatch.java new file mode 100644 index 0000000000..65d0c96ead --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/impl/SystemWorkflowFolderPatch.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.admin.patch.impl; + +import org.alfresco.i18n.I18NUtil; +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.workflow.WorkflowPackageImpl; +import org.alfresco.service.cmr.repository.NodeRef; + + +/** + * Ensures the system folder for Workflows is created. + * + * @author davidc + */ +public class SystemWorkflowFolderPatch extends AbstractPatch +{ + private static final String MSG_CREATED = "patch.systemWorkflowFolder.result.created"; + + private WorkflowPackageImpl workflowPackageImpl; + + public void setWorkflowPackageImpl(WorkflowPackageImpl workflowPackageImpl) + { + this.workflowPackageImpl = workflowPackageImpl; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.admin.patch.AbstractPatch#applyInternal() + */ + @Override + protected String applyInternal() throws Exception + { + NodeRef systemContainer = workflowPackageImpl.createSystemWorkflowContainer(); + return I18NUtil.getMessage(MSG_CREATED, systemContainer); + } + +} diff --git a/source/java/org/alfresco/repo/workflow/BPMEngine.java b/source/java/org/alfresco/repo/workflow/BPMEngine.java index 7083475f0c..82cae295b3 100644 --- a/source/java/org/alfresco/repo/workflow/BPMEngine.java +++ b/source/java/org/alfresco/repo/workflow/BPMEngine.java @@ -62,10 +62,6 @@ public class BPMEngine implements InitializingBean throw new WorkflowException("Engine Id not specified"); } - if (this instanceof WorkflowDefinitionComponent) - { - registry.registerWorkflowDefinitionComponent(engineId, (WorkflowDefinitionComponent)this); - } if (this instanceof WorkflowComponent) { registry.registerWorkflowComponent(engineId, (WorkflowComponent)this); diff --git a/source/java/org/alfresco/repo/workflow/BPMEngineRegistry.java b/source/java/org/alfresco/repo/workflow/BPMEngineRegistry.java index c2024b0a6d..3c37f98378 100644 --- a/source/java/org/alfresco/repo/workflow/BPMEngineRegistry.java +++ b/source/java/org/alfresco/repo/workflow/BPMEngineRegistry.java @@ -30,7 +30,6 @@ import org.apache.commons.logging.LogFactory; * Responsible for managing the list of registered BPM Engines for the * following components: * - * - Workflow Definition Component * - Workflow Component * - Task Component * @@ -44,7 +43,6 @@ public class BPMEngineRegistry /** Logging support */ private static Log logger = LogFactory.getLog("org.alfresco.repo.workflow"); - private Map workflowDefinitionComponents; private Map workflowComponents; private Map taskComponents; @@ -54,50 +52,10 @@ public class BPMEngineRegistry */ public BPMEngineRegistry() { - workflowDefinitionComponents = new HashMap(); workflowComponents = new HashMap(); taskComponents = new HashMap(); } - /** - * Register a BPM Engine Workflow Definition Component - * - * @param engineId engine id - * @param engine implementing engine - */ - public void registerWorkflowDefinitionComponent(String engineId, WorkflowDefinitionComponent engine) - { - if (workflowDefinitionComponents.containsKey(engineId)) - { - throw new WorkflowException("Workflow Definition Component already registered for engine id '" + engineId + "'"); - } - workflowDefinitionComponents.put(engineId, engine); - - if (logger.isInfoEnabled()) - logger.info("Registered Workflow Definition Component '" + engineId + "' (" + engine.getClass() + ")"); - } - - /** - * Gets all registered Workflow Definition Components - * - * @return array of engine ids - */ - public String[] getWorkflowDefinitionComponents() - { - return workflowDefinitionComponents.keySet().toArray(new String[workflowDefinitionComponents.keySet().size()]); - } - - /** - * Gets a specific BPM Engine Workflow Definition Component - * - * @param engineId engine id - * @return the Workflow Definition Component - */ - public WorkflowDefinitionComponent getWorkflowDefinitionComponent(String engineId) - { - return workflowDefinitionComponents.get(engineId); - } - /** * Register a BPM Engine Workflow Component * diff --git a/source/java/org/alfresco/repo/workflow/WorkflowComponent.java b/source/java/org/alfresco/repo/workflow/WorkflowComponent.java index a0f742e866..c397173f5d 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowComponent.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowComponent.java @@ -16,10 +16,12 @@ */ package org.alfresco.repo.workflow; +import java.io.InputStream; import java.io.Serializable; import java.util.List; import java.util.Map; +import org.alfresco.service.cmr.workflow.WorkflowDefinition; import org.alfresco.service.cmr.workflow.WorkflowInstance; import org.alfresco.service.cmr.workflow.WorkflowPath; import org.alfresco.service.cmr.workflow.WorkflowTask; @@ -34,6 +36,62 @@ import org.alfresco.service.namespace.QName; public interface WorkflowComponent { + // + // Workflow Definition Support + // + + + /** + * Deploy a Workflow Definition + * + * @param workflowDefinition the content object containing the definition + * @param mimetype (optional) the mime type of the workflow definition + * @return workflow definition + */ + public WorkflowDefinition deployDefinition(InputStream workflowDefinition, String mimetype); + + /** + * Is the specified Workflow Definition already deployed? + * + * Note: the notion of "already deployed" may differ between bpm engines. For example, + * different versions of the same process may be considered equal. + * + * @param workflowDefinition the definition to check + * @param mimetype the mimetype of the definition + * @return true => already deployed + */ + public boolean isDefinitionDeployed(InputStream workflowDefinition, String mimetype); + + /** + * Undeploy an exisiting Workflow Definition + * + * TODO: Determine behaviour when "in-flight" workflow instances exist + * + * @param workflowDefinitionId the id of the definition to undeploy + */ + public void undeployDefinition(String workflowDefinitionId); + + /** + * Gets all deployed Workflow Definitions + * + * @return the deployed workflow definitions + */ + public List getDefinitions(); + + /** + * Gets a Workflow Definition by unique Id + * + * @param workflowDefinitionId the workflow definition id + * @return the deployed workflow definition + */ + public WorkflowDefinition getDefinitionById(String workflowDefinitionId); + + + // + // Workflow Instance Support + // + + /** * Start a Workflow Instance * diff --git a/source/java/org/alfresco/repo/workflow/WorkflowDefinitionComponent.java b/source/java/org/alfresco/repo/workflow/WorkflowDefinitionComponent.java deleted file mode 100644 index db0530f7f1..0000000000 --- a/source/java/org/alfresco/repo/workflow/WorkflowDefinitionComponent.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.workflow; - -import java.io.InputStream; -import java.util.List; - -import org.alfresco.service.cmr.workflow.WorkflowDefinition; - - -/** - * SPI to be implemented by a BPM Engine that provides Workflow Definition management. - * - * @author davidc - */ -public interface WorkflowDefinitionComponent -{ - - /** - * Deploy a Workflow Definition - * - * @param workflowDefinition the content object containing the definition - * @param mimetype (optional) the mime type of the workflow definition - * @return workflow definition - */ - public WorkflowDefinition deployDefinition(InputStream workflowDefinition, String mimetype); - - /** - * Is the specified Workflow Definition already deployed? - * - * Note: the notion of "already deployed" may differ between bpm engines. For example, - * different versions of the same process may be considered equal. - * - * @param workflowDefinition the definition to check - * @param mimetype the mimetype of the definition - * @return true => already deployed - */ - public boolean isDefinitionDeployed(InputStream workflowDefinition, String mimetype); - - /** - * Undeploy an exisiting Workflow Definition - * - * TODO: Determine behaviour when "in-flight" workflow instances exist - * - * @param workflowDefinitionId the id of the definition to undeploy - */ - public void undeployDefinition(String workflowDefinitionId); - - /** - * Gets all deployed Workflow Definitions - * - * @return the deployed workflow definitions - */ - public List getDefinitions(); - - /** - * Gets a Workflow Definition by unique Id - * - * @param workflowDefinitionId the workflow definition id - * @return the deployed workflow definition - */ - public WorkflowDefinition getDefinitionById(String workflowDefinitionId); - -} - diff --git a/source/java/org/alfresco/repo/workflow/WorkflowModel.java b/source/java/org/alfresco/repo/workflow/WorkflowModel.java index 1b3b5de626..2e082cee7f 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowModel.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowModel.java @@ -41,5 +41,8 @@ public interface WorkflowModel static final QName TYPE_WORKFLOW_TASK = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowTask"); static final QName PROP_CONTEXT = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "context"); static final QName ASSOC_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "package"); + + // workflow package + static final QName ASPECT_WORKFLOW_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowPackage"); } diff --git a/source/java/org/alfresco/repo/workflow/WorkflowPackageComponent.java b/source/java/org/alfresco/repo/workflow/WorkflowPackageComponent.java new file mode 100644 index 0000000000..8a4675b3d2 --- /dev/null +++ b/source/java/org/alfresco/repo/workflow/WorkflowPackageComponent.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.workflow; + +import org.alfresco.service.cmr.repository.NodeRef; + + +/** + * Contract for managing Workflow Packages. A package is a container + * of Content that's routed through a Workflow. + * + * @author davidc + */ +public interface WorkflowPackageComponent +{ + + /** + * Create a Workflow Package (a container of content to route through the Workflow). + * + * If an existing container is supplied, it's supplemented with the workflow package aspect. + * + * @param container (optional) a pre-created container (e.g. folder, versioned folder or layered folder) + * @return the workflow package + */ + public NodeRef createPackage(NodeRef container); + + // TODO: Support for finding packages via meta-data of WorkflowPackage aspect + +} diff --git a/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java b/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java new file mode 100644 index 0000000000..3f15a29649 --- /dev/null +++ b/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.workflow; + +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.importer.ImporterBootstrap; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.cmr.workflow.WorkflowException; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.GUID; + + +/** + * Alfresco implementation of Workflow Package where the package is stored + * within the Alfresco Repository. + * + * @author davidc + */ +public class WorkflowPackageImpl implements WorkflowPackageComponent +{ + private final static String PACKAGE_FOLDER = "Workflow Packages"; + + // service dependencies + private ImporterBootstrap bootstrap; + private SearchService searchService; + private NodeService nodeService; + private NamespaceService namespaceService; + private FileFolderService fileFolderService; + private NodeRef systemWorkflowContainer = null; + + + /** + * @param bootstrap the importer bootstrap for the store to place workflow items into + */ + public void setImporterBootstrap(ImporterBootstrap bootstrap) + { + this.bootstrap = bootstrap; + } + + /** + * @param fileFolderService file folder service + */ + public void setFileFolderService(FileFolderService fileFolderService) + { + this.fileFolderService = fileFolderService; + } + + /** + * @param searchService search service + */ + public void setSearchService(SearchService searchService) + { + this.searchService = searchService; + } + + /** + * @param nodeService node service + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * @param namespaceService namespace service + */ + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + + /* (non-Javadoc) + * @see org.alfresco.repo.workflow.WorkflowPackageComponent#createPackage(org.alfresco.service.cmr.repository.NodeRef) + */ + public NodeRef createPackage(NodeRef container) + { + // create a container, if one is not specified + if (container == null) + { + // create simple folder in workflow system folder + NodeRef system = getSystemWorkflowContainer(); + + // TODO: Consider structuring this folder, if number of children becomes an issue + List folders = new ArrayList(); + folders.add(PACKAGE_FOLDER); + folders.add(GUID.generate()); + FileInfo containerFolder = fileFolderService.makeFolders(system, folders, ContentModel.TYPE_FOLDER); + container = containerFolder.getNodeRef(); + } + + // attach workflow package + if (nodeService.hasAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE)) + { + throw new WorkflowException("Container '" + container + "' is already a workflow package."); + } + nodeService.addAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE, null); + + // return container + return container; + } + + + /** + * Gets the system workflow container for storing workflow related items + * + * @return the system workflow container + */ + private NodeRef getSystemWorkflowContainer() + { + if (systemWorkflowContainer == null) + { + NodeRef systemContainer = findSystemContainer(); + systemWorkflowContainer = findSystemWorkflowContainer(systemContainer); + if (systemWorkflowContainer == null) + { + throw new WorkflowException("Unable to find system workflow folder - does not exist."); + } + } + return systemWorkflowContainer; + } + + + /** + * Finds the system workflow container + * + * @param systemContainer the system container + * @return the system workflow container + */ + private NodeRef findSystemWorkflowContainer(NodeRef systemContainer) + { + String path = bootstrap.getConfiguration().getProperty("system.workflow_container.childname"); + if (path == null) + { + throw new WorkflowException("Unable to locate workflow system container - path not specified"); + } + List nodeRefs = searchService.selectNodes(systemContainer, path, null, namespaceService, false); + if (nodeRefs != null && nodeRefs.size() > 0) + { + systemWorkflowContainer = nodeRefs.get(0); + } + return systemWorkflowContainer; + } + + + /** + * Finds the system container + * + * @return the system container + */ + private NodeRef findSystemContainer() + { + String path = bootstrap.getConfiguration().getProperty("system.system_container.childname"); + if (path == null) + { + throw new WorkflowException("Unable to locate system container - path not specified"); + } + NodeRef root = nodeService.getRootNode(bootstrap.getStoreRef()); + List nodeRefs = searchService.selectNodes(root, path, null, namespaceService, false); + if (nodeRefs == null || nodeRefs.size() == 0) + { + throw new WorkflowException("Unable to locate system container - path not found"); + } + return nodeRefs.get(0); + } + + + /** + * Creates the System Workflow Container + * + * @return the system workflow container + */ + public NodeRef createSystemWorkflowContainer() + { + NodeRef systemContainer = findSystemContainer(); + NodeRef systemWorkflowContainer = findSystemWorkflowContainer(systemContainer); + if (systemWorkflowContainer == null) + { + String name = bootstrap.getConfiguration().getProperty("system.workflow_container.childname"); + QName qname = QName.createQName(name, namespaceService); + ChildAssociationRef childRef = nodeService.createNode(systemContainer, ContentModel.ASSOC_CHILDREN, qname, ContentModel.TYPE_FOLDER); + systemWorkflowContainer = childRef.getChildRef(); + } + return systemWorkflowContainer; + } + +} diff --git a/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java b/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java index 2a850519af..770f8b2a0f 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java @@ -43,6 +43,7 @@ import org.alfresco.service.namespace.QName; public class WorkflowServiceImpl implements WorkflowService { private BPMEngineRegistry registry; + private WorkflowPackageComponent workflowPackageComponent; /** @@ -55,13 +56,23 @@ public class WorkflowServiceImpl implements WorkflowService this.registry = registry; } + /** + * Sets the Workflow Package Component + * + * @param workflowPackage workflow package component + */ + public void setWorkflowPackageComponent(WorkflowPackageComponent workflowPackageComponent) + { + this.workflowPackageComponent = workflowPackageComponent; + } + /* (non-Javadoc) * @see org.alfresco.service.cmr.workflow.WorkflowService#deployDefinition(java.lang.String, java.io.InputStream, java.lang.String) */ public WorkflowDefinition deployDefinition(String engineId, InputStream workflowDefinition, String mimetype) { - WorkflowDefinitionComponent component = getWorkflowDefinitionComponent(engineId); + WorkflowComponent component = getWorkflowComponent(engineId); return component.deployDefinition(workflowDefinition, mimetype); } @@ -70,7 +81,7 @@ public class WorkflowServiceImpl implements WorkflowService */ public boolean isDefinitionDeployed(String engineId, InputStream workflowDefinition, String mimetype) { - WorkflowDefinitionComponent component = getWorkflowDefinitionComponent(engineId); + WorkflowComponent component = getWorkflowComponent(engineId); return component.isDefinitionDeployed(workflowDefinition, mimetype); } @@ -89,7 +100,7 @@ public class WorkflowServiceImpl implements WorkflowService public void undeployDefinition(String workflowDefinitionId) { String engineId = BPMEngineRegistry.getEngineId(workflowDefinitionId); - WorkflowDefinitionComponent component = getWorkflowDefinitionComponent(engineId); + WorkflowComponent component = getWorkflowComponent(engineId); component.undeployDefinition(workflowDefinitionId); } @@ -99,10 +110,10 @@ public class WorkflowServiceImpl implements WorkflowService public List getDefinitions() { List definitions = new ArrayList(10); - String[] ids = registry.getWorkflowDefinitionComponents(); + String[] ids = registry.getWorkflowComponents(); for (String id: ids) { - WorkflowDefinitionComponent component = registry.getWorkflowDefinitionComponent(id); + WorkflowComponent component = registry.getWorkflowComponent(id); definitions.addAll(component.getDefinitions()); } return Collections.unmodifiableList(definitions); @@ -114,7 +125,7 @@ public class WorkflowServiceImpl implements WorkflowService public WorkflowDefinition getDefinitionById(String workflowDefinitionId) { String engineId = BPMEngineRegistry.getEngineId(workflowDefinitionId); - WorkflowDefinitionComponent component = getWorkflowDefinitionComponent(engineId); + WorkflowComponent component = getWorkflowComponent(engineId); return component.getDefinitionById(workflowDefinitionId); } @@ -254,25 +265,9 @@ public class WorkflowServiceImpl implements WorkflowService /* (non-Javadoc) * @see org.alfresco.service.cmr.workflow.WorkflowService#createPackage(java.lang.String, org.alfresco.service.cmr.repository.NodeRef) */ - public NodeRef createPackage(String workflowDefinitionId, NodeRef container) + public NodeRef createPackage(NodeRef container) { - // TODO - throw new UnsupportedOperationException(); - } - - /** - * Gets the Workflow Definition Component registered against the specified BPM Engine Id - * - * @param engineId engine id - */ - private WorkflowDefinitionComponent getWorkflowDefinitionComponent(String engineId) - { - WorkflowDefinitionComponent component = registry.getWorkflowDefinitionComponent(engineId); - if (component == null) - { - throw new WorkflowException("Workflow Definition Component for engine id '" + engineId + "' is not registered"); - } - return component; + return workflowPackageComponent.createPackage(container); } /** diff --git a/source/java/org/alfresco/repo/workflow/WorkflowServiceImplTest.java b/source/java/org/alfresco/repo/workflow/WorkflowServiceImplTest.java index c41b546332..8d61c1ee2a 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowServiceImplTest.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowServiceImplTest.java @@ -19,6 +19,8 @@ package org.alfresco.repo.workflow; import java.util.List; import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.workflow.WorkflowDefinition; import org.alfresco.service.cmr.workflow.WorkflowPath; import org.alfresco.service.cmr.workflow.WorkflowService; @@ -33,11 +35,13 @@ import org.alfresco.util.BaseSpringTest; public class WorkflowServiceImplTest extends BaseSpringTest { WorkflowService workflowService; + NodeService nodeService; //@Override protected void onSetUpInTransaction() throws Exception { workflowService = (WorkflowService)applicationContext.getBean(ServiceRegistry.WORKFLOW_SERVICE.getLocalName()); + nodeService = (NodeService)applicationContext.getBean(ServiceRegistry.NODE_SERVICE.getLocalName()); } public void testGetWorkflowDefinitions() @@ -60,4 +64,13 @@ public class WorkflowServiceImplTest extends BaseSpringTest assertNotNull(path.instance); assertEquals(workflowDef.id, path.instance.definition.id); } + + public void testWorkflowPackage() + { + NodeRef nodeRef = workflowService.createPackage(null); + assertNotNull(nodeRef); + assertTrue(nodeService.hasAspect(nodeRef, WorkflowModel.ASPECT_WORKFLOW_PACKAGE)); + setComplete(); + } + } diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java index 5b713ffb03..be48931089 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java @@ -34,7 +34,6 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.workflow.BPMEngine; import org.alfresco.repo.workflow.TaskComponent; import org.alfresco.repo.workflow.WorkflowComponent; -import org.alfresco.repo.workflow.WorkflowDefinitionComponent; import org.alfresco.repo.workflow.WorkflowModel; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.dictionary.AspectDefinition; @@ -55,6 +54,8 @@ import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition; import org.alfresco.service.cmr.workflow.WorkflowTaskState; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.hibernate.Query; +import org.hibernate.Session; import org.hibernate.proxy.HibernateProxy; import org.jbpm.JbpmContext; import org.jbpm.JbpmException; @@ -81,7 +82,7 @@ import org.springmodules.workflow.jbpm31.JbpmTemplate; * @author davidc */ public class JBPMEngine extends BPMEngine - implements WorkflowDefinitionComponent, WorkflowComponent, TaskComponent + implements WorkflowComponent, TaskComponent { // Implementation dependencies protected DictionaryService dictionaryService; @@ -91,6 +92,16 @@ public class JBPMEngine extends BPMEngine protected PersonService personService; private JbpmTemplate jbpmTemplate; + // Note: jBPM query which is not provided out-of-the-box + // TODO: Check jBPM 3.2 and get this implemented in jBPM + private final static String COMPLETED_TASKS_QUERY = + "select ti " + + "from org.jbpm.taskmgmt.exe.TaskInstance as ti " + + "where ti.actorId = :actorId " + + "and ti.isOpen = false " + + "and ti.end is not null"; + + /** * Sets the JBPM Template used for accessing JBoss JBPM in the correct context * @@ -528,27 +539,61 @@ public class JBPMEngine extends BPMEngine public List doInJbpm(JbpmContext context) { // retrieve tasks assigned to authority - TaskMgmtSession taskSession = context.getTaskMgmtSession(); - List tasks = taskSession.findTaskInstances(authority); + List tasks; + if (state.equals(WorkflowTaskState.IN_PROGRESS)) + { + TaskMgmtSession taskSession = context.getTaskMgmtSession(); + tasks = taskSession.findTaskInstances(authority); + } + else + { + // Note: This method is not implemented by jBPM + tasks = findCompletedTaskInstances(context, authority); + } + + // convert tasks to appropriate service response format List workflowTasks = new ArrayList(tasks.size()); for (TaskInstance task : tasks) { - if (getWorkflowTaskState(task).equals(state)) - { - WorkflowTask workflowTask = createWorkflowTask(task); - workflowTasks.add(workflowTask); - } + WorkflowTask workflowTask = createWorkflowTask(task); + workflowTasks.add(workflowTask); } return workflowTasks; } + + /** + * Gets the completed task list for the specified actor + * + * TODO: This method provides a query that's not in JBPM! Look to have JBPM implement this. + * + * @param jbpmContext the jbpm context + * @param actorId the actor to retrieve tasks for + * @return the tasks + */ + private List findCompletedTaskInstances(JbpmContext jbpmContext, String actorId) + { + List result = null; + try + { + Session session = jbpmContext.getSession(); + Query query = session.createQuery(COMPLETED_TASKS_QUERY); + query.setString("actorId", actorId); + result = query.list(); + } + catch (Exception e) + { + throw new JbpmException("Couldn't get completed task instances list for actor '" + actorId + "'", e); + } + return result; + } }); } catch(JbpmException e) { - throw new WorkflowException("Failed to retrieve tasks assigned to authority '" + authority + "'", e); + throw new WorkflowException("Failed to retrieve tasks assigned to authority '" + authority + "' in state '" + state + "'", e); } } - + /* (non-Javadoc) * @see org.alfresco.repo.workflow.TaskComponent#getPooledTasks(java.util.List) */ diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java index 5abfd40808..8ff75decdb 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java @@ -28,7 +28,6 @@ import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.workflow.BPMEngineRegistry; import org.alfresco.repo.workflow.TaskComponent; import org.alfresco.repo.workflow.WorkflowComponent; -import org.alfresco.repo.workflow.WorkflowDefinitionComponent; import org.alfresco.repo.workflow.WorkflowModel; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; @@ -53,7 +52,6 @@ import org.springframework.core.io.ClassPathResource; */ public class JBPMEngineTest extends BaseSpringTest { - WorkflowDefinitionComponent workflowDefinitionComponent; WorkflowComponent workflowComponent; TaskComponent taskComponent; WorkflowDefinition testWorkflowDef; @@ -64,18 +62,17 @@ public class JBPMEngineTest extends BaseSpringTest protected void onSetUpInTransaction() throws Exception { BPMEngineRegistry registry = (BPMEngineRegistry)applicationContext.getBean("bpm_engineRegistry"); - workflowDefinitionComponent = registry.getWorkflowDefinitionComponent("jbpm"); workflowComponent = registry.getWorkflowComponent("jbpm"); taskComponent = registry.getTaskComponent("jbpm"); // deploy test process definition ClassPathResource processDef = new ClassPathResource("org/alfresco/repo/workflow/jbpm/test_processdefinition.xml"); - assertFalse(workflowDefinitionComponent.isDefinitionDeployed(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML)); - testWorkflowDef = workflowDefinitionComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML); + assertFalse(workflowComponent.isDefinitionDeployed(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML)); + testWorkflowDef = workflowComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML); assertNotNull(testWorkflowDef); assertEquals("Test", testWorkflowDef.name); assertEquals("1", testWorkflowDef.version); - assertTrue(workflowDefinitionComponent.isDefinitionDeployed(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML)); + assertTrue(workflowComponent.isDefinitionDeployed(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML)); // get valid node ref NodeService nodeService = (NodeService)applicationContext.getBean(ServiceRegistry.NODE_SERVICE.getLocalName()); @@ -85,7 +82,7 @@ public class JBPMEngineTest extends BaseSpringTest public void testGetWorkflowDefinitions() { - List workflowDefs = workflowDefinitionComponent.getDefinitions(); + List workflowDefs = workflowComponent.getDefinitions(); assertNotNull(workflowDefs); assertTrue(workflowDefs.size() > 0); } @@ -94,7 +91,7 @@ public class JBPMEngineTest extends BaseSpringTest public void testDeployWorkflow() throws Exception { ClassPathResource processDef = new ClassPathResource("org/alfresco/repo/workflow/jbpm/test_processdefinition.xml"); - testWorkflowDef = workflowDefinitionComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML); + testWorkflowDef = workflowComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML); assertNotNull(testWorkflowDef); assertEquals("Test", testWorkflowDef.name); assertEquals("2", testWorkflowDef.version); @@ -343,8 +340,13 @@ public class JBPMEngineTest extends BaseSpringTest WorkflowTask updatedTask = taskComponent.endTask(tasks1.get(0).id, null); assertNotNull(updatedTask); assertEquals(WorkflowTaskState.COMPLETED, updatedTask.state); + List completedTasks = taskComponent.getAssignedTasks("System", WorkflowTaskState.COMPLETED); + assertNotNull(completedTasks); + assertEquals(1, completedTasks.size()); + assertEquals(WorkflowTaskState.COMPLETED, completedTasks.get(0).state); } + public void testGetTask() { WorkflowDefinition workflowDef = getTestDefinition(); diff --git a/source/java/org/alfresco/service/cmr/workflow/WorkflowService.java b/source/java/org/alfresco/service/cmr/workflow/WorkflowService.java index 88e13bf9d7..bd1388333c 100644 --- a/source/java/org/alfresco/service/cmr/workflow/WorkflowService.java +++ b/source/java/org/alfresco/service/cmr/workflow/WorkflowService.java @@ -212,12 +212,13 @@ public interface WorkflowService public WorkflowTask endTask(String taskId, String transition); /** - * Create a Workflow Package (a container of content to route through the Workflow) + * Create a Workflow Package (a container of content to route through the Workflow). + * + * If an existing container is supplied, it's supplemented with the workflow package aspect. * - * @param workflowDefinitionId workflow definition id * @param container (optional) a pre-created container (e.g. folder, versioned folder or layered folder) * @return the workflow package */ - public NodeRef createPackage(String workflowDefinitionId, NodeRef container); + public NodeRef createPackage(NodeRef container); }