/**
* Copyright (C) 2012 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jbpm.formModeler.core.processing.fieldHandlers.multipleSubform;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.jbpm.formModeler.api.model.DataHolder;
import org.jbpm.formModeler.api.model.Field;
import org.jbpm.formModeler.api.model.Form;
import org.jbpm.formModeler.core.processing.FormNamespaceData;
import org.jbpm.formModeler.core.processing.FormProcessor;
import org.jbpm.formModeler.core.processing.FormStatusData;
import org.jbpm.formModeler.core.processing.fieldHandlers.SubformFieldHandler;
import org.jbpm.formModeler.core.processing.fieldHandlers.subform.utils.SubFormHelper;
import org.jbpm.formModeler.core.rendering.SubformFinderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.*;
@Named("org.jbpm.formModeler.core.processing.fieldHandlers.multipleSubform.CreateDynamicObjectFieldHandler")
public class CreateDynamicObjectFieldHandler extends SubformFieldHandler {
private static transient Logger log = LoggerFactory.getLogger(CreateDynamicObjectFieldHandler.class);
public static final String CODE = "subformMultiple";
@Inject
private SubformFinderService subformFinderService;
@Inject
private FormProcessor formProcessor;
@Inject
private SubFormHelper helper;
/**
* Read a parameter value (normally from a request), and translate it to
* an object with desired class (that must be one of the returned by this handler)
*
* @return a object with desired class
* @throws Exception
*/
public Object getValue(Field field, String inputName, Map parametersMap, Map filesMap, String desiredClassName, Object previousValue) throws Exception {
String[] tableEnterMode = (String[]) parametersMap.get(inputName + FormProcessor.CUSTOM_NAMESPACE_SEPARATOR + "tableEnterMode");
boolean doTableEnterMode = tableEnterMode != null && tableEnterMode.length == 1 && tableEnterMode[0].equals("true");
String[] sCount = (String[]) parametersMap.get(inputName + FormProcessor.CUSTOM_NAMESPACE_SEPARATOR + "count");
int count = sCount != null && sCount.length == 1 ? Integer.valueOf(sCount[0]) : 0;
Form form = getTableDataForm(field, inputName);
Map[] previousValuesMap = (Map[]) previousValue;
if (doTableEnterMode && count > 0) {
if (previousValuesMap == null) previousValuesMap = new Map[count];
for (int i = 0; i < count; i++) {
String namespace = inputName + FormProcessor.CUSTOM_NAMESPACE_SEPARATOR + i;
formProcessor.setValues(form, namespace, parametersMap, filesMap);
FormStatusData status = formProcessor.read(form, namespace);
if (status.isValid()) {
final Map objectCreated = formProcessor.getMapRepresentationToPersist(form, namespace);
if (previousValuesMap[i] != null) previousValuesMap[i].putAll(objectCreated);
else previousValuesMap[i] = objectCreated;
}
}
}
String[] createParams = (String[]) parametersMap.get(inputName + FormProcessor.CUSTOM_NAMESPACE_SEPARATOR + "create");
boolean doCreate = createParams != null && createParams.length == 1 && createParams[0].equals("true");
if (doCreate) {
Form createForm = getCreateForm(field, inputName);
boolean addItemEnabled = Boolean.TRUE.equals(formProcessor.getAttribute(createForm, inputName, FormStatusData.DO_THE_ITEM_ADD));
if (addItemEnabled) {
formProcessor.setValues(createForm, inputName + FormProcessor.CUSTOM_NAMESPACE_SEPARATOR + "create", parametersMap, filesMap);
FormStatusData status = formProcessor.read(createForm, inputName + FormProcessor.CUSTOM_NAMESPACE_SEPARATOR + "create");
if (status.isValid()) {
final Map objectCreated = formProcessor.getMapRepresentationToPersist(createForm, inputName + FormProcessor.CUSTOM_NAMESPACE_SEPARATOR + "create");
if (previousValuesMap == null) previousValuesMap = new Map[0];
previousValuesMap = (Map[]) ArrayUtils.add(previousValuesMap, objectCreated);
helper.clearExpandedField( inputName );
}
}
}
String[] editParams = (String[]) parametersMap.get(inputName + FormProcessor.CUSTOM_NAMESPACE_SEPARATOR + "saveEdited");
boolean doSaveEdited = editParams != null && editParams.length == 1 && editParams[0].equals("true");
if (doSaveEdited) {
Integer position = helper.getEditFieldPosition( inputName );
if (position != null) {
Form editForm = getEditForm(field, inputName);
formProcessor.setValues(editForm, inputName, parametersMap, filesMap);
FormStatusData status = formProcessor.read(editForm, inputName);
if (status.isValid()) {
final Map objectCreated = formProcessor.getMapRepresentationToPersist(editForm, inputName);
previousValuesMap[position].putAll( objectCreated );
formProcessor.clear(editForm, inputName);
helper.clearEditFieldPositions( inputName );
}
}
}
return previousValuesMap;
}
@Override
public Map getParamValue(Field field, String inputName, Object value) {
return Collections.EMPTY_MAP;
}
@Override
public Object getStatusValue( Field field, String inputName, Object value, Map rootLoadedObjects ) {
if (value == null) return new Map[0];
if (!rootLoadedObjects.containsKey( inputName )) rootLoadedObjects.put( inputName, value );
Form form = getEnterDataForm(inputName, field);
DataHolder holder = form.getHolders().iterator().next();
List values = (List) value;
Map[] result = new Map[values.size()];
for (int i = 0; i < values.size(); i++) {
try {
Object val = values.get(i);
Map<String, Object> inputData = new HashMap();
if (!StringUtils.isEmpty(holder.getInputId())) inputData.put(holder.getInputId(), val);
rootLoadedObjects.remove( holder.getUniqeId() );
result[i] = formProcessor.readValuesToLoad(form, inputData, new HashMap(), rootLoadedObjects, inputName + FormProcessor.CUSTOM_NAMESPACE_SEPARATOR + i);
} catch (Exception e) {
log.error("Error getting status value for field: " + inputName, e);
}
}
Map<String, Object> loadedObjects = new HashMap();
loadedObjects.put(holder.getUniqeId(), result);
formProcessor.read(form, inputName, null, loadedObjects);
return result;
}
@Override
public Object persist( Field field, String inputName, Object fieldValue ) throws Exception {
if (fieldValue == null) return null;
FormNamespaceData rootNamespaceData = getNamespaceManager().getRootNamespace( inputName );
FormStatusData rootData = formProcessor.read(rootNamespaceData.getForm(), rootNamespaceData.getNamespace());
Form form = getEnterDataForm(inputName, field);
// getting parent object to obtain the parent child elements
Object originalValue = rootData.getLoadedObject( inputName );
List loadedObjects = null;
if (originalValue != null) loadedObjects = (List) originalValue;
else loadedObjects = Collections.EMPTY_LIST;
Map[] values = (Map[]) fieldValue;
List result = new ArrayList();
List<Integer> removedValues = helper.getRemovedFieldPositions( inputName );
if (removedValues != null) {
// Check if any value has been removed from the parent form
for (int i = 0; i < removedValues.size(); i++) {
Integer removed = removedValues.get(i);
if (removed < loadedObjects.size()) loadedObjects.remove(removed);
}
}
DataHolder holder = form.getHolders().iterator().next();
for (int i = 0; i < values.length; i++) {
Object loadedObject = null;
if (loadedObjects != null && loadedObjects.size() > i) {
loadedObject = loadedObjects.get(i);
}
result.add(formProcessor.persistFormHolder(form, inputName + FormProcessor.CUSTOM_NAMESPACE_SEPARATOR + i, values[i], holder, loadedObject));
}
helper.clearRemovedFieldPositions( inputName );
return result;
}
public Form calculateFieldForm(Field field, String formPath, String namespace) {
if (StringUtils.isEmpty(formPath)) formPath = field.getDefaultSubform();
return subformFinderService.getFormByPath(formPath, namespace);
}
public Object deleteElementInPosition(Form form, String namespace, String field, int position) {
synchronized (form) {
FormStatusData statusData = formProcessor.read(form, namespace);
Object previousValue = statusData.getCurrentValue(field);
if (previousValue != null) {
Object[] vals = (Object[]) previousValue;
if (position < vals.length) {
previousValue = ArrayUtils.remove(vals, position);
} else {
log.error("Cannot delete position " + position + " in array with size " + vals.length);
}
} else {
log.error("Cannot delete position " + position + " in null array.");
}
return previousValue;
}
}
public Form getCreateForm(Field field, String namespace) {
try {
return calculateFieldForm(field, field.getDefaultSubform(), namespace);
} catch (Exception e) {
log.error("Error: ", e);
}
return null;
}
public Form getPreviewDataForm(Field field, String namespace) {
try {
return calculateFieldForm(field, field.getPreviewSubform(), namespace);
} catch (Exception e) {
log.error("Error: ", e);
}
return null;
}
public Form getTableDataForm(Field field, String namespace) {
try {
return calculateFieldForm(field, field.getTableSubform(), namespace);
} catch (Exception e) {
log.error("Error: ", e);
}
return null;
}
public Form getEditForm(Field field, String namespace) {
try {
return calculateFieldForm(field, field.getDefaultSubform(), namespace);
} catch (Exception e) {
log.error("Error: ", e);
}
return null;
}
}