From f161572b1ef516ef7724a1058881e771497c61fb Mon Sep 17 00:00:00 2001 From: Jan Vonka Date: Wed, 12 Sep 2007 21:26:12 +0000 Subject: [PATCH] Workflow updates to support deployment of a workflow definition sourced from the repository (ie. node of type bpm:workflowDefinition) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@6770 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/bootstrap-context.xml | 7 +- .../bootstrap/customWorkflowDefsSpace.acp | Bin 0 -> 2094 bytes .../messages/patch-service.properties | 4 +- config/alfresco/model/bpmModel.xml | 26 +++ .../alfresco/patch/patch-services-context.xml | 21 ++ config/alfresco/version.properties | 2 +- config/alfresco/workflow-context.xml | 11 +- .../repo/workflow/WorkflowDefinitionType.java | 220 ++++++++++++++++++ .../alfresco/repo/workflow/WorkflowModel.java | 6 + .../repo/workflow/WorkflowServiceImpl.java | 37 ++- .../repo/workflow/jbpm/JBPMEngine.java | 11 +- 11 files changed, 336 insertions(+), 9 deletions(-) create mode 100644 config/alfresco/bootstrap/customWorkflowDefsSpace.acp create mode 100644 source/java/org/alfresco/repo/workflow/WorkflowDefinitionType.java diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index 0da6b3f999..c03d087d7b 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -216,7 +216,12 @@ /${spaces.company_home.childname}/${spaces.dictionary.childname} alfresco/bootstrap/customWebClientExtensionSpace.xml - + + + /${spaces.company_home.childname}/${spaces.dictionary.childname} + alfresco/bootstrap/customWorkflowDefsSpace.acp + + diff --git a/config/alfresco/bootstrap/customWorkflowDefsSpace.acp b/config/alfresco/bootstrap/customWorkflowDefsSpace.acp new file mode 100644 index 0000000000000000000000000000000000000000..e0750a50376593d431c44dbfc45a69d3917f22db GIT binary patch literal 2094 zcmaKtX*d*$7skgrgThz}BhA>iCS%EvWh~igBEk^UVC-vyEQ3%ZBfGK`##*vuFKZY@ zq)SYeavO}2WkM3lbwB+7_kOzPea>^v`<(ZA&c`3xl8s#m06G%eEhSCBzX}522jB={ z*MkDC1cmx}`3FT9dwPZ01!HlZ@W=pvd&gsd?skSr%Te#J?69mkW3mg+2@%KYnar7| zEc0vAG83}dFPqh-E7L_!3^`SZ$lv@xIRA4a7u5@fO8al9KbStb;apV6yBt%@%V4Z+ zA&PY9Ia$c(Epz!e>tLY)lCfJ*?fizGRofJ1V{}yN#l`5~2<#^K%ee-HcUt#8h+_Kd zo9`IJSRH)cUV`b-ud!r8abkM2N{4$wRdEu1yI*+vfQq8{6Oj_DHj;ri7k=~K236tl zj`ET%QwS4evq1wYjZ0BjDPKO@xSPWqyMxJ?xg;yfqv|R|1hZd`vIRn~Kkl@s%QF6| zXl^L58xW^uO(@W!DqO~F}U^+e=wLy_rTwG}cp>89!ClN=9Pi9E*k zPG3hU-~E)FLo?s*1hEdOQ`S)wZEM-APdFuu#73;4Zf-UMHuWe}v^uQVyQ$B(WYC}{ zm^9&H%N6RNYgK!2Ua5Sgu&;ie?Yco?u2Z)c+C2nweu`mF2A0rh)FM$^v3 z)_UwdPzprc1Go*N)&k2tndV}0$Wc&bmS$hUL>X5YV(HLky7HIKh{ZhhLIY-?u^=mH zA?-(9`|ZUbvTPiQY)!OW0N82YNavH5bRnPcNr+NGfR*BX9ttjM)l9zO%20DX4;dlx zao8O;%-OX4s9R8G)b!7N$Vu_LuATQ*7vl;qb$`kpo{>qeh_+g-;8X#Z-+v1CZQAzL zpMNuzT2PT7jrQ_1<7Ka!3<1CiRBfB7Xj=YS(eYs0)K(*MX|^v1;|Xe0p(a(Cm;QEv z;3j04-#umTu6wPPK6%4$xu$)FV8oA$4=pZk7u-uZYjg$0nitv;SmRJ0g5qX;{X*uW z-Y9cETLuq76&cUO&W|^X*af@o=+C zovEWXA7EvB1I?HdUlRg-ICS5sJ;;)vX{A+Bj7HWiYl^jDVRqA9>Rf_wa9Stl^Gu8JCm{yIrY-e3c+Zjk+PML4u5H1l z3kMl!ooDA|BD1JQ(v|f2H|tOj|?;)576M|z)xDUIn~bt2%wz2x*E2M z!3=~tS1x58T-s@v5y3RNLw#0zReYzsw`IvC)lY?0PwC-0J)#rlM72n0u0LLZ=F9wZ zrcbdoHGh!lnT z?+qmJj4aCn|MX8>8PjU-4ZZ!4Y=Q3gwNP(3F=l5}{F_I6j}NhR^HNaPO5xx&dhm5UeVF(t5_ph z<^5dod0_~xkyZyvd-;bDXKT_*Hs?!``dcMFU!IXEGU_hKd$zbHIRl_fl zZCdC8SyR4UW-}s_&`09W!4J7}dC>Nb?X0cbmQwr<-sAzNQkjaKEoOf87!2w4&5d!x zbl%y!_|x*p=5E!mm}8@NU9v*<=Xw`U347b_1~{oFh+-S8%?f2gmkX5yY-iI;Dt?+d z3wWt7Haqbh189cdCWnxE-zsfA*8Mf7r7MMOgo+_E5%V_F!7@7o=kEI4cj05J~9RG*t=aV z=M>CyQm>1@a!_wlz_&~AJzYkwftoAVP#euT)V0dacq5LVQ#*?dAILsi`b|~XWAWF@ zmSk;Q-F`wPb*i_@Cyka+U&hpC5|n?90lRx5Q!pR(P3ohF^&gXy^qUW>q$KADbAmoa z;ppLzlJ5i}c;$ywd)QCOBah!*G3@zrPeRZM{A{_w$8Sr2^S-yOem#!9XnI<3lz8p( zVZ7(cvjUBZ2$87yTMa + + + + + + + Workflow Process Definition + cm:content + + + Workflow Name + d:text + + + Workflow Engine Id + d:text + true + jbpm + + + Workflow Deployed + d:boolean + false + + + diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index d00b1b5825..dca8aef4fe 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -1017,4 +1017,25 @@ + + patch.customWorkflowDefs + patch.customWorkflowDefs.description + 0 + 105 + 106 + + + + + + /${spaces.company_home.childname}/${spaces.dictionary.childname}/app:workflow_defs + + + + /${spaces.company_home.childname}/${spaces.dictionary.childname} + alfresco/bootstrap/customWorkflowDefsSpace.acp + + + + diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index 6b17d748b2..ebff9289bb 100644 --- a/config/alfresco/version.properties +++ b/config/alfresco/version.properties @@ -19,4 +19,4 @@ version.build=@build-number@ # Schema number -version.schema=105 +version.schema=106 diff --git a/config/alfresco/workflow-context.xml b/config/alfresco/workflow-context.xml index 2194d39088..6a7e9d07e3 100644 --- a/config/alfresco/workflow-context.xml +++ b/config/alfresco/workflow-context.xml @@ -21,6 +21,8 @@ + + @@ -106,5 +108,12 @@ - + + + + + + + + diff --git a/source/java/org/alfresco/repo/workflow/WorkflowDefinitionType.java b/source/java/org/alfresco/repo/workflow/WorkflowDefinitionType.java new file mode 100644 index 0000000000..b1abbe05f0 --- /dev/null +++ b/source/java/org/alfresco/repo/workflow/WorkflowDefinitionType.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.workflow; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.ContentServicePolicies; +import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.policy.JavaBehaviour; +import org.alfresco.repo.policy.PolicyComponent; +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.WorkflowDeployment; +import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Workflow Definition type behaviour. + * + * @author JanV + */ +public class WorkflowDefinitionType implements ContentServicePolicies.OnContentUpdatePolicy, + NodeServicePolicies.OnUpdatePropertiesPolicy, + NodeServicePolicies.BeforeDeleteNodePolicy +{ + // logger + private static Log logger = LogFactory.getLog(WorkflowDefinitionType.class); + + /** The node service */ + private NodeService nodeService; + + /** The policy component */ + private PolicyComponent policyComponent; + + /** The workflow service */ + private WorkflowService workflowService; + + + + /** + * Set the node service + * + * @param nodeService the node service + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Set the policy component + * + * @param policyComponent the policy component + */ + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + + /** + * Set the workflow service + * + * @param workflowService the workflow service + */ + public void setWorkflowService(WorkflowService workflowService) + { + this.workflowService = workflowService; + } + + + /** + * The initialise method + */ + public void init() + { + // Register interest in the onContentUpdate policy for the workflow definition type + policyComponent.bindClassBehaviour( + ContentServicePolicies.ON_CONTENT_UPDATE, + WorkflowModel.TYPE_WORKFLOW_DEF, + new JavaBehaviour(this, "onContentUpdate")); + + // Register interest in the onPropertyUpdate policy for the workflow definition type + policyComponent.bindClassBehaviour( + QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"), + WorkflowModel.TYPE_WORKFLOW_DEF, + new JavaBehaviour(this, "onUpdateProperties")); + + // Register interest in the node delete policy + policyComponent.bindClassBehaviour( + QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"), + WorkflowModel.TYPE_WORKFLOW_DEF, + new JavaBehaviour(this, "beforeDeleteNode")); + } + + /** + * On content update behaviour implementation + * + * @param nodeRef the node reference whose content has been updated + */ + public void onContentUpdate(NodeRef nodeRef, boolean newContent) + { + deploy(nodeRef); + } + + /** + * On update properties behaviour implementation + * + * @param nodeRef the node reference + * @param before the values of the properties before update + * @param after the values of the properties after the update + */ + public void onUpdateProperties( + NodeRef nodeRef, + Map before, + Map after) + { + Boolean beforeValue = (Boolean)before.get(WorkflowModel.PROP_WORKFLOW_DEF_DEPLOYED); + Boolean afterValue = (Boolean)after.get(WorkflowModel.PROP_WORKFLOW_DEF_DEPLOYED); + + if (afterValue != null && + (beforeValue == null || (beforeValue != null && afterValue != null && beforeValue.equals(afterValue) == false))) + { + if (afterValue.booleanValue() == true) + { + deploy(nodeRef); + } + else + { + undeploy(nodeRef); + } + } + else if (afterValue == null && beforeValue != null) + { + // Undeploy the definition since the value has been cleared + undeploy(nodeRef); + } + + } + + public void beforeDeleteNode(NodeRef nodeRef) + { + // Ignore if the node is a working copy + if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY) == false) + { + undeploy(nodeRef); + } + } + + private void deploy(NodeRef nodeRef) + { + // deploy / re-deploy + WorkflowDeployment deployment = workflowService.deployDefinition(nodeRef); + + if (deployment != null) + { + WorkflowDefinition def = deployment.definition; + + // Update the meta data for the model + Map props = nodeService.getProperties(nodeRef); + + props.put(WorkflowModel.PROP_WORKFLOW_DEF_NAME, def.getName()); + + // TODO - ability to return and handle deployment problems / warnings + if (deployment.problems.length > 0) + { + for (String problem : deployment.problems) + { + logger.warn(problem); + } + } + + nodeService.setProperties(nodeRef, props); + } + } + + private void undeploy(NodeRef nodeRef) + { + String defName = (String)nodeService.getProperty(nodeRef, WorkflowModel.PROP_WORKFLOW_DEF_NAME); + if (defName != null) + { + // Undeploy the workflow definition - all versions in JBPM + List defs = workflowService.getAllDefinitionsByName(defName); + for (WorkflowDefinition def: defs) + { + logger.info("Undeploying workflow '" + defName + "' ..."); + workflowService.undeployDefinition(def.getId()); + logger.info("... undeployed '" + def.getId() + "' v" + def.getVersion()); + } + } + } +} diff --git a/source/java/org/alfresco/repo/workflow/WorkflowModel.java b/source/java/org/alfresco/repo/workflow/WorkflowModel.java index 030a359f5f..b914a2d362 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowModel.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowModel.java @@ -74,4 +74,10 @@ public interface WorkflowModel static final QName PROP_WORKFLOW_DEFINITION_NAME = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDefinitionName"); static final QName PROP_WORKFLOW_INSTANCE_ID = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowInstanceId"); + // workflow definition + static final QName TYPE_WORKFLOW_DEF = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDefinition"); + static final QName PROP_WORKFLOW_DEF_ENGINE_ID = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "engineId"); + static final QName PROP_WORKFLOW_DEF_NAME = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "definitionName"); + static final QName PROP_WORKFLOW_DEF_DEPLOYED = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "definitionDeployed"); + } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java b/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java index 9b84b16ba8..33678171a1 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java @@ -32,7 +32,11 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.workflow.WorkflowDefinition; @@ -66,6 +70,8 @@ public class WorkflowServiceImpl implements WorkflowService private AuthorityService authorityService; private BPMEngineRegistry registry; private WorkflowPackageComponent workflowPackageComponent; + private NodeService nodeService; + private ContentService contentService; /** @@ -98,6 +104,26 @@ public class WorkflowServiceImpl implements WorkflowService this.workflowPackageComponent = workflowPackageComponent; } + /** + * Sets the Node Service + * + * @param nodeService + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Sets the Content Service + * + * @param contentService + */ + public void setContentService(ContentService contentService) + { + this.contentService = contentService; + } + /* (non-Javadoc) * @see org.alfresco.service.cmr.workflow.WorkflowService#deployDefinition(java.lang.String, java.io.InputStream, java.lang.String) @@ -132,8 +158,15 @@ public class WorkflowServiceImpl implements WorkflowService */ public WorkflowDeployment deployDefinition(NodeRef definitionContent) { - // TODO - throw new UnsupportedOperationException(); + if (! nodeService.getType(definitionContent).equals(WorkflowModel.TYPE_WORKFLOW_DEF)) + { + throw new WorkflowException("Node " + definitionContent + " is not of type 'bpm:workflowDefinition'"); + } + + String engineId = (String)nodeService.getProperty(definitionContent, WorkflowModel.PROP_WORKFLOW_DEF_ENGINE_ID); + ContentReader contentReader = contentService.getReader(definitionContent, ContentModel.PROP_CONTENT); + + return deployDefinition(engineId, contentReader.getContentInputStream(), contentReader.getMimetype()); } /* (non-Javadoc) diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java index e1d83a3b15..0243edae7d 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java @@ -321,7 +321,7 @@ public class JBPMEngine extends BPMEngine } catch(JbpmException e) { - throw new WorkflowException("Failed to deploy workflow definition", e); + throw new WorkflowException("Failed to deploy workflow definition - " + e.getMessage(), e); } } @@ -380,7 +380,7 @@ public class JBPMEngine extends BPMEngine } catch(JbpmException e) { - throw new WorkflowException("Failed to undeploy workflow definition", e); + throw new WorkflowException("Failed to undeploy workflow definition - " + e.getMessage(), e); } } @@ -1801,8 +1801,13 @@ public class JBPMEngine extends BPMEngine throw new JbpmException("Failed to parse process definition from jBPM xml stream", e); } } + + else + { + throw new JbpmException("Failed to parse process definition - unsupported mime type '" + mimetype + "'"); + } - if (tenantService.isEnabled()) + if ((compiledDef != null) && tenantService.isEnabled()) { compiledDef.def.setName(tenantService.getName(compiledDef.def.getName())); }