Adding generic params to FilterFormProcessor and associated classes. Now the type of object being processed by the form processor is statically types at compile time.

The Filter interface uses the same generic params, ensuring that a filter can only be assigned to a FormProcessor if it handles the correct item type.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@16016 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
N Smith
2009-09-01 14:42:05 +00:00
parent 1793a46d7c
commit 9aef9620ad
8 changed files with 668 additions and 519 deletions

View File

@@ -32,7 +32,7 @@ import org.apache.commons.logging.LogFactory;
* *
* @author Gavin Cornwell * @author Gavin Cornwell
*/ */
public abstract class AbstractFilter implements Filter public abstract class AbstractFilter<ItemType, PersistType> implements Filter<ItemType, PersistType>
{ {
private static final Log logger = LogFactory.getLog(AbstractFilter.class); private static final Log logger = LogFactory.getLog(AbstractFilter.class);

View File

@@ -36,7 +36,7 @@ import org.alfresco.repo.forms.FormData;
* *
* @author Gavin Cornwell * @author Gavin Cornwell
*/ */
public interface Filter public interface Filter<ItemType, PersistType>
{ {
/** /**
* Determines whether the filter is active * Determines whether the filter is active
@@ -61,7 +61,7 @@ public interface Filter
* @param @param context Map representing optional context that * @param @param context Map representing optional context that
* can be used during retrieval of the form * can be used during retrieval of the form
*/ */
public void beforeGenerate(Object item, List<String> fields, List<String> forcedFields, public void beforeGenerate(ItemType item, List<String> fields, List<String> forcedFields,
Form form, Map<String, Object> context); Form form, Map<String, Object> context);
/** /**
@@ -80,7 +80,7 @@ public interface Filter
* @param context Map representing optional context that * @param context Map representing optional context that
* can be used during retrieval of the form * can be used during retrieval of the form
*/ */
public void afterGenerate(Object item, List<String> fields, List<String> forcedFields, public void afterGenerate(ItemType item, List<String> fields, List<String> forcedFields,
Form form, Map<String, Object> context); Form form, Map<String, Object> context);
/** /**
@@ -95,7 +95,7 @@ public interface Filter
* @param item The item to persist the form data for * @param item The item to persist the form data for
* @param data The form data * @param data The form data
*/ */
public void beforePersist(Object item, FormData data); public void beforePersist(ItemType item, FormData data);
/** /**
* Callback used to indicate that the given form data was just persisted * Callback used to indicate that the given form data was just persisted
@@ -112,5 +112,5 @@ public interface Filter
* @param persistedObject The object created or modified as a result of * @param persistedObject The object created or modified as a result of
* the form persistence * the form persistence
*/ */
public void afterPersist(Object item, FormData data, Object persistedObject); public void afterPersist(ItemType item, FormData data, PersistType persistedObject);
} }

View File

@@ -22,6 +22,7 @@
* the FLOSS exception, and it is also available here: * the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing" * http://www.alfresco.com/legal/licensing"
*/ */
package org.alfresco.repo.forms.processor; package org.alfresco.repo.forms.processor;
import java.util.ArrayList; import java.util.ArrayList;
@@ -33,31 +34,30 @@ import org.apache.commons.logging.LogFactory;
/** /**
* Holds a list of filters for a type of form processor. * Holds a list of filters for a type of form processor.
* <p> * <p>
* Each filter is called before and after the processor generates and * Each filter is called before and after the processor generates and persists
* persists the form, thus allowing the form and the effected objects * the form, thus allowing the form and the effected objects to be manipulated
* to be manipulated prior to generation or persistence or after the * prior to generation or persistence or after the fact.
* fact.
* </p> * </p>
* <p> * <p>
* Each filter is responsible for determing whether it applies to the item * Each filter is responsible for determing whether it applies to the item being
* being processed. * processed.
* </p> * </p>
* *
* @see org.alfresco.repo.forms.processor.Filter * @see org.alfresco.repo.forms.processor.Filter
* @author Gavin Cornwell * @author Gavin Cornwell
*/ */
public class FilterRegistry public class FilterRegistry<ItemType, PersistType>
{ {
private static final Log logger = LogFactory.getLog(FilterRegistry.class); private static final Log logger = LogFactory.getLog(FilterRegistry.class);
protected List<Filter> filters; protected List<Filter<ItemType, PersistType>> filters;
/** /**
* Constructs the registry * Constructs the registry
*/ */
public FilterRegistry() public FilterRegistry()
{ {
this.filters = new ArrayList<Filter>(4); this.filters = new ArrayList<Filter<ItemType, PersistType>>(4);
} }
/** /**
@@ -65,14 +65,13 @@ public class FilterRegistry
* *
* @param filter The Filter to regsiter * @param filter The Filter to regsiter
*/ */
public void addFilter(Filter filter) public void addFilter(Filter<ItemType, PersistType> filter)
{ {
if (filter.isActive()) if (filter.isActive())
{ {
this.filters.add(filter); this.filters.add(filter);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled()) logger.debug("Registered filter: " + filter + " in registry: " + this);
logger.debug("Registered filter: " + filter + " in registry: " + this);
} }
else if (logger.isWarnEnabled()) else if (logger.isWarnEnabled())
{ {
@@ -85,12 +84,12 @@ public class FilterRegistry
* *
* @return List of active Filter objects * @return List of active Filter objects
*/ */
public List<Filter> getFilters() public List<Filter<ItemType, PersistType>> getFilters()
{ {
List<Filter> activeFilters = new ArrayList<Filter>(4); List<Filter<ItemType, PersistType>> activeFilters = new ArrayList<Filter<ItemType, PersistType>>(4);
// iterate round the filters and add each active filter to the list // iterate round the filters and add each active filter to the list
for (Filter filter: this.filters) for (Filter<ItemType, PersistType> filter : this.filters)
{ {
if (filter.isActive()) if (filter.isActive())
{ {
@@ -98,8 +97,7 @@ public class FilterRegistry
} }
} }
if (logger.isDebugEnabled()) if (logger.isDebugEnabled()) logger.debug("Returning active filters: " + activeFilters);
logger.debug("Returning active filters: " + activeFilters);
return activeFilters; return activeFilters;
} }

View File

@@ -22,6 +22,7 @@
* the FLOSS exception, and it is also available here: * the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing" * http://www.alfresco.com/legal/licensing"
*/ */
package org.alfresco.repo.forms.processor; package org.alfresco.repo.forms.processor;
import java.util.List; import java.util.List;
@@ -34,23 +35,23 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
/** /**
* Abstract base class for all FormProcessor implementations that wish to use the * Abstract base class for all FormProcessor implementations that wish to use
* filter mechanism. * the filter mechanism.
* *
* @author Gavin Cornwell * @author Gavin Cornwell
*/ */
public abstract class FilteredFormProcessor extends AbstractFormProcessor public abstract class FilteredFormProcessor<ItemType, PersistType> extends AbstractFormProcessor
{ {
private static final Log logger = LogFactory.getLog(FilteredFormProcessor.class); private static final Log logger = LogFactory.getLog(FilteredFormProcessor.class);
protected FilterRegistry filterRegistry; protected FilterRegistry<ItemType, PersistType> filterRegistry;
/** /**
* Sets the filter registry * Sets the filter registry
* *
* @param filterRegistry The FilterRegistry instance * @param filterRegistry The FilterRegistry instance
*/ */
public void setFilterRegistry(FilterRegistry filterRegistry) public void setFilterRegistry(FilterRegistry<ItemType, PersistType> filterRegistry)
{ {
this.filterRegistry = filterRegistry; this.filterRegistry = filterRegistry;
@@ -59,13 +60,14 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
} }
/* /*
* @see org.alfresco.repo.forms.processor.FormProcessor#generate(org.alfresco.repo.forms.Item, java.util.List, java.util.List, java.util.Map) * @see
* org.alfresco.repo.forms.processor.FormProcessor#generate(org.alfresco
* .repo.forms.Item, java.util.List, java.util.List, java.util.Map)
*/ */
public Form generate(Item item, List<String> fields, List<String> forcedFields, public Form generate(Item item, List<String> fields, List<String> forcedFields, Map<String, Object> context)
Map<String, Object> context)
{ {
// get the typed object representing the item // get the typed object representing the item
Object typedItem = getTypedItem(item); ItemType typedItem = getTypedItem(item);
// create an empty Form // create an empty Form
Form form = new Form(item); Form form = new Form(item);
@@ -73,7 +75,7 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
// inform all regsitered filters the form is about to be generated // inform all regsitered filters the form is about to be generated
if (this.filterRegistry != null) if (this.filterRegistry != null)
{ {
for (Filter filter: this.filterRegistry.getFilters()) for (Filter filter : this.filterRegistry.getFilters())
{ {
filter.beforeGenerate(typedItem, fields, forcedFields, form, context); filter.beforeGenerate(typedItem, fields, forcedFields, form, context);
} }
@@ -85,7 +87,7 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
// inform all regsitered filters the form has been generated // inform all regsitered filters the form has been generated
if (this.filterRegistry != null) if (this.filterRegistry != null)
{ {
for (Filter filter: this.filterRegistry.getFilters()) for (Filter filter : this.filterRegistry.getFilters())
{ {
filter.afterGenerate(typedItem, fields, forcedFields, form, context); filter.afterGenerate(typedItem, fields, forcedFields, form, context);
} }
@@ -98,7 +100,8 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
* Persists the given form data for the given item, completed by calling * Persists the given form data for the given item, completed by calling
* each applicable registered handler * each applicable registered handler
* *
* @see org.alfresco.repo.forms.processor.FormProcessor#persist(org.alfresco.repo.forms.Item, org.alfresco.repo.forms.FormData) * @see org.alfresco.repo.forms.processor.FormProcessor#persist(org.alfresco.repo.forms.Item,
* org.alfresco.repo.forms.FormData)
* @param item The item to save the form for * @param item The item to save the form for
* @param data The object representing the form data * @param data The object representing the form data
* @return The object persisted * @return The object persisted
@@ -106,12 +109,12 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
public Object persist(Item item, FormData data) public Object persist(Item item, FormData data)
{ {
// get the typed object representing the item // get the typed object representing the item
Object typedItem = getTypedItem(item); ItemType typedItem = getTypedItem(item);
// inform all regsitered filters the form is about to be persisted // inform all regsitered filters the form is about to be persisted
if (this.filterRegistry != null) if (this.filterRegistry != null)
{ {
for (Filter filter: this.filterRegistry.getFilters()) for (Filter filter : this.filterRegistry.getFilters())
{ {
filter.beforePersist(typedItem, data); filter.beforePersist(typedItem, data);
} }
@@ -123,7 +126,7 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
// inform all regsitered filters the form has been persisted // inform all regsitered filters the form has been persisted
if (this.filterRegistry != null) if (this.filterRegistry != null)
{ {
for (Filter filter: this.filterRegistry.getFilters()) for (Filter filter : this.filterRegistry.getFilters())
{ {
filter.afterPersist(typedItem, data, persistedObject); filter.afterPersist(typedItem, data, persistedObject);
} }
@@ -132,17 +135,27 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
return persistedObject; return persistedObject;
} }
protected void setItemType(Form form, String type)
{
form.getItem().setType(type);
}
protected void setItemUrl(Form form, String url)
{
form.getItem().setUrl(url);
}
/** /**
* Returns a typed Object representing the given item. * Returns a typed Object representing the given item.
* <p> * <p>
* Subclasses that represent a form type will return a typed object * Subclasses that represent a form type will return a typed object that is
* that is then passed to each of it's handlers, the handlers can * then passed to each of it's handlers, the handlers can therefore safely
* therefore safely cast the Object to the type they expect. * cast the Object to the type they expect.
* *
* @param item The item to get a typed object for * @param item The item to get a typed object for
* @return The typed object * @return The typed object
*/ */
protected abstract Object getTypedItem(Item item); protected abstract ItemType getTypedItem(Item item);
/** /**
* Generates the form. * Generates the form.
@@ -151,11 +164,11 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
* @param fields Restricted list of fields to include * @param fields Restricted list of fields to include
* @param forcedFields List of fields to forcibly include * @param forcedFields List of fields to forcibly include
* @param form The form object being generated * @param form The form object being generated
* @param context Map representing optional context that * @param context Map representing optional context that can be used during
* can be used during retrieval of the form * retrieval of the form
*/ */
protected abstract void internalGenerate(Object item, List<String> fields, List<String> forcedFields, protected abstract void internalGenerate(ItemType item, List<String> fields, List<String> forcedFields, Form form,
Form form, Map<String, Object> context); Map<String, Object> context);
/** /**
* Persists the form data. * Persists the form data.
@@ -164,5 +177,6 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
* @param data The data to persist * @param data The data to persist
* @return The object that got created or modified * @return The object that got created or modified
*/ */
protected abstract Object internalPersist(Object item, FormData data); protected abstract PersistType internalPersist(ItemType item, FormData data);
} }

View File

@@ -1,3 +1,4 @@
package org.alfresco.repo.forms.processor.node; package org.alfresco.repo.forms.processor.node;
import java.io.Serializable; import java.io.Serializable;
@@ -56,56 +57,76 @@ import org.springframework.util.StringUtils;
* *
* @author Gavin Cornwell * @author Gavin Cornwell
*/ */
public abstract class ContentModelFormProcessor extends FilteredFormProcessor public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
FilteredFormProcessor<ItemType, PersistType>
{ {
/** Public constants */ /** Public constants */
public static final String ON = "on"; public static final String ON = "on";
public static final String PROP = "prop"; public static final String PROP = "prop";
public static final String ASSOC = "assoc"; public static final String ASSOC = "assoc";
public static final String DATA_KEY_SEPARATOR = "_"; public static final String DATA_KEY_SEPARATOR = "_";
public static final String PROP_DATA_PREFIX = PROP + DATA_KEY_SEPARATOR; public static final String PROP_DATA_PREFIX = PROP + DATA_KEY_SEPARATOR;
public static final String ASSOC_DATA_PREFIX = ASSOC + DATA_KEY_SEPARATOR; public static final String ASSOC_DATA_PREFIX = ASSOC + DATA_KEY_SEPARATOR;
public static final String ASSOC_DATA_ADDED_SUFFIX = DATA_KEY_SEPARATOR + "added"; public static final String ASSOC_DATA_ADDED_SUFFIX = DATA_KEY_SEPARATOR + "added";
public static final String ASSOC_DATA_REMOVED_SUFFIX = DATA_KEY_SEPARATOR + "removed"; public static final String ASSOC_DATA_REMOVED_SUFFIX = DATA_KEY_SEPARATOR + "removed";
public static final String TRANSIENT_MIMETYPE = "mimetype"; public static final String TRANSIENT_MIMETYPE = "mimetype";
public static final String TRANSIENT_SIZE = "size"; public static final String TRANSIENT_SIZE = "size";
public static final String TRANSIENT_ENCODING = "encoding"; public static final String TRANSIENT_ENCODING = "encoding";
/** Protected constants */ /** Protected constants */
protected static final String MSG_MIMETYPE_LABEL = "form_service.mimetype.label"; protected static final String MSG_MIMETYPE_LABEL = "form_service.mimetype.label";
protected static final String MSG_MIMETYPE_DESC = "form_service.mimetype.description"; protected static final String MSG_MIMETYPE_DESC = "form_service.mimetype.description";
protected static final String MSG_ENCODING_LABEL = "form_service.encoding.label"; protected static final String MSG_ENCODING_LABEL = "form_service.encoding.label";
protected static final String MSG_ENCODING_DESC = "form_service.encoding.description"; protected static final String MSG_ENCODING_DESC = "form_service.encoding.description";
protected static final String MSG_SIZE_LABEL = "form_service.size.label"; protected static final String MSG_SIZE_LABEL = "form_service.size.label";
protected static final String MSG_SIZE_DESC = "form_service.size.description"; protected static final String MSG_SIZE_DESC = "form_service.size.description";
/** Services */ /** Services */
protected NodeService nodeService; protected NodeService nodeService;
protected FileFolderService fileFolderService; protected FileFolderService fileFolderService;
protected DictionaryService dictionaryService; protected DictionaryService dictionaryService;
protected NamespaceService namespaceService; protected NamespaceService namespaceService;
/** /**
* A regular expression which can be used to match property names. * A regular expression which can be used to match property names. These
* These names will look like <code>"prop_cm_name"</code>. * names will look like <code>"prop_cm_name"</code>. The pattern can also be
* The pattern can also be used to extract the "cm" and the "name" parts. * used to extract the "cm" and the "name" parts.
*/ */
protected Pattern propertyNamePattern = Pattern.compile(PROP_DATA_PREFIX + "(.*){1}?_(.*){1}?"); protected Pattern propertyNamePattern = Pattern.compile(PROP_DATA_PREFIX + "(.*){1}?_(.*){1}?");
/** /**
* A regular expression which can be used to match tranisent property names. * A regular expression which can be used to match tranisent property names.
* These names will look like <code>"prop_name"</code>. * These names will look like <code>"prop_name"</code>. The pattern can also
* The pattern can also be used to extract the "name" part. * be used to extract the "name" part.
*/ */
protected Pattern transientPropertyPattern = Pattern.compile(PROP_DATA_PREFIX + "(.*){1}?"); protected Pattern transientPropertyPattern = Pattern.compile(PROP_DATA_PREFIX + "(.*){1}?");
/** /**
* A regular expression which can be used to match association names. * A regular expression which can be used to match association names. These
* These names will look like <code>"assoc_cm_references_added"</code>. * names will look like <code>"assoc_cm_references_added"</code>. The
* The pattern can also be used to extract the "cm", the "name" and the suffix parts. * pattern can also be used to extract the "cm", the "name" and the suffix
* parts.
*/ */
protected Pattern associationNamePattern = Pattern.compile(ASSOC_DATA_PREFIX + "(.*){1}?_(.*){1}?(_[a-zA-Z]+)"); protected Pattern associationNamePattern = Pattern.compile(ASSOC_DATA_PREFIX
+ "(.*){1}?_(.*){1}?(_[a-zA-Z]+)");
/** /**
* Sets the node service * Sets the node service
@@ -150,9 +171,9 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
/** /**
* Sets up a field definition for the given property. * Sets up a field definition for the given property.
* <p> * <p>
* NOTE: This method is static so that it can serve as a helper * NOTE: This method is static so that it can serve as a helper method for
* method for FormFilter implementations as adding additional * FormFilter implementations as adding additional property fields is likely
* property fields is likely to be a common extension. * to be a common extension.
* </p> * </p>
* *
* @param propDef The PropertyDefinition of the field to generate * @param propDef The PropertyDefinition of the field to generate
@@ -168,9 +189,9 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
/** /**
* Sets up a field definition for the given property. * Sets up a field definition for the given property.
* <p> * <p>
* NOTE: This method is static so that it can serve as a helper * NOTE: This method is static so that it can serve as a helper method for
* method for FormFilter implementations as adding additional * FormFilter implementations as adding additional property fields is likely
* property fields is likely to be a common extension. * to be a common extension.
* </p> * </p>
* *
* @param propDef The PropertyDefinition of the field to generate * @param propDef The PropertyDefinition of the field to generate
@@ -187,9 +208,9 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
/** /**
* Sets up a field definition for the given property. * Sets up a field definition for the given property.
* <p> * <p>
* NOTE: This method is static so that it can serve as a helper * NOTE: This method is static so that it can serve as a helper method for
* method for FormFilter implementations as adding additional * FormFilter implementations as adding additional property fields is likely
* property fields is likely to be a common extension. * to be a common extension.
* </p> * </p>
* *
* @param propDef The PropertyDefinition of the field to generate * @param propDef The PropertyDefinition of the field to generate
@@ -200,13 +221,12 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static void generatePropertyField(PropertyDefinition propDef, Form form, public static void generatePropertyField(PropertyDefinition propDef, Form form,
Serializable propValue, FieldGroup group, Serializable propValue, FieldGroup group, NamespaceService namespaceService)
NamespaceService namespaceService)
{ {
String propName = propDef.getName().toPrefixString(namespaceService); String propName = propDef.getName().toPrefixString(namespaceService);
String[] nameParts = QName.splitPrefixedQName(propName); String[] nameParts = QName.splitPrefixedQName(propName);
PropertyFieldDefinition fieldDef = new PropertyFieldDefinition( PropertyFieldDefinition fieldDef = new PropertyFieldDefinition(propName, propDef
propName, propDef.getDataType().getName().getLocalName()); .getDataType().getName().getLocalName());
String title = propDef.getTitle(); String title = propDef.getTitle();
if (title == null) if (title == null)
@@ -222,7 +242,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
fieldDef.setGroup(group); fieldDef.setGroup(group);
// any property from the system model (sys prefix) should be protected // 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 // 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())) if (NamespaceService.SYSTEM_MODEL_1_0_URI.equals(propDef.getName().getNamespaceURI()))
{ {
fieldDef.setProtectedField(true); fieldDef.setProtectedField(true);
@@ -251,14 +272,14 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
List<ConstraintDefinition> constraints = propDef.getConstraints(); List<ConstraintDefinition> constraints = propDef.getConstraints();
if (constraints != null && constraints.size() > 0) if (constraints != null && constraints.size() > 0)
{ {
List<FieldConstraint> fieldConstraints = List<FieldConstraint> fieldConstraints = new ArrayList<FieldConstraint>(constraints
new ArrayList<FieldConstraint>(constraints.size()); .size());
for (ConstraintDefinition constraintDef : constraints) for (ConstraintDefinition constraintDef : constraints)
{ {
Constraint constraint = constraintDef.getConstraint(); Constraint constraint = constraintDef.getConstraint();
FieldConstraint fieldConstraint = fieldDef.new FieldConstraint( FieldConstraint fieldConstraint = new FieldConstraint(constraint.getType(),
constraint.getType(), constraint.getParameters()); constraint.getParameters());
fieldConstraints.add(fieldConstraint); fieldConstraints.add(fieldConstraint);
} }
@@ -276,7 +297,7 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
// separated list, this will be changed to using // separated list, this will be changed to using
// a separate field for each value once we have full // a separate field for each value once we have full
// UI support in place. // UI support in place.
propValue = StringUtils.collectionToCommaDelimitedString((List)propValue); propValue = StringUtils.collectionToCommaDelimitedString((List) propValue);
} }
form.addData(dataKeyName, propValue); form.addData(dataKeyName, propValue);
@@ -286,17 +307,17 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
/** /**
* Sets up a field definition for the given association. * Sets up a field definition for the given association.
* <p> * <p>
* NOTE: This method is static so that it can serve as a helper * NOTE: This method is static so that it can serve as a helper method for
* method for FormFilter implementations as adding additional * FormFilter implementations as adding additional association fields is
* association fields is likely to be a common extension. * likely to be a common extension.
* </p> * </p>
* *
* @param assocDef The AssociationDefinition of the field to generate * @param assocDef The AssociationDefinition of the field to generate
* @param form The Form instance to populate * @param form The Form instance to populate
* @param namespaceService NamespaceService instance * @param namespaceService NamespaceService instance
*/ */
public static void generateAssociationField(AssociationDefinition assocDef, public static void generateAssociationField(AssociationDefinition assocDef, Form form,
Form form, NamespaceService namespaceService) NamespaceService namespaceService)
{ {
generateAssociationField(assocDef, form, null, null, namespaceService); generateAssociationField(assocDef, form, null, null, namespaceService);
} }
@@ -304,9 +325,9 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
/** /**
* Sets up a field definition for the given association. * Sets up a field definition for the given association.
* <p> * <p>
* NOTE: This method is static so that it can serve as a helper * NOTE: This method is static so that it can serve as a helper method for
* method for FormFilter implementations as adding additional * FormFilter implementations as adding additional association fields is
* association fields is likely to be a common extension. * likely to be a common extension.
* </p> * </p>
* *
* @param assocDef The AssociationDefinition of the field to generate * @param assocDef The AssociationDefinition of the field to generate
@@ -315,8 +336,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
* @param namespaceService NamespaceService instance * @param namespaceService NamespaceService instance
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static void generateAssociationField(AssociationDefinition assocDef, public static void generateAssociationField(AssociationDefinition assocDef, Form form,
Form form, List assocValues, NamespaceService namespaceService) List assocValues, NamespaceService namespaceService)
{ {
generateAssociationField(assocDef, form, assocValues, null, namespaceService); generateAssociationField(assocDef, form, assocValues, null, namespaceService);
} }
@@ -324,9 +345,9 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
/** /**
* Sets up a field definition for the given association. * Sets up a field definition for the given association.
* <p> * <p>
* NOTE: This method is static so that it can serve as a helper * NOTE: This method is static so that it can serve as a helper method for
* method for FormFilter implementations as adding additional * FormFilter implementations as adding additional association fields is
* association fields is likely to be a common extension. * likely to be a common extension.
* </p> * </p>
* *
* @param assocDef The AssociationDefinition of the field to generate * @param assocDef The AssociationDefinition of the field to generate
@@ -336,15 +357,13 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
* @param namespaceService NamespaceService instance * @param namespaceService NamespaceService instance
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static void generateAssociationField(AssociationDefinition assocDef, public static void generateAssociationField(AssociationDefinition assocDef, Form form,
Form form, List assocValues, FieldGroup group, List assocValues, FieldGroup group, NamespaceService namespaceService)
NamespaceService namespaceService)
{ {
String assocName = assocDef.getName().toPrefixString(namespaceService); String assocName = assocDef.getName().toPrefixString(namespaceService);
String[] nameParts = QName.splitPrefixedQName(assocName); String[] nameParts = QName.splitPrefixedQName(assocName);
AssociationFieldDefinition fieldDef = new AssociationFieldDefinition(assocName, AssociationFieldDefinition fieldDef = new AssociationFieldDefinition(assocName, assocDef
assocDef.getTargetClass().getName().toPrefixString( .getTargetClass().getName().toPrefixString(namespaceService), Direction.TARGET);
namespaceService), Direction.TARGET);
String title = assocDef.getTitle(); String title = assocDef.getTitle();
if (title == null) if (title == null)
{ {
@@ -367,17 +386,18 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (assocValues != null) if (assocValues != null)
{ {
// add the association value to the form // add the association value to the form
// determine the type of association values data and extract accordingly // determine the type of association values data and extract
// accordingly
List<String> values = new ArrayList<String>(4); List<String> values = new ArrayList<String>(4);
for (Object value : assocValues) for (Object value : assocValues)
{ {
if (value instanceof ChildAssociationRef) if (value instanceof ChildAssociationRef)
{ {
values.add(((ChildAssociationRef)value).getChildRef().toString()); values.add(((ChildAssociationRef) value).getChildRef().toString());
} }
else if (value instanceof AssociationRef) else if (value instanceof AssociationRef)
{ {
values.add(((AssociationRef)value).getTargetRef().toString()); values.add(((AssociationRef) value).getTargetRef().toString());
} }
else else
{ {
@@ -400,33 +420,33 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
/** /**
* Sets up the field definitions for all the requested fields. * Sets up the field definitions for all the requested fields.
* <p> * <p>
* A NodeRef or TypeDefinition can be provided, however, if a NodeRef * A NodeRef or TypeDefinition can be provided, however, if a NodeRef is
* is provided all type information will be derived from the NodeRef * provided all type information will be derived from the NodeRef and the
* and the TypeDefinition will be ignored. * TypeDefinition will be ignored.
* </p><p> * </p>
* If any of the requested fields are not present on the type and * <p>
* they appear in the forcedFields list an attempt to find a model * If any of the requested fields are not present on the type and they
* definition for those fields is made so they can be included. * appear in the forcedFields list an attempt to find a model definition for
* those fields is made so they can be included.
* </p> * </p>
* *
* @param nodeRef The NodeRef of the item being generated * @param nodeRef The NodeRef of the item being generated
* @param typeDef The TypeDefiniton of the item being generated * @param typeDef The TypeDefiniton of the item being generated
* @param fields Restricted list of fields to include * @param fields Restricted list of fields to include
* @param forcedFields List of field names that should be included * @param forcedFields List of field names that should be included even if
* even if the field is not currently present * the field is not currently present
* @param form The Form instance to populate * @param form The Form instance to populate
*/ */
protected void generateSelectedFields(NodeRef nodeRef, TypeDefinition typeDef, protected void generateSelectedFields(NodeRef nodeRef, TypeDefinition typeDef,
List<String> fields, List<String> forcedFields, Form form) List<String> fields, List<String> forcedFields, Form form)
{ {
// ensure a NodeRef or TypeDefinition is provided // ensure a NodeRef or TypeDefinition is provided
if (nodeRef == null && typeDef == null) if (nodeRef == null && typeDef == null) { throw new IllegalArgumentException(
{ "A NodeRef or TypeDefinition must be provided"); }
throw new IllegalArgumentException("A NodeRef or TypeDefinition must be provided");
}
if (getLogger().isDebugEnabled()) if (getLogger().isDebugEnabled())
getLogger().debug("Generating selected fields: " + fields + " and forcing: " + forcedFields); getLogger().debug(
"Generating selected fields: " + fields + " and forcing: " + forcedFields);
// get data dictionary definition for node if it is provided // get data dictionary definition for node if it is provided
QName type = null; QName type = null;
@@ -437,9 +457,11 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (nodeRef != null) if (nodeRef != null)
{ {
type = this.nodeService.getType(nodeRef); type = this.nodeService.getType(nodeRef);
typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService.getAspects(nodeRef)); typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService
.getAspects(nodeRef));
// NOTE: the anonymous type returns all property and association defs // NOTE: the anonymous type returns all property and association
// defs
// for all aspects applied as well as the type // for all aspects applied as well as the type
propDefs = typeDef.getProperties(); propDefs = typeDef.getProperties();
assocDefs = typeDef.getAssociations(); assocDefs = typeDef.getAssociations();
@@ -484,9 +506,12 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
} }
else else
{ {
// if there are 3 parts to the field name the first one represents // if there are 3 parts to the field name the first one
// whether the field is a property or association i.e. prop:prefix:local // represents
// or assoc:prefix:local, determine the prefix and ensure it's valid // 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])) if (PROP.equals(parts[0]))
{ {
tryAssociation = false; tryAssociation = false;
@@ -498,7 +523,11 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
else else
{ {
if (getLogger().isWarnEnabled()) if (getLogger().isWarnEnabled())
getLogger().warn("\"" + parts[0] + "\" is an invalid prefix for requesting a property or association"); getLogger()
.warn(
"\""
+ parts[0]
+ "\" is an invalid prefix for requesting a property or association");
continue; continue;
} }
@@ -518,7 +547,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (propDef != null) if (propDef != null)
{ {
// generate the property field // generate the property field
generatePropertyField(propDef, form, propValues.get(fullQName), this.namespaceService); generatePropertyField(propDef, form, propValues.get(fullQName),
this.namespaceService);
// no need to try and find an association // no need to try and find an association
tryAssociation = false; tryAssociation = false;
@@ -533,9 +563,11 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (assocDef != null) if (assocDef != null)
{ {
// generate the association field // generate the association field
generateAssociationField(assocDef, form, generateAssociationField(
(nodeRef != null) ? retrieveAssociationValues(nodeRef, assocDef) : null, assocDef,
this.namespaceService); form,
(nodeRef != null) ? retrieveAssociationValues(nodeRef, assocDef)
: null, this.namespaceService);
foundField = true; foundField = true;
} }
@@ -544,29 +576,35 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
// still not found the field, is it a force'd field? // still not found the field, is it a force'd field?
if (!foundField) if (!foundField)
{ {
if (forcedFields != null && forcedFields.size() > 0 && if (forcedFields != null && forcedFields.size() > 0
forcedFields.contains(fieldName)) && forcedFields.contains(fieldName))
{ {
generateForcedField(fieldName, form); generateForcedField(fieldName, form);
} }
else if (getLogger().isDebugEnabled()) else if (getLogger().isDebugEnabled())
{ {
getLogger().debug("Ignoring field \"" + fieldName + getLogger().debug(
"\" as it is not defined for the current " + ((nodeRef != null) ? "node" : "type") + "Ignoring field \"" + fieldName
" and it does not appear in the 'force' list"); + "\" as it is not defined for the current "
+ ((nodeRef != null) ? "node" : "type")
+ " and it does not appear in the 'force' list");
} }
} }
} }
else else
{ {
// see if the fieldName is a well known transient property // see if the fieldName is a well known transient property
if (TRANSIENT_MIMETYPE.equals(fieldName) || TRANSIENT_ENCODING.equals(fieldName) || if (TRANSIENT_MIMETYPE.equals(fieldName) || TRANSIENT_ENCODING.equals(fieldName)
TRANSIENT_SIZE.equals(fieldName)) || TRANSIENT_SIZE.equals(fieldName))
{ {
// if the node type is content or sublcass thereof generate appropriate field // if the node type is content or sublcass thereof generate
if (nodeRef != null && this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) // appropriate field
if (nodeRef != null
&& this.dictionaryService.isSubClass(type,
ContentModel.TYPE_CONTENT))
{ {
ContentData content = (ContentData)this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); ContentData content = (ContentData) this.nodeService.getProperty(nodeRef,
ContentModel.PROP_CONTENT);
if (content != null) if (content != null)
{ {
if (TRANSIENT_MIMETYPE.equals(fieldName)) if (TRANSIENT_MIMETYPE.equals(fieldName))
@@ -593,8 +631,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
} }
/** /**
* Generates a field definition for the given field that is being forced * Generates a field definition for the given field that is being forced to
* to show. * show.
* *
* @param fieldName Name of the field to force * @param fieldName Name of the field to force
* @param form The Form instance to populated * @param form The Form instance to populated
@@ -620,9 +658,12 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
} }
else else
{ {
// if there are 3 parts to the field name the first one represents // if there are 3 parts to the field name the first one
// whether the field is a property or association i.e. prop:prefix:local // represents
// or assoc:prefix:local, determine the prefix and ensure it's valid // 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])) if (PROP.equals(parts[0]))
{ {
tryAssociation = false; tryAssociation = false;
@@ -634,7 +675,11 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
else else
{ {
if (getLogger().isWarnEnabled()) if (getLogger().isWarnEnabled())
getLogger().warn("\"" + parts[0] + "\" is an invalid prefix for requesting a property or association"); getLogger()
.warn(
"\""
+ parts[0]
+ "\" is an invalid prefix for requesting a property or association");
return; return;
} }
@@ -676,8 +721,11 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (!foundField && getLogger().isDebugEnabled()) if (!foundField && getLogger().isDebugEnabled())
{ {
getLogger().debug("Ignoring field \"" + fieldName + getLogger()
"\" as it is not defined for the current node and can not be found in any model"); .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()) else if (getLogger().isWarnEnabled())
@@ -695,8 +743,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
protected void generateMimetypePropertyField(ContentData content, Form form) protected void generateMimetypePropertyField(ContentData content, Form form)
{ {
String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_MIMETYPE; String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_MIMETYPE;
PropertyFieldDefinition mimetypeField = new PropertyFieldDefinition( PropertyFieldDefinition mimetypeField = new PropertyFieldDefinition(TRANSIENT_MIMETYPE,
TRANSIENT_MIMETYPE, DataTypeDefinition.TEXT.getLocalName()); DataTypeDefinition.TEXT.getLocalName());
mimetypeField.setLabel(I18NUtil.getMessage(MSG_MIMETYPE_LABEL)); mimetypeField.setLabel(I18NUtil.getMessage(MSG_MIMETYPE_LABEL));
mimetypeField.setDescription(I18NUtil.getMessage(MSG_MIMETYPE_DESC)); mimetypeField.setDescription(I18NUtil.getMessage(MSG_MIMETYPE_DESC));
mimetypeField.setDataKeyName(dataKeyName); mimetypeField.setDataKeyName(dataKeyName);
@@ -717,8 +765,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
protected void generateEncodingPropertyField(ContentData content, Form form) protected void generateEncodingPropertyField(ContentData content, Form form)
{ {
String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_ENCODING; String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_ENCODING;
PropertyFieldDefinition encodingField = new PropertyFieldDefinition( PropertyFieldDefinition encodingField = new PropertyFieldDefinition(TRANSIENT_ENCODING,
TRANSIENT_ENCODING, DataTypeDefinition.TEXT.getLocalName()); DataTypeDefinition.TEXT.getLocalName());
encodingField.setLabel(I18NUtil.getMessage(MSG_ENCODING_LABEL)); encodingField.setLabel(I18NUtil.getMessage(MSG_ENCODING_LABEL));
encodingField.setDescription(I18NUtil.getMessage(MSG_ENCODING_DESC)); encodingField.setDescription(I18NUtil.getMessage(MSG_ENCODING_DESC));
encodingField.setDataKeyName(dataKeyName); encodingField.setDataKeyName(dataKeyName);
@@ -739,8 +787,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
protected void generateSizePropertyField(ContentData content, Form form) protected void generateSizePropertyField(ContentData content, Form form)
{ {
String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_SIZE; String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_SIZE;
PropertyFieldDefinition sizeField = new PropertyFieldDefinition( PropertyFieldDefinition sizeField = new PropertyFieldDefinition(TRANSIENT_SIZE,
TRANSIENT_SIZE, DataTypeDefinition.LONG.getLocalName()); DataTypeDefinition.LONG.getLocalName());
sizeField.setLabel(I18NUtil.getMessage(MSG_SIZE_LABEL)); sizeField.setLabel(I18NUtil.getMessage(MSG_SIZE_LABEL));
sizeField.setDescription(I18NUtil.getMessage(MSG_SIZE_DESC)); sizeField.setDescription(I18NUtil.getMessage(MSG_SIZE_DESC));
sizeField.setDataKeyName(dataKeyName); sizeField.setDataKeyName(dataKeyName);
@@ -754,7 +802,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
} }
/** /**
* Retrieves the values of the given association definition on the given node. * Retrieves the values of the given association definition on the given
* node.
* *
* @param nodeRef The node to get the association values for * @param nodeRef The node to get the association values for
* @param assocDef The association definition to look for values for * @param assocDef The association definition to look for values for
@@ -790,13 +839,14 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
{ {
// get the property definitions for the type of node being persisted // get the property definitions for the type of node being persisted
QName type = this.nodeService.getType(nodeRef); QName type = this.nodeService.getType(nodeRef);
TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService
this.nodeService.getAspects(nodeRef)); .getAspects(nodeRef));
Map<QName, AssociationDefinition> assocDefs = typeDef.getAssociations(); Map<QName, AssociationDefinition> assocDefs = typeDef.getAssociations();
Map<QName, ChildAssociationDefinition> childAssocDefs = typeDef.getChildAssociations(); Map<QName, ChildAssociationDefinition> childAssocDefs = typeDef.getChildAssociations();
Map<QName, PropertyDefinition> propDefs = typeDef.getProperties(); Map<QName, PropertyDefinition> propDefs = typeDef.getProperties();
Map<QName, Serializable> propsToPersist = new HashMap<QName, Serializable>(data.getNumberOfFields()); Map<QName, Serializable> propsToPersist = new HashMap<QName, Serializable>(data
.getNumberOfFields());
List<AbstractAssocCommand> assocsToPersist = new ArrayList<AbstractAssocCommand>(); List<AbstractAssocCommand> assocsToPersist = new ArrayList<AbstractAssocCommand>();
for (FieldData fieldData : data) for (FieldData fieldData : data)
@@ -812,7 +862,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
} }
else if (fieldName.startsWith(ASSOC_DATA_PREFIX)) else if (fieldName.startsWith(ASSOC_DATA_PREFIX))
{ {
processAssociationPersist(nodeRef, assocDefs, childAssocDefs, fieldData, assocsToPersist); processAssociationPersist(nodeRef, assocDefs, childAssocDefs, fieldData,
assocsToPersist);
} }
else if (getLogger().isWarnEnabled()) else if (getLogger().isWarnEnabled())
{ {
@@ -821,15 +872,19 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
} }
} }
// persist the properties using addProperties as this changes the repo values of // persist the properties using addProperties as this changes the repo
// those properties included in the Map, but leaves any other property values unchanged, // values of
// whereas setProperties causes the deletion of properties that are not included in the Map. // those properties included in the Map, but leaves any other property
// values unchanged,
// whereas setProperties causes the deletion of properties that are not
// included in the Map.
this.nodeService.addProperties(nodeRef, propsToPersist); this.nodeService.addProperties(nodeRef, propsToPersist);
for (AbstractAssocCommand cmd : assocsToPersist) for (AbstractAssocCommand cmd : assocsToPersist)
{ {
//TODO If there is an attempt to add and remove the same assoc in one request, // TODO If there is an attempt to add and remove the same assoc in
// we could drop each request and do nothing. // one request,
// we could drop each request and do nothing.
cmd.updateAssociations(nodeService); cmd.updateAssociations(nodeService);
} }
} }
@@ -859,7 +914,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
// ensure that the property being persisted is defined in the model // ensure that the property being persisted is defined in the model
PropertyDefinition propDef = propDefs.get(fullQName); PropertyDefinition propDef = propDefs.get(fullQName);
// if the property is not defined on the node, check for the property in all models // if the property is not defined on the node, check for the
// property in all models
if (propDef == null) if (propDef == null)
{ {
propDef = this.dictionaryService.getProperty(fullQName); propDef = this.dictionaryService.getProperty(fullQName);
@@ -868,7 +924,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
// if we have a property definition attempt the persist // if we have a property definition attempt the persist
if (propDef != null) if (propDef != null)
{ {
// look for properties that have well known handling requirements // look for properties that have well known handling
// requirements
if (fullQName.equals(ContentModel.PROP_NAME)) if (fullQName.equals(ContentModel.PROP_NAME))
{ {
processNamePropertyPersist(nodeRef, fieldData); processNamePropertyPersist(nodeRef, fieldData);
@@ -880,11 +937,12 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
// before persisting check data type of property // before persisting check data type of property
if (propDef.isMultiValued()) if (propDef.isMultiValued())
{ {
// depending on client the value could be a comma separated // depending on client the value could be a comma
// separated
// string, a List object or a JSONArray object // string, a List object or a JSONArray object
if (value instanceof String) if (value instanceof String)
{ {
if (((String)value).length() == 0) if (((String) value).length() == 0)
{ {
// empty string for multi-valued properties // empty string for multi-valued properties
// should be stored as null // should be stored as null
@@ -892,8 +950,9 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
} }
else else
{ {
// if value is a String convert to List of String // if value is a String convert to List of
StringTokenizer tokenizer = new StringTokenizer((String)value, ","); // String
StringTokenizer tokenizer = new StringTokenizer((String) value, ",");
List<String> list = new ArrayList<String>(8); List<String> list = new ArrayList<String>(8);
while (tokenizer.hasMoreTokens()) while (tokenizer.hasMoreTokens())
{ {
@@ -907,7 +966,7 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
else if (value instanceof JSONArray) else if (value instanceof JSONArray)
{ {
// if value is a JSONArray convert to List of Object // if value is a JSONArray convert to List of Object
JSONArray jsonArr = (JSONArray)value; JSONArray jsonArr = (JSONArray) value;
int arrLength = jsonArr.length(); int arrLength = jsonArr.length();
List<Object> list = new ArrayList<Object>(arrLength); List<Object> list = new ArrayList<Object>(arrLength);
try try
@@ -928,7 +987,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
} }
else if (propDef.getDataType().getName().equals(DataTypeDefinition.BOOLEAN)) else if (propDef.getDataType().getName().equals(DataTypeDefinition.BOOLEAN))
{ {
// check for browser representation of true, that being "on" // check for browser representation of true, that being
// "on"
if (value instanceof String && ON.equals(value)) if (value instanceof String && ON.equals(value))
{ {
value = Boolean.TRUE; value = Boolean.TRUE;
@@ -936,26 +996,30 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
} }
else if (propDef.getDataType().getName().equals(DataTypeDefinition.LOCALE)) else if (propDef.getDataType().getName().equals(DataTypeDefinition.LOCALE))
{ {
value = I18NUtil.parseLocale((String)value); value = I18NUtil.parseLocale((String) value);
} }
else if ((value instanceof String) && ((String)value).length() == 0) else if ((value instanceof String) && ((String) value).length() == 0)
{ {
// make sure empty strings stay as empty strings, everything else // make sure empty strings stay as empty strings,
// everything else
// should be represented as null // should be represented as null
if (!propDef.getDataType().getName().equals(DataTypeDefinition.TEXT) && if (!propDef.getDataType().getName().equals(DataTypeDefinition.TEXT)
!propDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT)) && !propDef.getDataType().getName().equals(
DataTypeDefinition.MLTEXT))
{ {
value = null; value = null;
} }
} }
// add the property to the map // add the property to the map
propsToPersist.put(fullQName, (Serializable)value); propsToPersist.put(fullQName, (Serializable) value);
} }
} }
else if (getLogger().isWarnEnabled()) else if (getLogger().isWarnEnabled())
{ {
getLogger().warn("Ignoring field '" + fieldData.getName() + "' as a property definition can not be found"); getLogger().warn(
"Ignoring field '" + fieldData.getName()
+ "' as a property definition can not be found");
} }
} }
else else
@@ -977,7 +1041,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
} }
else if (fieldName.equals(TRANSIENT_SIZE)) else if (fieldName.equals(TRANSIENT_SIZE))
{ {
// the size property is well known but should never be persisted // the size property is well known but should never be
// persisted
// as it is calculated so this is intentionally ignored // as it is calculated so this is intentionally ignored
} }
else if (getLogger().isWarnEnabled()) else if (getLogger().isWarnEnabled())
@@ -999,9 +1064,10 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
* @param fieldData Data to persist for the associations * @param fieldData Data to persist for the associations
* @param assocCommands List of associations to be persisted * @param assocCommands List of associations to be persisted
*/ */
protected void processAssociationPersist(NodeRef nodeRef, Map<QName, AssociationDefinition> assocDefs, protected void processAssociationPersist(NodeRef nodeRef,
Map<QName, ChildAssociationDefinition> childAssocDefs, Map<QName, AssociationDefinition> assocDefs,
FieldData fieldData, List<AbstractAssocCommand> assocCommands) Map<QName, ChildAssociationDefinition> childAssocDefs, FieldData fieldData,
List<AbstractAssocCommand> assocCommands)
{ {
if (getLogger().isDebugEnabled()) if (getLogger().isDebugEnabled())
getLogger().debug("Processing field " + fieldData + " for association persistence"); getLogger().debug("Processing field " + fieldData + " for association persistence");
@@ -1016,29 +1082,38 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
QName fullQName = QName.createQName(qNamePrefix, localName, namespaceService); QName fullQName = QName.createQName(qNamePrefix, localName, namespaceService);
// ensure that the association being persisted is defined in the model // ensure that the association being persisted is defined in the
// model
AssociationDefinition assocDef = assocDefs.get(fullQName); AssociationDefinition assocDef = assocDefs.get(fullQName);
// TODO: if the association is not defined on the node, check for the association // TODO: if the association is not defined on the node, check for
// in all models, however, the source of an association can be critical so we // the association
// can't just look up the association in the model regardless. We need to // in all models, however, the source of an association can be
// either check the source class of the node and the assoc def match or we // critical so we
// check that the association was defined as part of an aspect (where by it's // can't just look up the association in the model regardless. We
// nature can have any source type) // need to
// either check the source class of the node and the assoc def match
// or we
// check that the association was defined as part of an aspect
// (where by it's
// nature can have any source type)
if (assocDef == null) if (assocDef == null)
{ {
if (getLogger().isWarnEnabled()) if (getLogger().isWarnEnabled())
{ {
getLogger().warn("Definition for association " + fullQName + " not recognised and not persisted."); getLogger().warn(
"Definition for association " + fullQName
+ " not recognised and not persisted.");
} }
return; return;
} }
String value = (String)fieldData.getValue(); String value = (String) fieldData.getValue();
String[] nodeRefs = value.split(","); String[] nodeRefs = value.split(",");
// Each element in this array will be a new target node in association // Each element in this array will be a new target node in
// association
// with the current node. // with the current node.
for (String nextTargetNode : nodeRefs) for (String nextTargetNode : nodeRefs)
{ {
@@ -1050,26 +1125,26 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
{ {
if (assocDef.isChild()) if (assocDef.isChild())
{ {
assocCommands.add(new AddChildAssocCommand(nodeRef, new NodeRef(nextTargetNode), assocCommands.add(new AddChildAssocCommand(nodeRef, new NodeRef(
fullQName)); nextTargetNode), fullQName));
} }
else else
{ {
assocCommands.add(new AddAssocCommand(nodeRef, new NodeRef(nextTargetNode), assocCommands.add(new AddAssocCommand(nodeRef, new NodeRef(
fullQName)); nextTargetNode), fullQName));
} }
} }
else if (assocSuffix.equals(ASSOC_DATA_REMOVED_SUFFIX)) else if (assocSuffix.equals(ASSOC_DATA_REMOVED_SUFFIX))
{ {
if (assocDef.isChild()) if (assocDef.isChild())
{ {
assocCommands.add(new RemoveChildAssocCommand(nodeRef, new NodeRef(nextTargetNode), assocCommands.add(new RemoveChildAssocCommand(nodeRef, new NodeRef(
fullQName)); nextTargetNode), fullQName));
} }
else else
{ {
assocCommands.add(new RemoveAssocCommand(nodeRef, new NodeRef(nextTargetNode), assocCommands.add(new RemoveAssocCommand(nodeRef, new NodeRef(
fullQName)); nextTargetNode), fullQName));
} }
} }
else else
@@ -1077,13 +1152,11 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (getLogger().isWarnEnabled()) if (getLogger().isWarnEnabled())
{ {
StringBuilder msg = new StringBuilder(); StringBuilder msg = new StringBuilder();
msg.append("fieldName ") msg.append("fieldName ").append(fieldName).append(
.append(fieldName) " does not have one of the expected suffixes [")
.append(" does not have one of the expected suffixes [") .append(ASSOC_DATA_ADDED_SUFFIX).append(", ").append(
.append(ASSOC_DATA_ADDED_SUFFIX) ASSOC_DATA_REMOVED_SUFFIX).append(
.append(", ") "] and has been ignored.");
.append(ASSOC_DATA_REMOVED_SUFFIX)
.append("] and has been ignored.");
getLogger().warn(msg.toString()); getLogger().warn(msg.toString());
} }
} }
@@ -1093,9 +1166,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (getLogger().isWarnEnabled()) if (getLogger().isWarnEnabled())
{ {
StringBuilder msg = new StringBuilder(); StringBuilder msg = new StringBuilder();
msg.append("targetNode ") msg.append("targetNode ").append(nextTargetNode).append(
.append(nextTargetNode) " is not a valid NodeRef and has been ignored.");
.append(" is not a valid NodeRef and has been ignored.");
getLogger().warn(msg.toString()); getLogger().warn(msg.toString());
} }
} }
@@ -1115,8 +1187,9 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
try try
{ {
// if the name property changes the rename method of the file folder // if the name property changes the rename method of the file folder
// service should be called rather than updating the property directly // service should be called rather than updating the property
this.fileFolderService.rename(nodeRef, (String)fieldData.getValue()); // directly
this.fileFolderService.rename(nodeRef, (String) fieldData.getValue());
} }
catch (FileExistsException fee) catch (FileExistsException fee)
{ {
@@ -1138,17 +1211,18 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
protected void processMimetypePropertyPersist(NodeRef nodeRef, FieldData fieldData, protected void processMimetypePropertyPersist(NodeRef nodeRef, FieldData fieldData,
Map<QName, Serializable> propsToPersist) Map<QName, Serializable> propsToPersist)
{ {
ContentData contentData = (ContentData)propsToPersist.get(ContentModel.PROP_CONTENT); ContentData contentData = (ContentData) propsToPersist.get(ContentModel.PROP_CONTENT);
if (contentData == null) if (contentData == null)
{ {
// content data has not been persisted yet so get it from the node // content data has not been persisted yet so get it from the node
contentData = (ContentData)this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); contentData = (ContentData) this.nodeService.getProperty(nodeRef,
ContentModel.PROP_CONTENT);
} }
if (contentData != null) if (contentData != null)
{ {
// update content data if we found the property // update content data if we found the property
contentData = ContentData.setMimetype(contentData, (String)fieldData.getValue()); contentData = ContentData.setMimetype(contentData, (String) fieldData.getValue());
propsToPersist.put(ContentModel.PROP_CONTENT, contentData); propsToPersist.put(ContentModel.PROP_CONTENT, contentData);
} }
} }
@@ -1163,17 +1237,18 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
protected void processEncodingPropertyPersist(NodeRef nodeRef, FieldData fieldData, protected void processEncodingPropertyPersist(NodeRef nodeRef, FieldData fieldData,
Map<QName, Serializable> propsToPersist) Map<QName, Serializable> propsToPersist)
{ {
ContentData contentData = (ContentData)propsToPersist.get(ContentModel.PROP_CONTENT); ContentData contentData = (ContentData) propsToPersist.get(ContentModel.PROP_CONTENT);
if (contentData == null) if (contentData == null)
{ {
// content data has not been persisted yet so get it from the node // content data has not been persisted yet so get it from the node
contentData = (ContentData)this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); contentData = (ContentData) this.nodeService.getProperty(nodeRef,
ContentModel.PROP_CONTENT);
} }
if (contentData != null) if (contentData != null)
{ {
// update content data if we found the property // update content data if we found the property
contentData = ContentData.setEncoding(contentData, (String)fieldData.getValue()); contentData = ContentData.setEncoding(contentData, (String) fieldData.getValue());
propsToPersist.put(ContentModel.PROP_CONTENT, contentData); propsToPersist.put(ContentModel.PROP_CONTENT, contentData);
} }
} }
@@ -1187,11 +1262,12 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
abstract class AbstractAssocCommand abstract class AbstractAssocCommand
{ {
protected final NodeRef sourceNodeRef; protected final NodeRef sourceNodeRef;
protected final NodeRef targetNodeRef; protected final NodeRef targetNodeRef;
protected final QName assocQName; protected final QName assocQName;
public AbstractAssocCommand(NodeRef sourceNodeRef, NodeRef targetNodeRef, public AbstractAssocCommand(NodeRef sourceNodeRef, NodeRef targetNodeRef, QName assocQName)
QName assocQName)
{ {
this.sourceNodeRef = sourceNodeRef; this.sourceNodeRef = sourceNodeRef;
this.targetNodeRef = targetNodeRef; this.targetNodeRef = targetNodeRef;
@@ -1201,6 +1277,7 @@ abstract class AbstractAssocCommand
/** /**
* This method should use the specified nodeService reference to effect the * This method should use the specified nodeService reference to effect the
* update to the supplied associations. * update to the supplied associations.
*
* @param nodeService * @param nodeService
*/ */
protected abstract void updateAssociations(NodeService nodeService); protected abstract void updateAssociations(NodeService nodeService);
@@ -1214,8 +1291,8 @@ abstract class AbstractAssocCommand
class AddAssocCommand extends AbstractAssocCommand class AddAssocCommand extends AbstractAssocCommand
{ {
private static final Log logger = LogFactory.getLog(AddAssocCommand.class); private static final Log logger = LogFactory.getLog(AddAssocCommand.class);
public AddAssocCommand(NodeRef sourceNodeRef, NodeRef targetNodeRef,
QName assocQName) public AddAssocCommand(NodeRef sourceNodeRef, NodeRef targetNodeRef, QName assocQName)
{ {
super(sourceNodeRef, targetNodeRef, assocQName); super(sourceNodeRef, targetNodeRef, assocQName);
} }
@@ -1223,7 +1300,8 @@ class AddAssocCommand extends AbstractAssocCommand
@Override @Override
protected void updateAssociations(NodeService nodeService) protected void updateAssociations(NodeService nodeService)
{ {
List<AssociationRef> existingAssocs = nodeService.getTargetAssocs(sourceNodeRef, assocQName); List<AssociationRef> existingAssocs = nodeService
.getTargetAssocs(sourceNodeRef, assocQName);
for (AssociationRef assoc : existingAssocs) for (AssociationRef assoc : existingAssocs)
{ {
if (assoc.getTargetRef().equals(targetNodeRef)) if (assoc.getTargetRef().equals(targetNodeRef))
@@ -1247,8 +1325,8 @@ class AddAssocCommand extends AbstractAssocCommand
class RemoveAssocCommand extends AbstractAssocCommand class RemoveAssocCommand extends AbstractAssocCommand
{ {
private static final Log logger = LogFactory.getLog(RemoveAssocCommand.class); private static final Log logger = LogFactory.getLog(RemoveAssocCommand.class);
public RemoveAssocCommand(NodeRef sourceNodeRef, NodeRef targetNodeRef,
QName assocQName) public RemoveAssocCommand(NodeRef sourceNodeRef, NodeRef targetNodeRef, QName assocQName)
{ {
super(sourceNodeRef, targetNodeRef, assocQName); super(sourceNodeRef, targetNodeRef, assocQName);
} }
@@ -1256,7 +1334,8 @@ class RemoveAssocCommand extends AbstractAssocCommand
@Override @Override
protected void updateAssociations(NodeService nodeService) protected void updateAssociations(NodeService nodeService)
{ {
List<AssociationRef> existingAssocs = nodeService.getTargetAssocs(sourceNodeRef, assocQName); List<AssociationRef> existingAssocs = nodeService
.getTargetAssocs(sourceNodeRef, assocQName);
boolean assocDoesNotExist = true; boolean assocDoesNotExist = true;
for (AssociationRef assoc : existingAssocs) for (AssociationRef assoc : existingAssocs)
{ {
@@ -1271,11 +1350,8 @@ class RemoveAssocCommand extends AbstractAssocCommand
if (logger.isWarnEnabled()) if (logger.isWarnEnabled())
{ {
StringBuilder msg = new StringBuilder(); StringBuilder msg = new StringBuilder();
msg.append("Attempt to remove non-existent association prevented. ") msg.append("Attempt to remove non-existent association prevented. ").append(
.append(sourceNodeRef) sourceNodeRef).append("|").append(targetNodeRef).append(assocQName);
.append("|")
.append(targetNodeRef)
.append(assocQName);
logger.warn(msg.toString()); logger.warn(msg.toString());
} }
return; return;
@@ -1286,15 +1362,16 @@ class RemoveAssocCommand extends AbstractAssocCommand
} }
/** /**
* A class representing a request to add a new child association between two nodes. * A class representing a request to add a new child association between two
* nodes.
* *
* @author Neil McErlean * @author Neil McErlean
*/ */
class AddChildAssocCommand extends AbstractAssocCommand class AddChildAssocCommand extends AbstractAssocCommand
{ {
private static final Log logger = LogFactory.getLog(AddChildAssocCommand.class); private static final Log logger = LogFactory.getLog(AddChildAssocCommand.class);
public AddChildAssocCommand(NodeRef sourceNodeRef, NodeRef targetNodeRef,
QName assocQName) public AddChildAssocCommand(NodeRef sourceNodeRef, NodeRef targetNodeRef, QName assocQName)
{ {
super(sourceNodeRef, targetNodeRef, assocQName); super(sourceNodeRef, targetNodeRef, assocQName);
} }
@@ -1315,22 +1392,24 @@ class AddChildAssocCommand extends AbstractAssocCommand
return; return;
} }
} }
// We are following the behaviour of the JSF client here in using the same // We are following the behaviour of the JSF client here in using the
// same
// QName value for the 3rd and 4th parameters in the below call. // QName value for the 3rd and 4th parameters in the below call.
nodeService.addChild(sourceNodeRef, targetNodeRef, assocQName, assocQName); nodeService.addChild(sourceNodeRef, targetNodeRef, assocQName, assocQName);
} }
} }
/** /**
* A class representing a request to remove a child association between two nodes. * A class representing a request to remove a child association between two
* nodes.
* *
* @author Neil McErlean * @author Neil McErlean
*/ */
class RemoveChildAssocCommand extends AbstractAssocCommand class RemoveChildAssocCommand extends AbstractAssocCommand
{ {
private static final Log logger = LogFactory.getLog(RemoveChildAssocCommand.class); private static final Log logger = LogFactory.getLog(RemoveChildAssocCommand.class);
public RemoveChildAssocCommand(NodeRef sourceNodeRef, NodeRef targetNodeRef,
QName assocQName) public RemoveChildAssocCommand(NodeRef sourceNodeRef, NodeRef targetNodeRef, QName assocQName)
{ {
super(sourceNodeRef, targetNodeRef, assocQName); super(sourceNodeRef, targetNodeRef, assocQName);
} }
@@ -1353,11 +1432,8 @@ class RemoveChildAssocCommand extends AbstractAssocCommand
if (logger.isWarnEnabled()) if (logger.isWarnEnabled())
{ {
StringBuilder msg = new StringBuilder(); StringBuilder msg = new StringBuilder();
msg.append("Attempt to remove non-existent child association prevented. ") msg.append("Attempt to remove non-existent child association prevented. ").append(
.append(sourceNodeRef) sourceNodeRef).append("|").append(targetNodeRef).append(assocQName);
.append("|")
.append(targetNodeRef)
.append(assocQName);
logger.warn(msg.toString()); logger.warn(msg.toString());
} }
return; return;

View File

@@ -0,0 +1,56 @@
/*
* 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;
/**
* @author Nick Smith
*/
public interface FormFieldConstants
{
/** Public constants */
public static final String ON = "on";
public static final String PROP = "prop";
public static final String ASSOC = "assoc";
public static final String DATA_KEY_SEPARATOR = "_";
public static final String PROP_DATA_PREFIX = PROP + DATA_KEY_SEPARATOR;
public static final String ASSOC_DATA_PREFIX = ASSOC + DATA_KEY_SEPARATOR;
public static final String ASSOC_DATA_ADDED_SUFFIX = DATA_KEY_SEPARATOR + "added";
public static final String ASSOC_DATA_REMOVED_SUFFIX = DATA_KEY_SEPARATOR + "removed";
public static final String TRANSIENT_MIMETYPE = "mimetype";
public static final String TRANSIENT_SIZE = "size";
public static final String TRANSIENT_ENCODING = "encoding";
}

View File

@@ -22,6 +22,7 @@
* the FLOSS exception, and it is also available here: * the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing" * http://www.alfresco.com/legal/licensing"
*/ */
package org.alfresco.repo.forms.processor.node; package org.alfresco.repo.forms.processor.node;
import java.io.Serializable; import java.io.Serializable;
@@ -44,18 +45,20 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
/** /**
* FormProcessor implementation that can generate and persist Form objects * FormProcessor implementation that can generate and persist Form objects for
* for repository nodes. * repository nodes.
* *
* @author Gavin Cornwell * @author Gavin Cornwell
*/ */
public class NodeFormProcessor extends ContentModelFormProcessor public class NodeFormProcessor extends ContentModelFormProcessor<NodeRef, NodeRef>
{ {
/** Logger */ /** Logger */
private static Log logger = LogFactory.getLog(NodeFormProcessor.class); private static Log logger = LogFactory.getLog(NodeFormProcessor.class);
/* /*
* @see org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getLogger() * @see
* org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getLogger
* ()
*/ */
@Override @Override
protected Log getLogger() protected Log getLogger()
@@ -64,10 +67,12 @@ public class NodeFormProcessor extends ContentModelFormProcessor
} }
/* /*
* @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getTypedItem(org.alfresco.repo.forms.Item) * @see
* org.alfresco.repo.forms.processor.FilteredFormProcessor#getTypedItem(
* org.alfresco.repo.forms.Item)
*/ */
@Override @Override
protected Object getTypedItem(Item item) protected NodeRef getTypedItem(Item item)
{ {
// create NodeRef representation, the id could already be in a valid // create NodeRef representation, the id could already be in a valid
// NodeRef format or it may be in a URL friendly format // NodeRef format or it may be in a URL friendly format
@@ -97,17 +102,14 @@ public class NodeFormProcessor extends ContentModelFormProcessor
} }
// check we have a valid node ref // check we have a valid node ref
if (nodeRef == null) if (nodeRef == null) { throw new FormNotFoundException(item, new IllegalArgumentException(
{ item.getId())); }
throw new FormNotFoundException(item,
new IllegalArgumentException(item.getId()));
}
// check the node itself exists // check the node itself exists
if (this.nodeService.exists(nodeRef) == false) if (this.nodeService.exists(nodeRef) == false)
{ {
throw new FormNotFoundException(item, throw new FormNotFoundException(item, new InvalidNodeRefException(
new InvalidNodeRefException("Node does not exist: " + nodeRef, nodeRef)); "Node does not exist: " + nodeRef, nodeRef));
} }
else else
{ {
@@ -117,23 +119,21 @@ public class NodeFormProcessor extends ContentModelFormProcessor
} }
/* /*
* @see org.alfresco.repo.forms.processor.FilteredFormProcessor#internalGenerate(java.lang.Object, java.util.List, java.util.List, org.alfresco.repo.forms.Form, java.util.Map) * @see
* org.alfresco.repo.forms.processor.FilteredFormProcessor#internalGenerate
* (java.lang.Object, java.util.List, java.util.List,
* org.alfresco.repo.forms.Form, java.util.Map)
*/ */
@Override @Override
protected void internalGenerate(Object item, List<String> fields, List<String> forcedFields, protected void internalGenerate(NodeRef item, List<String> fields, List<String> forcedFields,
Form form, Map<String, Object> context) Form form, Map<String, Object> context)
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled()) logger.debug("Generating form for: " + item);
logger.debug("Generating form for: " + item);
// cast to the expected NodeRef representation
NodeRef nodeRef = (NodeRef)item;
// generate the form for the node // generate the form for the node
generateNode(nodeRef, fields, forcedFields, form); generateNode(item, fields, forcedFields, form);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled()) logger.debug("Generated form: " + form);
logger.debug("Generated form: " + form);
} }
/** /**
@@ -144,7 +144,8 @@ public class NodeFormProcessor extends ContentModelFormProcessor
* @param forcedFields List of fields to forcibly include * @param forcedFields List of fields to forcibly include
* @param form The Form instance to populate * @param form The Form instance to populate
*/ */
protected void generateNode(NodeRef nodeRef, List<String> fields, List<String> forcedFields, Form form) protected void generateNode(NodeRef nodeRef, List<String> fields, List<String> forcedFields,
Form form)
{ {
// set the type and URL of the item // set the type and URL of the item
QName type = this.nodeService.getType(nodeRef); QName type = this.nodeService.getType(nodeRef);
@@ -178,8 +179,8 @@ public class NodeFormProcessor extends ContentModelFormProcessor
{ {
// get data dictionary definition for node // get data dictionary definition for node
QName type = this.nodeService.getType(nodeRef); QName type = this.nodeService.getType(nodeRef);
TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService
this.nodeService.getAspects(nodeRef)); .getAspects(nodeRef));
// iterate round the property definitions for the node and create // iterate round the property definitions for the node and create
// the equivalent field definition and setup the data for the property // the equivalent field definition and setup the data for the property
@@ -202,15 +203,14 @@ public class NodeFormProcessor extends ContentModelFormProcessor
{ {
// get data dictionary definition for the node // get data dictionary definition for the node
QName type = this.nodeService.getType(nodeRef); QName type = this.nodeService.getType(nodeRef);
TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService
this.nodeService.getAspects(nodeRef)); .getAspects(nodeRef));
// iterate round the association defintions and setup field definition // iterate round the association defintions and setup field definition
Map<QName, AssociationDefinition> assocDefs = typeDef.getAssociations(); Map<QName, AssociationDefinition> assocDefs = typeDef.getAssociations();
for (AssociationDefinition assocDef : assocDefs.values()) for (AssociationDefinition assocDef : assocDefs.values())
{ {
generateAssociationField(assocDef, form, generateAssociationField(assocDef, form, retrieveAssociationValues(nodeRef, assocDef),
retrieveAssociationValues(nodeRef, assocDef),
this.namespaceService); this.namespaceService);
} }
} }
@@ -224,11 +224,13 @@ public class NodeFormProcessor extends ContentModelFormProcessor
*/ */
protected void generateTransientFields(NodeRef nodeRef, Form form) protected void generateTransientFields(NodeRef nodeRef, Form form)
{ {
// if the node is content add the 'mimetype', 'size' and 'encoding' fields. // if the node is content add the 'mimetype', 'size' and 'encoding'
// fields.
QName type = this.nodeService.getType(nodeRef); QName type = this.nodeService.getType(nodeRef);
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT))
{ {
ContentData content = (ContentData)this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); ContentData content = (ContentData) this.nodeService.getProperty(nodeRef,
ContentModel.PROP_CONTENT);
if (content != null) if (content != null)
{ {
// setup mimetype field // setup mimetype field
@@ -244,21 +246,18 @@ public class NodeFormProcessor extends ContentModelFormProcessor
} }
/* /*
* @see org.alfresco.repo.forms.processor.FilteredFormProcessor#internalPersist(java.lang.Object, org.alfresco.repo.forms.FormData) * @see
* org.alfresco.repo.forms.processor.FilteredFormProcessor#internalPersist
* (java.lang.Object, org.alfresco.repo.forms.FormData)
*/ */
@Override @Override
protected Object internalPersist(Object item, FormData data) protected NodeRef internalPersist(NodeRef item, FormData data)
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled()) logger.debug("Persisting form for: " + item);
logger.debug("Persisting form for: " + item);
// cast to the expected NodeRef representation
NodeRef nodeRef = (NodeRef)item;
// persist the node // persist the node
persistNode(nodeRef, data); persistNode(item, data);
return item; return item;
} }
} }

View File

@@ -22,6 +22,7 @@
* the FLOSS exception, and it is also available here: * the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing" * http://www.alfresco.com/legal/licensing"
*/ */
package org.alfresco.repo.forms.processor.node; package org.alfresco.repo.forms.processor.node;
import java.io.Serializable; import java.io.Serializable;
@@ -49,22 +50,25 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
/** /**
* FormProcessor implementation that can generate and persist Form objects * FormProcessor implementation that can generate and persist Form objects for
* for types in the Alfresco content model. * types in the Alfresco content model.
* *
* @author Gavin Cornwell * @author Gavin Cornwell
*/ */
public class TypeFormProcessor extends ContentModelFormProcessor public class TypeFormProcessor extends ContentModelFormProcessor<TypeDefinition, NodeRef>
{ {
/** Logger */ /** Logger */
private static Log logger = LogFactory.getLog(TypeFormProcessor.class); private static Log logger = LogFactory.getLog(TypeFormProcessor.class);
protected static final String NAME_PROP_DATA = PROP + DATA_KEY_SEPARATOR + "cm" + DATA_KEY_SEPARATOR + "name"; protected static final String NAME_PROP_DATA = PROP + DATA_KEY_SEPARATOR + "cm"
+ DATA_KEY_SEPARATOR + "name";
public static final String DESTINATION = "alf_destination"; public static final String DESTINATION = "alf_destination";
/* /*
* @see org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getLogger() * @see
* org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getLogger
* ()
*/ */
@Override @Override
protected Log getLogger() protected Log getLogger()
@@ -73,10 +77,12 @@ public class TypeFormProcessor extends ContentModelFormProcessor
} }
/* /*
* @see org.alfresco.repo.forms.processor.node.NodeFormProcessor#getTypedItem(org.alfresco.repo.forms.Item) * @see
* org.alfresco.repo.forms.processor.node.NodeFormProcessor#getTypedItem
* (org.alfresco.repo.forms.Item)
*/ */
@Override @Override
protected Object getTypedItem(Item item) protected TypeDefinition getTypedItem(Item item)
{ {
TypeDefinition typeDef = null; TypeDefinition typeDef = null;
@@ -98,7 +104,7 @@ public class TypeFormProcessor extends ContentModelFormProcessor
// if item id contains _ change the first occurrence to : // if item id contains _ change the first occurrence to :
// as it's more than likely been converted for URL use // as it's more than likely been converted for URL use
int idx = itemId.indexOf("_"); int idx = itemId.indexOf("_");
String parsedItemId = itemId.substring(0, idx) + ":" + itemId.substring(idx+1); String parsedItemId = itemId.substring(0, idx) + ":" + itemId.substring(idx + 1);
type = QName.createQName(parsedItemId, this.namespaceService); type = QName.createQName(parsedItemId, this.namespaceService);
} }
else else
@@ -110,11 +116,8 @@ public class TypeFormProcessor extends ContentModelFormProcessor
// retrieve the type from the dictionary // retrieve the type from the dictionary
typeDef = this.dictionaryService.getType(type); typeDef = this.dictionaryService.getType(type);
if (typeDef == null) if (typeDef == null) { throw new FormNotFoundException(item,
{ new IllegalArgumentException("Type does not exist: " + item.getId())); }
throw new FormNotFoundException(item,
new IllegalArgumentException("Type does not exist: " + item.getId()));
}
} }
catch (InvalidQNameException iqne) catch (InvalidQNameException iqne)
{ {
@@ -126,23 +129,20 @@ public class TypeFormProcessor extends ContentModelFormProcessor
} }
/* /*
* @see org.alfresco.repo.forms.processor.FilteredFormProcessor#internalGenerate(java.lang.Object, java.util.List, java.util.List, org.alfresco.repo.forms.Form, java.util.Map) * @see
* org.alfresco.repo.forms.processor.FilteredFormProcessor#internalGenerate
* (java.lang.Object, java.util.List, java.util.List,
* org.alfresco.repo.forms.Form, java.util.Map)
*/ */
@Override @Override
protected void internalGenerate(Object item, List<String> fields, List<String> forcedFields, protected void internalGenerate(TypeDefinition item, List<String> fields,
Form form, Map<String, Object> context) List<String> forcedFields, Form form, Map<String, Object> context)
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled()) logger.debug("Generating form for item: " + item);
logger.debug("Generating form for item: " + item);
// cast to the expected NodeRef representation
TypeDefinition typeDef = (TypeDefinition)item;
// generate the form for the node // generate the form for the node
generateType(typeDef, fields, forcedFields, form); generateType(item, fields, forcedFields, form);
if (logger.isDebugEnabled()) logger.debug("Generating form: " + form);
if (logger.isDebugEnabled())
logger.debug("Generating form: " + form);
} }
/** /**
@@ -153,11 +153,15 @@ public class TypeFormProcessor extends ContentModelFormProcessor
* @param forcedFields List of fields to forcibly include * @param forcedFields List of fields to forcibly include
* @param form The Form instance to populate * @param form The Form instance to populate
*/ */
protected void generateType(TypeDefinition typeDef, List<String> fields, List<String> forcedFields, Form form) protected void generateType(TypeDefinition typeDef, List<String> fields,
List<String> forcedFields, Form form)
{ {
// set the type and URL of the item // set the type and URL of the item
form.getItem().setType(typeDef.getName().toPrefixString(this.namespaceService)); form.getItem().setType(typeDef.getName().toPrefixString(this.namespaceService));
form.getItem().setUrl("/api/classes/" + typeDef.getName().toPrefixString(this.namespaceService).replace(":", "_")); form.getItem().setUrl(
"/api/classes/"
+ typeDef.getName().toPrefixString(this.namespaceService).replace(
":", "_"));
if (fields != null && fields.size() > 0) if (fields != null && fields.size() > 0)
{ {
@@ -230,19 +234,17 @@ public class TypeFormProcessor extends ContentModelFormProcessor
} }
/* /*
* @see org.alfresco.repo.forms.processor.node.NodeFormProcessor#internalPersist(java.lang.Object, org.alfresco.repo.forms.FormData) * @see
* org.alfresco.repo.forms.processor.node.NodeFormProcessor#internalPersist
* (java.lang.Object, org.alfresco.repo.forms.FormData)
*/ */
@Override @Override
protected Object internalPersist(Object item, FormData data) protected NodeRef internalPersist(TypeDefinition item, FormData data)
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled()) logger.debug("Persisting form for: " + item);
logger.debug("Persisting form for: " + item);
// cast to the expected NodeRef representation
TypeDefinition typeDef = (TypeDefinition)item;
// create a new instance of the type // create a new instance of the type
NodeRef nodeRef = createNode(typeDef, data); NodeRef nodeRef = createNode(item, data);
// persist the form data // persist the form data
persistNode(nodeRef, data); persistNode(nodeRef, data);
@@ -254,13 +256,13 @@ public class TypeFormProcessor extends ContentModelFormProcessor
/** /**
* Creates a new instance of the given type. * Creates a new instance of the given type.
* <p> * <p>
* If the form data has the name property present it is used as * If the form data has the name property present it is used as the name of
* the name of the node. * the node.
* </p><p> * </p>
* The new node is placed in the location defined by the "destination" * <p>
* data item in the form data (this will usually be a hidden field), * The new node is placed in the location defined by the "destination" data
* this will also be the NodeRef representation of the parent for the * item in the form data (this will usually be a hidden field), this will
* new node. * also be the NodeRef representation of the parent for the new node.
* </p> * </p>
* *
* @param typeDef The type defintion of the type to create * @param typeDef The type defintion of the type to create
@@ -276,32 +278,33 @@ public class TypeFormProcessor extends ContentModelFormProcessor
// firstly, ensure we have a destination to create the node in // firstly, ensure we have a destination to create the node in
NodeRef parentRef = null; NodeRef parentRef = null;
FieldData destination = data.getFieldData(DESTINATION); FieldData destination = data.getFieldData(DESTINATION);
if (destination == null) if (destination == null) { throw new FormException("Failed to persist form for '"
{ + typeDef.getName().toPrefixString(this.namespaceService) + "' as '"
throw new FormException("Failed to persist form for '" + + DESTINATION + "' data was not provided."); }
typeDef.getName().toPrefixString(this.namespaceService) +
"' as '" + DESTINATION + "' data was not provided.");
}
// create the parent NodeRef // create the parent NodeRef
parentRef = new NodeRef((String)destination.getValue()); parentRef = new NodeRef((String) destination.getValue());
// remove the destination data to avoid warning during persistence, this can // remove the destination data to avoid warning during persistence,
// this can
// always be retrieved by looking up the created node's parent // always be retrieved by looking up the created node's parent
data.removeFieldData(DESTINATION); data.removeFieldData(DESTINATION);
// TODO: determine what association to use when creating the node in the destination, // TODO: determine what association to use when creating the node in
// the destination,
// defaults to ContentModel.ASSOC_CONTAINS // defaults to ContentModel.ASSOC_CONTAINS
// if a name property is present in the form data use it as the node name, // if a name property is present in the form data use it as the node
// name,
// otherwise generate a guid // otherwise generate a guid
String nodeName = null; String nodeName = null;
FieldData nameData = data.getFieldData(NAME_PROP_DATA); FieldData nameData = data.getFieldData(NAME_PROP_DATA);
if (nameData != null) if (nameData != null)
{ {
nodeName = (String)nameData.getValue(); nodeName = (String) nameData.getValue();
// remove the name data otherwise 'rename' gets called in persistNode // remove the name data otherwise 'rename' gets called in
// persistNode
data.removeFieldData(NAME_PROP_DATA); data.removeFieldData(NAME_PROP_DATA);
} }
if (nodeName == null || nodeName.length() == 0) if (nodeName == null || nodeName.length() == 0)
@@ -312,9 +315,12 @@ public class TypeFormProcessor extends ContentModelFormProcessor
// create the node // create the node
Map<QName, Serializable> nodeProps = new HashMap<QName, Serializable>(1); Map<QName, Serializable> nodeProps = new HashMap<QName, Serializable>(1);
nodeProps.put(ContentModel.PROP_NAME, nodeName); nodeProps.put(ContentModel.PROP_NAME, nodeName);
nodeRef = this.nodeService.createNode(parentRef, ContentModel.ASSOC_CONTAINS, nodeRef = this.nodeService.createNode(
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createValidLocalName(nodeName)), parentRef,
typeDef.getName(), nodeProps).getChildRef(); ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName
.createValidLocalName(nodeName)), typeDef.getName(), nodeProps)
.getChildRef();
} }
return nodeRef; return nodeRef;