diff --git a/source/java/org/alfresco/repo/forms/FormData.java b/source/java/org/alfresco/repo/forms/FormData.java index 5d7b1de845..a645b2428e 100644 --- a/source/java/org/alfresco/repo/forms/FormData.java +++ b/source/java/org/alfresco/repo/forms/FormData.java @@ -25,8 +25,10 @@ package org.alfresco.repo.forms; import java.io.InputStream; +import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Set; @@ -77,16 +79,69 @@ public class FormData implements Iterable /** * Adds the given data to the form. - * If data for the given field is already present it will be - * overwritten. + *

+ * NOTE: Adding the same named data will append the value and + * thereafter return a List containing all added values. + *

* * @param fieldName The name of the field * @param fieldValue The value of the data */ public void addFieldData(String fieldName, Object fieldValue) { - FieldData item = new FieldData(fieldName, fieldValue, false); - this.data.put(fieldName, item); + this.addFieldData(fieldName, fieldValue, false); + } + + /** + * Adds the given data to the form. If data for the field is already + * present the behaviour is controlled by the overwrite property. + *

+ * If overwrite is true the provided value replaces the existing value + * whereas false will force the creation of a List (if necessary) and the + * provided value will be added to the List. + *

+ * + * @param fieldName The name of the field + * @param fieldValue The value of the data + * @param overwrite + */ + @SuppressWarnings("unchecked") + public void addFieldData(String fieldName, Object fieldValue, boolean overwrite) + { + // check whether some data already exists + if (this.data.containsKey(fieldName)) + { + // if we are overwriting just replace with provided data + if (overwrite) + { + this.data.put(fieldName, new FieldData(fieldName, fieldValue, false)); + } + else + { + // pull out the existing value and create a List if necessary + List currentValues = null; + Object currentValue = this.data.get(fieldName).getValue(); + if (currentValue instanceof List) + { + currentValues = (List)currentValue; + } + else + { + // a non List value is present, create the new list + // and add the current value to it + currentValues = new ArrayList(4); + currentValues.add(currentValue); + this.data.put(fieldName, new FieldData(fieldName, currentValues, false)); + } + + // add the provided value to the list + currentValues.add(fieldValue); + } + } + else + { + this.data.put(fieldName, new FieldData(fieldName, fieldValue, false)); + } } /** diff --git a/source/java/org/alfresco/repo/forms/FormServiceImplTest.java b/source/java/org/alfresco/repo/forms/FormServiceImplTest.java index 749710a127..17c95ccb60 100644 --- a/source/java/org/alfresco/repo/forms/FormServiceImplTest.java +++ b/source/java/org/alfresco/repo/forms/FormServiceImplTest.java @@ -993,6 +993,45 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest } } + @SuppressWarnings("unchecked") + public void testFormData() throws Exception + { + FormData formData = new FormData(); + + // test single value goes in and comes out successfully + formData.addFieldData("singleValue", "one"); + assertEquals("Expecting value of 'one'", "one", formData.getFieldData("singleValue").getValue()); + + // test adding multiple values to the same field + formData.addFieldData("multipleValues", "one"); + + Object value = formData.getFieldData("multipleValues").getValue(); + assertTrue("Expecting 'multipleValues' to be a String object", (value instanceof String)); + + formData.addFieldData("multipleValues", "two"); + value = formData.getFieldData("multipleValues").getValue(); + assertTrue("Expecting 'multipleValues' to be a List object", (value instanceof List)); + + formData.addFieldData("multipleValues", "three"); + List list = (List)formData.getFieldData("multipleValues").getValue(); + assertEquals("Expecting 'multipleValues' List to have 3 items", 3, list.size()); + + // add a List initially then add a value to it + formData.addFieldData("listValue", new ArrayList()); + formData.addFieldData("listValue", "one"); + formData.addFieldData("listValue", "two"); + list = (List)formData.getFieldData("listValue").getValue(); + assertEquals("Expecting 'listValue' List to have 2 items", 2, list.size()); + + // test overwrite parameter + formData.addFieldData("overwritten", "one", true); + formData.addFieldData("overwritten", "two", true); + formData.addFieldData("overwritten", "three", true); + value = formData.getFieldData("overwritten").getValue(); + assertTrue("Expecting 'overwritten' to be a String object", (value instanceof String)); + assertEquals("Expecting 'overwritten' value to be 'three'", "three", value); + } + public void testJavascriptAPI() throws Exception { Map model = new HashMap(); diff --git a/source/java/org/alfresco/repo/forms/processor/node/NodeFormProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/NodeFormProcessor.java index b3b69acf74..b02f341d40 100644 --- a/source/java/org/alfresco/repo/forms/processor/node/NodeFormProcessor.java +++ b/source/java/org/alfresco/repo/forms/processor/node/NodeFormProcessor.java @@ -72,6 +72,8 @@ import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.json.JSONArray; +import org.json.JSONException; /** * FormProcessor implementation that can generate and persist Form objects @@ -991,29 +993,53 @@ public class NodeFormProcessor extends FilteredFormProcessor Object value = fieldData.getValue(); // before persisting check data type of property - if ((value instanceof String) && ((String)value).length() == 0) + if (propDef.isMultiValued()) { - // make sure empty strings stay as empty strings, everything else - // should be represented as null - if (!propDef.getDataType().getName().equals(DataTypeDefinition.TEXT) && - !propDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT)) + // depending on client the value could be a comma separated + // string, a List object or a JSONArray object + if (value instanceof String) { - value = null; + if (((String)value).length() == 0) + { + // empty string for multi-valued properties + // should be stored as null + value = null; + } + else + { + // if value is a String convert to List of String + StringTokenizer tokenizer = new StringTokenizer((String)value, ","); + List list = new ArrayList(8); + while (tokenizer.hasMoreTokens()) + { + list.add(tokenizer.nextToken()); + } + + // persist the List + value = list; + } } - } - else if (propDef.isMultiValued()) - { - // currently we expect comma separated lists to represent - // the values of a multi valued property, change into List - StringTokenizer tokenizer = new StringTokenizer((String)value, ","); - List list = new ArrayList(8); - while (tokenizer.hasMoreTokens()) + else if (value instanceof JSONArray) { - list.add(tokenizer.nextToken()); + // if value is a JSONArray convert to List of Object + JSONArray jsonArr = (JSONArray)value; + int arrLength = jsonArr.length(); + List list = new ArrayList(arrLength); + try + { + for (int x = 0; x < arrLength; x++) + { + list.add(jsonArr.get(x)); + } + } + catch (JSONException je) + { + throw new FormException("Failed to convert JSONArray to List", je); + } + + // persist the list + value = list; } - - // persist the List - value = list; } else if (propDef.getDataType().getName().equals(DataTypeDefinition.BOOLEAN)) { @@ -1027,6 +1053,16 @@ public class NodeFormProcessor extends FilteredFormProcessor { value = I18NUtil.parseLocale((String)value); } + else if ((value instanceof String) && ((String)value).length() == 0) + { + // make sure empty strings stay as empty strings, everything else + // should be represented as null + if (!propDef.getDataType().getName().equals(DataTypeDefinition.TEXT) && + !propDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT)) + { + value = null; + } + } // add the property to the map propsToPersist.put(fullQName, (Serializable)value);