Merged BRANCHES/DEV/FORM-REFACTOR-MERGE to HEAD:

20935: Branch for form processor refactor merge
   21075: Utility class to help with writing tests which require creation/management of a person.
   21076: Forms Processor Refactor. Refactored the FilteredFormProcessor and ContentModelFormProcessor classes to be more concise. Also introduced the notion of a Field, FieldProcessors and the FieldProcessorRegistry. These are currently responsible for generating different types of fields such as Association fields, Property fields and the various transient fields.
   21083: Moved some utility classes into the correct packages for Forms.
   21084: Created
   21087: Created TaskFormProcessor
   21101: Added test for fdk:period property, in particular the retrieval of it's data type parameters
   21109: Fixed some issues witht he field processor logging. Also fixed an issue where data type properties were not being set correctly for Period property fields.
   21121: Changed AssociationFieldProcessor so that it now adds an empty list as a value instead of null.
   21124: Formatting updates and disabled FDK test ready for merge to HEAD


This commit contains all the re-factoring Nick has been doing to make the form processor mechansim more flexible for form filter developers and more importantly to make it easier to add additional form processor implementations, in particular the TaskFormProcessor and WorkflowFormProcessor. 

A field processor mechanism has also been introduced, this allows the processing of fields to be handled outside of the form processor and means common field handling code can be reused across different form processors. The field processors are also pluggable via Spring config so it's easy for customers to add their own or replace/override ours.

We have run numerous tests (unit and manual UI) and all seems well but as with any change of this size there maybe some edge cases that get missed so please let one of us know if you see any strange behaviour.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21134 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Gavin Cornwell
2010-07-13 15:03:19 +00:00
parent e468ab3a4b
commit 4cd5e90110
31 changed files with 3550 additions and 810 deletions

View File

@@ -69,7 +69,10 @@
<bean id="filteredFormProcessor" abstract="true" <bean id="filteredFormProcessor" abstract="true"
class="org.alfresco.repo.forms.processor.FilteredFormProcessor" class="org.alfresco.repo.forms.processor.FilteredFormProcessor"
parent="baseFormProcessor" /> parent="baseFormProcessor" >
<property name="fieldProcessorRegistry" ref="fieldProcessorRegistry" />
</bean>
<bean id="nodeFormProcessor" <bean id="nodeFormProcessor"
class="org.alfresco.repo.forms.processor.node.NodeFormProcessor" class="org.alfresco.repo.forms.processor.node.NodeFormProcessor"
@@ -134,4 +137,49 @@
<property name="formService" ref="FormService"/> <property name="formService" ref="FormService"/>
</bean> </bean>
<!-- Field Processor Config -->
<!-- The Field Processor Registry -->
<bean id="fieldProcessorRegistry"
class="org.alfresco.repo.forms.processor.node.ContentModelFieldProcessorRegistry">
<property name="defaultProcessor" ref="defaultFieldProcessor" />
</bean>
<!-- The Field Processors -->
<bean id="baseFieldProcessor" abstract="true"
class="org.alfresco.repo.forms.processor.AbstractFieldProcessor">
<property name="fieldProcessorRegistry" ref="fieldProcessorRegistry" />
</bean>
<bean id="qnameFieldProcessor" abstract="true"
class="org.alfresco.repo.forms.processor.node.QNameFieldProcessor"
parent="baseFieldProcessor">
<property name="namespaceService" ref="NamespaceService" />
<property name="dictionaryService" ref="DictionaryService" />
</bean>
<bean id="propertyFieldProcessor"
class="org.alfresco.repo.forms.processor.node.PropertyFieldProcessor"
parent="qnameFieldProcessor" />
<bean id="associationFieldProcessor"
class="org.alfresco.repo.forms.processor.node.AssociationFieldProcessor"
parent="qnameFieldProcessor" />
<bean id="encodingFieldProcessor"
class="org.alfresco.repo.forms.processor.node.TransientEncodingFieldProcessor"
parent="baseFieldProcessor" />
<bean id="mimetypeFieldProcessor"
class="org.alfresco.repo.forms.processor.node.TransientMimetypeFieldProcessor"
parent="baseFieldProcessor" />
<bean id="sizeFieldProcessor"
class="org.alfresco.repo.forms.processor.node.TransientSizeFieldProcessor"
parent="baseFieldProcessor" />
<bean id="defaultFieldProcessor"
class="org.alfresco.repo.forms.processor.node.DefaultFieldProcessor"
parent="qnameFieldProcessor" />
</beans> </beans>

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms;
/**
* Interface definition of a field
*
* @author Nick Smith
*/
public interface Field
{
/**
* @return the field definition
*/
FieldDefinition getFieldDefinition();
/**
* @return the fieldName
*/
String getFieldName();
/**
* @return the value for this field or <code>null</code>.
*/
Object getValue();
}

View File

@@ -185,6 +185,41 @@ public class Form
this.data.addFieldData(fieldName, fieldData); this.data.addFieldData(fieldName, fieldData);
} }
/**
* Adds a {@link Field} to the form by adding the {@link FieldDefinition}
* and the value if any.
*
* @param field
*/
public void addField(Field field)
{
if (field == null)
{
return;
}
FieldDefinition fieldDefinition = field.getFieldDefinition();
addFieldDefinition(fieldDefinition);
Object value = field.getValue();
if (value != null)
{
addData(fieldDefinition.getDataKeyName(), value);
}
}
/**
* Adds a {@link Collection} of {@link Field Fields} to the form by adding the {@link FieldDefinition FieldDefinitions}
* and the values if any.
*/
public void addFields(Collection<Field> fields)
{
for (Field field : fields)
{
addField(field);
}
}
/* /*
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
*/ */

View File

