mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-07 18:25:23 +00:00
Implemented persistence for the WorkflowFormProcessor.
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21258 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
parent
2bfa74df80
commit
18f23482b6
@ -1252,7 +1252,8 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
|
||||
fields.add("bpm:workflowDueDate");
|
||||
fields.add("packageItems");
|
||||
|
||||
String workflowDefName = "jbpm$wf:adhoc";
|
||||
// Use URL-friendly format.
|
||||
String workflowDefName = "jbpm_wf_adhoc";
|
||||
Form form = this.formService.getForm(new Item(WORKFLOW_FORM_ITEM_KIND, workflowDefName), fields);
|
||||
|
||||
// check a form got returned
|
||||
@ -1310,7 +1311,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
|
||||
assertTrue("Expecting there to be more tasks", tasksAfter > tasksBefore);
|
||||
|
||||
// check workflow instance details
|
||||
assertEquals(workflowDefName, workflow.definition.name);
|
||||
assertEquals("jbpm$wf:adhoc", workflow.definition.name);
|
||||
}
|
||||
|
||||
public void testNoForm() throws Exception
|
||||
|
@ -33,9 +33,7 @@ public abstract class AbstractFieldProcessor<Data> implements FieldProcessor
|
||||
public Field generateField(String fieldName, FormCreationData data)
|
||||
{
|
||||
Data typedData = checkDataType(data.getItemData());
|
||||
Field field = generateTypedField(fieldName, data, typedData);
|
||||
logIfFieldNotFound(field, fieldName);
|
||||
return field;
|
||||
return generateTypedField(fieldName, data, typedData);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -53,18 +51,6 @@ public abstract class AbstractFieldProcessor<Data> implements FieldProcessor
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
|
@ -24,4 +24,5 @@ import org.alfresco.repo.forms.Field;
|
||||
public interface FieldProcessor
|
||||
{
|
||||
Field generateField(String fieldName, FormCreationData data);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public interface FormPersister<PersistType>
|
||||
{
|
||||
PersistType persist();
|
||||
}
|
@ -31,14 +31,12 @@ import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.forms.Field;
|
||||
import org.alfresco.repo.forms.FieldDefinition;
|
||||
import org.alfresco.repo.forms.Form;
|
||||
import org.alfresco.repo.forms.FormData;
|
||||
import org.alfresco.repo.forms.FormException;
|
||||
import org.alfresco.repo.forms.PropertyFieldDefinition;
|
||||
import org.alfresco.repo.forms.FormData.FieldData;
|
||||
import org.alfresco.repo.forms.processor.FilteredFormProcessor;
|
||||
import org.alfresco.repo.forms.processor.FormCreationData;
|
||||
import org.alfresco.repo.forms.processor.workflow.DataKeyMatcher;
|
||||
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition;
|
||||
@ -146,6 +144,8 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
|
||||
*/
|
||||
protected Pattern associationNamePattern = Pattern.compile(ASSOC_DATA_PREFIX + "([a-zA-Z0-9]+)_(.*)(_[a-zA-Z]+)");
|
||||
|
||||
private DataKeyMatcher keyMatcher;
|
||||
|
||||
/**
|
||||
* Sets the node service
|
||||
*
|
||||
@ -184,6 +184,7 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
this.keyMatcher = new DataKeyMatcher(namespaceService);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -807,6 +808,7 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
|
||||
|
||||
return mimetype;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,7 +21,6 @@ package org.alfresco.repo.forms.processor.node;
|
||||
|
||||
import org.alfresco.repo.forms.Field;
|
||||
import org.alfresco.repo.forms.FieldDefinition;
|
||||
import org.alfresco.repo.forms.PropertyFieldDefinition;
|
||||
import org.alfresco.repo.forms.processor.AbstractFieldProcessor;
|
||||
import org.alfresco.repo.forms.processor.FormCreationData;
|
||||
|
||||
|
@ -27,14 +27,14 @@ import org.alfresco.service.namespace.QName;
|
||||
*/
|
||||
public class DataKeyInfo
|
||||
{
|
||||
private final String dataKey;
|
||||
private final String fieldName;
|
||||
private final QName qName;
|
||||
private final FieldType fieldType;
|
||||
private final boolean isAdd;
|
||||
|
||||
private DataKeyInfo(String dataKey, QName qName, FieldType fieldType, boolean isAdd)
|
||||
{
|
||||
this.dataKey = dataKey;
|
||||
this.fieldName = dataKey;
|
||||
this.qName = qName;
|
||||
this.fieldType = fieldType;
|
||||
this.isAdd = isAdd;
|
||||
@ -50,23 +50,28 @@ public class DataKeyInfo
|
||||
return new DataKeyInfo(dataKey, qName, FieldType.PROPERTY, true);
|
||||
}
|
||||
|
||||
public static DataKeyInfo makeTransientDataKeyInfo(String dataKey)
|
||||
public static DataKeyInfo makeTransientPropertyDataKeyInfo(String dataKey)
|
||||
{
|
||||
return new DataKeyInfo(dataKey, null, FieldType.TRANSIENT, true);
|
||||
return new DataKeyInfo(dataKey, null, FieldType.TRANSIENT_PROPERTY, true);
|
||||
}
|
||||
|
||||
public static DataKeyInfo makeTransientAssociationDataKeyInfo(String dataKey, boolean isAdd)
|
||||
{
|
||||
return new DataKeyInfo(dataKey, null, FieldType.TRANSIENT_ASSOCIATION, isAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dataKey
|
||||
* @return the fieldName
|
||||
*/
|
||||
public String getDataKey()
|
||||
public String getFieldName()
|
||||
{
|
||||
return dataKey;
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the qName
|
||||
*/
|
||||
public QName getqName()
|
||||
public QName getQName()
|
||||
{
|
||||
return qName;
|
||||
}
|
||||
@ -87,5 +92,25 @@ public class DataKeyInfo
|
||||
{
|
||||
return isAdd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the visitor pattern. Takes a DataKeyInfoVisitor and calls the
|
||||
* appropriate visit method based on the fieldType.
|
||||
*
|
||||
* @param <T>
|
||||
* @param visitor
|
||||
* @return
|
||||
*/
|
||||
public <T> T visit(DataKeyInfoVisitor<T> visitor)
|
||||
{
|
||||
switch(fieldType)
|
||||
{
|
||||
case ASSOCIATION: return visitor.visitAssociation(this);
|
||||
case PROPERTY: return visitor.visitProperty(this);
|
||||
case TRANSIENT_ASSOCIATION: return visitor.visitTransientAssociation(this);
|
||||
case TRANSIENT_PROPERTY: return visitor.visitTransientProperty(this);
|
||||
default: return null; //Should never be reached.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.workflow;
|
||||
|
||||
/**
|
||||
* Visitor interface used to enable the visitor pattern on {@link DataKeyInfo}
|
||||
* instances. Implementations of this interface can call
|
||||
* <code>DataKeyInfo.visit(DataKeyInfoVisitor)</code> to have the appropriate
|
||||
* visit method called on the visitor, based on the fieldType of the
|
||||
* {@link DataKeyInfo} instance.
|
||||
*
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public interface DataKeyInfoVisitor<T>
|
||||
{
|
||||
/**
|
||||
* Called for {@link DataKeyInfo} instances with a field type of ASSOCIATION.
|
||||
* @param info
|
||||
* @return
|
||||
*/
|
||||
T visitAssociation(DataKeyInfo info);
|
||||
|
||||
/**
|
||||
* Called for {@link DataKeyInfo} instances with a field type of PROPERTY.
|
||||
* @param info
|
||||
* @return
|
||||
*/
|
||||
T visitProperty(DataKeyInfo info);
|
||||
|
||||
/**
|
||||
* Called for {@link DataKeyInfo} instances with a field type of TRANSIENT_ASSOCIATION.
|
||||
* @param info
|
||||
* @return
|
||||
*/
|
||||
T visitTransientAssociation(DataKeyInfo info);
|
||||
|
||||
/**
|
||||
* Called for {@link DataKeyInfo} instances with a field type of TRANSIENT_PROPERTY.
|
||||
* @param info
|
||||
* @return
|
||||
*/
|
||||
T visitTransientProperty(DataKeyInfo info);
|
||||
}
|
@ -40,11 +40,6 @@ public class DataKeyMatcher
|
||||
*/
|
||||
private final static Pattern propertyNamePattern = Pattern.compile("(^[a-zA-Z0-9]+)_([a-zA-Z0-9_]+$)");
|
||||
|
||||
public DataKeyMatcher(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
/**
|
||||
* A regular expression which can be used to match association names. These
|
||||
* names will look like <code>"assoc_cm_references_added"</code>. The
|
||||
@ -53,12 +48,20 @@ public class DataKeyMatcher
|
||||
*/
|
||||
private final static Pattern associationNamePattern = Pattern.compile("(^[a-zA-Z0-9]+)_([a-zA-Z0-9_]+)(_[a-zA-Z]+$)");
|
||||
|
||||
private final static Pattern transientAssociationPattern = Pattern.compile("(^[a-zA-Z0-9]+)(_[a-zA-Z]+$)");
|
||||
|
||||
private final NamespaceService namespaceService;
|
||||
|
||||
public DataKeyMatcher(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param dataKey
|
||||
* @return
|
||||
* Attempts to match the <code>dataKey</code> to either a property or association pattern.
|
||||
* If no match can be found then returns <code>null</code>.
|
||||
* @param dataKey the dataKey to be matched.
|
||||
* @return a {@link DataKeyInfo} representation or <code>null</code>.
|
||||
*/
|
||||
public DataKeyInfo match(String dataKey)
|
||||
{
|
||||
@ -70,7 +73,6 @@ public class DataKeyMatcher
|
||||
{
|
||||
return matchAssociation(dataKey);
|
||||
}
|
||||
|
||||
// No match found.
|
||||
return null;
|
||||
}
|
||||
@ -79,14 +81,33 @@ public class DataKeyMatcher
|
||||
{
|
||||
String keyName = dataKey.substring(ASSOC_DATA_PREFIX.length());
|
||||
Matcher matcher = associationNamePattern.matcher(keyName);
|
||||
if (!matcher.matches())
|
||||
if (matcher.matches())
|
||||
{
|
||||
return null;
|
||||
QName qName = getQName(matcher);
|
||||
boolean isAdd = isAdd(matcher, 3);
|
||||
String name = qName.toPrefixString(namespaceService);
|
||||
return DataKeyInfo.makeAssociationDataKeyInfo(name, qName, isAdd);
|
||||
}
|
||||
QName qName = getQName(matcher);
|
||||
String suffix = matcher.group(3);
|
||||
return matchTransientAssociation(keyName);
|
||||
}
|
||||
|
||||
private DataKeyInfo matchTransientAssociation(String keyName)
|
||||
{
|
||||
Matcher matcher = transientAssociationPattern.matcher(keyName);
|
||||
if(matcher.matches())
|
||||
{
|
||||
boolean isAdd = isAdd(matcher, 2);
|
||||
String name = matcher.group(1);
|
||||
return DataKeyInfo.makeTransientAssociationDataKeyInfo(name, isAdd);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isAdd(Matcher matcher, int suffixPos)
|
||||
{
|
||||
String suffix = matcher.group(suffixPos);
|
||||
boolean isAdd = !(ASSOC_DATA_REMOVED_SUFFIX.equals(suffix));
|
||||
return DataKeyInfo.makeAssociationDataKeyInfo(keyName, qName, isAdd);
|
||||
return isAdd;
|
||||
}
|
||||
|
||||
private DataKeyInfo matchProperty(String dataKey)
|
||||
@ -96,9 +117,10 @@ public class DataKeyMatcher
|
||||
if (matcher.matches())
|
||||
{
|
||||
QName qName = getQName(matcher);
|
||||
return DataKeyInfo.makePropertyDataKeyInfo(keyName, qName);
|
||||
String name = qName.toPrefixString(namespaceService);
|
||||
return DataKeyInfo.makePropertyDataKeyInfo(name, qName);
|
||||
}
|
||||
return DataKeyInfo.makeTransientDataKeyInfo(keyName);
|
||||
return DataKeyInfo.makeTransientPropertyDataKeyInfo(keyName);
|
||||
}
|
||||
|
||||
private QName getQName(Matcher matcher)
|
||||
|
@ -27,5 +27,6 @@ public enum FieldType
|
||||
{
|
||||
ASSOCIATION,
|
||||
PROPERTY,
|
||||
TRANSIENT;
|
||||
TRANSIENT_ASSOCIATION,
|
||||
TRANSIENT_PROPERTY;
|
||||
}
|
||||
|
@ -51,11 +51,11 @@ import org.apache.commons.logging.LogFactory;
|
||||
public class TaskFormProcessor extends ContentModelFormProcessor<WorkflowTask, WorkflowTask>
|
||||
{
|
||||
/** Logger */
|
||||
private static final Log LOGGER = LogFactory.getLog(TaskFormProcessor.class);
|
||||
private static final TypedPropertyValueGetter valueGetter = new TypedPropertyValueGetter();
|
||||
|
||||
private DataKeyMatcher keyMatcher;
|
||||
private WorkflowService workflowService;
|
||||
private static final Log LOGGER = LogFactory.getLog(TaskFormProcessor.class);
|
||||
|
||||
private TypedPropertyValueGetter valueGetter;
|
||||
private DataKeyMatcher keyMatcher;
|
||||
private WorkflowService workflowService;
|
||||
|
||||
// Constructor for Spring
|
||||
public TaskFormProcessor()
|
||||
@ -72,6 +72,7 @@ public class TaskFormProcessor extends ContentModelFormProcessor<WorkflowTask, W
|
||||
this.dictionaryService = dictionaryService;
|
||||
this.fieldProcessorRegistry = fieldProcessorRegistry;
|
||||
this.keyMatcher = new DataKeyMatcher(namespaceService);
|
||||
this.valueGetter = new TypedPropertyValueGetter(dictionaryService);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -101,31 +102,30 @@ public class TaskFormProcessor extends ContentModelFormProcessor<WorkflowTask, W
|
||||
{
|
||||
String name = fieldData.getName();
|
||||
DataKeyInfo keyInfo = keyMatcher.match(name);
|
||||
if ((keyInfo == null || FieldType.TRANSIENT == keyInfo.getFieldType()) &&
|
||||
LOGGER.isWarnEnabled())
|
||||
if (keyInfo == null ||
|
||||
FieldType.TRANSIENT_PROPERTY == keyInfo.getFieldType() )
|
||||
{
|
||||
LOGGER.warn("Ignoring unrecognized field: " + name);
|
||||
if(LOGGER.isDebugEnabled())
|
||||
LOGGER.debug("Ignoring unrecognized field: " + name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyInfo != null)
|
||||
QName fullName = keyInfo.getQName();
|
||||
Object rawValue = fieldData.getValue();
|
||||
if (FieldType.PROPERTY == keyInfo.getFieldType())
|
||||
{
|
||||
QName fullName = keyInfo.getqName();
|
||||
Object rawValue = fieldData.getValue();
|
||||
if (FieldType.PROPERTY == keyInfo.getFieldType())
|
||||
Serializable propValue = getPropertyValueToPersist(fullName, rawValue, itemData);
|
||||
// TODO What if the user wants to set prop to null?
|
||||
if (propValue != null)
|
||||
{
|
||||
Serializable propValue = getPropertyValueToPersist(fullName, rawValue, itemData);
|
||||
// TODO What if the user wants to set prop to null?
|
||||
if (propValue != null)
|
||||
{
|
||||
updater.addProperty(fullName, propValue);
|
||||
}
|
||||
updater.addProperty(fullName, propValue);
|
||||
}
|
||||
else if (FieldType.ASSOCIATION == keyInfo.getFieldType())
|
||||
}
|
||||
else if (FieldType.ASSOCIATION == keyInfo.getFieldType())
|
||||
{
|
||||
if (rawValue instanceof String)
|
||||
{
|
||||
if (rawValue instanceof String)
|
||||
{
|
||||
updater.changeAssociation(fullName, (String) rawValue, keyInfo.isAdd());
|
||||
}
|
||||
updater.changeAssociation(fullName, (String) rawValue, keyInfo.isAdd());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -143,7 +143,7 @@ public class TaskFormProcessor extends ContentModelFormProcessor<WorkflowTask, W
|
||||
{
|
||||
return valueGetter.getValue(value, propDef);
|
||||
}
|
||||
return null;
|
||||
return (Serializable) value;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -232,4 +232,13 @@ public class TaskFormProcessor extends ContentModelFormProcessor<WorkflowTask, W
|
||||
this.keyMatcher = new DataKeyMatcher(namespaceService);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#setDictionaryService(org.alfresco.service.cmr.dictionary.DictionaryService)
|
||||
*/
|
||||
@Override
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
super.setDictionaryService(dictionaryService);
|
||||
this.valueGetter = new TypedPropertyValueGetter(dictionaryService);
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@
|
||||
package org.alfresco.repo.forms.processor.workflow;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -88,7 +87,7 @@ public class TaskUpdater
|
||||
|
||||
public boolean changeAssociation(QName name, String nodeRefs, boolean isAdd)
|
||||
{
|
||||
List<NodeRef> value = getNodeRefs(nodeRefs);
|
||||
List<NodeRef> value = NodeRef.getNodeRefs(nodeRefs, LOGGER);
|
||||
if (value == null)
|
||||
{
|
||||
return false;
|
||||
@ -120,34 +119,4 @@ public class TaskUpdater
|
||||
return map;
|
||||
}
|
||||
|
||||
private List<NodeRef> getNodeRefs(Object value)
|
||||
{
|
||||
String[] nodeRefIds = ((String) value).split(",");
|
||||
List<NodeRef> nodeRefs = new ArrayList<NodeRef>(nodeRefIds.length);
|
||||
for (String nodeRefString : nodeRefIds)
|
||||
{
|
||||
String nodeRefId = nodeRefString.trim();
|
||||
if (NodeRef.isNodeRef(nodeRefId))
|
||||
{
|
||||
NodeRef nodeRef = new NodeRef(nodeRefId);
|
||||
nodeRefs.add(nodeRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
logNodeRefError(nodeRefId);
|
||||
}
|
||||
}
|
||||
return nodeRefs;
|
||||
}
|
||||
|
||||
private void logNodeRefError(String nodeRefId)
|
||||
{
|
||||
if (LOGGER.isWarnEnabled())
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Target Node: ").append(nodeRefId);
|
||||
msg.append(" is not a valid NodeRef and has been ignored.");
|
||||
LOGGER.warn(msg.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,11 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.forms.FormException;
|
||||
import org.alfresco.repo.forms.processor.node.ItemData;
|
||||
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.namespace.QName;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
@ -44,6 +47,27 @@ public class TypedPropertyValueGetter
|
||||
{
|
||||
public static final String ON = "on";
|
||||
|
||||
private final DictionaryService dictionaryService;
|
||||
|
||||
public TypedPropertyValueGetter(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
public Serializable getPropertyValueToPersist(QName fullName, Object value, ItemData<?> itemData)
|
||||
{
|
||||
PropertyDefinition propDef = itemData.getPropertyDefinition(fullName);
|
||||
if (propDef == null)
|
||||
{
|
||||
propDef = dictionaryService.getProperty(fullName);
|
||||
}
|
||||
if (propDef != null)
|
||||
{
|
||||
return getValue(value, propDef);
|
||||
}
|
||||
return (Serializable) value;
|
||||
}
|
||||
|
||||
public Serializable getValue(Object value, PropertyDefinition propDef)
|
||||
{
|
||||
if (value == null)
|
||||
|
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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.workflow;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.workflow.WorkflowModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowInstance;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowPath;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* A helper class used to start workflows. The builder accumuates all the
|
||||
* changes to be made to the list of parameters and package items, then starts a
|
||||
* new workflow once the build() method is called.
|
||||
*
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public class WorkflowBuilder
|
||||
{
|
||||
private final WorkflowService workflowService;
|
||||
private final WorkflowDefinition definition;
|
||||
private final NodeService nodeService;
|
||||
|
||||
private final Map<QName, Serializable> params = new HashMap<QName, Serializable>();
|
||||
private final Set<NodeRef> packageItems = new HashSet<NodeRef>();
|
||||
private NodeRef packageNode = null;
|
||||
|
||||
|
||||
public WorkflowBuilder(WorkflowDefinition definition, WorkflowService workflowService, NodeService nodeService)
|
||||
{
|
||||
this.workflowService = workflowService;
|
||||
this.nodeService = nodeService;
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
public void addParameter(QName name, Serializable value)
|
||||
{
|
||||
params.put(name, value);
|
||||
}
|
||||
|
||||
public void addAssociationParameter(QName name, Serializable value)
|
||||
{
|
||||
params.put(name, value);
|
||||
}
|
||||
|
||||
public void addPackageItems(List<NodeRef> items)
|
||||
{
|
||||
packageItems.addAll(items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a comma-separated list of {@link NodeRef} ids and adds the
|
||||
* specified NodeRefs to the package.
|
||||
*
|
||||
* @param items
|
||||
*/
|
||||
public void addPackageItems(String items)
|
||||
{
|
||||
List<NodeRef> nodes = NodeRef.getNodeRefs(items);
|
||||
addPackageItems(nodes);
|
||||
}
|
||||
|
||||
public void addPackageItemsAsStrings(List<String> itemStrs)
|
||||
{
|
||||
for (String itemStr : itemStrs)
|
||||
{
|
||||
addPackageItem(itemStr);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPackageItem(NodeRef item)
|
||||
{
|
||||
packageItems.add(item);
|
||||
}
|
||||
|
||||
public void addPackageItem(String itemStr)
|
||||
{
|
||||
packageItems.add(new NodeRef(itemStr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param packageNode the packageNode to set
|
||||
*/
|
||||
public void setPackageNode(NodeRef packageNode)
|
||||
{
|
||||
this.packageNode = packageNode;
|
||||
}
|
||||
|
||||
public WorkflowInstance build()
|
||||
{
|
||||
buildPackage();
|
||||
WorkflowPath path = workflowService.startWorkflow(definition.id, params);
|
||||
signalStartTask(path);
|
||||
return path.instance;
|
||||
}
|
||||
|
||||
private void signalStartTask(WorkflowPath path)
|
||||
{
|
||||
List<WorkflowTask> tasks = workflowService.getTasksForWorkflowPath(path.id);
|
||||
if(tasks.size() == 1)
|
||||
{
|
||||
WorkflowTask startTask = tasks.get(0);
|
||||
workflowService.endTask(startTask.id, null);
|
||||
}
|
||||
else
|
||||
throw new WorkflowException("Start task not found! Expected 1 task but found: " + tasks.size());
|
||||
}
|
||||
|
||||
private void buildPackage()
|
||||
{
|
||||
final NodeRef packageRef = workflowService.createPackage(packageNode);
|
||||
final String url = NamespaceService.CONTENT_MODEL_1_0_URI;
|
||||
final QName packageContains = WorkflowModel.ASSOC_PACKAGE_CONTAINS;
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
for (NodeRef item : packageItems)
|
||||
{
|
||||
String name =
|
||||
(String) nodeService.getProperty(item, ContentModel.PROP_NAME);
|
||||
String localName = QName.createValidLocalName(name);
|
||||
QName qName = QName.createQName(url, localName);
|
||||
nodeService.addChild(packageRef, item, packageContains, qName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
params.put(WorkflowModel.ASSOC_PACKAGE, packageRef);
|
||||
}
|
||||
}
|
@ -28,11 +28,14 @@ import java.util.regex.Matcher;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.forms.FormData;
|
||||
import org.alfresco.repo.forms.FormException;
|
||||
import org.alfresco.repo.forms.FormNotFoundException;
|
||||
import org.alfresco.repo.forms.Item;
|
||||
import org.alfresco.repo.forms.FormData.FieldData;
|
||||
import org.alfresco.repo.forms.processor.node.ContentModelFormProcessor;
|
||||
import org.alfresco.repo.forms.processor.node.ItemData;
|
||||
import org.alfresco.repo.workflow.WorkflowModel;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
@ -66,6 +69,10 @@ public class WorkflowFormProcessor extends ContentModelFormProcessor<WorkflowDef
|
||||
/** Unprotected Node Service */
|
||||
private NodeService unprotectedNodeService;
|
||||
|
||||
/** TyepdPropertyValueGetter */
|
||||
private TypedPropertyValueGetter valueGetter;
|
||||
|
||||
private DataKeyMatcher keyMatcher;
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getAssociationValues(java.lang.Object)
|
||||
*/
|
||||
@ -188,13 +195,39 @@ public class WorkflowFormProcessor extends ContentModelFormProcessor<WorkflowDef
|
||||
return defName;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.alfresco.repo.forms.processor.node.NodeFormProcessor#internalPersist
|
||||
* (java.lang.Object, org.alfresco.repo.forms.FormData)
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.forms.processor.FilteredFormProcessor#internalPersist(java.lang.Object, org.alfresco.repo.forms.FormData)
|
||||
*/
|
||||
@Override
|
||||
protected WorkflowInstance internalPersist(WorkflowDefinition workflowDef, final FormData data)
|
||||
protected WorkflowInstance internalPersist(WorkflowDefinition definition, FormData data)
|
||||
{
|
||||
WorkflowBuilder builder = new WorkflowBuilder(definition, workflowService, nodeService);
|
||||
ItemData<WorkflowDefinition> itemData = makeItemData(definition);
|
||||
for (FieldData fieldData : data)
|
||||
{
|
||||
addFieldToSerialize(builder, itemData, fieldData);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void addFieldToSerialize(WorkflowBuilder builder, ItemData<WorkflowDefinition> itemData, FieldData fieldData)
|
||||
{
|
||||
String dataKeyName = fieldData.getName();
|
||||
DataKeyInfo keyInfo = keyMatcher.match(dataKeyName);
|
||||
if (keyInfo == null ||
|
||||
FieldType.TRANSIENT_PROPERTY == keyInfo.getFieldType() )
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
logger.debug("Ignoring unrecognized field: " + dataKeyName);
|
||||
return;
|
||||
}
|
||||
WorkflowDataKeyInfoVisitor visitor = new WorkflowDataKeyInfoVisitor(fieldData.getValue(), builder, itemData);
|
||||
keyInfo.visit(visitor);
|
||||
}
|
||||
|
||||
|
||||
protected WorkflowInstance oldInternalPersist(WorkflowDefinition workflowDef, final FormData data)
|
||||
{
|
||||
if (logger.isDebugEnabled()) logger.debug("Persisting form for: " + workflowDef);
|
||||
|
||||
@ -285,4 +318,88 @@ public class WorkflowFormProcessor extends ContentModelFormProcessor<WorkflowDef
|
||||
{
|
||||
this.workflowService = workflowService;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#setNamespaceService(org.alfresco.service.namespace.NamespaceService)
|
||||
*/
|
||||
@Override
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
super.setNamespaceService(namespaceService);
|
||||
this.keyMatcher = new DataKeyMatcher(namespaceService);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#setDictionaryService(org.alfresco.service.cmr.dictionary.DictionaryService)
|
||||
*/
|
||||
@Override
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
super.setDictionaryService(dictionaryService);
|
||||
this.valueGetter = new TypedPropertyValueGetter(dictionaryService);
|
||||
}
|
||||
|
||||
private class WorkflowDataKeyInfoVisitor implements DataKeyInfoVisitor<Void>
|
||||
{
|
||||
private final Object rawValue;
|
||||
private final WorkflowBuilder builder;
|
||||
private final ItemData<WorkflowDefinition> itemData;
|
||||
|
||||
public WorkflowDataKeyInfoVisitor(Object rawValue, WorkflowBuilder builder,
|
||||
ItemData<WorkflowDefinition> itemData)
|
||||
{
|
||||
this.rawValue = rawValue;
|
||||
this.builder = builder;
|
||||
this.itemData = itemData;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.forms.processor.workflow.DataKeyInfoVisitor#visitAssociation(org.alfresco.repo.forms.processor.workflow.DataKeyInfo)
|
||||
*/
|
||||
public Void visitAssociation(DataKeyInfo info)
|
||||
{
|
||||
QName qName = info.getQName();
|
||||
if (rawValue instanceof String)
|
||||
{
|
||||
Serializable nodes = (Serializable) NodeRef.getNodeRefs((String) rawValue);
|
||||
builder.addParameter(qName, nodes);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.forms.processor.workflow.DataKeyInfoVisitor#visitProperty(org.alfresco.repo.forms.processor.workflow.DataKeyInfo)
|
||||
*/
|
||||
public Void visitProperty(DataKeyInfo info)
|
||||
{
|
||||
QName qName = info.getQName();
|
||||
Serializable propValue = valueGetter.getPropertyValueToPersist(qName, rawValue, itemData);
|
||||
builder.addParameter(qName, propValue);
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.forms.processor.workflow.DataKeyInfoVisitor#visitTransientAssociation(org.alfresco.repo.forms.processor.workflow.DataKeyInfo)
|
||||
*/
|
||||
public Void visitTransientAssociation(DataKeyInfo info)
|
||||
{
|
||||
if(PackageItemsFieldProcessor.KEY.equals(info.getFieldName()))
|
||||
{
|
||||
if(rawValue instanceof String)
|
||||
{
|
||||
builder.addPackageItems((String)rawValue);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.forms.processor.workflow.DataKeyInfoVisitor#visitTransientProperty(org.alfresco.repo.forms.processor.workflow.DataKeyInfo)
|
||||
*/
|
||||
public Void visitTransientProperty(DataKeyInfo info)
|
||||
{
|
||||
throw new FormException("This methdo should never be called!");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user