diff --git a/source/java/org/alfresco/repo/forms/processor/AbstractFormProcessor.java b/source/java/org/alfresco/repo/forms/processor/AbstractFormProcessor.java index 9569cea6b3..cde8dd7f77 100644 --- a/source/java/org/alfresco/repo/forms/processor/AbstractFormProcessor.java +++ b/source/java/org/alfresco/repo/forms/processor/AbstractFormProcessor.java @@ -22,28 +22,33 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ + package org.alfresco.repo.forms.processor; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.alfresco.repo.forms.Form; import org.alfresco.repo.forms.Item; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * Abstract base class for all FormProcessor implementations provides - * a regex pattern match to test for processor applicability - * + * Abstract base class for all FormProcessor implementations provides a regex + * pattern match to test for processor applicability + * * @author Gavin Cornwell */ public abstract class AbstractFormProcessor implements FormProcessor { private static final Log logger = LogFactory.getLog(AbstractFormProcessor.class); - + protected FormProcessorRegistry processorRegistry; + protected String matchPattern; + protected boolean active = true; + protected Pattern patternMatcher; /** @@ -55,11 +60,12 @@ public abstract class AbstractFormProcessor implements FormProcessor { this.processorRegistry = processorRegistry; } - + /** * Sets the match pattern * - * @param pattern The regex pattern to use to determine if this processor is applicable + * @param pattern The regex pattern to use to determine if this processor is + * applicable */ public void setMatchPattern(String pattern) { @@ -84,16 +90,18 @@ public abstract class AbstractFormProcessor implements FormProcessor if (this.processorRegistry == null) { if (logger.isWarnEnabled()) - logger.warn("Property 'processorRegistry' has not been set. Ignoring auto-registration of processor: " + this); - + logger.warn("Property 'processorRegistry' has not been set. Ignoring auto-registration of processor: " + + this); + return; } - + if (this.matchPattern == null) { if (logger.isWarnEnabled()) - logger.warn("Property 'matchPattern' has not been set. Ignoring auto-registration of processor: " + this); - + logger.warn("Property 'matchPattern' has not been set. Ignoring auto-registration of processor: " + + this); + return; } else @@ -105,7 +113,7 @@ public abstract class AbstractFormProcessor implements FormProcessor // register this instance this.processorRegistry.addProcessor(this); } - + /* * @see org.alfresco.repo.forms.processor.FormProcessor#isActive() */ @@ -115,22 +123,25 @@ public abstract class AbstractFormProcessor implements FormProcessor } /* - * @see org.alfresco.repo.forms.processor.FormProcessor#isApplicable(org.alfresco.repo.forms.Item) + * @see + * org.alfresco.repo.forms.processor.FormProcessor#isApplicable(org.alfresco + * .repo.forms.Item) */ public boolean isApplicable(Item item) { // this form processor matches if the match pattern provided matches // the kind of the item provided - + Matcher matcher = patternMatcher.matcher(item.getKind()); boolean matches = matcher.matches(); - + if (logger.isDebugEnabled()) - logger.debug("Checking processor " + this + " for applicability for item '" + item + "', result = " + matches); - + logger.debug("Checking processor " + this + " for applicability for item '" + item + "', result = " + + matches); + return matches; } - + /* * @see java.lang.Object#toString() */ @@ -143,4 +154,29 @@ public abstract class AbstractFormProcessor implements FormProcessor buffer.append(")"); return buffer.toString(); } + + /** + * Gets the Item from the form parameter and sets its type + * field to type. + * + * @param form + * @param type + */ + protected void setFormItemType(Form form, String type) + { + form.getItem().setType(type); + } + + /** + * Gets the Item from the form parameter and sets its URL field + * to url. + * + * @param form + * @param url + */ + protected void setFormItemUrl(Form form, String url) + { + form.getItem().setUrl(url); + } + } diff --git a/source/java/org/alfresco/repo/forms/processor/FilteredFormProcessor.java b/source/java/org/alfresco/repo/forms/processor/FilteredFormProcessor.java index c94f406cd4..b6a5372bb6 100644 --- a/source/java/org/alfresco/repo/forms/processor/FilteredFormProcessor.java +++ b/source/java/org/alfresco/repo/forms/processor/FilteredFormProcessor.java @@ -75,7 +75,7 @@ public abstract class FilteredFormProcessor extends Abstr // inform all regsitered filters the form is about to be generated if (this.filterRegistry != null) { - for (Filter filter : this.filterRegistry.getFilters()) + for (Filter filter : this.filterRegistry.getFilters()) { filter.beforeGenerate(typedItem, fields, forcedFields, form, context); } @@ -87,7 +87,7 @@ public abstract class FilteredFormProcessor extends Abstr // inform all regsitered filters the form has been generated if (this.filterRegistry != null) { - for (Filter filter : this.filterRegistry.getFilters()) + for (Filter filter : this.filterRegistry.getFilters()) { filter.afterGenerate(typedItem, fields, forcedFields, form, context); } @@ -114,19 +114,19 @@ public abstract class FilteredFormProcessor extends Abstr // inform all regsitered filters the form is about to be persisted if (this.filterRegistry != null) { - for (Filter filter : this.filterRegistry.getFilters()) + for (Filter filter : this.filterRegistry.getFilters()) { filter.beforePersist(typedItem, data); } } // perform the actual persistence of the form - Object persistedObject = internalPersist(typedItem, data); + PersistType persistedObject = internalPersist(typedItem, data); // inform all regsitered filters the form has been persisted if (this.filterRegistry != null) { - for (Filter filter : this.filterRegistry.getFilters()) + for (Filter filter : this.filterRegistry.getFilters()) { filter.afterPersist(typedItem, data, persistedObject); } @@ -135,16 +135,6 @@ public abstract class FilteredFormProcessor extends Abstr return persistedObject; } - protected void setItemType(Form form, String type) - { - form.getItem().setType(type); - } - - protected void setItemUrl(Form form, String url) - { - form.getItem().setUrl(url); - } - /** * Returns a typed Object representing the given item. *

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 e099fbce29..66da5f8f3f 100644 --- a/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java +++ b/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java @@ -125,8 +125,7 @@ public abstract class ContentModelFormProcessor extends * pattern can also be used to extract the "cm", the "name" and the suffix * parts. */ - protected Pattern associationNamePattern = Pattern.compile(ASSOC_DATA_PREFIX - + "(.*){1}?_(.*){1}?(_[a-zA-Z]+)"); + protected Pattern associationNamePattern = Pattern.compile(ASSOC_DATA_PREFIX + "(.*){1}?_(.*){1}?(_[a-zA-Z]+)"); /** * Sets the node service @@ -180,8 +179,7 @@ public abstract class ContentModelFormProcessor extends * @param form The Form instance to populate * @param namespaceService NamespaceService instance */ - public static void generatePropertyField(PropertyDefinition propDef, Form form, - NamespaceService namespaceService) + public static void generatePropertyField(PropertyDefinition propDef, Form form, NamespaceService namespaceService) { generatePropertyField(propDef, form, null, null, namespaceService); } @@ -199,8 +197,8 @@ public abstract class ContentModelFormProcessor extends * @param propValue The value of the property field * @param namespaceService NamespaceService instance */ - public static void generatePropertyField(PropertyDefinition propDef, Form form, - Serializable propValue, NamespaceService namespaceService) + public static void generatePropertyField(PropertyDefinition propDef, Form form, Serializable propValue, + NamespaceService namespaceService) { generatePropertyField(propDef, form, propValue, null, namespaceService); } @@ -220,13 +218,13 @@ public abstract class ContentModelFormProcessor extends * @param namespaceService NamespaceService instance */ @SuppressWarnings("unchecked") - public static void generatePropertyField(PropertyDefinition propDef, Form form, - Serializable propValue, FieldGroup group, NamespaceService namespaceService) + public static 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()); + PropertyFieldDefinition fieldDef = new PropertyFieldDefinition(propName, propDef.getDataType().getName() + .getLocalName()); String title = propDef.getTitle(); if (title == null) @@ -272,14 +270,12 @@ public abstract class ContentModelFormProcessor extends List constraints = propDef.getConstraints(); if (constraints != null && constraints.size() > 0) { - List fieldConstraints = new ArrayList(constraints - .size()); + List fieldConstraints = new ArrayList(constraints.size()); for (ConstraintDefinition constraintDef : constraints) { Constraint constraint = constraintDef.getConstraint(); - FieldConstraint fieldConstraint = new FieldConstraint(constraint.getType(), - constraint.getParameters()); + FieldConstraint fieldConstraint = new FieldConstraint(constraint.getType(), constraint.getParameters()); fieldConstraints.add(fieldConstraint); } @@ -336,8 +332,8 @@ public abstract class ContentModelFormProcessor extends * @param namespaceService NamespaceService instance */ @SuppressWarnings("unchecked") - public static void generateAssociationField(AssociationDefinition assocDef, Form form, - List assocValues, NamespaceService namespaceService) + public static void generateAssociationField(AssociationDefinition assocDef, Form form, List assocValues, + NamespaceService namespaceService) { generateAssociationField(assocDef, form, assocValues, null, namespaceService); } @@ -357,13 +353,13 @@ public abstract class ContentModelFormProcessor extends * @param namespaceService NamespaceService instance */ @SuppressWarnings("unchecked") - public static void generateAssociationField(AssociationDefinition assocDef, Form form, - List assocValues, FieldGroup group, NamespaceService namespaceService) + public 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); + AssociationFieldDefinition fieldDef = new AssociationFieldDefinition(assocName, assocDef.getTargetClass() + .getName().toPrefixString(namespaceService), Direction.TARGET); String title = assocDef.getTitle(); if (title == null) { @@ -437,16 +433,15 @@ public abstract class ContentModelFormProcessor extends * 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) + 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); + getLogger().debug("Generating selected fields: " + fields + " and forcing: " + forcedFields); // get data dictionary definition for node if it is provided QName type = null; @@ -457,8 +452,7 @@ public abstract class ContentModelFormProcessor extends if (nodeRef != null) { type = this.nodeService.getType(nodeRef); - typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService - .getAspects(nodeRef)); + typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService.getAspects(nodeRef)); // NOTE: the anonymous type returns all property and association // defs @@ -547,8 +541,7 @@ public abstract class ContentModelFormProcessor extends if (propDef != null) { // generate the property field - generatePropertyField(propDef, form, propValues.get(fullQName), - this.namespaceService); + generatePropertyField(propDef, form, propValues.get(fullQName), this.namespaceService); // no need to try and find an association tryAssociation = false; @@ -563,11 +556,8 @@ public abstract class ContentModelFormProcessor extends if (assocDef != null) { // generate the association field - generateAssociationField( - assocDef, - form, - (nodeRef != null) ? retrieveAssociationValues(nodeRef, assocDef) - : null, this.namespaceService); + generateAssociationField(assocDef, form, (nodeRef != null) ? retrieveAssociationValues(nodeRef, + assocDef) : null, this.namespaceService); foundField = true; } @@ -576,16 +566,14 @@ public abstract class ContentModelFormProcessor extends // still not found the field, is it a force'd field? if (!foundField) { - if (forcedFields != null && forcedFields.size() > 0 - && forcedFields.contains(fieldName)) + 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 " + "Ignoring field \"" + fieldName + "\" as it is not defined for the current " + ((nodeRef != null) ? "node" : "type") + " and it does not appear in the 'force' list"); } @@ -599,9 +587,7 @@ public abstract class ContentModelFormProcessor extends { // if the node type is content or sublcass thereof generate // appropriate field - if (nodeRef != null - && this.dictionaryService.isSubClass(type, - ContentModel.TYPE_CONTENT)) + if (nodeRef != null && this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) { ContentData content = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); @@ -675,11 +661,9 @@ public abstract class ContentModelFormProcessor extends else { if (getLogger().isWarnEnabled()) - getLogger() - .warn( - "\"" - + parts[0] - + "\" is an invalid prefix for requesting a property or association"); + getLogger().warn( + "\"" + parts[0] + + "\" is an invalid prefix for requesting a property or association"); return; } @@ -743,8 +727,8 @@ public abstract class ContentModelFormProcessor extends protected void generateMimetypePropertyField(ContentData content, Form form) { String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_MIMETYPE; - PropertyFieldDefinition mimetypeField = new PropertyFieldDefinition(TRANSIENT_MIMETYPE, - DataTypeDefinition.TEXT.getLocalName()); + 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); @@ -765,8 +749,8 @@ public abstract class ContentModelFormProcessor extends protected void generateEncodingPropertyField(ContentData content, Form form) { String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_ENCODING; - PropertyFieldDefinition encodingField = new PropertyFieldDefinition(TRANSIENT_ENCODING, - DataTypeDefinition.TEXT.getLocalName()); + 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); @@ -787,8 +771,8 @@ public abstract class ContentModelFormProcessor extends protected void generateSizePropertyField(ContentData content, Form form) { String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_SIZE; - PropertyFieldDefinition sizeField = new PropertyFieldDefinition(TRANSIENT_SIZE, - DataTypeDefinition.LONG.getLocalName()); + 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); @@ -818,8 +802,7 @@ public abstract class ContentModelFormProcessor extends // get the list of values (if any) for the association if (assocDef instanceof ChildAssociationDefinition) { - assocValues = this.nodeService.getChildAssocs(nodeRef, assocDef.getName(), - RegexQNamePattern.MATCH_ALL); + assocValues = this.nodeService.getChildAssocs(nodeRef, assocDef.getName(), RegexQNamePattern.MATCH_ALL); } else { @@ -839,14 +822,12 @@ public abstract class ContentModelFormProcessor extends { // get the property definitions for the type of node being persisted QName type = this.nodeService.getType(nodeRef); - TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService - .getAspects(nodeRef)); + TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService.getAspects(nodeRef)); Map assocDefs = typeDef.getAssociations(); Map childAssocDefs = typeDef.getChildAssociations(); Map propDefs = typeDef.getProperties(); - Map propsToPersist = new HashMap(data - .getNumberOfFields()); + Map propsToPersist = new HashMap(data.getNumberOfFields()); List assocsToPersist = new ArrayList(); for (FieldData fieldData : data) @@ -862,8 +843,7 @@ public abstract class ContentModelFormProcessor extends } else if (fieldName.startsWith(ASSOC_DATA_PREFIX)) { - processAssociationPersist(nodeRef, assocDefs, childAssocDefs, fieldData, - assocsToPersist); + processAssociationPersist(nodeRef, assocDefs, childAssocDefs, fieldData, assocsToPersist); } else if (getLogger().isWarnEnabled()) { @@ -1004,8 +984,7 @@ public abstract class ContentModelFormProcessor extends // everything else // should be represented as null if (!propDef.getDataType().getName().equals(DataTypeDefinition.TEXT) - && !propDef.getDataType().getName().equals( - DataTypeDefinition.MLTEXT)) + && !propDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT)) { value = null; } @@ -1018,8 +997,7 @@ public abstract class ContentModelFormProcessor extends else if (getLogger().isWarnEnabled()) { getLogger().warn( - "Ignoring field '" + fieldData.getName() - + "' as a property definition can not be found"); + "Ignoring field '" + fieldData.getName() + "' as a property definition can not be found"); } } else @@ -1064,8 +1042,7 @@ public abstract class ContentModelFormProcessor extends * @param fieldData Data to persist for the associations * @param assocCommands List of associations to be persisted */ - protected void processAssociationPersist(NodeRef nodeRef, - Map assocDefs, + protected void processAssociationPersist(NodeRef nodeRef, Map assocDefs, Map childAssocDefs, FieldData fieldData, List assocCommands) { @@ -1102,9 +1079,7 @@ public abstract class ContentModelFormProcessor extends { if (getLogger().isWarnEnabled()) { - getLogger().warn( - "Definition for association " + fullQName - + " not recognised and not persisted."); + getLogger().warn("Definition for association " + fullQName + " not recognised and not persisted."); } return; } @@ -1125,26 +1100,25 @@ public abstract class ContentModelFormProcessor extends { if (assocDef.isChild()) { - assocCommands.add(new AddChildAssocCommand(nodeRef, new NodeRef( - nextTargetNode), fullQName)); + assocCommands.add(new AddChildAssocCommand(nodeRef, new NodeRef(nextTargetNode), + fullQName)); } else { - assocCommands.add(new AddAssocCommand(nodeRef, new NodeRef( - nextTargetNode), fullQName)); + assocCommands.add(new AddAssocCommand(nodeRef, new NodeRef(nextTargetNode), fullQName)); } } else if (assocSuffix.equals(ASSOC_DATA_REMOVED_SUFFIX)) { if (assocDef.isChild()) { - assocCommands.add(new RemoveChildAssocCommand(nodeRef, new NodeRef( - nextTargetNode), fullQName)); + assocCommands.add(new RemoveChildAssocCommand(nodeRef, new NodeRef(nextTargetNode), + fullQName)); } else { - assocCommands.add(new RemoveAssocCommand(nodeRef, new NodeRef( - nextTargetNode), fullQName)); + assocCommands.add(new RemoveAssocCommand(nodeRef, new NodeRef(nextTargetNode), + fullQName)); } } else @@ -1153,10 +1127,9 @@ public abstract class ContentModelFormProcessor extends { StringBuilder msg = new StringBuilder(); msg.append("fieldName ").append(fieldName).append( - " does not have one of the expected suffixes [") - .append(ASSOC_DATA_ADDED_SUFFIX).append(", ").append( - ASSOC_DATA_REMOVED_SUFFIX).append( - "] and has been ignored."); + " does not have one of the expected suffixes [").append( + ASSOC_DATA_ADDED_SUFFIX).append(", ").append(ASSOC_DATA_REMOVED_SUFFIX) + .append("] and has been ignored."); getLogger().warn(msg.toString()); } } @@ -1215,8 +1188,7 @@ public abstract class ContentModelFormProcessor extends if (contentData == null) { // content data has not been persisted yet so get it from the node - contentData = (ContentData) this.nodeService.getProperty(nodeRef, - ContentModel.PROP_CONTENT); + contentData = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); } if (contentData != null) @@ -1241,8 +1213,7 @@ public abstract class ContentModelFormProcessor extends if (contentData == null) { // content data has not been persisted yet so get it from the node - contentData = (ContentData) this.nodeService.getProperty(nodeRef, - ContentModel.PROP_CONTENT); + contentData = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); } if (contentData != null) @@ -1300,8 +1271,7 @@ class AddAssocCommand extends AbstractAssocCommand @Override protected void updateAssociations(NodeService nodeService) { - List existingAssocs = nodeService - .getTargetAssocs(sourceNodeRef, assocQName); + List existingAssocs = nodeService.getTargetAssocs(sourceNodeRef, assocQName); for (AssociationRef assoc : existingAssocs) { if (assoc.getTargetRef().equals(targetNodeRef)) @@ -1334,8 +1304,7 @@ class RemoveAssocCommand extends AbstractAssocCommand @Override protected void updateAssociations(NodeService nodeService) { - List existingAssocs = nodeService - .getTargetAssocs(sourceNodeRef, assocQName); + List existingAssocs = nodeService.getTargetAssocs(sourceNodeRef, assocQName); boolean assocDoesNotExist = true; for (AssociationRef assoc : existingAssocs) { @@ -1350,8 +1319,8 @@ class RemoveAssocCommand extends AbstractAssocCommand if (logger.isWarnEnabled()) { StringBuilder msg = new StringBuilder(); - msg.append("Attempt to remove non-existent association prevented. ").append( - sourceNodeRef).append("|").append(targetNodeRef).append(assocQName); + msg.append("Attempt to remove non-existent association prevented. ").append(sourceNodeRef).append("|") + .append(targetNodeRef).append(assocQName); logger.warn(msg.toString()); } return; @@ -1432,8 +1401,8 @@ class RemoveChildAssocCommand extends AbstractAssocCommand if (logger.isWarnEnabled()) { StringBuilder msg = new StringBuilder(); - msg.append("Attempt to remove non-existent child association prevented. ").append( - sourceNodeRef).append("|").append(targetNodeRef).append(assocQName); + msg.append("Attempt to remove non-existent child association prevented. ").append(sourceNodeRef) + .append("|").append(targetNodeRef).append(assocQName); logger.warn(msg.toString()); } return; 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 d4fa251702..81c750e02a 100644 --- a/source/java/org/alfresco/repo/forms/processor/node/NodeFormProcessor.java +++ b/source/java/org/alfresco/repo/forms/processor/node/NodeFormProcessor.java @@ -95,21 +95,19 @@ public class NodeFormProcessor extends ContentModelFormProcessor fields, List forcedFields, - Form form, Map context) + protected void internalGenerate(NodeRef item, List fields, List forcedFields, Form form, + Map context) { if (logger.isDebugEnabled()) logger.debug("Generating form for: " + item); @@ -144,17 +142,17 @@ public class NodeFormProcessor extends ContentModelFormProcessor fields, List forcedFields, - Form form) + protected void generateNode(NodeRef nodeRef, List fields, List forcedFields, Form form) { // set the type and URL of the item QName type = this.nodeService.getType(nodeRef); - form.getItem().setType(type.toPrefixString(this.namespaceService)); + setFormItemType(form, type.toPrefixString(this.namespaceService)); + StringBuilder builder = new StringBuilder("/api/node/"); builder.append(nodeRef.getStoreRef().getProtocol()).append("/"); builder.append(nodeRef.getStoreRef().getIdentifier()).append("/"); builder.append(nodeRef.getId()); - form.getItem().setUrl(builder.toString()); + setFormItemUrl(form, builder.toString()); if (fields != null && fields.size() > 0) { @@ -179,8 +177,7 @@ public class NodeFormProcessor extends ContentModelFormProcessor propValues = this.nodeService.getProperties(nodeRef); for (PropertyDefinition propDef : propDefs.values()) { - generatePropertyField(propDef, form, propValues.get(propDef.getName()), - this.namespaceService); + generatePropertyField(propDef, form, propValues.get(propDef.getName()), this.namespaceService); } } @@ -203,8 +199,7 @@ public class NodeFormProcessor extends ContentModelFormProcessor assocDefs = typeDef.getAssociations(); @@ -229,8 +224,7 @@ public class NodeFormProcessor extends ContentModelFormProcessor"prop_cm_name". The pattern can also + // be + // * used to extract the "cm" and the "name" parts. + // */ + // protected Pattern propertyNamePattern = Pattern.compile(PROP_DATA_PREFIX + // + "(.*){1}?_(.*){1}?"); + // + // /** + // * A regular expression which can be used to match tranisent property + // names. + // * These names will look like "prop_name". The pattern can + // also + // * be used to extract the "name" part. + // */ + // protected Pattern transientPropertyPattern = + // Pattern.compile(PROP_DATA_PREFIX + "(.*){1}?"); + // + // /** + // * A regular expression which can be used to match association names. + // These + // * names will look like "assoc_cm_references_added". The + // * pattern can also be used to extract the "cm", the "name" and the suffix + // * parts. + // */ + // protected Pattern associationNamePattern = + // Pattern.compile(ASSOC_DATA_PREFIX + "(.*){1}?_(.*){1}?(_[a-zA-Z]+)"); + // + // private NamespaceService namespaceService; + // + // private FieldDefinitionFactory factory; + // + // /** + // * 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 + // */ + // public void generateSelectedField(String fieldName, FieldCreationData + // data) + // { + // FieldInfo fieldInfo = new FieldInfo(fieldName, data); + // if (fieldInfo.isValid()) fieldInfo.addToForm(form); + // + // // try the field as a property + // if (fieldInfo.tryProperty) + // { + // // lookup property def on node + // PropertyDefinition propDef = propDefs.get(fullQName); + // if (propDef != null) + // { + // // generate the property field + // generatePropertyField(propDef, propValues.get(fullQName), null); + // + // // no need to try and find an association + // tryAssociation = false; + // foundField = true; + // } + // } + // + // // try the field as an association + // if (fieldInfo.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 forced 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"); + // } + // } + // } + // + // /** + // * 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 + // */ + // public void generateAssociationField(AssociationDefinition assocDef, + // List assocValues, FieldGroup group) + // { + // AssociationFieldDefinition fieldDef = + // makeAssociationFieldDefinition(assocDef, group); + // + // // 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(fieldDef.getDataKeyName(), values); + // } + // } + // + // /** + // * 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") + // public void generatePropertyField(PropertyDefinition propDef, + // Serializable propValue, FieldGroup group) + // { + // PropertyFieldDefinition fieldDef = + // factory.makePropertyFieldDefinition(propDef, group); + // form.addFieldDefinition(fieldDef); + // + // // add the property value to the form + // if (propValue != null) + // { + // if (propValue instanceof List) + // { + // // TODO Currently this adds repeating field data as a comma + // // separated list, this needs to be replaced with a separate + // // field for each value once we have full UI support in place. + // propValue = StringUtils.collectionToCommaDelimitedString((List) + // propValue); + // } + // form.addData(fieldDef.getDataKeyName(), propValue); + // } + // } + // + // private class FieldInfo + // { + // private final QName name; + // + // private final FieldDefinition fieldDefinition; + // + // private FieldType fieldType; + // + // private FieldInfo(String fieldName, FieldCreationData data) + // { + // this.name = makeNameAndFieldType(fieldName); + // this.fieldDefinition = createDefinition(data); + // } + // + // /** + // * @return + // */ + // public boolean isValid() + // { + // return fieldDefinition != null; + // } + // + // private QName makeNameAndFieldType(String fieldName) + // { + // String[] parts = fieldName.split(":"); + // if (parts.length < 2 || parts.length > 3) + // { + // this.fieldType = FieldType.INVALID; + // return QName.createQName(null, fieldName); + // } + // int indexer = 0; + // if (parts.length == 3) + // { + // indexer = 1; + // this.fieldType = FieldType.getType(parts[0]); + // } + // else + // this.fieldType = FieldType.UNKNOWN; + // String prefix = parts[0 + indexer]; + // String localName = parts[1 + indexer]; + // return QName.createQName(prefix, localName, namespaceService); + // } + // + // /** + // * @param data + // */ + // private FieldDefinition createDefinition(FieldCreationData data) + // { + // FieldDefinition fieldDef = null; + // switch (fieldType) + // { + // case INVALID:// So fieldDef will stay null. + // break; + // case PROPERTY: + // fieldDef = generatePropertyDefinition(data); + // break; + // case ASSOCIATION: + // fieldDef = generateAssociationDefinition(data); + // break; + // case UNKNOWN: + // fieldDef = generatePropertyDefinition(data); + // if (fieldDef != null) + // fieldType = FieldType.PROPERTY; + // else + // { + // fieldDef = generateAssociationDefinition(data); + // if (fieldDef != null) fieldType = FieldType.ASSOCIATION; + // } + // } + // if (fieldDef == null) + // { + // this.fieldType = FieldType.INVALID; + // } + // return fieldDef; + // } + // + // /** + // * @param data + // * @return + // */ + // private AssociationFieldDefinition + // generateAssociationDefinition(FieldCreationData data) + // { + // AssociationDefinition assocDef = data.getAssocDefs().get(name); + // if (assocDef != null) + // return factory.makeAssociationFieldDefinition(assocDef, data.getGroup()); + // else + // return null; + // } + // + // /** + // * @param data + // */ + // private PropertyFieldDefinition + // generatePropertyDefinition(FieldCreationData data) + // { + // PropertyDefinition propDef = data.getPropDefs().get(name); + // if (propDef != null) // + // return factory.makePropertyFieldDefinition(propDef, data.getGroup()); + // else + // return null; + // } + // + // public void addToForm(Form form, FieldCreationData data) + // { + // if (isValid()) + // { + // form.addFieldDefinition(fieldDefinition); + // Object value = null; + // if (fieldType == FieldType.PROPERTY) + // { + // value = buildPropertyData(data, (PropertyFieldDefinition) + // fieldDefinition); + // } + // else if (fieldType == FieldType.ASSOCIATION) + // { + // value = buildAssociationData(data, (AssociationFieldDefinition) + // fieldDefinition); + // } + // if (value != null) + // { + // form.addData(fieldDefinition.getDataKeyName(), value); + // } + // } + // else + // { + // throw new IllegalStateException("Cannot add invalid field:" + + // name.getLocalName() + " to a form!"); + // } + // } + // } + // + // private enum FieldType + // { + // ASSOCIATION, INVALID, PROPERTY, UNKNOWN; + // + // public static FieldType getType(String type) + // { + // if (PROP.equals(type)) + // { + // return PROPERTY; + // } + // else if (ASSOC.equals(type)) return ASSOCIATION; + // return UNKNOWN; + // } + // } + // + // protected abstract Object buildPropertyData(FieldCreationData data, + // PropertyFieldDefinition fieldDef); + // + // protected abstract Object buildAssociationData(FieldCreationData data, + // AssociationFieldDefinition fieldDef); +} diff --git a/source/java/org/alfresco/repo/forms/processor/task/FieldCreationData.java b/source/java/org/alfresco/repo/forms/processor/task/FieldCreationData.java new file mode 100644 index 0000000000..ad3faaa937 --- /dev/null +++ b/source/java/org/alfresco/repo/forms/processor/task/FieldCreationData.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2005-2009 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.forms.processor.task; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.forms.FieldGroup; +import org.alfresco.service.cmr.dictionary.AspectDefinition; +import org.alfresco.service.cmr.dictionary.AssociationDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.dictionary.TypeDefinition; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.workflow.WorkflowTask; +import org.alfresco.service.namespace.QName; + +/** + * @author Nick Smith + */ +public class FieldCreationData +{ + private final QName type; + + private final TypeDefinition typeDef; + + private final Map propValues; + + private final Map propDefs; + + private final Map assocDefs; + + private final FieldGroup group; + + private final List forcedFields; + + public FieldCreationData(NodeRef nodeRef, List forcedFields, FieldGroup group, NodeService nodeService, + DictionaryService dictionaryService) + { + this.forcedFields = forcedFields; + this.group = group; + this.type = nodeService.getType(nodeRef); + Set aspects = nodeService.getAspects(nodeRef); + this.typeDef = dictionaryService.getAnonymousType(type, aspects); + + // NOTE: the anonymous type returns all property and association + // defs for all aspects applied as well as the type + this.propDefs = typeDef.getProperties(); + this.assocDefs = typeDef.getAssociations(); + this.propValues = nodeService.getProperties(nodeRef); + } + + public FieldCreationData(TypeDefinition typeDef, List forcedFields, FieldGroup group) + { + this.propValues = null; + + this.forcedFields = forcedFields; + this.group = group; + this.typeDef = typeDef; + this.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 + this.propDefs = new HashMap(16); + this.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()); + } + } + + public FieldCreationData(WorkflowTask task, List forcedFields, FieldGroup group) + { + this.forcedFields = forcedFields; + this.group = group; + this.typeDef = task.definition.metadata; + this.type = typeDef.getName(); + + this.propDefs = populateProperties(typeDef); + this.assocDefs = populateAssociations(typeDef); + this.propValues = task.properties; + } + + private Map populateAssociations(TypeDefinition typeDef2) + { + HashMap allProps = new HashMap(); + allProps.putAll(typeDef.getAssociations()); + List aspects = typeDef.getDefaultAspects(true); + for (AspectDefinition aspect : aspects) + { + allProps.putAll(aspect.getAssociations()); + } + return Collections.unmodifiableMap(allProps); + } + + private Map populateProperties(TypeDefinition typeDef) + { + HashMap allProps = new HashMap(); + allProps.putAll(typeDef.getProperties()); + List aspects = typeDef.getDefaultAspects(true); + for (AspectDefinition aspect : aspects) + { + allProps.putAll(aspect.getProperties()); + } + return Collections.unmodifiableMap(allProps); + } + + /** + * @return the propValues + */ + public Map getPropValues() + { + return this.propValues; + } + + /** + * @return the propDefs + */ + public Map getPropDefs() + { + return this.propDefs; + } + + /** + * @return the assocDefs + */ + public Map getAssocDefs() + { + return this.assocDefs; + } + + /** + * @return the group + */ + public FieldGroup getGroup() + { + return this.group; + } + + /** + * @return the forcedFields + */ + public List getForcedFields() + { + return this.forcedFields; + } +} diff --git a/source/java/org/alfresco/repo/forms/processor/task/FieldDefinitionFactory.java b/source/java/org/alfresco/repo/forms/processor/task/FieldDefinitionFactory.java new file mode 100644 index 0000000000..4aee8e24eb --- /dev/null +++ b/source/java/org/alfresco/repo/forms/processor/task/FieldDefinitionFactory.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2005-2009 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.forms.processor.task; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.alfresco.repo.forms.processor.node.FormFieldConstants.*; +import org.alfresco.repo.forms.AssociationFieldDefinition; +import org.alfresco.repo.forms.FieldDefinition; +import org.alfresco.repo.forms.FieldGroup; +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.PeriodDataTypeParameters; +import org.alfresco.service.cmr.dictionary.AssociationDefinition; +import org.alfresco.service.cmr.dictionary.ClassAttributeDefinition; +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.repository.Period; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + +/** + * @author Nick Smith + */ +public class FieldDefinitionFactory +{ + private final NamespaceService namespaceService; + + public FieldDefinitionFactory(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + public AssociationFieldDefinition makeAssociationFieldDefinition( + final AssociationDefinition assocDef, FieldGroup group) + { + // Callback used to construct the AssociationFieldDefinition. + FieldDefinitionCreator factory = new FieldDefinitionCreator() + { + public AssociationFieldDefinition create(String name) + { + String endpointType = assocDef.getTargetClass().getName().toPrefixString( + namespaceService); + return new AssociationFieldDefinition(name, endpointType, Direction.TARGET); + } + }; + AssociationFieldDefinition fieldDef = makeFieldDefinition(assocDef, group, + ASSOC_DATA_PREFIX, factory); + + fieldDef.setEndpointMandatory(assocDef.isTargetMandatory()); + fieldDef.setEndpointMany(assocDef.isTargetMany()); + return fieldDef; + } + + public PropertyFieldDefinition makePropertyFieldDefinition(final PropertyDefinition propDef, + FieldGroup group) + { + // Callback used to construct the PropertyFieldDefinition. + FieldDefinitionCreator factory = new FieldDefinitionCreator() + { + public PropertyFieldDefinition create(String name) + { + QName dataType = propDef.getDataType().getName(); + return new PropertyFieldDefinition(name, dataType.getLocalName()); + } + }; + PropertyFieldDefinition fieldDef = makeFieldDefinition(propDef, group, PROP_DATA_PREFIX, + factory); + + fieldDef.setDefaultValue(propDef.getDefaultValue()); + fieldDef.setMandatory(propDef.isMandatory()); + fieldDef.setRepeating(propDef.isMultiValued()); + + // any property from the system model (sys prefix) should be protected + // the model doesn't + // cu rrently enforce this so make sure they are not editable + if (NamespaceService.SYSTEM_MODEL_1_0_URI.equals(propDef.getName().getNamespaceURI())) + { + fieldDef.setProtectedField(true); + } + + // If the property data type is d:period we need to setup a data + // type parameters object to represent the options and rules + if (fieldDef.getDataType().equals(DataTypeDefinition.PERIOD)) + { + PeriodDataTypeParameters periodOptions = getPeriodOptions(); + fieldDef.setDataTypeParameters(periodOptions); + } + + // setup constraints for the property + List fieldConstraints = makeFieldConstraints(propDef); + fieldDef.setConstraints(fieldConstraints); + return fieldDef; + } + + /** + * Creates either a PropertyFieldDefinition or an + * AssociationFieldDefinition, as defined by the factory class being passed + * in. Sets several properties on this FieldDefinition, including name, + * label, description, dataKeyName and whether the field is protected. These + * values are derived from the attribDef parameter. + * + * @param attribDef Used to set the values of name, description, label, + * dataKeyName and isProtected properties on the returned object. + * @param group Used to set the group on the returned FieldDefinition. + * @param factory A factory object used to create the FieldDefinition to be + * returned. + * @return An object of type T which extends + * FieldDefinition. + */ + private T makeFieldDefinition(ClassAttributeDefinition attribDef, + FieldGroup group, String dataKeyPrefix, FieldDefinitionCreator factory) + { + String attribName = attribDef.getName().toPrefixString(namespaceService); + T fieldDef = factory.create(attribName); + fieldDef.setGroup(group); + String title = attribDef.getTitle(); + title = title == null ? attribName : title; + fieldDef.setLabel(title); + fieldDef.setDescription(attribDef.getDescription()); + fieldDef.setProtectedField(attribDef.isProtected()); + + // define the data key name and set + String dataKeyName = makeDataKeyForName(attribName, dataKeyPrefix); + fieldDef.setDataKeyName(dataKeyName); + return fieldDef; + } + + private static List makeFieldConstraints(PropertyDefinition propDef) + { + List fieldConstraints = null; + List constraints = propDef.getConstraints(); + if (constraints != null && constraints.size() > 0) + { + fieldConstraints = new ArrayList(constraints.size()); + for (ConstraintDefinition constraintDef : constraints) + { + Constraint constraint = constraintDef.getConstraint(); + String type = constraint.getType(); + Map params = constraint.getParameters(); + FieldConstraint fieldConstraint = new FieldConstraint(type, params); + fieldConstraints.add(fieldConstraint); + } + } + return fieldConstraints; + } + + private PeriodDataTypeParameters getPeriodOptions() + { + PeriodDataTypeParameters periodOptions = new PeriodDataTypeParameters(); + Set providers = Period.getProviderNames(); + for (String provider : providers) + { + periodOptions.addPeriodProvider(Period.getProvider(provider)); + } + return periodOptions; + } + + private static String makeDataKeyForName(String propName, String prefix) + { + String[] nameParts = QName.splitPrefixedQName(propName); + return prefix + nameParts[0] + DATA_KEY_SEPARATOR + nameParts[1]; + } + + private interface FieldDefinitionCreator + { + T create(String fieldDefinitionName); + } + +} diff --git a/source/java/org/alfresco/repo/forms/processor/task/FieldInfo.java b/source/java/org/alfresco/repo/forms/processor/task/FieldInfo.java new file mode 100644 index 0000000000..ebb3a5cfbe --- /dev/null +++ b/source/java/org/alfresco/repo/forms/processor/task/FieldInfo.java @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2005-2009 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.forms.processor.task; + +import static org.alfresco.repo.forms.processor.node.FormFieldConstants.*; + +import org.alfresco.repo.forms.FieldDefinition; +import org.alfresco.service.cmr.dictionary.AssociationDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + +/** + * @author Nick Smith + */ +public class FieldInfo +{ + private final QName fullName; + + private final FieldDefinition fieldDefinition; + + private final String fieldName; + + private final DictionaryService dictionaryService; + + private final FieldDefinitionFactory factory; + + private FieldType fieldType; + + public FieldInfo(String fieldName, FieldCreationData data, FieldDefinitionFactory factory, + DictionaryService dictionaryService, NamespaceService namespaceService) + { + this.factory = factory; + this.dictionaryService = dictionaryService; + this.fieldName = fieldName; + this.fullName = makeNameAndFieldType(fieldName, namespaceService); + this.fieldDefinition = createDefinition(data); + } + + private FieldDefinition createDefinition(final FieldCreationData data) + { + // Callback used to find the PropertyDefinition associated with this + // field (if any). + Getter propDefGetter = new Getter() + { + public PropertyDefinition get() + { + return data.getPropDefs().get(fullName); + } + }; + + // Callback used to find the PropertyDefinition associated with this + // field (if any). + Getter assocDefGetter = new Getter() + { + public AssociationDefinition get() + { + return data.getAssocDefs().get(fullName); + } + }; + + FieldDefinition fieldDef = createDefinition(data, propDefGetter, assocDefGetter); + if (fieldDef == null) + { + // If field is a forced field try to get it from dictionary + // service. + if (data.getForcedFields().contains(fieldName)) + { + propDefGetter = new Getter() + { + public PropertyDefinition get() + { + return dictionaryService.getProperty(fullName); + } + }; + + new Getter() + { + public AssociationDefinition get() + { + return dictionaryService.getAssociation(fullName); + } + }; + fieldDef = createDefinition(data); + } + } + // If no field definition found then set fieldType to Invalid. + if (fieldDef == null) + { + this.fieldType = FieldType.INVALID; + } + return fieldDef; + } + + /** + * @return + */ + public boolean isValid() + { + return fieldDefinition != null; + } + + private QName makeNameAndFieldType(String fieldName, NamespaceService namespaceService) + { + String[] parts = fieldName.split(":"); + if (parts.length < 2 || parts.length > 3) + { + this.fieldType = FieldType.INVALID; + return QName.createQName(null, fieldName); + } + int indexer = 0; + if (parts.length == 3) + { + indexer = 1; + this.fieldType = FieldType.getType(parts[0]); + } + else + this.fieldType = FieldType.UNKNOWN; + String prefix = parts[0 + indexer]; + String localName = parts[1 + indexer]; + return QName.createQName(prefix, localName, namespaceService); + } + + /** + * @param data + */ + private FieldDefinition createDefinition(FieldCreationData data, Getter propDefGetter, + Getter assocDefGetter) + { + FieldDefinition fieldDef = null; + switch (fieldType) + { + case INVALID:// So fieldDef will stay null. + break; + case PROPERTY: + fieldDef = generatePropertyDefinition(data, propDefGetter); + break; + case ASSOCIATION: + fieldDef = generateAssociationDefinition(data, assocDefGetter); + break; + case UNKNOWN: + fieldDef = generatePropertyDefinition(data, propDefGetter); + if (fieldDef != null) + fieldType = FieldType.PROPERTY; + else + { + fieldDef = generateAssociationDefinition(data, assocDefGetter); + if (fieldDef != null) fieldType = FieldType.ASSOCIATION; + } + } + return fieldDef; + } + + private FieldDefinition generateAssociationDefinition(FieldCreationData data, + Getter assocDefGetter) + { + AssociationDefinition assocDef = assocDefGetter.get(); + if (assocDef != null) + return factory.makeAssociationFieldDefinition(assocDef, data.getGroup()); + else + return null; + } + + private FieldDefinition generatePropertyDefinition(FieldCreationData data, Getter propDefGetter) + { + PropertyDefinition propDef = propDefGetter.get(); + if (propDef != null) // + return factory.makePropertyFieldDefinition(propDef, data.getGroup()); + else + return null; + } + + /** + * @return the fieldDefinition + */ + public FieldDefinition getFieldDefinition() + { + return this.fieldDefinition; + } + + /** + * @return the fullName + */ + public QName getFullName() + { + return this.fullName; + } + + /** + * @return the fieldName + */ + public String getFieldName() + { + return this.fieldName; + } + + private enum FieldType + { + ASSOCIATION, INVALID, PROPERTY, UNKNOWN; + + public static FieldType getType(String type) + { + if (PROP.equals(type)) + { + return PROPERTY; + } + else if (ASSOC.equals(type)) return ASSOCIATION; + return UNKNOWN; + } + } +} diff --git a/source/java/org/alfresco/repo/forms/processor/task/Getter.java b/source/java/org/alfresco/repo/forms/processor/task/Getter.java new file mode 100644 index 0000000000..5c6f565598 --- /dev/null +++ b/source/java/org/alfresco/repo/forms/processor/task/Getter.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005-2009 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.forms.processor.task; + +/** + * This interface may be used as a parameter in a method instead of passing in + * an object of type T. This can be useful if you wish to lazy-create a + * parameter, cache a parameter or otherwise control how the parameter is used. + * + * @author Nick Smith + */ +public interface Getter +{ + /** + * Returns an object of type T. + * + * @return + */ + T get(); +} diff --git a/source/java/org/alfresco/repo/forms/processor/task/TaskFormProcessor.java b/source/java/org/alfresco/repo/forms/processor/task/TaskFormProcessor.java new file mode 100644 index 0000000000..56c957eb5f --- /dev/null +++ b/source/java/org/alfresco/repo/forms/processor/task/TaskFormProcessor.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2005-2009 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.forms.processor.task; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.forms.FieldDefinition; +import org.alfresco.repo.forms.Form; +import org.alfresco.repo.forms.FormData; +import org.alfresco.repo.forms.Item; +import org.alfresco.repo.forms.FormData.FieldData; +import org.alfresco.repo.forms.processor.FilteredFormProcessor; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.TypeDefinition; +import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.cmr.workflow.WorkflowTask; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.ParameterCheck; + +/** + * @author Nick Smith + */ +public class TaskFormProcessor extends FilteredFormProcessor +{ + /** Logger */ + // private static final Log logger = + // LogFactory.getLog(TaskFormProcessor.class); + + private final WorkflowService workflowService; + + private final NamespaceService namespaceService; + + private final DictionaryService dictionaryService; + + private final FieldDefinitionFactory factory; + + public TaskFormProcessor(WorkflowService workflowService, NamespaceService namespaceService, + DictionaryService dictionaryService) + { + this.workflowService = workflowService; + this.namespaceService = namespaceService; + this.dictionaryService = dictionaryService; + this.factory = new FieldDefinitionFactory(namespaceService); + } + + /* + * @see + * org.alfresco.repo.forms.processor.FilteredFormProcessor#getTypedItem( + * org.alfresco.repo.forms.Item) + */ + @Override + protected WorkflowTask getTypedItem(Item item) + { + ParameterCheck.mandatory("item", item); + String id = item.getId(); + WorkflowTask task = workflowService.getTaskById(id); + return task; + } + + /* + * @see + * org.alfresco.repo.forms.processor.FilteredFormProcessor#internalGenerate + * (java.lang.Object, java.util.List, java.util.List, + * org.alfresco.repo.forms.Form, java.util.Map) + */ + @Override + protected void internalGenerate(WorkflowTask item, List fields, List forcedFields, Form form, + Map context) + { + TypeDefinition typeDef = item.definition.metadata; + String type = typeDef.getName().toPrefixString(namespaceService); + setFormItemType(form, type); + + // TODO Check this URL is OK. + setFormItemUrl(form, "/api/task/" + item.id); + + FieldCreationData data = new FieldCreationData(item, forcedFields, null); + List fieldsToAdd = generateFields(data, fields); + for (FieldInfo fieldToAdd : fieldsToAdd) + { + if (fieldToAdd.isValid()) + { + FieldDefinition fieldDef = fieldToAdd.getFieldDefinition(); + form.addFieldDefinition(fieldDef); + Object value = data.getPropValues().get(fieldToAdd.getFullName()); + if (value != null) + { + form.addData(fieldDef.getDataKeyName(), value); + } + } + } + } + + private List generateFields(FieldCreationData data, List fields) + { + ArrayList fieldData = new ArrayList(fields.size()); + for (String fieldName : fields) + { + fieldData.add(makeFieldInfo(data, fieldName)); + } + return fieldData; + } + + private FieldInfo makeFieldInfo(FieldCreationData data, String fieldName) + { + return new FieldInfo(fieldName, data, factory, dictionaryService, namespaceService); + } + + /* + * @see + * org.alfresco.repo.forms.processor.FilteredFormProcessor#internalPersist + * (java.lang.Object, org.alfresco.repo.forms.FormData) + */ + @Override + protected WorkflowTask internalPersist(WorkflowTask item, FormData data) + { + //TODO Implement this method properly. + Map props = new HashMap(); + for (FieldData fieldData : data) + { + fieldData.getName(); + } + workflowService.updateTask(item.id, props, null, null); + return null; + } + +} diff --git a/source/java/org/alfresco/repo/forms/processor/task/TaskFormProcessorTest.java b/source/java/org/alfresco/repo/forms/processor/task/TaskFormProcessorTest.java new file mode 100644 index 0000000000..15986e1e1f --- /dev/null +++ b/source/java/org/alfresco/repo/forms/processor/task/TaskFormProcessorTest.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2005-2009 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.forms.processor.task; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; + +import java.io.Serializable; +import java.util.HashMap; + +import junit.framework.TestCase; + +import org.alfresco.repo.forms.Item; +import org.alfresco.repo.workflow.WorkflowModel; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.workflow.WorkflowException; +import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.cmr.workflow.WorkflowTask; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.NamespaceServiceMemoryImpl; +import org.alfresco.service.namespace.QName; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +/** + * @author Nick Smith + */ +public class TaskFormProcessorTest extends TestCase +{ + /** + * + */ + private static final String TASK_ID = "Real Id"; + + private WorkflowService workflowService; + + TaskFormProcessor processor; + + private WorkflowTask task; + + public void testGetTypedItem() throws Exception + { + try + { + processor.getTypedItem(null); + fail("Should have thrown an Exception here!"); + } + catch (IllegalArgumentException e) + { + // Do nothing! + } + try + { + processor.getTypedItem(new Item("task", "bad id")); + fail("Should have thrown an Exception here!"); + } + catch (WorkflowException e) + { + // Do nothing! + } + + Item item = new Item("task", TASK_ID); + WorkflowTask task = processor.getTypedItem(item); + assertNotNull(task); + assertEquals(TASK_ID, task.id); + } + + // public void testGenerateSimple() + // { + // Item item = new Item("task", TASK_ID); + // Form form = new Form(item); + // List fields = Arrays.asList("description"); + // processor.internalGenerate(task, fields, null, form, null); + // } + + // public void testPersist() throws Exception + // { + // FormData data = new FormData(); + // processor.internalPersist(task, data); + // } + + /* + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception + { + super.setUp(); + task = makeTask(); + workflowService = makeWorkflowService(); + DictionaryService dictionaryService = makeDictionaryService(); + NamespaceService namespaceService = makeNamespaceService(); + processor = new TaskFormProcessor(workflowService, namespaceService, dictionaryService); + } + + /** + * + */ + private WorkflowTask makeTask() + { + WorkflowTask task = new WorkflowTask(); + task.id = TASK_ID; + task.description = "Description"; + HashMap properties = new HashMap(); + QName descName = WorkflowModel.PROP_DESCRIPTION; + properties.put(descName, "Description"); + return task; + + } + + private NamespaceService makeNamespaceService() + { + return new NamespaceServiceMemoryImpl(); + } + + private DictionaryService makeDictionaryService() + { + return mock(DictionaryService.class); + } + + private WorkflowService makeWorkflowService() + { + WorkflowService service = mock(WorkflowService.class); + when(service.getTaskById(anyString())).thenAnswer(new Answer() + { + + public WorkflowTask answer(InvocationOnMock invocation) throws Throwable + { + String id = (String) invocation.getArguments()[0]; + if (TASK_ID.equals(id)) + return task; + else + throw new WorkflowException("Task Id not found!"); + } + }); + return service; + } +} diff --git a/source/java/org/alfresco/service/cmr/dictionary/AssociationDefinition.java b/source/java/org/alfresco/service/cmr/dictionary/AssociationDefinition.java index 669d2c9d8a..8fe3a67f29 100644 --- a/source/java/org/alfresco/service/cmr/dictionary/AssociationDefinition.java +++ b/source/java/org/alfresco/service/cmr/dictionary/AssociationDefinition.java @@ -33,7 +33,7 @@ import org.alfresco.service.namespace.QName; * @author David Caruana * */ -public interface AssociationDefinition +public interface AssociationDefinition extends ClassAttributeDefinition { /** diff --git a/source/java/org/alfresco/service/cmr/dictionary/ClassAttributeDefinition.java b/source/java/org/alfresco/service/cmr/dictionary/ClassAttributeDefinition.java new file mode 100644 index 0000000000..c22fed1d6e --- /dev/null +++ b/source/java/org/alfresco/service/cmr/dictionary/ClassAttributeDefinition.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2005-2009 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.service.cmr.dictionary; + +import org.alfresco.service.namespace.QName; + +/** + * + * @author Nick Smith + */ +public interface ClassAttributeDefinition +{ + /** + * @return defining model + */ + public ModelDefinition getModel(); + + /** + * @return the qualified name + */ + public QName getName(); + + /** + * @return the human-readable title + */ + public String getTitle(); + + /** + * @return the human-readable description + */ + public String getDescription(); + + /** + * Is this association or property maintained by the Repository? + * + * @return true => system maintained, false => client may maintain + */ + public boolean isProtected(); + +} diff --git a/source/java/org/alfresco/service/cmr/dictionary/PropertyDefinition.java b/source/java/org/alfresco/service/cmr/dictionary/PropertyDefinition.java index 4a8d9d201a..4ecab02fec 100644 --- a/source/java/org/alfresco/service/cmr/dictionary/PropertyDefinition.java +++ b/source/java/org/alfresco/service/cmr/dictionary/PropertyDefinition.java @@ -22,6 +22,7 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ + package org.alfresco.service.cmr.dictionary; import java.util.List; @@ -34,33 +35,33 @@ import org.alfresco.service.namespace.QName; * * @author David Caruana */ -public interface PropertyDefinition +public interface PropertyDefinition extends ClassAttributeDefinition { /** - * @return defining model + * @return defining model */ public ModelDefinition getModel(); - + /** * @return the qualified name of the property */ public QName getName(); /** - * @return the human-readable class title + * @return the human-readable class title */ public String getTitle(); - + /** - * @return the human-readable class description + * @return the human-readable class description */ public String getDescription(); - + /** - * @return the default value + * @return the default value */ public String getDefaultValue(); - + /** * @return the qualified name of the property type */ @@ -68,56 +69,59 @@ public interface PropertyDefinition /** * @return Returns the owning class's defintion - */ + */ public ClassDefinition getContainerClass(); - + public boolean isOverride(); - + /** - * @return true => multi-valued, false => single-valued + * @return true => multi-valued, false => single-valued */ public boolean isMultiValued(); /** - * @return true => mandatory, false => optional + * @return true => mandatory, false => optional */ public boolean isMandatory(); - + /** * @return Returns true if the system enforces the presence of - * {@link #isMandatory() mandatory} properties, or false if the system - * just marks objects that don't have all mandatory properties present. + * {@link #isMandatory() mandatory} properties, or false if the + * system just marks objects that don't have all mandatory + * properties present. */ public boolean isMandatoryEnforced(); - + /** - * @return true => system maintained, false => client may maintain + * @return true => system maintained, false => client may maintain */ public boolean isProtected(); /** - * @return true => indexed, false => not indexed + * @return true => indexed, false => not indexed */ public boolean isIndexed(); - + /** - * @return true => stored in index + * @return true => stored in index */ public boolean isStoredInIndex(); /** - * @return IndexTokenisationMode.TREU => tokenised when it is indexed (the stored value will not be tokenised) + * @return IndexTokenisationMode.TREU => tokenised when it is indexed (the + * stored value will not be tokenised) */ public IndexTokenisationMode getIndexTokenisationMode(); - + /** * All non atomic properties will be indexed at the same time. - * - * @return true => The attribute must be indexed in the commit of the transaction. - * false => the indexing will be done in the background and may be out of date. + * + * @return true => The attribute must be indexed in the commit of the + * transaction. false => the indexing will be done in the background + * and may be out of date. */ public boolean isIndexedAtomically(); - + /** * Get all constraints that apply to the property value *