org.activiti.dmn.xml.converter.DmnXMLConverter.java Source code

Java tutorial

Introduction

Here is the source code for org.activiti.dmn.xml.converter.DmnXMLConverter.java

Source

/* 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.activiti.dmn.xml.converter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import javax.xml.XMLConstants;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.activiti.dmn.converter.util.DmnXMLUtil;
import org.activiti.dmn.model.Decision;
import org.activiti.dmn.model.DecisionRule;
import org.activiti.dmn.model.DecisionTable;
import org.activiti.dmn.model.DmnDefinition;
import org.activiti.dmn.model.DmnElement;
import org.activiti.dmn.model.DmnExtensionElement;
import org.activiti.dmn.model.HitPolicy;
import org.activiti.dmn.model.InputClause;
import org.activiti.dmn.model.ItemDefinition;
import org.activiti.dmn.model.OutputClause;
import org.activiti.dmn.model.RuleInputClauseContainer;
import org.activiti.dmn.model.RuleOutputClauseContainer;
import org.activiti.dmn.xml.constants.DmnXMLConstants;
import org.activiti.dmn.xml.exception.DmnXMLException;
import org.activiti.engine.io.InputStreamProvider;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

/**
 * @author Tijs Rademakers
 * @author Yvo Swillens
 * @author Bassam Al-Sarori
 */
public class DmnXMLConverter implements DmnXMLConstants {

    protected static final Logger LOGGER = LoggerFactory.getLogger(DmnXMLConverter.class);

    protected static final String DMN_XSD = "org/activiti/impl/dmn/parser/dmn.xsd";
    protected static final String DEFAULT_ENCODING = "UTF-8";

    protected static Map<String, BaseDmnXMLConverter> convertersToDmnMap = new HashMap<String, BaseDmnXMLConverter>();
    protected static Map<Class<? extends DmnElement>, BaseDmnXMLConverter> convertersToXMLMap = new HashMap<Class<? extends DmnElement>, BaseDmnXMLConverter>();

    protected ClassLoader classloader;

    static {
        addConverter(new InputClauseXMLConverter());
        addConverter(new DecisionRuleXMLConverter());
    }

    public static void addConverter(BaseDmnXMLConverter converter) {
        addConverter(converter, converter.getDmnElementType());
    }

    public static void addConverter(BaseDmnXMLConverter converter, Class<? extends DmnElement> elementType) {
        convertersToDmnMap.put(converter.getXMLElementName(), converter);
        convertersToXMLMap.put(elementType, converter);
    }

    public void setClassloader(ClassLoader classloader) {
        this.classloader = classloader;
    }

    public void validateModel(InputStreamProvider inputStreamProvider) throws Exception {
        Schema schema = createSchema();

        Validator validator = schema.newValidator();
        validator.validate(new StreamSource(inputStreamProvider.getInputStream()));
    }

    public void validateModel(XMLStreamReader xmlStreamReader) throws Exception {
        Schema schema = createSchema();

        Validator validator = schema.newValidator();
        validator.validate(new StAXSource(xmlStreamReader));
    }

    protected Schema createSchema() throws SAXException {
        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = null;
        if (classloader != null) {
            schema = factory.newSchema(classloader.getResource(DMN_XSD));
        }

        if (schema == null) {
            schema = factory.newSchema(DmnXMLConverter.class.getClassLoader().getResource(DMN_XSD));
        }

        if (schema == null) {
            throw new DmnXMLException("DMN XSD could not be found");
        }
        return schema;
    }

    public DmnDefinition convertToDmnModel(InputStreamProvider inputStreamProvider, boolean validateSchema,
            boolean enableSafeBpmnXml) {
        return convertToDmnModel(inputStreamProvider, validateSchema, enableSafeBpmnXml, DEFAULT_ENCODING);
    }

