Switch to side-by-side view

--- a
+++ b/src/main/java/net/timbusproject/extractors/modules/tavernaextractor/TavernaExtractor.java
@@ -0,0 +1,2209 @@
+/**
+ * Copyright (c) 2013/2014 Verein zur Foerderung der IT-Sicherheit in Oesterreich (SBA).
+ * The work has been developed in the TIMBUS Project and the above-mentioned are Members of the TIMBUS Consortium.
+ * TIMBUS is supported by the European Union under the 7th Framework Programme for research and technological
+ * development and demonstration activities (FP7/2007-2013) under grant agreement no. 269940.
+ *
+ * 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, including without
+ * limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTIBITLY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise,
+ * unless required by applicable law or agreed to in writing, shall any Contributor be liable for damages, including
+ * any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this
+ * License or out of the use or inability to use the Work.
+ * See the License for the specific language governing permissions and limitation under the License.
+ */
+
+package net.timbusproject.extractors.modules.tavernaextractor;
+
+import edu.uci.ics.jung.algorithms.layout.AbstractLayout;
+import edu.uci.ics.jung.algorithms.layout.ISOMLayout;
+import edu.uci.ics.jung.algorithms.layout.Layout;
+import edu.uci.ics.jung.graph.Graph;
+import edu.uci.ics.jung.graph.SparseGraph;
+import net.sf.taverna.t2.activities.beanshell.BeanshellActivity;
+import net.sf.taverna.t2.activities.beanshell.BeanshellActivityConfigurationBean;
+import net.sf.taverna.t2.activities.dataflow.DataflowActivity;
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivity;
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivityConfigurationBean;
+import net.sf.taverna.t2.activities.rest.RESTActivity;
+import net.sf.taverna.t2.activities.rshell.RshellActivity;
+import net.sf.taverna.t2.activities.rshell.RshellActivityConfigurationBean;
+import net.sf.taverna.t2.activities.wsdl.WSDLActivity;
+import net.sf.taverna.t2.commandline.CommandLineLauncher;
+import net.sf.taverna.t2.commandline.exceptions.DatabaseConfigurationException;
+import net.sf.taverna.t2.commandline.exceptions.InvalidOptionException;
+import net.sf.taverna.t2.commandline.exceptions.OpenDataflowException;
+import net.sf.taverna.t2.commandline.exceptions.ReadInputException;
+import net.sf.taverna.t2.invocation.TokenOrderException;
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.workbench.models.graph.DotWriter;
+import net.sf.taverna.t2.workbench.models.graph.Graph.Alignment;
+import net.sf.taverna.t2.workbench.models.graph.GraphController.PortStyle;
+import net.sf.taverna.t2.workbench.models.graph.svg.SVGGraphController;
+import net.sf.taverna.t2.workflowmodel.*;
+import net.sf.taverna.t2.workflowmodel.impl.ProcessorInputPortImpl;
+import net.sf.taverna.t2.workflowmodel.processor.activity.Activity;
+import net.sf.taverna.t2.workflowmodel.processor.activity.DisabledActivity;
+import net.sf.taverna.t2.workflowmodel.processor.activity.UnrecognizedActivity;
+import net.sf.taverna.t2.workflowmodel.processor.iteration.IterationTypeMismatchException;
+import net.sf.taverna.t2.workflowmodel.serialization.DeserializationException;
+import net.timbusproject.extractors.core.Endpoint;
+import net.timbusproject.extractors.core.IExtractor;
+import net.timbusproject.extractors.core.OperatingSystem;
+import net.timbusproject.extractors.core.Parameter;
+import net.timbusproject.extractors.modules.tavernaextractor.utils.ArchiLayoutUtils;
+import net.timbusproject.extractors.modules.tavernaextractor.utils.ArchiUtils;
+import net.timbusproject.extractors.modules.tavernaextractor.utils.Container;
+import net.timbusproject.extractors.modules.tavernaextractor.utils.Container.Orientation;
+import org.apache.batik.swing.JSVGCanvas;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.DocumentHelper;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.osgi.framework.Version;
+import org.sbaresearch.licensecheck.LicenseCheck;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+import uk.ac.bolton.archimate.editor.model.viewpoints.IViewpoint;
+import uk.ac.bolton.archimate.model.*;
+import uk.ac.bolton.archimate.model.impl.BusinessEvent;
+import uk.ac.bolton.archimate.model.util.ArchimateResourceFactory;
+
+import static java.nio.file.FileVisitResult.*;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.*;
+import java.awt.*;
+import java.io.*;
+import java.net.URL;
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.*;
+import java.util.List;
+import java.util.Map.Entry;
+
+/**
+ * @author Rudolf Mayer (rmayer@sba-research.org)
+ * @author Marco Unterberger (munterberger@sba-research.org)
+ */
+public class TavernaExtractor extends CommandLineLauncher implements IExtractor {
+
+    private IArchimateFactory factory;
+    private Map<String, IDiagramModelArchimateObject> elementModelObjectMap;
+    private List<IRelationship> relations;
+    private IArchimateDiagramModel layeredView;
+    private Graph<IArchimateElement, IArchimateElement> graph;
+    private Layout<IArchimateElement, IArchimateElement> layout;
+    private int overall_X, overall_Y = 0;
+    private final int MIN_ELEMENTS_FOR_GROUPING = 3;
+    private Map<Processor, List<IBusinessObject>> processorObjectMapping = new HashMap<Processor, List<IBusinessObject>>();
+    private Map<IBusinessObject, IDataObject> business2dataMap = new HashMap<IBusinessObject, IDataObject>();
+    private Map<Processor, IOrJunction> loopsJunctions = new HashMap<Processor, IOrJunction>();
+    private HashMap<Processor, IBusinessProcess> processorProcessMap = new HashMap<Processor, IBusinessProcess>();
+    private List<BeanshellActivity> beanshellScripts = new ArrayList<BeanshellActivity>();
+    private Map<Processor, IAndJunction> processorInputMap = new HashMap<Processor, IAndJunction>();
+    private HashMap<Processor, IBusinessObject> processorValueMap = null;
+    private INode desktop;
+    private IDiagramModelArchimateObject diagramModelDesktop;
+    private IBusinessProcess parentProcessWorkflow;
+    private IBusinessEvent startEvent;
+    private IAndJunction andJunctionStart;
+    private IBusinessEvent endEvent;
+    private IAndJunction andJunctionEnd;
+
+    /*
+     * // Groups //////////////
+     */
+    private IDiagramModelGroup businessProcessModelGroup;
+    private IDiagramModelGroup externalApplicationModelGroup;
+    private IDiagramModelGroup applicationComponentModelGroup;
+    private IDiagramModelGroup externalInfrastructureModelGroup;
+    private IDiagramModelGroup infrastructureModelGroup;
+    private IDiagramModelGroup externalProviderModelGroup;
+    private IDiagramModelGroup processStepsModelGroup;
+
+    /*
+     * // Containers //////////////
+     */
+    private Container inputPorts;
+    private Container outputPorts;
+    private Container valueObjects = new Container(Orientation.VERTICAL);
+    private Container businessObjects;
+    private Container businessProcesses;
+    private Container infrastructureServices;
+    private Container externalApplicationServices;
+    private Container applicationComponents;
+    private Container infrastructure;
+    private Container externalProviders;
+    private Container dataObjects;
+
+    /*
+     * // Folders //////////////
+     */
+    private IFolder businessFolder;
+    private IFolder diagramFolder;
+    private IFolder infrastructureFolder;
+    private IFolder motivationFolder;
+    private IFolder applicationFolder;
+    private IFolder relationsFolder;
+
+
+    /*
+     * // PROPERTIES & ARGUMENTS //////////////
+     */
+    private static String archimateOutputPath;
+    private static String inputFileName;
+    private static String dotLocation;
+    private static Path tavernaHome;
+    private static Path tavernaHomeLib;
+    private static Path tavernaHomeRepo;
+
+    private List<IArchimateElement> nodeElements;
+    private static Logger LOGGER = LogManager.getLogger("TavernaExtractor");
+    private LicenseCheck licenseCheck = new LicenseCheck();
+    private IArtifact workflowFile;
+    private IArtifact taverna;
+    private IApplicationComponent workflowApplicationComponent = null;
+    private IApplicationFunction callScriptApplicationFunction = null;
+    private IApplicationFunction callWebServiceApplicationFunction = null;
+    private IApplicationFunction callToolInvocationFunction = null;
+
+    private Dataflow dataflow;
+
+    public TavernaExtractor(boolean verbose) {
+
+        if (verbose) {
+            LOGGER.setLevel(Level.DEBUG);
+        } else {
+            LOGGER.setLevel(Level.INFO);
+        }
+    }
+
+    /*
+     * // GETTER & SETTER ///////////////
+     */
+    public static void setDotLocation(String dotLocation) {
+        TavernaExtractor.dotLocation = dotLocation;
+    }
+
+    public static String getDotLocation() {
+        return dotLocation;
+    }
+
+    public static String getArchimateOutputPath() {
+        return archimateOutputPath;
+    }
+
+    public static void setArchimateOutputPath(String archimateOutputPath) {
+        TavernaExtractor.archimateOutputPath = archimateOutputPath;
+    }
+
+    public static String getInputFileName() {
+        return inputFileName;
+    }
+
+    public static void setInputFileName(String inputFileName) {
+        TavernaExtractor.inputFileName = inputFileName;
+    }
+
+    public static Path getTavernaHome() {
+        return tavernaHome;
+    }
+
+    public static void setTavernaHome(Path tavernaHome) {
+
+        TavernaExtractor.tavernaHome = tavernaHome;
+    }
+
+    public static Path getTavernaHomeLib() {
+        return tavernaHomeLib;
+    }
+
+    public static void setTavernaHomeLib(Path tavernaHomeLib) {
+        TavernaExtractor.tavernaHomeLib = tavernaHomeLib;
+    }
+
+    public static Path getTavernaHomeRepo() {
+        return tavernaHomeRepo;
+    }
+
+    public static void setTavernaHomeRepo(Path tavernaHomeRepo) {
+        TavernaExtractor.tavernaHomeRepo = tavernaHomeRepo;
+    }
+
+
+    public List<IRelationship> getRelations() {
+        return this.relations;
+    }
+
+    public List<IArchimateElement> getBusinessProcesses() {
+        return this.businessProcesses.getElements();
+    }
+
+    public List<IArchimateElement> getBusinessObjects() {
+        return this.businessObjects.getElements();
+    }
+
+    /*
+     * // Transform a Taverna (t2flow) file to an Archimate file ///////////////
+     */
+    public void process() throws EditException, OpenDataflowException, InvalidOptionException,
+            InvalidDataflowException, TokenOrderException, ReadInputException, DatabaseConfigurationException,
+            CMException, IOException, DeserializationException, IterationTypeMismatchException {
+
+        LOGGER.info("Start Taverna Extractor ...");
+
+        //setup
+        TavernaExtractor.setTavernaHomeLib(TavernaExtractor.getTavernaHome().resolve("lib"));
+        TavernaExtractor.setTavernaHomeRepo(TavernaExtractor.getTavernaHome().resolve("repository"));
+
+        validateDirectories(TavernaExtractor.getTavernaHome(), TavernaExtractor.getTavernaHomeLib(), TavernaExtractor.getTavernaHomeRepo());
+
+        LOGGER.info("TavernaHome is set to [" + TavernaExtractor.getTavernaHome() + "].");
+        LOGGER.info("TavernaHomeLib is set to [" + TavernaExtractor.getTavernaHomeLib() + "].");
+        LOGGER.info("TavernaHomeRepo is set to [" + TavernaExtractor.getTavernaHomeRepo() + "].");
+        LOGGER.info("Worflow input file is [" + TavernaExtractor.getInputFileName() + "].");
+        LOGGER.info("Archimate output file is [" + TavernaExtractor.getArchimateOutputPath() + "].");
+
+        inputPorts = new Container(Orientation.VERTICAL);
+        outputPorts = new Container(Orientation.VERTICAL);
+        businessObjects = new Container(Orientation.HORIZONTAL);
+        businessProcesses = new Container(Orientation.HORIZONTAL);
+        externalApplicationServices = new Container(Orientation.HORIZONTAL);
+        infrastructure = new Container(Orientation.HORIZONTAL);
+        infrastructureServices = new Container(Orientation.HORIZONTAL);
+        applicationComponents = new Container(Orientation.HORIZONTAL);
+        externalProviders = new Container(Orientation.HORIZONTAL);
+        dataObjects = new Container(Orientation.HORIZONTAL);
+
+        // project configured JRE!
+        final String JAVA_VERSION = System.getProperty("java.version");
+        final String JAVA_VENDOR = System.getProperty("java.vendor");
+
+        final String OS_SYSTEM_INFO = System.getProperty("os.name") + " [version=" + System.getProperty("os.version")
+                + "] [arch=" + System.getProperty("os.arch") + "]";
+
+        nodeElements = new ArrayList<IArchimateElement>();
+        elementModelObjectMap = new HashMap<String, IDiagramModelArchimateObject>();
+        relations = new ArrayList<IRelationship>();
+
+        try {
+            // try to load from classpath
+            URL workflowURL = getClass().getResource(inputFileName);
+
+            if (workflowURL == null) { // if not successful, try opening file
+
+                File f = new File(inputFileName);
+                if (f.exists()) {
+                    workflowURL = f.toURI().toURL();
+                }
+            }
+
+            LOGGER.info("Reading workflow from " + workflowURL);
+            dataflow = openDataflow(workflowURL);
+        } catch (NullPointerException npe) {
+            npe.printStackTrace();
+            LOGGER.error("ERROR reading workflow from [" + inputFileName + "]." + npe.getMessage());
+            return;
+        }
+
+        // current classpath
+        String classpath = System.getProperty("java.class.path");
+        String[] classpathEntries = classpath.split(File.pathSeparator);
+        List<String> cleanClasspathEntries = cleanedClasspath(Arrays.asList(classpathEntries));
+
+        factory = IArchimateFactory.eINSTANCE;
+
+        IArchimateModel model = factory.createArchimateModel();
+        model.setDefaults();
+        model.setName("Converted Taverna Workflow " + inputFileName);
+
+        // FOLDERS
+        businessFolder = model.getFolder(FolderType.BUSINESS);
+        diagramFolder = model.getFolder(FolderType.DIAGRAMS);
+        infrastructureFolder = model.getFolder(FolderType.TECHNOLOGY);
+        motivationFolder = model.getFolder(FolderType.MOTIVATION);
+        applicationFolder = model.getFolder(FolderType.APPLICATION);
+        relationsFolder = model.getFolder(FolderType.RELATIONS);
+
+        // LAYERED VIEWS
+        layeredView = factory.createArchimateDiagramModel();
+        layeredView.setName("Layered View");
+        layeredView.setViewpoint(IViewpoint.LAYERED_VIEWPOINT);
+        diagramFolder.getElements().add(layeredView);
+
+        // GROUPINGS
+        businessProcessModelGroup = ArchiLayoutUtils.createSubModelGroup(layeredView, "Business process");
+        externalApplicationModelGroup = ArchiLayoutUtils.createSubModelGroup(layeredView,
+                "External Application Services");
+        applicationComponentModelGroup = ArchiLayoutUtils.createSubModelGroup(layeredView,
+                "Application Component + Services");
+        externalInfrastructureModelGroup = ArchiLayoutUtils.createSubModelGroup(layeredView,
+                "External Infrastructure Services");
+        infrastructureModelGroup = ArchiLayoutUtils.createSubModelGroup(layeredView, "Infrastructure");
+
+        // --- CREATING DEFAULT ELEMENTS ---
+        desktop = factory.createNode();
+        desktop.setName("Desktop Computer");
+        infrastructureFolder.getElements().add(desktop);
+
+        diagramModelDesktop = factory.createDiagramModelArchimateObject();
+        diagramModelDesktop.setArchimateElement(desktop);
+        diagramModelDesktop.setBounds(15, 15, 0, 0);
+
+        infrastructure.getElements().add(desktop);
+
+        // // BEGIN PATTERN v2.0 UPDATE
+        // --- BEGIN Taverna ---
+        taverna = (IArtifact) ArchiUtils.initElement(factory.createArtifact(), "Taverna 2.4", infrastructureFolder,
+                nodeElements);
+        IConstraint GNULicense = ArchiUtils.initElement(factory.createConstraint(),
+                "GNU Lesser General Public License (LGPL) 2.1", motivationFolder, infrastructure);
+        ArchiUtils.initRelation(factory.createRealisationRelationship(), taverna, GNULicense, relationsFolder,
+                relations);
+
+        // Workflow file
+        workflowFile = (IArtifact) ArchiUtils.initElement(factory.createArtifact(), "Worfklow File",
+                infrastructureFolder, nodeElements);
+        ArchiUtils.initRelation(factory.createAssociationRelationship(), workflowFile, taverna, relationsFolder,
+                relations);
+
+        // Orchestration Service
+        parentProcessWorkflow = ArchiUtils.initElement(factory.createBusinessProcess(), dataflow.getLocalName()
+                + " Process", businessFolder, businessProcesses);
+        workflowApplicationComponent = ArchiUtils.initElement(factory.createApplicationComponent(),
+                "Workflow Execution Environment", applicationFolder, applicationComponents);
+
+        ArchiUtils.initRelation(factory.createRealisationRelationship(), taverna, workflowApplicationComponent,
+                relationsFolder, relations);
+
+        // add dependable Taverna jars from classpath
+        for(String jar : cleanClasspathEntries) {
+            taverna.getProperties().add(createDepProperties(jar));
+        }
+
+        // link relevant dependencies from taverna home to context model
+        IArtifact repoBundle = (IArtifact) ArchiUtils.initElement(factory.createArtifact(), "Repo Bundle", infrastructureFolder, nodeElements);
+        ArchiUtils.initRelation(factory.createAssociationRelationship(), taverna, repoBundle,
+                relationsFolder, relations);
+
+        if(TavernaExtractor.getTavernaHomeRepo().toFile().isDirectory()){
+
+            final List<File> jarFiles = new ArrayList<>();
+            final PathMatcher matcher = FileSystems.getDefault()
+                    .getPathMatcher("glob:*.jar");
+            Files.walkFileTree(TavernaExtractor.getTavernaHomeRepo(), new FileVisitor<Path>() {
+                @Override
+                public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes basicFileAttributes) throws IOException {
+                    return CONTINUE;
+                }
+
+                @Override
+                public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes) throws IOException {
+
+                   if (path != null && matcher.matches(path.getFileName())) {
+                        jarFiles.add(path.toFile());
+                   }
+                   return CONTINUE;
+                }
+
+                @Override
+                public FileVisitResult visitFileFailed(Path path, IOException e) throws IOException {
+                    return CONTINUE;
+                }
+
+                @Override
+                public FileVisitResult postVisitDirectory(Path path, IOException e) throws IOException {
+                    return CONTINUE;
+                }
+            });
+
+            for(File jarDep : jarFiles){
+                String jarLocation = jarDep.getAbsolutePath();
+                repoBundle.getProperties().add(createDepProperties(jarLocation));
+            }
+         }
+        else{
+            LOGGER.error("ERROR: "+TavernaExtractor.getTavernaHomeRepo().toFile()+" is not a directory. No further dependecies processing.");
+        }
+        // --- END Taverna ---
+
+        // --- BEGIN Events ---
+        // Start Event
+        startEvent = ArchiUtils.initElement(factory.createBusinessEvent(), "Start Experiment", businessFolder,
+                businessProcesses);
+
+        // End Event
+        endEvent = ArchiUtils.initElement(factory.createBusinessEvent(), "Experiment End", businessFolder,
+                businessProcesses);
+        // --- END Events ---
+
+        // --- BEGIN Java Runtime Environment ---
+        ISystemSoftware java = (ISystemSoftware) ArchiUtils.initElement(factory.createSystemSoftware(), "JRE "
+                + JAVA_VERSION + " (" + JAVA_VENDOR + ")", infrastructureFolder, nodeElements);
+        // FIXME: this must not always be an ORACLE license
+        IConstraint oracleLicense = ArchiUtils.initElement(factory.createConstraint(), "Oracle Binary Code License",
+                motivationFolder, infrastructure);
+        ArchiUtils.initRelation(factory.createRealisationRelationship(), java, oracleLicense, relationsFolder,
+                relations);
+        ArchiUtils.initRelation(factory.createUsedByRelationship(), java, taverna, relationsFolder, relations);
+
+        // --- BEGIN OS ---
+        ISystemSoftware operatingSystem = (ISystemSoftware) ArchiUtils.initElement(factory.createSystemSoftware(),
+                OS_SYSTEM_INFO, infrastructureFolder, nodeElements);
+        ArchiUtils.initRelationNodeElement(factory.createUsedByRelationship(), operatingSystem, java, relationsFolder,
+                nodeElements);
+        // --- END CREATING DEFAULT ELEMENTS ---
+
+        LOGGER.debug("Process Input ports");
+        for (DataflowInputPort inputPort : dataflow.getInputPorts()) {
+            IBusinessObject port_business = ArchiUtils.initElement(factory.createBusinessObject(), inputPort.getName(),
+                    businessFolder, inputPorts);
+            IDataObject port_data = ArchiUtils.initElement(factory.createDataObject(), inputPort.getName(),
+                    applicationFolder, dataObjects);
+            IArchimateElement port_infrastructure = ArchiUtils.initElement(factory.createArtifact(),
+                    inputPort.getName(), infrastructureFolder, infrastructure);
+
+            business2dataMap.put(port_business, port_data);
+
+            ArchiUtils.initRelation(factory.createRealisationRelationship(), port_data, port_business, relationsFolder,
+                    relations);
+            ArchiUtils.initRelation(factory.createRealisationRelationship(), port_infrastructure, port_data,
+                    relationsFolder, relations);
+        }
+        LOGGER.debug("Process Output ports");
+        for (DataflowOutputPort outputPort : dataflow.getOutputPorts()) {
+            IBusinessObject port_business = ArchiUtils.initElement(factory.createBusinessObject(),
+                    outputPort.getName(), businessFolder, outputPorts);
+            IDataObject port_data = ArchiUtils.initElement(factory.createDataObject(), outputPort.getName(),
+                    applicationFolder, dataObjects);
+            IArchimateElement port_infrastructure = ArchiUtils.initElement(factory.createArtifact(),
+                    outputPort.getName(), infrastructureFolder, infrastructure);
+
+            business2dataMap.put(port_business, port_data);
+
+            ArchiUtils.initRelation(factory.createRealisationRelationship(), port_data, port_business, relationsFolder,
+                    relations);
+            ArchiUtils.initRelation(factory.createRealisationRelationship(), port_infrastructure, port_data,
+                    relationsFolder, relations);
+        }
+
+        processorProcessMap = new HashMap<Processor, IBusinessProcess>();
+        processorValueMap = new HashMap<Processor, IBusinessObject>();
+
+        //
+        // first pass - get all Processors, and map them to IBusinessProcess, create business objects
+        //
+        treatProcessors(dataflow.getProcessors());
+
+        //
+        // (extend second pass) - redirect relations in case of multiple incoming ports
+        //
+        for (Entry<Processor, IAndJunction> entry : processorInputMap.entrySet()) {
+
+            Processor targetProcessor = entry.getKey();
+            IAndJunction andJunction = entry.getValue();
+
+            IBusinessProcess targetProcess = processorProcessMap.get(targetProcessor);
+
+            // detect incoming triggering relations
+            List<IRelationship> incomingTriggeringRelations = ArchiUtils.ofClass(relations,
+                    ITriggeringRelationship.class, targetProcess, false);
+
+            List<IArchimateElement> sourceElements = ArchiUtils.getSourceElements(incomingTriggeringRelations);
+
+            // remove the original incoming relations
+            ArchiUtils.removeRelation(incomingTriggeringRelations, relations, relationsFolder);
+
+            // reconnect relations to AND junction
+            for (IArchimateElement sourceElement : sourceElements) {
+
+                ArchiUtils.initRelation(factory.createTriggeringRelationship(), sourceElement, andJunction,
+                        relationsFolder, relations);
+            }
+
+            // create new relation
+            ArchiUtils.initRelation(factory.createTriggeringRelationship(), andJunction, targetProcess,
+                    relationsFolder, relations);
+        }
+
+        //
+        // third pass - detail process steps on other layers
+        //
+        detailProcessorsOnLayers(dataflow.getProcessors());
+
+        // drawing archimate elements and relations
+        drawBusinessProcessGroup();
+        drawExternalApplicationServices();
+        drawApplicationComponentServices();
+        drawExternalInfrastructureServices();
+        drawInfrastructure();
+        drawExternalProviders();
+        drawRelations();
+
+        // set size of main process diagram element to hold all others
+        int padding = 5;
+        IBounds outerBounds = processStepsModelGroup.getBounds();
+        processStepsModelGroup.setBounds(outerBounds.getX() - padding / 2, outerBounds.getY(), outerBounds.getWidth()
+                + padding, outerBounds.getHeight() + 10);
+        IDiagramModelArchimateObject processDiagramObject = elementModelObjectMap.get(parentProcessWorkflow.getId());
+        processDiagramObject.setBounds(padding, padding, outerBounds.getWidth() - padding * 2, outerBounds.getHeight()
+                - padding * 2);
+
+        // Set new file
+        File outFile = new File(TavernaExtractor.getArchimateOutputPath());
+        model.setFile(outFile);
+
+        // Set model version
+        model.setVersion(ModelVersion.VERSION);
+
+        // Adapted from {@link ArchiveManager#saveModelToXMLFile}
+        ResourceSet resourceSet = ArchimateResourceFactory.createResourceSet();
+        Resource resource = resourceSet.createResource(URI.createFileURI(outFile.getAbsolutePath()));
+        resource.getContents().add(model);
+        resource.save(null);
+
+        LOGGER.info("Wrote model successfully to " + outFile.getAbsolutePath());
+    }
+
+    public void processWebServiceActivity(IFolder businessFolder, IFolder infrastructureFolder,
+                                          IFolder applicationFolder, IFolder relationsFolder, IApplicationComponent workflowApplicationComponent,
+                                          HashMap<Processor, IBusinessProcess> processorProcessMap,
+                                          IApplicationFunction callWebServiceApplicationFunction, Processor processor, String processorName,
+                                          Activity<?> a) {
+
+        // external service provider
+        INode externalNode = ArchiUtils.initElement(factory.createNode(), "External Service", infrastructureFolder,
+                externalProviders);
+
+        String type = null;
+        IProperty prop = factory.createProperty();
+        IProperty locationProp = factory.createProperty();
+        if (a instanceof WSDLActivity) {
+
+            LOGGER.debug("WSDL Service found = " + processor.getLocalName());
+            type = "SOAP";
+            WSDLActivity wsdlActivity = (WSDLActivity) a;
+            prop.setKey("WSDL_Location");
+            prop.setValue(wsdlActivity.getConfiguration().getWsdl());
+            externalNode.getProperties().add(prop);
+
+            locationProp = createDepProperties(WSDLActivity.class);
+        }
+
+        if (a instanceof RESTActivity) {
+
+            LOGGER.debug("RESTful Service found = " + processor.getLocalName());
+            type = "HTTP";
+            RESTActivity restActivity = (RESTActivity) a;
+            prop.setKey("URL");
+            prop.setValue(restActivity.getConfiguration().getUrlSignature());
+            externalNode.getProperties().add(prop);
+
+            locationProp = createDepProperties(RESTActivity.class);
+        }
+
+        // create archimate function call only once
+        if (callWebServiceApplicationFunction == null) {
+
+            callWebServiceApplicationFunction = ArchiUtils.initElement(factory.createApplicationFunction(),
+                    "Calling Web Service", applicationFolder, applicationComponents);
+
+            ArchiUtils.initRelation(factory.createAssignmentRelationship(), callWebServiceApplicationFunction,
+                    workflowApplicationComponent, relationsFolder, relations);
+
+            ArchiUtils.initRelation(factory.createUsedByRelationship(), workflowFile,
+                    callWebServiceApplicationFunction, relationsFolder, relations);
+
+            ArchiUtils.initRelation(factory.createRealisationRelationship(), taverna,
+                    callWebServiceApplicationFunction, relationsFolder, relations);
+        }
+
+        IApplicationInterface appIf = ArchiUtils.initElement(factory.createApplicationInterface(), type,
+                applicationFolder, externalApplicationServices);
+
+        IApplicationService appService = ArchiUtils.initElement(factory.createApplicationService(), processorName
+                + "Service", applicationFolder, externalApplicationServices);
+
+        appService.getProperties().add(locationProp);
+
+        ArchiUtils.initRelation(factory.createUsedByRelationship(), appService, processorProcessMap.get(processor),
+                relationsFolder, relations);
+
+        // used-by relation between business processor and application function
+        ArchiUtils.initRelation(factory.createUsedByRelationship(), callWebServiceApplicationFunction,
+                processorProcessMap.get(processor), relationsFolder, relations);
+
+        ArchiUtils.initRelation(factory.createAssignmentRelationship(), appService, appIf, relationsFolder, relations);
+
+        // creating request response data objects
+        for (IArchimateElement inputElement : ArchiUtils.getInputElementsOfProcess(processorProcessMap.get(processor),
+                relations)) {
+
+            if (!business2dataMap.containsKey(inputElement)) {
+
+                IDataObject requestObject = ArchiUtils.initElement(factory.createDataObject(), inputElement.getName()
+                        + "(Request)", applicationFolder, applicationComponents);
+
+                business2dataMap.put((IBusinessObject) inputElement, requestObject);
+
+                ArchiUtils.initRelation(factory.createRealisationRelationship(), requestObject, inputElement,
+                        relationsFolder, relations);
+            }
+            ArchiUtils.initAccessRelation(factory.createAccessRelationship(), appService,
+                    business2dataMap.get(inputElement), applicationFolder, relations, IAccessRelationship.READ_ACCESS);
+        }
+
+        for (IArchimateElement outputElement : ArchiUtils.getOutputElementsOfProcess(
+                processorProcessMap.get(processor), relations)) {
+
+            if (!business2dataMap.containsKey(outputElement)) {
+
+                IDataObject responseObject = ArchiUtils.initElement(factory.createDataObject(), outputElement.getName()
+                        + "(Response)", applicationFolder, applicationComponents);
+
+                business2dataMap.put((IBusinessObject) outputElement, responseObject);
+
+                ArchiUtils.initRelation(factory.createRealisationRelationship(), responseObject, outputElement,
+                        relationsFolder, relations);
+            }
+            ArchiUtils
+                    .initAccessRelation(factory.createAccessRelationship(), appService,
+                            business2dataMap.get(outputElement), applicationFolder, relations,
+                            IAccessRelationship.WRITE_ACCESS);
+        }
+        ArchiUtils.initRelation(factory.createRealisationRelationship(), externalNode, appService, relationsFolder,
+                relations);
+    }
+
+    public void processRShellActivity(IFolder businessFolder, IFolder infrastructureFolder, IFolder applicationFolder,
+                                      IFolder relationsFolder, IApplicationComponent workflowApplicationComponent,
+                                      HashMap<Processor, IBusinessProcess> processorProcessMap,
+                                      IApplicationFunction callWebServiceApplicationFunction, Processor processor, String processorName,
+                                      Activity<?> a) {
+
+        if (!(a instanceof RshellActivity)) {
+            LOGGER.info("Activity [" + a + "] is not an instance of RshellActivity. Stop further processing!");
+            return;
+        }
+
+        RshellActivity rshellActivity = (RshellActivity) a;
+
+        // create archimate function call only once
+        if (callToolInvocationFunction == null) {
+
+            callToolInvocationFunction = ArchiUtils.initElement(factory.createApplicationFunction(),
+                    "Tool Invocation Service", applicationFolder, applicationComponents);
+
+            ArchiUtils.initRelation(factory.createAssignmentRelationship(), callToolInvocationFunction,
+                    workflowApplicationComponent, relationsFolder, relations);
+
+            ArchiUtils.initRelation(factory.createUsedByRelationship(), workflowFile, callToolInvocationFunction,
+                    relationsFolder, relations);
+
+            ArchiUtils.initRelation(factory.createRealisationRelationship(), taverna, callToolInvocationFunction,
+                    relationsFolder, relations);
+        }
+
+        IApplicationService appService = ArchiUtils.initElement(factory.createApplicationService(), processorName
+                + "Service", applicationFolder, externalApplicationServices);
+
+
+        appService.getProperties().add(createDepProperties(RshellActivity.class));
+
+        ArchiUtils.initRelation(factory.createUsedByRelationship(), appService, processorProcessMap.get(processor),
+                relationsFolder, relations);
+
+        // used-by relation between business processor and application function
+        ArchiUtils.initRelation(factory.createUsedByRelationship(), callToolInvocationFunction,
+                processorProcessMap.get(processor), relationsFolder, relations);
+
+        // creating input output data objects
+        for (IArchimateElement inputElement : ArchiUtils.getInputElementsOfProcess(processorProcessMap.get(processor),
+                relations)) {
+
+            if (!business2dataMap.containsKey(inputElement)) {
+
+                IDataObject requestObject = ArchiUtils.initElement(factory.createDataObject(), inputElement.getName()
+                        + "(Input)", applicationFolder, applicationComponents);
+
+                business2dataMap.put((IBusinessObject) inputElement, requestObject);
+
+                ArchiUtils.initRelation(factory.createRealisationRelationship(), requestObject, inputElement,
+                        relationsFolder, relations);
+            }
+            ArchiUtils.initAccessRelation(factory.createAccessRelationship(), appService,
+                    business2dataMap.get(inputElement), applicationFolder, relations, IAccessRelationship.READ_ACCESS);
+        }
+
+        for (IArchimateElement outputElement : ArchiUtils.getOutputElementsOfProcess(
+                processorProcessMap.get(processor), relations)) {
+
+            if (!business2dataMap.containsKey(outputElement)) {
+
+                IDataObject responseObject = ArchiUtils.initElement(factory.createDataObject(), outputElement.getName()
+                        + "(Output)", applicationFolder, applicationComponents);
+
+                business2dataMap.put((IBusinessObject) outputElement, responseObject);
+
+                ArchiUtils.initRelation(factory.createRealisationRelationship(), responseObject, outputElement,
+                        relationsFolder, relations);
+            }
+            ArchiUtils
+                    .initAccessRelation(factory.createAccessRelationship(), appService,
+                            business2dataMap.get(outputElement), applicationFolder, relations,
+                            IAccessRelationship.WRITE_ACCESS);
+
+        }
+
+        IApplicationInterface appIf = ArchiUtils.initElement(factory.createApplicationInterface(), "SSH",
+                applicationFolder, externalApplicationServices);
+
+        INode externalNode = ArchiUtils.initElement(factory.createNode(), "External Service", infrastructureFolder,
+                externalProviders);
+
+        ArchiUtils.initRelation(factory.createAssignmentRelationship(), appService, appIf, relationsFolder, relations);
+
+        ArchiUtils.initRelation(factory.createRealisationRelationship(), externalNode, appService, relationsFolder,
+                relations);
+
+        List<IProperty> props = createPropertiesOutOfRshellConfig(rshellActivity.getConfiguration());
+        externalNode.getProperties().addAll(props);
+    }
+
+    public void processToolActivity(IFolder businessFolder, IFolder infrastructureFolder, IFolder applicationFolder,
+                                    IFolder relationsFolder, IApplicationComponent workflowApplicationComponent,
+                                    HashMap<Processor, IBusinessProcess> processorProcessMap,
+                                    IApplicationFunction callWebServiceApplicationFunction, Processor processor, String processorName,
+                                    Activity<?> a, boolean isExternal) {
+
+        if (!(a instanceof ExternalToolActivity)) {
+            LOGGER.info("Activity [" + a + "] is not an instance of ExternalToolActivity. Stop further processing!");
+            return;
+        }
+
+        ExternalToolActivity externalInvocation = (ExternalToolActivity) a;
+
+        // create archimate function call only once
+        if (callToolInvocationFunction == null) {
+
+            callToolInvocationFunction = ArchiUtils.initElement(factory.createApplicationFunction(),
+                    "Tool Invocation Service", applicationFolder, applicationComponents);
+
+            ArchiUtils.initRelation(factory.createAssignmentRelationship(), callToolInvocationFunction,
+                    workflowApplicationComponent, relationsFolder, relations);
+
+            ArchiUtils.initRelation(factory.createUsedByRelationship(), workflowFile, callToolInvocationFunction,
+                    relationsFolder, relations);
+
+            ArchiUtils.initRelation(factory.createRealisationRelationship(), taverna, callToolInvocationFunction,
+                    relationsFolder, relations);
+        }
+
+        IApplicationService appService = isExternal ? ArchiUtils.initElement(factory.createApplicationService(),
+                processorName + "Service", applicationFolder, externalApplicationServices) : ArchiUtils
+                .initElement(factory.createApplicationService(), processorName + "Service", applicationFolder,
+                        applicationComponents);
+
+        appService.getProperties().add(createDepProperties(ExternalToolActivity.class));
+
+        ArchiUtils.initRelation(factory.createUsedByRelationship(), appService, processorProcessMap.get(processor),
+                relationsFolder, relations);
+
+        // used-by relation between business processor and application function
+        ArchiUtils.initRelation(factory.createUsedByRelationship(), callToolInvocationFunction,
+                processorProcessMap.get(processor), relationsFolder, relations);
+
+        // creating input output data objects
+        for (IArchimateElement inputElement : ArchiUtils.getInputElementsOfProcess(processorProcessMap.get(processor),
+                relations)) {
+
+            if (!business2dataMap.containsKey(inputElement)) {
+
+                IDataObject requestObject = ArchiUtils.initElement(factory.createDataObject(), inputElement.getName()
+                        + "(Input)", applicationFolder, applicationComponents);
+
+                business2dataMap.put((IBusinessObject) inputElement, requestObject);
+
+                ArchiUtils.initRelation(factory.createRealisationRelationship(), requestObject, inputElement,
+                        relationsFolder, relations);
+            }
+            ArchiUtils.initAccessRelation(factory.createAccessRelationship(), appService,
+                    business2dataMap.get(inputElement), applicationFolder, relations, IAccessRelationship.READ_ACCESS);
+        }
+
+        for (IArchimateElement outputElement : ArchiUtils.getOutputElementsOfProcess(
+                processorProcessMap.get(processor), relations)) {
+
+            if (!business2dataMap.containsKey(outputElement)) {
+
+                IDataObject responseObject = ArchiUtils.initElement(factory.createDataObject(), outputElement.getName()
+                        + "(Output)", applicationFolder, applicationComponents);
+
+                business2dataMap.put((IBusinessObject) outputElement, responseObject);
+
+                ArchiUtils.initRelation(factory.createRealisationRelationship(), responseObject, outputElement,
+                        relationsFolder, relations);
+            }
+            ArchiUtils
+                    .initAccessRelation(factory.createAccessRelationship(), appService,
+                            business2dataMap.get(outputElement), applicationFolder, relations,
+                            IAccessRelationship.WRITE_ACCESS);
+
+        }
+
+        if (isExternal) {
+
+            IApplicationInterface appIf = ArchiUtils.initElement(factory.createApplicationInterface(), "SSH",
+                    applicationFolder, externalApplicationServices);
+
+            INode externalNode = ArchiUtils.initElement(factory.createNode(), "External Service", infrastructureFolder,
+                    externalProviders);
+
+            ArchiUtils.initRelation(factory.createAssignmentRelationship(), appService, appIf, relationsFolder,
+                    relations);
+
+            ArchiUtils.initRelation(factory.createRealisationRelationship(), externalNode, appService, relationsFolder,
+                    relations);
+
+            List<IProperty> props = createPropertiesOutOfXMLMechanism(externalInvocation.getConfiguration());
+            externalNode.getProperties().addAll(props);
+
+        } else {
+
+            IArtifact toolAsArtifact = (IArtifact) ArchiUtils.initElement(factory.createArtifact(), "Tool",
+                    infrastructureFolder, nodeElements);
+
+            ArchiUtils.initRelation(factory.createRealisationRelationship(), toolAsArtifact, appService,
+                    relationsFolder, relations);
+
+            IProperty commandProperty = factory.createProperty();
+            commandProperty.setKey("Command");
+            commandProperty.setValue(externalInvocation.getConfiguration().getUseCaseDescription().getCommand());
+            toolAsArtifact.getProperties().add(commandProperty);
+        }
+    }
+
+    public void processBeanshellActivity(IFolder infrastructureFolder, IFolder motivationFolder,
+                                         IFolder applicationFolder, IFolder relationsFolder, IApplicationComponent workflowApplicationComponent,
+                                         HashMap<Processor, IBusinessProcess> processorProcessMap, Processor processor, Activity<?> a)
+            throws IOException {
+        beanshellScripts.add((BeanshellActivity) a);
+
+        LOGGER.debug("Beanshell script found = " + processor.getLocalName());
+
+        // create external application service for each business process/function
+        if (callScriptApplicationFunction == null) {
+
+            callScriptApplicationFunction = ArchiUtils.initElement(factory.createApplicationFunction(),
+                    "Calling Script", applicationFolder, applicationComponents);
+
+            ArchiUtils.initRelation(factory.createAssignmentRelationship(), callScriptApplicationFunction,
+                    workflowApplicationComponent, relationsFolder, relations);
+
+            ArchiUtils.initRelation(factory.createRealisationRelationship(), taverna, callScriptApplicationFunction,
+                    relationsFolder, relations);
+        }
+
+        IApplicationService appService = ArchiUtils.initElement(factory.createApplicationService(),
+                processor.getLocalName(), applicationFolder, externalApplicationServices);
+
+        appService.getProperties().add(createDepProperties(BeanshellActivity.class));
+
+        ArchiUtils.initRelation(factory.createUsedByRelationship(), appService, processorProcessMap.get(processor),
+                relationsFolder, relations);
+
+        ArchiUtils.initRelation(factory.createUsedByRelationship(), callScriptApplicationFunction,
+                processorProcessMap.get(processor), relationsFolder, relations);
+
+        IArtifact script = (IArtifact) ArchiUtils.initElement(factory.createArtifact(), processor.getLocalName()
+                + "Script", infrastructureFolder, nodeElements);
+
+        ArchiUtils.initRelation(factory.createCompositionRelationship(), workflowFile, script, relationsFolder,
+                relations);
+
+        ArchiUtils
+                .initRelation(factory.createRealisationRelationship(), script, appService, relationsFolder, relations);
+
+        // creating request response data objects
+        for (IArchimateElement inputElement : ArchiUtils.getInputElementsOfProcess(processorProcessMap.get(processor),
+                relations)) {
+
+            if (!business2dataMap.containsKey(inputElement)) {
+
+                IDataObject requestObject = ArchiUtils.initElement(factory.createDataObject(), inputElement.getName(),
+                        applicationFolder, applicationComponents);
+
+                business2dataMap.put((IBusinessObject) inputElement, requestObject);
+
+                ArchiUtils.initRelation(factory.createRealisationRelationship(), requestObject, inputElement,
+                        relationsFolder, relations);
+            }
+            ArchiUtils.initAccessRelation(factory.createAccessRelationship(), appService,
+                    business2dataMap.get(inputElement), applicationFolder, relations, IAccessRelationship.READ_ACCESS);
+
+        }
+
+        for (IArchimateElement outputElement : ArchiUtils.getOutputElementsOfProcess(
+                processorProcessMap.get(processor), relations)) {
+
+            if (!business2dataMap.containsKey(outputElement)) {
+
+                IDataObject responseObject = ArchiUtils.initElement(factory.createDataObject(),
+                        outputElement.getName(), applicationFolder, applicationComponents);
+
+                ArchiUtils.initRelation(factory.createRealisationRelationship(), responseObject, outputElement,
+                        relationsFolder, relations);
+
+                business2dataMap.put((IBusinessObject) outputElement, responseObject);
+            }
+
+            ArchiUtils
+                    .initAccessRelation(factory.createAccessRelationship(), appService,
+                            business2dataMap.get(outputElement), applicationFolder, relations,
+                            IAccessRelationship.WRITE_ACCESS);
+
+        }
+
+        BeanshellActivity bs = (BeanshellActivity) a;
+        BeanshellActivityConfigurationBean conf = bs.getConfiguration();
+
+        // one or more physical dependencies
+        if (conf.getLocalDependencies().size() > 0) {
+
+            Iterator<String> iter = conf.getLocalDependencies().iterator();
+            while (iter.hasNext()) {
+
+                String item = iter.next();
+
+                LOGGER.debug("\t Dependency for " + processor.getLocalName() + " [" + item + "]");
+
+                IArtifact beanshellScriptDep = (IArtifact) ArchiUtils.initElement(factory.createArtifact(), item,
+                        infrastructureFolder, nodeElements);
+
+                ArchiUtils.initRelationNodeElement(factory.createAssociationRelationship(), script, beanshellScriptDep,
+                        relationsFolder, nodeElements);
+
+                // Do the license checking
+                String fileName = TavernaExtractor.getTavernaHomeLib() + File.separator + item;
+
+                IProperty jarLocation = factory.createProperty();
+                jarLocation.setKey("hasSourceLocation");
+                jarLocation.setValue(fileName);
+                beanshellScriptDep.getProperties().add(jarLocation);
+
+                // do proper checking whether the file exists !
+                Path pathToDep = Paths.get(fileName);
+                if (Files.exists(pathToDep)) {
+                    String license = licenseCheck.extract(pathToDep.toAbsolutePath().toString());
+
+                    if (license.equals("Unknown license")) {
+                        LOGGER.debug("\t Unknown license for dependency [" + item + "].");
+                    }
+
+                    if (license != null && !license.equals("Unknown license")) {
+
+                        LOGGER.debug("\t Found license [" + license + "] for dependency [" + item + "].");
+
+                        // create constraint element for dependency
+                        IConstraint licenseConstraint = ArchiUtils.initElement(factory.createConstraint(), license,
+                                motivationFolder, infrastructure);
+
+                        ArchiUtils.initRelation(factory.createRealisationRelationship(), beanshellScriptDep,
+                                licenseConstraint, relationsFolder, relations);
+                    }
+                } else {
+                    LOGGER.error("\t ERROR: Jar file [" + fileName + "] not found!");
+                }
+            }
+        }
+    }
+
+    private void drawBusinessProcessGroup() {
+        int maxX = 15;
+        int maxY = 15;
+
+        int defaultGroupWidth = 130;
+        int defaultGroupHeight = ArchiLayoutUtils.DEFAULT_ELEMENT_HEIGHT + 10;
+
+        businessProcessModelGroup.setBounds(0, 0, 0, 0);
+
+        // --- draw input ports ---
+        IDiagramModelGroup group_inputObjects = factory.createDiagramModelGroup();
+        group_inputObjects.setName("Input Ports");
+        businessProcessModelGroup.getChildren().add(group_inputObjects);
+        group_inputObjects.setBounds(15, 15, defaultGroupWidth, defaultGroupHeight * inputPorts.getElements().size());
+
+        Map<String, int[]> boundsMap = ArchiLayoutUtils.getBoundsForElements(inputPorts.getElements(),
+                inputPorts.getOrientation());
+        for (IArchimateElement inputPort : inputPorts.getElements()) {
+            IDiagramModelArchimateObject diagramModelBusinessObject = factory.createDiagramModelArchimateObject();
+            diagramModelBusinessObject.setArchimateElement(inputPort);
+            int[] bounds = boundsMap.get(inputPort.getId());
+            Dimension elementSize = ArchiLayoutUtils.getElementSize(inputPort);
+            diagramModelBusinessObject.setBounds(bounds[0], bounds[1] + 10, elementSize.width, elementSize.height);
+            group_inputObjects.getChildren().add(diagramModelBusinessObject);
+            elementModelObjectMap.put(inputPort.getId(), diagramModelBusinessObject);
+        }
+        ArchiLayoutUtils.resize(group_inputObjects);
+        maxY += ArchiLayoutUtils.getLowerEdgePosition(group_inputObjects);
+        maxX += ArchiLayoutUtils.getRightEdgePosition(group_inputObjects);
+
+        // --- draw value processors ---
+        if (valueObjects.getElements().size() > 0) { // only draw a group if elements exists
+            IDiagramModelGroup groupValueProcessors = factory.createDiagramModelGroup();
+            groupValueProcessors.setName("Constants Input Ports");
+            businessProcessModelGroup.getChildren().add(groupValueProcessors);
+            groupValueProcessors.setBounds(15, maxY, defaultGroupWidth, defaultGroupHeight
+                    * valueObjects.getElements().size());
+
+            boundsMap = ArchiLayoutUtils
+                    .getBoundsForElements(valueObjects.getElements(), valueObjects.getOrientation());
+            for (IArchimateElement valueProcessor : valueObjects.getElements()) {
+                IDiagramModelArchimateObject diagramModelBusinessObject = factory.createDiagramModelArchimateObject();
+                diagramModelBusinessObject.setArchimateElement(valueProcessor);
+                int[] bounds = boundsMap.get(valueProcessor.getId());
+                Dimension elementSize = ArchiLayoutUtils.getElementSize(valueProcessor);
+                diagramModelBusinessObject.setBounds(bounds[0], bounds[1] + 10, elementSize.width, elementSize.height);
+                groupValueProcessors.getChildren().add(diagramModelBusinessObject);
+                elementModelObjectMap.put(valueProcessor.getId(), diagramModelBusinessObject);
+            }
+            ArchiLayoutUtils.resize(groupValueProcessors);
+            maxY += ArchiLayoutUtils.getLowerEdgePosition(groupValueProcessors);
+            maxX = Math.max(maxX, ArchiLayoutUtils.getRightEdgePosition(groupValueProcessors));
+        }
+
+        // --- draw business objects ---
+        IDiagramModelGroup group_businessObjects = ArchiLayoutUtils.createSubModelGroup(businessProcessModelGroup,
+                "Business Objects");
+        group_businessObjects.setBounds(maxX, 15, 0, 0);
+
+        boundsMap = ArchiLayoutUtils.getBoundsForElements(businessObjects.getElements(),
+                businessObjects.getOrientation());
+
+        for (Entry<List<IArchimateElement>, List<IArchimateElement>> group : ArchiUtils.groupElements(
+                getBusinessProcesses(), relations).entrySet()) {
+
+            List<IArchimateElement> elementsInGroup = group.getValue();
+
+            IBusinessObject parentBusinessObject = null;
+            IDiagramModelArchimateObject diagramModelBusinessObjectParent = null;
+            if (elementsInGroup.size() >= MIN_ELEMENTS_FOR_GROUPING) {
+
+                String elementName = group.getKey().get(0).getName() + "=>" + group.getKey().get(1).getName();
+                parentBusinessObject = ArchiUtils.initElement(factory.createBusinessObject(), elementName,
+                        businessFolder, businessObjects);
+                parentBusinessObject.setName(elementName);
+                diagramModelBusinessObjectParent = factory.createDiagramModelArchimateObject();
+                diagramModelBusinessObjectParent.setArchimateElement(parentBusinessObject);
+                diagramModelBusinessObjectParent.setBounds(100, 100, 100, 100);
+                elementModelObjectMap.put(parentBusinessObject.getId(), diagramModelBusinessObjectParent);
+                group_businessObjects.getChildren().add(diagramModelBusinessObjectParent);
+
+                // redirect connections to parent object
+                ArchiUtils.redirectRelations(parentBusinessObject, group.getKey().get(0), group.getKey().get(1),
+                        elementsInGroup, relations);
+
+                ArchiUtils.initAccessRelation(factory.createAccessRelationship(), group.getKey().get(0),
+                        parentBusinessObject, relationsFolder, relations, IAccessRelationship.WRITE_ACCESS);
+
+                ArchiUtils.initAccessRelation(factory.createAccessRelationship(), group.getKey().get(1),
+                        parentBusinessObject, relationsFolder, relations, IAccessRelationship.READ_ACCESS);
+
+            }
+            for (IArchimateElement businessObject : elementsInGroup) {
+                IDiagramModelArchimateObject diagramModelBusinessObject = factory.createDiagramModelArchimateObject();
+                diagramModelBusinessObject.setArchimateElement(businessObject);
+                int[] bounds = boundsMap.get(businessObject.getId());
+                Dimension elementSize = ArchiLayoutUtils.getElementSize(businessObject);
+                diagramModelBusinessObject.setBounds(bounds[0], bounds[1], elementSize.width, elementSize.height);
+                group_businessObjects.getChildren().add(diagramModelBusinessObject);
+                elementModelObjectMap.put(businessObject.getId(), diagramModelBusinessObject);
+
+                // if parent exists -> add child & add composition relation & resize
+                if (diagramModelBusinessObjectParent != null) {
+
+                    ArchiUtils.initRelation(factory.createCompositionRelationship(), parentBusinessObject,
+                            businessObject, relationsFolder, relations);
+
+                    diagramModelBusinessObjectParent.getChildren().add(diagramModelBusinessObject);
+                    diagramModelBusinessObjectParent.setBounds(elementModelObjectMap
+                                    .get(elementsInGroup.get(0).getId()).getBounds().getX(),
+                            elementModelObjectMap.get(elementsInGroup.get(0).getId()).getBounds().getY(),
+                            diagramModelBusinessObject.getBounds().getX()
+                                    + diagramModelBusinessObject.getBounds().getWidth(), diagramModelBusinessObject
+                                    .getBounds().getY() + diagramModelBusinessObject.getBounds().getHeight());
+                }
+            }
+        }
+
+        ArchiLayoutUtils.resize(group_businessObjects);
+        maxX = Math.max(maxX, ArchiLayoutUtils.getRightEdgePosition(group_businessObjects));
+
+        // --- draw business process steps ---
+        processStepsModelGroup = ArchiLayoutUtils.createSubModelGroup(businessProcessModelGroup, "Business Processes");
+        int starting_y = ArchiLayoutUtils.boundsOf(group_businessObjects)[1]
+                + ArchiLayoutUtils.boundsOf(group_businessObjects)[3] + 10;
+        processStepsModelGroup.setBounds(group_businessObjects.getBounds().getX(), starting_y, 0, 0);
+
+        boundsMap = ArchiLayoutUtils.getBoundsForElements(businessProcesses.getElements(),
+                businessProcesses.getOrientation());
+
+        Map<String, Point> graph = null;
+        if (isDotAvailable()) {
+            graph = getGraph(dataflow);
+        }
+
+        for (IArchimateElement businessProcess : businessProcesses.getElements()) {
+
+            IDiagramModelArchimateObject diagramModelBusinessProcess = factory.createDiagramModelArchimateObject();
+            diagramModelBusinessProcess.setArchimateElement(businessProcess);
+
+            int[] bounds;
+            if (graph != null) {
+                bounds = this.getBounds(graph, businessProcess.getName());
+            } else {
+                bounds = boundsMap.get(businessProcess.getId());
+            }
+            diagramModelBusinessProcess.setBounds(bounds[0], bounds[1] + 15,
+                    ArchiLayoutUtils.CUSTOM_BUSINESS_PROCESS_WIDTH, ArchiLayoutUtils.DEFAULT_ELEMENT_HEIGHT);
+
+            if (businessProcess instanceof BusinessEvent) {
+
+                businessProcessModelGroup.getChildren().add(diagramModelBusinessProcess);
+                elementModelObjectMap.put(businessProcess.getId(), diagramModelBusinessProcess);
+                continue;
+            }
+            processStepsModelGroup.getChildren().add(diagramModelBusinessProcess);
+            elementModelObjectMap.put(businessProcess.getId(), diagramModelBusinessProcess);
+            ArchiLayoutUtils.resize(processStepsModelGroup);
+            ArchiLayoutUtils.resize(businessProcessModelGroup);
+        }
+
+        // relocating loop junctions
+        for (Entry<Processor, IOrJunction> junction : loopsJunctions.entrySet()) {
+            IBusinessProcess processElement = processorProcessMap.get(junction.getKey());
+            IBounds bounds = elementModelObjectMap.get(processElement.getId()).getBounds();
+            int x = bounds.getX() + bounds.getWidth() / 2;
+            int y = bounds.getY() + bounds.getHeight() + 20;
+            elementModelObjectMap.get(junction.getValue().getId()).setBounds(x, y, 15, 15);
+        }
+
+        // relocating AND junctions
+        for (Entry<Processor, IAndJunction> junction : processorInputMap.entrySet()) {
+            IBusinessProcess processElement = processorProcessMap.get(junction.getKey());
+            IBounds bounds = elementModelObjectMap.get(processElement.getId()).getBounds();
+            int x = bounds.getX() + bounds.getWidth() / 2;
+            int y = bounds.getY() + bounds.getHeight() + 20;
+            elementModelObjectMap.get(junction.getValue().getId()).setBounds(x, y, 15, 15);
+        }
+
+        // relocate start and end event
+        elementModelObjectMap.get(startEvent.getId()).setBounds(processStepsModelGroup.getBounds().getX() - 100,
+                processStepsModelGroup.getBounds().getY() + processStepsModelGroup.getBounds().getHeight() / 2, 100,
+                ArchiLayoutUtils.DEFAULT_ELEMENT_HEIGHT);
+        if (andJunctionStart != null) {
+            elementModelObjectMap.get(andJunctionStart.getId()).setBounds(50,
+                    processStepsModelGroup.getBounds().getHeight() / 2, 15, 15);
+        }
+
+        elementModelObjectMap.get(endEvent.getId()).setBounds(
+                processStepsModelGroup.getBounds().getX() + processStepsModelGroup.getBounds().getWidth() + 50,
+                processStepsModelGroup.getBounds().getY() + processStepsModelGroup.getBounds().getHeight() / 2, 100,
+                ArchiLayoutUtils.DEFAULT_ELEMENT_HEIGHT);
+
+        if (andJunctionEnd != null) {
+            elementModelObjectMap.get(andJunctionEnd.getId()).setBounds(processStepsModelGroup.getBounds().getWidth(),
+                    processStepsModelGroup.getBounds().getHeight() / 2, 15, 15);
+        }
+
+        ArchiLayoutUtils.resize(processStepsModelGroup);
+        ArchiLayoutUtils.resize(businessProcessModelGroup);
+
+        // ArchiLayoutUtils.resize(processStepsModelGroup);
+        maxX = Math.max(maxX, ArchiLayoutUtils.getRightEdgePosition(processStepsModelGroup));
+
+        // all process steps are children of the parent process
+        for (IArchimateElement element : businessProcesses.getElements()) {
+            if (element != parentProcessWorkflow && !(element instanceof BusinessEvent)) {
+                elementModelObjectMap.get(parentProcessWorkflow.getId()).getChildren()
+                        .add(elementModelObjectMap.get(element.getId()));
+            }
+        }
+
+        // --- draw output ports ---
+        IDiagramModelGroup groupOutputPorts = ArchiLayoutUtils.createSubModelGroup(businessProcessModelGroup,
+                "Output Ports");
+        groupOutputPorts.setBounds(maxX + 35, 15, defaultGroupWidth, defaultGroupHeight
+                * outputPorts.getElements().size());
+
+        boundsMap = ArchiLayoutUtils.getBoundsForElements(outputPorts.getElements(), outputPorts.getOrientation());
+        for (IArchimateElement outputPort : outputPorts.getElements()) {
+            IDiagramModelArchimateObject diagramModelBusinessObject = factory.createDiagramModelArchimateObject();
+            diagramModelBusinessObject.setArchimateElement(outputPort);
+            int[] bounds = boundsMap.get(outputPort.getId());
+            final Dimension elementSize = ArchiLayoutUtils.getElementSize(outputPort);
+            diagramModelBusinessObject.setBounds(bounds[0], bounds[1], elementSize.width, elementSize.height);
+            groupOutputPorts.getChildren().add(diagramModelBusinessObject);
+            elementModelObjectMap.put(outputPort.getId(), diagramModelBusinessObject);
+            ArchiLayoutUtils.resize(groupOutputPorts);
+            ArchiLayoutUtils.resize(businessProcessModelGroup);
+        }
+
+        maxX = businessProcessModelGroup.getBounds().getWidth() + businessProcessModelGroup.getBounds().getX();
+        maxY = businessProcessModelGroup.getBounds().getHeight() + businessProcessModelGroup.getBounds().getY();
+
+        overall_X = maxX;
+        overall_Y = maxY;
+    }
+
+    private void drawExternalApplicationServices() {
+
+        // hide empty container
+        if (externalApplicationServices.getElements().isEmpty()) {
+            externalApplicationModelGroup.setBounds(0, overall_Y + 30, 0, 0);
+            return;
+        }
+
+        externalApplicationModelGroup.setBounds(0, overall_Y + 30, overall_X, 150);
+        overall_Y += 150;
+
+        Map<String, int[]> boundsMap = ArchiLayoutUtils.getBoundsForElements(externalApplicationServices.getElements(),
+                externalApplicationServices.orientation);
+        for (IArchimateElement element : externalApplicationServices.getElements()) {
+
+            IDiagramModelArchimateObject diagramModelBusinessObject = factory.createDiagramModelArchimateObject();
+            diagramModelBusinessObject.setArchimateElement(element);
+            int[] bounds = boundsMap.get(element.getId());
+            Dimension elementSize = ArchiLayoutUtils.getElementSize(element);
+            diagramModelBusinessObject.setBounds(bounds[0], bounds[1], elementSize.width, elementSize.height);
+            externalApplicationModelGroup.getChildren().add(diagramModelBusinessObject);
+            elementModelObjectMap.put(element.getId(), diagramModelBusinessObject);
+        }
+        ArchiLayoutUtils.resize(externalApplicationModelGroup);
+    }
+
+    private void drawApplicationComponentServices() {
+
+        int starting_y = ArchiLayoutUtils.boundsOf(externalApplicationModelGroup)[1]
+                + ArchiLayoutUtils.boundsOf(externalApplicationModelGroup)[3] + 20;
+        applicationComponentModelGroup.setBounds(0, starting_y, overall_X, 150);
+        overall_Y += 150;
+
+        Map<String, int[]> boundsMap = ArchiLayoutUtils.getBoundsForElements(dataObjects.getElements(),
+                dataObjects.getOrientation());
+
+        List<IArchimateElement> alreadyDrawnElements = new ArrayList<IArchimateElement>();
+
+        // --- draw data objects ---
+        for (Entry<List<IArchimateElement>, List<IArchimateElement>> group : ArchiUtils.groupElements(
+                applicationComponents.getElements(), relations).entrySet()) {
+
+            List<IArchimateElement> elementsInGroup = group.getValue();
+
+            IDataObject parentDataObject = null;
+            IDiagramModelArchimateObject diagramModelDataObjectParent = null;
+            if (elementsInGroup.size() >= MIN_ELEMENTS_FOR_GROUPING) {
+
+                String elementName = group.getKey().get(0).getName() + "=>" + group.getKey().get(1).getName();
+                parentDataObject = ArchiUtils.initElement(factory.createDataObject(), elementName, applicationFolder,
+                        dataObjects);
+                parentDataObject.setName(elementName);
+                diagramModelDataObjectParent = factory.createDiagramModelArchimateObject();
+                diagramModelDataObjectParent.setArchimateElement(parentDataObject);
+                diagramModelDataObjectParent.setBounds(0, 0, 10, 10);
+                elementModelObjectMap.put(parentDataObject.getId(), diagramModelDataObjectParent);
+                applicationComponentModelGroup.getChildren().add(diagramModelDataObjectParent);
+
+                // redirect connections to parent object
+                ArchiUtils.redirectRelations(parentDataObject, group.getKey().get(0), group.getKey().get(1),
+                        elementsInGroup, relations);
+
+                ArchiUtils.initAccessRelation(factory.createAccessRelationship(), group.getKey().get(0),
+                        parentDataObject, relationsFolder, relations, IAccessRelationship.WRITE_ACCESS);
+
+                ArchiUtils.initAccessRelation(factory.createAccessRelationship(), group.getKey().get(1),
+                        parentDataObject, relationsFolder, relations, IAccessRelationship.READ_ACCESS);
+                alreadyDrawnElements.add(parentDataObject);
+            }
+            for (IArchimateElement dataObject : elementsInGroup) {
+                IDiagramModelArchimateObject diagramModelBusinessObject = factory.createDiagramModelArchimateObject();
+                diagramModelBusinessObject.setArchimateElement(dataObject);
+
+                int[] bounds = { 10, 10 };
+                if (boundsMap.containsKey(dataObject.getId())) {
+                    bounds = boundsMap.get(dataObject.getId());
+                }
+                Dimension elementSize = ArchiLayoutUtils.getElementSize(dataObject);
+
+                diagramModelBusinessObject.setBounds(bounds[0], bounds[1], elementSize.width, elementSize.height);
+                applicationComponentModelGroup.getChildren().add(diagramModelBusinessObject);
+                elementModelObjectMap.put(dataObject.getId(), diagramModelBusinessObject);
+
+                alreadyDrawnElements.add(dataObject);
+
+                // if parent exists -> add child & add composition relation & resize
+                if (diagramModelDataObjectParent != null) {
+
+                    ArchiUtils.initRelation(factory.createCompositionRelationship(), parentDataObject, dataObject,
+                            relationsFolder, relations);
+
+                    diagramModelDataObjectParent.getChildren().add(diagramModelBusinessObject);
+                    diagramModelDataObjectParent.setBounds(elementModelObjectMap.get(elementsInGroup.get(0).getId())
+                            .getBounds().getX(), elementModelObjectMap.get(elementsInGroup.get(0).getId()).getBounds()
+                            .getY(), diagramModelBusinessObject.getBounds().getX()
+                            + diagramModelBusinessObject.getBounds().getWidth(), diagramModelBusinessObject.getBounds()
+                            .getY() + diagramModelBusinessObject.getBounds().getHeight());
+                }
+            }
+        }
+
+        ArrayList<IArchimateElement> objectsToDraw = (ArrayList<IArchimateElement>) dataObjects.getElements();
+        objectsToDraw.removeAll(alreadyDrawnElements);
+        objectsToDraw.addAll(applicationComponents.getElements());
+
+        boundsMap = ArchiLayoutUtils.getBoundsForElements(objectsToDraw, applicationComponents.orientation);
+
+        for (IArchimateElement element : objectsToDraw) {
+
+            IDiagramModelArchimateObject diagramModelBusinessObject = factory.createDiagramModelArchimateObject();
+            diagramModelBusinessObject.setArchimateElement(element);
+            int[] bounds = boundsMap.get(element.getId());
+            final Dimension elementSize = ArchiLayoutUtils.getElementSize(element);
+            diagramModelBusinessObject.setBounds(bounds[0], bounds[1], elementSize.width, elementSize.height);
+
+            applicationComponentModelGroup.getChildren().add(diagramModelBusinessObject);
+            elementModelObjectMap.put(element.getId(), diagramModelBusinessObject);
+        }
+        ArchiLayoutUtils.resize(applicationComponentModelGroup);
+    }
+
+    private void drawExternalInfrastructureServices() {
+
+        int starting_y = ArchiLayoutUtils.boundsOf(applicationComponentModelGroup)[1]
+                + ArchiLayoutUtils.boundsOf(applicationComponentModelGroup)[3] + 20;
+
+        // hide empty container
+        if (infrastructureServices.getElements().isEmpty()) {
+            externalInfrastructureModelGroup.setBounds(0, starting_y, 0, 0);
+            return;
+        }
+
+        externalInfrastructureModelGroup.setBounds(0, starting_y, overall_X, 150);
+        overall_Y += 150;
+
+        LOGGER.debug("drawExternalInfrastructureServices.getElements().size() = "
+                + infrastructureServices.getElements().size());
+
+        Map<String, int[]> boundsMap = ArchiLayoutUtils.getBoundsForElements(infrastructureServices.getElements(),
+                infrastructureServices.orientation);
+        for (IArchimateElement element : infrastructureServices.getElements()) {
+
+            IDiagramModelArchimateObject diagramModelBusinessObject = factory.createDiagramModelArchimateObject();
+            diagramModelBusinessObject.setArchimateElement(element);
+            int[] bounds = boundsMap.get(element.getId());
+            diagramModelBusinessObject.setBounds(bounds[0], bounds[1], bounds[2], bounds[3]);
+            externalInfrastructureModelGroup.getChildren().add(diagramModelBusinessObject);
+            elementModelObjectMap.put(element.getId(), diagramModelBusinessObject);
+        }
+        ArchiLayoutUtils.resize(externalInfrastructureModelGroup);
+    }
+
+    private void drawInfrastructure() {
+
+        int starting_y = ArchiLayoutUtils.boundsOf(externalInfrastructureModelGroup)[1]
+                + ArchiLayoutUtils.boundsOf(externalInfrastructureModelGroup)[3] + 20;
+        infrastructureModelGroup.setBounds(0, starting_y, overall_X, 150);
+
+        Map<String, int[]> boundsMap = ArchiLayoutUtils.getBoundsForElements(infrastructure.getElements(),
+                infrastructure.orientation);
+        for (IArchimateElement element : infrastructure.getElements()) {
+
+            IDiagramModelArchimateObject diagramModelBusinessObject = factory.createDiagramModelArchimateObject();
+            diagramModelBusinessObject.setArchimateElement(element);
+
+            int[] bounds = boundsMap.get(element.getId());
+            diagramModelBusinessObject.setBounds(bounds[0], bounds[1], bounds[2], bounds[3]);
+
+            infrastructureModelGroup.getChildren().add(diagramModelBusinessObject);
+            elementModelObjectMap.put(element.getId(), diagramModelBusinessObject);
+
+            if (element.getId().equals(desktop.getId())) {
+                createDiagramElements(generateLayout(nodeElements), diagramModelBusinessObject);
+                infrastructureModelGroup.setBounds(0, starting_y, overall_X, diagramModelBusinessObject.getBounds()
+                        .getHeight() + 25);
+            }
+        }
+        ArchiLayoutUtils.resize(infrastructureModelGroup);
+    }
+
+    private void drawExternalProviders() {
+
+        if (!externalProviders.getElements().isEmpty()) {
+
+            // (*) Group "External Provider"
+            externalProviderModelGroup = ArchiLayoutUtils.createSubModelGroup(layeredView, "External Service Provider");
+
+            int starting_y = ArchiLayoutUtils.boundsOf(externalInfrastructureModelGroup)[1];
+            int starting_x = ArchiLayoutUtils.boundsOf(externalInfrastructureModelGroup)[0]
+                    + ArchiLayoutUtils.boundsOf(externalInfrastructureModelGroup)[2] + 20;
+            externalProviderModelGroup.setBounds(starting_x, starting_y, 150, 150);
+
+            Map<String, int[]> boundsMap = ArchiLayoutUtils.getBoundsForElements(externalProviders.getElements(),
+                    externalProviders.orientation);
+            for (IArchimateElement element : externalProviders.getElements()) {
+
+                IDiagramModelArchimateObject diagramModelBusinessObject = factory.createDiagramModelArchimateObject();
+                diagramModelBusinessObject.setArchimateElement(element);
+
+                int[] bounds = boundsMap.get(element.getId());
+                diagramModelBusinessObject.setBounds(bounds[0], bounds[1], bounds[2], bounds[3]);
+
+                externalProviderModelGroup.getChildren().add(diagramModelBusinessObject);
+                elementModelObjectMap.put(element.getId(), diagramModelBusinessObject);
+            }
+            ArchiLayoutUtils.resize(externalProviderModelGroup);
+        }
+    }
+
+    private void drawRelations() {
+        for (IRelationship relation : relations) {
+
+            if (relation.getSource() == null) {
+                return;
+            }
+            if (relation.getTarget() == null) {
+                return;
+            }
+
+            LOGGER.debug("drawing relation [" + relation.getSource().getName() + "("
+                    + relation.getSource().eClass().getName() + ")] --> [" + relation.getTarget().getName() + "("
+                    + relation.getTarget().eClass().getName() + ")]");
+
+            IDiagramModelArchimateObject source = elementModelObjectMap.get(relation.getSource().getId());
+            IDiagramModelArchimateObject target = elementModelObjectMap.get(relation.getTarget().getId());
+
+            ArchiLayoutUtils.createConnection(factory, relation, source, target);
+        }
+    }
+
+    private Map<IArchimateElement, Point> generateLayout(List<IArchimateElement> elements) {
+
+        Map<IArchimateElement, Point> items = new HashMap<IArchimateElement, Point>();
+        graph = new SparseGraph<IArchimateElement, IArchimateElement>();
+
+        for (IArchimateElement element : elements) {
+            if (element instanceof IRelationship) {
+                IArchimateElement source = ((IRelationship) element).getSource();
+                IArchimateElement target = ((IRelationship) element).getTarget();
+                graph.addEdge(element, source, target);
+            } else {
+                graph.addVertex(element);
+            }
+        }
+
+        layout = new ISOMLayout<IArchimateElement, IArchimateElement>(graph);
+        layout.setSize(new Dimension(650, 650));
+
+        for (IArchimateElement element : layout.getGraph().getVertices()) {
+
+            int x = (int) ((AbstractLayout<IArchimateElement, IArchimateElement>) layout).getX(element);
+            int y = (int) ((AbstractLayout<IArchimateElement, IArchimateElement>) layout).getY(element);
+            LOGGER.debug(element.getName() + "[" + x + "][" + y + "]");
+            items.put(element, new Point(x, y));
+        }
+        return items;
+    }
+
+    private void createDiagramElements(Map<IArchimateElement, Point> elements, IDiagramModelContainer parent) {
+
+        // draw elements
+        for (Entry<IArchimateElement, Point> entry : elements.entrySet()) {
+
+            IDiagramModelArchimateObject diagramModelObject = factory.createDiagramModelArchimateObject();
+            diagramModelObject.setArchimateElement(entry.getKey());
+            Dimension size = ArchiLayoutUtils.getElementSize(entry.getKey());
+
+            diagramModelObject.setBounds(entry.getValue().x, entry.getValue().y, size.width, size.height);
+            parent.getChildren().add(diagramModelObject);
+
+            // resize parent container
+            ArchiLayoutUtils.resize(parent);
+            elementModelObjectMap.put(entry.getKey().getId(), diagramModelObject);
+        }
+
+        // create connections
+        for (IArchimateElement edge : layout.getGraph().getEdges()) {
+
+            IRelationship relationShip = (IRelationship) edge;
+
+            String sourceID = relationShip.getSource().getId();
+            String targetID = relationShip.getTarget().getId();
+            IDiagramModelArchimateObject source = elementModelObjectMap.get(sourceID);
+            IDiagramModelArchimateObject target = elementModelObjectMap.get(targetID);
+
+            ArchiLayoutUtils.createConnection(factory, relationShip, source, target);
+        }
+    }
+
+    private boolean sshInvocation(String mechanismAsXMLString) {
+        return mechanismAsXMLString.contains("<sshInvocation>");
+    }
+
+    private IProperty createDepProperties(Class clazz) {
+
+        IProperty property = factory.createProperty();
+        property.setKey("hasSourceLocation");
+        property.setValue(getJarLocationOfClass(clazz).getPath().replaceFirst("/",""));
+        return property;
+    }
+
+    private IProperty createDepProperties(String pathToJar) {
+
+        IProperty property = factory.createProperty();
+        property.setKey("hasSourceLocation");
+        property.setValue(pathToJar);
+        return property;
+    }
+
+    private List<IProperty> createPropertiesOutOfXMLMechanism(ExternalToolActivityConfigurationBean configuration) {
+
+        List<IProperty> props = new ArrayList<IProperty>();
+
+        try {
+            Document document = DocumentHelper.parseText(configuration.getMechanismXML());
+
+            IProperty hostProperty = factory.createProperty();
+            hostProperty.setKey("Host");
+            hostProperty.setValue(document.selectSingleNode("//host").getText());
+            props.add(hostProperty);
+
+            IProperty portProperty = factory.createProperty();
+            portProperty.setKey("Port");
+            portProperty.setValue(document.selectSingleNode("//port").getText());
+            props.add(portProperty);
+
+        } catch (DocumentException e) {
+            LOGGER.error("ERROR parsing external tool invocation mechanism. " + e.getMessage());
+        }
+
+        IProperty commandProperty = factory.createProperty();
+        commandProperty.setKey("Command");
+        commandProperty.setValue(configuration.getUseCaseDescription().getCommand());
+        props.add(commandProperty);
+
+        return props;
+    }
+
+    private List<IProperty> createPropertiesOutOfRshellConfig(RshellActivityConfigurationBean configuration) {
+
+        List<IProperty> props = new ArrayList<IProperty>();
+
+        IProperty hostProperty = factory.createProperty();
+        hostProperty.setKey("Host");
+        hostProperty.setValue(configuration.getConnectionSettings().getHost());
+        props.add(hostProperty);
+
+        IProperty portProperty = factory.createProperty();
+        portProperty.setKey("Port");
+        portProperty.setValue("" + configuration.getConnectionSettings().getPort());
+        props.add(portProperty);
+
+        IProperty scriptProperty = factory.createProperty();
+        scriptProperty.setKey("Script");
+        scriptProperty.setValue(configuration.getScript());
+        props.add(scriptProperty);
+
+        return props;
+    }
+
+    private void printPortInformation(Processor processor) {
+
+        if (processor != null) {
+            for (ProcessorInputPort inputPort : processor.getInputPorts()) {
+                LOGGER.debug("--> Port = " + inputPort.getName() + "[depth = " + inputPort.getDepth() + "]");
+            }
+            for (ProcessorOutputPort outputPort : processor.getOutputPorts()) {
+                LOGGER.debug("<-- Port = " + outputPort.getName() + "[depth = " + outputPort.getDepth() + "]");
+            }
+        }
+    }
+
+    private List<Processor> findStartingProcessors(Dataflow dataflow) {
+
+        List<OutputPort> outputPorts = new ArrayList<OutputPort>();
+        for (Processor processor : dataflow.getProcessors()) {
+            for (OutputPort outputPort : processor.getOutputPorts()) {
+                outputPorts.add(outputPort);
+            }
+        }
+
+        List<Processor> startingProcessors = new ArrayList<Processor>();
+        for (Processor processor : dataflow.getProcessors()) {
+
+            // detect if first step processor
+
+            if (ArchiUtils.isValueProcessor(processor)) {
+                break;
+            }
+
+            if (hasNoPrecedentProcessor(processor, outputPorts)) {
+                LOGGER.debug("Processor '" + processor.getLocalName() + "' has no precendent processors.");
+                startingProcessors.add(processor);
+            }
+        }
+        return startingProcessors;
+    }
+
+    private List<Processor> findEndProcessors(Dataflow dataflow) {
+
+        List<InputPort> inputPorts = new ArrayList<InputPort>();
+        for (Processor processor : dataflow.getProcessors()) {
+            for (InputPort inputPort : processor.getInputPorts()) {
+                inputPorts.add(inputPort);
+            }
+        }
+
+        List<Processor> endingProcessors = new ArrayList<Processor>();
+        for (Processor processor : dataflow.getProcessors()) {
+
+            // detect if first step processor
+            if (hasNoSucceedProcessor(processor, inputPorts)) {
+                LOGGER.debug("Processor '" + processor.getLocalName() + "' has no succeed processors.");
+                endingProcessors.add(processor);
+            }
+        }
+        return endingProcessors;
+    }
+
+    private boolean hasNoPrecedentProcessor(Processor processor, List<OutputPort> outputPorts) {
+
+        for (ProcessorInputPort sink : processor.getInputPorts()) {
+            if (outputPorts.contains(sink.getIncomingLink().getSource())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean hasNoSucceedProcessor(Processor processor, List<InputPort> inputPort) {
+
+        for (ProcessorOutputPort out : processor.getOutputPorts()) {
+
+            for (Datalink links : out.getOutgoingLinks()) {
+                if (inputPort.contains(links.getSink())) {
+                    return false;
+                }
+            }
+
+        }
+        return true;
+    }
+
+    public Map<String, Point> getGraph(Dataflow dataflow) {
+
+        SVGGraphController con = new SVGGraphController(dataflow, false, new JSVGCanvas(), Alignment.HORIZONTAL,
+                PortStyle.NONE);
+
+        StringWriter stringWriter = new StringWriter();
+        DotWriter dotWriter = new DotWriter(stringWriter);
+
+        try {
+
+            String tmpDirPath = System.getProperty("java.io.tmpdir");
+            File dotTmp = new File(tmpDirPath + File.separator + "tavernaExtractorToArchimate.dot");
+            FileWriter fw = new FileWriter(dotTmp);
+            dotWriter = new DotWriter(fw);
+            dotWriter.writeGraph(con.getGraph());
+            fw.close();
+
+            // Dot to SVG
+            File svgTmp = new File(tmpDirPath + File.separator + "tavernaExtractorToArchimate.dot.svg");
+
+            String[] COMMAND = { TavernaExtractor.getDotLocation(), "-Tsvg", dotTmp.getAbsolutePath(), "-o", svgTmp.getAbsolutePath() };
+
+            LOGGER.debug("Running command '" + StringUtils.join(COMMAND, " ") + "'.");
+
+            ProcessBuilder proc = new ProcessBuilder(COMMAND);
+            Process process = proc.start();
+
+            InputStream stderr = process.getErrorStream();
+            InputStreamReader isr = new InputStreamReader(stderr);
+            BufferedReader br = new BufferedReader(isr);
+            String line = null;
+            while ((line = br.readLine()) != null) {
+                ;
+            }
+            process.waitFor();
+
+            // parse SVG
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            factory.setNamespaceAware(false);
+            DocumentBuilder builder;
+            builder = factory.newDocumentBuilder();
+            org.w3c.dom.Document doc = builder.parse(svgTmp);
+            XPath xpath = XPathFactory.newInstance().newXPath();
+
+            final String XPATH_EXPRESSION = "//g[@class='node']/text/text() | //g[@class='node']/text/@x | //g[@class='node']/text/@y";
+            XPathExpression expr = xpath.compile(XPATH_EXPRESSION);
+            Object result = expr.evaluate(doc, XPathConstants.NODESET);
+            NodeList nodes = (NodeList) result;
+
+            return transform(nodes);
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (ParserConfigurationException e) {
+            e.printStackTrace();
+        } catch (SAXException e) {
+            e.printStackTrace();
+        } catch (XPathExpressionException e) {
+            e.printStackTrace();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        return Collections.emptyMap();
+    }
+
+    private Map<String, Point> transform(NodeList nodeList) {
+
+        Map<String, Point> reducedMap = new HashMap<String, Point>();
+        Map<String, Point> map = new HashMap<String, Point>();
+        for (int i = 0; i < nodeList.getLength() - 1; i += 3) {
+
+            String key = nodeList.item(i + 2).getTextContent();
+            try {
+                Integer x = (int) Math.abs(Double.parseDouble(nodeList.item(i).getTextContent()));
+                Integer y = (int) Math.abs(Double.parseDouble(nodeList.item(i + 1).getTextContent()));
+                map.put(key, new Point(x, y));
+            } catch (NumberFormatException nfe) {
+                LOGGER.error("ERROR: Unable to convert to integer. " + nfe.getMessage());
+                map.put(key, new Point(1, 1));
+            }
+        }
+
+        for (Entry<String, Point> entry : map.entrySet()) {
+            for (IArchimateElement businessProcess : businessProcesses.getElements()) {
+                if (businessProcess.getName().equals(entry.getKey())) {
+                    reducedMap.put(entry.getKey(), entry.getValue());
+                }
+            }
+        }
+        return reducedMap;
+    }
+
+    private int[] getBounds(Map<String, Point> map, String name) {
+
+        if (map.containsKey(name)) {
+            return new int[] { map.get(name).x, map.get(name).y };
+        }
+        return new int[] { -1, -1 };
+    }
+
+    private int numberOfTriggringInputProcessors(Dataflow dataflow, Processor processor) {
+
+        @SuppressWarnings("unchecked")
+        List<ProcessorInputPort> inputs = (List<ProcessorInputPort>) processor.getInputPorts();
+        int inputsNumber = inputs.size();
+        for (ProcessorInputPort processorInput : processor.getInputPorts()) {
+
+            for (DataflowInputPort dataflowInput : dataflow.getInputPorts()) {
+                if (processorInput.getIncomingLink().getSource().getName().equals(dataflowInput.getName())) {
+                    inputsNumber--;
+                }
+            }
+        }
+        return inputsNumber;
+    }
+
+    private boolean isDotAvailable() {
+
+        if (dotLocation != null && !dotLocation.isEmpty()) {
+
+            try {
+                Paths.get(dotLocation);
+            }catch(InvalidPathException ipe){
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private void detailProcessorsOnLayers(List<? extends Processor> processors) throws IOException {
+        for (Processor processor : processors) {
+
+            String processorName = processor.getLocalName();
+
+            for (Activity<?> a : processor.getActivityList()) {
+
+                LOGGER.debug(processorName + " [" + processor.getActivityList().size() + "] -> "
+                        + a.getClass().getName());
+
+                printPortInformation(processor);
+
+                // TODO UnrecognizedActivity detected !!
+                if (a instanceof UnrecognizedActivity) {
+                    LOGGER.error("PROBLEM: UnrecognizedActivity detected! ");
+                }
+                // TODO DisabledActivity detected !!
+                // From the javadoc: A disabled activity is a wrapper for an Activity that is offline or similarly
+                // disabled
+                if (a instanceof DisabledActivity) {
+                    LOGGER.error("PROBLEM: DisabledActivity detected! ");
+                    // TODO: create a note element with information
+                }
+
+                // nested worklfow
+                if (a instanceof DataflowActivity) {
+                    DataflowActivity nestedWF = (DataflowActivity) a;
+                    detailProcessorsOnLayers(nestedWF.getNestedDataflow().getProcessors());
+                }
+
+                // processing RShellActivity
+                if (a instanceof RshellActivity) {
+
+                    processRShellActivity(businessFolder, infrastructureFolder, applicationFolder, relationsFolder,
+                            workflowApplicationComponent, processorProcessMap, callToolInvocationFunction, processor,
+                            processorName, a);
+                }
+
+                // processing ExternalToolActivity
+                if (a instanceof ExternalToolActivity) {
+                    ExternalToolActivityConfigurationBean conf = (ExternalToolActivityConfigurationBean) a
+                            .getConfiguration();
+
+                    if (conf != null && conf.getMechanismXML() != null) {
+
+                        String mechanismAsXMLString = conf.getMechanismXML();
+                        if (sshInvocation(mechanismAsXMLString)) { // SSH invocation
+
+                            // treat like as an web service dependency
+                            processToolActivity(businessFolder, infrastructureFolder, applicationFolder,
+                                    relationsFolder, workflowApplicationComponent, processorProcessMap,
+                                    callToolInvocationFunction, processor, processorName, a, true);
+
+                        } else { // local tool invocation
+
+                            processToolActivity(businessFolder, infrastructureFolder, applicationFolder,
+                                    relationsFolder, workflowApplicationComponent, processorProcessMap,
+                                    callToolInvocationFunction, processor, processorName, a, false);
+                        }
+                    }
+                }
+                // processing Beanshell activities
+                if (a instanceof BeanshellActivity) {
+                    processBeanshellActivity(infrastructureFolder, motivationFolder, applicationFolder,
+                            relationsFolder, workflowApplicationComponent, processorProcessMap, processor, a);
+                }
+                // processing REST activity
+                if (a instanceof RESTActivity) {
+                    processWebServiceActivity(businessFolder, infrastructureFolder, applicationFolder, relationsFolder,
+                            workflowApplicationComponent, processorProcessMap, callWebServiceApplicationFunction,
+                            processor, processorName, a);
+                }
+                // processing WSDL activity
+                // IMPORTANT: Service(=Activity) MUST BE ONLINE !! Otherwise it will be of type DisabledActivity
+                // From the javadoc: A disabled activity is a wrapper for an Activity that is offline or similarly
+                // disabled
+                if (a instanceof WSDLActivity) {
+                    processWebServiceActivity(businessFolder, infrastructureFolder, applicationFolder, relationsFolder,
+                            workflowApplicationComponent, processorProcessMap, callWebServiceApplicationFunction,
+                            processor, processorName, a);
+                }
+            }
+        }
+    }
+
+    private void validateDirectories(Path... dirs) throws IOException{
+
+        for(Path path : dirs) {
+            if (path == null || Files.notExists(path) || !Files.isDirectory(path) || !Files.isReadable(path)) {
+                throw new IOException("Directory '" + path + "' does not exists or is invalid.");
+            }
+        }
+    }
+
+    private List<String> cleanedClasspath(List<String> classpathEntries){
+
+        List<String> cleanedClasspathEntries = new ArrayList<String>();
+
+        for(String entry : classpathEntries)
+            if(entry.contains("taverna-2."))
+                cleanedClasspathEntries.add(entry);
+
+        return cleanedClasspathEntries;
+    }
+
+    private URL getJarLocationOfClass(Class clazz) {
+        return clazz.getProtectionDomain().getCodeSource().getLocation();
+    }
+
+    public void treatProcessors(List<? extends Processor> processors) {
+
+        for (Processor processor : dataflow.getProcessors()) {
+            IArchimateElement archimateElement = null;
+
+            // "value" processors are actually a constant input port, treat them special
+            if (ArchiUtils.isValueProcessor(processor)) {
+                IBusinessObject valueBusinessObject = ArchiUtils.initElement(factory.createBusinessObject(),
+                        processor.getLocalName(), businessFolder, valueObjects);
+                archimateElement = valueBusinessObject;
+                processorValueMap.put(processor, valueBusinessObject);
+
+            }
+
+            else {
+                // create the archimate element
+                IBusinessProcess process = ArchiUtils.initElement(factory.createBusinessProcess(),
+                        processor.getLocalName(), businessFolder, businessProcesses);
+                archimateElement = process;
+                // composition relation to parent workflow
+                ArchiUtils.initRelation(factory.createCompositionRelationship(), parentProcessWorkflow, process,
+                        relationsFolder, relations);
+                // put created elements to lookup map for later when creating relations
+                processorProcessMap.put(processor, process);
+            }
+
+            // add additional relationship between processor and workflow input port
+            for (ProcessorInputPort port : processor.getInputPorts()) {
+                for (IArchimateElement item : ArchiUtils.getElementsByname(
+                        port.getIncomingLink().getSource().getName(), inputPorts.getElements())) {
+                    IAccessRelationship readAccessRelation = ArchiUtils.initRelation(
+                            factory.createAccessRelationship(), archimateElement, item, relationsFolder, relations);
+                    readAccessRelation.setAccessType(IAccessRelationship.READ_ACCESS);
+                }
+            }
+
+            // add additional relationship between processor and workflow output port
+            for (ProcessorOutputPort port : processor.getOutputPorts()) {
+                for (Datalink datalink : port.getOutgoingLinks()) {
+                    for (IArchimateElement item : ArchiUtils.getElementsByname(datalink.getSink().getName(),
+                            outputPorts.getElements())) {
+                        IAccessRelationship readAccessRelation = ArchiUtils.initRelation(
+                                factory.createAccessRelationship(), archimateElement, item, relationsFolder, relations);
+                        readAccessRelation.setAccessType(IAccessRelationship.WRITE_ACCESS);
+                    }
+                }
+            }
+        }
+
+        // connect all starting processors with the start event
+        List<Processor> startingProcessors = findStartingProcessors(dataflow);
+        for (Processor processor : startingProcessors) {
+
+            if (startingProcessors.size() <= 1) {
+                ArchiUtils.initRelation(factory.createTriggeringRelationship(), startEvent,
+                        processorProcessMap.get(processor), relationsFolder, relations);
+            }
+            // additional AND junction
+            else {
+                if (andJunctionStart == null) {
+                    andJunctionStart = ArchiUtils.initElement(factory.createAndJunction(), "AndJunction",
+                            businessFolder, businessProcesses);
+                    ArchiUtils.initRelation(factory.createTriggeringRelationship(), startEvent, andJunctionStart,
+                            relationsFolder, relations);
+                }
+                ArchiUtils.initRelation(factory.createTriggeringRelationship(), andJunctionStart,
+                        processorProcessMap.get(processor), relationsFolder, relations);
+            }
+        }
+
+        // connect all ending processors with the end event
+        List<Processor> endprocessors = findEndProcessors(dataflow);
+        for (Processor processor : endprocessors) {
+
+            if (endprocessors.size() <= 1) {
+                ArchiUtils.initRelation(factory.createTriggeringRelationship(), processorProcessMap.get(processor),
+                        endEvent, relationsFolder, relations);
+            }
+            // additional AND junction
+            else {
+                if (andJunctionEnd == null) {
+                    andJunctionEnd = ArchiUtils.initElement(factory.createAndJunction(), "EndingAndJunction",
+                            businessFolder, businessProcesses);
+                    ArchiUtils.initRelation(factory.createTriggeringRelationship(), andJunctionEnd, endEvent,
+                            relationsFolder, relations);
+                }
+                ArchiUtils.initRelation(factory.createTriggeringRelationship(), processorProcessMap.get(processor),
+                        andJunctionEnd, relationsFolder, relations);
+            }
+        }
+
+        //
+        // second pass - add relations between processes
+        //
+        Stack<Processor> processorStack = new Stack<Processor>();
+        for (Processor processor : dataflow.getProcessors()) {
+            boolean isValueProcessor = ArchiUtils.isValueProcessor(processor);
+
+            for (ProcessorOutputPort processorOutputPort : processor.getOutputPorts()) {
+
+                LOGGER.debug("Process processorOutputPort = '" + processorOutputPort.getName() + "'");
+
+                for (Datalink datalink : processorOutputPort.getOutgoingLinks()) {
+
+                    EventHandlingInputPort sink = datalink.getSink();
+
+                    if (sink instanceof ProcessorInputPortImpl) {
+
+                        boolean split = false;
+                        IOrJunction orJunction = null;
+
+                        // after this processor we need an Or-junction
+                        if (datalink.getSource().getDepth() - datalink.getSink().getDepth() > 0) {
+
+                            split = true;
+
+                            orJunction = ArchiUtils.initElement(factory.createOrJunction(), "OrJunctionMerge",
+                                    businessFolder, businessProcesses);
+
+                            // if (!loopsJunctions.containsKey(processor)) {
+                            loopsJunctions.put(processor, orJunction);
+                            // }
+
+                            processorStack.push(processor);
+                        }
+
+                        // after this processor we need an Or-junction
+                        if (datalink.getSource().getDepth() - datalink.getSink().getDepth() < 0) {
+                            split = true;
+                            orJunction = ArchiUtils.initElement(factory.createOrJunction(), "OrJunctionSplit",
+                                    businessFolder, businessProcesses);
+
+                            // if (!loopsJunctions.containsKey(processor)) {
+                            loopsJunctions.put(processor, orJunction);
+                            // }
+
+                            if (!processorStack.isEmpty()) {
+                                Processor startProcessor = processorStack.pop();
+
+                                // draw loop back relation
+                                IOrJunction splitJunction = loopsJunctions.get(startProcessor);
+                                IOrJunction mergeJunction = loopsJunctions.get(processor);
+
+                                ArchiUtils.initRelation(factory.createTriggeringRelationship(), mergeJunction,
+                                        splitJunction, relationsFolder, relations);
+
+                                LOGGER.debug("loop detected between [" + startProcessor.getLocalName() + "] --> ["
+                                        + processor.getLocalName() + "]");
+                            }
+                        }
+
+                        Processor targetProcessor = ((ProcessorInputPortImpl) sink).getProcessor();
+                        IBusinessProcess targetProcess = processorProcessMap.get(targetProcessor);
+
+                        if (isValueProcessor) {
+
+                            // value processors are constants, we treat them like process inputs
+                            IBusinessObject sourceBusinessObject = processorValueMap.get(processor);
+                            // make sure we only create one triggering relation combining two elements
+                            if (!ArchiUtils.containsRelation(targetProcess, sourceBusinessObject, relations)) {
+                                ArchiUtils.initRelation(factory.createTriggeringRelationship(), sourceBusinessObject,
+                                        targetProcess, relationsFolder, relations);
+                            }
+                        } else {
+
+                            // 1. create relation
+                            IBusinessProcess sourceProcess = processorProcessMap.get(processor);
+
+                            // check if source processor has more than one input port. if so, we need a additional AND
+                            // junction
+                            if (numberOfTriggringInputProcessors(dataflow, processor) > 1) {
+
+                                // have to do that check, otherwise we will initialize (which means create and draw
+                                // ) an Archimate element every time
+                                if (!processorInputMap.containsKey(processor)) {
+
+                                    // create additional AND Junction
+                                    processorInputMap.put(processor, ArchiUtils.initElement(
+                                            factory.createAndJunction(), processor.getLocalName() + "_AND",
+                                            businessFolder, businessProcesses));
+                                }
+                            }
+
+                            // make sure we only create one triggering relation combining two elements
+                            if (!ArchiUtils.containsRelation(targetProcess, sourceProcess, relations)) {
+                                if (split) {
+                                    ArchiUtils.initRelation(factory.createTriggeringRelationship(), sourceProcess,
+                                            orJunction, relationsFolder, relations);
+                                    ArchiUtils.initRelation(factory.createTriggeringRelationship(), orJunction,
+                                            targetProcess, relationsFolder, relations);
+
+                                } else {
+                                    ArchiUtils.initRelation(factory.createTriggeringRelationship(), sourceProcess,
+                                            targetProcess, relationsFolder, relations);
+                                }
+                                split = false; // reset flags!
+                            }
+
+                            // 2. create business object
+                            IBusinessObject businessObject = ArchiUtils.initElement(factory.createBusinessObject(),
+                                    sink.getName(), businessFolder, businessObjects);
+
+                            LOGGER.debug("\t BusinessObject for datalink '" + datalink.getSource().getName() + " -> "
+                                    + sink.getName() + "' created.");
+
+                            if (processorObjectMapping.get(processor) == null) {
+                                processorObjectMapping.put(processor, new ArrayList<IBusinessObject>());
+                            }
+                            processorObjectMapping.get(processor).add(businessObject);
+
+                            ArchiUtils.initAccessRelation(factory.createAccessRelationship(), sourceProcess,
+                                    businessObject, relationsFolder, relations, IAccessRelationship.WRITE_ACCESS);
+
+                            // 3. create read access relation from target process to business object
+                            ArchiUtils.initAccessRelation(factory.createAccessRelationship(), targetProcess,
+                                    businessObject, relationsFolder, relations, IAccessRelationship.READ_ACCESS);
+                        }
+                    } else { // TODO these are likely workflow output ports, need to be treated special
+                        // System.out.println("Unknown sink type for processor " + processor + ", dataLink " + datalink
+                        // + ": " + sink.getClass());
+                    }
+                }
+            }
+        }
+
+    }
+
+    @Override
+    public String getName() {
+        return null;
+    }
+
+    @Override
+    public String getSymbolicName() {
+        return null;
+    }
+
+    @Override
+    public Version getVersion() {
+        return null;
+    }
+
+    @Override
+    public EnumSet<OperatingSystem> getSupportedOperatingSystems() {
+        return null;
+    }
+
+    @Override
+    public HashMap<String, Parameter> getParameters() {
+        return null;
+    }
+
+    @Override
+    public String extract(Endpoint endpoint, boolean b) throws Exception {
+        return null;
+    }
+}