First cut of MOB-837 (type support in forms)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14606 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Gavin Cornwell
2009-06-09 15:00:51 +00:00
parent e4c1d31655
commit 65a61fa306
6 changed files with 313 additions and 20 deletions

View File

@@ -78,6 +78,19 @@
</property> </property>
</bean> </bean>
<bean id="typeFormProcessor"
class="org.alfresco.repo.forms.processor.node.TypeFormProcessor"
parent="filteredFormProcessor">
<!-- <property name="filterRegistry" ref="nodeFilterRegistry" /> -->
<property name="nodeService" ref="NodeService" />
<property name="fileFolderService" ref="FileFolderService" />
<property name="dictionaryService" ref="DictionaryService" />
<property name="namespaceService" ref="NamespaceService" />
<property name="matchPattern">
<value>type</value>
</property>
</bean>
<!-- Filters --> <!-- Filters -->
<bean id="baseFormFilter" abstract="true" init-method="register" <bean id="baseFormFilter" abstract="true" init-method="register"
class="org.alfresco.repo.forms.processor.AbstractFilter" /> class="org.alfresco.repo.forms.processor.AbstractFilter" />

View File

@@ -39,7 +39,6 @@ import org.alfresco.repo.forms.AssociationFieldDefinition.Direction;
import org.alfresco.repo.forms.PropertyFieldDefinition.FieldConstraint; import org.alfresco.repo.forms.PropertyFieldDefinition.FieldConstraint;
import org.alfresco.repo.jscript.ClasspathScriptLocation; import org.alfresco.repo.jscript.ClasspathScriptLocation;
import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
@@ -108,6 +107,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
private static final String USER_ONE = "UserOne_FormServiceImplTest"; private static final String USER_ONE = "UserOne_FormServiceImplTest";
private static final String NODE_FORM_ITEM_KIND = "node"; private static final String NODE_FORM_ITEM_KIND = "node";
private static final String TYPE_FORM_ITEM_KIND = "type";
/** /**
* Called during the transaction setup * Called during the transaction setup
@@ -804,6 +804,55 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
*/ */
} }
// TODO: enable this once the RM caveat stuff is fixed
public void xtestGetAllCreateForm() throws Exception
{
// get a form for the cm:content type
Form form = this.formService.getForm(new Item(TYPE_FORM_ITEM_KIND, "cm:content"));
// check a form got returned
assertNotNull("Expecting form to be present", form);
// check item identifier matches
assertEquals(TYPE_FORM_ITEM_KIND, form.getItem().getKind());
assertEquals("cm:content", form.getItem().getId());
// check the type is correct
assertEquals(ContentModel.TYPE_CONTENT.toPrefixString(this.namespaceService),
form.getItem().getType());
// check there is no group info
assertNull("Expecting the form groups to be null!", form.getFieldGroups());
// check the field definitions
Collection<FieldDefinition> fieldDefs = form.getFieldDefinitions();
assertNotNull("Expecting to find fields", fieldDefs);
assertEquals("Expecting to find 11 fields", 11, fieldDefs.size());
// create a Map of the field definitions
// NOTE: we can safely do this as we know there are no duplicate field names and we're not
// concerned with ordering!
Map<String, FieldDefinition> fieldDefMap = new HashMap<String, FieldDefinition>(fieldDefs.size());
for (FieldDefinition fieldDef : fieldDefs)
{
fieldDefMap.put(fieldDef.getName(), fieldDef);
}
// find the fields
PropertyFieldDefinition nameField = (PropertyFieldDefinition)fieldDefMap.get("cm:name");
PropertyFieldDefinition createdField = (PropertyFieldDefinition)fieldDefMap.get("cm:created");
PropertyFieldDefinition creatorField = (PropertyFieldDefinition)fieldDefMap.get("cm:creator");
PropertyFieldDefinition modifiedField = (PropertyFieldDefinition)fieldDefMap.get("cm:modified");
PropertyFieldDefinition modifierField = (PropertyFieldDefinition)fieldDefMap.get("cm:modifier");
// check fields are present
assertNotNull("Expecting to find the cm:name field", nameField);
assertNotNull("Expecting to find the cm:created field", createdField);
assertNotNull("Expecting to find the cm:creator field", creatorField);
assertNotNull("Expecting to find the cm:modified field", modifiedField);
assertNotNull("Expecting to find the cm:modifier field", modifierField);
}
public void testNoForm() throws Exception public void testNoForm() throws Exception
{ {
// test that a form can not be retrieved for a non-existent item // test that a form can not be retrieved for a non-existent item

View File

@@ -26,6 +26,7 @@ package org.alfresco.repo.forms.processor.node;
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;
@@ -260,7 +261,7 @@ public class NodeFormProcessor extends FilteredFormProcessor
if (fields != null && fields.size() > 0) if (fields != null && fields.size() > 0)
{ {
generateSelectedFields(nodeRef, fields, forcedFields, form); generateSelectedFields(nodeRef, null, fields, forcedFields, form);
} }
else else
{ {
@@ -273,28 +274,52 @@ public class NodeFormProcessor extends FilteredFormProcessor
/** /**
* Sets up the field definitions for all the requested fields. * Sets up the field definitions for all the requested fields.
* If any of the requested fields are not present on the node and they * <p>
* appear in the forcedFields list an attempt to find a model * 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. * definition for those fields is made so they can be included.
* </p>
* *
* @param nodeRef The NodeRef of the node being setup * @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 fields Restricted list of fields to include
* @param forcedFields List of field names that should be included * @param forcedFields List of field names that should be included
* even if the field is not currently present * even if the field is not currently present
* @param form The Form instance to populate * @param form The Form instance to populate
*/ */
protected void generateSelectedFields(NodeRef nodeRef, List<String> fields, List<String> forcedFields, Form form) 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 (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("Generating selected fields: " + fields + " and forcing: " + forcedFields); logger.debug("Generating selected fields: " + fields + " and forcing: " + forcedFields);
// get data dictionary definition for node // get data dictionary definition for node if it is provided
QName type = this.nodeService.getType(nodeRef); QName type = null;
TypeDefinition typeDef = this.dictionaryService.getAnonymousType(type, Map<QName, Serializable> propValues = Collections.emptyMap();
this.nodeService.getAspects(nodeRef));
if (nodeRef != null)
{
type = this.nodeService.getType(nodeRef);
typeDef = this.dictionaryService.getAnonymousType(type, this.nodeService.getAspects(nodeRef));
propValues = this.nodeService.getProperties(nodeRef);
}
else
{
type = typeDef.getName();
}
Map<QName, PropertyDefinition> propDefs = typeDef.getProperties(); Map<QName, PropertyDefinition> propDefs = typeDef.getProperties();
Map<QName, AssociationDefinition> assocDefs = typeDef.getAssociations(); Map<QName, AssociationDefinition> assocDefs = typeDef.getAssociations();
Map<QName, Serializable> propValues = this.nodeService.getProperties(nodeRef);
for (String fieldName : fields) for (String fieldName : fields)
{ {
@@ -365,7 +390,8 @@ public class NodeFormProcessor extends FilteredFormProcessor
{ {
// generate the association field // generate the association field
generateAssociationField(assocDef, generateAssociationField(assocDef,
retrieveAssociationValues(nodeRef, assocDef), form); (nodeRef != null) ? retrieveAssociationValues(nodeRef, assocDef) : null,
form);
foundField = true; foundField = true;
} }
@@ -382,7 +408,8 @@ public class NodeFormProcessor extends FilteredFormProcessor
else if (logger.isDebugEnabled()) else if (logger.isDebugEnabled())
{ {
logger.debug("Ignoring field \"" + fieldName + logger.debug("Ignoring field \"" + fieldName +
"\" as it is not defined for the current node and it does not appear in the 'force' list"); "\" as it is not defined for the current " + ((nodeRef != null) ? "node" : "type") +
" and it does not appear in the 'force' list");
} }
} }
} }
@@ -393,7 +420,7 @@ public class NodeFormProcessor extends FilteredFormProcessor
TRANSIENT_SIZE.equals(fieldName)) TRANSIENT_SIZE.equals(fieldName))
{ {
// if the node type is content or sublcass thereof generate appropriate field // if the node type is content or sublcass thereof generate appropriate field
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT)) if (nodeRef != null && this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT))
{ {
ContentData content = (ContentData)this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); ContentData content = (ContentData)this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
if (content != null) if (content != null)

View File

@@ -0,0 +1,196 @@
/*
* 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.util.List;
import java.util.Map;
import org.alfresco.repo.forms.Form;
import org.alfresco.repo.forms.FormData;
import org.alfresco.repo.forms.FormNotFoundException;
import org.alfresco.repo.forms.Item;
import org.alfresco.service.cmr.dictionary.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.namespace.InvalidQNameException;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* FormProcessor implementation that can generate and persist Form objects
* for types in the Alfresco content model.
*
* @author Gavin Cornwell
*/
public class TypeFormProcessor extends NodeFormProcessor
{
/** Logger */
private static Log logger = LogFactory.getLog(TypeFormProcessor.class);
@Override
protected Object getTypedItem(Item item)
{
TypeDefinition typeDef = null;
try
{
// convert the prefix type into full QName representation
// TODO: Also look for and deal with full QName as itemId
QName type = QName.createQName(item.getId(), this.namespaceService);
// retrieve the type from the dictionary
typeDef = this.dictionaryService.getType(type);
if (typeDef == null)
{
throw new FormNotFoundException(item,
new IllegalArgumentException("Type does not exist: " + item.getId()));
}
}
catch (InvalidQNameException iqne)
{
throw new FormNotFoundException(item, iqne);
}
// return the type definition object for the requested type
return typeDef;
}
@Override
protected void internalGenerate(Object item, List<String> fields, List<String> forcedFields, Form form)
{
if (logger.isDebugEnabled())
logger.debug("Generating form for item: " + item);
// cast to the expected NodeRef representation
TypeDefinition typeDef = (TypeDefinition)item;
// generate the form for the node
generateType(typeDef, 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);
}
}
/**
* 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, null, form);
}
// 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, null, form);
}
}
}
/**
* 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())
{
this.generateAssociationField(assocDef, null, form);
}
// 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())
{
this.generateAssociationField(assocDef, null, form);
}
}
}
@Override
protected Object internalPersist(Object item, FormData data)
{
if (logger.isDebugEnabled())
logger.debug("Persisting form for: " + item);
// cast to the expected NodeRef representation
TypeDefinition typeDef = (TypeDefinition)item;
if (logger.isWarnEnabled())
logger.warn("Persisting of 'type' form items has not been implemented yet!");
return item;
}
}

View File

@@ -51,8 +51,13 @@ public class ScriptForm implements Serializable
this.form = formObject; this.form = formObject;
fieldDefinitionData = new HashMap<String, FieldDefinition>(); fieldDefinitionData = new HashMap<String, FieldDefinition>();
for (FieldDefinition fd : form.getFieldDefinitions()) { List<FieldDefinition> fieldDefs = form.getFieldDefinitions();
fieldDefinitionData.put(fd.getName(), fd); if (fieldDefs != null)
{
for (FieldDefinition fd : fieldDefs)
{
fieldDefinitionData.put(fd.getName(), fd);
}
} }
} }

View File

@@ -51,10 +51,13 @@ public class ScriptFormData implements Serializable
public ScriptableHashMap<String, ScriptFieldData> getData() public ScriptableHashMap<String, ScriptFieldData> getData()
{ {
ScriptableHashMap<String, ScriptFieldData> result = new ScriptableHashMap<String, ScriptFieldData>(); ScriptableHashMap<String, ScriptFieldData> result = new ScriptableHashMap<String, ScriptFieldData>();
for (String k : formData.getData().keySet()) if (this.formData != null)
{ {
ScriptFieldData wrappedFieldData = new ScriptFieldData(formData.getData().get(k)); for (String k : formData.getData().keySet())
result.put(k, wrappedFieldData); {
ScriptFieldData wrappedFieldData = new ScriptFieldData(formData.getData().get(k));
result.put(k, wrappedFieldData);
}
} }
return result; return result;
} }