diff --git a/config/alfresco/form-services-context.xml b/config/alfresco/form-services-context.xml index df65cb8130..a7869618c5 100644 --- a/config/alfresco/form-services-context.xml +++ b/config/alfresco/form-services-context.xml @@ -2,7 +2,7 @@ - + @@ -10,29 +10,30 @@ - + org.alfresco.repo.forms.FormService - + - - - - + + + + - - - + + + - + @@ -42,144 +43,144 @@ - - - - - - - - + - - - - - - - - + - - + + + + + + + + + + + + + + + + - - - - - - - - - - - node - - - - + + + + + node + + + + - - - - - - - type + + type + + + + + + + + + + + formService + - - - - - - - + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + workflow - - - - - - - - - formService - - - - - - - - + + + + + task + - - - - + - - - - + - + - - - - - - - - - - diff --git a/config/alfresco/messages/form-service.properties b/config/alfresco/messages/form-service.properties index fef6e474f9..a28d1eca0c 100644 --- a/config/alfresco/messages/form-service.properties +++ b/config/alfresco/messages/form-service.properties @@ -5,4 +5,7 @@ form_service.mimetype.description=Mimetype of the content form_service.encoding.label=Encoding form_service.encoding.description=Encoding of the content form_service.size.label=Size -form_service.size.description=Size of the content in bytes \ No newline at end of file +form_service.size.description=Size of the content in bytes + +form_service.package.items.label=Items +form_service.package.items.description=Items that are part of the workflow \ No newline at end of file diff --git a/source/java/org/alfresco/repo/forms/processor/node/ContentField.java b/source/java/org/alfresco/repo/forms/processor/node/ContentField.java index e3abeccbd0..aef3734ad4 100644 --- a/source/java/org/alfresco/repo/forms/processor/node/ContentField.java +++ b/source/java/org/alfresco/repo/forms/processor/node/ContentField.java @@ -35,13 +35,11 @@ public class ContentField implements Field { private final FieldDefinition fieldDefinition; private final ClassAttributeDefinition classDefinition; - private final boolean isProperty; private final Object value; public ContentField(PropertyDefinition propertyDefinition, PropertyFieldDefinition fieldDef, Object value) { - this.isProperty = true; this.classDefinition = propertyDefinition; this.fieldDefinition = fieldDef; this.value = value; @@ -50,7 +48,6 @@ public class ContentField implements Field public ContentField(AssociationDefinition assocDefinition, AssociationFieldDefinition fieldDef, Object value) { - this.isProperty = false; this.classDefinition = assocDefinition; this.fieldDefinition = fieldDef; this.value = value; @@ -60,10 +57,9 @@ public class ContentField implements Field * This constructor should only be used to create FieldInfo for transient properties such as encoding, mimetype or size. * @param fieldDef The PropertyFieldDefinition for the transient property. */ - public ContentField(PropertyFieldDefinition fieldDef, Object value) + public ContentField(FieldDefinition fieldDef, Object value) { this.classDefinition = null; - this.isProperty = true; this.fieldDefinition = fieldDef; this.value = value; } @@ -76,6 +72,14 @@ public class ContentField implements Field return classDefinition == null; } + /* (non-Javadoc) + * @see org.alfresco.repo.forms.processor.task.Field#isTransient() + */ + public boolean isProperty() + { + return fieldDefinition instanceof PropertyFieldDefinition; + } + /* (non-Javadoc) * @see org.alfresco.repo.forms.processor.task.Field#getFieldDefinition() */ @@ -112,7 +116,7 @@ public class ContentField implements Field public String toString() { String type = isTransient()?"Transient ":""; - type += isProperty ? "Property" : "Association"; + type += isProperty() ? "Property" : "Association"; return "Field: " + getFieldName() + " Type: " + type; } diff --git a/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java index ddb356e371..1d9f9dcbd7 100644 --- a/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java +++ b/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java @@ -244,108 +244,6 @@ public abstract class ContentModelFormProcessor extends protected abstract TypeDefinition getBaseType(ItemType item); - /** - * Generates the field definition for the transient mimetype property - * - * @param content The ContentData object to generate the field from - * @param form The Form instance to populate - */ - protected void generateMimetypePropertyField(ContentData content, Form form) - { - String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_MIMETYPE; - PropertyFieldDefinition mimetypeField = new PropertyFieldDefinition(TRANSIENT_MIMETYPE, DataTypeDefinition.TEXT - .getLocalName()); - mimetypeField.setLabel(I18NUtil.getMessage(MSG_MIMETYPE_LABEL)); - mimetypeField.setDescription(I18NUtil.getMessage(MSG_MIMETYPE_DESC)); - mimetypeField.setDataKeyName(dataKeyName); - form.addFieldDefinition(mimetypeField); - - if (content != null) - { - form.addData(dataKeyName, content.getMimetype()); - } - } - - /** - * Generates the field definition for the transient encoding property - * - * @param content The ContentData object to generate the field from - * @param form The Form instance to populate - */ - protected void generateEncodingPropertyField(ContentData content, Form form) - { - String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_ENCODING; - PropertyFieldDefinition encodingField = new PropertyFieldDefinition(TRANSIENT_ENCODING, DataTypeDefinition.TEXT - .getLocalName()); - encodingField.setLabel(I18NUtil.getMessage(MSG_ENCODING_LABEL)); - encodingField.setDescription(I18NUtil.getMessage(MSG_ENCODING_DESC)); - encodingField.setDataKeyName(dataKeyName); - form.addFieldDefinition(encodingField); - - if (content != null) - { - form.addData(dataKeyName, content.getEncoding()); - } - } - - /** - * Generates the field definition for the transient size property - * - * @param content The ContentData object to generate the field from - * @param form The Form instance to populate - */ - protected void generateSizePropertyField(ContentData content, Form form) - { - String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_SIZE; - PropertyFieldDefinition sizeField = new PropertyFieldDefinition(TRANSIENT_SIZE, DataTypeDefinition.LONG - .getLocalName()); - sizeField.setLabel(I18NUtil.getMessage(MSG_SIZE_LABEL)); - sizeField.setDescription(I18NUtil.getMessage(MSG_SIZE_DESC)); - sizeField.setDataKeyName(dataKeyName); - sizeField.setProtectedField(true); - form.addFieldDefinition(sizeField); - - if (content != null) - { - form.addData(dataKeyName, new Long(content.getSize())); - } - } - - /** - * Determines whether the given node represents a working copy, if it does - * the name field is searched for and set to protected as the name field - * should not be edited for a working copy. - * - * If the node is not a working copy this method has no effect. - * - * @param nodeRef NodeRef of node to check and potentially process - * @param form The generated form - */ - protected void processWorkingCopy(NodeRef nodeRef, Form form) - { - // if the node is a working copy ensure that the name field (id present) - // is set to be protected as it can not be edited - if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY)) - { - // go through fields looking for name field - for (FieldDefinition fieldDef : form.getFieldDefinitions()) - { - if (fieldDef.getName().equals(ContentModel.PROP_NAME.toPrefixString(this.namespaceService))) - { - fieldDef.setProtectedField(true); - - if (getLogger().isDebugEnabled()) - { - getLogger().debug("Set " + ContentModel.PROP_NAME.toPrefixString(this.namespaceService) + - "field to protected as it is a working copy"); - } - - break; - } - } - } - } - /** * Retrieves the values of the given association definition on the given * node. diff --git a/source/java/org/alfresco/repo/forms/processor/node/NodeFormProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/NodeFormProcessor.java index 6f6b577316..e74f2a912c 100644 --- a/source/java/org/alfresco/repo/forms/processor/node/NodeFormProcessor.java +++ b/source/java/org/alfresco/repo/forms/processor/node/NodeFormProcessor.java @@ -27,6 +27,8 @@ import java.util.Map; import java.util.Set; import org.alfresco.model.ContentModel; +import org.alfresco.repo.forms.FieldDefinition; +import org.alfresco.repo.forms.Form; import org.alfresco.repo.forms.FormData; import org.alfresco.repo.forms.FormNotFoundException; import org.alfresco.repo.forms.Item; @@ -223,6 +225,52 @@ public class NodeFormProcessor extends ContentModelFormProcessor fields, List forcedFields, Form form, + Map context) + { + super.internalGenerate(item, fields, forcedFields, form, context); + processWorkingCopy(item, form); + } + /* * @see * org.alfresco.repo.forms.processor.FilteredFormProcessor#internalPersist diff --git a/source/java/org/alfresco/repo/forms/processor/node/TransientEncodingFieldProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/TransientEncodingFieldProcessor.java index 27e9bd541f..8920ce1db1 100644 --- a/source/java/org/alfresco/repo/forms/processor/node/TransientEncodingFieldProcessor.java +++ b/source/java/org/alfresco/repo/forms/processor/node/TransientEncodingFieldProcessor.java @@ -22,6 +22,7 @@ package org.alfresco.repo.forms.processor.node; import static org.alfresco.repo.forms.processor.node.FormFieldConstants.PROP_DATA_PREFIX; import static org.alfresco.repo.forms.processor.node.FormFieldConstants.TRANSIENT_ENCODING; +import org.alfresco.repo.forms.FieldDefinition; import org.alfresco.repo.forms.PropertyFieldDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.apache.commons.logging.Log; @@ -42,7 +43,7 @@ public class TransientEncodingFieldProcessor extends TransientFieldProcessor } @Override - protected PropertyFieldDefinition makeTransientPropertyDefinition() + protected FieldDefinition makeTransientPropertyDefinition() { String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_ENCODING; PropertyFieldDefinition encodingField = new PropertyFieldDefinition(TRANSIENT_ENCODING, diff --git a/source/java/org/alfresco/repo/forms/processor/node/TransientFieldProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/TransientFieldProcessor.java index 37f8957b2e..046d72b3e2 100644 --- a/source/java/org/alfresco/repo/forms/processor/node/TransientFieldProcessor.java +++ b/source/java/org/alfresco/repo/forms/processor/node/TransientFieldProcessor.java @@ -20,6 +20,7 @@ package org.alfresco.repo.forms.processor.node; import org.alfresco.repo.forms.Field; +import org.alfresco.repo.forms.FieldDefinition; import org.alfresco.repo.forms.PropertyFieldDefinition; import org.alfresco.repo.forms.processor.AbstractFieldProcessor; import org.alfresco.repo.forms.processor.FormCreationData; @@ -32,7 +33,7 @@ public abstract class TransientFieldProcessor extends AbstractFieldProcessor. + */ + +package org.alfresco.repo.forms.processor.workflow; + +import org.alfresco.repo.forms.AssociationFieldDefinition; +import org.alfresco.repo.forms.FieldDefinition; +import org.alfresco.repo.forms.AssociationFieldDefinition.Direction; +import org.alfresco.repo.forms.processor.FieldProcessor; +import org.alfresco.repo.forms.processor.node.TransientFieldProcessor; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.I18NUtil; + +import static org.alfresco.repo.forms.processor.node.FormFieldConstants.ASSOC_DATA_PREFIX; + +/** + * {@link FieldProcessor} for handling package contents when displaying Workflow and Task Forms. + * @author Nick Smith + */ +public class PackageItemsFieldProcessor extends TransientFieldProcessor +{ + /** Logger */ + private final static Log logger = LogFactory.getLog(PackageItemsFieldProcessor.class); + + public static final String KEY = "packageItems"; + + private static final String MSG_LABEL = "form_service.package.items.label"; + private static final String MSG_DESCRIPTION = "form_service.package.items.description"; + + /* (non-Javadoc) + * @see org.alfresco.repo.forms.processor.node.TransientFieldProcessor#makeTransientPropertyDefinition() + */ + @Override + protected FieldDefinition makeTransientPropertyDefinition() + { + AssociationFieldDefinition fieldDef = new AssociationFieldDefinition( + KEY, "cm:content", Direction.TARGET); + fieldDef.setLabel(I18NUtil.getMessage(MSG_LABEL)); + fieldDef.setDescription(I18NUtil.getMessage(MSG_DESCRIPTION)); + fieldDef.setProtectedField(false); + fieldDef.setEndpointMandatory(false); + fieldDef.setEndpointMany(true); + + // define the data key name and set + String dataKey = ASSOC_DATA_PREFIX + KEY; + fieldDef.setDataKeyName(dataKey); + return fieldDef; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.forms.processor.AbstractFieldProcessor#getLogger() + */ + @Override + protected Log getLogger() + { + return logger; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.forms.processor.AbstractFieldProcessor#getRegistryKey() + */ + @Override + protected String getRegistryKey() + { + return KEY; + } + +} diff --git a/source/java/org/alfresco/repo/forms/processor/workflow/WorkflowFormProcessor.java b/source/java/org/alfresco/repo/forms/processor/workflow/WorkflowFormProcessor.java index a39f8e87f1..c7c4a25292 100644 --- a/source/java/org/alfresco/repo/forms/processor/workflow/WorkflowFormProcessor.java +++ b/source/java/org/alfresco/repo/forms/processor/workflow/WorkflowFormProcessor.java @@ -24,40 +24,22 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import org.alfresco.model.ContentModel; -import org.alfresco.repo.forms.AssociationFieldDefinition; -import org.alfresco.repo.forms.FieldGroup; -import org.alfresco.repo.forms.Form; import org.alfresco.repo.forms.FormData; import org.alfresco.repo.forms.FormNotFoundException; import org.alfresco.repo.forms.Item; -import org.alfresco.repo.forms.PropertyFieldDefinition; -import org.alfresco.repo.forms.AssociationFieldDefinition.Direction; -import org.alfresco.repo.forms.PropertyFieldDefinition.FieldConstraint; import org.alfresco.repo.forms.processor.node.ContentModelFormProcessor; -import org.alfresco.repo.forms.processor.node.PeriodDataTypeParameters; import org.alfresco.repo.workflow.WorkflowModel; -import org.alfresco.service.cmr.dictionary.AspectDefinition; -import org.alfresco.service.cmr.dictionary.AssociationDefinition; -import org.alfresco.service.cmr.dictionary.Constraint; -import org.alfresco.service.cmr.dictionary.ConstraintDefinition; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.dictionary.TypeDefinition; -import org.alfresco.service.cmr.repository.AssociationRef; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.Period; import org.alfresco.service.cmr.workflow.WorkflowDefinition; -import org.alfresco.service.cmr.workflow.WorkflowException; import org.alfresco.service.cmr.workflow.WorkflowInstance; import org.alfresco.service.cmr.workflow.WorkflowPath; import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowTask; +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; @@ -69,39 +51,78 @@ import org.springframework.util.StringUtils; * Temporary FormProcessor implementation that can generate and persist * Form objects for workflow definitions. * - * @author Gavin Cornwell + * @author Nick Smith */ public class WorkflowFormProcessor extends ContentModelFormProcessor { /** Logger */ - private static Log logger = LogFactory.getLog(WorkflowFormProcessor.class); + private final static Log logger = LogFactory.getLog(WorkflowFormProcessor.class); - public static final String TRANSIENT_PACKAGE_ITEMS = "packageItems"; + /** WorkflowService */ + private WorkflowService workflowService; - /** workflow service */ - protected WorkflowService workflowService; - - protected NodeService unprotectedNodeService; - - /** - * Sets the workflow service - * - * @param workflowService The WorkflowService instance + /** Unprotected Node Service */ + private NodeService unprotectedNodeService; + + /* (non-Javadoc) + * @see org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getAssociationValues(java.lang.Object) */ - public void setWorkflowService(WorkflowService workflowService) + @Override + protected Map getAssociationValues(WorkflowDefinition item) { - this.workflowService = workflowService; + return null; } - - public void setSmallNodeService(NodeService nodeService) + + /* (non-Javadoc) + * @see org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getBaseType(java.lang.Object) + */ + @Override + protected TypeDefinition getBaseType(WorkflowDefinition item) { - this.unprotectedNodeService = nodeService; + //TODO I'm not sure this is safe as getStartTaskDefinition() is 'optional'. + WorkflowTaskDefinition startTask = item.getStartTaskDefinition(); + return startTask.getMetadata(); } - - /* - * @see - * org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getLogger - * () + + /* (non-Javadoc) + * @see org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getPropertyValues(java.lang.Object) + */ + @Override + protected Map getPropertyValues(WorkflowDefinition item) + { + return null; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getTransientValues(java.lang.Object) + */ + @Override + protected Map getTransientValues(WorkflowDefinition item) + { + return Collections.singletonMap( + PackageItemsFieldProcessor.KEY, Collections.EMPTY_LIST); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getItemType(java.lang.Object) + */ + @Override + protected String getItemType(WorkflowDefinition item) + { + return item.name; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getItemURI(java.lang.Object) + */ + @Override + protected String getItemURI(WorkflowDefinition item) + { + return "api/workflow-definitions/"+item.id; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getLogger() */ @Override protected Log getLogger() @@ -109,6 +130,11 @@ public class WorkflowFormProcessor extends ContentModelFormProcessor fields, - List forcedFields, Form form, Map context) - { - if (logger.isDebugEnabled()) logger.debug("Generating form for item: " + workflowDef); - - // generate the form for the workflow definition - form.getItem().setType(workflowDef.name); - form.getItem().setUrl("/api/workflow-definition/" + workflowDef.id); - - // get the type of the start task for the workflow definition - TypeDefinition typeDef = workflowDef.getStartTaskDefinition().metadata; - - if (fields != null && fields.size() > 0) - { - generateSelectedFields(null, typeDef, fields, forcedFields, form); - } - else - { - // setup field definitions and data - generateAllPropertyFields(typeDef, form); - generateAllAssociationFields(typeDef, form); - } - - // add the "packageItems" transient field - generatePackageItemsTransientField(form); - - if (logger.isDebugEnabled()) logger.debug("Generating form: " + form); - } - /** - * Generates the 'packageItems' field + * The itemId may be in a URL/Webscript-friendly format. If so it must be converted + * back to the proper workflow definition name. * - * @param form The Form instance to populate + * @param itemId */ - protected void generatePackageItemsTransientField(Form form) + private String decodeWorkflowDefinitionName(String itemId) { - // setup basic field info - AssociationFieldDefinition fieldDef = new AssociationFieldDefinition(TRANSIENT_PACKAGE_ITEMS, - "cm:content", Direction.TARGET); - fieldDef.setLabel("Items"); - fieldDef.setDescription("Items that are part of the workflow"); - fieldDef.setProtectedField(false); - fieldDef.setEndpointMandatory(false); - fieldDef.setEndpointMany(true); - - // define the data key name and set - fieldDef.setDataKeyName(ASSOC_DATA_PREFIX + TRANSIENT_PACKAGE_ITEMS); - - // add definition to the form - form.addFieldDefinition(fieldDef); + String defName = itemId; + if (itemId.contains("$")==false) + { + defName = itemId.replaceFirst("_", "$"); + } + if (itemId.contains(":")==false) + { + defName = defName.replaceFirst("_", ":"); + } + return defName; } - /** - * Sets up the field definitions for all the type's properties. - * - * @param typeDef The type being setup - * @param form The Form instance to populate - */ - protected void generateAllPropertyFields(TypeDefinition typeDef, Form form) - { - // iterate round the property defintions and setup field definition - Map propDefs = typeDef.getProperties(); - for (PropertyDefinition propDef : propDefs.values()) - { - generatePropertyField(propDef, form, this.namespaceService); - } - - // get all default aspects for the type and iterate round their - // property definitions too - List aspects = typeDef.getDefaultAspects(true); - for (AspectDefinition aspect : aspects) - { - propDefs = aspect.getProperties(); - for (PropertyDefinition propDef : propDefs.values()) - { - generatePropertyField(propDef, form, this.namespaceService); - } - } - } - - /** - * Sets up the field definitions for all the type's associations. - * - * @param typeDef The type being setup - * @param form The Form instance to populate - */ - protected void generateAllAssociationFields(TypeDefinition typeDef, Form form) - { - // iterate round the association defintions and setup field definition - Map assocDefs = typeDef.getAssociations(); - for (AssociationDefinition assocDef : assocDefs.values()) - { - generateAssociationField(assocDef, form, this.namespaceService); - } - - // get all default aspects for the type and iterate round their - // association definitions too - List aspects = typeDef.getDefaultAspects(true); - for (AspectDefinition aspect : aspects) - { - assocDefs = aspect.getAssociations(); - for (AssociationDefinition assocDef : assocDefs.values()) - { - generateAssociationField(assocDef, form, this.namespaceService); - } - } - } - /* * @see * org.alfresco.repo.forms.processor.node.NodeFormProcessor#internalPersist @@ -341,595 +263,10 @@ public class WorkflowFormProcessor extends ContentModelFormProcessor - * NOTE: This method is static so that it can serve as a helper method for - * FormFilter implementations as adding additional property fields is likely - * to be a common extension. - *

- * - * @param propDef The PropertyDefinition of the field to generate - * @param form The Form instance to populate - * @param namespaceService NamespaceService instance + * @param workflowService the workflowService to set */ - protected void generatePropertyField(PropertyDefinition propDef, Form form, NamespaceService namespaceService) + public void setWorkflowService(WorkflowService workflowService) { - generatePropertyField(propDef, form, null, null, namespaceService); - } - - /** - * Sets up a field definition for the given property. - *

- * NOTE: This method is static so that it can serve as a helper method for - * FormFilter implementations as adding additional property fields is likely - * to be a common extension. - *

- * - * @param propDef The PropertyDefinition of the field to generate - * @param form The Form instance to populate - * @param propValue The value of the property field - * @param namespaceService NamespaceService instance - */ - protected void generatePropertyField(PropertyDefinition propDef, Form form, Serializable propValue, - NamespaceService namespaceService) - { - generatePropertyField(propDef, form, propValue, null, namespaceService); - } - - /** - * Sets up a field definition for the given property. - *

- * NOTE: This method is static so that it can serve as a helper method for - * FormFilter implementations as adding additional property fields is likely - * to be a common extension. - *

- * - * @param propDef The PropertyDefinition of the field to generate - * @param form The Form instance to populate - * @param propValue The value of the property field - * @param group The FieldGroup the property field belongs to, can be null - * @param namespaceService NamespaceService instance - */ - @SuppressWarnings("unchecked") - protected void generatePropertyField(PropertyDefinition propDef, Form form, Serializable propValue, - FieldGroup group, NamespaceService namespaceService) - { - String propName = propDef.getName().toPrefixString(namespaceService); - String[] nameParts = QName.splitPrefixedQName(propName); - PropertyFieldDefinition fieldDef = new PropertyFieldDefinition(propName, propDef.getDataType().getName() - .getLocalName()); - - String title = propDef.getTitle(); - if (title == null) - { - title = propName; - } - fieldDef.setLabel(title); - fieldDef.setDefaultValue(propDef.getDefaultValue()); - fieldDef.setDescription(propDef.getDescription()); - fieldDef.setMandatory(propDef.isMandatory()); - fieldDef.setProtectedField(propDef.isProtected()); - fieldDef.setRepeating(propDef.isMultiValued()); - fieldDef.setGroup(group); - - // any property from the system model (sys prefix) should be protected - // the model doesn't currently enforce this so make sure they are not - // editable - if (NamespaceService.SYSTEM_MODEL_1_0_URI.equals(propDef.getName().getNamespaceURI())) - { - fieldDef.setProtectedField(true); - } - - // define the data key name and set - String dataKeyName = PROP_DATA_PREFIX + nameParts[0] + DATA_KEY_SEPARATOR + nameParts[1]; - fieldDef.setDataKeyName(dataKeyName); - - // setup any parameters requried for the data type - if (propDef.getDataType().getName().equals(DataTypeDefinition.PERIOD)) - { - // if the property data type is d:period we need to setup a data - // type parameters object to represent the options and rules - PeriodDataTypeParameters periodOptions = new PeriodDataTypeParameters(); - Set providers = Period.getProviderNames(); - for (String provider : providers) - { - periodOptions.addPeriodProvider(Period.getProvider(provider)); - } - - fieldDef.setDataTypeParameters(periodOptions); - } - - // setup constraints for the property - List constraints = propDef.getConstraints(); - if (constraints != null && constraints.size() > 0) - { - List fieldConstraints = new ArrayList(constraints.size()); - - for (ConstraintDefinition constraintDef : constraints) - { - Constraint constraint = constraintDef.getConstraint(); - FieldConstraint fieldConstraint = new FieldConstraint(constraint.getType(), constraint.getParameters()); - fieldConstraints.add(fieldConstraint); - } - - fieldDef.setConstraints(fieldConstraints); - } - - form.addFieldDefinition(fieldDef); - - // add the property value to the form - if (propValue != null) - { - if (propValue instanceof List) - { - // temporarily add repeating field data as a comma - // separated list, this will be changed to using - // a separate field for each value once we have full - // UI support in place. - propValue = StringUtils.collectionToCommaDelimitedString((List) propValue); - } - else if (propValue instanceof ContentData) - { - // for content properties retrieve the info URL rather than the - // the object value itself - propValue = ((ContentData)propValue).getInfoUrl(); - } - - form.addData(dataKeyName, propValue); - } - } - - /** - * Sets up a field definition for the given association. - *

- * NOTE: This method is static so that it can serve as a helper method for - * FormFilter implementations as adding additional association fields is - * likely to be a common extension. - *

- * - * @param assocDef The AssociationDefinition of the field to generate - * @param form The Form instance to populate - * @param namespaceService NamespaceService instance - */ - protected void generateAssociationField(AssociationDefinition assocDef, Form form, - NamespaceService namespaceService) - { - generateAssociationField(assocDef, form, null, null, namespaceService); - } - - /** - * Sets up a field definition for the given association. - *

- * NOTE: This method is static so that it can serve as a helper method for - * FormFilter implementations as adding additional association fields is - * likely to be a common extension. - *

- * - * @param assocDef The AssociationDefinition of the field to generate - * @param form The Form instance to populate - * @param assocValues The values of the association field, can be null - * @param namespaceService NamespaceService instance - */ - @SuppressWarnings("unchecked") - protected void generateAssociationField(AssociationDefinition assocDef, Form form, List assocValues, - NamespaceService namespaceService) - { - generateAssociationField(assocDef, form, assocValues, null, namespaceService); - } - - /** - * Sets up a field definition for the given association. - *

- * NOTE: This method is static so that it can serve as a helper method for - * FormFilter implementations as adding additional association fields is - * likely to be a common extension. - *

- * - * @param assocDef The AssociationDefinition of the field to generate - * @param form The Form instance to populate - * @param assocValues The values of the association field, can be null - * @param group The FieldGroup the association field belongs to, can be null - * @param namespaceService NamespaceService instance - */ - @SuppressWarnings("unchecked") - protected static void generateAssociationField(AssociationDefinition assocDef, Form form, List assocValues, - FieldGroup group, NamespaceService namespaceService) - { - String assocName = assocDef.getName().toPrefixString(namespaceService); - String[] nameParts = QName.splitPrefixedQName(assocName); - AssociationFieldDefinition fieldDef = new AssociationFieldDefinition(assocName, assocDef.getTargetClass() - .getName().toPrefixString(namespaceService), Direction.TARGET); - String title = assocDef.getTitle(); - if (title == null) - { - title = assocName; - } - fieldDef.setLabel(title); - fieldDef.setDescription(assocDef.getDescription()); - fieldDef.setProtectedField(assocDef.isProtected()); - fieldDef.setEndpointMandatory(assocDef.isTargetMandatory()); - fieldDef.setEndpointMany(assocDef.isTargetMany()); - fieldDef.setGroup(group); - - // define the data key name and set - String dataKeyName = ASSOC_DATA_PREFIX + nameParts[0] + DATA_KEY_SEPARATOR + nameParts[1]; - fieldDef.setDataKeyName(dataKeyName); - - // add definition to the form - form.addFieldDefinition(fieldDef); - - if (assocValues != null) - { - // add the association value to the form - // determine the type of association values data and extract - // accordingly - List values = new ArrayList(4); - for (Object value : assocValues) - { - if (value instanceof ChildAssociationRef) - { - values.add(((ChildAssociationRef) value).getChildRef().toString()); - } - else if (value instanceof AssociationRef) - { - values.add(((AssociationRef) value).getTargetRef().toString()); - } - else - { - values.add(value.toString()); - } - } - - // Add the list as the value for the association. - form.addData(dataKeyName, values); - } - } - - /** - * Sets up the field definitions for all the requested fields. - *

- * A NodeRef or TypeDefinition can be provided, however, if a NodeRef is - * provided all type information will be derived from the NodeRef and the - * TypeDefinition will be ignored. - *

- *

- * If any of the requested fields are not present on the type and they - * appear in the forcedFields list an attempt to find a model definition for - * those fields is made so they can be included. - *

- * - * @param nodeRef The NodeRef of the item being generated - * @param typeDef The TypeDefiniton of the item being generated - * @param fields Restricted list of fields to include - * @param forcedFields List of field names that should be included even if - * the field is not currently present - * @param form The Form instance to populate - */ - protected void generateSelectedFields(NodeRef nodeRef, TypeDefinition typeDef, List fields, - List forcedFields, Form form) - { - // ensure a NodeRef or TypeDefinition is provided - if (nodeRef == null && typeDef == null) { throw new IllegalArgumentException( - "A NodeRef or TypeDefinition must be provided"); } - - if (getLogger().isDebugEnabled()) - getLogger().debug("Generating selected fields: " + fields + " and forcing: " + forcedFields); - - // get data dictionary definition for node if it is provided - QName type = null; - Map propValues = Collections.emptyMap(); - Map propDefs = null; - Map assocDefs = null; - - if (nodeRef != null) - { - type = this.nodeService.getType(nodeRef); - typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService.getAspects(nodeRef)); - - // NOTE: the anonymous type returns all property and association - // defs - // for all aspects applied as well as the type - propDefs = typeDef.getProperties(); - assocDefs = typeDef.getAssociations(); - propValues = this.nodeService.getProperties(nodeRef); - } - else - { - type = typeDef.getName(); - - // we only get the properties and associations of the actual type so - // we also need to manually get properties and associations from any - // mandatory aspects - propDefs = new HashMap(16); - assocDefs = new HashMap(16); - propDefs.putAll(typeDef.getProperties()); - assocDefs.putAll(typeDef.getAssociations()); - - List aspects = typeDef.getDefaultAspects(true); - for (AspectDefinition aspect : aspects) - { - propDefs.putAll(aspect.getProperties()); - assocDefs.putAll(aspect.getAssociations()); - } - } - - for (String fieldName : fields) - { - // try and split the field name - String[] parts = fieldName.split(":"); - if (parts.length == 2 || parts.length == 3) - { - boolean foundField = false; - boolean tryProperty = true; - boolean tryAssociation = true; - String qNamePrefix = null; - String localName = null; - - if (parts.length == 2) - { - qNamePrefix = parts[0]; - localName = parts[1]; - } - else - { - // if there are 3 parts to the field name the first one - // represents - // whether the field is a property or association i.e. - // prop:prefix:local - // or assoc:prefix:local, determine the prefix and ensure - // it's valid - if (PROP.equals(parts[0])) - { - tryAssociation = false; - } - else if (ASSOC.equals(parts[0])) - { - tryProperty = false; - } - else - { - if (getLogger().isWarnEnabled()) - getLogger() - .warn( - "\"" - + parts[0] - + "\" is an invalid prefix for requesting a property or association"); - - continue; - } - - qNamePrefix = parts[1]; - localName = parts[2]; - } - - // create qname of field name - QName fullQName = QName.createQName(qNamePrefix, localName, namespaceService); - - // try the field as a property - if (tryProperty) - { - // lookup property def on node - PropertyDefinition propDef = propDefs.get(fullQName); - if (propDef != null) - { - // generate the property field - generatePropertyField(propDef, form, propValues.get(fullQName), this.namespaceService); - - // no need to try and find an association - tryAssociation = false; - foundField = true; - } - } - - // try the field as an association - if (tryAssociation) - { - AssociationDefinition assocDef = assocDefs.get(fullQName); - if (assocDef != null) - { - // generate the association field - generateAssociationField(assocDef, form, (nodeRef != null) ? retrieveAssociationValues(nodeRef, - assocDef) : null, this.namespaceService); - - foundField = true; - } - } - - // still not found the field, is it a force'd field? - if (!foundField) - { - if (forcedFields != null && forcedFields.size() > 0 && forcedFields.contains(fieldName)) - { - generateForcedField(fieldName, form); - } - else if (getLogger().isDebugEnabled()) - { - getLogger().debug( - "Ignoring field \"" + fieldName + "\" as it is not defined for the current " - + ((nodeRef != null) ? "node" : "type") - + " and it does not appear in the 'force' list"); - } - } - } - else - { - // see if the fieldName is a well known transient property - if (TRANSIENT_MIMETYPE.equals(fieldName) || TRANSIENT_ENCODING.equals(fieldName) - || TRANSIENT_SIZE.equals(fieldName)) - { - // if the node type is content or sublcass thereof generate appropriate field - if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) - { - ContentData content = null; - - if (nodeRef != null) - { - content = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); - } - - if (TRANSIENT_MIMETYPE.equals(fieldName)) - { - generateMimetypePropertyField(content, form); - } - else if (TRANSIENT_ENCODING.equals(fieldName)) - { - generateEncodingPropertyField(content, form); - } - else if (TRANSIENT_SIZE.equals(fieldName)) - { - generateSizePropertyField(content, form); - } - } - } - else if (getLogger().isWarnEnabled()) - { - getLogger().warn("Ignoring unrecognised field \"" + fieldName + "\""); - } - } - } - } - - /** - * Generates a field definition for the given field that is being forced to - * show. - * - * @param fieldName Name of the field to force - * @param form The Form instance to populated - */ - protected void generateForcedField(String fieldName, Form form) - { - if (getLogger().isDebugEnabled()) - getLogger().debug("Attempting to force the inclusion of field \"" + fieldName + "\""); - - String[] parts = fieldName.split(":"); - if (parts.length == 2 || parts.length == 3) - { - boolean foundField = false; - boolean tryProperty = true; - boolean tryAssociation = true; - String qNamePrefix = null; - String localName = null; - - if (parts.length == 2) - { - qNamePrefix = parts[0]; - localName = parts[1]; - } - else - { - // if there are 3 parts to the field name the first one - // represents - // whether the field is a property or association i.e. - // prop:prefix:local - // or assoc:prefix:local, determine the prefix and ensure it's - // valid - if (PROP.equals(parts[0])) - { - tryAssociation = false; - } - else if (ASSOC.equals(parts[0])) - { - tryProperty = false; - } - else - { - if (getLogger().isWarnEnabled()) - getLogger().warn( - "\"" + parts[0] - + "\" is an invalid prefix for requesting a property or association"); - - return; - } - - qNamePrefix = parts[1]; - localName = parts[2]; - } - - // create qname of field name - QName fullQName = QName.createQName(qNamePrefix, localName, namespaceService); - - if (tryProperty) - { - // lookup the field as a property in the whole model - PropertyDefinition propDef = this.dictionaryService.getProperty(fullQName); - if (propDef != null) - { - // generate the property field - generatePropertyField(propDef, form, this.namespaceService); - - // no need to try and find an association - tryAssociation = false; - foundField = true; - } - } - - if (tryAssociation) - { - // lookup the field as an association in the whole model - AssociationDefinition assocDef = this.dictionaryService.getAssociation(fullQName); - if (assocDef != null) - { - // generate the association field - generateAssociationField(assocDef, form, this.namespaceService); - - foundField = true; - } - } - - if (!foundField && getLogger().isDebugEnabled()) - { - getLogger() - .debug( - "Ignoring field \"" - + fieldName - + "\" as it is not defined for the current node and can not be found in any model"); - } - } - else if (getLogger().isWarnEnabled()) - { - getLogger().warn("Ignoring unrecognised field \"" + fieldName + "\""); - } - } - - /* (non-Javadoc) - * @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getItemType(java.lang.Object) - */ - @Override - protected String getItemType(WorkflowDefinition item) - { - return item.name; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getItemURI(java.lang.Object) - */ - @Override - protected String getItemURI(WorkflowDefinition item) - { - return "/api/workflow-definitions/" + item.id; - } - - @Override - protected Map getAssociationValues(WorkflowDefinition item) - { - return null; - } - - @Override - protected Map getPropertyValues(WorkflowDefinition item) - { - return null; - } - - @Override - protected Map getTransientValues(WorkflowDefinition item) - { - return null; - } - - @Override - protected TypeDefinition getBaseType(WorkflowDefinition item) - { - return item.getStartTaskDefinition().metadata; + this.workflowService = workflowService; } } diff --git a/source/java/org/alfresco/service/cmr/workflow/WorkflowTaskDefinition.java b/source/java/org/alfresco/service/cmr/workflow/WorkflowTaskDefinition.java index 74ae18d632..19c1a718be 100644 --- a/source/java/org/alfresco/service/cmr/workflow/WorkflowTaskDefinition.java +++ b/source/java/org/alfresco/service/cmr/workflow/WorkflowTaskDefinition.java @@ -40,10 +40,34 @@ public class WorkflowTaskDefinition /** Task Metadata */ public TypeDefinition metadata; + /** + * @return the id + */ + public String getId() + { + return id; + } + + /** + * @return the metadata + */ + public TypeDefinition getMetadata() + { + return metadata; + } + + /** + * @return the node + */ + public WorkflowNode getNode() + { + return node; + } /* (non-Javadoc) * @see java.lang.Object#toString() */ + @Override public String toString() { return "WorkflowTaskDefinition[id=" + id + ",metadata=" + metadata + "]";