cross.datastructures.workflow.DefaultWorkflow.java Source code

Java tutorial

Introduction

Here is the source code for cross.datastructures.workflow.DefaultWorkflow.java

Source

/*
 * Cross, common runtime object support system.
 * Copyright (C) 2008-2012, The authors of Cross. All rights reserved.
 *
 * Project website: http://maltcms.sf.net
 *
 * Cross may be used under the terms of either the
 *
 * GNU Lesser General Public License (LGPL)
 * http://www.gnu.org/licenses/lgpl.html
 *
 * or the
 *
 * Eclipse Public License (EPL)
 * http://www.eclipse.org/org/documents/epl-v10.php
 *
 * As a user/recipient of Cross, you may choose which license to receive the code
 * under. Certain files or entire directories may not be covered by this
 * dual license, but are subject to licenses compatible to both LGPL and EPL.
 * License exceptions are explicitly declared in all relevant files or in a
 * LICENSE file in the relevant directories.
 *
 * Cross 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. Please consult the relevant license documentation
 * for details.
 */
package cross.datastructures.workflow;

import cross.IFactory;
import cross.annotations.Configurable;
import cross.commands.fragments.AFragmentCommand;
import cross.commands.fragments.IFragmentCommand;
import cross.datastructures.fragments.FileFragment;
import cross.datastructures.fragments.IFileFragment;
import cross.datastructures.pipeline.ICommandSequence;
import cross.datastructures.tuple.TupleND;
import cross.event.AEvent;
import cross.event.EventSource;
import cross.event.IEvent;
import cross.event.IEventSource;
import cross.event.IListener;
import cross.exception.ConstraintViolationException;
import cross.io.misc.DefaultConfigurableFileFilter;
import cross.io.xml.IXMLSerializable;
import cross.tools.StringTools;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.ProcessingInstruction;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.openide.util.lookup.ServiceProvider;

/**
 * A default implementation of {@link cross.datastructures.workflow.IWorkflow}.
 * Is a source of
 * <code>IEvent<IWorkflowResult></code> events.
 *
 * @author Nils Hoffmann
 *
 */
@Slf4j
@ServiceProvider(service = IWorkflow.class)
public class DefaultWorkflow implements IWorkflow, IXMLSerializable {

    /**
     *
     */
    private static final long serialVersionUID = 1781229121330043626L;
    private Collection<IWorkflowResult> al = new ArrayList<>();
    private transient IEventSource<IWorkflowResult> iwres = new EventSource<>();
    private ICommandSequence commandSequence = null;
    private String name = "workflow";
    private IFragmentCommand activeCommand = null;
    @Configurable
    private String xslPathPrefix;
    @Configurable(name = "resultFileFilter")
    private String fileFilter = DefaultConfigurableFileFilter.class.getName();
    @Configurable
    private boolean saveHTML = false;
    @Configurable
    private boolean saveTEXT = false;
    private Date date = new Date();
    private Configuration cfg = new PropertiesConfiguration();
    private boolean executeLocal = true;
    private File outputDirectory = new File(System.getProperty("user.dir"));
    private List<IWorkflowPostProcessor> workflowPostProcessors = new ArrayList<>();
    private transient IFactory factory;

    @Override
    public void addListener(final IListener<IEvent<IWorkflowResult>> l) {
        this.iwres.addListener(l);
    }

    @Override
    public void append(final IWorkflowResult iwr) {
        if (this.al == null) {
            this.al = new LinkedHashSet<>();
        }
        if (iwr instanceof IWorkflowProgressResult) {
            final IWorkflowProgressResult iwpr = (IWorkflowProgressResult) iwr;
            log.info("Step {}/{}, Overall progress: {}%",
                    new Object[] { iwpr.getCurrentStep(), iwpr.getNumberOfSteps(), iwpr.getOverallProgress() });
        } else {
            this.al.add(iwr);
        }
        fireEvent(new AEvent<>(iwr, DefaultWorkflow.this.iwres));
    }