@@ -30,10 +30,10 @@ import java.util.Map;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.forms.AssociationFieldDefinition.Direction; import org.alfresco.repo.forms.AssociationFieldDefinition.Direction;
import org.alfresco.repo.forms.FormData.FieldData;
import org.alfresco.repo.forms.PropertyFieldDefinition.FieldConstraint; import org.alfresco.repo.forms.PropertyFieldDefinition.FieldConstraint;
import org.alfresco.repo.forms.processor.node.TypeFormProcessor; import org.alfresco.repo.forms.processor.node.TypeFormProcessor;
import org.alfresco.repo.jscript.ClasspathScriptLocation; import org.alfresco.repo.jscript.ClasspathScriptLocation;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentReader;
@@ -130,9 +130,6 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
this.contentService = (ContentService)this.applicationContext.getBean("ContentService"); this.contentService = (ContentService)this.applicationContext.getBean("ContentService");
this.workflowService = (WorkflowService)this.applicationContext.getBean("WorkflowService"); this.workflowService = (WorkflowService)this.applicationContext.getBean("WorkflowService");
AuthenticationComponent authenticationComponent = (AuthenticationComponent) this.applicationContext
.getBean("authenticationComponent");
// Do the tests as userOne // Do the tests as userOne
createUser(USER_ONE); createUser(USER_ONE);
authenticationComponent.setCurrentUser(USER_ONE); authenticationComponent.setCurrentUser(USER_ONE);
@@ -1091,6 +1088,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
QName underscoreProperty = QName.createQName(fdkUri, "with_underscore"); QName underscoreProperty = QName.createQName(fdkUri, "with_underscore");
QName dashProperty = QName.createQName(fdkUri, "with-dash"); QName dashProperty = QName.createQName(fdkUri, "with-dash");
QName duplicateProperty = QName.createQName(fdkUri, "duplicate"); QName duplicateProperty = QName.createQName(fdkUri, "duplicate");
QName periodProperty = QName.createQName(fdkUri, "period");
String guid = GUID.generate(); String guid = GUID.generate();
String name = "everything" + guid + ".txt"; String name = "everything" + guid + ".txt";
@@ -1098,6 +1096,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
String underscoreValue = "Property with an underscore in the name."; String underscoreValue = "Property with an underscore in the name.";
String dashValue = "Property with a dash in the name."; String dashValue = "Property with a dash in the name.";
String duplicateValue = "Property with the same name as an association."; String duplicateValue = "Property with the same name as an association.";
String periodValue = "day|1";
Map<QName, Serializable> docProps = new HashMap<QName, Serializable>(4); Map<QName, Serializable> docProps = new HashMap<QName, Serializable>(4);
docProps.put(ContentModel.PROP_NAME, name); docProps.put(ContentModel.PROP_NAME, name);
@@ -1105,6 +1104,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
docProps.put(underscoreProperty, underscoreValue); docProps.put(underscoreProperty, underscoreValue);
docProps.put(dashProperty, dashValue); docProps.put(dashProperty, dashValue);
docProps.put(duplicateProperty, duplicateValue); docProps.put(duplicateProperty, duplicateValue);
docProps.put(periodProperty, periodValue);
NodeRef everythingNode = this.nodeService.createNode(this.folder, ContentModel.ASSOC_CONTAINS, NodeRef everythingNode = this.nodeService.createNode(this.folder, ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name), everythingType, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name), everythingType,
docProps).getChildRef(); docProps).getChildRef();
@@ -1117,6 +1117,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
fields.add("fdk:with-dash"); fields.add("fdk:with-dash");
fields.add("prop:fdk:duplicate"); fields.add("prop:fdk:duplicate");
fields.add("assoc:fdk:duplicate"); fields.add("assoc:fdk:duplicate");
fields.add("fdk:period");
Form form = this.formService.getForm(new Item(NODE_FORM_ITEM_KIND, everythingNode.toString()), fields); Form form = this.formService.getForm(new Item(NODE_FORM_ITEM_KIND, everythingNode.toString()), fields);
@@ -1136,6 +1137,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
PropertyFieldDefinition textField = null; PropertyFieldDefinition textField = null;
PropertyFieldDefinition underscoreField = null; PropertyFieldDefinition underscoreField = null;
PropertyFieldDefinition dashField = null; PropertyFieldDefinition dashField = null;
PropertyFieldDefinition periodField = null;
PropertyFieldDefinition duplicatePropField = null; PropertyFieldDefinition duplicatePropField = null;
AssociationFieldDefinition duplicateAssocField = null; AssociationFieldDefinition duplicateAssocField = null;
@@ -1168,12 +1170,17 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
duplicateAssocField = (AssociationFieldDefinition)field; duplicateAssocField = (AssociationFieldDefinition)field;
} }
} }
else if (field.getName().equals("fdk:period"))
{
periodField = (PropertyFieldDefinition)field;
}
} }
assertNotNull("Expected to find nameField", nameField); assertNotNull("Expected to find nameField", nameField);
assertNotNull("Expected to find textField", textField); assertNotNull("Expected to find textField", textField);
assertNotNull("Expected to find underscoreField", underscoreField); assertNotNull("Expected to find underscoreField", underscoreField);
assertNotNull("Expected to find dashField", dashField); assertNotNull("Expected to find dashField", dashField);
assertNotNull("Expected to find periodField", periodField);
assertNotNull("Expected to find duplicatePropField", duplicatePropField); assertNotNull("Expected to find duplicatePropField", duplicatePropField);
assertNotNull("Expected to find duplicateAssocField", duplicateAssocField); assertNotNull("Expected to find duplicateAssocField", duplicateAssocField);
@@ -1183,11 +1190,18 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
assertEquals(textValue, values.getFieldData(textField.getDataKeyName()).getValue()); assertEquals(textValue, values.getFieldData(textField.getDataKeyName()).getValue());
assertEquals(underscoreValue, values.getFieldData(underscoreField.getDataKeyName()).getValue()); assertEquals(underscoreValue, values.getFieldData(underscoreField.getDataKeyName()).getValue());
assertEquals(dashValue, values.getFieldData(dashField.getDataKeyName()).getValue()); assertEquals(dashValue, values.getFieldData(dashField.getDataKeyName()).getValue());
assertEquals(periodValue, values.getFieldData(periodField.getDataKeyName()).getValue().toString());
assertEquals(duplicateValue, values.getFieldData(duplicatePropField.getDataKeyName()).getValue()); assertEquals(duplicateValue, values.getFieldData(duplicatePropField.getDataKeyName()).getValue());
List assocs = (List)values.getFieldData(duplicateAssocField.getDataKeyName()).getValue(); FieldData fieldData = values.getFieldData(duplicateAssocField.getDataKeyName());
assertNotNull(fieldData);
List assocs = (List)fieldData.getValue();
assertNotNull(assocs); assertNotNull(assocs);
assertEquals(0, assocs.size()); assertEquals(0, assocs.size());
// check the period property data type parameters were returned
DataTypeParameters dtp = periodField.getDataTypeParameters();
assertNotNull("Expected to find data type parameters for the fdk:period field", dtp);
// update the properties via FormService // update the properties via FormService
FormData data = new FormData(); FormData data = new FormData();

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor;
import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.FormException;
import org.apache.commons.logging.Log;
import com.sun.star.lang.IllegalArgumentException;
public abstract class AbstractFieldProcessor<Data> implements FieldProcessor
{
/* (non-Javadoc)
* @see org.alfresco.repo.forms.field.processor.FieldProcessor#generateField(java.lang.String, java.lang.Object)
*/
public Field generateField(String fieldName, FormCreationData data)
{
Data typedData = checkDataType(data.getItemData());
Field field = generateTypedField(fieldName, data, typedData);
logIfFieldNotFound(field, fieldName);
return field;
}
@SuppressWarnings("unchecked")
private Data checkDataType(Object itemData)
{
Class<Data> expectedType = getExpectedDataType();
if (expectedType.isAssignableFrom(itemData.getClass()))
{
return (Data)itemData;
}
else
{
String msg = "Data object: "+itemData+" is not of expected type: "+expectedType;
throw new FormException(msg, new IllegalArgumentException());
}
}
protected void logIfFieldNotFound(Field fieldInfo, String fieldName)
{
if (fieldInfo == null)
{
Log logger = getLogger();
if (logger!=null && logger.isDebugEnabled())
{
logger.debug("Ignoring unrecognised field \"" + fieldName + "\"");
}
}
}
/**
* Registers this {@link FieldProcessor} with the supplied registry.
*
* @param registry The registry to which this {@link FieldProcessor} is added.
*/
public void setFieldProcessorRegistry(FieldProcessorRegistry registry)
{
registry.register(getRegistryKey(), this);
}
/**
* @return a {@link Log} used to log events that occur while processing fields.
*/
protected abstract Log getLogger();
/**
* @return a {@link String} key used to identify this {@link FieldProcessor} in a {@link FieldProcessorRegistry}.
*/
protected abstract String getRegistryKey();
/**
* @return the expected {@link Class} of the <code>data</code> parameter for the method <code>generateField</code>.
*/
protected abstract Class<Data> getExpectedDataType();
/**
* The method which actually creates the {@link Field}.
* @param fieldName the name of the {@link Field} to be genereated.
* @param formData TODO
* @param typedData the data used to create the field.
* @return a {@link Field} or <code>null</code>.
*/
protected abstract Field generateTypedField(String fieldName, FormCreationData formData, Data typedData);
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor;
import org.alfresco.repo.forms.Field;
public interface FieldProcessor
{
Field generateField(String fieldName, FormCreationData data);
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.repo.forms.Field;
public class FieldProcessorRegistry
{
private final Map<String, FieldProcessor> processors = new HashMap<String, FieldProcessor>();
/**
* The {@link FieldProcessor} to be used if no specific processor can be found.
*/
private FieldProcessor defaultProcessor;
/**
* Registers a {@link FieldProcessor} with this registry using the specified key.
* @param key
* @param processor
*/
public void register(String key, FieldProcessor processor)
{
processors.put(key, processor);
}
/**
* Returns the {@link FieldProcessor} that was registered witht he specified key.
* @param key
* @return
*/
public FieldProcessor get(String key)
{
return processors.get(key);
}
/**
* Attempts to build a {@link Field}. The method first tries to derive a key from the fieldname, then uses this key to look up a {@link FieldProcessor}.
* This {@link FieldProcessor} is then used to generate a {@link Field}.
* @param fieldName the name of the field to be created.
* @param data A data object used by the {@link FieldProcessor} to build the {@link Field}.
* @return a {@link Field} or <code>null</code>.
*/
public Field buildField(String fieldName, FormCreationData data)
{
FieldProcessor fieldProcessor = getFieldProcessor(fieldName);
if (fieldProcessor == null)
{
return null;
}
return fieldProcessor.generateField(fieldName, data);
}
protected FieldProcessor getFieldProcessor(String fieldName)
{
FieldProcessor fieldProcessor = get(getKey(fieldName));
if (fieldProcessor == null && useDefaultProcessor(fieldName))
{
fieldProcessor = defaultProcessor;
}
return fieldProcessor;
}
/**
* Determines if the defaultProcessor should be used.
* @param fieldName
* @return <code>true</code> if the defaultProcessor should be used, otherwise <code>false</code>.
*/
protected boolean useDefaultProcessor(String fieldName)
{
return true;
}
/**
* Derives the key used to look up the {@link FieldProcessor} from the fieldName.
* @param fieldName
* @return the key used to look up the {@link FieldProcessor}.
*/
protected String getKey(String fieldName)
{
return fieldName;
}
/**
* @param defaultProcessor the defaultProcessor to set
*/
public void setDefaultProcessor(FieldProcessor defaultProcessor)
{
this.defaultProcessor = defaultProcessor;
}
}

View File

@@ -19,9 +19,12 @@
package org.alfresco.repo.forms.processor; package org.alfresco.repo.forms.processor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.Form; import org.alfresco.repo.forms.Form;
import org.alfresco.repo.forms.FormData; import org.alfresco.repo.forms.FormData;
import org.alfresco.repo.forms.Item; import org.alfresco.repo.forms.Item;
@@ -40,6 +43,8 @@ public abstract class FilteredFormProcessor<ItemType, PersistType> extends Abstr
protected FilterRegistry<ItemType, PersistType> filterRegistry; protected FilterRegistry<ItemType, PersistType> filterRegistry;
protected FieldProcessorRegistry fieldProcessorRegistry;
/** /**
* Sets the filter registry * Sets the filter registry
* *
@@ -129,6 +134,79 @@ public abstract class FilteredFormProcessor<ItemType, PersistType> extends Abstr
return persistedObject; return persistedObject;
} }
/**
* Generates the form.
*
* @param item The object to generate a form for
* @param fields Restricted list of fields to include
* @param forcedFields List of fields to forcibly include
* @param form The form object being generated
* @param context Map representing optional context that can be used during
* retrieval of the form
*/
protected void internalGenerate(ItemType item, List<String> fields, List<String> forcedFields, Form form, Map<String, Object> context)
{
Log log = getLogger();
if (log.isDebugEnabled()) log.debug("Generating form for: " + item);
// generate the form type and URI for the item.
Item formItem = form.getItem();
formItem.setType(getItemType(item));
formItem.setUrl(getItemURI(item));
Object itemData = makeItemData(item);
FormCreationData data = new FormCreationData(itemData, forcedFields, context);
List<Field> fieldsToAdd;
if (fields != null && fields.size() > 0)
{
fieldsToAdd = generateSelectedFields(fields, data);
}
else
{
fieldsToAdd = generateDefaultFields(data);
}
form.addFields(fieldsToAdd);
if (log.isDebugEnabled()) //
log.debug("Generated form: " + form);
}
/**
* Generates a list of default fields to add if no field names are specified.
* @param data Used for field creation.
* @return a {@link List} of {@link Field Fields} which may be empty.
*/
protected List<Field> generateDefaultFields(FormCreationData data)
{
return Collections.emptyList();
}
protected List<Field> generateSelectedFields(List<String> fields, FormCreationData data)
{
List<Field> fieldData = new ArrayList<Field>(fields.size());
for (String fieldName : fields)
{
Field field = fieldProcessorRegistry.buildField(fieldName, data);
if (field == null)
{
if (getLogger().isWarnEnabled()) {
String msg = "Ignoring unrecognised field \"" + fieldName + "\"";
getLogger().warn(msg);
}
}
else
{
fieldData.add(field);
}
}
return fieldData;
}
/**
* Creates a data object used by the {@link FormProcessor} and {@link FieldProcessor FieldProcessors} to create {@link Field Fields}
* @return
*/
protected abstract Object makeItemData(ItemType item);
/** /**
* Returns a typed Object representing the given item. * Returns a typed Object representing the given item.
* <p> * <p>
@@ -142,18 +220,37 @@ public abstract class FilteredFormProcessor<ItemType, PersistType> extends Abstr
protected abstract ItemType getTypedItem(Item item); protected abstract ItemType getTypedItem(Item item);
/** /**
* Generates the form. * Retrieves a logger instance to log to.
* *
* @param item The object to generate a form for * @return Log instance to log to.
* @param fields Restricted list of fields to include
* @param forcedFields List of fields to forcibly include
* @param form The form object being generated
* @param context Map representing optional context that can be used during
* retrieval of the form
*/ */
protected abstract void internalGenerate(ItemType item, List<String> fields, List<String> forcedFields, Form form, protected abstract Log getLogger();
Map<String, Object> context);
/**
* Returns a {@link String} describing the type fo the specified item.
* @param item
* @return
*/
protected abstract String getItemType(ItemType item);
/**
* Returns the URI location of the specified item.
* @param item
* @return
*/
protected abstract String getItemURI(ItemType item);
/**
* Sets the field processor registry.
*
* @param fieldProcessorRegistry
* The {@link FieldProcessorRegistry} to use.
*/
public void setFieldProcessorRegistry(FieldProcessorRegistry fieldProcessorRegistry)
{
this.fieldProcessorRegistry = fieldProcessorRegistry;
}
/** /**
* Persists the form data. * Persists the form data.
* *

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.forms.processor;
import java.util.List;
import java.util.Map;
/**
* Simple DTO containing various objects needed to generate Forms.
* @author Nick Smith
*/
public class FormCreationData
{
private final Object itemData;
private final List<String> forcedFields;
private final Map<String, Object> context;
public FormCreationData(Object itemData,
List<String> forcedFields,
Map<String, Object> context)
{
this.itemData = itemData;
this.forcedFields = forcedFields;
this.context = context;
}
/**
* @return the itemData
*/
public Object getItemData()
{
return itemData;
}
/**
* @return If the <code>fieldName</code> given is a forced field then
* returns <code>true</code>, otherwise returns <code>false</code>.
*/
public boolean isForcedField(String fieldName)
{
if (forcedFields == null)
return false;
return forcedFields.contains(fieldName);
}
/**
* @return the context
*/
public Map<String, Object> getContext()
{
return context;
}
}

View File

@@ -0,0 +1,125 @@
package org.alfresco.repo.forms.processor.node;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.ASSOC_DATA_PREFIX;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.alfresco.repo.forms.AssociationFieldDefinition;
import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.FieldGroup;
import org.alfresco.repo.forms.AssociationFieldDefinition.Direction;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class AssociationFieldProcessor extends QNameFieldProcessor<AssociationDefinition>
{
private static final Log logger = LogFactory.getLog(AssociationFieldProcessor.class);
public AssociationFieldProcessor()
{
// Constructor for Spring.
}
public AssociationFieldProcessor(NamespaceService namespaceService, DictionaryService dictionaryService)
{
super(namespaceService, dictionaryService);
}
@Override
protected Log getLogger()
{
return logger;
}
@Override
protected FieldGroup getGroup(AssociationDefinition assocDef)
{
// TODO Need to Implement this once Composite Content is implementd.
return null;
}
@Override
public Field makeField(AssociationDefinition assocDef, Object value, FieldGroup group)
{
AssociationFieldDefinition fieldDef = makeAssociationFieldDefinition(assocDef, group);
return new ContentField(assocDef, fieldDef, value);
}
/**
* Gets the associated value from the {@link ItemData}.
* If the value is <code>null</code> the method returns an empty {@link List}.
* If the value is a single Object (assumed to be a NodeRef) it returns a {@link List} containing a {@link String} representation of that object.
* If the value is a {@link Collection} of Objects, returns a {@link List} containing {@link String} representations of all the objects.
* @return An {@link ArrayList} of Strings or <code>null</code>.
*/
@Override
protected Object getValue(QName name, ItemData<?> data)
{
Serializable values = data.getAssociationValue(name);
if (values == null)
{
return Collections.EMPTY_LIST;
}
if (values instanceof Collection<?>)
{
return getValues((Collection<?>) values);
}
return Collections.singletonList(values);
}
private List<String> getValues(Collection<?> collection)
{
List<String> results = new ArrayList<String>(collection.size());
for (Object value : collection)
{
results.add(value.toString());
}
return results;
}
public AssociationFieldDefinition makeAssociationFieldDefinition(final AssociationDefinition assocDef, FieldGroup group)
{
String name = getPrefixedName(assocDef);
String endpointType = assocDef.getTargetClass().getName().toPrefixString(namespaceService);
AssociationFieldDefinition fieldDef = new AssociationFieldDefinition(name,
endpointType,
Direction.TARGET);
populateFieldDefinition(assocDef, fieldDef, group, ASSOC_DATA_PREFIX);
fieldDef.setEndpointMandatory(assocDef.isTargetMandatory());
fieldDef.setEndpointMany(assocDef.isTargetMany());
return fieldDef;
}
@Override
protected String getRegistryKey()
{
return FormFieldConstants.ASSOC;
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.node.QNameFieldProcessor#getTypeDefinition(org.alfresco.service.namespace.QName, org.alfresco.repo.forms.processor.node.ItemData, boolean)
*/
@Override
protected AssociationDefinition getTypeDefinition(QName fullName, ItemData<?> itemData, boolean isForcedField)
{
AssociationDefinition assocDefinition = itemData.getAssociationDefinition(fullName);
if (assocDefinition == null)
{
if (isForcedField)
{
assocDefinition = dictionaryService.getAssociation(fullName);
}
}
return assocDefinition;
}
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
import org.alfresco.repo.forms.AssociationFieldDefinition;
import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.FieldDefinition;
import org.alfresco.repo.forms.PropertyFieldDefinition;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ClassAttributeDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.namespace.QName;
/**
* @author Nick Smith
*/
public class ContentField implements Field
{
private final FieldDefinition fieldDefinition;
private final ClassAttributeDefinition classDefinition;
private final boolean isProperty;
private final Object value;
public ContentField(PropertyDefinition propertyDefinition,
PropertyFieldDefinition fieldDef, Object value)
{
this.isProperty = true;
this.classDefinition = propertyDefinition;
this.fieldDefinition = fieldDef;
this.value = value;
}
public ContentField(AssociationDefinition assocDefinition,
AssociationFieldDefinition fieldDef, Object value)
{
this.isProperty = false;
this.classDefinition = assocDefinition;
this.fieldDefinition = fieldDef;
this.value = value;
}
/**
* This constructor should only be used to create FieldInfo for transient properties such as encoding, mimetype or size.
* @param fieldDef The PropertyFieldDefinition for the transient property.
*/
public ContentField(PropertyFieldDefinition fieldDef, Object value)
{
this.classDefinition = null;
this.isProperty = true;
this.fieldDefinition = fieldDef;
this.value = value;
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.task.Field#isTransient()
*/
public boolean isTransient()
{
return classDefinition == null;
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.task.Field#getFieldDefinition()
*/
public FieldDefinition getFieldDefinition()
{
return this.fieldDefinition;
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.task.Field#getFullName()
*/
public QName getFullName()
{
if (classDefinition == null)
{
return null;
}
return classDefinition.getName();
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.task.Field#getFieldName()
*/
public String getFieldName()
{
return fieldDefinition.getName();
}
/*
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
String type = isTransient()?"Transient ":"";
type += isProperty ? "Property" : "Association";
return "Field: " + getFieldName() + " Type: " + type;
}
public Object getValue()
{
return value;
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
import org.alfresco.repo.forms.processor.FieldProcessorRegistry;
/**
* @author Nick Smith
*
*/
public class ContentModelFieldProcessorRegistry extends FieldProcessorRegistry
{
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.FieldProcessorRegistry#getKey(java.lang.String)
*/
@Override
protected String getKey(String fieldName)
{
String[] parts = fieldName.split(FormFieldConstants.FIELD_NAME_SEPARATOR);
if (parts.length > 0)
{
return parts[0];
}
else
{
return null;
}
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.FieldProcessorRegistry#useDefaultProcessor(java.lang.String)
*/
@Override
protected boolean useDefaultProcessor(String fieldName)
{
// Only use default if the fieldName follows the format
// prefix:localname
String[] parts = fieldName.split(FormFieldConstants.FIELD_NAME_SEPARATOR);
return parts.length == 2;
}
}

View File

@@ -30,21 +30,18 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.forms.AssociationFieldDefinition; import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.FieldDefinition; import org.alfresco.repo.forms.FieldDefinition;
import org.alfresco.repo.forms.FieldGroup;
import org.alfresco.repo.forms.Form; import org.alfresco.repo.forms.Form;
import org.alfresco.repo.forms.FormData; import org.alfresco.repo.forms.FormData;
import org.alfresco.repo.forms.FormException; import org.alfresco.repo.forms.FormException;
import org.alfresco.repo.forms.PropertyFieldDefinition; import org.alfresco.repo.forms.PropertyFieldDefinition;
import org.alfresco.repo.forms.AssociationFieldDefinition.Direction;
import org.alfresco.repo.forms.FormData.FieldData; import org.alfresco.repo.forms.FormData.FieldData;
import org.alfresco.repo.forms.PropertyFieldDefinition.FieldConstraint;
import org.alfresco.repo.forms.processor.FilteredFormProcessor; import org.alfresco.repo.forms.processor.FilteredFormProcessor;
import org.alfresco.repo.forms.processor.FormCreationData;
import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.AssociationDefinition; import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition; import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition;
import org.alfresco.service.cmr.dictionary.Constraint;
import org.alfresco.service.cmr.dictionary.ConstraintDefinition; import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
@@ -60,7 +57,6 @@ import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Period;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
@@ -69,7 +65,6 @@ import org.apache.commons.logging.LogFactory;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.springframework.extensions.surf.util.I18NUtil; import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.util.StringUtils;
/** /**
* Abstract FormProcessor implementation that provides common functionality for * Abstract FormProcessor implementation that provides common functionality for
@@ -201,563 +196,53 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
this.contentService = contentService; this.contentService = contentService;
} }
/** @Override
* Sets up a field definition for the given property. protected List<Field> generateDefaultFields(FormCreationData data)
* <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.
* </p>
*
* @param propDef The PropertyDefinition of the field to generate
* @param form The Form instance to populate
* @param namespaceService NamespaceService instance
*/
public static void generatePropertyField(PropertyDefinition propDef, Form form, NamespaceService namespaceService)
{ {
generatePropertyField(propDef, form, null, null, namespaceService); DefaultFieldBuilder defaultFieldBuilder = new DefaultFieldBuilder(data, fieldProcessorRegistry);
return defaultFieldBuilder.buildDefaultFields();
} }
/** protected Map<QName, AssociationDefinition> populateAssociations(TypeDefinition typeDef)
* 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.
* </p>
*
* @param propDef The PropertyDefinition of the field to generate
* @param form The Form instance to populate
* @param propValue The value of the property field
* @param namespaceService NamespaceService instance
*/
public static void generatePropertyField(PropertyDefinition propDef, Form form, Serializable propValue,
NamespaceService namespaceService)
{ {
generatePropertyField(propDef, form, propValue, null, namespaceService); // we only get the associations of the actual type so
// we also need to manually get associations from any
// mandatory aspects
HashMap<QName, AssociationDefinition> allAssocs = new HashMap<QName, AssociationDefinition>();
allAssocs.putAll(typeDef.getAssociations());
List<AspectDefinition> aspects = typeDef.getDefaultAspects(true);
for (AspectDefinition aspect : aspects) {
allAssocs.putAll(aspect.getAssociations());
}
return Collections.unmodifiableMap(allAssocs);
} }
/** @Override
* Sets up a field definition for the given property. protected ItemData<ItemType> makeItemData(ItemType item)
* <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.
* </p>
*
* @param propDef The PropertyDefinition of the field to generate
* @param form The Form instance to populate
* @param propValue The value of the property field
* @param group The FieldGroup the property field belongs to, can be null
* @param namespaceService NamespaceService instance
*/
@SuppressWarnings("unchecked")
public static void generatePropertyField(PropertyDefinition propDef, Form form, Serializable propValue,
FieldGroup group, NamespaceService namespaceService)
{ {
String propName = propDef.getName().toPrefixString(namespaceService); TypeDefinition baseType = getBaseType(item);
String[] nameParts = QName.splitPrefixedQName(propName); Set<QName> aspects = getAspectNames(item);
PropertyFieldDefinition fieldDef = new PropertyFieldDefinition(propName, propDef.getDataType().getName() TypeDefinition anonType = dictionaryService.getAnonymousType(baseType.getName(), aspects);
.getLocalName()); Map<QName, PropertyDefinition> propDefs = anonType.getProperties();
Map<QName, AssociationDefinition> assocDefs = anonType.getAssociations();
String title = propDef.getTitle(); Map<QName, Serializable> propValues = getPropertyValues(item);
if (title == null) Map<QName, Serializable> assocValues = getAssociationValues(item);
{ Map<String, Object> transientValues = getTransientValues(item);
title = propName; return new ItemData<ItemType>(item, propDefs, assocDefs, propValues, assocValues, transientValues);
}
fieldDef.setLabel(title);
fieldDef.setDefaultValue(propDef.getDefaultValue());
fieldDef.setDescription(propDef.getDescription());
fieldDef.setMandatory(propDef.isMandatory());
fieldDef.setProtectedField(propDef.isProtected());
fieldDef.setRepeating(propDef.isMultiValued());
fieldDef.setGroup(group);
// any property from the system model (sys prefix) should be protected
// the model doesn't currently enforce this so make sure they are not
// editable
if (NamespaceService.SYSTEM_MODEL_1_0_URI.equals(propDef.getName().getNamespaceURI()))
{
fieldDef.setProtectedField(true);
}
// define the data key name and set
String dataKeyName = PROP_DATA_PREFIX + nameParts[0] + DATA_KEY_SEPARATOR + nameParts[1];
fieldDef.setDataKeyName(dataKeyName);
// setup any parameters requried for the data type
if (propDef.getDataType().getName().equals(DataTypeDefinition.PERIOD))
{
// if the property data type is d:period we need to setup a data
// type parameters object to represent the options and rules
PeriodDataTypeParameters periodOptions = new PeriodDataTypeParameters();
Set<String> providers = Period.getProviderNames();
for (String provider : providers)
{
periodOptions.addPeriodProvider(Period.getProvider(provider));
}
fieldDef.setDataTypeParameters(periodOptions);
}
// setup constraints for the property
List<ConstraintDefinition> constraints = propDef.getConstraints();
if (constraints != null && constraints.size() > 0)
{
List<FieldConstraint> fieldConstraints = new ArrayList<FieldConstraint>(constraints.size());
for (ConstraintDefinition constraintDef : constraints)
{
Constraint constraint = constraintDef.getConstraint();
FieldConstraint fieldConstraint = new FieldConstraint(constraint.getType(), constraint.getParameters());
fieldConstraints.add(fieldConstraint);
}
fieldDef.setConstraints(fieldConstraints);
}
form.addFieldDefinition(fieldDef);
// add the property value to the form
if (propValue != null)
{
if (propValue instanceof List)
{
// temporarily add repeating field data as a comma
// separated list, this will be changed to using
// a separate field for each value once we have full
// UI support in place.
propValue = StringUtils.collectionToCommaDelimitedString((List) propValue);
}
else if (propValue instanceof ContentData)
{
// for content properties retrieve the info URL rather than the
// the object value itself
propValue = ((ContentData)propValue).getInfoUrl();
}
form.addData(dataKeyName, propValue);
}
} }
/** protected Set<QName> getAspectNames(ItemType item)
* 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.
* </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)
{ {
generateAssociationField(assocDef, form, null, null, namespaceService); return getBaseType(item).getDefaultAspectNames();
} }
/** protected abstract Map<QName, Serializable> getAssociationValues(ItemType item);
* 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.
* </p>
*
* @param assocDef The AssociationDefinition of the field to generate
* @param form The Form instance to populate
* @param assocValues The values of the association field, can be null
* @param namespaceService NamespaceService instance
*/
@SuppressWarnings("unchecked")
public static void generateAssociationField(AssociationDefinition assocDef, Form form, List assocValues,
NamespaceService namespaceService)
{
generateAssociationField(assocDef, form, assocValues, null, namespaceService);
}
/** protected abstract Map<QName, Serializable> getPropertyValues(ItemType item);
* 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.
* </p>
*
* @param assocDef The AssociationDefinition of the field to generate
* @param form The Form instance to populate
* @param assocValues The values of the association field, can be null
* @param group The FieldGroup the association field belongs to, can be null
* @param namespaceService NamespaceService instance
*/
@SuppressWarnings("unchecked")
public static void generateAssociationField(AssociationDefinition assocDef, Form form, List assocValues,
FieldGroup group, NamespaceService namespaceService)
{
String assocName = assocDef.getName().toPrefixString(namespaceService);
String[] nameParts = QName.splitPrefixedQName(assocName);
AssociationFieldDefinition fieldDef = new AssociationFieldDefinition(assocName, assocDef.getTargetClass()
.getName().toPrefixString(namespaceService), Direction.TARGET);
String title = assocDef.getTitle();
if (title == null)
{
title = assocName;
}
fieldDef.setLabel(title);
fieldDef.setDescription(assocDef.getDescription());
fieldDef.setProtectedField(assocDef.isProtected());
fieldDef.setEndpointMandatory(assocDef.isTargetMandatory());
fieldDef.setEndpointMany(assocDef.isTargetMany());
fieldDef.setGroup(group);
// define the data key name and set protected abstract Map<String, Object> getTransientValues(ItemType item);
String dataKeyName = ASSOC_DATA_PREFIX + nameParts[0] + DATA_KEY_SEPARATOR + nameParts[1];
fieldDef.setDataKeyName(dataKeyName);
// add definition to the form protected abstract TypeDefinition getBaseType(ItemType item);
form.addFieldDefinition(fieldDef);
if (assocValues != null)
{
// add the association value to the form
// determine the type of association values data and extract
// accordingly
List<String> values = new ArrayList<String>(4);
for (Object value : assocValues)
{
if (value instanceof ChildAssociationRef)
{
values.add(((ChildAssociationRef) value).getChildRef().toString());
}
else if (value instanceof AssociationRef)
{
values.add(((AssociationRef) value).getTargetRef().toString());
}
else
{
values.add(value.toString());
}
}
// Add the list as the value for the association.
form.addData(dataKeyName, values);
}
}
/**
* Retrieves a logger instance to log to.
*
* @return Log instance to log to.
*/
protected abstract Log getLogger();
/**
* Sets up the field definitions for all the requested fields.
* <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.
* </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 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 (getLogger().isDebugEnabled())
getLogger().debug("Generating selected fields: " + fields + " and forcing: " + forcedFields);
// get data dictionary definition for node if it is provided
QName type = null;
Map<QName, Serializable> propValues = Collections.emptyMap();
Map<QName, PropertyDefinition> propDefs = null;
Map<QName, AssociationDefinition> assocDefs = null;
if (nodeRef != null)
{
type = this.nodeService.getType(nodeRef);
typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService.getAspects(nodeRef));
// NOTE: the anonymous type returns all property and association
// defs
// for all aspects applied as well as the type
propDefs = typeDef.getProperties();
assocDefs = typeDef.getAssociations();
propValues = this.nodeService.getProperties(nodeRef);
}
else
{
type = typeDef.getName();
// we only get the properties and associations of the actual type so
// we also need to manually get properties and associations from any
// mandatory aspects
propDefs = new HashMap<QName, PropertyDefinition>(16);
assocDefs = new HashMap<QName, AssociationDefinition>(16);
propDefs.putAll(typeDef.getProperties());
assocDefs.putAll(typeDef.getAssociations());
List<AspectDefinition> aspects = typeDef.getDefaultAspects(true);
for (AspectDefinition aspect : aspects)
{
propDefs.putAll(aspect.getProperties());
assocDefs.putAll(aspect.getAssociations());
}
}
for (String fieldName : fields)
{
// try and split the field name
String[] parts = fieldName.split(":");
if (parts.length == 2 || parts.length == 3)
{
boolean foundField = false;
boolean tryProperty = true;
boolean tryAssociation = true;
String qNamePrefix = null;
String localName = null;
if (parts.length == 2)
{
qNamePrefix = parts[0];
localName = parts[1];
}
else
{
// if there are 3 parts to the field name the first one
// represents
// whether the field is a property or association i.e.
// prop:prefix:local
// or assoc:prefix:local, determine the prefix and ensure
// it's valid
if (PROP.equals(parts[0]))
{
tryAssociation = false;
}
else if (ASSOC.equals(parts[0]))
{
tryProperty = false;
}
else
{
if (getLogger().isWarnEnabled())
getLogger()
.warn(
"\""
+ parts[0]
+ "\" is an invalid prefix for requesting a property or association");
continue;
}
qNamePrefix = parts[1];
localName = parts[2];
}
// create qname of field name
QName fullQName = QName.createQName(qNamePrefix, localName, namespaceService);
// try the field as a property
if (tryProperty)
{
// lookup property def on node
PropertyDefinition propDef = propDefs.get(fullQName);
if (propDef != null)
{
// generate the property field
generatePropertyField(propDef, form, propValues.get(fullQName), this.namespaceService);
// no need to try and find an association
tryAssociation = false;
foundField = true;
}
}
// try the field as an association
if (tryAssociation)
{
AssociationDefinition assocDef = assocDefs.get(fullQName);
if (assocDef != null)
{
// generate the association field
generateAssociationField(assocDef, form, (nodeRef != null) ? retrieveAssociationValues(nodeRef,
assocDef) : null, this.namespaceService);
foundField = true;
}
}
// still not found the field, is it a force'd field?
if (!foundField)
{
if (forcedFields != null && forcedFields.size() > 0 && forcedFields.contains(fieldName))
{
generateForcedField(fieldName, form);
}
else if (getLogger().isDebugEnabled())
{
getLogger().debug(
"Ignoring field \"" + fieldName + "\" as it is not defined for the current "
+ ((nodeRef != null) ? "node" : "type")
+ " and it does not appear in the 'force' list");
}
}
}
else
{
// see if the fieldName is a well known transient property
if (TRANSIENT_MIMETYPE.equals(fieldName) || TRANSIENT_ENCODING.equals(fieldName)
|| TRANSIENT_SIZE.equals(fieldName))
{
// if the node type is content or sublcass thereof generate appropriate field
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT))
{
ContentData content = null;
if (nodeRef != null)
{
content = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
}
if (TRANSIENT_MIMETYPE.equals(fieldName))
{
generateMimetypePropertyField(content, form);
}
else if (TRANSIENT_ENCODING.equals(fieldName))
{
generateEncodingPropertyField(content, form);
}
else if (TRANSIENT_SIZE.equals(fieldName))
{
generateSizePropertyField(content, form);
}
}
}
else if (getLogger().isWarnEnabled())
{
getLogger().warn("Ignoring unrecognised field \"" + fieldName + "\"");
}
}
}
}
/**
* Generates a field definition for the given field that is being forced to
* show.
*
* @param fieldName Name of the field to force
* @param form The Form instance to populated
*/
protected void generateForcedField(String fieldName, Form form)
{
if (getLogger().isDebugEnabled())
getLogger().debug("Attempting to force the inclusion of field \"" + fieldName + "\"");
String[] parts = fieldName.split(":");
if (parts.length == 2 || parts.length == 3)
{
boolean foundField = false;
boolean tryProperty = true;
boolean tryAssociation = true;
String qNamePrefix = null;
String localName = null;
if (parts.length == 2)
{
qNamePrefix = parts[0];
localName = parts[1];
}
else
{
// if there are 3 parts to the field name the first one
// represents
// whether the field is a property or association i.e.
// prop:prefix:local
// or assoc:prefix:local, determine the prefix and ensure it's
// valid
if (PROP.equals(parts[0]))
{
tryAssociation = false;
}
else if (ASSOC.equals(parts[0]))
{
tryProperty = false;
}
else
{
if (getLogger().isWarnEnabled())
getLogger().warn(
"\"" + parts[0]
+ "\" is an invalid prefix for requesting a property or association");
return;
}
qNamePrefix = parts[1];
localName = parts[2];
}
// create qname of field name
QName fullQName = QName.createQName(qNamePrefix, localName, namespaceService);
if (tryProperty)
{
// lookup the field as a property in the whole model
PropertyDefinition propDef = this.dictionaryService.getProperty(fullQName);
if (propDef != null)
{
// generate the property field
generatePropertyField(propDef, form, this.namespaceService);
// no need to try and find an association
tryAssociation = false;
foundField = true;
}
}
if (tryAssociation)
{
// lookup the field as an association in the whole model
AssociationDefinition assocDef = this.dictionaryService.getAssociation(fullQName);
if (assocDef != null)
{
// generate the association field
generateAssociationField(assocDef, form, this.namespaceService);
foundField = true;
}
}
if (!foundField && getLogger().isDebugEnabled())
{
getLogger()
.debug(
"Ignoring field \""
+ fieldName
+ "\" as it is not defined for the current node and can not be found in any model");
}
}
else if (getLogger().isWarnEnabled())
{
getLogger().warn("Ignoring unrecognised field \"" + fieldName + "\"");
}
}
/** /**
* Generates the field definition for the transient mimetype property * Generates the field definition for the transient mimetype property

View File

@@ -0,0 +1,150 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.processor.FieldProcessor;
import org.alfresco.repo.forms.processor.FieldProcessorRegistry;
import org.alfresco.repo.forms.processor.FormCreationData;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author Nick Smith
*/
public class DefaultFieldBuilder
{
private static final String ASSOC_WARN = "Could not build Association Field as no valid FieldProcessor was specified";
private static final String PROP_WARNING = "Could not build Property Field as no valid FieldProcessor was specified";
private static final Log MY_LOGGER = LogFactory.getLog(DefaultFieldBuilder.class);
private final FormCreationData formData;
private final ItemData<?> ItemData;
private final FieldProcessorRegistry registry;
private final Log logger;
public DefaultFieldBuilder(FormCreationData data,
FieldProcessorRegistry registry)
{
this(data, registry, MY_LOGGER);
}
public DefaultFieldBuilder(FormCreationData formData,
FieldProcessorRegistry registry,
Log logger)
{
this.logger = logger;
this.formData = formData;
this.registry = registry;
this.ItemData = (ItemData<?>) formData.getItemData();
}
public List<Field> buildDefaultFields()
{
List<Field> assocFields = buildDefaultAssociationFields();
List<Field> propFields = buildDefaultPropertyFields();
List<Field> transFields = buildDefaultTransientFields();
int size = assocFields.size() + propFields.size() + transFields.size();
ArrayList<Field> fields = new ArrayList<Field>(size);
fields.addAll(assocFields);
fields.addAll(propFields);
fields.addAll(transFields);
return fields;
}
public List<Field> buildDefaultPropertyFields()
{
Collection<QName> names = ItemData.getAllPropertyDefinitionNames();
List<Field> fields = new ArrayList<Field>(names.size());
for (QName name : names)
{
fields.add(buildPropertyField(name));
}
return fields;
}
public List<Field> buildDefaultAssociationFields()
{
Collection<QName> names = ItemData.getAllAssociationDefinitionNames();
List<Field> fields = new ArrayList<Field>(names.size());
for (QName name : names)
{
fields.add(buildAssociationField(name));
}
return fields;
}
public List<Field> buildDefaultTransientFields()
{
Collection<String> names = ItemData.getAllTransientFieldNames();
List<Field> fields = new ArrayList<Field>(names.size());
for (String name : names)
{
fields.add(buildTransientField(name));
}
return fields;
}
public Field buildAssociationField(QName assocName)
{
return buildQNameField(assocName, FormFieldConstants.ASSOC, ASSOC_WARN);
}
public Field buildPropertyField(QName propName)
{
return buildQNameField(propName, FormFieldConstants.PROP, PROP_WARNING);
}
private Field buildQNameField(QName assocName, String key, String warningMsg)
{
FieldProcessor fieldProcessor = registry.get(key);
if (fieldProcessor != null && fieldProcessor instanceof QNameFieldProcessor<?>)
{
QNameFieldProcessor<?> qnameProcessor = (QNameFieldProcessor<?>) fieldProcessor;
return qnameProcessor.generateField(assocName, ItemData, false);
}
if (logger.isWarnEnabled())
logger.warn(warningMsg);
return null;
}
public Field buildTransientField(String name)
{
FieldProcessor fieldProcessor = registry.get(name);
if (fieldProcessor != null)
{
return fieldProcessor.generateField(name, formData);
}
if (logger.isWarnEnabled())
logger.warn("Could not build Transient Field: "+ name +" as no FieldProcessor specified");
return null;
}
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.FieldGroup;
import org.alfresco.service.cmr.dictionary.ClassAttributeDefinition;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
public class DefaultFieldProcessor extends QNameFieldProcessor<ClassAttributeDefinition> implements InitializingBean
{
private static final Log logger = LogFactory.getLog(DefaultFieldProcessor.class);
private final AssociationFieldProcessor assocProcessor = new AssociationFieldProcessor();
private final PropertyFieldProcessor propProcessor = new PropertyFieldProcessor();
@Override
protected Log getLogger()
{
return logger;
}
@Override
protected QName getFullName(String name)
{
String[] parts = name.split(FormFieldConstants.FIELD_NAME_SEPARATOR);
int position = parts.length - 1;
String localName = parts[position];// local name is always the last
// string in the arry
position--;
// prefix is always the penultimate string in the array.
String prefix = parts[position];
return QName.createQName(prefix, localName, namespaceService);
}
@Override
public Field generateField(QName fullName, ItemData<?> itemData, boolean isForcedField)
{
Field fieldInfo = propProcessor.generateField(fullName, itemData, isForcedField);
if (fieldInfo == null)
{
fieldInfo = assocProcessor.generateField(fullName, itemData, isForcedField);
}
return fieldInfo;
}
@Override
protected String getRegistryKey()
{
return "";
}
public void afterPropertiesSet() throws Exception
{
ParameterCheck.mandatory("dictionaryService", dictionaryService);
ParameterCheck.mandatory("namespaceService", namespaceService);
assocProcessor.setDictionaryService(dictionaryService);
assocProcessor.setNamespaceService(namespaceService);
propProcessor.setDictionaryService(dictionaryService);
propProcessor.setNamespaceService(namespaceService);
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.node.QNameFieldProcessor#getGroup(org.alfresco.service.cmr.dictionary.ClassAttributeDefinition)
*/
@Override
protected FieldGroup getGroup(ClassAttributeDefinition typeDef)
{
throw new UnsupportedOperationException("This method should never be called!");
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.node.QNameFieldProcessor#getTypeDefinition(org.alfresco.service.namespace.QName, org.alfresco.repo.forms.processor.node.ItemData, boolean)
*/
@Override
protected ClassAttributeDefinition getTypeDefinition(QName fullName, ItemData<?> itemData, boolean isForcedField)
{
throw new UnsupportedOperationException("This method should never be called!");
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.node.QNameFieldProcessor#getValue(org.alfresco.service.namespace.QName, org.alfresco.repo.forms.processor.node.ItemData)
*/
@Override
protected Object getValue(QName fullName, ItemData<?> itemData)
{
throw new UnsupportedOperationException("This method should never be called!");
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.node.QNameFieldProcessor#makeField(org.alfresco.service.cmr.dictionary.ClassAttributeDefinition, java.lang.Object, org.alfresco.repo.forms.FieldGroup)
*/
@Override
protected Field makeField(ClassAttributeDefinition typeDef, Object value, FieldGroup group)
{
throw new UnsupportedOperationException("This method should never be called!");
}
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.ASSOC;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.PROP;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import junit.framework.TestCase;
import org.alfresco.repo.forms.AssociationFieldDefinition;
import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.PropertyFieldDefinition;
import org.alfresco.repo.forms.AssociationFieldDefinition.Direction;
import org.alfresco.repo.forms.processor.FormCreationData;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.NamespaceServiceMemoryImpl;
import org.alfresco.service.namespace.QName;
/**
* @author Nick Smith
*/
public class FieldProcessorTest extends TestCase
{
private static final String PREFIX = "test";
private static final String URI = "http://test/";
private static final String NAME1 = "Name1";
private static final String NAME2 = "Name2";
private static final String DESCRIPTION1 = "Description";
private static final String DESCRIPTION2 = "Another Description";
private static final String TITLE = "Title";
private static final QName qName1 = QName.createQName(URI, NAME1);
private static final QName qName2 = QName.createQName(URI, NAME2);
private NamespaceService namespaceService;
private FormCreationData data;
public void testMakeAssociationFieldDefinition() throws Exception
{
AssociationFieldProcessor processor = new AssociationFieldProcessor();
processor.setNamespaceService(namespaceService);
String name1 = ASSOC + ":"+ PREFIX +":"+ NAME1;
Field field = processor.generateField(name1, data);
AssociationFieldDefinition assocFieldDef = (AssociationFieldDefinition) field.getFieldDefinition();
assertNotNull(assocFieldDef);
assertEquals("assoc_" + PREFIX + "_" + NAME1, assocFieldDef.getDataKeyName());
assertEquals(PREFIX + ":" + NAME1, assocFieldDef.getName());
assertEquals(PREFIX + ":" + NAME1, assocFieldDef.getLabel());
assertEquals(Direction.TARGET, assocFieldDef.getEndpointDirection());
assertEquals(PREFIX + ":Target", assocFieldDef.getEndpointType());
assertEquals(DESCRIPTION1, assocFieldDef.getDescription());
assertFalse(assocFieldDef.isProtectedField());
assertFalse(assocFieldDef.isEndpointMandatory());
assertFalse(assocFieldDef.isEndpointMany());
// Repeat using different params to ensuere the fieldDefinition values
// are dependant on the AssociationDefinition values.
String name2 = ASSOC + ":" + PREFIX +":"+ NAME2;
field = processor.generateField(name2, data);
assocFieldDef = (AssociationFieldDefinition) field.getFieldDefinition();
assertEquals(TITLE, assocFieldDef.getLabel());
assertEquals(DESCRIPTION2, assocFieldDef.getDescription());
assertTrue(assocFieldDef.isProtectedField());
assertTrue(assocFieldDef.isEndpointMandatory());
assertTrue(assocFieldDef.isEndpointMany());
}
public void testMakePropertyFieldDefinition() throws Exception
{
PropertyFieldProcessor processor = new PropertyFieldProcessor();
processor.setNamespaceService(namespaceService);
String name1 = PROP+ ":" + PREFIX + ":" + NAME1;
Field field = processor.generateField(name1, data);
PropertyFieldDefinition propFieldDef = (PropertyFieldDefinition) field.getFieldDefinition();
assertNotNull(propFieldDef);
assertEquals("prop_" + PREFIX + "_" + NAME1, propFieldDef.getDataKeyName());
assertEquals(PREFIX + ":" + NAME1, propFieldDef.getName());
assertEquals(PREFIX + ":" + NAME1, propFieldDef.getLabel());
assertEquals("Default1", propFieldDef.getDefaultValue());
assertEquals(DESCRIPTION1, propFieldDef.getDescription());
assertFalse(propFieldDef.isProtectedField());
assertFalse(propFieldDef.isMandatory());
assertFalse(propFieldDef.isRepeating());// Maps to isMultiValued() on
// Repeat using different params to ensuere the fieldDefinition values
// are dependant on the PropertyDefinition values.
String name2 = PROP + ":" + PREFIX + ":" + NAME2;
field = processor.generateField(name2, data);
propFieldDef = (PropertyFieldDefinition) field.getFieldDefinition();
assertEquals(TITLE, propFieldDef.getLabel());
assertEquals(DESCRIPTION2, propFieldDef.getDescription());
assertEquals("Default2", propFieldDef.getDefaultValue());
assertTrue(propFieldDef.isProtectedField());
assertTrue(propFieldDef.isMandatory());
assertTrue(propFieldDef.isRepeating());
}
/*
* @see junit.framework.TestCase#setUp()
*/
@Override
protected void setUp() throws Exception
{
super.setUp();
namespaceService = makeNamespaceService();
data = new FormCreationData(makeItemData(), null, null);
}
private ItemData<Void> makeItemData()
{
Map<QName, PropertyDefinition> propDefs = makePropertyDefs();
Map<QName, AssociationDefinition> assocDefs = makeAssociationDefs();
Map<QName, Serializable> propValues = new HashMap<QName, Serializable>();
Map<QName, Serializable> assocValues = new HashMap<QName, Serializable>();
Map<String, Object> transientValues = new HashMap<String, Object>();
return new ItemData<Void>(null, propDefs, assocDefs, propValues, assocValues, transientValues);
}
private Map<QName, AssociationDefinition> makeAssociationDefs()
{
QName targetClass = QName.createQName(URI, "Target");
AssociationDefinition assocDef1 = MockClassAttributeDefinition.mockAssociationDefinition(
qName1, targetClass,
null,// Defalt title, so sets label to be same as name.
DESCRIPTION1, false, false, false);
MockClassAttributeDefinition assocDef2 = MockClassAttributeDefinition.mockAssociationDefinition(
qName2, targetClass,
TITLE, DESCRIPTION2,
true, true, true);
Map<QName, AssociationDefinition> assocDefs = new HashMap<QName, AssociationDefinition>();
assocDefs.put(qName1, assocDef1);
assocDefs.put(qName2, assocDef2);
return assocDefs;
}
private Map<QName, PropertyDefinition> makePropertyDefs()
{
QName dataTypeName = QName.createQName(URI, "Type");
PropertyDefinition propDef1 = MockClassAttributeDefinition.mockPropertyDefinition(
qName1, dataTypeName,
null,// Defalt title, so sets label to be same as name.
DESCRIPTION1, false,
"Default1", false, false);
PropertyDefinition propDef2 = MockClassAttributeDefinition.mockPropertyDefinition(
qName2, dataTypeName,
TITLE,
DESCRIPTION2, true,
"Default2", true, true);
Map<QName, PropertyDefinition> propDefs = new HashMap<QName, PropertyDefinition>();
propDefs.put(qName1, propDef1);
propDefs.put(qName2, propDef2);
return propDefs;
}
private NamespaceService makeNamespaceService()
{
NamespaceServiceMemoryImpl nsService = new NamespaceServiceMemoryImpl();
namespaceService.registerNamespace(PREFIX, URI);
return nsService;
}
}

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.FieldGroup;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.namespace.NamespaceService;
/**
* Utility class to assist in creating {@link Field Fields} which represent
* {@link PropertyDefinition PropertyDefinitions} and
* {@link AssociationDefinition AssociationDefinitions}
*
* @author Nick Smith
*
*/
public class FieldUtils
{
public static Field makePropertyField(
PropertyDefinition property,
Object value,
FieldGroup group,
NamespaceService namespaceService)
{
PropertyFieldProcessor processor = new PropertyFieldProcessor(namespaceService, null);
return processor.makeField(property, value, group);
}
public static List<Field> makePropertyFields(
Collection<PropertyDefinition> propDefs,
FieldGroup group,
NamespaceService namespaceService)
{
return makePropertyFields(propDefs, null, group, namespaceService);
}
public static List<Field> makePropertyFields(
Map<PropertyDefinition, Object> propDefAndValue,
FieldGroup group,
NamespaceService namespaceService)
{
return makePropertyFields(propDefAndValue.keySet(), propDefAndValue, group, namespaceService);
}
public static List<Field> makePropertyFields(
Collection<PropertyDefinition> propDefs,
Map<PropertyDefinition, Object> values,
FieldGroup group,
NamespaceService namespaceService)
{
PropertyFieldProcessor processor = new PropertyFieldProcessor(namespaceService, null);
ArrayList<Field> fields = new ArrayList<Field>(propDefs.size());
for (PropertyDefinition propDef : propDefs)
{
Object value = values==null?null:values.get(propDef);
Field field = processor.makeField(propDef, value, group);
fields.add(field);
}
return fields;
}
public static Field makeAssociationField(
AssociationDefinition assocDef,
Object value,
FieldGroup group,
NamespaceService namespaceService)
{
AssociationFieldProcessor processor = new AssociationFieldProcessor(namespaceService, null);
return processor.makeField(assocDef, value, group);
}
public static List<Field> makeAssociationFields(
Collection<AssociationDefinition> assocDefs,
FieldGroup group,
NamespaceService namespaceService)
{
return makeAssociationFields(assocDefs, null, group, namespaceService);
}
public static List<Field> makeAssociationFields(
Map<AssociationDefinition, Object> assocDefAndValue,
FieldGroup group,
NamespaceService namespaceService)
{
return makeAssociationFields(assocDefAndValue.keySet(), assocDefAndValue, group, namespaceService);
}
public static List<Field> makeAssociationFields(
Collection<AssociationDefinition> assocDefs,
Map<AssociationDefinition, Object> values,
FieldGroup group,
NamespaceService namespaceService)
{
AssociationFieldProcessor processor = new AssociationFieldProcessor(namespaceService, null);
ArrayList<Field> fields = new ArrayList<Field>(assocDefs.size());
for (AssociationDefinition propDef : assocDefs)
{
Object value = values==null?null:values.get(propDef);
Field field = processor.makeField(propDef, value, group);
fields.add(field);
}
return fields;
}
}

View File

@@ -31,6 +31,8 @@ public interface FormFieldConstants
public static final String ASSOC = "assoc"; public static final String ASSOC = "assoc";
public static final String FIELD_NAME_SEPARATOR = ":";
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;
@@ -47,4 +49,7 @@ public interface FormFieldConstants
public static final String TRANSIENT_ENCODING = "encoding"; public static final String TRANSIENT_ENCODING = "encoding";
public static final String ADDED = "added";
public static final String REMOVED = "removed";
} }

View File

@@ -0,0 +1,194 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.forms.processor.node;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.namespace.QName;
/**
* Simple data transfer object used by the ContentModelFormProcessor and its
* descendants.
*
* @author Nick Smith
*/
public class ItemData<ItemType> implements TransientValueGetter
{
private final ItemType item;
private final Map<QName, PropertyDefinition> propDefs;
private final Map<QName, AssociationDefinition> assocDefs;
private final Map<QName, Serializable> propValues;
private final Map<QName, Serializable> assocValues;
private final Map<String, Object> transientValues;
public ItemData(ItemType item,
Map<QName, PropertyDefinition> propDefs,
Map<QName, AssociationDefinition> assocDefs,
Map<QName, Serializable> propValues,
Map<QName, Serializable> assocValues,
Map<String, Object> transientValues)
{
this.item = item;
this.propDefs = propDefs;
this.assocDefs = assocDefs;
this.propValues = propValues;
this.assocValues = assocValues;
this.transientValues = transientValues;
}
/**
* @return the item
*/
public ItemType getItem()
{
return this.item;
}
/**
* @return the property value associated with the <code>key</code> or
* <code>null</null> if none exists.
*/
public Serializable getPropertyValue(QName key)
{
return getValue(key, propValues);
}
/**
* @return the association value associated with the <code>key</code> or
* <code>null</null> if none exists.
*/
public Serializable getAssociationValue(QName key)
{
return getValue(key, assocValues);
}
/**
* @return the value associated with the transient property specified by the
* fieldName or <code>null</null> if none exists.
*/
public Object getTransientValue(String fieldName)
{
Object value = null;
if (transientValues != null)
{
value = transientValues.get(fieldName);
}
return value;
}
private Serializable getValue(QName key, Map<QName, Serializable> values)
{
Serializable value = null;
if (values != null)
{
value = values.get(key);
}
return value;
}
/**
* @return The PropertyDefinition associated with the <code>propName</code>
* or <code>null</code> if none exists.
*/
public PropertyDefinition getPropertyDefinition(QName propName)
{
PropertyDefinition propDef = null;
if (propDefs != null)
{
propDef = propDefs.get(propName);
}
return propDef;
}
/**
* @return The AssociationDefinition associated with the
* <code>assocName</code> or <code>null</code> if none exists.
*/
public AssociationDefinition getAssociationDefinition(QName assocName)
{
AssociationDefinition assocDef = null;
if (assocDefs != null)
{
assocDef = assocDefs.get(assocName);
}
return assocDef;
}
/**
* @return Returns an unmodifiable Collection containing all the association
* definition {@link QName QNames} for the item.
*/
public Collection<QName> getAllAssociationDefinitionNames()
{
if (assocDefs == null)
{
return Collections.emptyList();
}
else
{
return Collections.unmodifiableCollection(assocDefs.keySet());
}
}
/**
* @return Returns an unmodifiable Collection containing all the property
* definitions for the item.
*/
public Collection<QName> getAllPropertyDefinitionNames()
{
if (propDefs == null)
{
return Collections.emptyList();
}
else
{
return Collections.unmodifiableCollection(propDefs.keySet());
}
}
/**
* @return Returns an unmodifiable Collection containing all the property
* definitions for the item.
*/
public Collection<String> getAllTransientFieldNames()
{
if (transientValues == null)
{
return Collections.emptyList();
}
else
{
return Collections.unmodifiableCollection(transientValues.keySet());
}
}
}

View File

@@ -0,0 +1,372 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.forms.processor.node;
import static org.mockito.Mockito.*;
import java.util.List;
import org.alfresco.repo.dictionary.IndexTokenisationMode;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.ModelDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.namespace.QName;
/**
* @author Nick Smith
*/
public class MockClassAttributeDefinition implements PropertyDefinition, AssociationDefinition
{
private final QName name;
private DataTypeDefinition dataType = mock(DataTypeDefinition.class);
private ClassDefinition targetClass = mock(ClassDefinition.class);
private String description = null;
private String defaultValue = null;
private String title = null;
private boolean targetMandatory = false;
private boolean targetMany = false;
private boolean isProtected = false;
private boolean mandatory = false;
private boolean multiValued = false;
private MockClassAttributeDefinition(QName name)
{
this.name = name;
}
private MockClassAttributeDefinition(QName name, String title, String description, boolean isProtected)
{
this(name);
this.title = title;
this.description = description;
this.isProtected = isProtected;
}
public static MockClassAttributeDefinition mockPropertyDefinition(QName name, QName dataTypeName)
{
MockClassAttributeDefinition mock = new MockClassAttributeDefinition(name);
mockDataTypeName(dataTypeName, mock);
return mock;
}
public static MockClassAttributeDefinition mockPropertyDefinition(QName name,//
QName dataTypeName,//
String title,//
String description,//
boolean isProtected,//
String defaultValue,//
boolean Mandatory,//
boolean multiValued)
{
MockClassAttributeDefinition mock = new MockClassAttributeDefinition(name, title, description, isProtected);
mockDataTypeName(dataTypeName, mock);
mock.defaultValue = defaultValue;
mock.mandatory = Mandatory;
mock.multiValued = multiValued;
return mock;
}
public static MockClassAttributeDefinition mockAssociationDefinition(QName name, QName targetClassName)
{
MockClassAttributeDefinition mock = new MockClassAttributeDefinition(name);
mockTargetClassName(targetClassName, mock);
return mock;
}
public static MockClassAttributeDefinition mockAssociationDefinition(QName name,//
QName targetClassName,//
String title,//
String description,//
boolean isProtected,//
boolean targetMandatory,//
boolean targetMany)
{
MockClassAttributeDefinition mock = new MockClassAttributeDefinition(name, title, description, isProtected);
mockTargetClassName(targetClassName, mock);
mock.targetMandatory = targetMandatory;
mock.targetMany = targetMany;
return mock;
}
private static void mockDataTypeName(QName dataTypeName, MockClassAttributeDefinition mock)
{
when(mock.dataType.getName()).thenReturn(dataTypeName);
}
private static void mockTargetClassName(QName targetClassName, MockClassAttributeDefinition mock)
{
when(mock.targetClass.getName()).thenReturn(targetClassName);
}
/*
* @see
* org.alfresco.service.cmr.dictionary.PropertyDefinition#getConstraints()
*/
public List<ConstraintDefinition> getConstraints()
{
return null;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.PropertyDefinition#getContainerClass
* ()
*/
public ClassDefinition getContainerClass()
{
return null;
}
/*
* @see org.alfresco.service.cmr.dictionary.PropertyDefinition#getDataType()
*/
public DataTypeDefinition getDataType()
{
return dataType;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.PropertyDefinition#getDefaultValue()
*/
public String getDefaultValue()
{
return defaultValue;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.PropertyDefinition#getDescription()
*/
public String getDescription()
{
return description;
}
/*
* @seeorg.alfresco.service.cmr.dictionary.PropertyDefinition#
* getIndexTokenisationMode()
*/
public IndexTokenisationMode getIndexTokenisationMode()
{
return null;
}
/*
* @see org.alfresco.service.cmr.dictionary.PropertyDefinition#getModel()
*/
public ModelDefinition getModel()
{
return null;
}
/*
* @see org.alfresco.service.cmr.dictionary.PropertyDefinition#getName()
*/
public QName getName()
{
return name;
}
/*
* @see org.alfresco.service.cmr.dictionary.PropertyDefinition#getTitle()
*/
public String getTitle()
{
return title;
}
/*
* @see org.alfresco.service.cmr.dictionary.PropertyDefinition#isIndexed()
*/
public boolean isIndexed()
{
return false;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.PropertyDefinition#isIndexedAtomically
* ()
*/
public boolean isIndexedAtomically()
{
return false;
}
/*
* @see org.alfresco.service.cmr.dictionary.PropertyDefinition#isMandatory()
*/
public boolean isMandatory()
{
return mandatory;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.PropertyDefinition#isMandatoryEnforced
* ()
*/
public boolean isMandatoryEnforced()
{
return false;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.PropertyDefinition#isMultiValued()
*/
public boolean isMultiValued()
{
return multiValued;
}
/*
* @see org.alfresco.service.cmr.dictionary.PropertyDefinition#isOverride()
*/
public boolean isOverride()
{
return false;
}
/*
* @see org.alfresco.service.cmr.dictionary.PropertyDefinition#isProtected()
*/
public boolean isProtected()
{
return isProtected;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.PropertyDefinition#isStoredInIndex()
*/
public boolean isStoredInIndex()
{
return false;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.AssociationDefinition#getSourceClass
* ()
*/
public ClassDefinition getSourceClass()
{
return null;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.AssociationDefinition#getSourceRoleName
* ()
*/
public QName getSourceRoleName()
{
return null;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.AssociationDefinition#getTargetClass
* ()
*/
public ClassDefinition getTargetClass()
{
return targetClass;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.AssociationDefinition#getTargetRoleName
* ()
*/
public QName getTargetRoleName()
{
return null;
}
/*
* @see org.alfresco.service.cmr.dictionary.AssociationDefinition#isChild()
*/
public boolean isChild()
{
return false;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.AssociationDefinition#isSourceMandatory
* ()
*/
public boolean isSourceMandatory()
{
return false;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.AssociationDefinition#isSourceMany()
*/
public boolean isSourceMany()
{
return false;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.AssociationDefinition#isTargetMandatory
* ()
*/
public boolean isTargetMandatory()
{
return targetMandatory;
}
/*
* @seeorg.alfresco.service.cmr.dictionary.AssociationDefinition#
* isTargetMandatoryEnforced()
*/
public boolean isTargetMandatoryEnforced()
{
return false;
}
/*
* @see
* org.alfresco.service.cmr.dictionary.AssociationDefinition#isTargetMany()
*/
public boolean isTargetMany()
{
return targetMany;
}
}

View File

@@ -0,0 +1,75 @@
package org.alfresco.repo.forms.processor.node;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.ASSOC;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.PROP;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.TRANSIENT_ENCODING;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.TRANSIENT_MIMETYPE;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.TRANSIENT_SIZE;
import org.alfresco.repo.forms.processor.FieldProcessor;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.namespace.NamespaceService;
public class MockFieldProcessorRegistry extends ContentModelFieldProcessorRegistry
{
public MockFieldProcessorRegistry(NamespaceService namespaceService, DictionaryService dictionaryService)
{
register(PROP, makePropertyFieldProcessor(namespaceService, dictionaryService));
register(ASSOC, makeAssociationFieldProcessor(namespaceService, dictionaryService));
register(TRANSIENT_ENCODING, makeEncodingFieldProcessor(namespaceService));
register(TRANSIENT_MIMETYPE, makeMimetypeFieldProcessor(namespaceService));
register(TRANSIENT_SIZE, makeSizeFieldProcessor(namespaceService));
setDefaultProcessor(makeDefaultFieldProcessor(namespaceService, dictionaryService));
}
private FieldProcessor makeDefaultFieldProcessor(NamespaceService namespaceService,
DictionaryService dictionaryService)
{
DefaultFieldProcessor processor = new DefaultFieldProcessor();
processor.setDictionaryService(dictionaryService);
processor.setNamespaceService(namespaceService);
try
{
processor.afterPropertiesSet();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
return processor;
}
private TransientEncodingFieldProcessor makeEncodingFieldProcessor(NamespaceService namespaceService)
{
return new TransientEncodingFieldProcessor();
}
private TransientMimetypeFieldProcessor makeMimetypeFieldProcessor(NamespaceService namespaceService)
{
return new TransientMimetypeFieldProcessor();
}
private TransientSizeFieldProcessor makeSizeFieldProcessor(NamespaceService namespaceService)
{
return new TransientSizeFieldProcessor();
}
private PropertyFieldProcessor makePropertyFieldProcessor(NamespaceService namespaceService,
DictionaryService dictionaryService)
{
PropertyFieldProcessor processor = new PropertyFieldProcessor();
processor.setDictionaryService(dictionaryService);
processor.setNamespaceService(namespaceService);
return processor;
}
private AssociationFieldProcessor makeAssociationFieldProcessor(NamespaceService namespaceService,
DictionaryService dictionaryService)
{
AssociationFieldProcessor processor = new AssociationFieldProcessor();
processor.setDictionaryService(dictionaryService);
processor.setNamespaceService(namespaceService);
return processor;
}
}

View File

@@ -20,21 +20,24 @@
package org.alfresco.repo.forms.processor.node; package org.alfresco.repo.forms.processor.node;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.forms.Form;
import org.alfresco.repo.forms.FormData; import org.alfresco.repo.forms.FormData;
import org.alfresco.repo.forms.FormNotFoundException; import org.alfresco.repo.forms.FormNotFoundException;
import org.alfresco.repo.forms.Item; import org.alfresco.repo.forms.Item;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -89,7 +92,8 @@ public class NodeFormProcessor extends ContentModelFormProcessor<NodeRef, NodeRe
{ {
// ignored for now, dealt with below // ignored for now, dealt with below
if (logger.isDebugEnabled()) logger.debug("NodeRef creation failed for: " + item.getId(), iae); if (logger.isDebugEnabled())
logger.debug("NodeRef creation failed for: " + item.getId(), iae);
} }
} }
} }
@@ -110,131 +114,114 @@ public class NodeFormProcessor extends ContentModelFormProcessor<NodeRef, NodeRe
} }
} }
/*
* @see /* (non-Javadoc)
* org.alfresco.repo.forms.processor.FilteredFormProcessor#internalGenerate * @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getItemType(java.lang.Object)
* (java.lang.Object, java.util.List, java.util.List,
* org.alfresco.repo.forms.Form, java.util.Map)
*/ */
@Override @Override
protected void internalGenerate(NodeRef item, List<String> fields, List<String> forcedFields, Form form, protected String getItemType(NodeRef item)
Map<String, Object> context)
{ {
if (logger.isDebugEnabled()) logger.debug("Generating form for: " + item); QName type = this.nodeService.getType(item);
return type.toPrefixString(this.namespaceService);
// generate the form for the node }
generateNode(item, fields, forcedFields, form);
/* (non-Javadoc)
if (logger.isDebugEnabled()) logger.debug("Generated form: " + form); * @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getItemURI(java.lang.Object)
*/
@Override
protected String getItemURI(NodeRef item)
{
StringBuilder builder = new StringBuilder("/api/node/");
builder.append(item.getStoreRef().getProtocol()).append("/");
builder.append(item.getStoreRef().getIdentifier()).append("/");
builder.append(item.getId());
return builder.toString();
}
@Override
protected Map<QName, Serializable> getPropertyValues(NodeRef nodeRef)
{
return nodeService.getProperties(nodeRef);
} }
/** @Override
* Sets up the Form object for the given NodeRef protected Map<QName, Serializable> getAssociationValues(NodeRef item)
*
* @param nodeRef The NodeRef to generate a Form for
* @param fields Restricted list of fields to include
* @param forcedFields List of fields to forcibly include
* @param form The Form instance to populate
*/
protected void generateNode(NodeRef nodeRef, List<String> fields, List<String> forcedFields, Form form)
{ {
// set the type and URL of the item HashMap<QName, Serializable> assocs = new HashMap<QName, Serializable>();
QName type = this.nodeService.getType(nodeRef); List<AssociationRef> targetAssocs = nodeService.getTargetAssocs(item, RegexQNamePattern.MATCH_ALL);
setFormItemType(form, type.toPrefixString(this.namespaceService)); List<ChildAssociationRef> childAssocs = nodeService.getChildAssocs(item);
for (ChildAssociationRef childAssoc : childAssocs)
StringBuilder builder = new StringBuilder("/api/node/");
builder.append(nodeRef.getStoreRef().getProtocol()).append("/");
builder.append(nodeRef.getStoreRef().getIdentifier()).append("/");
builder.append(nodeRef.getId());
setFormItemUrl(form, builder.toString());
if (fields != null && fields.size() > 0)
{ {
generateSelectedFields(nodeRef, null, fields, forcedFields, form); QName name = childAssoc.getTypeQName();
NodeRef target = childAssoc.getChildRef();
addAssocToMap(name, target, assocs);
}
for (AssociationRef associationRef : targetAssocs)
{
QName name = associationRef.getTypeQName();
NodeRef target = associationRef.getTargetRef();
addAssocToMap(name, target, assocs);
}
return assocs;
}
@SuppressWarnings("unchecked")
private void addAssocToMap(QName name, NodeRef target, HashMap<QName, Serializable> assocs)
{
Serializable value = assocs.get(name);
if(value == null)
{
LinkedHashSet<NodeRef> values = new LinkedHashSet<NodeRef>();
values.add(target);
assocs.put(name, values);
} }
else else
{ {
// setup field definitions and data if(value instanceof Set<?>)
generateAllPropertyFields(nodeRef, form);
generateAllAssociationFields(nodeRef, form);
generateTransientFields(nodeRef, form);
}
// process working copy nodes, just returns if it's not
processWorkingCopy(nodeRef, form);
}
/**
* Sets up the field definitions for all the node's properties.
*
* @param nodeRef The NodeRef of the node being setup
* @param form The Form instance to populate
*/
protected void generateAllPropertyFields(NodeRef nodeRef, Form form)
{
// get data dictionary definition for node
QName type = this.nodeService.getType(nodeRef);
TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService.getAspects(nodeRef));
// iterate round the property definitions for the node and create
// the equivalent field definition and setup the data for the property
Map<QName, PropertyDefinition> propDefs = typeDef.getProperties();
Map<QName, Serializable> propValues = this.nodeService.getProperties(nodeRef);
for (PropertyDefinition propDef : propDefs.values())
{
generatePropertyField(propDef, form, propValues.get(propDef.getName()), this.namespaceService);
}
}
/**
* Sets up the field definitions for all the node's associations.
*
* @param nodeRef The NodeRef of the node being setup
* @param form The Form instance to populate
*/
protected void generateAllAssociationFields(NodeRef nodeRef, Form form)
{
// get data dictionary definition for the node
QName type = this.nodeService.getType(nodeRef);
TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService.getAspects(nodeRef));
// iterate round the association defintions and setup field definition
Map<QName, AssociationDefinition> assocDefs = typeDef.getAssociations();
for (AssociationDefinition assocDef : assocDefs.values())
{
generateAssociationField(assocDef, form, retrieveAssociationValues(nodeRef, assocDef),
this.namespaceService);
}
}
/**
* Sets up the field definitions for any transient fields that may be
* useful, for example, 'mimetype', 'size' and 'encoding'.
*
* @param nodeRef The NodeRef of the node being setup
* @param form The Form instance to populate
*/
protected void generateTransientFields(NodeRef nodeRef, Form form)
{
// if the node is content add the 'mimetype', 'size' and 'encoding'
// fields.
QName type = this.nodeService.getType(nodeRef);
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT))
{
ContentData content = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
if (content != null)
{ {
// setup mimetype field ((Set<NodeRef>)value).add(target);
generateMimetypePropertyField(content, form);
// setup encoding field
generateEncodingPropertyField(content, form);
// setup size field
generateSizePropertyField(content, form);
} }
} }
} }
@Override
protected Map<String, Object> getTransientValues(NodeRef item)
{
Map<String, Object> values = new HashMap<String, Object>(3);
ContentData contentData = getContentData(item);
if(contentData!=null)
{
values.put(TRANSIENT_ENCODING, contentData.getEncoding());
values.put(TRANSIENT_MIMETYPE, contentData.getMimetype());
values.put(TRANSIENT_SIZE, contentData.getSize());
}
return values;
}
@Override
protected Set<QName> getAspectNames(NodeRef nodeRef)
{
return nodeService.getAspects(nodeRef);
}
@Override
protected TypeDefinition getBaseType(NodeRef nodeRef)
{
QName typeName = nodeService.getType(nodeRef);
return dictionaryService.getType(typeName);
}
private ContentData getContentData(NodeRef nodeRef)
{
// Checks if the node is content and if so gets the ContentData
QName type = this.nodeService.getType(nodeRef);
ContentData content = null;
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT))
{
content = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
}
return content;
}
/* /*
* @see * @see
@@ -244,7 +231,8 @@ public class NodeFormProcessor extends ContentModelFormProcessor<NodeRef, NodeRe
@Override @Override
protected NodeRef internalPersist(NodeRef item, FormData data) protected NodeRef internalPersist(NodeRef item, FormData data)
{ {
if (logger.isDebugEnabled()) logger.debug("Persisting form for: " + item); if (logger.isDebugEnabled())
logger.debug("Persisting form for: " + item);
// persist the node // persist the node
persistNode(item, data); persistNode(item, data);

View File

@@ -0,0 +1,193 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.PROP_DATA_PREFIX;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.FieldGroup;
import org.alfresco.repo.forms.PropertyFieldDefinition;
import org.alfresco.repo.forms.PropertyFieldDefinition.FieldConstraint;
import org.alfresco.service.cmr.dictionary.Constraint;
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.Period;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;
public class PropertyFieldProcessor extends QNameFieldProcessor<PropertyDefinition>
{
private static final Log logger = LogFactory.getLog(PropertyFieldProcessor.class);
public PropertyFieldProcessor()
{
// Constructor for Spring.
}
public PropertyFieldProcessor(NamespaceService namespaceService, DictionaryService dictionaryService)
{
super(namespaceService, dictionaryService);
}
@Override
protected Log getLogger()
{
return logger;
}
@Override
protected PropertyDefinition getTypeDefinition(QName fullName, ItemData<?> itemData, boolean isForcedField)
{
PropertyDefinition propDef = itemData.getPropertyDefinition(fullName);
if (propDef == null)
{
if (isForcedField)
{
propDef = dictionaryService.getProperty(fullName);
}
}
return propDef;
}
@Override
public Field makeField(PropertyDefinition propDef, Object value, FieldGroup group)
{
PropertyFieldDefinition fieldDef = makePropertyFieldDefinition(propDef, group);
return new ContentField(propDef, fieldDef, value);
}
@Override
protected FieldGroup getGroup(PropertyDefinition propDef)
{
// TODO Need to Implement this once Composite Content is implementd.
return null;
}
@Override
protected Object getValue(QName name, ItemData<?> data)
{
Serializable value = data.getPropertyValue(name);
if (value == null)
{
return null;
}
if (value instanceof Collection<?>)
{
// temporarily add repeating field data as a comma
// separated list, this will be changed to using
// a separate field for each value once we have full
// UI support in place.
Collection<?> values = (Collection<?>) value;
return StringUtils.collectionToCommaDelimitedString(values);
}
else if (value instanceof ContentData)
{
// for content properties retrieve the info URL rather than the
// the object value itself
ContentData contentData = (ContentData)value;
return contentData.getInfoUrl();
}
return value;
}
private PropertyFieldDefinition makePropertyFieldDefinition(final PropertyDefinition propDef, FieldGroup group)
{
String name = getPrefixedName(propDef);
QName dataType = propDef.getDataType().getName();
PropertyFieldDefinition fieldDef = new PropertyFieldDefinition(name, dataType.getLocalName());
populateFieldDefinition(propDef, fieldDef, group, PROP_DATA_PREFIX);
fieldDef.setDefaultValue(propDef.getDefaultValue());
fieldDef.setMandatory(propDef.isMandatory());
fieldDef.setRepeating(propDef.isMultiValued());
// any property from the system model (sys prefix) should be protected
// the model doesn't
// currently enforce this so make sure they are not editable
if (NamespaceService.SYSTEM_MODEL_1_0_URI.equals(propDef.getName().getNamespaceURI()))
{
fieldDef.setProtectedField(true);
}
// If the property data type is d:period we need to setup a data
// type parameters object to represent the options and rules
if (dataType.equals(DataTypeDefinition.PERIOD))
{
PeriodDataTypeParameters periodOptions = getPeriodOptions();
fieldDef.setDataTypeParameters(periodOptions);
}
// setup constraints for the property
List<FieldConstraint> fieldConstraints = makeFieldConstraints(propDef);
fieldDef.setConstraints(fieldConstraints);
return fieldDef;
}
private List<FieldConstraint> makeFieldConstraints(PropertyDefinition propDef)
{
List<FieldConstraint> fieldConstraints = null;
List<ConstraintDefinition> constraints = propDef.getConstraints();
if (constraints != null && constraints.size() > 0)
{
fieldConstraints = new ArrayList<FieldConstraint>(constraints.size());
for (ConstraintDefinition constraintDef : constraints)
{
Constraint constraint = constraintDef.getConstraint();
String type = constraint.getType();
Map<String, Object> params = constraint.getParameters();
FieldConstraint fieldConstraint = new FieldConstraint(type, params);
fieldConstraints.add(fieldConstraint);
}
}
return fieldConstraints;
}
private PeriodDataTypeParameters getPeriodOptions()
{
PeriodDataTypeParameters periodOptions = new PeriodDataTypeParameters();
Set<String> providers = Period.getProviderNames();
for (String provider : providers)
{
periodOptions.addPeriodProvider(Period.getProvider(provider));
}
return periodOptions;
}
@Override
protected String getRegistryKey()
{
return FormFieldConstants.PROP;
}
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.DATA_KEY_SEPARATOR;
import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.FieldDefinition;
import org.alfresco.repo.forms.FieldGroup;
import org.alfresco.repo.forms.processor.AbstractFieldProcessor;
import org.alfresco.repo.forms.processor.FormCreationData;
import org.alfresco.service.cmr.dictionary.ClassAttributeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
public abstract class QNameFieldProcessor<Type extends ClassAttributeDefinition> extends AbstractFieldProcessor<ItemData<?>>
{
protected NamespaceService namespaceService;
protected DictionaryService dictionaryService;
public QNameFieldProcessor()
{
// Constructor for Spring.
}
public QNameFieldProcessor(NamespaceService namespaceService, DictionaryService dictionaryService)
{
this.namespaceService = namespaceService;
this.dictionaryService = dictionaryService;
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.field.processor.AbstractFieldProcessor#generateTypedField(java.lang.String, java.lang.Object)
*/
@Override
protected Field generateTypedField(String fieldName, FormCreationData formData, ItemData<?> typedData)
{
QName fullName = getFullName(fieldName);
boolean isForcedField = formData.isForcedField(fieldName);
Field field = generateField(fullName, typedData, isForcedField);
return field;
}
protected QName getFullName(String name)
{
String[] parts = name.split(FormFieldConstants.FIELD_NAME_SEPARATOR);
String prefix = parts[1];
String localName = parts[2];
return QName.createQName(prefix, localName, namespaceService);
}
protected String getPrefixedName(ClassAttributeDefinition attribDef)
{
return attribDef.getName().toPrefixString(namespaceService);
}
public Field generateField(QName fullName, ItemData<?> itemData, boolean isForcedField)
{
Type propDef = getTypeDefinition(fullName, itemData, isForcedField);
Field field = null;
if (propDef != null)
{
Object value = getValue(fullName, itemData);
FieldGroup group = getGroup(propDef);
field = makeField(propDef, value, group);
}
return field;
}
/**
* Sets several properties on the {@link FieldDefinition}, including name,
* label, description, dataKeyName and whether the field is protected. These
* values are derived from the <code>attribDef</code> parameter.
*
* @param attribDef Used to set the values of name, description, label,
* dataKeyName and isProtected properties on the returned object.
* @param fieldDef A factory object used to create the FieldDefinition to be
* returned.
* @param group Used to set the group on the returned FieldDefinition.
*/
protected void populateFieldDefinition(Type attribDef, FieldDefinition fieldDef,
FieldGroup group, String dataKeyPrefix)
{
String attribName = fieldDef.getName();
fieldDef.setGroup(group);
String title = attribDef.getTitle();
title = title == null ? attribName : title;
fieldDef.setLabel(title);
fieldDef.setDescription(attribDef.getDescription());
fieldDef.setProtectedField(attribDef.isProtected());
// define the data key name and set
String dataKeyName = makeDataKeyForName(attribName, dataKeyPrefix);
fieldDef.setDataKeyName(dataKeyName);
}
protected String makeDataKeyForName(String propName, String prefix)
{
String[] nameParts = QName.splitPrefixedQName(propName);
String firstPart = nameParts[0];
StringBuilder builder = new StringBuilder(prefix);
if (firstPart.length() > 0)
{
builder.append(firstPart);
builder.append(DATA_KEY_SEPARATOR);
}
builder.append(nameParts[1]);
return builder.toString();
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.field.processor.AbstractFieldProcessor#getExpectedDataType()
*/
@SuppressWarnings("unchecked")
@Override
protected Class<ItemData<?>> getExpectedDataType()
{
// This is nasty but unavoidable because of generics.
Object clazz = ItemData.class;
return (Class<ItemData<?>>)clazz;
}
/**
* @param namespaceService the namespaceService to set
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param dictionaryService the dictionaryService to set
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
protected abstract Field makeField(Type typeDef, Object value, FieldGroup group);
protected abstract FieldGroup getGroup(Type typeDef);
protected abstract Object getValue(QName fullName, ItemData<?> itemData);
protected abstract Type getTypeDefinition(QName fullName, ItemData<?> itemData, boolean isForcedField);
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.PROP_DATA_PREFIX;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.TRANSIENT_ENCODING;
import org.alfresco.repo.forms.PropertyFieldDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.I18NUtil;
public class TransientEncodingFieldProcessor extends TransientFieldProcessor
{
private static final Log logger = LogFactory.getLog(TransientEncodingFieldProcessor.class);
private static final String MSG_ENCODING_LABEL = "form_service.encoding.label";
private static final String MSG_ENCODING_DESC = "form_service.encoding.description";
@Override
protected Log getLogger()
{
return logger;
}
@Override
protected PropertyFieldDefinition makeTransientPropertyDefinition()
{
String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_ENCODING;
PropertyFieldDefinition encodingField = new PropertyFieldDefinition(TRANSIENT_ENCODING,
DataTypeDefinition.TEXT.getLocalName());
encodingField.setLabel(I18NUtil.getMessage(MSG_ENCODING_LABEL));
encodingField.setDescription(I18NUtil.getMessage(MSG_ENCODING_DESC));
encodingField.setDataKeyName(dataKeyName);
return encodingField;
}
@Override
protected String getRegistryKey()
{
return FormFieldConstants.TRANSIENT_ENCODING;
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.PropertyFieldDefinition;
import org.alfresco.repo.forms.processor.AbstractFieldProcessor;
import org.alfresco.repo.forms.processor.FormCreationData;
public abstract class TransientFieldProcessor extends AbstractFieldProcessor<TransientValueGetter>
{
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.AbstractFieldProcessor#generateTypedField(java.lang.String, org.alfresco.repo.forms.processor.node.FormCreationData, java.lang.Object)
*/
@Override
protected Field generateTypedField(String fieldName, FormCreationData formData, TransientValueGetter typedData)
{
PropertyFieldDefinition transientPropDef = makeTransientPropertyDefinition();
Field fieldInfo = null;
Object value = getValue(fieldName, typedData);
if (transientPropDef != null)
{
fieldInfo = new ContentField(transientPropDef, value);
}
return fieldInfo;
}
protected Object getValue(String fieldName, TransientValueGetter data)
{
return data.getTransientValue(fieldName);
}
/*
* (non-Javadoc)
*
* @seeorg.alfresco.repo.forms.field.processor.AbstractFieldProcessor#
* getExpectedDataType()
*/
@Override
protected Class<TransientValueGetter> getExpectedDataType()
{
return TransientValueGetter.class;
}
protected abstract PropertyFieldDefinition makeTransientPropertyDefinition();
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.PROP_DATA_PREFIX;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.TRANSIENT_MIMETYPE;
import org.alfresco.repo.forms.PropertyFieldDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.I18NUtil;
public class TransientMimetypeFieldProcessor extends TransientFieldProcessor
{
private static final Log logger = LogFactory.getLog(TransientMimetypeFieldProcessor.class);
private static final String MSG_MIMETYPE_LABEL = "form_service.mimetype.label";
private static final String MSG_MIMETYPE_DESC = "form_service.mimetype.description";
@Override
protected Log getLogger() {
return logger;
}
@Override
protected PropertyFieldDefinition makeTransientPropertyDefinition() {
String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_MIMETYPE;
PropertyFieldDefinition mimetypeField = new PropertyFieldDefinition(TRANSIENT_MIMETYPE, DataTypeDefinition.TEXT
.getLocalName());
mimetypeField.setLabel(I18NUtil.getMessage(MSG_MIMETYPE_LABEL));
mimetypeField.setDescription(I18NUtil.getMessage(MSG_MIMETYPE_DESC));
mimetypeField.setDataKeyName(dataKeyName);
return mimetypeField;
}
@Override
protected String getRegistryKey()
{
return FormFieldConstants.TRANSIENT_MIMETYPE;
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.PROP_DATA_PREFIX;
import static org.alfresco.repo.forms.processor.node.FormFieldConstants.TRANSIENT_SIZE;
import org.alfresco.repo.forms.PropertyFieldDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.I18NUtil;
public class TransientSizeFieldProcessor extends TransientFieldProcessor
{
private static final Log logger = LogFactory.getLog(TransientSizeFieldProcessor.class);
private static final String MSG_SIZE_LABEL = "form_service.size.label";
private static final String MSG_SIZE_DESC = "form_service.size.description";
@Override
protected Log getLogger()
{
return logger;
}
@Override
protected PropertyFieldDefinition makeTransientPropertyDefinition()
{
String dataKeyName = PROP_DATA_PREFIX + TRANSIENT_SIZE;
PropertyFieldDefinition sizeField = new PropertyFieldDefinition(TRANSIENT_SIZE,
DataTypeDefinition.LONG.getLocalName());
sizeField.setLabel(I18NUtil.getMessage(MSG_SIZE_LABEL));
sizeField.setDescription(I18NUtil.getMessage(MSG_SIZE_DESC));
sizeField.setDataKeyName(dataKeyName);
sizeField.setProtectedField(true);
return sizeField;
}
@Override
protected String getRegistryKey()
{
return FormFieldConstants.TRANSIENT_SIZE;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.forms.processor.node;
/**
* @author Nick Smith
*
*/
public interface TransientValueGetter
{
Object getTransientValue(String name);
}

View File

@@ -21,20 +21,15 @@ package org.alfresco.repo.forms.processor.node;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.forms.Form;
import org.alfresco.repo.forms.FormData; import org.alfresco.repo.forms.FormData;
import org.alfresco.repo.forms.FormException; import org.alfresco.repo.forms.FormException;
import org.alfresco.repo.forms.FormNotFoundException; import org.alfresco.repo.forms.FormNotFoundException;
import org.alfresco.repo.forms.Item; import org.alfresco.repo.forms.Item;
import org.alfresco.repo.forms.FormData.FieldData; import org.alfresco.repo.forms.FormData.FieldData;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.InvalidQNameException; import org.alfresco.service.namespace.InvalidQNameException;
@@ -113,8 +108,11 @@ public class TypeFormProcessor extends ContentModelFormProcessor<TypeDefinition,
// 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) { throw new FormNotFoundException(item, if (typeDef == null)
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)
{ {
@@ -125,111 +123,6 @@ public class TypeFormProcessor extends ContentModelFormProcessor<TypeDefinition,
return typeDef; return typeDef;
} }
/*
* @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(TypeDefinition item, List<String> fields,
List<String> forcedFields, Form form, Map<String, Object> context)
{
if (logger.isDebugEnabled()) logger.debug("Generating form for item: " + item);
// generate the form for the node
generateType(item, fields, forcedFields, form);
if (logger.isDebugEnabled()) logger.debug("Generating form: " + form);
}
/**
* Sets up the Form object for the given NodeRef
*
* @param nodeRef The NodeRef to generate a Form for
* @param fields Restricted list of fields to include
* @param forcedFields List of fields to forcibly include
* @param form The Form instance to populate
*/
protected void generateType(TypeDefinition typeDef, List<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(
":", "_"));
if (fields != null && fields.size() > 0)
{
generateSelectedFields(null, typeDef, fields, forcedFields, form);
}
else
{
// setup field definitions and data
generateAllPropertyFields(typeDef, form);
generateAllAssociationFields(typeDef, form);
// TODO: generate transient properties for content types?
}
}
/**
* Sets up the field definitions for all the type's properties.
*
* @param typeDef The type being setup
* @param form The Form instance to populate
*/
protected void generateAllPropertyFields(TypeDefinition typeDef, Form form)
{
// iterate round the property defintions and setup field definition
Map<QName, PropertyDefinition> propDefs = typeDef.getProperties();
for (PropertyDefinition propDef : propDefs.values())
{
generatePropertyField(propDef, form, this.namespaceService);
}
// get all default aspects for the type and iterate round their
// property definitions too
List<AspectDefinition> aspects = typeDef.getDefaultAspects(true);
for (AspectDefinition aspect : aspects)
{
propDefs = aspect.getProperties();
for (PropertyDefinition propDef : propDefs.values())
{
generatePropertyField(propDef, form, this.namespaceService);
}
}
}
/**
* Sets up the field definitions for all the type's associations.
*
* @param typeDef The type being setup
* @param form The Form instance to populate
*/
protected void generateAllAssociationFields(TypeDefinition typeDef, Form form)
{
// iterate round the association defintions and setup field definition
Map<QName, AssociationDefinition> assocDefs = typeDef.getAssociations();
for (AssociationDefinition assocDef : assocDefs.values())
{
generateAssociationField(assocDef, form, this.namespaceService);
}
// get all default aspects for the type and iterate round their
// association definitions too
List<AspectDefinition> aspects = typeDef.getDefaultAspects(true);
for (AspectDefinition aspect : aspects)
{
assocDefs = aspect.getAssociations();
for (AssociationDefinition assocDef : assocDefs.values())
{
generateAssociationField(assocDef, form, this.namespaceService);
}
}
}
/* /*
* @see * @see
* org.alfresco.repo.forms.processor.node.NodeFormProcessor#internalPersist * org.alfresco.repo.forms.processor.node.NodeFormProcessor#internalPersist
@@ -238,30 +131,29 @@ public class TypeFormProcessor extends ContentModelFormProcessor<TypeDefinition,
@Override @Override
protected NodeRef internalPersist(TypeDefinition item, final FormData data) protected NodeRef internalPersist(TypeDefinition item, final FormData data)
{ {
if (logger.isDebugEnabled()) logger.debug("Persisting form for: " + item); if (logger.isDebugEnabled())
logger.debug("Persisting form for: " + item);
// create a new instance of the type // create a new instance of the type
final NodeRef nodeRef = createNode(item, data); final NodeRef nodeRef = createNode(item, data);
if (nodeService.hasAspect(nodeRef, ASPECT_FILE_PLAN_COMPONENT) == true) if (nodeService.hasAspect(nodeRef, ASPECT_FILE_PLAN_COMPONENT) == true)
{ {
// persist the form data as the admin user // persist the form data as the admin user
AuthenticationUtil.runAs( AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
new AuthenticationUtil.RunAsWork<Object>() {
{ public Object doWork() throws Exception
public Object doWork() throws Exception {
{ persistNode(nodeRef, data);
persistNode(nodeRef, data); return null;
return null; }
} },
AuthenticationUtil.getSystemUserName());
},
AuthenticationUtil.getSystemUserName());
} }
else else
{ {
// persist the form data // persist the form data
persistNode(nodeRef, data); persistNode(nodeRef, data);
} }
// return the newly created node // return the newly created node
@@ -293,9 +185,12 @@ public class TypeFormProcessor extends ContentModelFormProcessor<TypeDefinition,
// 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) { throw new FormException("Failed to persist form for '" if (destination == null)
+ typeDef.getName().toPrefixString(this.namespaceService) + "' as '" {
+ DESTINATION + "' data was not provided."); } throw new FormException("Failed to persist form for '"
+ 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());
@@ -340,4 +235,46 @@ public class TypeFormProcessor extends ContentModelFormProcessor<TypeDefinition,
return nodeRef; return nodeRef;
} }
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getItemType(java.lang.Object)
*/
@Override
protected String getItemType(TypeDefinition item)
{
return item.getName().toPrefixString(namespaceService);
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getItemURI(java.lang.Object)
*/
@Override
protected String getItemURI(TypeDefinition item)
{
return "/api/classes/" + getItemType(item).replace(":", "_");
}
@Override
protected TypeDefinition getBaseType(TypeDefinition type)
{
return type;
}
@Override
protected Map<QName, Serializable> getAssociationValues(TypeDefinition item)
{
return null;
}
@Override
protected Map<QName, Serializable> getPropertyValues(TypeDefinition item)
{
return null;
}
@Override
protected Map<String, Object> getTransientValues(TypeDefinition item)
{
return null;
}
} }

View File

@@ -20,25 +20,38 @@ package org.alfresco.repo.forms.processor.workflow;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.forms.AssociationFieldDefinition; import org.alfresco.repo.forms.AssociationFieldDefinition;
import org.alfresco.repo.forms.FieldGroup;
import org.alfresco.repo.forms.Form; import org.alfresco.repo.forms.Form;
import org.alfresco.repo.forms.FormData; import org.alfresco.repo.forms.FormData;
import org.alfresco.repo.forms.FormNotFoundException; import org.alfresco.repo.forms.FormNotFoundException;
import org.alfresco.repo.forms.Item; import org.alfresco.repo.forms.Item;
import org.alfresco.repo.forms.PropertyFieldDefinition;
import org.alfresco.repo.forms.AssociationFieldDefinition.Direction; import org.alfresco.repo.forms.AssociationFieldDefinition.Direction;
import org.alfresco.repo.forms.PropertyFieldDefinition.FieldConstraint;
import org.alfresco.repo.forms.processor.node.ContentModelFormProcessor; import org.alfresco.repo.forms.processor.node.ContentModelFormProcessor;
import org.alfresco.repo.forms.processor.node.PeriodDataTypeParameters;
import org.alfresco.repo.workflow.WorkflowModel; import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.AssociationDefinition; import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.Constraint;
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Period;
import org.alfresco.service.cmr.workflow.WorkflowDefinition; import org.alfresco.service.cmr.workflow.WorkflowDefinition;
import org.alfresco.service.cmr.workflow.WorkflowException; import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.cmr.workflow.WorkflowInstance; import org.alfresco.service.cmr.workflow.WorkflowInstance;
@@ -326,4 +339,597 @@ public class WorkflowFormProcessor extends ContentModelFormProcessor<WorkflowDef
// return the workflow just started // return the workflow just started
return workflow; return workflow;
} }
/**
* 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.
* </p>
*
* @param propDef The PropertyDefinition of the field to generate
* @param form The Form instance to populate
* @param namespaceService NamespaceService instance
*/
protected void generatePropertyField(PropertyDefinition propDef, Form form, NamespaceService namespaceService)
{
generatePropertyField(propDef, form, null, null, namespaceService);
}
/**
* Sets up a field definition for the given property.
* <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.
* </p>
*
* @param propDef The PropertyDefinition of the field to generate
* @param form The Form instance to populate
* @param propValue The value of the property field
* @param namespaceService NamespaceService instance
*/
protected void generatePropertyField(PropertyDefinition propDef, Form form, Serializable propValue,
NamespaceService namespaceService)
{
generatePropertyField(propDef, form, propValue, null, namespaceService);
}
/**
* Sets up a field definition for the given property.
* <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.
* </p>
*
* @param propDef The PropertyDefinition of the field to generate
* @param form The Form instance to populate
* @param propValue The value of the property field
* @param group The FieldGroup the property field belongs to, can be null
* @param namespaceService NamespaceService instance
*/
@SuppressWarnings("unchecked")
protected void generatePropertyField(PropertyDefinition propDef, Form form, Serializable propValue,
FieldGroup group, NamespaceService namespaceService)
{
String propName = propDef.getName().toPrefixString(namespaceService);
String[] nameParts = QName.splitPrefixedQName(propName);
PropertyFieldDefinition fieldDef = new PropertyFieldDefinition(propName, propDef.getDataType().getName()
.getLocalName());
String title = propDef.getTitle();
if (title == null)
{
title = propName;
}
fieldDef.setLabel(title);
fieldDef.setDefaultValue(propDef.getDefaultValue());
fieldDef.setDescription(propDef.getDescription());
fieldDef.setMandatory(propDef.isMandatory());
fieldDef.setProtectedField(propDef.isProtected());
fieldDef.setRepeating(propDef.isMultiValued());
fieldDef.setGroup(group);
// any property from the system model (sys prefix) should be protected
// the model doesn't currently enforce this so make sure they are not
// editable
if (NamespaceService.SYSTEM_MODEL_1_0_URI.equals(propDef.getName().getNamespaceURI()))
{
fieldDef.setProtectedField(true);
}
// define the data key name and set
String dataKeyName = PROP_DATA_PREFIX + nameParts[0] + DATA_KEY_SEPARATOR + nameParts[1];
fieldDef.setDataKeyName(dataKeyName);
// setup any parameters requried for the data type
if (propDef.getDataType().getName().equals(DataTypeDefinition.PERIOD))
{
// if the property data type is d:period we need to setup a data
// type parameters object to represent the options and rules
PeriodDataTypeParameters periodOptions = new PeriodDataTypeParameters();
Set<String> providers = Period.getProviderNames();
for (String provider : providers)
{
periodOptions.addPeriodProvider(Period.getProvider(provider));
}
fieldDef.setDataTypeParameters(periodOptions);
}
// setup constraints for the property
List<ConstraintDefinition> constraints = propDef.getConstraints();
if (constraints != null && constraints.size() > 0)
{
List<FieldConstraint> fieldConstraints = new ArrayList<FieldConstraint>(constraints.size());
for (ConstraintDefinition constraintDef : constraints)
{
Constraint constraint = constraintDef.getConstraint();
FieldConstraint fieldConstraint = new FieldConstraint(constraint.getType(), constraint.getParameters());
fieldConstraints.add(fieldConstraint);
}
fieldDef.setConstraints(fieldConstraints);
}
form.addFieldDefinition(fieldDef);
// add the property value to the form
if (propValue != null)
{
if (propValue instanceof List)
{
// temporarily add repeating field data as a comma
// separated list, this will be changed to using
// a separate field for each value once we have full
// UI support in place.
propValue = StringUtils.collectionToCommaDelimitedString((List) propValue);
}
else if (propValue instanceof ContentData)
{
// for content properties retrieve the info URL rather than the
// the object value itself
propValue = ((ContentData)propValue).getInfoUrl();
}
form.addData(dataKeyName, propValue);
}
}
/**
* Sets up a field definition for the given association.
* <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.
* </p>
*
* @param assocDef The AssociationDefinition of the field to generate
* @param form The Form instance to populate
* @param namespaceService NamespaceService instance
*/
protected void generateAssociationField(AssociationDefinition assocDef, Form form,
NamespaceService namespaceService)
{
generateAssociationField(assocDef, form, null, null, namespaceService);
}
/**
* Sets up a field definition for the given association.
* <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.
* </p>
*
* @param assocDef The AssociationDefinition of the field to generate
* @param form The Form instance to populate
* @param assocValues The values of the association field, can be null
* @param namespaceService NamespaceService instance
*/
@SuppressWarnings("unchecked")
protected void generateAssociationField(AssociationDefinition assocDef, Form form, List assocValues,
NamespaceService namespaceService)
{
generateAssociationField(assocDef, form, assocValues, null, namespaceService);
}
/**
* Sets up a field definition for the given association.
* <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.
* </p>
*
* @param assocDef The AssociationDefinition of the field to generate
* @param form The Form instance to populate
* @param assocValues The values of the association field, can be null
* @param group The FieldGroup the association field belongs to, can be null
* @param namespaceService NamespaceService instance
*/
@SuppressWarnings("unchecked")
protected static void generateAssociationField(AssociationDefinition assocDef, Form form, List assocValues,
FieldGroup group, NamespaceService namespaceService)
{
String assocName = assocDef.getName().toPrefixString(namespaceService);
String[] nameParts = QName.splitPrefixedQName(assocName);
AssociationFieldDefinition fieldDef = new AssociationFieldDefinition(assocName, assocDef.getTargetClass()
.getName().toPrefixString(namespaceService), Direction.TARGET);
String title = assocDef.getTitle();
if (title == null)
{
title = assocName;
}
fieldDef.setLabel(title);
fieldDef.setDescription(assocDef.getDescription());
fieldDef.setProtectedField(assocDef.isProtected());
fieldDef.setEndpointMandatory(assocDef.isTargetMandatory());
fieldDef.setEndpointMany(assocDef.isTargetMany());
fieldDef.setGroup(group);
// define the data key name and set
String dataKeyName = ASSOC_DATA_PREFIX + nameParts[0] + DATA_KEY_SEPARATOR + nameParts[1];
fieldDef.setDataKeyName(dataKeyName);
// add definition to the form
form.addFieldDefinition(fieldDef);
if (assocValues != null)
{
// add the association value to the form
// determine the type of association values data and extract
// accordingly
List<String> values = new ArrayList<String>(4);
for (Object value : assocValues)
{
if (value instanceof ChildAssociationRef)
{
values.add(((ChildAssociationRef) value).getChildRef().toString());
}
else if (value instanceof AssociationRef)
{
values.add(((AssociationRef) value).getTargetRef().toString());
}
else
{
values.add(value.toString());
}
}
// Add the list as the value for the association.
form.addData(dataKeyName, values);
}
}
/**
* Sets up the field definitions for all the requested fields.
* <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.
* </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 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 (getLogger().isDebugEnabled())
getLogger().debug("Generating selected fields: " + fields + " and forcing: " + forcedFields);
// get data dictionary definition for node if it is provided
QName type = null;
Map<QName, Serializable> propValues = Collections.emptyMap();
Map<QName, PropertyDefinition> propDefs = null;
Map<QName, AssociationDefinition> assocDefs = null;
if (nodeRef != null)
{
type = this.nodeService.getType(nodeRef);
typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService.getAspects(nodeRef));
// NOTE: the anonymous type returns all property and association
// defs
// for all aspects applied as well as the type
propDefs = typeDef.getProperties();
assocDefs = typeDef.getAssociations();
propValues = this.nodeService.getProperties(nodeRef);
}
else
{
type = typeDef.getName();
// we only get the properties and associations of the actual type so
// we also need to manually get properties and associations from any
// mandatory aspects
propDefs = new HashMap<QName, PropertyDefinition>(16);
assocDefs = new HashMap<QName, AssociationDefinition>(16);
propDefs.putAll(typeDef.getProperties());
assocDefs.putAll(typeDef.getAssociations());
List<AspectDefinition> aspects = typeDef.getDefaultAspects(true);
for (AspectDefinition aspect : aspects)
{
propDefs.putAll(aspect.getProperties());
assocDefs.putAll(aspect.getAssociations());
}
}
for (String fieldName : fields)
{
// try and split the field name
String[] parts = fieldName.split(":");
if (parts.length == 2 || parts.length == 3)
{
boolean foundField = false;
boolean tryProperty = true;
boolean tryAssociation = true;
String qNamePrefix = null;
String localName = null;
if (parts.length == 2)
{
qNamePrefix = parts[0];
localName = parts[1];
}
else
{
// if there are 3 parts to the field name the first one
// represents
// whether the field is a property or association i.e.
// prop:prefix:local
// or assoc:prefix:local, determine the prefix and ensure
// it's valid
if (PROP.equals(parts[0]))
{
tryAssociation = false;
}
else if (ASSOC.equals(parts[0]))
{
tryProperty = false;
}
else
{
if (getLogger().isWarnEnabled())
getLogger()
.warn(
"\""
+ parts[0]
+ "\" is an invalid prefix for requesting a property or association");
continue;
}
qNamePrefix = parts[1];
localName = parts[2];
}
// create qname of field name
QName fullQName = QName.createQName(qNamePrefix, localName, namespaceService);
// try the field as a property
if (tryProperty)
{
// lookup property def on node
PropertyDefinition propDef = propDefs.get(fullQName);
if (propDef != null)
{
// generate the property field
generatePropertyField(propDef, form, propValues.get(fullQName), this.namespaceService);
// no need to try and find an association
tryAssociation = false;
foundField = true;
}
}
// try the field as an association
if (tryAssociation)
{
AssociationDefinition assocDef = assocDefs.get(fullQName);
if (assocDef != null)
{
// generate the association field
generateAssociationField(assocDef, form, (nodeRef != null) ? retrieveAssociationValues(nodeRef,
assocDef) : null, this.namespaceService);
foundField = true;
}
}
// still not found the field, is it a force'd field?
if (!foundField)
{
if (forcedFields != null && forcedFields.size() > 0 && forcedFields.contains(fieldName))
{
generateForcedField(fieldName, form);
}
else if (getLogger().isDebugEnabled())
{
getLogger().debug(
"Ignoring field \"" + fieldName + "\" as it is not defined for the current "
+ ((nodeRef != null) ? "node" : "type")
+ " and it does not appear in the 'force' list");
}
}
}
else
{
// see if the fieldName is a well known transient property
if (TRANSIENT_MIMETYPE.equals(fieldName) || TRANSIENT_ENCODING.equals(fieldName)
|| TRANSIENT_SIZE.equals(fieldName))
{
// if the node type is content or sublcass thereof generate appropriate field
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT))
{
ContentData content = null;
if (nodeRef != null)
{
content = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
}
if (TRANSIENT_MIMETYPE.equals(fieldName))
{
generateMimetypePropertyField(content, form);
}
else if (TRANSIENT_ENCODING.equals(fieldName))
{
generateEncodingPropertyField(content, form);
}
else if (TRANSIENT_SIZE.equals(fieldName))
{
generateSizePropertyField(content, form);
}
}
}
else if (getLogger().isWarnEnabled())
{
getLogger().warn("Ignoring unrecognised field \"" + fieldName + "\"");
}
}
}
}
/**
* Generates a field definition for the given field that is being forced to
* show.
*
* @param fieldName Name of the field to force
* @param form The Form instance to populated
*/
protected void generateForcedField(String fieldName, Form form)
{
if (getLogger().isDebugEnabled())
getLogger().debug("Attempting to force the inclusion of field \"" + fieldName + "\"");
String[] parts = fieldName.split(":");
if (parts.length == 2 || parts.length == 3)
{
boolean foundField = false;
boolean tryProperty = true;
boolean tryAssociation = true;
String qNamePrefix = null;
String localName = null;
if (parts.length == 2)
{
qNamePrefix = parts[0];
localName = parts[1];
}
else
{
// if there are 3 parts to the field name the first one
// represents
// whether the field is a property or association i.e.
// prop:prefix:local
// or assoc:prefix:local, determine the prefix and ensure it's
// valid
if (PROP.equals(parts[0]))
{
tryAssociation = false;
}
else if (ASSOC.equals(parts[0]))
{
tryProperty = false;
}
else
{
if (getLogger().isWarnEnabled())
getLogger().warn(
"\"" + parts[0]
+ "\" is an invalid prefix for requesting a property or association");
return;
}
qNamePrefix = parts[1];
localName = parts[2];
}
// create qname of field name
QName fullQName = QName.createQName(qNamePrefix, localName, namespaceService);
if (tryProperty)
{
// lookup the field as a property in the whole model
PropertyDefinition propDef = this.dictionaryService.getProperty(fullQName);
if (propDef != null)
{
// generate the property field
generatePropertyField(propDef, form, this.namespaceService);
// no need to try and find an association
tryAssociation = false;
foundField = true;
}
}
if (tryAssociation)
{
// lookup the field as an association in the whole model
AssociationDefinition assocDef = this.dictionaryService.getAssociation(fullQName);
if (assocDef != null)
{
// generate the association field
generateAssociationField(assocDef, form, this.namespaceService);
foundField = true;
}
}
if (!foundField && getLogger().isDebugEnabled())
{
getLogger()
.debug(
"Ignoring field \""
+ fieldName
+ "\" as it is not defined for the current node and can not be found in any model");
}
}
else if (getLogger().isWarnEnabled())
{
getLogger().warn("Ignoring unrecognised field \"" + fieldName + "\"");
}
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getItemType(java.lang.Object)
*/
@Override
protected String getItemType(WorkflowDefinition item)
{
return item.name;
}
/* (non-Javadoc)
* @see org.alfresco.repo.forms.processor.FilteredFormProcessor#getItemURI(java.lang.Object)
*/
@Override
protected String getItemURI(WorkflowDefinition item)
{
return "/api/workflow-definitions/" + item.id;
}
@Override
protected Map<QName, Serializable> getAssociationValues(WorkflowDefinition item)
{
return null;
}
@Override
protected Map<QName, Serializable> getPropertyValues(WorkflowDefinition item)
{
return null;
}
@Override
protected Map<String, Object> getTransientValues(WorkflowDefinition item)
{
return null;
}
@Override
protected TypeDefinition getBaseType(WorkflowDefinition item)
{
return item.getStartTaskDefinition().metadata;
}
} }