diff --git a/config/alfresco/form-services-context.xml b/config/alfresco/form-services-context.xml
index ec7677b313..df65cb8130 100644
--- a/config/alfresco/form-services-context.xml
+++ b/config/alfresco/form-services-context.xml
@@ -69,7 +69,10 @@
+ parent="baseFormProcessor" >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/java/org/alfresco/repo/forms/Field.java b/source/java/org/alfresco/repo/forms/Field.java
new file mode 100644
index 0000000000..8fba2dc124
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/Field.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.forms;
+
+/**
+ * Interface definition of a field
+ *
+ * @author Nick Smith
+ */
+public interface Field
+{
+ /**
+ * @return the field definition
+ */
+ FieldDefinition getFieldDefinition();
+
+ /**
+ * @return the fieldName
+ */
+ String getFieldName();
+
+ /**
+ * @return the value for this field or null.
+ */
+ Object getValue();
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/forms/Form.java b/source/java/org/alfresco/repo/forms/Form.java
index 3636975fb0..f8d3e51b96 100644
--- a/source/java/org/alfresco/repo/forms/Form.java
+++ b/source/java/org/alfresco/repo/forms/Form.java
@@ -185,6 +185,41 @@ public class Form
this.data.addFieldData(fieldName, fieldData);
}
+ /**
+ * Adds a {@link Field} to the form by adding the {@link FieldDefinition}
+ * and the value if any.
+ *
+ * @param field
+ */
+ public void addField(Field field)
+ {
+ if (field == null)
+ {
+ return;
+ }
+
+ FieldDefinition fieldDefinition = field.getFieldDefinition();
+ addFieldDefinition(fieldDefinition);
+ Object value = field.getValue();
+
+ if (value != null)
+ {
+ addData(fieldDefinition.getDataKeyName(), value);
+ }
+ }
+
+ /**
+ * Adds a {@link Collection} of {@link Field Fields} to the form by adding the {@link FieldDefinition FieldDefinitions}
+ * and the values if any.
+ */
+ public void addFields(Collection fields)
+ {
+ for (Field field : fields)
+ {
+ addField(field);
+ }
+ }
+
/*
* @see java.lang.Object#toString()
*/
diff --git a/source/java/org/alfresco/repo/forms/FormServiceImplTest.java b/source/java/org/alfresco/repo/forms/FormServiceImplTest.java
index 9a11ea101e..8c38471fa0 100644
--- a/source/java/org/alfresco/repo/forms/FormServiceImplTest.java
+++ b/source/java/org/alfresco/repo/forms/FormServiceImplTest.java
@@ -30,10 +30,10 @@ import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.forms.AssociationFieldDefinition.Direction;
+import org.alfresco.repo.forms.FormData.FieldData;
import org.alfresco.repo.forms.PropertyFieldDefinition.FieldConstraint;
import org.alfresco.repo.forms.processor.node.TypeFormProcessor;
import org.alfresco.repo.jscript.ClasspathScriptLocation;
-import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentReader;
@@ -130,9 +130,6 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
this.contentService = (ContentService)this.applicationContext.getBean("ContentService");
this.workflowService = (WorkflowService)this.applicationContext.getBean("WorkflowService");
- AuthenticationComponent authenticationComponent = (AuthenticationComponent) this.applicationContext
- .getBean("authenticationComponent");
-
// Do the tests as userOne
createUser(USER_ONE);
authenticationComponent.setCurrentUser(USER_ONE);
@@ -1091,6 +1088,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
QName underscoreProperty = QName.createQName(fdkUri, "with_underscore");
QName dashProperty = QName.createQName(fdkUri, "with-dash");
QName duplicateProperty = QName.createQName(fdkUri, "duplicate");
+ QName periodProperty = QName.createQName(fdkUri, "period");
String guid = GUID.generate();
String name = "everything" + guid + ".txt";
@@ -1098,6 +1096,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
String underscoreValue = "Property with an underscore in the name.";
String dashValue = "Property with a dash in the name.";
String duplicateValue = "Property with the same name as an association.";
+ String periodValue = "day|1";
Map docProps = new HashMap(4);
docProps.put(ContentModel.PROP_NAME, name);
@@ -1105,6 +1104,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
docProps.put(underscoreProperty, underscoreValue);
docProps.put(dashProperty, dashValue);
docProps.put(duplicateProperty, duplicateValue);
+ docProps.put(periodProperty, periodValue);
NodeRef everythingNode = this.nodeService.createNode(this.folder, ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name), everythingType,
docProps).getChildRef();
@@ -1117,6 +1117,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
fields.add("fdk:with-dash");
fields.add("prop:fdk:duplicate");
fields.add("assoc:fdk:duplicate");
+ fields.add("fdk:period");
Form form = this.formService.getForm(new Item(NODE_FORM_ITEM_KIND, everythingNode.toString()), fields);
@@ -1136,6 +1137,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
PropertyFieldDefinition textField = null;
PropertyFieldDefinition underscoreField = null;
PropertyFieldDefinition dashField = null;
+ PropertyFieldDefinition periodField = null;
PropertyFieldDefinition duplicatePropField = null;
AssociationFieldDefinition duplicateAssocField = null;
@@ -1168,12 +1170,17 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
duplicateAssocField = (AssociationFieldDefinition)field;
}
}
+ else if (field.getName().equals("fdk:period"))
+ {
+ periodField = (PropertyFieldDefinition)field;
+ }
}
assertNotNull("Expected to find nameField", nameField);
assertNotNull("Expected to find textField", textField);
assertNotNull("Expected to find underscoreField", underscoreField);
assertNotNull("Expected to find dashField", dashField);
+ assertNotNull("Expected to find periodField", periodField);
assertNotNull("Expected to find duplicatePropField", duplicatePropField);
assertNotNull("Expected to find duplicateAssocField", duplicateAssocField);
@@ -1183,11 +1190,18 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
assertEquals(textValue, values.getFieldData(textField.getDataKeyName()).getValue());
assertEquals(underscoreValue, values.getFieldData(underscoreField.getDataKeyName()).getValue());
assertEquals(dashValue, values.getFieldData(dashField.getDataKeyName()).getValue());
+ assertEquals(periodValue, values.getFieldData(periodField.getDataKeyName()).getValue().toString());
assertEquals(duplicateValue, values.getFieldData(duplicatePropField.getDataKeyName()).getValue());
- List assocs = (List)values.getFieldData(duplicateAssocField.getDataKeyName()).getValue();
+ FieldData fieldData = values.getFieldData(duplicateAssocField.getDataKeyName());
+ assertNotNull(fieldData);
+ List assocs = (List)fieldData.getValue();
assertNotNull(assocs);
assertEquals(0, assocs.size());
+ // check the period property data type parameters were returned
+ DataTypeParameters dtp = periodField.getDataTypeParameters();
+ assertNotNull("Expected to find data type parameters for the fdk:period field", dtp);
+
// update the properties via FormService
FormData data = new FormData();
diff --git a/source/java/org/alfresco/repo/forms/processor/AbstractFieldProcessor.java b/source/java/org/alfresco/repo/forms/processor/AbstractFieldProcessor.java
new file mode 100644
index 0000000000..34c57a9a40
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/AbstractFieldProcessor.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.forms.processor;
+
+import org.alfresco.repo.forms.Field;
+import org.alfresco.repo.forms.FormException;
+import org.apache.commons.logging.Log;
+
+import com.sun.star.lang.IllegalArgumentException;
+
+public abstract class AbstractFieldProcessor implements FieldProcessor
+{
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.field.processor.FieldProcessor#generateField(java.lang.String, java.lang.Object)
+ */
+ public Field generateField(String fieldName, FormCreationData data)
+ {
+ Data typedData = checkDataType(data.getItemData());
+ Field field = generateTypedField(fieldName, data, typedData);
+ logIfFieldNotFound(field, fieldName);
+ return field;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Data checkDataType(Object itemData)
+ {
+ Class expectedType = getExpectedDataType();
+ if (expectedType.isAssignableFrom(itemData.getClass()))
+ {
+ return (Data)itemData;
+ }
+ else
+ {
+ String msg = "Data object: "+itemData+" is not of expected type: "+expectedType;
+ throw new FormException(msg, new IllegalArgumentException());
+ }
+ }
+
+ protected void logIfFieldNotFound(Field fieldInfo, String fieldName)
+ {
+ if (fieldInfo == null)
+ {
+ Log logger = getLogger();
+ if (logger!=null && logger.isDebugEnabled())
+ {
+ logger.debug("Ignoring unrecognised field \"" + fieldName + "\"");
+ }
+ }
+ }
+
+ /**
+ * Registers this {@link FieldProcessor} with the supplied registry.
+ *
+ * @param registry The registry to which this {@link FieldProcessor} is added.
+ */
+ public void setFieldProcessorRegistry(FieldProcessorRegistry registry)
+ {
+ registry.register(getRegistryKey(), this);
+ }
+
+ /**
+ * @return a {@link Log} used to log events that occur while processing fields.
+ */
+ protected abstract Log getLogger();
+
+ /**
+ * @return a {@link String} key used to identify this {@link FieldProcessor} in a {@link FieldProcessorRegistry}.
+ */
+ protected abstract String getRegistryKey();
+
+ /**
+ * @return the expected {@link Class} of the data parameter for the method generateField.
+ */
+ protected abstract Class getExpectedDataType();
+
+ /**
+ * The method which actually creates the {@link Field}.
+ * @param fieldName the name of the {@link Field} to be genereated.
+ * @param formData TODO
+ * @param typedData the data used to create the field.
+ * @return a {@link Field} or null.
+ */
+ protected abstract Field generateTypedField(String fieldName, FormCreationData formData, Data typedData);
+}
diff --git a/source/java/org/alfresco/repo/forms/processor/FieldProcessor.java b/source/java/org/alfresco/repo/forms/processor/FieldProcessor.java
new file mode 100644
index 0000000000..e24af2448f
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/FieldProcessor.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.forms.processor;
+
+import org.alfresco.repo.forms.Field;
+
+public interface FieldProcessor
+{
+ Field generateField(String fieldName, FormCreationData data);
+}
diff --git a/source/java/org/alfresco/repo/forms/processor/FieldProcessorRegistry.java b/source/java/org/alfresco/repo/forms/processor/FieldProcessorRegistry.java
new file mode 100644
index 0000000000..c5116c073b
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/FieldProcessorRegistry.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.forms.processor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.alfresco.repo.forms.Field;
+
+public class FieldProcessorRegistry
+{
+ private final Map processors = new HashMap();
+
+ /**
+ * The {@link FieldProcessor} to be used if no specific processor can be found.
+ */
+ private FieldProcessor defaultProcessor;
+
+ /**
+ * Registers a {@link FieldProcessor} with this registry using the specified key.
+ * @param key
+ * @param processor
+ */
+ public void register(String key, FieldProcessor processor)
+ {
+ processors.put(key, processor);
+ }
+
+ /**
+ * Returns the {@link FieldProcessor} that was registered witht he specified key.
+ * @param key
+ * @return
+ */
+ public FieldProcessor get(String key)
+ {
+ return processors.get(key);
+ }
+
+
+ /**
+ * Attempts to build a {@link Field}. The method first tries to derive a key from the fieldname, then uses this key to look up a {@link FieldProcessor}.
+ * This {@link FieldProcessor} is then used to generate a {@link Field}.
+ * @param fieldName the name of the field to be created.
+ * @param data A data object used by the {@link FieldProcessor} to build the {@link Field}.
+ * @return a {@link Field} or null.
+ */
+ public Field buildField(String fieldName, FormCreationData data)
+ {
+ FieldProcessor fieldProcessor = getFieldProcessor(fieldName);
+ if (fieldProcessor == null)
+ {
+ return null;
+ }
+ return fieldProcessor.generateField(fieldName, data);
+ }
+
+ protected FieldProcessor getFieldProcessor(String fieldName)
+ {
+ FieldProcessor fieldProcessor = get(getKey(fieldName));
+ if (fieldProcessor == null && useDefaultProcessor(fieldName))
+ {
+ fieldProcessor = defaultProcessor;
+ }
+ return fieldProcessor;
+ }
+
+ /**
+ * Determines if the defaultProcessor should be used.
+ * @param fieldName
+ * @return true if the defaultProcessor should be used, otherwise false.
+ */
+ protected boolean useDefaultProcessor(String fieldName)
+ {
+ return true;
+ }
+
+ /**
+ * Derives the key used to look up the {@link FieldProcessor} from the fieldName.
+ * @param fieldName
+ * @return the key used to look up the {@link FieldProcessor}.
+ */
+ protected String getKey(String fieldName)
+ {
+ return fieldName;
+ }
+
+ /**
+ * @param defaultProcessor the defaultProcessor to set
+ */
+ public void setDefaultProcessor(FieldProcessor defaultProcessor)
+ {
+ this.defaultProcessor = defaultProcessor;
+ }
+}
diff --git a/source/java/org/alfresco/repo/forms/processor/FilteredFormProcessor.java b/source/java/org/alfresco/repo/forms/processor/FilteredFormProcessor.java
index b8dec235fc..6a05f29ebb 100644
--- a/source/java/org/alfresco/repo/forms/processor/FilteredFormProcessor.java
+++ b/source/java/org/alfresco/repo/forms/processor/FilteredFormProcessor.java
@@ -19,9 +19,12 @@
package org.alfresco.repo.forms.processor;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
+import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.Form;
import org.alfresco.repo.forms.FormData;
import org.alfresco.repo.forms.Item;
@@ -40,6 +43,8 @@ public abstract class FilteredFormProcessor extends Abstr
protected FilterRegistry filterRegistry;
+ protected FieldProcessorRegistry fieldProcessorRegistry;
+
/**
* Sets the filter registry
*
@@ -129,6 +134,79 @@ public abstract class FilteredFormProcessor extends Abstr
return persistedObject;
}
+ /**
+ * Generates the form.
+ *
+ * @param item The object to generate a form for
+ * @param fields Restricted list of fields to include
+ * @param forcedFields List of fields to forcibly include
+ * @param form The form object being generated
+ * @param context Map representing optional context that can be used during
+ * retrieval of the form
+ */
+ protected void internalGenerate(ItemType item, List fields, List forcedFields, Form form, Map context)
+ {
+ Log log = getLogger();
+ if (log.isDebugEnabled()) log.debug("Generating form for: " + item);
+
+ // generate the form type and URI for the item.
+ Item formItem = form.getItem();
+ formItem.setType(getItemType(item));
+ formItem.setUrl(getItemURI(item));
+
+ Object itemData = makeItemData(item);
+ FormCreationData data = new FormCreationData(itemData, forcedFields, context);
+ List fieldsToAdd;
+ if (fields != null && fields.size() > 0)
+ {
+ fieldsToAdd = generateSelectedFields(fields, data);
+ }
+ else
+ {
+ fieldsToAdd = generateDefaultFields(data);
+ }
+ form.addFields(fieldsToAdd);
+ if (log.isDebugEnabled()) //
+ log.debug("Generated form: " + form);
+ }
+
+ /**
+ * Generates a list of default fields to add if no field names are specified.
+ * @param data Used for field creation.
+ * @return a {@link List} of {@link Field Fields} which may be empty.
+ */
+ protected List generateDefaultFields(FormCreationData data)
+ {
+ return Collections.emptyList();
+ }
+
+ protected List generateSelectedFields(List fields, FormCreationData data)
+ {
+ List fieldData = new ArrayList(fields.size());
+ for (String fieldName : fields)
+ {
+ Field field = fieldProcessorRegistry.buildField(fieldName, data);
+ if (field == null)
+ {
+ if (getLogger().isWarnEnabled()) {
+ String msg = "Ignoring unrecognised field \"" + fieldName + "\"";
+ getLogger().warn(msg);
+ }
+ }
+ else
+ {
+ fieldData.add(field);
+ }
+ }
+ return fieldData;
+ }
+
+ /**
+ * Creates a data object used by the {@link FormProcessor} and {@link FieldProcessor FieldProcessors} to create {@link Field Fields}
+ * @return
+ */
+ protected abstract Object makeItemData(ItemType item);
+
/**
* Returns a typed Object representing the given item.
*
@@ -142,18 +220,37 @@ public abstract class FilteredFormProcessor extends Abstr
protected abstract ItemType getTypedItem(Item item);
/**
- * Generates the form.
+ * Retrieves a logger instance to log to.
*
- * @param item The object to generate a form for
- * @param fields Restricted list of fields to include
- * @param forcedFields List of fields to forcibly include
- * @param form The form object being generated
- * @param context Map representing optional context that can be used during
- * retrieval of the form
+ * @return Log instance to log to.
*/
- protected abstract void internalGenerate(ItemType item, List fields, List forcedFields, Form form,
- Map context);
+ protected abstract Log getLogger();
+ /**
+ * Returns a {@link String} describing the type fo the specified item.
+ * @param item
+ * @return
+ */
+ protected abstract String getItemType(ItemType item);
+
+ /**
+ * Returns the URI location of the specified item.
+ * @param item
+ * @return
+ */
+ protected abstract String getItemURI(ItemType item);
+
+ /**
+ * Sets the field processor registry.
+ *
+ * @param fieldProcessorRegistry
+ * The {@link FieldProcessorRegistry} to use.
+ */
+ public void setFieldProcessorRegistry(FieldProcessorRegistry fieldProcessorRegistry)
+ {
+ this.fieldProcessorRegistry = fieldProcessorRegistry;
+ }
+
/**
* Persists the form data.
*
diff --git a/source/java/org/alfresco/repo/forms/processor/FormCreationData.java b/source/java/org/alfresco/repo/forms/processor/FormCreationData.java
new file mode 100644
index 0000000000..79f884c11e
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/FormCreationData.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Simple DTO containing various objects needed to generate Forms.
+ * @author Nick Smith
+ */
+public class FormCreationData
+{
+ private final Object itemData;
+ private final List forcedFields;
+ private final Map context;
+
+ public FormCreationData(Object itemData,
+ List forcedFields,
+ Map context)
+ {
+ this.itemData = itemData;
+ this.forcedFields = forcedFields;
+ this.context = context;
+ }
+
+
+ /**
+ * @return the itemData
+ */
+ public Object getItemData()
+ {
+ return itemData;
+ }
+
+ /**
+ * @return If the fieldName given is a forced field then
+ * returns true, otherwise returns false.
+ */
+ public boolean isForcedField(String fieldName)
+ {
+ if (forcedFields == null)
+ return false;
+ return forcedFields.contains(fieldName);
+ }
+
+ /**
+ * @return the context
+ */
+ public Map getContext()
+ {
+ return context;
+ }
+}
diff --git a/source/java/org/alfresco/repo/forms/processor/node/AssociationFieldProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/AssociationFieldProcessor.java
new file mode 100644
index 0000000000..4daa908111
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/AssociationFieldProcessor.java
@@ -0,0 +1,125 @@
+package org.alfresco.repo.forms.processor.node;
+
+import static org.alfresco.repo.forms.processor.node.FormFieldConstants.ASSOC_DATA_PREFIX;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.alfresco.repo.forms.AssociationFieldDefinition;
+import org.alfresco.repo.forms.Field;
+import org.alfresco.repo.forms.FieldGroup;
+import org.alfresco.repo.forms.AssociationFieldDefinition.Direction;
+import org.alfresco.service.cmr.dictionary.AssociationDefinition;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class AssociationFieldProcessor extends QNameFieldProcessor
+{
+ private static final Log logger = LogFactory.getLog(AssociationFieldProcessor.class);
+
+ public AssociationFieldProcessor()
+ {
+ // Constructor for Spring.
+ }
+
+ public AssociationFieldProcessor(NamespaceService namespaceService, DictionaryService dictionaryService)
+ {
+ super(namespaceService, dictionaryService);
+ }
+
+ @Override
+ protected Log getLogger()
+ {
+ return logger;
+ }
+
+ @Override
+ protected FieldGroup getGroup(AssociationDefinition assocDef)
+ {
+ // TODO Need to Implement this once Composite Content is implementd.
+ return null;
+ }
+
+ @Override
+ public Field makeField(AssociationDefinition assocDef, Object value, FieldGroup group)
+ {
+ AssociationFieldDefinition fieldDef = makeAssociationFieldDefinition(assocDef, group);
+ return new ContentField(assocDef, fieldDef, value);
+ }
+
+ /**
+ * Gets the associated value from the {@link ItemData}.
+ * If the value is null the method returns an empty {@link List}.
+ * If the value is a single Object (assumed to be a NodeRef) it returns a {@link List} containing a {@link String} representation of that object.
+ * If the value is a {@link Collection} of Objects, returns a {@link List} containing {@link String} representations of all the objects.
+ * @return An {@link ArrayList} of Strings or null.
+ */
+ @Override
+ protected Object getValue(QName name, ItemData> data)
+ {
+ Serializable values = data.getAssociationValue(name);
+ if (values == null)
+ {
+ return Collections.EMPTY_LIST;
+ }
+ if (values instanceof Collection>)
+ {
+ return getValues((Collection>) values);
+ }
+ return Collections.singletonList(values);
+ }
+
+ private List getValues(Collection> collection)
+ {
+ List results = new ArrayList(collection.size());
+ for (Object value : collection)
+ {
+ results.add(value.toString());
+ }
+ return results;
+ }
+
+ public AssociationFieldDefinition makeAssociationFieldDefinition(final AssociationDefinition assocDef, FieldGroup group)
+ {
+ String name = getPrefixedName(assocDef);
+ String endpointType = assocDef.getTargetClass().getName().toPrefixString(namespaceService);
+ AssociationFieldDefinition fieldDef = new AssociationFieldDefinition(name,
+ endpointType,
+ Direction.TARGET);
+
+ populateFieldDefinition(assocDef, fieldDef, group, ASSOC_DATA_PREFIX);
+
+ fieldDef.setEndpointMandatory(assocDef.isTargetMandatory());
+ fieldDef.setEndpointMany(assocDef.isTargetMany());
+ return fieldDef;
+ }
+
+ @Override
+ protected String getRegistryKey()
+ {
+ return FormFieldConstants.ASSOC;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.node.QNameFieldProcessor#getTypeDefinition(org.alfresco.service.namespace.QName, org.alfresco.repo.forms.processor.node.ItemData, boolean)
+ */
+ @Override
+ protected AssociationDefinition getTypeDefinition(QName fullName, ItemData> itemData, boolean isForcedField)
+ {
+ AssociationDefinition assocDefinition = itemData.getAssociationDefinition(fullName);
+ if (assocDefinition == null)
+ {
+ if (isForcedField)
+ {
+ assocDefinition = dictionaryService.getAssociation(fullName);
+ }
+ }
+ return assocDefinition;
+ }
+}
\ 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
new file mode 100644
index 0000000000..e3abeccbd0
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/ContentField.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.forms.processor.node;
+
+import org.alfresco.repo.forms.AssociationFieldDefinition;
+import org.alfresco.repo.forms.Field;
+import org.alfresco.repo.forms.FieldDefinition;
+import org.alfresco.repo.forms.PropertyFieldDefinition;
+import org.alfresco.service.cmr.dictionary.AssociationDefinition;
+import org.alfresco.service.cmr.dictionary.ClassAttributeDefinition;
+import org.alfresco.service.cmr.dictionary.PropertyDefinition;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * @author Nick Smith
+ */
+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;
+ }
+
+ public ContentField(AssociationDefinition assocDefinition,
+ AssociationFieldDefinition fieldDef, Object value)
+ {
+ this.isProperty = false;
+ this.classDefinition = assocDefinition;
+ this.fieldDefinition = fieldDef;
+ this.value = value;
+ }
+
+ /**
+ * 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)
+ {
+ this.classDefinition = null;
+ this.isProperty = true;
+ this.fieldDefinition = fieldDef;
+ this.value = value;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.task.Field#isTransient()
+ */
+ public boolean isTransient()
+ {
+ return classDefinition == null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.task.Field#getFieldDefinition()
+ */
+ public FieldDefinition getFieldDefinition()
+ {
+ return this.fieldDefinition;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.task.Field#getFullName()
+ */
+ public QName getFullName()
+ {
+ if (classDefinition == null)
+ {
+ return null;
+ }
+
+ return classDefinition.getName();
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.task.Field#getFieldName()
+ */
+ public String getFieldName()
+ {
+ return fieldDefinition.getName();
+ }
+
+ /*
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ String type = isTransient()?"Transient ":"";
+ type += isProperty ? "Property" : "Association";
+ return "Field: " + getFieldName() + " Type: " + type;
+ }
+
+ public Object getValue()
+ {
+ return value;
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/forms/processor/node/ContentModelFieldProcessorRegistry.java b/source/java/org/alfresco/repo/forms/processor/node/ContentModelFieldProcessorRegistry.java
new file mode 100644
index 0000000000..4e870f4fd8
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/ContentModelFieldProcessorRegistry.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.forms.processor.node;
+
+import org.alfresco.repo.forms.processor.FieldProcessorRegistry;
+
+/**
+ * @author Nick Smith
+ *
+ */
+public class ContentModelFieldProcessorRegistry extends FieldProcessorRegistry
+{
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.FieldProcessorRegistry#getKey(java.lang.String)
+ */
+ @Override
+ protected String getKey(String fieldName)
+ {
+ String[] parts = fieldName.split(FormFieldConstants.FIELD_NAME_SEPARATOR);
+ if (parts.length > 0)
+ {
+ return parts[0];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.FieldProcessorRegistry#useDefaultProcessor(java.lang.String)
+ */
+ @Override
+ protected boolean useDefaultProcessor(String fieldName)
+ {
+ // Only use default if the fieldName follows the format
+ // prefix:localname
+ String[] parts = fieldName.split(FormFieldConstants.FIELD_NAME_SEPARATOR);
+ return parts.length == 2;
+ }
+}
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 f4530e4db1..ddb356e371 100644
--- a/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java
+++ b/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java
@@ -30,21 +30,18 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.alfresco.model.ContentModel;
-import org.alfresco.repo.forms.AssociationFieldDefinition;
+import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.FieldDefinition;
-import org.alfresco.repo.forms.FieldGroup;
import org.alfresco.repo.forms.Form;
import org.alfresco.repo.forms.FormData;
import org.alfresco.repo.forms.FormException;
import org.alfresco.repo.forms.PropertyFieldDefinition;
-import org.alfresco.repo.forms.AssociationFieldDefinition.Direction;
import org.alfresco.repo.forms.FormData.FieldData;
-import org.alfresco.repo.forms.PropertyFieldDefinition.FieldConstraint;
import org.alfresco.repo.forms.processor.FilteredFormProcessor;
+import org.alfresco.repo.forms.processor.FormCreationData;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition;
-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.DictionaryService;
@@ -60,7 +57,6 @@ import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
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.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
@@ -69,7 +65,6 @@ import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.springframework.extensions.surf.util.I18NUtil;
-import org.springframework.util.StringUtils;
/**
* Abstract FormProcessor implementation that provides common functionality for
@@ -201,563 +196,53 @@ public abstract class ContentModelFormProcessor extends
this.contentService = contentService;
}
- /**
- * 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 namespaceService NamespaceService instance
- */
- public static void generatePropertyField(PropertyDefinition propDef, Form form, NamespaceService namespaceService)
+ @Override
+ protected List generateDefaultFields(FormCreationData data)
{
- generatePropertyField(propDef, form, null, null, namespaceService);
+ DefaultFieldBuilder defaultFieldBuilder = new DefaultFieldBuilder(data, fieldProcessorRegistry);
+ return defaultFieldBuilder.buildDefaultFields();
}
- /**
- * 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
- */
- public static void generatePropertyField(PropertyDefinition propDef, Form form, Serializable propValue,
- NamespaceService namespaceService)
+ protected Map populateAssociations(TypeDefinition typeDef)
{
- generatePropertyField(propDef, form, propValue, null, namespaceService);
+ // we only get the associations of the actual type so
+ // we also need to manually get associations from any
+ // mandatory aspects
+ HashMap allAssocs = new HashMap();
+ allAssocs.putAll(typeDef.getAssociations());
+ List aspects = typeDef.getDefaultAspects(true);
+ for (AspectDefinition aspect : aspects) {
+ allAssocs.putAll(aspect.getAssociations());
+ }
+ return Collections.unmodifiableMap(allAssocs);
}
- /**
- * 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 static void generatePropertyField(PropertyDefinition propDef, Form form, Serializable propValue,
- FieldGroup group, NamespaceService namespaceService)
+ @Override
+ protected ItemData makeItemData(ItemType item)
{
- 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);
- }
+ TypeDefinition baseType = getBaseType(item);
+ Set aspects = getAspectNames(item);
+ TypeDefinition anonType = dictionaryService.getAnonymousType(baseType.getName(), aspects);
+ Map propDefs = anonType.getProperties();
+ Map assocDefs = anonType.getAssociations();
+ Map propValues = getPropertyValues(item);
+ Map assocValues = getAssociationValues(item);
+ Map transientValues = getTransientValues(item);
+ return new ItemData(item, propDefs, assocDefs, propValues, assocValues, transientValues);
}
- /**
- * 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
- */
- public static void generateAssociationField(AssociationDefinition assocDef, Form form,
- NamespaceService namespaceService)
+ protected Set getAspectNames(ItemType item)
{
- generateAssociationField(assocDef, form, null, null, namespaceService);
+ return getBaseType(item).getDefaultAspectNames();
}
- /**
- * 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")
- public static void generateAssociationField(AssociationDefinition assocDef, Form form, List assocValues,
- NamespaceService namespaceService)
- {
- generateAssociationField(assocDef, form, assocValues, null, namespaceService);
- }
+ protected abstract Map getAssociationValues(ItemType item);
- /**
- * 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")
- 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);
- 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);
+ protected abstract Map getPropertyValues(ItemType item);
- // define the data key name and set
- String dataKeyName = ASSOC_DATA_PREFIX + nameParts[0] + DATA_KEY_SEPARATOR + nameParts[1];
- fieldDef.setDataKeyName(dataKeyName);
+ protected abstract Map getTransientValues(ItemType item);
- // 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);
- }
- }
-
- /**
- * Retrieves a logger instance to log to.
- *
- * @return Log instance to log to.
- */
- protected abstract Log getLogger();
-
- /**
- * 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 + "\"");
- }
- }
+ protected abstract TypeDefinition getBaseType(ItemType item);
/**
* Generates the field definition for the transient mimetype property
diff --git a/source/java/org/alfresco/repo/forms/processor/node/DefaultFieldBuilder.java b/source/java/org/alfresco/repo/forms/processor/node/DefaultFieldBuilder.java
new file mode 100644
index 0000000000..3121324cbc
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/DefaultFieldBuilder.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.forms.processor.node;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.alfresco.repo.forms.Field;
+import org.alfresco.repo.forms.processor.FieldProcessor;
+import org.alfresco.repo.forms.processor.FieldProcessorRegistry;
+import org.alfresco.repo.forms.processor.FormCreationData;
+import org.alfresco.service.namespace.QName;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Nick Smith
+ */
+public class DefaultFieldBuilder
+{
+ private static final String ASSOC_WARN = "Could not build Association Field as no valid FieldProcessor was specified";
+ private static final String PROP_WARNING = "Could not build Property Field as no valid FieldProcessor was specified";
+
+ private static final Log MY_LOGGER = LogFactory.getLog(DefaultFieldBuilder.class);
+
+ private final FormCreationData formData;
+ private final ItemData> ItemData;
+ private final FieldProcessorRegistry registry;
+
+ private final Log logger;
+
+ public DefaultFieldBuilder(FormCreationData data,
+ FieldProcessorRegistry registry)
+ {
+ this(data, registry, MY_LOGGER);
+ }
+
+ public DefaultFieldBuilder(FormCreationData formData,
+ FieldProcessorRegistry registry,
+ Log logger)
+ {
+ this.logger = logger;
+ this.formData = formData;
+ this.registry = registry;
+ this.ItemData = (ItemData>) formData.getItemData();
+ }
+
+ public List buildDefaultFields()
+ {
+ List assocFields = buildDefaultAssociationFields();
+ List propFields = buildDefaultPropertyFields();
+ List transFields = buildDefaultTransientFields();
+ int size = assocFields.size() + propFields.size() + transFields.size();
+ ArrayList fields = new ArrayList(size);
+ fields.addAll(assocFields);
+ fields.addAll(propFields);
+ fields.addAll(transFields);
+ return fields;
+ }
+
+ public List buildDefaultPropertyFields()
+ {
+ Collection names = ItemData.getAllPropertyDefinitionNames();
+ List fields = new ArrayList(names.size());
+ for (QName name : names)
+ {
+ fields.add(buildPropertyField(name));
+ }
+ return fields;
+ }
+
+ public List buildDefaultAssociationFields()
+ {
+ Collection names = ItemData.getAllAssociationDefinitionNames();
+ List fields = new ArrayList(names.size());
+ for (QName name : names)
+ {
+ fields.add(buildAssociationField(name));
+ }
+ return fields;
+ }
+
+ public List buildDefaultTransientFields()
+ {
+ Collection names = ItemData.getAllTransientFieldNames();
+ List fields = new ArrayList(names.size());
+ for (String name : names)
+ {
+ fields.add(buildTransientField(name));
+ }
+ return fields;
+ }
+
+ public Field buildAssociationField(QName assocName)
+ {
+ return buildQNameField(assocName, FormFieldConstants.ASSOC, ASSOC_WARN);
+ }
+
+ public Field buildPropertyField(QName propName)
+ {
+ return buildQNameField(propName, FormFieldConstants.PROP, PROP_WARNING);
+ }
+
+ private Field buildQNameField(QName assocName, String key, String warningMsg)
+ {
+ FieldProcessor fieldProcessor = registry.get(key);
+ if (fieldProcessor != null && fieldProcessor instanceof QNameFieldProcessor>)
+ {
+ QNameFieldProcessor> qnameProcessor = (QNameFieldProcessor>) fieldProcessor;
+ return qnameProcessor.generateField(assocName, ItemData, false);
+ }
+
+ if (logger.isWarnEnabled())
+ logger.warn(warningMsg);
+
+ return null;
+ }
+
+ public Field buildTransientField(String name)
+ {
+ FieldProcessor fieldProcessor = registry.get(name);
+ if (fieldProcessor != null)
+ {
+ return fieldProcessor.generateField(name, formData);
+ }
+
+ if (logger.isWarnEnabled())
+ logger.warn("Could not build Transient Field: "+ name +" as no FieldProcessor specified");
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/forms/processor/node/DefaultFieldProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/DefaultFieldProcessor.java
new file mode 100644
index 0000000000..1fc8bd23f4
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/DefaultFieldProcessor.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.forms.processor.node;
+
+import org.alfresco.repo.forms.Field;
+import org.alfresco.repo.forms.FieldGroup;
+import org.alfresco.service.cmr.dictionary.ClassAttributeDefinition;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.util.ParameterCheck;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+
+public class DefaultFieldProcessor extends QNameFieldProcessor implements InitializingBean
+{
+ private static final Log logger = LogFactory.getLog(DefaultFieldProcessor.class);
+
+ private final AssociationFieldProcessor assocProcessor = new AssociationFieldProcessor();
+ private final PropertyFieldProcessor propProcessor = new PropertyFieldProcessor();
+
+ @Override
+ protected Log getLogger()
+ {
+ return logger;
+ }
+
+ @Override
+ protected QName getFullName(String name)
+ {
+ String[] parts = name.split(FormFieldConstants.FIELD_NAME_SEPARATOR);
+ int position = parts.length - 1;
+ String localName = parts[position];// local name is always the last
+ // string in the arry
+ position--;
+ // prefix is always the penultimate string in the array.
+ String prefix = parts[position];
+ return QName.createQName(prefix, localName, namespaceService);
+ }
+
+ @Override
+ public Field generateField(QName fullName, ItemData> itemData, boolean isForcedField)
+ {
+ Field fieldInfo = propProcessor.generateField(fullName, itemData, isForcedField);
+ if (fieldInfo == null)
+ {
+ fieldInfo = assocProcessor.generateField(fullName, itemData, isForcedField);
+ }
+ return fieldInfo;
+ }
+
+ @Override
+ protected String getRegistryKey()
+ {
+ return "";
+ }
+
+ public void afterPropertiesSet() throws Exception
+ {
+ ParameterCheck.mandatory("dictionaryService", dictionaryService);
+ ParameterCheck.mandatory("namespaceService", namespaceService);
+ assocProcessor.setDictionaryService(dictionaryService);
+ assocProcessor.setNamespaceService(namespaceService);
+ propProcessor.setDictionaryService(dictionaryService);
+ propProcessor.setNamespaceService(namespaceService);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.node.QNameFieldProcessor#getGroup(org.alfresco.service.cmr.dictionary.ClassAttributeDefinition)
+ */
+ @Override
+ protected FieldGroup getGroup(ClassAttributeDefinition typeDef)
+ {
+ throw new UnsupportedOperationException("This method should never be called!");
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.node.QNameFieldProcessor#getTypeDefinition(org.alfresco.service.namespace.QName, org.alfresco.repo.forms.processor.node.ItemData, boolean)
+ */
+ @Override
+ protected ClassAttributeDefinition getTypeDefinition(QName fullName, ItemData> itemData, boolean isForcedField)
+ {
+ throw new UnsupportedOperationException("This method should never be called!");
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.node.QNameFieldProcessor#getValue(org.alfresco.service.namespace.QName, org.alfresco.repo.forms.processor.node.ItemData)
+ */
+ @Override
+ protected Object getValue(QName fullName, ItemData> itemData)
+ {
+ throw new UnsupportedOperationException("This method should never be called!");
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.node.QNameFieldProcessor#makeField(org.alfresco.service.cmr.dictionary.ClassAttributeDefinition, java.lang.Object, org.alfresco.repo.forms.FieldGroup)
+ */
+ @Override
+ protected Field makeField(ClassAttributeDefinition typeDef, Object value, FieldGroup group)
+ {
+ throw new UnsupportedOperationException("This method should never be called!");
+ }
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/forms/processor/node/FieldProcessorTest.java b/source/java/org/alfresco/repo/forms/processor/node/FieldProcessorTest.java
new file mode 100644
index 0000000000..6625ee66a1
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/FieldProcessorTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.forms.processor.node;
+
+import static org.alfresco.repo.forms.processor.node.FormFieldConstants.ASSOC;
+import static org.alfresco.repo.forms.processor.node.FormFieldConstants.PROP;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.alfresco.repo.forms.AssociationFieldDefinition;
+import org.alfresco.repo.forms.Field;
+import org.alfresco.repo.forms.PropertyFieldDefinition;
+import org.alfresco.repo.forms.AssociationFieldDefinition.Direction;
+import org.alfresco.repo.forms.processor.FormCreationData;
+import org.alfresco.service.cmr.dictionary.AssociationDefinition;
+import org.alfresco.service.cmr.dictionary.PropertyDefinition;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.NamespaceServiceMemoryImpl;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * @author Nick Smith
+ */
+public class FieldProcessorTest extends TestCase
+{
+ private static final String PREFIX = "test";
+ private static final String URI = "http://test/";
+ private static final String NAME1 = "Name1";
+ private static final String NAME2 = "Name2";
+ private static final String DESCRIPTION1 = "Description";
+ private static final String DESCRIPTION2 = "Another Description";
+ private static final String TITLE = "Title";
+ private static final QName qName1 = QName.createQName(URI, NAME1);
+ private static final QName qName2 = QName.createQName(URI, NAME2);
+
+ private NamespaceService namespaceService;
+ private FormCreationData data;
+
+ public void testMakeAssociationFieldDefinition() throws Exception
+ {
+ AssociationFieldProcessor processor = new AssociationFieldProcessor();
+ processor.setNamespaceService(namespaceService);
+
+ String name1 = ASSOC + ":"+ PREFIX +":"+ NAME1;
+ Field field = processor.generateField(name1, data);
+ AssociationFieldDefinition assocFieldDef = (AssociationFieldDefinition) field.getFieldDefinition();
+
+ assertNotNull(assocFieldDef);
+ assertEquals("assoc_" + PREFIX + "_" + NAME1, assocFieldDef.getDataKeyName());
+ assertEquals(PREFIX + ":" + NAME1, assocFieldDef.getName());
+ assertEquals(PREFIX + ":" + NAME1, assocFieldDef.getLabel());
+ assertEquals(Direction.TARGET, assocFieldDef.getEndpointDirection());
+ assertEquals(PREFIX + ":Target", assocFieldDef.getEndpointType());
+ assertEquals(DESCRIPTION1, assocFieldDef.getDescription());
+ assertFalse(assocFieldDef.isProtectedField());
+ assertFalse(assocFieldDef.isEndpointMandatory());
+ assertFalse(assocFieldDef.isEndpointMany());
+
+ // Repeat using different params to ensuere the fieldDefinition values
+ // are dependant on the AssociationDefinition values.
+ String name2 = ASSOC + ":" + PREFIX +":"+ NAME2;
+ field = processor.generateField(name2, data);
+ assocFieldDef = (AssociationFieldDefinition) field.getFieldDefinition();
+
+ assertEquals(TITLE, assocFieldDef.getLabel());
+ assertEquals(DESCRIPTION2, assocFieldDef.getDescription());
+ assertTrue(assocFieldDef.isProtectedField());
+ assertTrue(assocFieldDef.isEndpointMandatory());
+ assertTrue(assocFieldDef.isEndpointMany());
+ }
+
+ public void testMakePropertyFieldDefinition() throws Exception
+ {
+ PropertyFieldProcessor processor = new PropertyFieldProcessor();
+ processor.setNamespaceService(namespaceService);
+
+ String name1 = PROP+ ":" + PREFIX + ":" + NAME1;
+ Field field = processor.generateField(name1, data);
+ PropertyFieldDefinition propFieldDef = (PropertyFieldDefinition) field.getFieldDefinition();
+ assertNotNull(propFieldDef);
+ assertEquals("prop_" + PREFIX + "_" + NAME1, propFieldDef.getDataKeyName());
+ assertEquals(PREFIX + ":" + NAME1, propFieldDef.getName());
+ assertEquals(PREFIX + ":" + NAME1, propFieldDef.getLabel());
+ assertEquals("Default1", propFieldDef.getDefaultValue());
+ assertEquals(DESCRIPTION1, propFieldDef.getDescription());
+ assertFalse(propFieldDef.isProtectedField());
+ assertFalse(propFieldDef.isMandatory());
+ assertFalse(propFieldDef.isRepeating());// Maps to isMultiValued() on
+
+ // Repeat using different params to ensuere the fieldDefinition values
+ // are dependant on the PropertyDefinition values.
+ String name2 = PROP + ":" + PREFIX + ":" + NAME2;
+ field = processor.generateField(name2, data);
+ propFieldDef = (PropertyFieldDefinition) field.getFieldDefinition();
+ assertEquals(TITLE, propFieldDef.getLabel());
+ assertEquals(DESCRIPTION2, propFieldDef.getDescription());
+ assertEquals("Default2", propFieldDef.getDefaultValue());
+ assertTrue(propFieldDef.isProtectedField());
+ assertTrue(propFieldDef.isMandatory());
+ assertTrue(propFieldDef.isRepeating());
+ }
+
+ /*
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ namespaceService = makeNamespaceService();
+ data = new FormCreationData(makeItemData(), null, null);
+ }
+
+ private ItemData makeItemData()
+ {
+ Map propDefs = makePropertyDefs();
+ Map assocDefs = makeAssociationDefs();
+
+ Map propValues = new HashMap();
+ Map assocValues = new HashMap();
+ Map transientValues = new HashMap();
+ return new ItemData(null, propDefs, assocDefs, propValues, assocValues, transientValues);
+ }
+
+ private Map makeAssociationDefs()
+ {
+ QName targetClass = QName.createQName(URI, "Target");
+ AssociationDefinition assocDef1 = MockClassAttributeDefinition.mockAssociationDefinition(
+ qName1, targetClass,
+ null,// Defalt title, so sets label to be same as name.
+ DESCRIPTION1, false, false, false);
+ MockClassAttributeDefinition assocDef2 = MockClassAttributeDefinition.mockAssociationDefinition(
+ qName2, targetClass,
+ TITLE, DESCRIPTION2,
+ true, true, true);
+ Map assocDefs = new HashMap();
+ assocDefs.put(qName1, assocDef1);
+ assocDefs.put(qName2, assocDef2);
+ return assocDefs;
+ }
+
+ private Map makePropertyDefs()
+ {
+ QName dataTypeName = QName.createQName(URI, "Type");
+ PropertyDefinition propDef1 = MockClassAttributeDefinition.mockPropertyDefinition(
+ qName1, dataTypeName,
+ null,// Defalt title, so sets label to be same as name.
+ DESCRIPTION1, false,
+ "Default1", false, false);
+ PropertyDefinition propDef2 = MockClassAttributeDefinition.mockPropertyDefinition(
+ qName2, dataTypeName,
+ TITLE,
+ DESCRIPTION2, true,
+ "Default2", true, true);
+ Map propDefs = new HashMap();
+ propDefs.put(qName1, propDef1);
+ propDefs.put(qName2, propDef2);
+ return propDefs;
+ }
+
+ private NamespaceService makeNamespaceService()
+ {
+ NamespaceServiceMemoryImpl nsService = new NamespaceServiceMemoryImpl();
+ namespaceService.registerNamespace(PREFIX, URI);
+ return nsService;
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/forms/processor/node/FieldUtils.java b/source/java/org/alfresco/repo/forms/processor/node/FieldUtils.java
new file mode 100644
index 0000000000..aca0a00033
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/FieldUtils.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.forms.processor.node;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.alfresco.repo.forms.Field;
+import org.alfresco.repo.forms.FieldGroup;
+import org.alfresco.service.cmr.dictionary.AssociationDefinition;
+import org.alfresco.service.cmr.dictionary.PropertyDefinition;
+import org.alfresco.service.namespace.NamespaceService;
+
+/**
+ * Utility class to assist in creating {@link Field Fields} which represent
+ * {@link PropertyDefinition PropertyDefinitions} and
+ * {@link AssociationDefinition AssociationDefinitions}
+ *
+ * @author Nick Smith
+ *
+ */
+public class FieldUtils
+{
+
+ public static Field makePropertyField(
+ PropertyDefinition property,
+ Object value,
+ FieldGroup group,
+ NamespaceService namespaceService)
+ {
+ PropertyFieldProcessor processor = new PropertyFieldProcessor(namespaceService, null);
+ return processor.makeField(property, value, group);
+ }
+
+ public static List makePropertyFields(
+ Collection propDefs,
+ FieldGroup group,
+ NamespaceService namespaceService)
+ {
+ return makePropertyFields(propDefs, null, group, namespaceService);
+ }
+
+ public static List makePropertyFields(
+ Map propDefAndValue,
+ FieldGroup group,
+ NamespaceService namespaceService)
+ {
+ return makePropertyFields(propDefAndValue.keySet(), propDefAndValue, group, namespaceService);
+ }
+
+ public static List makePropertyFields(
+ Collection propDefs,
+ Map values,
+ FieldGroup group,
+ NamespaceService namespaceService)
+ {
+ PropertyFieldProcessor processor = new PropertyFieldProcessor(namespaceService, null);
+ ArrayList fields = new ArrayList(propDefs.size());
+ for (PropertyDefinition propDef : propDefs)
+ {
+ Object value = values==null?null:values.get(propDef);
+ Field field = processor.makeField(propDef, value, group);
+ fields.add(field);
+ }
+ return fields;
+ }
+
+ public static Field makeAssociationField(
+ AssociationDefinition assocDef,
+ Object value,
+ FieldGroup group,
+ NamespaceService namespaceService)
+ {
+ AssociationFieldProcessor processor = new AssociationFieldProcessor(namespaceService, null);
+ return processor.makeField(assocDef, value, group);
+ }
+
+
+ public static List makeAssociationFields(
+ Collection assocDefs,
+ FieldGroup group,
+ NamespaceService namespaceService)
+ {
+ return makeAssociationFields(assocDefs, null, group, namespaceService);
+ }
+
+ public static List makeAssociationFields(
+ Map assocDefAndValue,
+ FieldGroup group,
+ NamespaceService namespaceService)
+ {
+ return makeAssociationFields(assocDefAndValue.keySet(), assocDefAndValue, group, namespaceService);
+ }
+
+ public static List makeAssociationFields(
+ Collection assocDefs,
+ Map values,
+ FieldGroup group,
+ NamespaceService namespaceService)
+ {
+ AssociationFieldProcessor processor = new AssociationFieldProcessor(namespaceService, null);
+ ArrayList fields = new ArrayList(assocDefs.size());
+ for (AssociationDefinition propDef : assocDefs)
+ {
+ Object value = values==null?null:values.get(propDef);
+ Field field = processor.makeField(propDef, value, group);
+ fields.add(field);
+ }
+ return fields;
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/forms/processor/node/FormFieldConstants.java b/source/java/org/alfresco/repo/forms/processor/node/FormFieldConstants.java
index 8877537eaa..c8c7fab675 100644
--- a/source/java/org/alfresco/repo/forms/processor/node/FormFieldConstants.java
+++ b/source/java/org/alfresco/repo/forms/processor/node/FormFieldConstants.java
@@ -31,6 +31,8 @@ public interface FormFieldConstants
public static final String ASSOC = "assoc";
+ public static final String FIELD_NAME_SEPARATOR = ":";
+
public static final String DATA_KEY_SEPARATOR = "_";
public static final String PROP_DATA_PREFIX = PROP + DATA_KEY_SEPARATOR;
@@ -47,4 +49,7 @@ public interface FormFieldConstants
public static final String TRANSIENT_ENCODING = "encoding";
+ public static final String ADDED = "added";
+
+ public static final String REMOVED = "removed";
}
diff --git a/source/java/org/alfresco/repo/forms/processor/node/ItemData.java b/source/java/org/alfresco/repo/forms/processor/node/ItemData.java
new file mode 100644
index 0000000000..b68505a648
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/ItemData.java
@@ -0,0 +1,194 @@
+/*
+ * 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.node;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.alfresco.service.cmr.dictionary.AssociationDefinition;
+import org.alfresco.service.cmr.dictionary.PropertyDefinition;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * Simple data transfer object used by the ContentModelFormProcessor and its
+ * descendants.
+ *
+ * @author Nick Smith
+ */
+public class ItemData implements TransientValueGetter
+{
+ private final ItemType item;
+ private final Map propDefs;
+ private final Map assocDefs;
+ private final Map propValues;
+ private final Map assocValues;
+ private final Map transientValues;
+
+ public ItemData(ItemType item,
+ Map propDefs,
+ Map assocDefs,
+ Map propValues,
+ Map assocValues,
+ Map transientValues)
+ {
+ this.item = item;
+ this.propDefs = propDefs;
+ this.assocDefs = assocDefs;
+ this.propValues = propValues;
+ this.assocValues = assocValues;
+ this.transientValues = transientValues;
+ }
+
+ /**
+ * @return the item
+ */
+ public ItemType getItem()
+ {
+ return this.item;
+ }
+
+ /**
+ * @return the property value associated with the key or
+ * null if none exists.
+ */
+ public Serializable getPropertyValue(QName key)
+ {
+ return getValue(key, propValues);
+ }
+
+ /**
+ * @return the association value associated with the key or
+ * null if none exists.
+ */
+ public Serializable getAssociationValue(QName key)
+ {
+ return getValue(key, assocValues);
+ }
+
+ /**
+ * @return the value associated with the transient property specified by the
+ * fieldName or null if none exists.
+ */
+ public Object getTransientValue(String fieldName)
+ {
+ Object value = null;
+
+ if (transientValues != null)
+ {
+ value = transientValues.get(fieldName);
+ }
+
+ return value;
+ }
+
+ private Serializable getValue(QName key, Map values)
+ {
+ Serializable value = null;
+ if (values != null)
+ {
+ value = values.get(key);
+ }
+ return value;
+ }
+
+ /**
+ * @return The PropertyDefinition associated with the propName
+ * or null if none exists.
+ */
+ public PropertyDefinition getPropertyDefinition(QName propName)
+ {
+ PropertyDefinition propDef = null;
+ if (propDefs != null)
+ {
+ propDef = propDefs.get(propName);
+ }
+ return propDef;
+ }
+
+ /**
+ * @return The AssociationDefinition associated with the
+ * assocName or null if none exists.
+ */
+ public AssociationDefinition getAssociationDefinition(QName assocName)
+ {
+ AssociationDefinition assocDef = null;
+ if (assocDefs != null)
+ {
+ assocDef = assocDefs.get(assocName);
+ }
+ return assocDef;
+ }
+
+ /**
+ * @return Returns an unmodifiable Collection containing all the association
+ * definition {@link QName QNames} for the item.
+ */
+ public Collection getAllAssociationDefinitionNames()
+ {
+ if (assocDefs == null)
+ {
+ return Collections.emptyList();
+ }
+ else
+ {
+ return Collections.unmodifiableCollection(assocDefs.keySet());
+ }
+ }
+
+ /**
+ * @return Returns an unmodifiable Collection containing all the property
+ * definitions for the item.
+ */
+ public Collection getAllPropertyDefinitionNames()
+ {
+ if (propDefs == null)
+ {
+ return Collections.emptyList();
+ }
+ else
+ {
+ return Collections.unmodifiableCollection(propDefs.keySet());
+ }
+ }
+
+ /**
+ * @return Returns an unmodifiable Collection containing all the property
+ * definitions for the item.
+ */
+ public Collection getAllTransientFieldNames()
+ {
+ if (transientValues == null)
+ {
+ return Collections.emptyList();
+ }
+ else
+ {
+ return Collections.unmodifiableCollection(transientValues.keySet());
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/forms/processor/node/MockClassAttributeDefinition.java b/source/java/org/alfresco/repo/forms/processor/node/MockClassAttributeDefinition.java
new file mode 100644
index 0000000000..fe6a7f28b0
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/MockClassAttributeDefinition.java
@@ -0,0 +1,372 @@
+/*
+ * 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.node;
+
+import static org.mockito.Mockito.*;
+
+import java.util.List;
+
+import org.alfresco.repo.dictionary.IndexTokenisationMode;
+import org.alfresco.service.cmr.dictionary.AssociationDefinition;
+import org.alfresco.service.cmr.dictionary.ClassDefinition;
+import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+import org.alfresco.service.cmr.dictionary.ModelDefinition;
+import org.alfresco.service.cmr.dictionary.PropertyDefinition;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * @author Nick Smith
+ */
+public class MockClassAttributeDefinition implements PropertyDefinition, AssociationDefinition
+{
+
+ private final QName name;
+ private DataTypeDefinition dataType = mock(DataTypeDefinition.class);
+ private ClassDefinition targetClass = mock(ClassDefinition.class);
+ private String description = null;
+ private String defaultValue = null;
+ private String title = null;
+
+ private boolean targetMandatory = false;
+ private boolean targetMany = false;
+ private boolean isProtected = false;
+ private boolean mandatory = false;
+ private boolean multiValued = false;
+
+ private MockClassAttributeDefinition(QName name)
+ {
+ this.name = name;
+ }
+
+ private MockClassAttributeDefinition(QName name, String title, String description, boolean isProtected)
+ {
+ this(name);
+ this.title = title;
+ this.description = description;
+ this.isProtected = isProtected;
+ }
+
+ public static MockClassAttributeDefinition mockPropertyDefinition(QName name, QName dataTypeName)
+ {
+ MockClassAttributeDefinition mock = new MockClassAttributeDefinition(name);
+ mockDataTypeName(dataTypeName, mock);
+ return mock;
+ }
+
+ public static MockClassAttributeDefinition mockPropertyDefinition(QName name,//
+ QName dataTypeName,//
+ String title,//
+ String description,//
+ boolean isProtected,//
+ String defaultValue,//
+ boolean Mandatory,//
+ boolean multiValued)
+ {
+ MockClassAttributeDefinition mock = new MockClassAttributeDefinition(name, title, description, isProtected);
+ mockDataTypeName(dataTypeName, mock);
+ mock.defaultValue = defaultValue;
+ mock.mandatory = Mandatory;
+ mock.multiValued = multiValued;
+ return mock;
+ }
+
+ public static MockClassAttributeDefinition mockAssociationDefinition(QName name, QName targetClassName)
+ {
+ MockClassAttributeDefinition mock = new MockClassAttributeDefinition(name);
+ mockTargetClassName(targetClassName, mock);
+ return mock;
+ }
+
+ public static MockClassAttributeDefinition mockAssociationDefinition(QName name,//
+ QName targetClassName,//
+ String title,//
+ String description,//
+ boolean isProtected,//
+ boolean targetMandatory,//
+ boolean targetMany)
+ {
+ MockClassAttributeDefinition mock = new MockClassAttributeDefinition(name, title, description, isProtected);
+ mockTargetClassName(targetClassName, mock);
+ mock.targetMandatory = targetMandatory;
+ mock.targetMany = targetMany;
+ return mock;
+ }
+
+ private static void mockDataTypeName(QName dataTypeName, MockClassAttributeDefinition mock)
+ {
+ when(mock.dataType.getName()).thenReturn(dataTypeName);
+ }
+
+ private static void mockTargetClassName(QName targetClassName, MockClassAttributeDefinition mock)
+ {
+ when(mock.targetClass.getName()).thenReturn(targetClassName);
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.PropertyDefinition#getConstraints()
+ */
+ public List getConstraints()
+ {
+ return null;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.PropertyDefinition#getContainerClass
+ * ()
+ */
+ public ClassDefinition getContainerClass()
+ {
+ return null;
+ }
+
+ /*
+ * @see org.alfresco.service.cmr.dictionary.PropertyDefinition#getDataType()
+ */
+ public DataTypeDefinition getDataType()
+ {
+ return dataType;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.PropertyDefinition#getDefaultValue()
+ */
+ public String getDefaultValue()
+ {
+ return defaultValue;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.PropertyDefinition#getDescription()
+ */
+ public String getDescription()
+ {
+ return description;
+ }
+
+ /*
+ * @seeorg.alfresco.service.cmr.dictionary.PropertyDefinition#
+ * getIndexTokenisationMode()
+ */
+ public IndexTokenisationMode getIndexTokenisationMode()
+ {
+ return null;
+ }
+
+ /*
+ * @see org.alfresco.service.cmr.dictionary.PropertyDefinition#getModel()
+ */
+ public ModelDefinition getModel()
+ {
+ return null;
+ }
+
+ /*
+ * @see org.alfresco.service.cmr.dictionary.PropertyDefinition#getName()
+ */
+ public QName getName()
+ {
+ return name;
+ }
+
+ /*
+ * @see org.alfresco.service.cmr.dictionary.PropertyDefinition#getTitle()
+ */
+ public String getTitle()
+ {
+ return title;
+ }
+
+ /*
+ * @see org.alfresco.service.cmr.dictionary.PropertyDefinition#isIndexed()
+ */
+ public boolean isIndexed()
+ {
+ return false;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.PropertyDefinition#isIndexedAtomically
+ * ()
+ */
+ public boolean isIndexedAtomically()
+ {
+ return false;
+ }
+
+ /*
+ * @see org.alfresco.service.cmr.dictionary.PropertyDefinition#isMandatory()
+ */
+ public boolean isMandatory()
+ {
+ return mandatory;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.PropertyDefinition#isMandatoryEnforced
+ * ()
+ */
+ public boolean isMandatoryEnforced()
+ {
+ return false;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.PropertyDefinition#isMultiValued()
+ */
+ public boolean isMultiValued()
+ {
+ return multiValued;
+ }
+
+ /*
+ * @see org.alfresco.service.cmr.dictionary.PropertyDefinition#isOverride()
+ */
+ public boolean isOverride()
+ {
+ return false;
+ }
+
+ /*
+ * @see org.alfresco.service.cmr.dictionary.PropertyDefinition#isProtected()
+ */
+ public boolean isProtected()
+ {
+ return isProtected;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.PropertyDefinition#isStoredInIndex()
+ */
+ public boolean isStoredInIndex()
+ {
+ return false;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.AssociationDefinition#getSourceClass
+ * ()
+ */
+ public ClassDefinition getSourceClass()
+ {
+ return null;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.AssociationDefinition#getSourceRoleName
+ * ()
+ */
+ public QName getSourceRoleName()
+ {
+ return null;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.AssociationDefinition#getTargetClass
+ * ()
+ */
+ public ClassDefinition getTargetClass()
+ {
+ return targetClass;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.AssociationDefinition#getTargetRoleName
+ * ()
+ */
+ public QName getTargetRoleName()
+ {
+ return null;
+ }
+
+ /*
+ * @see org.alfresco.service.cmr.dictionary.AssociationDefinition#isChild()
+ */
+ public boolean isChild()
+ {
+ return false;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.AssociationDefinition#isSourceMandatory
+ * ()
+ */
+ public boolean isSourceMandatory()
+ {
+ return false;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.AssociationDefinition#isSourceMany()
+ */
+ public boolean isSourceMany()
+ {
+ return false;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.AssociationDefinition#isTargetMandatory
+ * ()
+ */
+ public boolean isTargetMandatory()
+ {
+ return targetMandatory;
+ }
+
+ /*
+ * @seeorg.alfresco.service.cmr.dictionary.AssociationDefinition#
+ * isTargetMandatoryEnforced()
+ */
+ public boolean isTargetMandatoryEnforced()
+ {
+ return false;
+ }
+
+ /*
+ * @see
+ * org.alfresco.service.cmr.dictionary.AssociationDefinition#isTargetMany()
+ */
+ public boolean isTargetMany()
+ {
+ return targetMany;
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/forms/processor/node/MockFieldProcessorRegistry.java b/source/java/org/alfresco/repo/forms/processor/node/MockFieldProcessorRegistry.java
new file mode 100644
index 0000000000..908d8985f6
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/MockFieldProcessorRegistry.java
@@ -0,0 +1,75 @@
+package org.alfresco.repo.forms.processor.node;
+
+import static org.alfresco.repo.forms.processor.node.FormFieldConstants.ASSOC;
+import static org.alfresco.repo.forms.processor.node.FormFieldConstants.PROP;
+import static org.alfresco.repo.forms.processor.node.FormFieldConstants.TRANSIENT_ENCODING;
+import static org.alfresco.repo.forms.processor.node.FormFieldConstants.TRANSIENT_MIMETYPE;
+import static org.alfresco.repo.forms.processor.node.FormFieldConstants.TRANSIENT_SIZE;
+
+import org.alfresco.repo.forms.processor.FieldProcessor;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.namespace.NamespaceService;
+
+public class MockFieldProcessorRegistry extends ContentModelFieldProcessorRegistry
+{
+ public MockFieldProcessorRegistry(NamespaceService namespaceService, DictionaryService dictionaryService)
+ {
+ register(PROP, makePropertyFieldProcessor(namespaceService, dictionaryService));
+ register(ASSOC, makeAssociationFieldProcessor(namespaceService, dictionaryService));
+ register(TRANSIENT_ENCODING, makeEncodingFieldProcessor(namespaceService));
+ register(TRANSIENT_MIMETYPE, makeMimetypeFieldProcessor(namespaceService));
+ register(TRANSIENT_SIZE, makeSizeFieldProcessor(namespaceService));
+ setDefaultProcessor(makeDefaultFieldProcessor(namespaceService, dictionaryService));
+ }
+
+ private FieldProcessor makeDefaultFieldProcessor(NamespaceService namespaceService,
+ DictionaryService dictionaryService)
+ {
+ DefaultFieldProcessor processor = new DefaultFieldProcessor();
+ processor.setDictionaryService(dictionaryService);
+ processor.setNamespaceService(namespaceService);
+ try
+ {
+ processor.afterPropertiesSet();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ return processor;
+ }
+
+ private TransientEncodingFieldProcessor makeEncodingFieldProcessor(NamespaceService namespaceService)
+ {
+ return new TransientEncodingFieldProcessor();
+ }
+
+ private TransientMimetypeFieldProcessor makeMimetypeFieldProcessor(NamespaceService namespaceService)
+ {
+ return new TransientMimetypeFieldProcessor();
+ }
+
+ private TransientSizeFieldProcessor makeSizeFieldProcessor(NamespaceService namespaceService)
+ {
+ return new TransientSizeFieldProcessor();
+ }
+
+ private PropertyFieldProcessor makePropertyFieldProcessor(NamespaceService namespaceService,
+ DictionaryService dictionaryService)
+ {
+ PropertyFieldProcessor processor = new PropertyFieldProcessor();
+ processor.setDictionaryService(dictionaryService);
+ processor.setNamespaceService(namespaceService);
+ return processor;
+ }
+
+ private AssociationFieldProcessor makeAssociationFieldProcessor(NamespaceService namespaceService,
+ DictionaryService dictionaryService)
+ {
+ AssociationFieldProcessor processor = new AssociationFieldProcessor();
+ processor.setDictionaryService(dictionaryService);
+ processor.setNamespaceService(namespaceService);
+ return processor;
+ }
+
+}
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 e7f21788aa..6f6b577316 100644
--- a/source/java/org/alfresco/repo/forms/processor/node/NodeFormProcessor.java
+++ b/source/java/org/alfresco/repo/forms/processor/node/NodeFormProcessor.java
@@ -20,21 +20,24 @@
package org.alfresco.repo.forms.processor.node;
import java.io.Serializable;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.alfresco.model.ContentModel;
-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.service.cmr.dictionary.AssociationDefinition;
-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.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
+import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -89,7 +92,8 @@ public class NodeFormProcessor extends ContentModelFormProcessor fields, List forcedFields, Form form,
- Map context)
+ protected String getItemType(NodeRef item)
{
- if (logger.isDebugEnabled()) logger.debug("Generating form for: " + item);
-
- // generate the form for the node
- generateNode(item, fields, forcedFields, form);
-
- if (logger.isDebugEnabled()) logger.debug("Generated form: " + form);
+ QName type = this.nodeService.getType(item);
+ return type.toPrefixString(this.namespaceService);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getItemURI(java.lang.Object)
+ */
+ @Override
+ protected String getItemURI(NodeRef item)
+ {
+ StringBuilder builder = new StringBuilder("/api/node/");
+ builder.append(item.getStoreRef().getProtocol()).append("/");
+ builder.append(item.getStoreRef().getIdentifier()).append("/");
+ builder.append(item.getId());
+ return builder.toString();
+ }
+
+ @Override
+ protected Map getPropertyValues(NodeRef nodeRef)
+ {
+ return nodeService.getProperties(nodeRef);
}
- /**
- * Sets up the Form object for the given NodeRef
- *
- * @param nodeRef The NodeRef to generate a Form for
- * @param fields Restricted list of fields to include
- * @param forcedFields List of fields to forcibly include
- * @param form The Form instance to populate
- */
- protected void generateNode(NodeRef nodeRef, List fields, List forcedFields, Form form)
+ @Override
+ protected Map getAssociationValues(NodeRef item)
{
- // set the type and URL of the item
- QName type = this.nodeService.getType(nodeRef);
- 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());
- setFormItemUrl(form, builder.toString());
-
- if (fields != null && fields.size() > 0)
+ HashMap assocs = new HashMap();
+ List targetAssocs = nodeService.getTargetAssocs(item, RegexQNamePattern.MATCH_ALL);
+ List childAssocs = nodeService.getChildAssocs(item);
+ for (ChildAssociationRef childAssoc : childAssocs)
{
- generateSelectedFields(nodeRef, null, fields, forcedFields, form);
+ QName name = childAssoc.getTypeQName();
+ NodeRef target = childAssoc.getChildRef();
+ addAssocToMap(name, target, assocs);
+ }
+ for (AssociationRef associationRef : targetAssocs)
+ {
+ QName name = associationRef.getTypeQName();
+ NodeRef target = associationRef.getTargetRef();
+ addAssocToMap(name, target, assocs);
+ }
+ return assocs;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void addAssocToMap(QName name, NodeRef target, HashMap assocs)
+ {
+ Serializable value = assocs.get(name);
+ if(value == null)
+ {
+ LinkedHashSet values = new LinkedHashSet();
+ values.add(target);
+ assocs.put(name, values);
}
else
{
- // setup field definitions and data
- generateAllPropertyFields(nodeRef, form);
- generateAllAssociationFields(nodeRef, form);
- generateTransientFields(nodeRef, form);
- }
-
- // process working copy nodes, just returns if it's not
- processWorkingCopy(nodeRef, form);
- }
-
- /**
- * Sets up the field definitions for all the node's properties.
- *
- * @param nodeRef The NodeRef of the node being setup
- * @param form The Form instance to populate
- */
- protected void generateAllPropertyFields(NodeRef nodeRef, Form form)
- {
- // get data dictionary definition for node
- QName type = this.nodeService.getType(nodeRef);
- TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService.getAspects(nodeRef));
-
- // iterate round the property definitions for the node and create
- // the equivalent field definition and setup the data for the property
- Map propDefs = typeDef.getProperties();
- Map propValues = this.nodeService.getProperties(nodeRef);
- for (PropertyDefinition propDef : propDefs.values())
- {
- generatePropertyField(propDef, form, propValues.get(propDef.getName()), this.namespaceService);
- }
- }
-
- /**
- * Sets up the field definitions for all the node's associations.
- *
- * @param nodeRef The NodeRef of the node being setup
- * @param form The Form instance to populate
- */
- protected void generateAllAssociationFields(NodeRef nodeRef, Form form)
- {
- // get data dictionary definition for the node
- QName type = this.nodeService.getType(nodeRef);
- TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService.getAspects(nodeRef));
-
- // iterate round the association defintions and setup field definition
- Map assocDefs = typeDef.getAssociations();
- for (AssociationDefinition assocDef : assocDefs.values())
- {
- generateAssociationField(assocDef, form, retrieveAssociationValues(nodeRef, assocDef),
- this.namespaceService);
- }
- }
-
- /**
- * Sets up the field definitions for any transient fields that may be
- * useful, for example, 'mimetype', 'size' and 'encoding'.
- *
- * @param nodeRef The NodeRef of the node being setup
- * @param form The Form instance to populate
- */
- protected void generateTransientFields(NodeRef nodeRef, Form form)
- {
- // if the node is content add the 'mimetype', 'size' and 'encoding'
- // fields.
- QName type = this.nodeService.getType(nodeRef);
- if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT))
- {
- ContentData content = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
- if (content != null)
+ if(value instanceof Set>)
{
- // setup mimetype field
- generateMimetypePropertyField(content, form);
-
- // setup encoding field
- generateEncodingPropertyField(content, form);
-
- // setup size field
- generateSizePropertyField(content, form);
+ ((Set)value).add(target);
}
}
}
+
+ @Override
+ protected Map getTransientValues(NodeRef item)
+ {
+ Map values = new HashMap(3);
+ ContentData contentData = getContentData(item);
+ if(contentData!=null)
+ {
+ values.put(TRANSIENT_ENCODING, contentData.getEncoding());
+ values.put(TRANSIENT_MIMETYPE, contentData.getMimetype());
+ values.put(TRANSIENT_SIZE, contentData.getSize());
+ }
+ return values;
+ }
+
+ @Override
+ protected Set getAspectNames(NodeRef nodeRef)
+ {
+ return nodeService.getAspects(nodeRef);
+ }
+
+ @Override
+ protected TypeDefinition getBaseType(NodeRef nodeRef)
+ {
+ QName typeName = nodeService.getType(nodeRef);
+ return dictionaryService.getType(typeName);
+ }
+
+ private ContentData getContentData(NodeRef nodeRef)
+ {
+ // Checks if the node is content and if so gets the ContentData
+ QName type = this.nodeService.getType(nodeRef);
+ ContentData content = null;
+ if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT))
+ {
+ content = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
+ }
+ return content;
+ }
/*
* @see
@@ -244,7 +231,8 @@ public class NodeFormProcessor extends ContentModelFormProcessor.
+ */
+
+package org.alfresco.repo.forms.processor.node;
+
+import static org.alfresco.repo.forms.processor.node.FormFieldConstants.PROP_DATA_PREFIX;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.alfresco.repo.forms.Field;
+import org.alfresco.repo.forms.FieldGroup;
+import org.alfresco.repo.forms.PropertyFieldDefinition;
+import org.alfresco.repo.forms.PropertyFieldDefinition.FieldConstraint;
+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.DictionaryService;
+import org.alfresco.service.cmr.dictionary.PropertyDefinition;
+import org.alfresco.service.cmr.repository.ContentData;
+import org.alfresco.service.cmr.repository.Period;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.util.StringUtils;
+
+public class PropertyFieldProcessor extends QNameFieldProcessor
+{
+ private static final Log logger = LogFactory.getLog(PropertyFieldProcessor.class);
+
+ public PropertyFieldProcessor()
+ {
+ // Constructor for Spring.
+ }
+
+ public PropertyFieldProcessor(NamespaceService namespaceService, DictionaryService dictionaryService)
+ {
+ super(namespaceService, dictionaryService);
+ }
+
+ @Override
+ protected Log getLogger()
+ {
+ return logger;
+ }
+
+ @Override
+ protected PropertyDefinition getTypeDefinition(QName fullName, ItemData> itemData, boolean isForcedField)
+ {
+ PropertyDefinition propDef = itemData.getPropertyDefinition(fullName);
+ if (propDef == null)
+ {
+ if (isForcedField)
+ {
+ propDef = dictionaryService.getProperty(fullName);
+ }
+ }
+ return propDef;
+ }
+
+ @Override
+ public Field makeField(PropertyDefinition propDef, Object value, FieldGroup group)
+ {
+ PropertyFieldDefinition fieldDef = makePropertyFieldDefinition(propDef, group);
+ return new ContentField(propDef, fieldDef, value);
+ }
+
+ @Override
+ protected FieldGroup getGroup(PropertyDefinition propDef)
+ {
+ // TODO Need to Implement this once Composite Content is implementd.
+ return null;
+ }
+
+ @Override
+ protected Object getValue(QName name, ItemData> data)
+ {
+ Serializable value = data.getPropertyValue(name);
+ if (value == null)
+ {
+ return null;
+ }
+
+ if (value instanceof Collection>)
+ {
+ // 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.
+ Collection> values = (Collection>) value;
+ return StringUtils.collectionToCommaDelimitedString(values);
+ }
+ else if (value instanceof ContentData)
+ {
+ // for content properties retrieve the info URL rather than the
+ // the object value itself
+ ContentData contentData = (ContentData)value;
+ return contentData.getInfoUrl();
+ }
+ return value;
+ }
+
+ private PropertyFieldDefinition makePropertyFieldDefinition(final PropertyDefinition propDef, FieldGroup group)
+ {
+ String name = getPrefixedName(propDef);
+ QName dataType = propDef.getDataType().getName();
+ PropertyFieldDefinition fieldDef = new PropertyFieldDefinition(name, dataType.getLocalName());
+
+ populateFieldDefinition(propDef, fieldDef, group, PROP_DATA_PREFIX);
+
+ 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
+ // currently 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 (dataType.equals(DataTypeDefinition.PERIOD))
+ {
+ PeriodDataTypeParameters periodOptions = getPeriodOptions();
+ fieldDef.setDataTypeParameters(periodOptions);
+ }
+
+ // setup constraints for the property
+ List fieldConstraints = makeFieldConstraints(propDef);
+ fieldDef.setConstraints(fieldConstraints);
+ return fieldDef;
+ }
+
+ private 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;
+ }
+
+ @Override
+ protected String getRegistryKey()
+ {
+ return FormFieldConstants.PROP;
+ }
+}
diff --git a/source/java/org/alfresco/repo/forms/processor/node/QNameFieldProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/QNameFieldProcessor.java
new file mode 100644
index 0000000000..6e88297154
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/QNameFieldProcessor.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.forms.processor.node;
+
+import static org.alfresco.repo.forms.processor.node.FormFieldConstants.DATA_KEY_SEPARATOR;
+
+import org.alfresco.repo.forms.Field;
+import org.alfresco.repo.forms.FieldDefinition;
+import org.alfresco.repo.forms.FieldGroup;
+import org.alfresco.repo.forms.processor.AbstractFieldProcessor;
+import org.alfresco.repo.forms.processor.FormCreationData;
+import org.alfresco.service.cmr.dictionary.ClassAttributeDefinition;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+
+public abstract class QNameFieldProcessor extends AbstractFieldProcessor>
+{
+ protected NamespaceService namespaceService;
+ protected DictionaryService dictionaryService;
+
+ public QNameFieldProcessor()
+ {
+ // Constructor for Spring.
+ }
+
+ public QNameFieldProcessor(NamespaceService namespaceService, DictionaryService dictionaryService)
+ {
+ this.namespaceService = namespaceService;
+ this.dictionaryService = dictionaryService;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.field.processor.AbstractFieldProcessor#generateTypedField(java.lang.String, java.lang.Object)
+ */
+ @Override
+ protected Field generateTypedField(String fieldName, FormCreationData formData, ItemData> typedData)
+ {
+ QName fullName = getFullName(fieldName);
+ boolean isForcedField = formData.isForcedField(fieldName);
+ Field field = generateField(fullName, typedData, isForcedField);
+ return field;
+ }
+
+ protected QName getFullName(String name)
+ {
+ String[] parts = name.split(FormFieldConstants.FIELD_NAME_SEPARATOR);
+ String prefix = parts[1];
+ String localName = parts[2];
+ return QName.createQName(prefix, localName, namespaceService);
+ }
+
+ protected String getPrefixedName(ClassAttributeDefinition attribDef)
+ {
+ return attribDef.getName().toPrefixString(namespaceService);
+ }
+
+ public Field generateField(QName fullName, ItemData> itemData, boolean isForcedField)
+ {
+ Type propDef = getTypeDefinition(fullName, itemData, isForcedField);
+ Field field = null;
+ if (propDef != null)
+ {
+ Object value = getValue(fullName, itemData);
+ FieldGroup group = getGroup(propDef);
+ field = makeField(propDef, value, group);
+ }
+ return field;
+ }
+
+ /**
+ * Sets several properties on the {@link 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 fieldDef A factory object used to create the FieldDefinition to be
+ * returned.
+ * @param group Used to set the group on the returned FieldDefinition.
+ */
+ protected void populateFieldDefinition(Type attribDef, FieldDefinition fieldDef,
+ FieldGroup group, String dataKeyPrefix)
+ {
+ String attribName = fieldDef.getName();
+ 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);
+ }
+
+ protected String makeDataKeyForName(String propName, String prefix)
+ {
+ String[] nameParts = QName.splitPrefixedQName(propName);
+ String firstPart = nameParts[0];
+ StringBuilder builder = new StringBuilder(prefix);
+ if (firstPart.length() > 0)
+ {
+ builder.append(firstPart);
+ builder.append(DATA_KEY_SEPARATOR);
+ }
+ builder.append(nameParts[1]);
+ return builder.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.field.processor.AbstractFieldProcessor#getExpectedDataType()
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Class> getExpectedDataType()
+ {
+ // This is nasty but unavoidable because of generics.
+ Object clazz = ItemData.class;
+ return (Class>)clazz;
+ }
+
+ /**
+ * @param namespaceService the namespaceService to set
+ */
+ public void setNamespaceService(NamespaceService namespaceService)
+ {
+ this.namespaceService = namespaceService;
+ }
+
+ /**
+ * @param dictionaryService the dictionaryService to set
+ */
+ public void setDictionaryService(DictionaryService dictionaryService)
+ {
+ this.dictionaryService = dictionaryService;
+ }
+
+ protected abstract Field makeField(Type typeDef, Object value, FieldGroup group);
+
+ protected abstract FieldGroup getGroup(Type typeDef);
+
+ protected abstract Object getValue(QName fullName, ItemData> itemData);
+
+ protected abstract Type getTypeDefinition(QName fullName, ItemData> itemData, boolean isForcedField);
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/forms/processor/node/TransientEncodingFieldProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/TransientEncodingFieldProcessor.java
new file mode 100644
index 0000000000..27e9bd541f
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/TransientEncodingFieldProcessor.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+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.PropertyFieldDefinition;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.extensions.surf.util.I18NUtil;
+
+public class TransientEncodingFieldProcessor extends TransientFieldProcessor
+{
+ private static final Log logger = LogFactory.getLog(TransientEncodingFieldProcessor.class);
+
+ private static final String MSG_ENCODING_LABEL = "form_service.encoding.label";
+ private static final String MSG_ENCODING_DESC = "form_service.encoding.description";
+
+ @Override
+ protected Log getLogger()
+ {
+ return logger;
+ }
+
+ @Override
+ protected PropertyFieldDefinition makeTransientPropertyDefinition()
+ {
+ 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);
+ return encodingField;
+ }
+
+ @Override
+ protected String getRegistryKey()
+ {
+ return FormFieldConstants.TRANSIENT_ENCODING;
+ }
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/forms/processor/node/TransientFieldProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/TransientFieldProcessor.java
new file mode 100644
index 0000000000..37f8957b2e
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/TransientFieldProcessor.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.forms.processor.node;
+
+import org.alfresco.repo.forms.Field;
+import org.alfresco.repo.forms.PropertyFieldDefinition;
+import org.alfresco.repo.forms.processor.AbstractFieldProcessor;
+import org.alfresco.repo.forms.processor.FormCreationData;
+
+public abstract class TransientFieldProcessor extends AbstractFieldProcessor
+{
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.forms.processor.AbstractFieldProcessor#generateTypedField(java.lang.String, org.alfresco.repo.forms.processor.node.FormCreationData, java.lang.Object)
+ */
+ @Override
+ protected Field generateTypedField(String fieldName, FormCreationData formData, TransientValueGetter typedData)
+ {
+ PropertyFieldDefinition transientPropDef = makeTransientPropertyDefinition();
+ Field fieldInfo = null;
+ Object value = getValue(fieldName, typedData);
+ if (transientPropDef != null)
+ {
+ fieldInfo = new ContentField(transientPropDef, value);
+ }
+ return fieldInfo;
+ }
+
+ protected Object getValue(String fieldName, TransientValueGetter data)
+ {
+ return data.getTransientValue(fieldName);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seeorg.alfresco.repo.forms.field.processor.AbstractFieldProcessor#
+ * getExpectedDataType()
+ */
+ @Override
+ protected Class getExpectedDataType()
+ {
+ return TransientValueGetter.class;
+ }
+
+ protected abstract PropertyFieldDefinition makeTransientPropertyDefinition();
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/forms/processor/node/TransientMimetypeFieldProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/TransientMimetypeFieldProcessor.java
new file mode 100644
index 0000000000..48bc291602
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/TransientMimetypeFieldProcessor.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+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_MIMETYPE;
+
+import org.alfresco.repo.forms.PropertyFieldDefinition;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.extensions.surf.util.I18NUtil;
+
+public class TransientMimetypeFieldProcessor extends TransientFieldProcessor
+{
+ private static final Log logger = LogFactory.getLog(TransientMimetypeFieldProcessor.class);
+ private static final String MSG_MIMETYPE_LABEL = "form_service.mimetype.label";
+ private static final String MSG_MIMETYPE_DESC = "form_service.mimetype.description";
+
+ @Override
+ protected Log getLogger() {
+ return logger;
+ }
+
+ @Override
+ protected PropertyFieldDefinition makeTransientPropertyDefinition() {
+ 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);
+ return mimetypeField;
+ }
+
+ @Override
+ protected String getRegistryKey()
+ {
+ return FormFieldConstants.TRANSIENT_MIMETYPE;
+ }
+}
diff --git a/source/java/org/alfresco/repo/forms/processor/node/TransientSizeFieldProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/TransientSizeFieldProcessor.java
new file mode 100644
index 0000000000..97e95167e0
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/TransientSizeFieldProcessor.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+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_SIZE;
+
+import org.alfresco.repo.forms.PropertyFieldDefinition;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.extensions.surf.util.I18NUtil;
+
+public class TransientSizeFieldProcessor extends TransientFieldProcessor
+{
+ private static final Log logger = LogFactory.getLog(TransientSizeFieldProcessor.class);
+ private static final String MSG_SIZE_LABEL = "form_service.size.label";
+ private static final String MSG_SIZE_DESC = "form_service.size.description";
+
+ @Override
+ protected Log getLogger()
+ {
+ return logger;
+ }
+
+ @Override
+ protected PropertyFieldDefinition makeTransientPropertyDefinition()
+ {
+ 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);
+ return sizeField;
+ }
+
+ @Override
+ protected String getRegistryKey()
+ {
+ return FormFieldConstants.TRANSIENT_SIZE;
+ }
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/forms/processor/node/TransientValueGetter.java b/source/java/org/alfresco/repo/forms/processor/node/TransientValueGetter.java
new file mode 100644
index 0000000000..f53d5887dc
--- /dev/null
+++ b/source/java/org/alfresco/repo/forms/processor/node/TransientValueGetter.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.forms.processor.node;
+
+/**
+ * @author Nick Smith
+ *
+ */
+public interface TransientValueGetter
+{
+
+ Object getTransientValue(String name);
+}
diff --git a/source/java/org/alfresco/repo/forms/processor/node/TypeFormProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/TypeFormProcessor.java
index 16153634e4..80798eb8c9 100644
--- a/source/java/org/alfresco/repo/forms/processor/node/TypeFormProcessor.java
+++ b/source/java/org/alfresco/repo/forms/processor/node/TypeFormProcessor.java
@@ -21,20 +21,15 @@ package org.alfresco.repo.forms.processor.node;
import java.io.Serializable;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
-import org.alfresco.repo.forms.Form;
import org.alfresco.repo.forms.FormData;
import org.alfresco.repo.forms.FormException;
import org.alfresco.repo.forms.FormNotFoundException;
import org.alfresco.repo.forms.Item;
import org.alfresco.repo.forms.FormData.FieldData;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
-import org.alfresco.service.cmr.dictionary.AspectDefinition;
-import org.alfresco.service.cmr.dictionary.AssociationDefinition;
-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.namespace.InvalidQNameException;
@@ -113,8 +108,11 @@ public class TypeFormProcessor extends ContentModelFormProcessor fields,
- List forcedFields, Form form, Map context)
- {
- if (logger.isDebugEnabled()) logger.debug("Generating form for item: " + item);
-
- // generate the form for the node
- generateType(item, fields, forcedFields, form);
- if (logger.isDebugEnabled()) logger.debug("Generating form: " + form);
- }
-
- /**
- * Sets up the Form object for the given NodeRef
- *
- * @param nodeRef The NodeRef to generate a Form for
- * @param fields Restricted list of fields to include
- * @param forcedFields List of fields to forcibly include
- * @param form The Form instance to populate
- */
- protected void generateType(TypeDefinition typeDef, List fields,
- List forcedFields, Form form)
- {
- // set the type and URL of the item
- form.getItem().setType(typeDef.getName().toPrefixString(this.namespaceService));
- form.getItem().setUrl(
- "/api/classes/"
- + typeDef.getName().toPrefixString(this.namespaceService).replace(
- ":", "_"));
-
- if (fields != null && fields.size() > 0)
- {
- generateSelectedFields(null, typeDef, fields, forcedFields, form);
- }
- else
- {
- // setup field definitions and data
- generateAllPropertyFields(typeDef, form);
- generateAllAssociationFields(typeDef, form);
-
- // TODO: generate transient properties for content types?
- }
- }
-
- /**
- * 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
@@ -238,30 +131,29 @@ public class TypeFormProcessor extends ContentModelFormProcessor()
- {
- public Object doWork() throws Exception
- {
- persistNode(nodeRef, data);
- return null;
- }
-
- },
- AuthenticationUtil.getSystemUserName());
+ // persist the form data as the admin user
+ AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork
+ *
+ * @param propDef The PropertyDefinition of the field to generate
+ * @param form The Form instance to populate
+ * @param namespaceService NamespaceService instance
+ */
+ protected void generatePropertyField(PropertyDefinition propDef, Form form, NamespaceService namespaceService)
+ {
+ 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;
+ }
}