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
*/
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);

View File

@@ -36,7 +36,7 @@ import org.alfresco.repo.forms.FormData;
*
* @author Gavin Cornwell
*/
public interface Filter
public interface Filter<ItemType, PersistType>
{
/**
* Determines whether the filter is active
@@ -61,7 +61,7 @@ public interface Filter
* @param @param context Map representing optional context that
* 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);
/**
@@ -80,7 +80,7 @@ public interface Filter
* @param context Map representing optional context that
* 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);
/**
@@ -95,7 +95,7 @@ public interface Filter
* @param item The item to persist the form data for
* @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
@@ -112,5 +112,5 @@ public interface Filter
* @param persistedObject The object created or modified as a result of
* 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:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.forms.processor;
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.
* <p>
* Each filter is called before and after the processor generates and
* persists the form, thus allowing the form and the effected objects
* to be manipulated prior to generation or persistence or after the
* fact.
* Each filter is called before and after the processor generates and persists
* the form, thus allowing the form and the effected objects to be manipulated
* prior to generation or persistence or after the fact.
* </p>
* <p>
* Each filter is responsible for determing whether it applies to the item
* being processed.
* Each filter is responsible for determing whether it applies to the item being
* processed.
* </p>
*
* @see org.alfresco.repo.forms.processor.Filter
* @author Gavin Cornwell
*/
public class FilterRegistry
public class FilterRegistry<ItemType, PersistType>
{
private static final Log logger = LogFactory.getLog(FilterRegistry.class);
protected List<Filter> filters;
protected List<Filter<ItemType, PersistType>> filters;
/**
* Constructs the registry
*/
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
*/
public void addFilter(Filter filter)
public void addFilter(Filter<ItemType, PersistType> filter)
{
if (filter.isActive())
{
this.filters.add(filter);
if (logger.isDebugEnabled())
logger.debug("Registered filter: " + filter + " in registry: " + this);
if (logger.isDebugEnabled()) logger.debug("Registered filter: " + filter + " in registry: " + this);
}
else if (logger.isWarnEnabled())
{
@@ -85,12 +84,12 @@ public class FilterRegistry
*
* @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
for (Filter filter: this.filters)
for (Filter<ItemType, PersistType> filter : this.filters)
{
if (filter.isActive())
{
@@ -98,8 +97,7 @@ public class FilterRegistry
}
}
if (logger.isDebugEnabled())
logger.debug("Returning active filters: " + activeFilters);
if (logger.isDebugEnabled()) logger.debug("Returning active filters: " + activeFilters);
return activeFilters;
}

View File

@@ -22,6 +22,7 @@
* 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;
@@ -34,23 +35,23 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Abstract base class for all FormProcessor implementations that wish to use the
* filter mechanism.
* Abstract base class for all FormProcessor implementations that wish to use
* the filter mechanism.
*
* @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);
protected FilterRegistry filterRegistry;
protected FilterRegistry<ItemType, PersistType> filterRegistry;
/**
* Sets the filter registry
*
* @param filterRegistry The FilterRegistry instance
*/
public void setFilterRegistry(FilterRegistry filterRegistry)
public void setFilterRegistry(FilterRegistry<ItemType, PersistType> 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,
Map<String, Object> context)
public Form generate(Item item, List<String> fields, List<String> forcedFields, Map<String, Object> context)
{
// get the typed object representing the item
Object typedItem = getTypedItem(item);
ItemType typedItem = getTypedItem(item);
// create an empty Form
Form form = new Form(item);
@@ -98,7 +100,8 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
* Persists the given form data for the given item, completed by calling
* 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 data The object representing the form data
* @return The object persisted
@@ -106,7 +109,7 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
public Object persist(Item item, FormData data)
{
// 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
if (this.filterRegistry != null)
@@ -132,17 +135,27 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
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.
* <p>
* Subclasses that represent a form type will return a typed object
* that is then passed to each of it's handlers, the handlers can
* therefore safely cast the Object to the type they expect.
* Subclasses that represent a form type will return a typed object that is
* then passed to each of it's handlers, the handlers can therefore safely
* cast the Object to the type they expect.
*
* @param item The item to get a typed object for
* @return The typed object
*/
protected abstract Object getTypedItem(Item item);
protected abstract ItemType getTypedItem(Item item);
/**
* Generates the form.
@@ -151,11 +164,11 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
* @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
* @param context Map representing optional context that can be used during
* retrieval of the form
*/
protected abstract void internalGenerate(Object item, List<String> fields, List<String> forcedFields,
Form form, Map<String, Object> context);
protected abstract void internalGenerate(ItemType item, List<String> fields, List<String> forcedFields, Form form,
Map<String, Object> context);
/**
* Persists the form data.
@@ -164,5 +177,6 @@ public abstract class FilteredFormProcessor extends AbstractFormProcessor
* @param data The data to persist
* @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;
import java.io.Serializable;
@@ -56,56 +57,76 @@ import org.springframework.util.StringUtils;
*
* @author Gavin Cornwell
*/
public abstract class ContentModelFormProcessor extends FilteredFormProcessor
public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
FilteredFormProcessor<ItemType, PersistType>
{
/** 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";
/** Protected constants */
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_ENCODING_LABEL = "form_service.encoding.label";
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_DESC = "form_service.size.description";
/** Services */
protected NodeService nodeService;
protected FileFolderService fileFolderService;
protected DictionaryService dictionaryService;
protected NamespaceService namespaceService;
/**
* A regular expression which can be used to match property names.
* These names will look like <code>"prop_cm_name"</code>.
* The pattern can also be used to extract the "cm" and the "name" parts.
* A regular expression which can be used to match property names. These
* names will look like <code>"prop_cm_name"</code>. The pattern can also be
* used to extract the "cm" and the "name" parts.
*/
protected Pattern propertyNamePattern = Pattern.compile(PROP_DATA_PREFIX + "(.*){1}?_(.*){1}?");
/**
* A regular expression which can be used to match tranisent property names.
* These names will look like <code>"prop_name"</code>.
* The pattern can also be used to extract the "name" part.
* These names will look like <code>"prop_name"</code>. The pattern can also
* be used to extract the "name" part.
*/
protected Pattern transientPropertyPattern = Pattern.compile(PROP_DATA_PREFIX + "(.*){1}?");
/**
* A regular expression which can be used to match association names.
* These names will look like <code>"assoc_cm_references_added"</code>.
* The pattern can also be used to extract the "cm", the "name" and the suffix parts.
* A regular expression which can be used to match association names. These
* names will look like <code>"assoc_cm_references_added"</code>. The
* pattern can also be used to extract the "cm", the "name" and the suffix
* parts.
*/
protected Pattern associationNamePattern = Pattern.compile(ASSOC_DATA_PREFIX + "(.*){1}?_(.*){1}?(_[a-zA-Z]+)");
protected Pattern associationNamePattern = Pattern.compile(ASSOC_DATA_PREFIX
+ "(.*){1}?_(.*){1}?(_[a-zA-Z]+)");
/**
* Sets the node service
@@ -150,9 +171,9 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
/**
* Sets up a field definition for the given property.
* <p>
* 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.
* 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.
* </p>
*
* @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.
* <p>
* 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.
* 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.
* </p>
*
* @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.
* <p>
* 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.
* 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.
* </p>
*
* @param propDef The PropertyDefinition of the field to generate
@@ -200,13 +221,12 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
*/
@SuppressWarnings("unchecked")
public static void generatePropertyField(PropertyDefinition propDef, Form form,
Serializable propValue, FieldGroup group,
NamespaceService namespaceService)
Serializable propValue, FieldGroup group, NamespaceService namespaceService)
{
String propName = propDef.getName().toPrefixString(namespaceService);
String[] nameParts = QName.splitPrefixedQName(propName);
PropertyFieldDefinition fieldDef = new PropertyFieldDefinition(
propName, propDef.getDataType().getName().getLocalName());
PropertyFieldDefinition fieldDef = new PropertyFieldDefinition(propName, propDef
.getDataType().getName().getLocalName());
String title = propDef.getTitle();
if (title == null)
@@ -222,7 +242,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
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
// 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);
@@ -251,14 +272,14 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
List<ConstraintDefinition> constraints = propDef.getConstraints();
if (constraints != null && constraints.size() > 0)
{
List<FieldConstraint> fieldConstraints =
new ArrayList<FieldConstraint>(constraints.size());
List<FieldConstraint> fieldConstraints = new ArrayList<FieldConstraint>(constraints
.size());
for (ConstraintDefinition constraintDef : constraints)
{
Constraint constraint = constraintDef.getConstraint();
FieldConstraint fieldConstraint = fieldDef.new FieldConstraint(
constraint.getType(), constraint.getParameters());
FieldConstraint fieldConstraint = new FieldConstraint(constraint.getType(),
constraint.getParameters());
fieldConstraints.add(fieldConstraint);
}
@@ -286,17 +307,17 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
/**
* Sets up a field definition for the given association.
* <p>
* 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.
* 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.
* </p>
*
* @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)
public static void generateAssociationField(AssociationDefinition assocDef, Form form,
NamespaceService 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.
* <p>
* 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.
* 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.
* </p>
*
* @param assocDef The AssociationDefinition of the field to generate
@@ -315,8 +336,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
* @param namespaceService NamespaceService instance
*/
@SuppressWarnings("unchecked")
public static void generateAssociationField(AssociationDefinition assocDef,
Form form, List assocValues, NamespaceService namespaceService)
public static void generateAssociationField(AssociationDefinition assocDef, Form form,
List assocValues, NamespaceService namespaceService)
{
generateAssociationField(assocDef, form, assocValues, null, namespaceService);
}
@@ -324,9 +345,9 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
/**
* Sets up a field definition for the given association.
* <p>
* 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.
* 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.
* </p>
*
* @param assocDef The AssociationDefinition of the field to generate
@@ -336,15 +357,13 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
* @param namespaceService NamespaceService instance
*/
@SuppressWarnings("unchecked")
public static void generateAssociationField(AssociationDefinition assocDef,
Form form, List assocValues, FieldGroup group,
NamespaceService namespaceService)
public static void generateAssociationField(AssociationDefinition assocDef, Form form,
List assocValues, FieldGroup group, NamespaceService namespaceService)
{
String assocName = assocDef.getName().toPrefixString(namespaceService);
String[] nameParts = QName.splitPrefixedQName(assocName);
AssociationFieldDefinition fieldDef = new AssociationFieldDefinition(assocName,
assocDef.getTargetClass().getName().toPrefixString(
namespaceService), Direction.TARGET);
AssociationFieldDefinition fieldDef = new AssociationFieldDefinition(assocName, assocDef
.getTargetClass().getName().toPrefixString(namespaceService), Direction.TARGET);
String title = assocDef.getTitle();
if (title == null)
{
@@ -367,7 +386,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (assocValues != null)
{
// 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);
for (Object value : assocValues)
{
@@ -400,33 +420,33 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
/**
* Sets up the field definitions for all the requested fields.
* <p>
* 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.
* </p><p>
* 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.
* 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.
* </p>
* <p>
* 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.
* </p>
*
* @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 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<String> fields, List<String> 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 (nodeRef == null && typeDef == null) { throw new IllegalArgumentException(
"A NodeRef or TypeDefinition must be provided"); }
if (getLogger().isDebugEnabled())
getLogger().debug("Generating selected fields: " + fields + " and forcing: " + forcedFields);
getLogger().debug(
"Generating selected fields: " + fields + " and forcing: " + forcedFields);
// get data dictionary definition for node if it is provided
QName type = null;
@@ -437,9 +457,11 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (nodeRef != null)
{
type = this.nodeService.getType(nodeRef);
typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService.getAspects(nodeRef));
typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService
.getAspects(nodeRef));
// NOTE: the anonymous type returns all property and association defs
// 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();
@@ -484,9 +506,12 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
}
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 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;
@@ -498,7 +523,11 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
else
{
if (getLogger().isWarnEnabled())
getLogger().warn("\"" + parts[0] + "\" is an invalid prefix for requesting a property or association");
getLogger()
.warn(
"\""
+ parts[0]
+ "\" is an invalid prefix for requesting a property or association");
continue;
}
@@ -518,7 +547,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (propDef != null)
{
// generate the property field
generatePropertyField(propDef, form, propValues.get(fullQName), this.namespaceService);
generatePropertyField(propDef, form, propValues.get(fullQName),
this.namespaceService);
// no need to try and find an association
tryAssociation = false;
@@ -533,9 +563,11 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (assocDef != null)
{
// generate the association field
generateAssociationField(assocDef, form,
(nodeRef != null) ? retrieveAssociationValues(nodeRef, assocDef) : null,
this.namespaceService);
generateAssociationField(
assocDef,
form,
(nodeRef != null) ? retrieveAssociationValues(nodeRef, assocDef)
: null, this.namespaceService);
foundField = true;
}
@@ -544,29 +576,35 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
// still not found the field, is it a force'd field?
if (!foundField)
{
if (forcedFields != null && forcedFields.size() > 0 &&
forcedFields.contains(fieldName))
if (forcedFields != null && forcedFields.size() > 0
&& forcedFields.contains(fieldName))
{
generateForcedField(fieldName, form);
}
else if (getLogger().isDebugEnabled())
{
getLogger().debug("Ignoring field \"" + fieldName +
"\" as it is not defined for the current " + ((nodeRef != null) ? "node" : "type") +
" and it does not appear in the 'force' list");
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 (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 (nodeRef != null && this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT))
// if the node type is content or sublcass thereof generate
// 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 (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
* to show.
* 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
@@ -620,9 +658,12 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
}
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 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;
@@ -634,7 +675,11 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
else
{
if (getLogger().isWarnEnabled())
getLogger().warn("\"" + parts[0] + "\" is an invalid prefix for requesting a property or association");
getLogger()
.warn(
"\""
+ parts[0]
+ "\" is an invalid prefix for requesting a property or association");
return;
}
@@ -676,8 +721,11 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
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");
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())
@@ -695,8 +743,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
protected void generateMimetypePropertyField(ContentData content, Form form)
{
String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_MIMETYPE;
PropertyFieldDefinition mimetypeField = new PropertyFieldDefinition(
TRANSIENT_MIMETYPE, DataTypeDefinition.TEXT.getLocalName());
PropertyFieldDefinition mimetypeField = new PropertyFieldDefinition(TRANSIENT_MIMETYPE,
DataTypeDefinition.TEXT.getLocalName());
mimetypeField.setLabel(I18NUtil.getMessage(MSG_MIMETYPE_LABEL));
mimetypeField.setDescription(I18NUtil.getMessage(MSG_MIMETYPE_DESC));
mimetypeField.setDataKeyName(dataKeyName);
@@ -717,8 +765,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
protected void generateEncodingPropertyField(ContentData content, Form form)
{
String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_ENCODING;
PropertyFieldDefinition encodingField = new PropertyFieldDefinition(
TRANSIENT_ENCODING, DataTypeDefinition.TEXT.getLocalName());
PropertyFieldDefinition encodingField = new PropertyFieldDefinition(TRANSIENT_ENCODING,
DataTypeDefinition.TEXT.getLocalName());
encodingField.setLabel(I18NUtil.getMessage(MSG_ENCODING_LABEL));
encodingField.setDescription(I18NUtil.getMessage(MSG_ENCODING_DESC));
encodingField.setDataKeyName(dataKeyName);
@@ -739,8 +787,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
protected void generateSizePropertyField(ContentData content, Form form)
{
String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_SIZE;
PropertyFieldDefinition sizeField = new PropertyFieldDefinition(
TRANSIENT_SIZE, DataTypeDefinition.LONG.getLocalName());
PropertyFieldDefinition sizeField = new PropertyFieldDefinition(TRANSIENT_SIZE,
DataTypeDefinition.LONG.getLocalName());
sizeField.setLabel(I18NUtil.getMessage(MSG_SIZE_LABEL));
sizeField.setDescription(I18NUtil.getMessage(MSG_SIZE_DESC));
sizeField.setDataKeyName(dataKeyName);
@@ -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 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
QName type = this.nodeService.getType(nodeRef);
TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type,
this.nodeService.getAspects(nodeRef));
TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService
.getAspects(nodeRef));
Map<QName, AssociationDefinition> assocDefs = typeDef.getAssociations();
Map<QName, ChildAssociationDefinition> childAssocDefs = typeDef.getChildAssociations();
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>();
for (FieldData fieldData : data)
@@ -812,7 +862,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
}
else if (fieldName.startsWith(ASSOC_DATA_PREFIX))
{
processAssociationPersist(nodeRef, assocDefs, childAssocDefs, fieldData, assocsToPersist);
processAssociationPersist(nodeRef, assocDefs, childAssocDefs, fieldData,
assocsToPersist);
}
else if (getLogger().isWarnEnabled())
{
@@ -821,14 +872,18 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
}
}
// persist the properties using addProperties as this changes the repo values of
// 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.
// persist the properties using addProperties as this changes the repo
// values of
// 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);
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
// one request,
// we could drop each request and do nothing.
cmd.updateAssociations(nodeService);
}
@@ -859,7 +914,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
// ensure that the property being persisted is defined in the model
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)
{
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 (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))
{
processNamePropertyPersist(nodeRef, fieldData);
@@ -880,7 +937,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
// before persisting check data type of property
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
if (value instanceof String)
{
@@ -892,7 +950,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
}
else
{
// if value is a String convert to List of String
// if value is a String convert to List of
// String
StringTokenizer tokenizer = new StringTokenizer((String) value, ",");
List<String> list = new ArrayList<String>(8);
while (tokenizer.hasMoreTokens())
@@ -928,7 +987,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
}
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))
{
value = Boolean.TRUE;
@@ -940,10 +1000,12 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
}
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
if (!propDef.getDataType().getName().equals(DataTypeDefinition.TEXT) &&
!propDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT))
if (!propDef.getDataType().getName().equals(DataTypeDefinition.TEXT)
&& !propDef.getDataType().getName().equals(
DataTypeDefinition.MLTEXT))
{
value = null;
}
@@ -955,7 +1017,9 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
}
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
@@ -977,7 +1041,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
}
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
}
else if (getLogger().isWarnEnabled())
@@ -999,9 +1064,10 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
* @param fieldData Data to persist for the associations
* @param assocCommands List of associations to be persisted
*/
protected void processAssociationPersist(NodeRef nodeRef, Map<QName, AssociationDefinition> assocDefs,
Map<QName, ChildAssociationDefinition> childAssocDefs,
FieldData fieldData, List<AbstractAssocCommand> assocCommands)
protected void processAssociationPersist(NodeRef nodeRef,
Map<QName, AssociationDefinition> assocDefs,
Map<QName, ChildAssociationDefinition> childAssocDefs, FieldData fieldData,
List<AbstractAssocCommand> assocCommands)
{
if (getLogger().isDebugEnabled())
getLogger().debug("Processing field " + fieldData + " for association persistence");
@@ -1016,21 +1082,29 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
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);
// TODO: if the association is not defined on the node, check for the association
// in all models, however, the source of an association can be critical so we
// can't just look up the association in the model regardless. We 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
// TODO: if the association is not defined on the node, check for
// the association
// in all models, however, the source of an association can be
// critical so we
// can't just look up the association in the model regardless. We
// 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 (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;
}
@@ -1038,7 +1112,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
String value = (String) fieldData.getValue();
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.
for (String nextTargetNode : nodeRefs)
{
@@ -1050,26 +1125,26 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
{
if (assocDef.isChild())
{
assocCommands.add(new AddChildAssocCommand(nodeRef, new NodeRef(nextTargetNode),
fullQName));
assocCommands.add(new AddChildAssocCommand(nodeRef, new NodeRef(
nextTargetNode), fullQName));
}
else
{
assocCommands.add(new AddAssocCommand(nodeRef, new NodeRef(nextTargetNode),
fullQName));
assocCommands.add(new AddAssocCommand(nodeRef, new NodeRef(
nextTargetNode), fullQName));
}
}
else if (assocSuffix.equals(ASSOC_DATA_REMOVED_SUFFIX))
{
if (assocDef.isChild())
{
assocCommands.add(new RemoveChildAssocCommand(nodeRef, new NodeRef(nextTargetNode),
fullQName));
assocCommands.add(new RemoveChildAssocCommand(nodeRef, new NodeRef(
nextTargetNode), fullQName));
}
else
{
assocCommands.add(new RemoveAssocCommand(nodeRef, new NodeRef(nextTargetNode),
fullQName));
assocCommands.add(new RemoveAssocCommand(nodeRef, new NodeRef(
nextTargetNode), fullQName));
}
}
else
@@ -1077,13 +1152,11 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (getLogger().isWarnEnabled())
{
StringBuilder msg = new StringBuilder();
msg.append("fieldName ")
.append(fieldName)
.append(" does not have one of the expected suffixes [")
.append(ASSOC_DATA_ADDED_SUFFIX)
.append(", ")
.append(ASSOC_DATA_REMOVED_SUFFIX)
.append("] and has been ignored.");
msg.append("fieldName ").append(fieldName).append(
" does not have one of the expected suffixes [")
.append(ASSOC_DATA_ADDED_SUFFIX).append(", ").append(
ASSOC_DATA_REMOVED_SUFFIX).append(
"] and has been ignored.");
getLogger().warn(msg.toString());
}
}
@@ -1093,9 +1166,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (getLogger().isWarnEnabled())
{
StringBuilder msg = new StringBuilder();
msg.append("targetNode ")
.append(nextTargetNode)
.append(" is not a valid NodeRef and has been ignored.");
msg.append("targetNode ").append(nextTargetNode).append(
" is not a valid NodeRef and has been ignored.");
getLogger().warn(msg.toString());
}
}
@@ -1115,7 +1187,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
try
{
// 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
// directly
this.fileFolderService.rename(nodeRef, (String) fieldData.getValue());
}
catch (FileExistsException fee)
@@ -1142,7 +1215,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (contentData == null)
{
// content data has not been persisted yet so get it from the node
contentData = (ContentData)this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
contentData = (ContentData) this.nodeService.getProperty(nodeRef,
ContentModel.PROP_CONTENT);
}
if (contentData != null)
@@ -1167,7 +1241,8 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
if (contentData == null)
{
// content data has not been persisted yet so get it from the node
contentData = (ContentData)this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
contentData = (ContentData) this.nodeService.getProperty(nodeRef,
ContentModel.PROP_CONTENT);
}
if (contentData != null)
@@ -1187,11 +1262,12 @@ public abstract class ContentModelFormProcessor extends FilteredFormProcessor
abstract class AbstractAssocCommand
{
protected final NodeRef sourceNodeRef;
protected final NodeRef targetNodeRef;
protected final QName assocQName;
public AbstractAssocCommand(NodeRef sourceNodeRef, NodeRef targetNodeRef,
QName assocQName)
public AbstractAssocCommand(NodeRef sourceNodeRef, NodeRef targetNodeRef, QName assocQName)
{
this.sourceNodeRef = sourceNodeRef;
this.targetNodeRef = targetNodeRef;
@@ -1201,6 +1277,7 @@ abstract class AbstractAssocCommand
/**
* This method should use the specified nodeService reference to effect the
* update to the supplied associations.
*
* @param nodeService
*/
protected abstract void updateAssociations(NodeService nodeService);
@@ -1214,8 +1291,8 @@ abstract class AbstractAssocCommand
class AddAssocCommand extends AbstractAssocCommand
{
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);
}
@@ -1223,7 +1300,8 @@ class AddAssocCommand extends AbstractAssocCommand
@Override
protected void updateAssociations(NodeService nodeService)
{
List<AssociationRef> existingAssocs = nodeService.getTargetAssocs(sourceNodeRef, assocQName);
List<AssociationRef> existingAssocs = nodeService
.getTargetAssocs(sourceNodeRef, assocQName);
for (AssociationRef assoc : existingAssocs)
{
if (assoc.getTargetRef().equals(targetNodeRef))
@@ -1247,8 +1325,8 @@ class AddAssocCommand extends AbstractAssocCommand
class RemoveAssocCommand extends AbstractAssocCommand
{
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);
}
@@ -1256,7 +1334,8 @@ class RemoveAssocCommand extends AbstractAssocCommand
@Override
protected void updateAssociations(NodeService nodeService)
{
List<AssociationRef> existingAssocs = nodeService.getTargetAssocs(sourceNodeRef, assocQName);
List<AssociationRef> existingAssocs = nodeService
.getTargetAssocs(sourceNodeRef, assocQName);
boolean assocDoesNotExist = true;
for (AssociationRef assoc : existingAssocs)
{
@@ -1271,11 +1350,8 @@ class RemoveAssocCommand extends AbstractAssocCommand
if (logger.isWarnEnabled())
{
StringBuilder msg = new StringBuilder();
msg.append("Attempt to remove non-existent association prevented. ")
.append(sourceNodeRef)
.append("|")
.append(targetNodeRef)
.append(assocQName);
msg.append("Attempt to remove non-existent association prevented. ").append(
sourceNodeRef).append("|").append(targetNodeRef).append(assocQName);
logger.warn(msg.toString());
}
return;
@@ -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
*/
class AddChildAssocCommand extends AbstractAssocCommand
{
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);
}
@@ -1315,22 +1392,24 @@ class AddChildAssocCommand extends AbstractAssocCommand
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.
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
*/
class RemoveChildAssocCommand extends AbstractAssocCommand
{
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);
}
@@ -1353,11 +1432,8 @@ class RemoveChildAssocCommand extends AbstractAssocCommand
if (logger.isWarnEnabled())
{
StringBuilder msg = new StringBuilder();
msg.append("Attempt to remove non-existent child association prevented. ")
.append(sourceNodeRef)
.append("|")
.append(targetNodeRef)
.append(assocQName);
msg.append("Attempt to remove non-existent child association prevented. ").append(
sourceNodeRef).append("|").append(targetNodeRef).append(assocQName);
logger.warn(msg.toString());
}
return;

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:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.forms.processor.node;
import java.io.Serializable;
@@ -44,18 +45,20 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* FormProcessor implementation that can generate and persist Form objects
* for repository nodes.
* FormProcessor implementation that can generate and persist Form objects for
* repository nodes.
*
* @author Gavin Cornwell
*/
public class NodeFormProcessor extends ContentModelFormProcessor
public class NodeFormProcessor extends ContentModelFormProcessor<NodeRef, NodeRef>
{
/** Logger */
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
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
protected Object getTypedItem(Item item)
protected NodeRef getTypedItem(Item item)
{
// create NodeRef representation, the id could already be in a valid
// 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
if (nodeRef == null)
{
throw new FormNotFoundException(item,
new IllegalArgumentException(item.getId()));
}
if (nodeRef == null) { throw new FormNotFoundException(item, new IllegalArgumentException(
item.getId())); }
// check the node itself exists
if (this.nodeService.exists(nodeRef) == false)
{
throw new FormNotFoundException(item,
new InvalidNodeRefException("Node does not exist: " + nodeRef, nodeRef));
throw new FormNotFoundException(item, new InvalidNodeRefException(
"Node does not exist: " + nodeRef, nodeRef));
}
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
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)
{
if (logger.isDebugEnabled())
logger.debug("Generating form for: " + item);
// cast to the expected NodeRef representation
NodeRef nodeRef = (NodeRef)item;
if (logger.isDebugEnabled()) logger.debug("Generating form for: " + item);
// generate the form for the node
generateNode(nodeRef, fields, forcedFields, form);
generateNode(item, fields, forcedFields, form);
if (logger.isDebugEnabled())
logger.debug("Generated form: " + form);
if (logger.isDebugEnabled()) logger.debug("Generated form: " + form);
}
/**
@@ -144,7 +144,8 @@ public class NodeFormProcessor extends ContentModelFormProcessor
* @param forcedFields List of fields to forcibly include
* @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
QName type = this.nodeService.getType(nodeRef);
@@ -178,8 +179,8 @@ public class NodeFormProcessor extends ContentModelFormProcessor
{
// get data dictionary definition for node
QName type = this.nodeService.getType(nodeRef);
TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type,
this.nodeService.getAspects(nodeRef));
TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService
.getAspects(nodeRef));
// iterate round the property definitions for the node and create
// 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
QName type = this.nodeService.getType(nodeRef);
TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type,
this.nodeService.getAspects(nodeRef));
TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService
.getAspects(nodeRef));
// iterate round the association defintions and setup field definition
Map<QName, AssociationDefinition> assocDefs = typeDef.getAssociations();
for (AssociationDefinition assocDef : assocDefs.values())
{
generateAssociationField(assocDef, form,
retrieveAssociationValues(nodeRef, assocDef),
generateAssociationField(assocDef, form, retrieveAssociationValues(nodeRef, assocDef),
this.namespaceService);
}
}
@@ -224,11 +224,13 @@ public class NodeFormProcessor extends ContentModelFormProcessor
*/
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);
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)
{
// 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
protected Object internalPersist(Object item, FormData data)
protected NodeRef internalPersist(NodeRef item, FormData data)
{
if (logger.isDebugEnabled())
logger.debug("Persisting form for: " + item);
// cast to the expected NodeRef representation
NodeRef nodeRef = (NodeRef)item;
if (logger.isDebugEnabled()) logger.debug("Persisting form for: " + item);
// persist the node
persistNode(nodeRef, data);
persistNode(item, data);
return item;
}
}

View File

@@ -22,6 +22,7 @@
* 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;
@@ -49,22 +50,25 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* FormProcessor implementation that can generate and persist Form objects
* for types in the Alfresco content model.
* FormProcessor implementation that can generate and persist Form objects for
* types in the Alfresco content model.
*
* @author Gavin Cornwell
*/
public class TypeFormProcessor extends ContentModelFormProcessor
public class TypeFormProcessor extends ContentModelFormProcessor<TypeDefinition, NodeRef>
{
/** Logger */
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";
/*
* @see org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getLogger()
* @see
* org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getLogger
* ()
*/
@Override
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
protected Object getTypedItem(Item item)
protected TypeDefinition getTypedItem(Item item)
{
TypeDefinition typeDef = null;
@@ -110,11 +116,8 @@ public class TypeFormProcessor extends ContentModelFormProcessor
// retrieve the type from the dictionary
typeDef = this.dictionaryService.getType(type);
if (typeDef == null)
{
throw new FormNotFoundException(item,
new IllegalArgumentException("Type does not exist: " + item.getId()));
}
if (typeDef == null) { throw new FormNotFoundException(item,
new IllegalArgumentException("Type does not exist: " + item.getId())); }
}
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
protected void internalGenerate(Object item, List<String> fields, List<String> forcedFields,
Form form, Map<String, Object> context)
protected void internalGenerate(TypeDefinition item, List<String> fields,
List<String> forcedFields, Form form, Map<String, Object> context)
{
if (logger.isDebugEnabled())
logger.debug("Generating form for item: " + item);
// cast to the expected NodeRef representation
TypeDefinition typeDef = (TypeDefinition)item;
if (logger.isDebugEnabled()) logger.debug("Generating form for item: " + item);
// generate the form for the node
generateType(typeDef, fields, forcedFields, form);
if (logger.isDebugEnabled())
logger.debug("Generating form: " + form);
generateType(item, fields, forcedFields, 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 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
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)
{
@@ -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
protected Object internalPersist(Object item, FormData data)
protected NodeRef internalPersist(TypeDefinition item, FormData data)
{
if (logger.isDebugEnabled())
logger.debug("Persisting form for: " + item);
// cast to the expected NodeRef representation
TypeDefinition typeDef = (TypeDefinition)item;
if (logger.isDebugEnabled()) logger.debug("Persisting form for: " + item);
// create a new instance of the type
NodeRef nodeRef = createNode(typeDef, data);
NodeRef nodeRef = createNode(item, data);
// persist the form data
persistNode(nodeRef, data);
@@ -254,13 +256,13 @@ public class TypeFormProcessor extends ContentModelFormProcessor
/**
* Creates a new instance of the given type.
* <p>
* If the form data has the name property present it is used as
* the name of the node.
* </p><p>
* The new node is placed in the location defined by the "destination"
* data item in the form data (this will usually be a hidden field),
* this will also be the NodeRef representation of the parent for the
* new node.
* If the form data has the name property present it is used as the name of
* the node.
* </p>
* <p>
* The new node is placed in the location defined by the "destination" data
* item in the form data (this will usually be a hidden field), this will
* also be the NodeRef representation of the parent for the new node.
* </p>
*
* @param typeDef The type defintion of the type to create
@@ -276,24 +278,24 @@ public class TypeFormProcessor extends ContentModelFormProcessor
// firstly, ensure we have a destination to create the node in
NodeRef parentRef = null;
FieldData destination = data.getFieldData(DESTINATION);
if (destination == null)
{
throw new FormException("Failed to persist form for '" +
typeDef.getName().toPrefixString(this.namespaceService) +
"' as '" + DESTINATION + "' data was not provided.");
}
if (destination == null) { throw new FormException("Failed to persist form for '"
+ typeDef.getName().toPrefixString(this.namespaceService) + "' as '"
+ DESTINATION + "' data was not provided."); }
// create the parent NodeRef
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
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
// 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
String nodeName = null;
FieldData nameData = data.getFieldData(NAME_PROP_DATA);
@@ -301,7 +303,8 @@ public class TypeFormProcessor extends ContentModelFormProcessor
{
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);
}
if (nodeName == null || nodeName.length() == 0)
@@ -312,9 +315,12 @@ public class TypeFormProcessor extends ContentModelFormProcessor
// create the node
Map<QName, Serializable> nodeProps = new HashMap<QName, Serializable>(1);
nodeProps.put(ContentModel.PROP_NAME, nodeName);
nodeRef = this.nodeService.createNode(parentRef, ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createValidLocalName(nodeName)),
typeDef.getName(), nodeProps).getChildRef();
nodeRef = this.nodeService.createNode(
parentRef,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName
.createValidLocalName(nodeName)), typeDef.getName(), nodeProps)
.getChildRef();
}
return nodeRef;