From dcc9ac128c47fe4e32516cbcbbbabe9b9c53c979 Mon Sep 17 00:00:00 2001 From: Andrew Hind Date: Tue, 19 Aug 2008 11:54:31 +0000 Subject: [PATCH] Work flow updates to Javs script git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@10417 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/workflow-context.xml | 3 + .../org/alfresco/repo/template/Workflow.java | 63 +-- .../repo/workflow/WorkflowServiceImpl.java | 121 ++++- .../workflow/jscript/JscriptWorkflowTask.java | 439 +++++++++++------- .../service/cmr/workflow/WorkflowService.java | 7 + 5 files changed, 430 insertions(+), 203 deletions(-) diff --git a/config/alfresco/workflow-context.xml b/config/alfresco/workflow-context.xml index 5e4d964910..d67de37e67 100644 --- a/config/alfresco/workflow-context.xml +++ b/config/alfresco/workflow-context.xml @@ -26,6 +26,9 @@ + + + diff --git a/source/java/org/alfresco/repo/template/Workflow.java b/source/java/org/alfresco/repo/template/Workflow.java index 519bc576bf..6078728bcd 100644 --- a/source/java/org/alfresco/repo/template/Workflow.java +++ b/source/java/org/alfresco/repo/template/Workflow.java @@ -43,6 +43,7 @@ import org.alfresco.service.cmr.dictionary.DictionaryService; 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.repository.StoreRef; import org.alfresco.service.cmr.repository.TemplateImageResolver; import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowTask; @@ -51,6 +52,7 @@ import org.alfresco.service.cmr.workflow.WorkflowTransition; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QNameMap; import org.alfresco.service.namespace.RegexQNamePattern; +import org.alfresco.util.Pair; /** * Workflow and task support in FreeMarker templates. @@ -246,52 +248,33 @@ public class Workflow extends BaseTemplateProcessorExtension public List getPackageResources() { List resources = new ArrayList(); - if (this.task.properties.get(PROP_FROM_PATH) != null) + List contents = this.services.getWorkflowService().getPackageContents(this.task.id); + + NodeService nodeService = this.services.getNodeService(); + DictionaryService ddService = this.services.getDictionaryService(); + + for(NodeRef nodeRef : contents) { - AVMService avmService = this.services.getAVMService(); - NodeRef workflowPackage = getPackage(); - NodeRef stagingNodeRef = (NodeRef)this.services.getNodeService().getProperty( - workflowPackage, WCMModel.PROP_AVM_DIR_INDIRECTION); - String stagingAvmPath = AVMNodeConverter.ToAVMVersionPath(stagingNodeRef).getSecond(); - String packageAvmPath = AVMNodeConverter.ToAVMVersionPath(workflowPackage).getSecond(); - for (AVMDifference d : this.services.getAVMSyncService().compare( - -1, packageAvmPath, -1, stagingAvmPath, null)) + if (nodeRef.getStoreRef().getProtocol().equals(StoreRef.PROTOCOL_AVM)) { - if (d.getDifferenceCode() == AVMDifference.NEWER || - d.getDifferenceCode() == AVMDifference.CONFLICT) - { - resources.add(new AVMTemplateNode( - d.getSourcePath(), d.getSourceVersion(), this.services, this.resolver)); - } + Pair vp = AVMNodeConverter.ToAVMVersionPath(nodeRef); + resources.add(new AVMTemplateNode( + vp.getSecond(), vp.getFirst(), this.services, this.resolver)); + } - } - else - { - // get existing workflow package items - NodeService nodeService = this.services.getNodeService(); - DictionaryService ddService = this.services.getDictionaryService(); - List childRefs = nodeService.getChildAssocs( - getPackage(), ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); - - for (ChildAssociationRef ref: childRefs) + else { - // create our Node representation from the NodeRef - NodeRef nodeRef = ref.getChildRef(); - if (nodeService.exists(nodeRef)) - { - // find it's type so we can see if it's a node we are interested in - QName type = nodeService.getType(nodeRef); + QName type = nodeService.getType(nodeRef); - // make sure the type is defined in the data dictionary - if (ddService.getType(type) != null) + // make sure the type is defined in the data dictionary + if (ddService.getType(type) != null) + { + // look for content nodes or links to content + // NOTE: folders within workflow packages are ignored for now + if (ddService.isSubClass(type, ContentModel.TYPE_CONTENT) || + ApplicationModel.TYPE_FILELINK.equals(type)) { - // look for content nodes or links to content - // NOTE: folders within workflow packages are ignored for now - if (ddService.isSubClass(type, ContentModel.TYPE_CONTENT) || - ApplicationModel.TYPE_FILELINK.equals(type)) - { - resources.add(new TemplateNode(nodeRef, this.services, this.resolver)); - } + resources.add(new TemplateNode(nodeRef, this.services, this.resolver)); } } } diff --git a/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java b/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java index aae6ec0334..bdd5761b60 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java @@ -33,10 +33,18 @@ import java.util.Map; import java.util.Set; import org.alfresco.model.ContentModel; +import org.alfresco.model.WCMModel; +import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.service.cmr.avmsync.AVMDifference; +import org.alfresco.service.cmr.avmsync.AVMSyncService; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.TypeDefinition; +import org.alfresco.service.cmr.repository.ChildAssociationRef; 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.repository.StoreRef; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.workflow.WorkflowDefinition; @@ -51,6 +59,7 @@ import org.alfresco.service.cmr.workflow.WorkflowTaskQuery; import org.alfresco.service.cmr.workflow.WorkflowTaskState; import org.alfresco.service.cmr.workflow.WorkflowTimer; import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.RegexQNamePattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -72,6 +81,9 @@ public class WorkflowServiceImpl implements WorkflowService private WorkflowPackageComponent workflowPackageComponent; private NodeService nodeService; private ContentService contentService; + private AVMSyncService avmSyncService; + private DictionaryService dictionaryService; + private NodeService protectedNodeService; /** @@ -97,7 +109,7 @@ public class WorkflowServiceImpl implements WorkflowService /** * Sets the Workflow Package Component * - * @param workflowPackage workflow package component + * @param workflowPackageComponent workflow package component */ public void setWorkflowPackageComponent(WorkflowPackageComponent workflowPackageComponent) { @@ -124,7 +136,35 @@ public class WorkflowServiceImpl implements WorkflowService this.contentService = contentService; } + /** + * Set the avm sync service + * @param avmSyncService + */ + public void setAvmSyncService(AVMSyncService avmSyncService) + { + this.avmSyncService = avmSyncService; + } + + /** + * Set the dictionary service + * + * @param dictionaryService + */ + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + + /** + * Set the node service which applies permissions + * @param protectedNodeService + */ + public void setProtectedNodeService(NodeService protectedNodeService) + { + this.protectedNodeService = protectedNodeService; + } + /* (non-Javadoc) * @see org.alfresco.service.cmr.workflow.WorkflowService#deployDefinition(java.lang.String, java.io.InputStream, java.lang.String) */ @@ -573,4 +613,83 @@ public class WorkflowServiceImpl implements WorkflowService return component; } + public List getPackageContents(String taskId) + { + WorkflowTask workflowTask = getTaskById(taskId); + List contents = new ArrayList(); + + if(workflowTask != null) + { + NodeRef workflowPackage = (NodeRef)workflowTask.properties.get(WorkflowModel.ASSOC_PACKAGE); + if (workflowPackage.getStoreRef().getProtocol().equals(StoreRef.PROTOCOL_AVM)) + { + if (protectedNodeService.exists(workflowPackage)) + { + final NodeRef stagingNodeRef = (NodeRef) + protectedNodeService.getProperty(workflowPackage, + WCMModel.PROP_AVM_DIR_INDIRECTION); + final String stagingAvmPath = AVMNodeConverter.ToAVMVersionPath(stagingNodeRef).getSecond(); + final String packageAvmPath = AVMNodeConverter.ToAVMVersionPath(workflowPackage).getSecond(); + if (logger.isDebugEnabled()) + logger.debug("comparing " + packageAvmPath + " with " + stagingAvmPath); + for (AVMDifference d : avmSyncService.compare(-1, packageAvmPath, + -1, stagingAvmPath, + null)) + { + if (logger.isDebugEnabled()) + logger.debug("got difference " + d); + if (d.getDifferenceCode() == AVMDifference.NEWER || + d.getDifferenceCode() == AVMDifference.CONFLICT) + { + contents.add(AVMNodeConverter.ToNodeRef(d.getSourceVersion(), d.getSourcePath())); + } + } + } + } + else + { + // get existing workflow package items + List childRefs = protectedNodeService.getChildAssocs( + workflowPackage, ContentModel.ASSOC_CONTAINS, + RegexQNamePattern.MATCH_ALL); + + for (ChildAssociationRef ref: childRefs) + { + // create our Node representation from the NodeRef + NodeRef nodeRef = ref.getChildRef(); + + if (!protectedNodeService.exists(nodeRef)) + { + if (logger.isDebugEnabled()) + logger.debug("Ignoring " + nodeRef + " as it has been removed from the repository"); + } + else + { + // find it's type so we can see if it's a node we are interested in + QName type = protectedNodeService.getType(nodeRef); + + // make sure the type is defined in the data dictionary + TypeDefinition typeDef = dictionaryService.getType(type); + + if (typeDef == null) + { + if (logger.isWarnEnabled()) + logger.warn("Found invalid object in database: id = " + nodeRef + + ", type = " + type); + } + else + { + contents.add(nodeRef); + } + } + } + } + } + + return contents; + + } + + + } diff --git a/source/java/org/alfresco/repo/workflow/jscript/JscriptWorkflowTask.java b/source/java/org/alfresco/repo/workflow/jscript/JscriptWorkflowTask.java index 081f65f2ad..f54b00dfdf 100644 --- a/source/java/org/alfresco/repo/workflow/jscript/JscriptWorkflowTask.java +++ b/source/java/org/alfresco/repo/workflow/jscript/JscriptWorkflowTask.java @@ -25,197 +25,312 @@ package org.alfresco.repo.workflow.jscript; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import java.util.Set; +import org.alfresco.model.ApplicationModel; +import org.alfresco.model.ContentModel; +import org.alfresco.model.WCMModel; +import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.repo.jscript.ScriptNode; +import org.alfresco.repo.jscript.ScriptableHashMap; import org.alfresco.repo.jscript.ScriptableQNameMap; +import org.alfresco.repo.template.AVMTemplateNode; +import org.alfresco.repo.template.TemplateContent; +import org.alfresco.repo.template.TemplateNode; +import org.alfresco.repo.workflow.WorkflowModel; import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avmsync.AVMDifference; +import org.alfresco.service.cmr.dictionary.DictionaryService; +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.repository.StoreRef; import org.alfresco.service.cmr.workflow.WorkflowTask; +import org.alfresco.service.cmr.workflow.WorkflowTransition; import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.RegexQNamePattern; +import org.alfresco.util.Pair; +import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; /** - * This class represents a workflow task (an instance of a workflow - * task definition) + * This class represents a workflow task (an instance of a workflow task definition) * * @author glenj - * */ public class JscriptWorkflowTask implements Serializable { - static final long serialVersionUID = -8285971359421912313L; - - /** Unique ID for workflow task */ - private final String id; - - /** Name for workflow task */ - private final String name; - - /** Title for workflow task */ - private final String title; - - /** Description of workflow task */ - private final String description; - + private static final String WCM_WF_MODEL_1_0_URI = "http://www.alfresco.org/model/wcmworkflow/1.0"; + + private static final QName PROP_FROM_PATH = QName.createQName(WCM_WF_MODEL_1_0_URI, "fromPath"); + + static final long serialVersionUID = -8285971359421912313L; + + /** Unique ID for workflow task */ + private final String id; + + /** Name for workflow task */ + private final String name; + + /** Title for workflow task */ + private final String title; + + /** Description of workflow task */ + private final String description; + /** Properties (key/value pairs) for this Workflow Task */ private ScriptableQNameMap properties; - + /** Whether task is complete or not - 'true':complete, 'false':in-progress */ private boolean complete = false; - + /** Whether task is pooled or not */ private boolean pooled = false; - + /** Service Registry object */ private ServiceRegistry serviceRegistry; - - /** - * Creates a new instance of a workflow task (instance of a workflow task definition) - * - * @param id workflow task ID - * @param name workflow task name - * @param title workflow task title - * @param description workflow task description - * @param serviceRegistry Service Registry object - */ - public JscriptWorkflowTask(final String id, final String name, final String title, - final String description, final ServiceRegistry serviceRegistry, - final ScriptableQNameMap properties) - { - this.id = id; - this.name = name; - this.title = title; - this.description = description; - this.serviceRegistry = serviceRegistry; - this.properties = properties; - } - - /** - * Creates a new instance of a workflow task from a WorkflowTask from the CMR - * workflow object model - * - * @param cmrWorkflowTask an instance of WorkflowTask from CMR workflow object model - * @param serviceRegistry Service Registry object - */ - public JscriptWorkflowTask(final WorkflowTask cmrWorkflowTask, - final ServiceRegistry serviceRegistry) - { - this.id = cmrWorkflowTask.id; - this.name = cmrWorkflowTask.name; - this.title = cmrWorkflowTask.title; - this.description = cmrWorkflowTask.description; - this.serviceRegistry = serviceRegistry; - - // instantiate ScriptableQNameMap properties - // from WorkflowTasks's Map properties - this.properties = new ScriptableQNameMap( - serviceRegistry.getNamespaceService()); - - Set keys = cmrWorkflowTask.properties.keySet(); - for (QName key : keys) - { - Serializable value = cmrWorkflowTask.properties.get(key); - this.properties.put(key.toString(), value); - } - } - /** - * Gets the value of the id property - * - * @return the id - */ - public String getId() - { - return id; - } + /** Available transitions * */ + private ScriptableHashMap transitions; - /** - * Gets the value of the name property - * - * @return the name - */ - public String getName() - { - return name; - } + /** Package resources * */ + private Scriptable packageResources; - /** - * Gets the value of the title property - * - * @return the title - */ - public String getTitle() - { - return title; - } + /** + * Creates a new instance of a workflow task (instance of a workflow task definition) + * + * @param id + * workflow task ID + * @param name + * workflow task name + * @param title + * workflow task title + * @param description + * workflow task description + * @param serviceRegistry + * Service Registry object + * @param properties + * @param transitions + * @param packageResources + */ + public JscriptWorkflowTask(final String id, final String name, final String title, final String description, final ServiceRegistry serviceRegistry, + final ScriptableQNameMap properties, final ScriptableHashMap transitions, Scriptable packageResources) + { + this.id = id; + this.name = name; + this.title = title; + this.description = description; + this.serviceRegistry = serviceRegistry; + this.properties = properties; + this.transitions = transitions; + this.packageResources = packageResources; + } - /** - * Gets the value of the description property - * - * @return the description - */ - public String getDescription() - { - return description; - } + /** + * Creates a new instance of a workflow task from a WorkflowTask from the CMR workflow object model + * + * @param cmrWorkflowTask + * an instance of WorkflowTask from CMR workflow object model + * @param serviceRegistry + * Service Registry object + */ + public JscriptWorkflowTask(final WorkflowTask cmrWorkflowTask, final ServiceRegistry serviceRegistry) + { + this.id = cmrWorkflowTask.id; + this.name = cmrWorkflowTask.name; + this.title = cmrWorkflowTask.title; + this.description = cmrWorkflowTask.description; + this.serviceRegistry = serviceRegistry; - /** - * Gets the value of the properties property - * - * @return the properties - */ - public Scriptable getProperties() - { - return properties; - } + // instantiate ScriptableQNameMap properties + // from WorkflowTasks's Map properties + this.properties = new ScriptableQNameMap(serviceRegistry.getNamespaceService()); - /** - * Sets the value of the properties property - * - * @param properties the properties to set - */ - public void setProperties(ScriptableQNameMap properties) - { - this.properties = properties; - } + Set keys = cmrWorkflowTask.properties.keySet(); + for (QName key : keys) + { + Serializable value = cmrWorkflowTask.properties.get(key); + this.properties.put(key.toString(), value); + } - /** - * Returns whether the task is complete - * 'true':complete, 'false':in-progress - * - * @return the complete - */ - public boolean isComplete() - { - return complete; - } + transitions = new ScriptableHashMap(); + for (WorkflowTransition transition : cmrWorkflowTask.path.node.transitions) + { + transitions.put(transition.id, transition.title); + } - /** - * Returns whether this task is pooled or not - * - * @return 'true': task is pooled, 'false': task is not pooled - */ - public boolean isPooled() - { - return pooled; - } + // build package context .... should be centralised... YUK + // Needs to match org.alfresco.repo.template.Workflow.WorkflowTaskItem.getPackageResources + + NodeRef workflowPackage = (NodeRef) cmrWorkflowTask.properties.get(WorkflowModel.ASSOC_PACKAGE); + + List contents = serviceRegistry.getWorkflowService().getPackageContents(cmrWorkflowTask.id); + List resources = new ArrayList(contents.size()); + + NodeService nodeService = serviceRegistry.getNodeService(); + DictionaryService ddService = serviceRegistry.getDictionaryService(); + + for (NodeRef nodeRef : contents) + { + if (nodeRef.getStoreRef().getProtocol().equals(StoreRef.PROTOCOL_AVM)) + { + resources.add(nodeRef); + } + else + { + if (nodeService.exists(nodeRef)) + { + // find it's type so we can see if it's a node we are interested in + QName type = nodeService.getType(nodeRef); + + // make sure the type is defined in the data dictionary + if (ddService.getType(type) != null) + { + // look for content nodes or links to content + // NOTE: folders within workflow packages are ignored for now + if (ddService.isSubClass(type, ContentModel.TYPE_CONTENT) || ApplicationModel.TYPE_FILELINK.equals(type)) + { + resources.add(nodeRef); + } + } + } + } + } + + Object[] answer = new Object[resources.size()]; + for (int i = 0; i < resources.size(); i++) + { + // create our Node representation from the NodeRef + answer[i] = new ScriptNode(resources.get(i), serviceRegistry, null); + } + packageResources = Context.getCurrentContext().newArray(null, answer); + + } + + /** + * Gets the value of the id property + * + * @return the id + */ + public String getId() + { + return id; + } + + /** + * Gets the value of the name property + * + * @return the name + */ + public String getName() + { + return name; + } + + /** + * Gets the value of the title property + * + * @return the title + */ + public String getTitle() + { + return title; + } + + /** + * Gets the value of the description property + * + * @return the description + */ + public String getDescription() + { + return description; + } + + /** + * Gets the value of the properties property + * + * @return the properties + */ + public Scriptable getProperties() + { + return properties; + } + + /** + * Sets the value of the properties property + * + * @param properties + * the properties to set + */ + public void setProperties(ScriptableQNameMap properties) + { + this.properties = properties; + } + + /** + * Returns whether the task is complete 'true':complete, 'false':in-progress + * + * @return the complete + */ + public boolean isComplete() + { + return complete; + } + + /** + * Returns whether this task is pooled or not + * + * @return 'true': task is pooled, 'false': task is not pooled + */ + public boolean isPooled() + { + return pooled; + } + + /** + * Sets whether task is pooled('true') or not('false') + * + * @param pooled + * the pooled to set + */ + public void setPooled(boolean pooled) + { + this.pooled = pooled; + } + + /** + * End the task + * + * @param transition + * transition to end the task for + */ + public void endTask(String transitionId) + { + serviceRegistry.getWorkflowService().endTask(this.id, transitionId); + } + + /** + * Get the available transition ids. + * + * @return + */ + public ScriptableHashMap getTransitions() + { + return transitions; + } + + /** + * Get the packe resources (array of noderefs) + * + * @return + */ + public Scriptable getPackageResources() + { + return packageResources; + } - /** - * Sets whether task is pooled('true') or not('false') - * - * @param pooled the pooled to set - */ - public void setPooled(boolean pooled) - { - this.pooled = pooled; - } - - /** - * End the task - * - * @param transition transition to end the task for - */ - public void endTask(String transitionId) - { - serviceRegistry.getWorkflowService().endTask(this.id, transitionId); - } } diff --git a/source/java/org/alfresco/service/cmr/workflow/WorkflowService.java b/source/java/org/alfresco/service/cmr/workflow/WorkflowService.java index 482726f77e..193887ca06 100644 --- a/source/java/org/alfresco/service/cmr/workflow/WorkflowService.java +++ b/source/java/org/alfresco/service/cmr/workflow/WorkflowService.java @@ -384,4 +384,11 @@ public interface WorkflowService @Auditable(key = Auditable.Key.ARG_0, parameters = {"packageItem", "active"}) public List getWorkflowsForContent(NodeRef packageItem, boolean active); + /** + * Get a list of node refs to all the package contents for the given task id. + * @param taskId - the task id + * @return - A list of NodeRefs + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = {"packageItem", "active"}) + public List getPackageContents(String taskId); }