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);
}