/**
* 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.config;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.xerces.parsers.DOMParser;
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.api.model.wrappers.I18nEntry;
import org.jbpm.formModeler.api.model.wrappers.I18nSet;
import org.jbpm.formModeler.core.config.builders.dataHolder.DataHolderBuildConfig;
import org.jbpm.formModeler.core.wrappers.HTMLi18n;
import org.jbpm.formModeler.core.xml.util.XMLNode;
import org.jbpm.formModeler.service.LocaleManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
@ApplicationScoped
public class FormSerializationManagerImpl implements FormSerializationManager {
public static final String NODE_FORM = "form";
public static final String NODE_FIELD = "field";
public static final String NODE_PROPERTY = "property";
public static final String NODE_DATA_HOLDER = "dataHolder";
public static final String ATTR_ID = "id";
public static final String ATTR_INPUT_ID = "inputId";
public static final String ATTR_OUT_ID = "outId";
public static final String ATTR_POSITION = "position";
public static final String ATTR_TYPE = "type";
public static final String ATTR_BAG_TYPE = "bag-type";
public static final String ATTR_SUPPORTED_TYPE = "supportedType";
public static final String ATTR_NAME = "name";
public static final String ATTR_VALUE = "value";
@Inject
protected DataHolderManager dataHolderManager;
@Inject
private LocaleManager localeManager;
protected Logger log = LoggerFactory.getLogger(FormSerializationManager.class);
@Inject
protected FormManager formManager;
@Inject
protected FieldTypeManager fieldTypeManager;
public String generateFormXML(Form form) {
XMLNode rootNode = new XMLNode(NODE_FORM, null);
//TestFormSerialization test = new TestFormSerialization();
//test.saveFormToLocalDrive(form);
try {
return generateFormXML(form, rootNode);
} catch (Exception e) {
log.error("Error serializing form to XML.", e);
return "";
}
}
@Override
public String generateHeaderFormFormId(long formId) throws IOException {
XMLNode rootNode = new XMLNode(NODE_FORM, null);
rootNode.addAttribute(ATTR_ID, String.valueOf(formId));
StringWriter sw = new StringWriter();
rootNode.writeXML(sw, true);
return sw.toString().replace("/","").trim();
}
@Override
public Form loadFormFromXML(String xml, String path) throws Exception {
if (StringUtils.isBlank(xml)) return null;
return loadFormFromXML(new InputSource(new StringReader(xml)), path, null);
}
@Override
public Form loadFormFromXML(String xml) throws Exception {
if (StringUtils.isBlank(xml)) return null;
return loadFormFromXML(new InputSource(new StringReader(xml)), null);
}
@Override
public Form loadFormFromXML(InputStream is) throws Exception {
return loadFormFromXML(is, null);
}
@Override
public Form loadFormFromXML(InputStream is, Map<String, Properties> resources) throws Exception {
return loadFormFromXML(new InputSource(is), resources);
}
public Form loadFormFromXML(InputSource source, Map<String, Properties> resources) throws Exception {
DOMParser parser = new DOMParser();
parser.parse(source);
Document doc = parser.getDocument();
NodeList nodes = doc.getElementsByTagName(NODE_FORM);
Node rootNode = nodes.item(0);
return deserializeForm(rootNode, null, resources);
}
public Form loadFormFromXML(InputSource source, String path, Map<String, Properties> resources) throws Exception {
DOMParser parser = new DOMParser();
parser.parse(source);
Document doc = parser.getDocument();
NodeList nodes = doc.getElementsByTagName(NODE_FORM);
Node rootNode = nodes.item(0); // only comes a form
return deserializeForm(rootNode, path, resources);
}
public Form deserializeForm(Node nodeForm, String path, Map<String, Properties> resources) throws Exception {
if (!nodeForm.getNodeName().equals(NODE_FORM)) return null;
Form form = formManager.createForm("");
form.setId(Long.valueOf(StringEscapeUtils.unescapeXml(nodeForm.getAttributes().getNamedItem(ATTR_ID).getNodeValue())));
Set<Field> fields = new TreeSet<Field>();
NodeList childNodes = nodeForm.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node.getNodeName().equals(NODE_PROPERTY)) {
String propName = node.getAttributes().getNamedItem(ATTR_NAME).getNodeValue();
String value = StringEscapeUtils.unescapeXml(node.getAttributes().getNamedItem(ATTR_VALUE).getNodeValue());
if ("subject".equals(propName)) {
form.setSubject(value);
} else if ("name".equals(propName)) {
form.setName(value);
} else if ("displayMode".equals(propName)) {
form.setDisplayMode(value);
} else if ("labelMode".equals(propName)) {
form.setLabelMode(value);
} else if ("showMode".equals(propName)) {
form.setShowMode(value);
} else if ("status".equals(propName)) {
form.setStatus(Long.valueOf(value));
} else if ("formTemplate".equals(propName)) {
form.setFormTemplate(value);
}
} else if (node.getNodeName().equals(NODE_FIELD)) {
Field field = deserializeField(form, node, resources);
field.setForm(form);
fields.add(field);
} else if (node.getNodeName().equals(NODE_DATA_HOLDER)) {
String holderId = getNodeAttributeValue(node, ATTR_ID);
String holderInputId = getNodeAttributeValue(node, ATTR_INPUT_ID);
String holderOutId = getNodeAttributeValue(node, ATTR_OUT_ID);
String holderType = getNodeAttributeValue(node, ATTR_TYPE);
String holderValue = getNodeAttributeValue(node, ATTR_VALUE);
String holderRenderColor = getNodeAttributeValue(node, ATTR_NAME);
String holderSupportedType = getNodeAttributeValue(node, ATTR_SUPPORTED_TYPE);
if(!StringUtils.isEmpty(holderId) && !StringUtils.isEmpty(holderType) && !StringUtils.isEmpty(holderValue)) {
DataHolderBuildConfig config = new DataHolderBuildConfig(holderId, holderInputId, holderOutId, holderRenderColor, holderValue);
config.addAttribute("path", path);
if (!StringUtils.isEmpty(holderSupportedType)) config.addAttribute(ATTR_SUPPORTED_TYPE, holderSupportedType);
DataHolder holder = dataHolderManager.createDataHolderByType(holderType, config);
if (!StringUtils.isEmpty(holderId)) form.setDataHolder(holder);
}
} else if (node.getNodeName().equals(NODE_FORM)) {
Form subform = deserializeForm(node, path, resources);
form.addSubForm(subform.getName(), subform);
}
}
if (fields != null) form.setFormFields(fields);
return form;
}
protected String getNodeAttributeValue(Node node, String attributeName) {
Node attribute = node.getAttributes().getNamedItem(attributeName);
return attribute != null ? attribute.getNodeValue() : "";
}
private void addXMLNode(String propName, String value, XMLNode parent) {
if (!StringUtils.isEmpty(value)) {
XMLNode propertyNode = new XMLNode(NODE_PROPERTY, parent);
propertyNode.addAttribute(ATTR_NAME, propName);
propertyNode.addAttribute(ATTR_VALUE, value);
parent.addChild(propertyNode);
}
}
/**
* Generates the xml representation and mount in rootNode the structure to be included.
* Fills the XMLNode structure with the form representation and returns the string.
*/
public String generateFormXML(Form form, XMLNode rootNode) throws Exception {
rootNode.addAttribute(ATTR_ID, form.getId().toString());
addXMLNode("subject", form.getSubject(), rootNode);
addXMLNode("name", form.getName(), rootNode);
addXMLNode("displayMode", form.getDisplayMode(), rootNode);
addXMLNode("labelMode", form.getLabelMode(), rootNode);
addXMLNode("showMode", form.getShowMode(), rootNode);
addXMLNode("status", (form.getStatus() != null ? String.valueOf(form.getStatus()) : null), rootNode);
addXMLNode("formTemplate", form.getFormTemplate(), rootNode);
for (Field field: form.getFormFields()) {
generateFieldXML(field, rootNode);
}
for (DataHolder dataHolder: form.getHolders()) {
generateDataHolderXML(dataHolder, rootNode);
}
StringWriter sw = new StringWriter();
rootNode.writeXML(sw, true);
return sw.toString();
}
public Field deserializeField(Form form, Node nodeField, Map<String, Properties> resources) throws Exception {
if (!nodeField.getNodeName().equals(NODE_FIELD)) return null;
Field field = new Field();
field.setId(Long.valueOf(nodeField.getAttributes().getNamedItem(ATTR_ID).getNodeValue()));
field.setFieldName(nodeField.getAttributes().getNamedItem(ATTR_NAME).getNodeValue());
field.setPosition(Integer.parseInt(nodeField.getAttributes().getNamedItem(ATTR_POSITION).getNodeValue()));
field.setFieldType(fieldTypeManager.getTypeByCode(nodeField.getAttributes().getNamedItem(ATTR_TYPE).getNodeValue()));
Node bag = nodeField.getAttributes().getNamedItem(ATTR_BAG_TYPE);
if (bag != null) {
field.setBag(bag.getNodeValue());
}
NodeList fieldPropsNodes = nodeField.getChildNodes();
for (int j = 0; j < fieldPropsNodes.getLength(); j++) {
Node nodeFieldProp = fieldPropsNodes.item(j);
if (nodeFieldProp.getNodeName().equals(NODE_PROPERTY)) {
String propName = nodeFieldProp.getAttributes().getNamedItem(ATTR_NAME).getNodeValue();
String value = StringEscapeUtils.unescapeXml(nodeFieldProp.getAttributes().getNamedItem(ATTR_VALUE).getNodeValue());
if (propName != null && value != null) {
if ("fieldRequired".equals(propName)) {
field.setFieldRequired(Boolean.valueOf(value));
} else if ("groupWithPrevious".equals(propName)) {
field.setGroupWithPrevious(Boolean.valueOf(value));
} else if ("height".equals(propName)) {
field.setHeight(value);
} else if ("labelCSSClass".equals(propName)) {
field.setLabelCSSClass(value);
} else if ("labelCSSStyle".equals(propName)) {
field.setLabelCSSStyle(value);
} else if ("label".equals(propName)) {
field.setLabel(deserializeI18nEntrySet(value));
} else if ("errorMessage".equals(propName)) {
field.setErrorMessage(deserializeI18nEntrySet(value));
} else if ("title".equals(propName)) {
field.setTitle(deserializeI18nEntrySet(value));
} else if ("readonly".equals(propName)) {
field.setReadonly(Boolean.valueOf(value));
} else if ("size".equals(propName)) {
if (!StringUtils.isEmpty( value ) && StringUtils.isNumeric( value )) field.setSize(Long.valueOf(value));
} else if ("formula".equals(propName)) {
field.setFormula(value);
} else if ("rangeFormula".equals(propName)) {
field.setRangeFormula(value);
} else if ("pattern".equals(propName)) {
field.setPattern(value);
} else if ("maxlength".equals(propName)) {
if (!StringUtils.isEmpty( value ) && StringUtils.isNumeric( value )) field.setMaxlength(Long.valueOf(value));
} else if ("styleclass".equals(propName)) {
field.setStyleclass(value);
} else if ("cssStyle".equals(propName)) {
field.setCssStyle(value);
} else if ("tabindex".equals(propName)) {
if (!StringUtils.isEmpty( value ) && StringUtils.isNumeric( value )) field.setTabindex(Long.valueOf(value));
} else if ("accesskey".equals(propName)) {
field.setAccesskey(value);
} else if ("isHTML".equals(propName)) {
field.setIsHTML(Boolean.valueOf(value));
} else if ("htmlContent".equals(propName)) {
field.setHtmlContent(deserializeHMLI18nEntrySet(value));
} else if ("hideContent".equals(propName)) {
field.setHideContent(Boolean.valueOf(value));
} else if ("defaultValueFormula".equals(propName)) {
field.setDefaultValueFormula(value);
} else if ("defaultSubform".equals(propName)) {
field.setDefaultSubform(value);
} else if ("previewSubform".equals(propName)) {
field.setPreviewSubform(value);
} else if ("tableSubform".equals(propName)) {
field.setTableSubform(value);
} else if ("newItemText".equals(propName)) {
field.setNewItemText(deserializeI18nEntrySet(value));
} else if ("addItemText".equals(propName)) {
field.setAddItemText(deserializeI18nEntrySet(value));
} else if ("cancelItemText".equals(propName)) {
field.setCancelItemText(deserializeI18nEntrySet(value));
} else if ("deleteItems".equals(propName)) {
field.setDeleteItems(Boolean.valueOf(value));
} else if ("updateItems".equals(propName)) {
field.setUpdateItems(Boolean.valueOf(value));
} else if ("visualizeItems".equals(propName)) {
field.setVisualizeItem(Boolean.valueOf(value));
} else if ("hideCreateItem".equals(propName)) {
field.setHideCreateItem(Boolean.valueOf(value));
} else if ("expanded".equals(propName)) {
field.setExpanded(Boolean.valueOf(value));
} else if ("enableTableEnterData".equals(propName)) {
field.setEnableTableEnterData(Boolean.valueOf(value));
} else if ("inputBinding".equals(propName)) {
field.setInputBinding(value);
} else if ("outputBinding".equals(propName)) {
field.setOutputBinding(value);
} else if ("customFieldType".equals(propName)) {
field.setCustomFieldType(value);
} else if ("param1".equals(propName)) {
field.setParam1(value);
} else if ("param2".equals(propName)) {
field.setParam2(value);
} else if ("param3".equals(propName)) {
field.setParam3(value);
} else if ("param4".equals(propName)) {
field.setParam4(value);
} else if ("param5".equals(propName)) {
field.setParam5(value);
} else if ("fieldClass".equals(propName)) {
field.getFieldType().setFieldClass(value);
} else if ("onChangeScript".equals(propName)) {
field.setOnChangeScript(value);
}
}
}
}
if (resources != null) {
field.setTitle(new I18nSet());
field.setLabel(new I18nSet());
field.setErrorMessage(new I18nSet());
if (resources.containsKey("default")){
resources.put(localeManager.getDefaultLang(), resources.remove("default"));
}
for(String lang : resources.keySet()) {
Properties props = resources.get(lang);
String value = getFieldProperty(form.getName(), field.getFieldName(), "title", props);
if (!StringUtils.isEmpty(value)) field.getTitle().setValue(lang, value);
value = getFieldProperty(form.getName(), field.getFieldName(), "label", props);
if (!StringUtils.isEmpty(value)) field.getLabel().setValue(lang, value);
value = getFieldProperty(form.getName(), field.getFieldName(), "errorMessage", props);
if (!StringUtils.isEmpty(value)) field.getErrorMessage().setValue(lang, value);
}
}
return field;
}
private String getFieldProperty(String formName, String fieldName, String selector, Properties props) {
if (props == null) return null;
String value = props.getProperty(formName + "." + fieldName + "." + selector);
if (StringUtils.isEmpty(value)) value = props.getProperty(fieldName + "." + selector);
return value;
}
public void generateFieldXML(Field field, XMLNode parent) {
XMLNode rootNode = new XMLNode(NODE_FIELD, parent);
rootNode.addAttribute(ATTR_ID, String.valueOf(field.getId()));
rootNode.addAttribute(ATTR_POSITION, String.valueOf(field.getPosition()));
rootNode.addAttribute(ATTR_NAME, field.getFieldName());
if (field.getFieldType() != null) {
rootNode.addAttribute(ATTR_TYPE, field.getFieldType().getCode());
}
if (!StringUtils.isEmpty(field.getBag())) {
rootNode.addAttribute(ATTR_BAG_TYPE, field.getBag());
}
addXMLNode("fieldRequired", (field.getFieldRequired() != null ? String.valueOf(field.getFieldRequired()) : null), rootNode);
addXMLNode("groupWithPrevious", (field.getGroupWithPrevious() != null ? String.valueOf(field.getGroupWithPrevious()) : null), rootNode);
addXMLNode("height", field.getHeight(), rootNode);
addXMLNode("labelCSSClass", field.getLabelCSSClass(), rootNode);
addXMLNode("labelCSSStyle", field.getLabelCSSStyle(), rootNode);
addXMLNode("label", (field.getLabel() != null ? serializeI18nSet(field.getLabel()) : null), rootNode);
addXMLNode("errorMessage", (field.getErrorMessage() != null ? serializeI18nSet(field.getErrorMessage()) : null), rootNode);
addXMLNode("title", (field.getTitle() != null ? serializeI18nSet(field.getTitle()) : null), rootNode);
addXMLNode("readonly", (field.getReadonly() != null ? String.valueOf(field.getReadonly()) : null), rootNode);
addXMLNode("size", (field.getSize() != null ? String.valueOf(field.getSize()) : null), rootNode);
addXMLNode("formula", field.getFormula(), rootNode);
addXMLNode("rangeFormula", field.getRangeFormula(), rootNode);
addXMLNode("pattern", field.getPattern(), rootNode);
addXMLNode("maxlength", (field.getMaxlength() != null ? String.valueOf(field.getMaxlength()) : null), rootNode);
addXMLNode("styleclass", field.getStyleclass(), rootNode);
addXMLNode("cssStyle", field.getCssStyle(), rootNode);
addXMLNode("tabindex", (field.getTabindex() != null ? String.valueOf(field.getTabindex()) : null), rootNode);
addXMLNode("accesskey", field.getAccesskey(), rootNode);
addXMLNode("isHTML", (field.getIsHTML() != null ? String.valueOf(field.getIsHTML()) : null), rootNode);
addXMLNode("hideContent", (field.getHideContent() != null ? String.valueOf(field.getHideContent()) : null), rootNode);
addXMLNode("defaultValueFormula", field.getDefaultValueFormula(), rootNode);
addXMLNode("inputBinding", field.getInputBinding(), rootNode);
addXMLNode("outputBinding", field.getOutputBinding(), rootNode);
addXMLNode("htmlContent", (field.getHtmlContent() != null ? serializeI18nSet(field.getHtmlContent()) : null), rootNode);
addXMLNode("defaultSubform", field.getDefaultSubform(), rootNode);
addXMLNode("previewSubform", field.getPreviewSubform(), rootNode);
addXMLNode("tableSubform", field.getTableSubform(), rootNode);
addXMLNode("newItemText", (field.getNewItemText() != null ? serializeI18nSet(field.getNewItemText()):null), rootNode);
addXMLNode("addItemText", (field.getAddItemText() != null ? serializeI18nSet(field.getAddItemText()):null), rootNode);
addXMLNode("cancelItemText", (field.getCancelItemText() != null ? serializeI18nSet(field.getCancelItemText()):null), rootNode);
addXMLNode("deleteItems", (field.getDeleteItems() != null ? String.valueOf(field.getDeleteItems()) : null), rootNode);
addXMLNode("updateItems", (field.getUpdateItems() != null ? String.valueOf(field.getUpdateItems()) : null), rootNode);
addXMLNode("visualizeItems", (field.getVisualizeItem() != null ? String.valueOf(field.getVisualizeItem()) : null), rootNode);
addXMLNode("hideCreateItem", (field.getHideCreateItem() != null ? String.valueOf(field.getHideCreateItem()) : null), rootNode);
addXMLNode("expanded", (field.getExpanded() != null ? String.valueOf(field.getExpanded()) : null), rootNode);
addXMLNode("enableTableEnterData", (field.getEnableTableEnterData() != null ? String.valueOf(field.getEnableTableEnterData()) : null), rootNode);
addXMLNode("customFieldType", field.getCustomFieldType(), rootNode);
addXMLNode("fieldClass", field.getFieldType().getFieldClass(), rootNode);
addXMLNode("param1", field.getParam1(), rootNode);
addXMLNode("param2", field.getParam2(), rootNode);
addXMLNode("param3", field.getParam3(), rootNode);
addXMLNode("param4", field.getParam4(), rootNode);
addXMLNode("param5", field.getParam5(), rootNode);
addXMLNode("onChangeScript", field.getOnChangeScript(), rootNode);
parent.addChild(rootNode);
}
public void generateDataHolderXML(DataHolder dataHolder, XMLNode parent) {
XMLNode rootNode = new XMLNode(NODE_DATA_HOLDER, parent);
rootNode.addAttribute(ATTR_ID, dataHolder.getUniqeId());
rootNode.addAttribute(ATTR_INPUT_ID, dataHolder.getInputId());
rootNode.addAttribute(ATTR_OUT_ID, dataHolder.getOuputId());
rootNode.addAttribute(ATTR_TYPE, dataHolder.getTypeCode());
rootNode.addAttribute(ATTR_VALUE, dataHolder.getInfo());
rootNode.addAttribute(ATTR_NAME, dataHolder.getRenderColor());
if (!StringUtils.isEmpty(dataHolder.getSupportedType())) rootNode.addAttribute(ATTR_SUPPORTED_TYPE, dataHolder.getSupportedType());
parent.addChild(rootNode);
}
protected String[] decodeStringArray(String textValue) {
if (textValue == null || textValue.trim().length() == 0) return new String[0];
String[] lista;
lista = textValue.split("quot;");
return lista;
}
protected String encodeStringArray(String[] value) {
String cad = "";
for (int i = 0; i < value.length; i++) {
cad += "quot;" + value[i] + "quot;";
i++;
cad += ",quot;" + value[i] + "quot;";
}
return cad;
}
public String serializeI18nSet(I18nSet i18nSet) {
String[] values = new String[i18nSet.entrySet().size() * 2];
int i = 0;
for (Iterator it = i18nSet.entrySet().iterator(); it.hasNext(); ) {
I18nEntry entry = (I18nEntry) it.next();
values[i] = entry.getLang();
i++;
values[i] = (String) entry.getValue();
i++;
}
return encodeStringArray(values);
}
public I18nSet deserializeI18nEntrySet(String cadena) {
String[] values = decodeStringArray(cadena);
Map mapValues = new HashMap();
for (int i = 0; i < values.length;i=i+4) {
String key = values[i + 1];
String value="";
if( i+3 < values.length){
value = values[i + 3];
}
if(key.length()==2){
mapValues.put(key, value);
}
}
return new I18nSet(mapValues);
}
public HTMLi18n deserializeHMLI18nEntrySet(String cadena) {
String[] values = decodeStringArray(cadena);
Map mapValues = new HashMap();
for (int i = 0; i < values.length;i=i+4) {
String key = values[i + 1];
String value="";
if( i+3 < values.length){
value = values[i + 3];
}
if(key.length()==2){
mapValues.put(key, value);
}
}
return new HTMLi18n(mapValues);
}
}