    public DmnDefinition convertToDmnModel(InputStreamProvider inputStreamProvider, boolean validateSchema,
            boolean enableSafeBpmnXml, String encoding) {
        XMLInputFactory xif = XMLInputFactory.newInstance();

        if (xif.isPropertySupported(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES)) {
            xif.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
        }

        if (xif.isPropertySupported(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES)) {
            xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
        }

        if (xif.isPropertySupported(XMLInputFactory.SUPPORT_DTD)) {
            xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
        }

        InputStreamReader in = null;
        try {
            in = new InputStreamReader(inputStreamProvider.getInputStream(), encoding);
            XMLStreamReader xtr = xif.createXMLStreamReader(in);

            try {
                if (validateSchema) {

                    if (!enableSafeBpmnXml) {
                        validateModel(inputStreamProvider);
                    } else {
                        validateModel(xtr);
                    }

                    // The input stream is closed after schema validation
                    in = new InputStreamReader(inputStreamProvider.getInputStream(), encoding);
                    xtr = xif.createXMLStreamReader(in);
                }

            } catch (Exception e) {
                throw new DmnXMLException(e.getMessage(), e);
            }

            // XML conversion
            return convertToDmnModel(xtr);

        } catch (UnsupportedEncodingException e) {
            throw new DmnXMLException("The dmn xml is not UTF8 encoded", e);
        } catch (XMLStreamException e) {
            throw new DmnXMLException("Error while reading the BPMN 2.0 XML", e);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    LOGGER.debug("Problem closing DMN input stream", e);
                }
            }
        }
    }

    public DmnDefinition convertToDmnModel(XMLStreamReader xtr) {
        DmnDefinition model = new DmnDefinition();
        DmnElement parentElement = null;

        try {
            while (xtr.hasNext()) {
                try {
                    xtr.next();
                } catch (Exception e) {
                    LOGGER.debug("Error reading XML document", e);
                    throw new DmnXMLException("Error reading XML", e);
                }

                if (xtr.isStartElement() == false) {
                    continue;
                }

                if (ELEMENT_DEFINITIONS.equals(xtr.getLocalName())) {
                    model.setId(xtr.getAttributeValue(null, ATTRIBUTE_ID));
                    model.setName(xtr.getAttributeValue(null, ATTRIBUTE_NAME));
                    model.setNamespace(MODEL_NAMESPACE);
                    parentElement = model;
                } else if (ELEMENT_DECISION.equals(xtr.getLocalName())) {
                    Decision decision = new Decision();
                    model.addDrgElement(decision);
                    decision.setId(xtr.getAttributeValue(null, ATTRIBUTE_ID));
                    decision.setName(xtr.getAttributeValue(null, ATTRIBUTE_NAME));
                    parentElement = decision;
                } else if (ELEMENT_DECISION_TABLE.equals(xtr.getLocalName())) {
                    DecisionTable currentDecisionTable = new DecisionTable();
                    currentDecisionTable.setId(xtr.getAttributeValue(null, ATTRIBUTE_ID));

                    if (xtr.getAttributeValue(null, ATTRIBUTE_HIT_POLICY) != null) {
                        currentDecisionTable
                                .setHitPolicy(HitPolicy.valueOf(xtr.getAttributeValue(null, ATTRIBUTE_HIT_POLICY)));
                    } else {
                        currentDecisionTable.setHitPolicy(HitPolicy.FIRST);
                    }

                    model.getDrgElements().get(model.getDrgElements().size() - 1)
                            .setDecisionTable(currentDecisionTable);
                    model.setCurrentDecisionTable(currentDecisionTable);
                    parentElement = currentDecisionTable;
                } else if (ELEMENT_OUTPUT_CLAUSE.equals(xtr.getLocalName())) {
                    OutputClause outputClause = new OutputClause();
                    model.getCurrentDecisionTable().addOutput(outputClause);
                    outputClause.setId(xtr.getAttributeValue(null, ATTRIBUTE_ID));
                    outputClause.setLabel(xtr.getAttributeValue(null, ATTRIBUTE_LABEL));
                    outputClause.setName(xtr.getAttributeValue(null, ATTRIBUTE_NAME));
                    outputClause.setTypeRef(xtr.getAttributeValue(null, ATTRIBUTE_TYPE_REF));
                    parentElement = outputClause;
                } else if (ELEMENT_DESCRIPTION.equals(xtr.getLocalName())) {
                    parentElement.setDescription(xtr.getElementText());
                } else if (ELEMENT_EXTENSIONS.equals(xtr.getLocalName())) {
                    while (xtr.hasNext()) {
                        xtr.next();
                        if (xtr.isStartElement()) {
                            DmnExtensionElement extensionElement = DmnXMLUtil.parseExtensionElement(xtr);
                            parentElement.addExtensionElement(extensionElement);
                        } else if (xtr.isEndElement()) {
                            if (ELEMENT_EXTENSIONS.equals(xtr.getLocalName())) {
                                break;
                            }
                        }
                    }

                } else if (convertersToDmnMap.containsKey(xtr.getLocalName())) {
                    BaseDmnXMLConverter converter = convertersToDmnMap.get(xtr.getLocalName());
                    converter.convertToDmnModel(xtr, model);
                }
            }

            processDmnElements(model.getCurrentDecisionTable());

        } catch (DmnXMLException e) {
            throw e;

        } catch (Exception e) {
            LOGGER.error("Error processing DMN document", e);
            throw new DmnXMLException("Error processing DMN document", e);
        }
        return model;
    }

    protected void processDmnElements(DecisionTable decisionTable) {
        Map<String, RuleInputClauseContainer> inputClauseMap = new HashMap<String, RuleInputClauseContainer>();
        Map<String, RuleOutputClauseContainer> outputClauseMap = new HashMap<String, RuleOutputClauseContainer>();
        //
        //        for (DecisionRule rule : decisionTable.getRules()) {
        //            List<RuleInputClauseContainer> finalInputs = new ArrayList<>();
        //            for (RuleInputClauseContainer inputContainer : rule.getInputEntries()) {
        //                if (inputContainer.getInputEntry() != null) {
        //                    finalInputs.add(inputContainer);
        //                }
        //            }
        //
        //            List<RuleOutputClauseContainer> finalOutputs = new ArrayList<>();
        //            for (RuleOutputClauseContainer outputContainer : rule.getOutputEntries()) {
        //                if (outputContainer.getInputOutputExpression() != null) {
        //                    finalConclusions.add(conclusionContainer);
        //
        //                } else {
        //                    throw new DmnXMLException("Can not find conclusion entry " + conclusionContainer.getInputOutputExpression().getId());
        //                }
        //            }
        //
        //            rule.setInputEntries(ru);
        //            rule.setConclusions(finalConclusions);
        //        }
    }

    public byte[] convertToXML(DmnDefinition model) {
        return convertToXML(model, DEFAULT_ENCODING);
    }

    public byte[] convertToXML(DmnDefinition model, String encoding) {
        try {

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            XMLOutputFactory xof = XMLOutputFactory.newInstance();
            OutputStreamWriter out = new OutputStreamWriter(outputStream, encoding);

            XMLStreamWriter writer = xof.createXMLStreamWriter(out);
            XMLStreamWriter xtw = new IndentingXMLStreamWriter(writer);

            xtw.writeStartElement(ELEMENT_DEFINITIONS);
            xtw.writeDefaultNamespace(DMN_NAMESPACE);
            xtw.writeAttribute(ATTRIBUTE_ID, model.getId());
            if (StringUtils.isNotEmpty(model.getName())) {
                xtw.writeAttribute(ATTRIBUTE_NAME, model.getName());
            }
            xtw.writeAttribute(ATTRIBUTE_NAMESPACE, MODEL_NAMESPACE);

            DmnXMLUtil.writeElementDescription(model, xtw);
            DmnXMLUtil.writeExtensionElements(model, xtw);

            for (ItemDefinition itemDefinition : model.getItemDefinitions()) {
                xtw.writeStartElement(ELEMENT_ITEM_DEFINITION);
                xtw.writeAttribute(ATTRIBUTE_ID, itemDefinition.getId());
                if (StringUtils.isNotEmpty(itemDefinition.getName())) {
                    xtw.writeAttribute(ATTRIBUTE_NAME, itemDefinition.getName());
                }

                DmnXMLUtil.writeElementDescription(itemDefinition, xtw);
                DmnXMLUtil.writeExtensionElements(itemDefinition, xtw);

                xtw.writeStartElement(ELEMENT_TYPE_DEFINITION);
                xtw.writeCharacters(itemDefinition.getTypeDefinition());
                xtw.writeEndElement();

                xtw.writeEndElement();
            }

            for (Decision decision : model.getDrgElements()) {
                xtw.writeStartElement(ELEMENT_DECISION);
                xtw.writeAttribute(ATTRIBUTE_ID, decision.getId());
                if (StringUtils.isNotEmpty(decision.getName())) {
                    xtw.writeAttribute(ATTRIBUTE_NAME, decision.getName());
                }

                DmnXMLUtil.writeElementDescription(decision, xtw);
                DmnXMLUtil.writeExtensionElements(decision, xtw);

                DecisionTable decisionTable = decision.getDecisionTable();
                xtw.writeStartElement(ELEMENT_DECISION_TABLE);
                xtw.writeAttribute(ATTRIBUTE_ID, decisionTable.getId());

                if (decisionTable.getHitPolicy() != null) {
                    xtw.writeAttribute(ATTRIBUTE_HIT_POLICY, decisionTable.getHitPolicy().toString());
                }

                DmnXMLUtil.writeElementDescription(decisionTable, xtw);
                DmnXMLUtil.writeExtensionElements(decisionTable, xtw);

                for (InputClause clause : decisionTable.getInputs()) {
                    xtw.writeStartElement(ELEMENT_INPUT_CLAUSE);
                    if (StringUtils.isNotEmpty(clause.getId())) {
                        xtw.writeAttribute(ATTRIBUTE_ID, clause.getId());
                    }
                    if (StringUtils.isNotEmpty(clause.getLabel())) {
                        xtw.writeAttribute(ATTRIBUTE_LABEL, clause.getLabel());
                    }

                    DmnXMLUtil.writeElementDescription(clause, xtw);
                    DmnXMLUtil.writeExtensionElements(clause, xtw);

                    if (clause.getInputExpression() != null) {
                        xtw.writeStartElement(ELEMENT_INPUT_EXPRESSION);
                        xtw.writeAttribute(ATTRIBUTE_ID, clause.getInputExpression().getId());

                        if (StringUtils.isNotEmpty(clause.getInputExpression().getTypeRef())) {
                            xtw.writeAttribute(ATTRIBUTE_TYPE_REF, clause.getInputExpression().getTypeRef());
                        }

                        if (StringUtils.isNotEmpty(clause.getInputExpression().getText())) {
                            xtw.writeStartElement(ELEMENT_TEXT);
                            xtw.writeCharacters(clause.getInputExpression().getText());
                            xtw.writeEndElement();
                        }

                        xtw.writeEndElement();
                    }

                    xtw.writeEndElement();
                }

                for (OutputClause clause : decisionTable.getOutputs()) {
                    xtw.writeStartElement(ELEMENT_OUTPUT_CLAUSE);
                    if (StringUtils.isNotEmpty(clause.getId())) {
                        xtw.writeAttribute(ATTRIBUTE_ID, clause.getId());
                    }
                    if (StringUtils.isNotEmpty(clause.getLabel())) {
                        xtw.writeAttribute(ATTRIBUTE_LABEL, clause.getLabel());
                    }
                    if (StringUtils.isNotEmpty(clause.getName())) {
                        xtw.writeAttribute(ATTRIBUTE_NAME, clause.getName());
                    }
                    if (StringUtils.isNotEmpty(clause.getTypeRef())) {
                        xtw.writeAttribute(ATTRIBUTE_TYPE_REF, clause.getTypeRef());
                    }

                    DmnXMLUtil.writeElementDescription(clause, xtw);
                    DmnXMLUtil.writeExtensionElements(clause, xtw);

                    xtw.writeEndElement();
                }

                for (DecisionRule rule : decisionTable.getRules()) {
                    xtw.writeStartElement(ELEMENT_RULE);
                    if (StringUtils.isNotEmpty(rule.getId())) {
                        xtw.writeAttribute(ATTRIBUTE_ID, rule.getId());
                    }

                    DmnXMLUtil.writeElementDescription(rule, xtw);
                    DmnXMLUtil.writeExtensionElements(rule, xtw);

                    for (RuleInputClauseContainer container : rule.getInputEntries()) {
                        xtw.writeStartElement(ELEMENT_INPUT_ENTRY);
                        xtw.writeAttribute(ATTRIBUTE_ID, container.getInputEntry().getId());

                        xtw.writeStartElement(ELEMENT_TEXT);
                        xtw.writeCharacters(container.getInputEntry().getText());
                        xtw.writeEndElement();

                        xtw.writeEndElement();
                    }

                    for (RuleOutputClauseContainer container : rule.getOutputEntries()) {
                        xtw.writeStartElement(ELEMENT_OUTPUT_ENTRY);
                        xtw.writeAttribute(ATTRIBUTE_ID, container.getOutputEntry().getId());

                        xtw.writeStartElement(ELEMENT_TEXT);
                        xtw.writeCharacters(container.getOutputEntry().getText());
                        xtw.writeEndElement();

                        xtw.writeEndElement();
                    }

                    xtw.writeEndElement();
                }

                xtw.writeEndElement();

                xtw.writeEndElement();
            }

            // end definitions root element
            xtw.writeEndElement();
            xtw.writeEndDocument();

            xtw.flush();

            outputStream.close();

            xtw.close();

            return outputStream.toByteArray();

        } catch (Exception e) {
            LOGGER.error("Error writing BPMN XML", e);
            throw new DmnXMLException("Error writing BPMN XML", e);
        }
    }

    private void createXML(DmnDefinition model, XMLStreamWriter xtw) throws Exception {
        for (Decision decision : model.getDrgElements()) {

            /*BaseDmnXMLConverter converter = convertersToXMLMap.get(flowElement.getClass());
                
            if (converter == null) {
            throw new DmnXMLException("No converter for " + flowElement.getClass() + " found");
            }
                
            converter.convertToXML(xtw, flowElement, model);*/
        }
    }
}