de.mwolff.command.chainbuilder.XMLChainBuilder.java Source code

Java tutorial

Introduction

Here is the source code for de.mwolff.command.chainbuilder.XMLChainBuilder.java

Source

/**
Simple Command Framework.
    
Framework for easy building software that fits the SOLID principles.
@author Manfred Wolff <m.wolff@neusta.de>
Download: https://github.com/simplecommand/SimpleCommandFramework
    
    
Copyright (C) 2015 neusta software development
    
This library 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 2.1 of the License, or (at your option) any later version.
    
This library 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 this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
USA
 */
package de.mwolff.command.chainbuilder;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import de.mwolff.commons.command.DefaultCommandContainer;
import de.mwolff.commons.command.DefaultTransition;
import de.mwolff.commons.command.iface.ChainBuilder;
import de.mwolff.commons.command.iface.Command;
import de.mwolff.commons.command.iface.CommandContainer;
import de.mwolff.commons.command.iface.CommandException;
import de.mwolff.commons.command.iface.ParameterObject;
import de.mwolff.commons.command.iface.ProcessCommand;
import de.mwolff.commons.command.iface.Transition;

/**
 * Chain builder parsing an XML file for building chains or process chains.
 *
 * @author Manfred Wolff
 */
public class XMLChainBuilder<T extends ParameterObject> implements ChainBuilder<T> {

    private static final Logger LOG = Logger.getLogger(XMLChainBuilder.class);
    private static final String ROOT = "//process/action";
    private static final String TRANS = "//process/action[@id='%s']/transition";
    private static final String CLASS = "class";

    private static final String ID = "id";
    private static final String NAME = "name";
    private static final String TO = "to";
    private String xmlFileName;

    private final List<Command<ParameterObject>> actions;
    Document document;

    /**
     * Constructor.
     *
     * @param xmlFileName
     *            Filename of the XML file. File has to reachable during
     *            CLASSPATH.
     */
    public XMLChainBuilder(final String xmlFileName) {
        this.xmlFileName = xmlFileName;
        actions = new ArrayList<Command<ParameterObject>>();
    }

    // **** Methods from super type *****

    /*
     * @see de.mwolff.commons.command.iface.ChainBuilder#buildChain()
     */
    @Override
    public CommandContainer<T> buildChain() throws CommandException {

        final String resource = xmlFileName;
        final SAXReader reader = new SAXReader();
        createXMLStream(reader, resource);
        createCommandsOutOfXML(document);

        return addCommandsToCommandContainer();
    }

    /*
     * @see
     * de.mwolff.commons.command.iface.Command#execute(de.mwolff.commons.command
     * .iface.ParameterObject)
     */
    @Override
    public void execute(final T context) throws CommandException {
        try {
            buildChain().execute(context);
        } catch (final Exception e) {
            // Just log, do nothing else
            XMLChainBuilder.LOG.error("Error while executing chain.", e);

        }
    }

    /*
     * @see
     * de.mwolff.commons.command.iface.ChainCommand#executeAsChain(de.mwolff.
     * commons.command.iface.ParameterObject)
     */
    @Override
    public boolean executeAsChain(final T context) {
        CommandContainer<T> chain = null;
        try {
            chain = buildChain();
        } catch (final Exception e) {
            XMLChainBuilder.LOG.error("Operation aborted via command implementation.", e);
            return false;
        }
        return chain.executeAsChain(context);
    }

    /*
     * @see
     * de.mwolff.commons.command.iface.ProcessCommand#executeAsProcess(java.lang
     * .String, de.mwolff.commons.command.iface.ParameterObject)
     */
    @Override
    public String executeAsProcess(final String startCommand, final T context) {
        try {
            return buildChain().executeAsProcess(startCommand, context);
        } catch (final CommandException e) {
            LOG.error(e);
            return null;
        }
    }

    /*
     * @see de.mwolff.commons.command.iface.ProcessCommand#getProcessID()
     */
    @Override
    public String getProcessID() {
        return null;
    }

    /*
     * @see
     * de.mwolff.commons.command.iface.ProcessCommand#setProcessID(java.lang.
     * String)
     */
    @Override
    public void setProcessID(final String processID) {
        throw new IllegalArgumentException("ProcessID cannot be set on Container.");
    }

    @SuppressWarnings("unchecked")
    private void createCommandsOutOfXML(final Document document) throws CommandException {

        final List<Element> list = document.selectNodes(ROOT);

        if (!list.isEmpty()) {
            for (final Element element : list) {
                extractAttributesOfActionElement(element);
            }
        }
    }

    private void readXMLDocument(final SAXReader reader, final InputStream xmlStream) throws CommandException {
        try {
            document = reader.read(xmlStream);
        } catch (final DocumentException e) {
            throw new CommandException("XML Document could not created", e);
        }
    }

    @SuppressWarnings("unchecked")
    private CommandContainer<T> addCommandsToCommandContainer() {
        final CommandContainer<T> commandContainer = new DefaultCommandContainer<T>();
        for (final Command<ParameterObject> command : actions) {
            commandContainer.addCommand((Command<T>) command);
        }
        return commandContainer;
    }

    @SuppressWarnings("unchecked")
    private Command<ParameterObject> createAndAddAction(final String name)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Command<ParameterObject> command;
        command = (Command<ParameterObject>) Class.forName(name).newInstance();
        actions.add(command);
        return command;
    }

    private void createXMLStream(final SAXReader reader, final String resource) throws CommandException {
        final InputStream xmlStream = this.getClass().getResourceAsStream(resource);
        if (xmlStream != null) {
            readXMLDocument(reader, xmlStream);
        } else {
            throw new CommandException("Could not read xml file");
        }
    }

    private void extractAttributesOfActionElement(final Element element) throws CommandException {

        Command<ParameterObject> action = null;
        String actionID = null;

        final Map<String, String> attributeMap = getAttributeOfElement(element);

        String value = attributeMap.get(CLASS);
        try {
            action = createAndAddAction(value);
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            LOG.error(e);
            throw new CommandException("Error creating class via reflection out of xml definition.", e);
        }

        value = attributeMap.get(ID);
        if (value != null) {
            ((ProcessCommand<ParameterObject>) action).setProcessID(value);
            actionID = value;
        }

        if (actionID != null) {
            extractAttributesOfTransitionElement((ProcessCommand<ParameterObject>) action, actionID);
        }
    }

    private static Map<String, String> getAttributeOfElement(final Element element) {
        final Map<String, String> attributeMap = new HashMap<>();
        for (int i = 0; i < element.attributeCount(); i++) {
            attributeMap.put(element.attribute(i).getName(), element.attribute(i).getValue());
        }
        return attributeMap;
    }

    @SuppressWarnings("unchecked")
    private void extractAttributesOfTransitionElement(final ProcessCommand<ParameterObject> command,
            final String commandID) {

        final List<Element> transitionElementList = document.selectNodes(String.format(TRANS, commandID));

        for (final Element transition : transitionElementList) {
            final Transition transitionClass = new DefaultTransition();

            final Map<String, String> attributeMap = getAttributeOfElement(transition);

            String value = attributeMap.get(NAME);
            transitionClass.setReturnValue(value);

            value = attributeMap.get(TO);
            transitionClass.setTarget(value);

            command.addTransition(transitionClass);
        }
    }
}