forcedFields);
/**
* Persists the given object representing the form data
@@ -68,5 +78,5 @@ public interface FormProcessor
* @param item The item to generate a Form object for
* @param data An object representing the data of the form
*/
- public void persist(String item, FormData data);
+ public void persist(Item item, FormData data);
}
diff --git a/source/java/org/alfresco/repo/forms/processor/FormProcessorRegistry.java b/source/java/org/alfresco/repo/forms/processor/FormProcessorRegistry.java
index 508d4b43f0..946dc0ff12 100644
--- a/source/java/org/alfresco/repo/forms/processor/FormProcessorRegistry.java
+++ b/source/java/org/alfresco/repo/forms/processor/FormProcessorRegistry.java
@@ -27,6 +27,7 @@ package org.alfresco.repo.forms.processor;
import java.util.ArrayList;
import java.util.List;
+import org.alfresco.repo.forms.Item;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -85,7 +86,7 @@ public class FormProcessorRegistry
* @param item The item to find a form processor for
* @return An applicable FormProcessor
*/
- public FormProcessor getApplicableFormProcessor(String item)
+ public FormProcessor getApplicableFormProcessor(Item item)
{
FormProcessor selectedProcessor = null;
diff --git a/source/java/org/alfresco/repo/forms/processor/Handler.java b/source/java/org/alfresco/repo/forms/processor/Handler.java
index fabaec18ca..091ebf2ccc 100644
--- a/source/java/org/alfresco/repo/forms/processor/Handler.java
+++ b/source/java/org/alfresco/repo/forms/processor/Handler.java
@@ -24,6 +24,8 @@
*/
package org.alfresco.repo.forms.processor;
+import java.util.List;
+
import org.alfresco.repo.forms.Form;
import org.alfresco.repo.forms.FormData;
@@ -35,8 +37,6 @@ import org.alfresco.repo.forms.FormData;
*/
public interface Handler
{
- // TODO: Investigate whether Generics can be used instead of Object
-
/**
* Determines whether the handler is applicable for the given item.
*
@@ -63,11 +63,14 @@ public interface Handler
* to a more appropriate object, for example all the Node based handlers
* can expect a NodeRef object and therefore cast to that.
*
+ * @see org.alfresco.repo.forms.processor.FormProcessor#generate(org.alfresco.repo.forms.Item, java.util.List, java.util.List)
* @param item The item 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
* @return The modified Form object
*/
- public Form handleGenerate(Object item, Form form);
+ public Form handleGenerate(Object item, List fields, List forcedFields, Form form);
/**
* Handles the persistence of form data for the given item.
diff --git a/source/java/org/alfresco/repo/forms/processor/NodeFormProcessor.java b/source/java/org/alfresco/repo/forms/processor/NodeFormProcessor.java
index 97ce3bedf1..2560d60388 100644
--- a/source/java/org/alfresco/repo/forms/processor/NodeFormProcessor.java
+++ b/source/java/org/alfresco/repo/forms/processor/NodeFormProcessor.java
@@ -24,9 +24,13 @@
*/
package org.alfresco.repo.forms.processor;
+import org.alfresco.repo.forms.FormNotFoundException;
+import org.alfresco.repo.forms.Item;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
/**
* FormProcessor implementation that can generate and persist Form objects
@@ -36,6 +40,9 @@ import org.alfresco.service.cmr.repository.NodeService;
*/
public class NodeFormProcessor extends AbstractFormProcessorByHandlers
{
+ /** Logger */
+ private static Log logger = LogFactory.getLog(NodeFormProcessor.class);
+
/** Services */
protected NodeService nodeService;
@@ -50,18 +57,50 @@ public class NodeFormProcessor extends AbstractFormProcessorByHandlers
}
/*
- * @see org.alfresco.repo.forms.processor.AbstractFormProcessor#getTypedItem(java.lang.String)
+ * @see org.alfresco.repo.forms.processor.AbstractFormProcessorByHandlers#getTypedItem(org.alfresco.repo.forms.Item)
*/
@Override
- protected Object getTypedItem(String item)
+ protected Object getTypedItem(Item item)
{
- // create NodeRef representation
- NodeRef nodeRef = new NodeRef(item);
+ // create NodeRef representation, the id could already be in a valid
+ // NodeRef format or it may be in a URL friendly format
+ NodeRef nodeRef = null;
+ if (NodeRef.isNodeRef(item.getId()))
+ {
+ nodeRef = new NodeRef(item.getId());
+ }
+ else
+ {
+ // split the string into the 3 required parts
+ String[] parts = item.getId().split("/");
+ if (parts.length == 3)
+ {
+ try
+ {
+ nodeRef = new NodeRef(parts[0], parts[1], parts[2]);
+ }
+ catch (IllegalArgumentException iae)
+ {
+ // ignored for now, dealt with below
+
+ if (logger.isDebugEnabled())
+ logger.debug("NodeRef creation failed for: " + item.getId(), iae);
+ }
+ }
+ }
+
+ // check we have a valid node ref
+ if (nodeRef == null)
+ {
+ throw new FormNotFoundException(item,
+ new IllegalArgumentException(item.getId()));
+ }
// check the node itself exists
if (this.nodeService.exists(nodeRef) == false)
{
- throw new InvalidNodeRefException("Node does not exist: " + nodeRef, nodeRef);
+ throw new FormNotFoundException(item,
+ new InvalidNodeRefException("Node does not exist: " + nodeRef, nodeRef));
}
else
{
diff --git a/source/java/org/alfresco/repo/forms/processor/NodeHandler.java b/source/java/org/alfresco/repo/forms/processor/NodeHandler.java
index 55c9ff2737..914cc583c0 100644
--- a/source/java/org/alfresco/repo/forms/processor/NodeHandler.java
+++ b/source/java/org/alfresco/repo/forms/processor/NodeHandler.java
@@ -26,7 +26,6 @@ package org.alfresco.repo.forms.processor;
import java.io.Serializable;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -163,9 +162,9 @@ public class NodeHandler extends AbstractHandler
}
/*
- * @see org.alfresco.repo.forms.processor.FormProcessorHandler#handleGenerate(java.lang.Object, org.alfresco.repo.forms.Form)
+ * @see org.alfresco.repo.forms.processor.Handler#handleGenerate(java.lang.Object, java.util.List, java.util.List, org.alfresco.repo.forms.Form)
*/
- public Form handleGenerate(Object item, Form form)
+ public Form handleGenerate(Object item, List fields, List forcedFields, Form form)
{
if (logger.isDebugEnabled())
logger.debug("Generating form for: " + item);
@@ -174,7 +173,7 @@ public class NodeHandler extends AbstractHandler
NodeRef nodeRef = (NodeRef)item;
// generate the form for the node
- generateNode(nodeRef, form);
+ generateNode(nodeRef, fields, forcedFields, form);
if (logger.isDebugEnabled())
logger.debug("Returning form: " + form);
@@ -182,201 +181,384 @@ public class NodeHandler extends AbstractHandler
return form;
}
- /*
- * @see org.alfresco.repo.forms.processor.FormProcessorHandler#handlePersist(java.lang.Object, org.alfresco.repo.forms.FormData)
- */
- public void handlePersist(Object item, FormData data)
- {
- if (logger.isDebugEnabled())
- logger.debug("Persisting form for: " + item);
-
- // cast to the expected NodeRef representation
- NodeRef nodeRef = (NodeRef)item;
-
- // persist the node
- persistNode(nodeRef, data);
- }
-
/**
* Sets up the Form object for the given NodeRef
*
* @param nodeRef The NodeRef to generate a Form for
+ * @param fields Restricted list of fields to include
+ * @param forcedFields List of fields to forcibly include
* @param form The Form instance to populate
*/
- protected void generateNode(NodeRef nodeRef, Form form)
+ protected void generateNode(NodeRef nodeRef, List fields, List forcedFields, Form form)
{
// set the type
QName type = this.nodeService.getType(nodeRef);
form.setType(type.toPrefixString(this.namespaceService));
- // setup field definitions and data
- FormData formData = new FormData();
- generatePropertyFields(nodeRef, form, formData);
- generateAssociationFields(nodeRef, form, formData);
- generateChildAssociationFields(nodeRef, form, formData);
- generateTransientFields(nodeRef, form, formData);
- form.setFormData(formData);
+ if (fields != null && fields.size() > 0)
+ {
+ generateSelectedFields(nodeRef, fields, forcedFields, form);
+ }
+ else
+ {
+ // setup field definitions and data
+ generateAllPropertyFields(nodeRef, form);
+ generateAllAssociationFields(nodeRef, form);
+ generateAllChildAssociationFields(nodeRef, form);
+ generateTransientFields(nodeRef, form);
+ }
}
/**
- * Persists the given FormData on the given NodeRef
+ * Sets up the field definitions for all the requested fields.
+ * If any of the requested fields are not present on the node and they
+ * appear in the forcedFields list an attempt to find a model
+ * definition for those fields is made so they can be included.
*
- * @param nodeRef The NodeRef to persist the form data on
- * @param data The FormData to persist
+ * @param nodeRef The NodeRef of the node being setup
+ * @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 persistNode(NodeRef nodeRef, FormData data)
+ protected void generateSelectedFields(NodeRef nodeRef, List fields, List forcedFields, Form form)
{
- // get the property definitions for the type of node being persisted
+ if (logger.isDebugEnabled())
+ logger.debug("Generating selected fields: " + fields + " and forcing: " + forcedFields);
+
+ // get data dictionary definition for node
QName type = this.nodeService.getType(nodeRef);
- Collection aspects = this.getAspectsToInclude(nodeRef);
- TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, aspects);
+ TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type,
+ this.nodeService.getAspects(nodeRef));
+ Map propDefs = typeDef.getProperties();
Map assocDefs = typeDef.getAssociations();
Map childAssocDefs = typeDef.getChildAssociations();
- Map propDefs = typeDef.getProperties();
+ Map propValues = this.nodeService.getProperties(nodeRef);
- Map propsToPersist = new HashMap(data.getData().size());
- List assocsToPersist = new ArrayList();
-
- for (String dataKey : data.getData().keySet())
+ for (String fieldName : fields)
{
- FieldData fieldData = data.getData().get(dataKey);
- // NOTE: ignore file fields for now, not supported yet!
- if (fieldData.isFile() == false)
+ // try and split the field name
+ String[] parts = fieldName.split(":");
+ if (parts.length == 2)
{
- String fieldName = fieldData.getName();
-
- if (fieldName.startsWith(PROP_PREFIX))
+ // create qname of field name
+ String qNamePrefix = parts[0];
+ String localName = parts[1];
+ QName fullQName = QName.createQName(qNamePrefix, localName, namespaceService);
+
+ // lookup property def on node
+ PropertyDefinition propDef = propDefs.get(fullQName);
+ if (propDef != null)
{
- processPropertyPersist(nodeRef, propDefs, fieldData, propsToPersist);
+ // generate the property field
+ generatePropertyField(propDef, propValues.get(propDef.getName()), form);
}
- else if (fieldName.startsWith(ASSOC_PREFIX))
+ else
{
- processAssociationPersist(nodeRef, assocDefs, childAssocDefs, fieldData, assocsToPersist);
+ // look for association defined for the type
+ AssociationDefinition assocDef = assocDefs.get(fullQName);
+ if (assocDef != null)
+ {
+ // generate the association field
+ generateAssociationField(assocDef,
+ this.nodeService.getTargetAssocs(nodeRef, fullQName), form);
+ }
+ else
+ {
+ ChildAssociationDefinition childAssocDef = childAssocDefs.get(fullQName);
+ if (childAssocDef != null)
+ {
+ // generate the association field
+ // TODO: see if we can get just the specific child assoc data
+ generateAssociationField(childAssocDef,
+ this.nodeService.getChildAssocs(nodeRef), form);
+ }
+ else
+ {
+ // still not found the field, is it a force'd field?
+ if (forcedFields != null && forcedFields.size() > 0 &&
+ forcedFields.contains(fieldName))
+ {
+ generateForcedField(fullQName, form);
+ }
+ else if (logger.isWarnEnabled())
+ {
+ logger.warn("Ignoring field \"" + fieldName +
+ "\" as it is not defined for the current node 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 = (ContentData)this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
+ if (content != null)
+ {
+ 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 (logger.isWarnEnabled())
{
- logger.warn("Ignoring unrecognised field '" + fieldName + "'");
+ logger.warn("Ignoring unrecognised field \"" + fieldName + "\"");
}
}
}
-
- // persist the properties using addProperties as this changes the repo values of
- // those properties included in the Map, but leaves any other property values unchanged,
- // whereas setProperties causes the deletion of properties that are not included in the Map.
- this.nodeService.addProperties(nodeRef, propsToPersist);
-
- for (AbstractAssocCommand cmd : assocsToPersist)
- {
- //TODO If there is an attempt to add and remove the same assoc in one request,
- // we could drop each request and do nothing.
- cmd.updateAssociations(nodeService);
- }
}
/**
- * Sets up the field definitions for the node's properties.
+ * Generates a field definition for the given field that is being forced
+ * to show
+ *
+ * @param fieldName QName of the field to force
+ * @param form The Form instance to populated
+ */
+ protected void generateForcedField(QName fieldName, Form form)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Attempting to force the inclusion of field \"" +
+ fieldName.toPrefixString(this.namespaceService) + "\"");
+
+ // lookup the field as a property in the model
+ PropertyDefinition propDef = this.dictionaryService.getProperty(fieldName);
+ if (propDef != null)
+ {
+ // generate the property field
+ generatePropertyField(propDef, null, form);
+ }
+ else
+ {
+ // lookup the field as an association in the model
+ AssociationDefinition assocDef = this.dictionaryService.getAssociation(fieldName);
+ if (assocDef != null)
+ {
+ // generate the association field
+ generateAssociationField(assocDef, null, form);
+ }
+ else if (logger.isWarnEnabled())
+ {
+ logger.warn("Ignoring field \"" + fieldName.toPrefixString(this.namespaceService) +
+ "\" as it is not defined for the current node and can not be found in any model");
+ }
+ }
+ }
+
+ /**
+ * 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
- * @param formData The FormData instance to populate
*/
- @SuppressWarnings("unchecked")
- protected void generatePropertyFields(NodeRef nodeRef, Form form, FormData formData)
+ protected void generateAllPropertyFields(NodeRef nodeRef, Form form)
{
// get data dictionary definition for node
QName type = this.nodeService.getType(nodeRef);
- Collection aspects = this.getAspectsToInclude(nodeRef);
- TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, aspects);
+ TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type,
+ this.nodeService.getAspects(nodeRef));
- // iterate round the property definitions, create the equivalent
- // field definition and setup the data for the property
+ // iterate round the property definitions for the node and create
+ // the equivalent field definition and setup the data for the property
Map propDefs = typeDef.getProperties();
Map propValues = this.nodeService.getProperties(nodeRef);
for (PropertyDefinition propDef : propDefs.values())
{
- String propName = propDef.getName().toPrefixString(this.namespaceService);
- PropertyFieldDefinition fieldDef = new PropertyFieldDefinition(
- propName, propDef.getDataType().getName().toPrefixString(
- this.namespaceService));
+ generatePropertyField(propDef, propValues.get(propDef.getName()), form);
+ }
+ }
+
+ /**
+ * Sets up a field definition for the given property
+ *
+ * @param propDef The PropertyDefinition of the field to generate
+ * @param propValue The value of the property field
+ * @param form The Form instance to populate
+ */
+ @SuppressWarnings("unchecked")
+ protected void generatePropertyField(PropertyDefinition propDef, Serializable propValue, Form form)
+ {
+ String propName = propDef.getName().toPrefixString(this.namespaceService);
+ PropertyFieldDefinition fieldDef = new PropertyFieldDefinition(
+ propName, propDef.getDataType().getName().toPrefixString(
+ this.namespaceService));
+
+ 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());
+
+ // setup constraints for the property
+ List constraints = propDef.getConstraints();
+ if (constraints != null && constraints.size() > 0)
+ {
+ List fieldConstraints =
+ new ArrayList(constraints.size());
- String title = propDef.getTitle();
- if (title == null)
+ for (ConstraintDefinition constraintDef : constraints)
{
- 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());
-
- // setup constraints for the property
- List constraints = propDef.getConstraints();
- if (constraints != null && constraints.size() > 0)
- {
- List fieldConstraints =
- new ArrayList(constraints.size());
-
- for (ConstraintDefinition constraintDef : constraints)
+ Constraint constraint = constraintDef.getConstraint();
+ Map fieldConstraintParams = null;
+ Map constraintParams = constraint.getParameters();
+ if (constraintParams != null)
{
- Constraint constraint = constraintDef.getConstraint();
- Map fieldConstraintParams = null;
- Map constraintParams = constraint.getParameters();
- if (constraintParams != null)
+ // TODO: Just return the param value object, don't convert to String
+ fieldConstraintParams = new HashMap(constraintParams.size());
+ for (String name : constraintParams.keySet())
{
- // TODO: Just return the param value object, don't convert to String
- fieldConstraintParams = new HashMap(constraintParams.size());
- for (String name : constraintParams.keySet())
+ Object paramValue = constraintParams.get(name);
+
+ if (paramValue instanceof List)
{
- Object paramValue = constraintParams.get(name);
-
- if (paramValue instanceof List)
- {
- paramValue = makeListString((List)paramValue);
- }
-
- fieldConstraintParams.put(name, paramValue.toString());
+ paramValue = makeListString((List)paramValue);
}
+
+ fieldConstraintParams.put(name, paramValue.toString());
}
- FieldConstraint fieldConstraint = fieldDef.new FieldConstraint(
- constraint.getType(), fieldConstraintParams);
- fieldConstraints.add(fieldConstraint);
}
-
- fieldDef.setConstraints(fieldConstraints);
+ FieldConstraint fieldConstraint = fieldDef.new FieldConstraint(
+ constraint.getType(), fieldConstraintParams);
+ fieldConstraints.add(fieldConstraint);
}
- form.addFieldDefinition(fieldDef);
-
- // get the field value and add to the form data object
- Serializable fieldData = propValues.get(propDef.getName());
- if (fieldData != null)
+ fieldDef.setConstraints(fieldConstraints);
+ }
+
+ form.addFieldDefinition(fieldDef);
+
+ // add the property value to the form
+ if (propValue != null)
+ {
+ if (propValue instanceof List)
{
- if (fieldData 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.
- fieldData = makeListString((List)fieldData);
- }
+ // 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 = makeListString((List)propValue);
+ }
+
+ form.addData(PROP_PREFIX + fieldDef.getName(), propValue);
+ }
+ }
+
+ /**
+ * 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
+ generateMimetypePropertyField(content, form);
- formData.addData(PROP_PREFIX + fieldDef.getName(), fieldData);
+ // setup encoding field
+ generateEncodingPropertyField(content, form);
+
+ // setup size field
+ generateSizePropertyField(content, form);
}
}
}
/**
- * Sets up the field definitions for the node's associations.
+ * Generates the field definition for the transient mimetype property
+ *
+ * @param content The ContentData object to generate the field from
+ * @param form The Form instance to populate
+ */
+ protected void generateMimetypePropertyField(ContentData content, Form form)
+ {
+ PropertyFieldDefinition mimetypeField = new PropertyFieldDefinition(
+ TRANSIENT_MIMETYPE, DataTypeDefinition.TEXT.toPrefixString(
+ this.namespaceService));
+ mimetypeField.setLabel(I18NUtil.getMessage(MSG_MIMETYPE_LABEL));
+ mimetypeField.setDescription(I18NUtil.getMessage(MSG_MIMETYPE_DESC));
+ form.addFieldDefinition(mimetypeField);
+ form.addData(PROP_PREFIX + TRANSIENT_MIMETYPE, content.getMimetype());
+ }
+
+ /**
+ * Generates the field definition for the transient encoding property
+ *
+ * @param content The ContentData object to generate the field from
+ * @param form The Form instance to populate
+ */
+ protected void generateEncodingPropertyField(ContentData content, Form form)
+ {
+ PropertyFieldDefinition encodingField = new PropertyFieldDefinition(
+ TRANSIENT_ENCODING, DataTypeDefinition.TEXT.toPrefixString(
+ this.namespaceService));
+ encodingField.setLabel(I18NUtil.getMessage(MSG_ENCODING_LABEL));
+ encodingField.setDescription(I18NUtil.getMessage(MSG_ENCODING_DESC));
+ form.addFieldDefinition(encodingField);
+ form.addData(PROP_PREFIX + TRANSIENT_ENCODING, content.getEncoding());
+ }
+
+ /**
+ * Generates the field definition for the transient size property
+ *
+ * @param content The ContentData object to generate the field from
+ * @param form The Form instance to populate
+ */
+ protected void generateSizePropertyField(ContentData content, Form form)
+ {
+ PropertyFieldDefinition sizeField = new PropertyFieldDefinition(
+ TRANSIENT_SIZE, DataTypeDefinition.LONG.toPrefixString(
+ this.namespaceService));
+ sizeField.setLabel(I18NUtil.getMessage(MSG_SIZE_LABEL));
+ sizeField.setDescription(I18NUtil.getMessage(MSG_SIZE_DESC));
+ sizeField.setProtectedField(true);
+ form.addFieldDefinition(sizeField);
+ form.addData(PROP_PREFIX + TRANSIENT_SIZE, new Long(content.getSize()));
+ }
+
+ /**
+ * 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
- * @param formData The FormData instance to populate
*/
@SuppressWarnings("unchecked")
- protected void generateAssociationFields(NodeRef nodeRef, Form form, FormData formData)
+ protected void generateAllAssociationFields(NodeRef nodeRef, Form form)
{
+ // ********************************************************
+ // re-factor this to gen. all assocs defs and not values
+ // ********************************************************
+
// add target association data
List associations = this.nodeService.getTargetAssocs(nodeRef,
RegexQNamePattern.MATCH_ALL);
@@ -431,11 +613,11 @@ public class NodeHandler extends AbstractHandler
// add the value as a List (or add to the list if the form data
// is already present)
- FieldData fieldData = formData.getData().get(prefixedAssocName);
+ FieldData fieldData = form.getFormData().getData().get(prefixedAssocName);
if (fieldData == null)
{
targets = new ArrayList(4);
- formData.addData(prefixedAssocName, targets);
+ form.addData(prefixedAssocName, targets);
}
else
{
@@ -448,7 +630,7 @@ public class NodeHandler extends AbstractHandler
else
{
// there should only be one value
- formData.addData(prefixedAssocName, assocValue);
+ form.addData(prefixedAssocName, assocValue);
}
}
}
@@ -459,9 +641,8 @@ public class NodeHandler extends AbstractHandler
*
* @param nodeRef The NodeRef of the node being setup
* @param form The Form instance to populate
- * @param formData The FormData instance to populate
*/
- protected void generateChildAssociationFields(NodeRef nodeRef, Form form, FormData formData)
+ protected void generateAllChildAssociationFields(NodeRef nodeRef, Form form)
{
List childAssocs = this.nodeService.getChildAssocs(nodeRef);
if (childAssocs.isEmpty())
@@ -527,7 +708,7 @@ public class NodeHandler extends AbstractHandler
// We don't want the whitespace or enclosing square brackets that come
// with java.util.List.toString(), hence the custom String construction.
- StringBuilder assocValue = new StringBuilder();
+ /*StringBuilder assocValue = new StringBuilder();
for (Iterator iter = values.iterator(); iter.hasNext(); )
{
ChildAssociationRef nextChild = iter.next();
@@ -537,55 +718,142 @@ public class NodeHandler extends AbstractHandler
assocValue.append(",");
}
}
- formData.addData(ASSOC_PREFIX + associationName, assocValue.toString());
+ form.addData(ASSOC_PREFIX + associationName, assocValue.toString());*/
+
+ List nodeRefs = new ArrayList(4);
+ for (Iterator iter = values.iterator(); iter.hasNext(); )
+ {
+ ChildAssociationRef nextChild = iter.next();
+ nodeRefs.add(nextChild.getChildRef().toString());
+ }
+ form.addData(ASSOC_PREFIX + associationName, nodeRefs);
}
}
/**
- * Sets up the field definitions for any transient fields that may be
- * useful, for example, 'mimetype', 'size' and 'encoding'.
+ * Sets up a field definition for the given association
*
- * @param nodeRef The NodeRef of the node being setup
+ * @param assocDef The AssociationDefinition of the field to generate
+ * @param assocValues The values of the association field
* @param form The Form instance to populate
- * @param formData The FormData instance to populate
*/
- protected void generateTransientFields(NodeRef nodeRef, Form form, FormData formData)
+ @SuppressWarnings("unchecked")
+ protected void generateAssociationField(AssociationDefinition assocDef,
+ List assocValues, 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))
+ String assocName = assocDef.getName().toPrefixString(this.namespaceService);
+ AssociationFieldDefinition fieldDef = new AssociationFieldDefinition(assocName,
+ assocDef.getTargetClass().getName().toPrefixString(
+ this.namespaceService), Direction.TARGET);
+ String title = assocDef.getTitle();
+ if (title == null)
{
- ContentData content = (ContentData)this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
- if (content != null)
+ title = assocName;
+ }
+ fieldDef.setLabel(title);
+ fieldDef.setDescription(assocDef.getDescription());
+ fieldDef.setProtectedField(assocDef.isProtected());
+ fieldDef.setEndpointMandatory(assocDef.isTargetMandatory());
+ fieldDef.setEndpointMany(assocDef.isTargetMany());
+
+ // add definition to the form
+ form.addFieldDefinition(fieldDef);
+
+ // add the association value to the form
+ String prefixedAssocName = ASSOC_PREFIX + assocName;
+
+ // determine the type of association values data and extract accordingly
+ List values = new ArrayList(4);
+ for (Object value : assocValues)
+ {
+ if (value instanceof ChildAssociationRef)
{
- // setup mimetype field
- PropertyFieldDefinition mimetypeField = new PropertyFieldDefinition(
- TRANSIENT_MIMETYPE, DataTypeDefinition.TEXT.toPrefixString(
- this.namespaceService));
- mimetypeField.setLabel(I18NUtil.getMessage(MSG_MIMETYPE_LABEL));
- mimetypeField.setDescription(I18NUtil.getMessage(MSG_MIMETYPE_DESC));
- form.addFieldDefinition(mimetypeField);
- formData.addData(PROP_PREFIX + TRANSIENT_MIMETYPE, content.getMimetype());
-
- // setup encoding field
- PropertyFieldDefinition encodingField = new PropertyFieldDefinition(
- TRANSIENT_ENCODING, DataTypeDefinition.TEXT.toPrefixString(
- this.namespaceService));
- encodingField.setLabel(I18NUtil.getMessage(MSG_ENCODING_LABEL));
- encodingField.setDescription(I18NUtil.getMessage(MSG_ENCODING_DESC));
- form.addFieldDefinition(encodingField);
- formData.addData(PROP_PREFIX + TRANSIENT_ENCODING, content.getEncoding());
-
- // setup size field
- PropertyFieldDefinition sizeField = new PropertyFieldDefinition(
- TRANSIENT_SIZE, DataTypeDefinition.LONG.toPrefixString(
- this.namespaceService));
- sizeField.setLabel(I18NUtil.getMessage(MSG_SIZE_LABEL));
- sizeField.setDescription(I18NUtil.getMessage(MSG_SIZE_DESC));
- sizeField.setProtectedField(true);
- form.addFieldDefinition(sizeField);
- formData.addData(PROP_PREFIX + TRANSIENT_SIZE, new Long(content.getSize()));
+ 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.
+ // TODO: Do we also return a well known named list of association names
+ // for each noderef so that clients do not have extra work to do
+ // to display the current values to the user
+ form.addData(prefixedAssocName, values);
+ }
+
+ /*
+ * @see org.alfresco.repo.forms.processor.FormProcessorHandler#handlePersist(java.lang.Object, org.alfresco.repo.forms.FormData)
+ */
+ public void handlePersist(Object item, FormData data)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Persisting form for: " + item);
+
+ // cast to the expected NodeRef representation
+ NodeRef nodeRef = (NodeRef)item;
+
+ // persist the node
+ persistNode(nodeRef, data);
+ }
+
+ /**
+ * Persists the given FormData on the given NodeRef
+ *
+ * @param nodeRef The NodeRef to persist the form data on
+ * @param data The FormData to persist
+ */
+ protected void persistNode(NodeRef nodeRef, FormData data)
+ {
+ // get the property definitions for the type of node being persisted
+ QName type = this.nodeService.getType(nodeRef);
+ TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type,
+ this.nodeService.getAspects(nodeRef));
+ Map assocDefs = typeDef.getAssociations();
+ Map childAssocDefs = typeDef.getChildAssociations();
+ Map propDefs = typeDef.getProperties();
+
+ Map propsToPersist = new HashMap(data.getData().size());
+ List assocsToPersist = new ArrayList();
+
+ for (String dataKey : data.getData().keySet())
+ {
+ FieldData fieldData = data.getData().get(dataKey);
+ // NOTE: ignore file fields for now, not supported yet!
+ if (fieldData.isFile() == false)
+ {
+ String fieldName = fieldData.getName();
+
+ if (fieldName.startsWith(PROP_PREFIX))
+ {
+ processPropertyPersist(nodeRef, propDefs, fieldData, propsToPersist);
+ }
+ else if (fieldName.startsWith(ASSOC_PREFIX))
+ {
+ processAssociationPersist(nodeRef, assocDefs, childAssocDefs, fieldData, assocsToPersist);
+ }
+ else if (logger.isWarnEnabled())
+ {
+ logger.warn("Ignoring unrecognised field '" + fieldName + "'");
+ }
+ }
+ }
+
+ // persist the properties using addProperties as this changes the repo values of
+ // those properties included in the Map, but leaves any other property values unchanged,
+ // whereas setProperties causes the deletion of properties that are not included in the Map.
+ this.nodeService.addProperties(nodeRef, propsToPersist);
+
+ for (AbstractAssocCommand cmd : assocsToPersist)
+ {
+ //TODO If there is an attempt to add and remove the same assoc in one request,
+ // we could drop each request and do nothing.
+ cmd.updateAssociations(nodeService);
}
}
@@ -946,33 +1214,6 @@ public class NodeHandler extends AbstractHandler
}
}
- /**
- * Returns a Collection of aspects for the given noderef to use
- * for generating and persisting the form.
- *
- * @param nodeRef The NodeRef of the node to get aspects for
- * @return The Collection of aspects
- */
- protected Collection getAspectsToInclude(NodeRef nodeRef)
- {
- List currentAspects = new ArrayList();
- currentAspects.addAll(this.nodeService.getAspects(nodeRef));
-
- // TODO: make the list of aspects to ensure are present configurable
-
- // make sure the titled and author aspects are present
- if (currentAspects.contains(ContentModel.ASPECT_TITLED) == false)
- {
- currentAspects.add(ContentModel.ASPECT_TITLED);
- }
- if (currentAspects.contains(ContentModel.ASPECT_AUTHOR) == false)
- {
- currentAspects.add(ContentModel.ASPECT_AUTHOR);
- }
-
- return currentAspects;
- }
-
/**
* Returns a comma separated list string of the given list object.
*
diff --git a/source/java/org/alfresco/repo/forms/script/ScriptForm.java b/source/java/org/alfresco/repo/forms/script/ScriptForm.java
index 6c175a316a..a600af641d 100644
--- a/source/java/org/alfresco/repo/forms/script/ScriptForm.java
+++ b/source/java/org/alfresco/repo/forms/script/ScriptForm.java
@@ -58,9 +58,14 @@ public class ScriptForm implements Serializable
}
}
- public String getItem()
+ public String getItemKind()
{
- return form.getItem();
+ return form.getItem().getKind();
+ }
+
+ public String getItemId()
+ {
+ return form.getItem().getId();
}
public String getType()
diff --git a/source/java/org/alfresco/repo/forms/script/ScriptFormService.java b/source/java/org/alfresco/repo/forms/script/ScriptFormService.java
index 2d6a32b137..19d4d48f62 100644
--- a/source/java/org/alfresco/repo/forms/script/ScriptFormService.java
+++ b/source/java/org/alfresco/repo/forms/script/ScriptFormService.java
@@ -24,11 +24,14 @@
*/
package org.alfresco.repo.forms.script;
+import java.util.Arrays;
+import java.util.List;
+
import org.alfresco.repo.forms.Form;
import org.alfresco.repo.forms.FormData;
import org.alfresco.repo.forms.FormService;
+import org.alfresco.repo.forms.Item;
import org.alfresco.repo.jscript.BaseScopableProcessorExtension;
-import org.alfresco.service.ServiceRegistry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -40,22 +43,10 @@ import org.apache.commons.logging.LogFactory;
public class ScriptFormService extends BaseScopableProcessorExtension
{
private static Log logger = LogFactory.getLog(ScriptFormService.class);
- /** Service Registry */
- private ServiceRegistry serviceRegistry;
-
+
/** The site service */
private FormService formService;
- /**
- * Sets the Service Registry
- *
- * @param serviceRegistry
- */
- public void setServiceRegistry(ServiceRegistry serviceRegistry)
- {
- this.serviceRegistry = serviceRegistry;
- }
-
/**
* Set the form service
*
@@ -68,25 +59,79 @@ public class ScriptFormService extends BaseScopableProcessorExtension
}
/**
- * Returns the form for the given item
+ * Returns a form representation of the given item,
+ * all known fields for the item are included.
*
- * @param item The item to retrieve a form for
+ * @param itemKind The kind of item to retrieve a form for
+ * @param itemId The identifier of the item to retrieve a form for
* @return The form
*/
- public ScriptForm getForm(String item)
+ public ScriptForm getForm(String itemKind, String itemId)
{
- Form result = formService.getForm(item);
+ return getForm(itemKind, itemId, null);
+ }
+
+ /**
+ * Returns a form representation of the given item consisting
+ * only of the given fields.
+ *
+ * @param itemKind The kind of item to retrieve a form for
+ * @param itemId The identifier of the item to retrieve a form for
+ * @param fields String array of fields to include, null
+ * indicates all possible fields for the item
+ * should be included
+ * @return The form
+ */
+ public ScriptForm getForm(String itemKind, String itemId, String[] fields)
+ {
+ return getForm(itemKind, itemId, fields, null);
+ }
+
+ /**
+ * Returns a form representation of the given item consisting
+ * only of the given fields.
+ *
+ * @param itemKind The kind of item to retrieve a form for
+ * @param itemId The identifier of the item to retrieve a form for
+ * @param fields String array of fields to include, null
+ * indicates all possible fields for the item
+ * should be included
+ * @param forcedFields List of field names from 'fields' list
+ * that should be forcibly included, it is
+ * up to the form processor implementation
+ * to determine how to enforce this
+ * @return The form
+ */
+ public ScriptForm getForm(String itemKind, String itemId,
+ String[] fields, String[] forcedFields)
+ {
+ // create List representations of field params if necessary
+ List fieldsList = null;
+ List forcedFieldsList = null;
+
+ if (fields != null)
+ {
+ fieldsList = Arrays.asList(fields);
+ }
+
+ if (forcedFields != null)
+ {
+ forcedFieldsList = Arrays.asList(forcedFields);
+ }
+
+ Form result = formService.getForm(new Item(itemKind, itemId), fieldsList, forcedFieldsList);
return result == null ? null : new ScriptForm(result);
}
/**
* Persists the given data object for the item provided
*
- * @param item The item to persist the data for
+ * @param itemKind The kind of item to retrieve a form for
+ * @param itemId The identifier of the item to retrieve a form for
* @param postData The post data, this can be a Map of name value
* pairs, a webscript FormData object or a JSONObject
*/
- public void saveForm(String item, Object postData)
+ public void saveForm(String itemKind, String itemId, Object postData)
{
// A note on data conversion as passed in to this method:
// Each of the 3 submission methods (multipart/formdata, JSON Post and
@@ -109,6 +154,6 @@ public class ScriptFormService extends BaseScopableProcessorExtension
return;
}
- formService.saveForm(item, dataForFormService);
+ formService.saveForm(new Item(itemKind, itemId), dataForFormService);
}
}
diff --git a/source/java/org/alfresco/repo/forms/script/test_formService.js b/source/java/org/alfresco/repo/forms/script/test_formService.js
index 99044bcb2d..3e2107470b 100644
--- a/source/java/org/alfresco/repo/forms/script/test_formService.js
+++ b/source/java/org/alfresco/repo/forms/script/test_formService.js
@@ -3,37 +3,48 @@ function testGetFormForNonExistentContentNode()
// Replace all the digits in the ID with an 'x'.
// Surely that node will not exist...
var corruptedTestDoc = testDoc.replace(/\d/g, "x");
- var form = formService.getForm(corruptedTestDoc);
+ var form = null;
+
+ try
+ {
+ form = formService.getForm("node", corruptedTestDoc);
+ }
+ catch (e)
+ {
+ // expected
+ }
+
test.assertNull(form, "Form should have not been found: " + testDoc);
}
function testGetFormForContentNode()
{
- // Get a known form and check its various attributes/properties.
- var form = formService.getForm(testDoc);
- test.assertNotNull(form, "Form should have been found: " + testDoc);
-
- test.assertEquals(testDoc, form.item);
- test.assertEquals('cm:content', form.type);
-
- test.assertNull(form.fieldGroups, "form.fieldGroups should be null.");
-
- var fieldDefs = form.fieldDefinitions;
- test.assertNotNull(fieldDefs, "field definitions should not be null.");
- test.assertEquals(23, fieldDefs.length);
-
- // as we know there are no duplicates we can safely create a map of the
- // field definitions for the purposes of this test
- var fieldDefnDataHash = {};
- var fieldDef = null;
- for (var x = 0; x < fieldDefs.length; x++)
- {
- fieldDef = fieldDefs[x];
- fieldDefnDataHash[fieldDef.name] = fieldDef;
- }
-
- var nameField = fieldDefnDataHash['cm:name'];
- var titleField = fieldDefnDataHash['cm:title'];
+ // Get a known form and check its various attributes/properties.
+ var form = formService.getForm("node", testDoc);
+ test.assertNotNull(form, "Form should have been found for: " + testDoc);
+
+ test.assertEquals("node", form.itemKind);
+ test.assertEquals(testDoc, form.itemId);
+ test.assertEquals('cm:content', form.type);
+
+ test.assertNull(form.fieldGroups, "form.fieldGroups should be null.");
+
+ var fieldDefs = form.fieldDefinitions;
+ test.assertNotNull(fieldDefs, "field definitions should not be null.");
+ test.assertEquals(22, fieldDefs.length);
+
+ // as we know there are no duplicates we can safely create a map of the
+ // field definitions for the purposes of this test
+ var fieldDefnDataHash = {};
+ var fieldDef = null;
+ for (var x = 0; x < fieldDefs.length; x++)
+ {
+ fieldDef = fieldDefs[x];
+ fieldDefnDataHash[fieldDef.name] = fieldDef;
+ }
+
+ var nameField = fieldDefnDataHash['cm:name'];
+ var titleField = fieldDefnDataHash['cm:title'];
var descField = fieldDefnDataHash['cm:description'];
var originatorField = fieldDefnDataHash['cm:originator'];
var addresseeField = fieldDefnDataHash['cm:addressee'];
@@ -101,6 +112,7 @@ function testGetFormForContentNode()
test.assertNotNull(fieldData, "fieldData should not be null.");
test.assertNotNull(fieldData.length, "fieldData.length should not be null.");
+ test.assertEquals(testDocName, fieldData["prop:cm:name"].value);
test.assertEquals("This is the title for the test document", fieldData["prop:cm:title"].value);
test.assertEquals("This is the description for the test document", fieldData["prop:cm:description"].value);
test.assertEquals("fred@customer.com", fieldData["prop:cm:originator"].value);
@@ -126,6 +138,195 @@ function testGetFormForContentNode()
test.assertEquals(testAssociatedDoc, targets);
}
+function testGetFormForFolderNode()
+{
+ // Get a known form and check its various attributes/properties.
+ var form = formService.getForm("node", folder);
+ test.assertNotNull(form, "Form should have been found for: " + testDoc);
+
+ test.assertEquals("node", form.itemKind);
+ test.assertEquals(folder, form.itemId);
+ test.assertEquals('cm:folder', form.type);
+
+ test.assertNull(form.fieldGroups, "form.fieldGroups should be null.");
+
+ var fieldDefs = form.fieldDefinitions;
+ test.assertNotNull(fieldDefs, "field definitions should not be null.");
+ test.assertEquals(11, fieldDefs.length);
+
+ // as we know there are no duplicates we can safely create a map of the
+ // field definitions for the purposes of this test
+ var fieldDefnDataHash = {};
+ var fieldDef = null;
+ for (var x = 0; x < fieldDefs.length; x++)
+ {
+ fieldDef = fieldDefs[x];
+ fieldDefnDataHash[fieldDef.name] = fieldDef;
+ }
+
+ var nameField = fieldDefnDataHash['cm:name'];
+ var containsField = fieldDefnDataHash['cm:contains'];
+
+ test.assertNotNull(nameField, "Expecting to find the cm:name field");
+ test.assertNotNull(containsField, "Expecting to find the cm:contains field");
+
+ // check the labels of all the fields
+ test.assertEquals("Name", nameField.label);
+ test.assertEquals("Contains", containsField.label);
+
+ // check details of name field
+ test.assertEquals("d:text", nameField.dataType);
+ test.assertTrue(nameField.mandatory);
+ // Expecting cm:name to be single-valued.
+ test.assertFalse(nameField.repeating, "nameField.repeating was not false.");
+
+ // compare the association details
+ test.assertEquals("TARGET", "" + containsField.endpointDirection);
+ test.assertFalse(containsField.endpointMandatory, "containsField.endpointMandatory was not false.");
+ test.assertTrue(containsField.endpointMany, "constainsField.endpointMany was not true.");
+
+ // check the form data
+ var formData = form.formData;
+ test.assertNotNull(formData, "formData should not be null.");
+ var fieldData = formData.data;
+ test.assertNotNull(fieldData, "fieldData should not be null.");
+ test.assertNotNull(fieldData.length, "fieldData.length should not be null.");
+
+ test.assertEquals(folderName, fieldData["prop:cm:name"].value);
+ var children = fieldData["assoc:cm:contains"].value;
+ test.assertNotNull(children, "children should not be null.");
+ var childrenArr = children.split(",");
+ test.assertTrue(childrenArr.length == 3, "Expecting there to be 3 children");
+}
+
+function testGetFormWithSelectedFields()
+{
+ // Define list of fields to retrieve
+ var fields = [];
+ fields.push("cm:name");
+ fields.push("cm:title");
+ fields.push("mimetype");
+ fields.push("cm:modified");
+ // add field that will be missing
+ fields.push("cm:author");
+
+ // Get a a form for the given fields
+ var form = formService.getForm("node", testDoc, fields);
+ test.assertNotNull(form, "Form should have been found for: " + testDoc);
+
+ var fieldDefs = form.fieldDefinitions;
+ test.assertNotNull(fieldDefs, "field definitions should not be null.");
+ test.assertEquals(4, fieldDefs.length);
+
+ // as we know there are no duplicates we can safely create a map of the
+ // field definitions for the purposes of this test
+ var fieldDefnDataHash = {};
+ var fieldDef = null;
+ for (var x = 0; x < fieldDefs.length; x++)
+ {
+ fieldDef = fieldDefs[x];
+ fieldDefnDataHash[fieldDef.name] = fieldDef;
+ }
+
+ var nameField = fieldDefnDataHash['cm:name'];
+ var titleField = fieldDefnDataHash['cm:title'];
+ var mimetypeField = fieldDefnDataHash['mimetype'];
+ var modifiedField = fieldDefnDataHash['cm:modified'];
+ var authorField = fieldDefnDataHash['cm:author'];
+
+ test.assertNotNull(nameField, "Expecting to find the cm:name field");
+ test.assertNotNull(titleField, "Expecting to find the cm:title field");
+ test.assertNotNull(mimetypeField, "Expecting to find the mimetype field");
+ test.assertNotNull(modifiedField, "Expecting to find the cm:modified field");
+ test.assertTrue(authorField === undefined, "Expecting cm:author field to be missing");
+
+ // check the labels of all the fields
+ test.assertEquals("Name", nameField.label);
+ test.assertEquals("Title", titleField.label);
+ test.assertEquals("Mimetype", mimetypeField.label);
+ test.assertEquals("Modified Date", modifiedField.label);
+
+ // check the form data
+ var formData = form.formData;
+ test.assertNotNull(formData, "formData should not be null.");
+ var fieldData = formData.data;
+ test.assertNotNull(fieldData, "fieldData should not be null.");
+ test.assertNotNull(fieldData.length, "fieldData.length should not be null.");
+
+ test.assertEquals(testDocName, fieldData["prop:cm:name"].value);
+ test.assertEquals("This is the title for the test document", fieldData["prop:cm:title"].value);
+}
+
+function testGetFormWithForcedFields()
+{
+ // Define list of fields to retrieve
+ var fields = [];
+ fields.push("cm:name");
+ fields.push("cm:title");
+ fields.push("mimetype");
+ fields.push("cm:modified");
+ fields.push("cm:author");
+ fields.push("cm:wrong");
+
+ // define a list of fields to force
+ var force = [];
+ force.push("cm:author");
+ force.push("cm:wrong");
+
+ // Get a a form for the given fields
+ var form = formService.getForm("node", testDoc, fields, force);
+ test.assertNotNull(form, "Form should have been found for: " + testDoc);
+
+ var fieldDefs = form.fieldDefinitions;
+ test.assertNotNull(fieldDefs, "field definitions should not be null.");
+ test.assertEquals(5, fieldDefs.length);
+
+ // as we know there are no duplicates we can safely create a map of the
+ // field definitions for the purposes of this test
+ var fieldDefnDataHash = {};
+ var fieldDef = null;
+ for (var x = 0; x < fieldDefs.length; x++)
+ {
+ fieldDef = fieldDefs[x];
+ fieldDefnDataHash[fieldDef.name] = fieldDef;
+ }
+
+ var nameField = fieldDefnDataHash['cm:name'];
+ var titleField = fieldDefnDataHash['cm:title'];
+ var mimetypeField = fieldDefnDataHash['mimetype'];
+ var modifiedField = fieldDefnDataHash['cm:modified'];
+ var authorField = fieldDefnDataHash['cm:author'];
+ var wrongField = fieldDefnDataHash['cm:wrong'];
+
+ test.assertNotNull(nameField, "Expecting to find the cm:name field");
+ test.assertNotNull(titleField, "Expecting to find the cm:title field");
+ test.assertNotNull(mimetypeField, "Expecting to find the mimetype field");
+ test.assertNotNull(modifiedField, "Expecting to find the cm:modified field");
+ test.assertNotNull(authorField, "Expecting to find the cm:author field");
+ test.assertTrue(wrongField === undefined, "Expecting cm:wrong field to be missing");
+
+ // check the labels of all the fields
+ test.assertEquals("Name", nameField.label);
+ test.assertEquals("Title", titleField.label);
+ test.assertEquals("Mimetype", mimetypeField.label);
+ test.assertEquals("Modified Date", modifiedField.label);
+ test.assertEquals("Author", authorField.label);
+
+ // check the form data
+ var formData = form.formData;
+ test.assertNotNull(formData, "formData should not be null.");
+ var fieldData = formData.data;
+ test.assertNotNull(fieldData, "fieldData should not be null.");
+ test.assertNotNull(fieldData.length, "fieldData.length should not be null.");
+
+ test.assertEquals(testDocName, fieldData["prop:cm:name"].value);
+ test.assertEquals("This is the title for the test document", fieldData["prop:cm:title"].value);
+ test.assertNull(fieldData["prop:cm:author"], "Expecting cm:author to be null");
+}
+
// Execute tests
testGetFormForNonExistentContentNode();
-testGetFormForContentNode();
\ No newline at end of file
+testGetFormForContentNode();
+testGetFormForFolderNode();
+testGetFormWithSelectedFields();
+testGetFormWithForcedFields();