    @Override
    public void appendXML(final Element e) {
        log.debug("Appending xml for DefaultWorkflow " + getName());
        getCommandSequence().appendXML(e);
        for (final IWorkflowResult wr : this.al) {
            wr.appendXML(e);
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * cross.IConfigurable#configure(org.apache.commons.configuration.Configuration
     * )
     */
    @Override
    public void configure(final Configuration cfg) {
        this.saveHTML = cfg.getBoolean(this.getClass().getName() + ".saveHTML", false);
        this.saveTEXT = cfg.getBoolean(this.getClass().getName() + ".saveTEXT", false);
        this.xslPathPrefix = cfg.getString(this.getClass().getName() + ".xslPathPrefix", "");
        this.fileFilter = cfg.getString(this.getClass().getName() + ".resultFileFilter",
                DefaultConfigurableFileFilter.class.getName());
    }

    @Override
    public void fireEvent(final IEvent<IWorkflowResult> e) {
        this.iwres.fireEvent(e);
    }

    /**
     * @return the ICommandSequence
     */
    @Override
    public ICommandSequence getCommandSequence() {
        return this.commandSequence;
    }

    /*
     * (non-Javadoc)
     *
     * @see cross.datastructures.workflow.IWorkflow#getConfiguration()
     */
    @Override
    public Configuration getConfiguration() {
        return this.cfg;
    }

    /**
     * @return the fileFilter
     */
    public String getFileFilter() {
        return this.fileFilter;
    }

    /**
     * @return the iwres
     */
    public IEventSource<IWorkflowResult> getIwres() {
        return this.iwres;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public Iterator<IWorkflowResult> getResults() {
        return this.al.iterator();
    }

    /*
     * (non-Javadoc)
     *
     * @see cross.datastructures.workflow.IWorkflow#getStartupDate()
     */
    @Override
    public Date getStartupDate() {
        return this.date;
    }

    /**
     * @return the IWorkflowResults as List
     */
    public Collection<IWorkflowResult> getWorkflowResults() {
        return this.al;
    }

    /**
     * @return the xslPathPrefix
     */
    public String getXslPathPrefix() {
        return this.xslPathPrefix;
    }

    @Override
    public void readXML(final Element e) throws IOException, ClassNotFoundException {
        final String workflowname = e.getAttributeValue("name");
        if (workflowname != null) {
            setName(workflowname);
        }

        TupleND<IFileFragment> inputFragments = new TupleND<>();
        Element workflowInputs = e.getChild("workflowInputs");
        for (Object child : workflowInputs.getChildren("workflowInput")) {
            Element workflowInput = (Element) child;
            String uri = workflowInput.getAttributeValue("uri");
            inputFragments.add(new FileFragment(URI.create(uri)));
        }

        Element workflowOutputs = e.getChild("workflowOutputs");
        for (Object child : workflowOutputs.getChildren("workflowOutput")) {
            Element workflowOutput = (Element) child;
            String uri = workflowOutput.getAttributeValue("uri");
        }

        Element workflowCommands = e.getChild("workflowCommands");
        List<?> commandChildren = workflowCommands.getChildren("workflowCommand");
        if (commandChildren.size() != getCommandSequence().getCommands().size()) {
            throw new ConstraintViolationException(
                    "Number of workflow commands between stored and active workflow differ! Not loading old workflow!");
        }
        int i = 0;
        for (Object child : commandChildren) {
            Element workflowCommand = (Element) child;
            String clazz = workflowCommand.getAttributeValue("class");
            if (!getCommandSequence().getCommands().get(i).getClass().getCanonicalName().equals(clazz)) {
                throw new ConstraintViolationException(
                        "Workflow commands differ between stored and active workflow at position " + i + "!");
            }
            i++;
        }

        final List<?> l = e.getChildren("workflowElementResult");
        for (final Object obj : l) {
            final Element elem = (Element) obj;
            final String cls = elem.getAttributeValue("class");
            final String slot = elem.getAttributeValue("slot");
            final String generator = elem.getAttributeValue("generator");
            IWorkflowResult iwr = null;
            String file = "";
            try {

                iwr = getFactory().getObjectFactory().instantiate(cls, IWorkflowResult.class);
                final IWorkflowElement iwe = getFactory().getObjectFactory().instantiate(generator,
                        IWorkflowElement.class);
                iwr.setWorkflowElement(iwe);
                iwr.setWorkflowSlot(WorkflowSlot.valueOf(slot));
                if (iwr instanceof IWorkflowFileResult) {
                    file = elem.getAttributeValue("file");
                    IWorkflowFileResult fileResult = (IWorkflowFileResult) iwr;
                    fileResult.setFile(new File(file));
                    Element resources = e.getChild("resources");
                    if (resources != null) {
                        List<IFileFragment> fragments = new ArrayList<>();
                        for (Object o : resources.getChildren("resource")) {
                            Element resource = (Element) o;
                            URI uri = URI.create(resource.getAttributeValue("resource"));
                            fragments.add(new FileFragment(uri));
                        }
                        fileResult.setResources(fragments.toArray(new IFileFragment[fragments.size()]));
                    }
                } else {
                    log.warn("Unsupported workflow result type! Can not convert!");
                }
                append(iwr);
            } catch (ConstraintViolationException rnae) {
                if (iwr != null) {
                    log.warn("Could not load result! Not found at location: " + file);
                } else {
                    log.warn("Could not load workflow result!");
                }
            }
        }
    }

    @Override
    public void removeListener(final IListener<IEvent<IWorkflowResult>> l) {
        this.iwres.removeListener(l);
    }

    @Override
    public void load(File f) {
        if (f.exists()) {
            try {
                SAXBuilder saxBuilder = new SAXBuilder();
                Document dom = saxBuilder.build(f);
                try {
                    log.info("Reading workflow state from {}.", f);
                    readXML(dom.getRootElement());
                } catch (ClassNotFoundException ex) {
                    Logger.getLogger(DefaultWorkflow.class.getName()).log(Level.SEVERE, null, ex);
                }
            } catch (JDOMException | IOException ex) {
                Logger.getLogger(DefaultWorkflow.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            log.info("No workflow.xml from previous invocation found!");
        }
    }

    @Override
    public void save() {
        try {
            final String wflname = getName();
            log.info("Saving workflow {}", wflname);
            final Document doc = new Document();
            final ProcessingInstruction pi = new ProcessingInstruction("xml-stylesheet",
                    "type=\"text/xsl\" href=\"http://maltcms.sourceforge.net/res/maltcmsHTMLResult.xsl\"");
            doc.addContent(pi);
            doc.addContent(writeXML());
            final XMLOutputter outp = new XMLOutputter(Format.getPrettyFormat());
            try {
                final File f = new File(getOutputDirectory(), getName() + ".xml");//new File(wflname);
                final File dir = f.getParentFile();
                dir.mkdirs();
                f.createNewFile();
                outp.output(doc, new BufferedOutputStream(new FileOutputStream(f)));
                if (this.saveHTML) {
                    saveHTML(f);
                }
                if (this.saveTEXT) {
                    saveTEXT(f);
                }
            } catch (final IOException e) {
                log.error(e.getLocalizedMessage());
            }
        } catch (final FileNotFoundException e) {
            log.error(e.getLocalizedMessage());
        } catch (final IOException e) {
            log.error(e.getLocalizedMessage());
        }
    }

    /**
     * Applies a stylesheet transformation to this DefaultWorkflow to create
     * html with clickable links.
     *
     * @param f
     */
    protected void saveHTML(final File f) {

        final TransformerFactory tf = TransformerFactory.newInstance();
        try {
            final InputStream xsstyler = getClass().getClassLoader()
                    .getResourceAsStream("res/xslt/maltcmsHTMLResult.xsl");
            final StreamSource sstyles = new StreamSource(xsstyler);
            final FileInputStream xsr = new FileInputStream(f);
            final FileOutputStream xsw = new FileOutputStream(new File(f.getParentFile(), "workflow.html"));
            final StreamSource sts = new StreamSource(xsr);
            final StreamResult str = new StreamResult(xsw);
            final Transformer t = tf.newTransformer(sstyles);
            t.transform(sts, str);
        } catch (final TransformerConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (final FileNotFoundException | TransformerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    /**
     * Applies a stylesheet transformation to this DefaultWorkflow to create
     * text.
     *
     * @param f
     */
    protected void saveTEXT(final File f) {

        final TransformerFactory tf = TransformerFactory.newInstance();
        try {
            final InputStream xsstyler = getClass().getClassLoader()
                    .getResourceAsStream("res/xslt/maltcmsTEXTResult.xsl");
            final StreamSource sstyles = new StreamSource(xsstyler);
            final FileInputStream xsr = new FileInputStream(f);
            final FileOutputStream xsw = new FileOutputStream(new File(f.getParentFile(), "workflow.txt"));
            final StreamSource sts = new StreamSource(xsr);
            final StreamResult str = new StreamResult(xsw);
            final Transformer t = tf.newTransformer(sstyles);
            t.transform(sts, str);
        } catch (final TransformerConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (final FileNotFoundException | TransformerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    /**
     */
    @Override
    public void setCommandSequence(final ICommandSequence ics) {
        this.commandSequence = ics;
        this.commandSequence.setWorkflow(this);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * cross.datastructures.workflow.IWorkflow#setConfiguration(org.apache.commons
     * .configuration.Configuration)
     */
    @Override
    public void setConfiguration(final Configuration configuration) {
        this.cfg = configuration;

    }

    /**
     * @param iwres the EventSource<IWorkflowResult> to set
     */
    public void setEventSource(final IEventSource<IWorkflowResult> iwres) {
        this.iwres = iwres;
    }

    /**
     * @param fileFilter the fileFilter to set
     */
    public void setFileFilter(final String fileFilter) {
        this.fileFilter = fileFilter;
    }

    @Override
    public void setName(final String name1) {
        this.name = name1;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * cross.datastructures.workflow.IWorkflow#setStartupDate(java.util.Date)
     */
    @Override
    public void setStartupDate(final Date date1) {
        this.date = date1;
    }

    /**
     * @param xslPathPrefix the xslPathPrefix to set
     */
    public void setXslPathPrefix(final String xslPathPrefix) {
        this.xslPathPrefix = xslPathPrefix;
    }

    @Override
    public Element writeXML() throws IOException {
        final Element root = new Element("workflow");
        root.setAttribute("class", getClass().getCanonicalName());
        root.setAttribute("name", getName());
        appendXML(root);
        return root;
    }

    /*
     * (non-Javadoc)
     *
     * @seecross.datastructures.workflow.IWorkflow#getOutputDirectory(java.lang.
     * Object)
     */
    @Override
    public File getOutputDirectory(Object iwe) {
        if (iwe instanceof AFragmentCommand) {
            Collection<IFragmentCommand> c = this.commandSequence.getCommands();
            int i = 0;
            int digits = (int) Math.ceil(Math.log10(c.size())) + 1;
            for (IFragmentCommand afc : c) {
                IFragmentCommand iwa = (IFragmentCommand) iwe;
                log.debug("Checking for reference equality!");
                // check for reference equality
                if (iwa == afc) {
                    log.debug("Reference equality holds!");
                    if (activeCommand == null) {
                        activeCommand = iwa;
                    }
                    if (activeCommand != iwa) {
                        activeCommand = iwa;
                    }
                    File outputFile = new File(outputDirectory,
                            String.format("%0" + digits + "d", i) + "_" + iwa.getClass().getSimpleName());
                    outputFile.mkdirs();
                    log.info("Output dir for object of type {}: {}", iwe.getClass().getSimpleName(),
                            this.outputDirectory);
                    return outputFile;
                }
                i++;
            }
            if (activeCommand != null) {
                File dir = new File(getOutputDirectory(activeCommand), iwe.getClass().getSimpleName());
                if (!dir.exists()) {
                    dir.mkdirs();
                }
                log.info("Output dir for object of type {}: {}", iwe.getClass().getSimpleName(),
                        this.outputDirectory);
                return dir;
            }
        } else if (iwe instanceof IWorkflowElement) {
            if (activeCommand != null) {
                File dir = new File(getOutputDirectory(activeCommand), iwe.getClass().getSimpleName());
                if (!dir.exists()) {
                    dir.mkdirs();
                }
                log.info("Output dir for object of type {}: {}", iwe.getClass().getSimpleName(),
                        this.outputDirectory);
                return dir;
            }
        }

        File outputFile = new File(outputDirectory, iwe.getClass().getSimpleName());
        outputFile.mkdirs();
        log.info("Output dir for object of type {}: {}", iwe.getClass().getSimpleName(), this.outputDirectory);
        return outputFile;
    }

    @Override
    public File getWorkflowXmlFile() {
        File f = new File(getOutputDirectory(), getName() + ".xml");
        return f;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * cross.datastructures.workflow.IWorkflow#getResultsFor(cross.datastructures
     * .fragments.IFileFragment)
     */
    @Override
    public List<IWorkflowResult> getResultsFor(IFileFragment iff) {
        List<IWorkflowResult> l = new ArrayList<>();
        Iterator<IWorkflowResult> iter = getResults();
        while (iter.hasNext()) {
            IWorkflowResult iwr = iter.next();
            if (iwr instanceof IWorkflowFileResult) {
                IWorkflowFileResult iwfr = (IWorkflowFileResult) iwr;
                IFileFragment[] res = iwfr.getResources();
                for (IFileFragment resf : res) {
                    if (StringTools.removeFileExt(resf.getName())
                            .equals(StringTools.removeFileExt(iff.getName()))) {
                        l.add(iwfr);
                    }
                }
            }
        }
        return l;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * cross.datastructures.workflow.IWorkflow#getResultsFor(cross.commands.
     * fragments.IWorkflowElement)
     */
    @Override
    public List<IWorkflowResult> getResultsFor(IWorkflowElement afc) {
        List<IWorkflowResult> l = new ArrayList<>();
        Iterator<IWorkflowResult> iter = getResults();
        while (iter.hasNext()) {
            IWorkflowResult iwr = iter.next();
            IWorkflowElement iwe = iwr.getWorkflowElement();
            if (iwe.getClass().getName().equals(afc.getClass().getName())) {
                l.add(iwr);
            }
        }
        return l;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * cross.datastructures.workflow.IWorkflow#getResultsFor(cross.commands.
     * fragments.IWorkflowElement, cross.datastructures.fragments.IFileFragment)
     */
    @Override
    public List<IWorkflowResult> getResultsFor(IWorkflowElement afc, IFileFragment iff) {
        List<IWorkflowResult> afcl = getResultsFor(afc);
        List<IWorkflowResult> l = new ArrayList<>();
        for (IWorkflowResult iwr : afcl) {
            if (iwr instanceof IWorkflowFileResult) {
                IWorkflowFileResult iwfr = (IWorkflowFileResult) iwr;
                IFileFragment[] res = iwfr.getResources();
                for (IFileFragment resf : res) {
                    if (StringTools.removeFileExt(resf.getName())
                            .equals(StringTools.removeFileExt(iff.getName()))) {
                        l.add(iwfr);
                    }
                }
            }
        }
        return l;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * cross.datastructures.workflow.IWorkflow#getResultsOfType(java.lang.String
     * )
     */
    @Override
    public List<IWorkflowResult> getResultsOfType(String fileExtension) {
        List<IWorkflowResult> l = new ArrayList<>();
        Iterator<IWorkflowResult> iter = getResults();
        while (iter.hasNext()) {
            IWorkflowResult iwr = iter.next();
            if (iwr instanceof IWorkflowFileResult) {
                IWorkflowFileResult iwfr = (IWorkflowFileResult) iwr;
                if (iwfr.getFile().getAbsolutePath().endsWith(fileExtension)) {
                    l.add(iwr);
                }
            }
        }
        return l;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * cross.datastructures.workflow.IWorkflow#getResultsOfType(cross.datastructures
     * .workflow.IWorkflowElement, java.lang.String)
     */
    @Override
    public List<IWorkflowResult> getResultsOfType(IWorkflowElement afc, String fileExtension) {
        List<IWorkflowResult> l = new ArrayList<>();
        Iterator<IWorkflowResult> iter = getResults();
        while (iter.hasNext()) {
            IWorkflowResult iwr = iter.next();
            if (iwr instanceof IWorkflowFileResult) {
                IWorkflowFileResult iwfr = (IWorkflowFileResult) iwr;
                if (iwfr.getWorkflowElement().getClass().getCanonicalName()
                        .equals(afc.getClass().getCanonicalName())) {
                    if (iwfr.getFile().getAbsolutePath().endsWith(fileExtension)) {
                        l.add(iwr);
                    }
                }
            }
        }
        return l;
    }

    @Override
    public <T> List<IWorkflowObjectResult> getResultsOfType(IWorkflowElement afc, Class<? extends T> c) {
        List<IWorkflowObjectResult> l = new ArrayList<>();
        Iterator<IWorkflowResult> iter = getResults();
        while (iter.hasNext()) {
            IWorkflowResult iwr = iter.next();
            if (iwr instanceof IWorkflowObjectResult) {
                IWorkflowObjectResult iwfr = (IWorkflowObjectResult) iwr;
                if (iwfr.getWorkflowElement().getClass().getCanonicalName()
                        .equals(afc.getClass().getCanonicalName())) {
                    if (c.isAssignableFrom(iwfr.getObject().getClass())) {
                        l.add((IWorkflowObjectResult) iwr);
                    }
                }
            }
        }
        return l;
    }

    @Override
    public boolean isExecuteLocal() {
        return executeLocal;
    }

    @Override
    public void setExecuteLocal(boolean executeLocal) {
        this.executeLocal = executeLocal;
    }

    @Override
    public TupleND<IFileFragment> call() throws Exception {
        TupleND<IFileFragment> results = null;
        if (commandSequence.isCheckCommandDependencies() && !commandSequence.validate()) {
            throw new ConstraintViolationException("Pipeline validation failed! Check output for details!");
        }
        try {
            commandSequence.before();
            while (commandSequence.hasNext()) {
                results = commandSequence.next();
            }
        } finally {
            //ensure that any resources are cleaned up
            commandSequence.after();
            // Save configuration
            getFactory().dumpConfig("runtime.properties", getStartupDate());
        }
        //only run workflow post processors if we have not experienced any exceptions
        for (IWorkflowPostProcessor pp : workflowPostProcessors) {
            log.info("Running workflowPostProcessor {}", pp.getClass().getName());
            pp.process(this);
        }
        return results;
    }

    @Override
    public File getOutputDirectory() {
        return outputDirectory;
    }

    @Override
    public void setOutputDirectory(File f) {
        this.outputDirectory = f;
        log.info("Workflow output base directory: " + this.outputDirectory);
    }

    @Override
    public List<IWorkflowPostProcessor> getWorkflowPostProcessors() {
        return workflowPostProcessors;
    }

    @Override
    public void setWorkflowPostProcessors(List<IWorkflowPostProcessor> workflowPostProcessors) {
        this.workflowPostProcessors = workflowPostProcessors;
    }

    @Override
    public IFactory getFactory() {
        return factory;
    }

    @Override
    public void setFactory(IFactory factory) {
        if (this.factory != null) {
            throw new IllegalStateException("Factory was already initialized!");
        }
        this.factory = factory;
    }

    @Override
    public void clearResults() {
        this.al.clear();
    }
}