LearnPAd/learnpad

View on GitHub
lp-model-verification/verification-component-deadlock-plugin/src/main/java/eu/learnpad/verification/plugin/pn/impexp/PNImport.java

Summary

Maintainability
F
2 wks
Test Coverage
/**
 * LearnPAd - Verification Component - Deadlock Check Plugin
 * 
 *  Copyright (C) 2015 Unicam
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *   
 * @author Damiano Falcioni - Unicam <damiano.falcioni@gmail.com>
 */

package eu.learnpad.verification.plugin.pn.impexp;

import java.util.ArrayList;

import javax.xml.xpath.XPathConstants;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import eu.learnpad.verification.plugin.pn.PetriNet;
import eu.learnpad.verification.plugin.pn.PetriNet.PL;
import eu.learnpad.verification.plugin.pn.PetriNet.PT;
import eu.learnpad.verification.plugin.pn.PetriNet.TR;
import eu.learnpad.verification.plugin.pn.impexp.PNMapping.GeneratedElements;
import eu.learnpad.verification.plugin.utils.Utils;
import eu.learnpad.verification.plugin.utils.XMLUtils;

public class PNImport {
    
    public static boolean isOMGBPMN2(Document model){
        try{
            String queryRoot = "/*[namespace-uri()='http://www.omg.org/spec/BPMN/20100524/MODEL' and local-name()='definitions']";
            Node bpmnRootNode =  (Node) XMLUtils.execXPath(model.getDocumentElement(), queryRoot, XPathConstants.NODE);
            if(bpmnRootNode!=null)
                return true;
        }catch(Exception e){}
        return false;
    }
    
    public static boolean isADOXX(Document model){
        try{
            String queryRoot = "/*[local-name()='ADOXML' or local-name()='adoxml']";
            Node bpmnRootNode =  (Node) XMLUtils.execXPath(model.getDocumentElement(), queryRoot, XPathConstants.NODE);
            if(bpmnRootNode!=null)
                return true;
        }catch(Exception e){}
        return false;
    }
    
    public static boolean isPNML(Document model){
        try{
            String queryRoot = "/*[local-name()='pnml']";
            Node pnmlRootNode =  (Node) XMLUtils.execXPath(model.getDocumentElement(), queryRoot, XPathConstants.NODE);
            if(pnmlRootNode!=null)
                return true;
        }catch(Exception e){}
        return false;
    }
    
    /**
     * Generate a PetriNet from the provided OMG BPMN2 Standard.
     * Supported BPMN2 elements are: startEvent, endEvent, task, userTask, serviceTask, manualTask, businessRuleTask, receiveTask, sendTask, scriptTask, intermediateCatchEvent, intermediateThrowEvent, adHocSubProcess, subProcess, transaction, callActivity, choreographyTask, subChoreography, callChoreography, standardLoopCharacteristics, boundaryEvent, parallelGateway, exclusiveGateway, eventBasedGateway, inclusiveGateway, complexGateway, sequenceFlow, messageFlow, participant.
     * The function provide a personalized mapping for every element.
     * @param bpmnXml The BPMN2 model
     * @return The PetriNet
     * @throws Exception
     */
    //FIXME: rimuovere i conversation dato che non saranno che non si gestisce il conversationlink?
    //FIXME: analizzare meglio i task che non continuano (transizione senza place uscenti)
    //FIXME: loop con numero specificato mettere un place con dentro tanti token quanti sono i loop che entra nella transizione del loop: aggiungere p1(n)>t1 al mapping del loop con p1 escluso dal deadlock
    //FIXME: gestire i parallel event gateways!!! pag 298 eventGatewayType=parallel
    //FIXME: una sequenceflow che esce da un activity può avere una condizione, quindi partire o meno (solo se ci sono almeno 2 fresce uscenti)
    public static PetriNet generateFromBPMN(Document bpmnXml) throws Exception{
        if(!isOMGBPMN2(bpmnXml))
            throw new Exception("ERROR: The provided model is not a valid OMG standard BPMN2.0 model");
        
        PNMapping pnm = new PNMapping();
        
        pnm.addMapping("task : p>t ; in:sequence=p, message=t ; out:sequence=t, message=t, bound=p");
        pnm.addMapping("start: p(1)>t ; in: ; out:sequence=t");
        pnm.addMapping("startMsg: p>t ; in: message=p ; out:sequence=t");
        pnm.addMapping("end|terminateEventDefinition|errorEventDefinition: p ; in: sequence=p ; out: ");
        pnm.addMapping("endMsg|terminateEventDefinitionMsg|errorEventDefinitionMsg: p>t,t>p1 ; in: sequence=p ; out: message=t");
        pnm.addMapping("loop: p>t0,t0>p0,p0>t,p0>t1,t1>p ; in:sequence=p, message=t0 ; out:sequence=t, message=t0, bound=p");
        pnm.addMapping("xor|inclusiveComplexG|eventG : p ; in:sequence=p ; out:sequence=p");
        pnm.addMapping("and : t ; in:sequence=t ; out:sequence=t");
        pnm.addMapping("bound : t ; in:bound=t ; out:sequence=t");
        
        String startQuery = "//*[local-name()='startEvent']";
        String endQuery = "//*[local-name()='endEvent']";
        //String endSpecialQuery = "./*[local-name()='terminateEventDefinition']|./*[local-name()='errorEventDefinition']";
        String anyTaskQuery = "//*[local-name()='task']|//*[local-name()='userTask']|//*[local-name()='serviceTask']|//*[local-name()='manualTask']|//*[local-name()='businessRuleTask']|//*[local-name()='receiveTask']|//*[local-name()='sendTask']|//*[local-name()='scriptTask']|//*[local-name()='intermediateCatchEvent']|//*[local-name()='intermediateThrowEvent']|//*[local-name()='adHocSubProcess']|//*[local-name()='subProcess']|//*[local-name()='transaction']|//*[local-name()='callActivity']|//*[local-name()='choreographyTask']|//*[local-name()='subChoreography']|//*[local-name()='callChoreography']";
        //String anyTaskLoopQuery = "./*[local-name()='standardLoopCharacteristics']|./*[local-name()='multiInstanceLoopCharacteristics']";
        String anyTaskLoopQuery = "./*[local-name()='standardLoopCharacteristics']";
        String boundaryTaskQuery = "//*[local-name()='boundaryEvent']";
        //String andQuery = "//*[local-name()='inclusiveGateway']|//*[local-name()='eventBasedGateway']|//*[local-name()='complexGateway']|//*[local-name()='parallelGateway']";
        String andQuery = "//*[local-name()='parallelGateway']";
        String xorQuery = "//*[local-name()='exclusiveGateway']";
        String eventGatewayQuery = "//*[local-name()='eventBasedGateway']";
        String inclusiveComplexGatewayQuery = "//*[local-name()='inclusiveGateway']|//*[local-name()='complexGateway']";
        
        String sequenceFlowQuery = "//*[local-name()='sequenceFlow']";
        String messageFlowQuery = "//*[local-name()='messageFlow']";
        String sequenceFlowExcludeFromToElemList = "participant"; //Se ci sono sequence flow da/verso una pool allora non li considero
        String messageFlowExcludeFromToElemList = "participant"; //Se ci sono messaggi da/verso una pool allora non li considero in quanto per la verifica si assumerebbe che il messaggio sia inviato/ricevuto sempre perci� � come se non ci fosse; se si toglie, vanno mappati a parte un place con un token ed una transizione per ogni messaggio
        
        String modelId = bpmnXml.getDocumentElement().getAttribute("id");
        
        NodeList startEventNodeList =  (NodeList) XMLUtils.execXPath(bpmnXml.getDocumentElement(), startQuery, XPathConstants.NODESET);
        for(int i=0;i<startEventNodeList.getLength();i++){
            String id = startEventNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            
            boolean isMessageStart = false;
            NodeList messagesToStartNodeList =  (NodeList) XMLUtils.execXPath(bpmnXml.getDocumentElement(), "//*[local-name()='messageFlow' and (@targetRef="+XMLUtils.escapeXPathField(id)+")]", XPathConstants.NODESET);
            for(int x=0;x<messagesToStartNodeList.getLength();x++){
                String sourceId = messagesToStartNodeList.item(x).getAttributes().getNamedItem("sourceRef").getNodeValue();
                String sourceType =  ((Node) XMLUtils.execXPath(bpmnXml.getDocumentElement(), "//*[@id="+XMLUtils.escapeXPathField(sourceId)+"]", XPathConstants.NODE)).getLocalName();
                if(!messageFlowExcludeFromToElemList.contains(sourceType))
                    isMessageStart = true;
            }
            
            String elemType = "start";
            if(isMessageStart)
                elemType += "Msg";
            float[] xy = getBPMNElementCoordinatesXY(bpmnXml, id);
            
            GeneratedElements ge = pnm.processElement(id, elemType, id, xy[0], xy[1]);
            
            String poolId = getBPMNElementPool(bpmnXml, id);
            for(PL place:ge.placeList)
                place.addInfo("poolId", poolId);
            for(TR transition:ge.transitionList)
                transition.addInfo("poolId", poolId);
            //map dependent
            ge.transitionList[0].addInfo("isEntryPoint", "true");
        }
        
        NodeList endEventNodeList =  (NodeList) XMLUtils.execXPath(bpmnXml.getDocumentElement(), endQuery, XPathConstants.NODESET);
        for(int i=0;i<endEventNodeList.getLength();i++){
            String id = endEventNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            
            boolean isMessageEnd = false;
            NodeList messagesFromEndNodeList =  (NodeList) XMLUtils.execXPath(bpmnXml.getDocumentElement(), "//*[local-name()='messageFlow' and (@sourceRef="+XMLUtils.escapeXPathField(id)+")]", XPathConstants.NODESET);
            for(int x=0;x<messagesFromEndNodeList.getLength();x++){
                String targetId = messagesFromEndNodeList.item(x).getAttributes().getNamedItem("targetRef").getNodeValue();
                String targetType =  ((Node) XMLUtils.execXPath(bpmnXml.getDocumentElement(), "//*[@id="+XMLUtils.escapeXPathField(targetId)+"]", XPathConstants.NODE)).getLocalName();
                if(!messageFlowExcludeFromToElemList.contains(targetType))
                    isMessageEnd = true;
            }
            
            String elemType = "end";
            if(isMessageEnd)
                elemType += "Msg";
            float[] xy = getBPMNElementCoordinatesXY(bpmnXml, id);
            GeneratedElements ge = pnm.processElement(id, elemType, id, xy[0], xy[1]);
            
            String poolId = getBPMNElementPool(bpmnXml, id);
            for(PL place:ge.placeList)
                place.addInfo("poolId", poolId);
            for(TR transition:ge.transitionList)
                transition.addInfo("poolId", poolId);
            
            //map dependent
            if(elemType.equals("endMsg"))
                ge.transitionList[0].addInfo("isEntryPoint", "true");
            else
                ge.placeList[0].addInfo("isEntryPoint", "true");
        }
        
        NodeList anyTaskNodeList =  (NodeList) XMLUtils.execXPath(bpmnXml.getDocumentElement(), anyTaskQuery, XPathConstants.NODESET);
        for(int i=0;i<anyTaskNodeList.getLength();i++){
            String id = anyTaskNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            String elemType = "task";
            NodeList taskLoopDefinitionNodeList =  (NodeList) XMLUtils.execXPath(anyTaskNodeList.item(i), anyTaskLoopQuery, XPathConstants.NODESET);
            if(taskLoopDefinitionNodeList.getLength()>0)
                elemType = "loop";
            float[] xy = getBPMNElementCoordinatesXY(bpmnXml, id);
            GeneratedElements ge = pnm.processElement(id, elemType, id, xy[0], xy[1]);
            
            if(anyTaskNodeList.item(i).getAttributes().getNamedItem("calledElement")!=null){
                String calledElement = anyTaskNodeList.item(i).getAttributes().getNamedItem("calledElement").getNodeValue();
                for(PL place: ge.placeList)
                    place.addInfo("calledElement", calledElement);
                for(TR transition: ge.transitionList)
                    transition.addInfo("calledElement", calledElement);
            }
            
            String poolId = getBPMNElementPool(bpmnXml, id);
            for(PL place:ge.placeList)
                place.addInfo("poolId", poolId);
            for(TR transition:ge.transitionList)
                transition.addInfo("poolId", poolId);
            
            //map dependent
            if(elemType.equals("task"))
                ge.transitionList[0].addInfo("isEntryPoint", "true");
            else
                for(TR transition:ge.transitionList)
                    if(transition.name.startsWith("t0"))
                        transition.addInfo("isEntryPoint", "true");
        }
        
        NodeList andNodeList =  (NodeList) XMLUtils.execXPath(bpmnXml.getDocumentElement(), andQuery, XPathConstants.NODESET);
        for(int i=0;i<andNodeList.getLength();i++){
            String id = andNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            float[] xy = getBPMNElementCoordinatesXY(bpmnXml, id);
            GeneratedElements ge = pnm.processElement(id, "and", id, xy[0], xy[1]);
            
            String poolId = getBPMNElementPool(bpmnXml, id);
            for(PL place:ge.placeList)
                place.addInfo("poolId", poolId);
            for(TR transition:ge.transitionList)
                transition.addInfo("poolId", poolId);
            
            //map dependent
            ge.transitionList[0].addInfo("isEntryPoint", "true");
        }
        
        NodeList xorNodeList =  (NodeList) XMLUtils.execXPath(bpmnXml.getDocumentElement(), xorQuery, XPathConstants.NODESET);
        for(int i=0;i<xorNodeList.getLength();i++){
            String id = xorNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            float[] xy = getBPMNElementCoordinatesXY(bpmnXml, id);
            GeneratedElements ge = pnm.processElement(id, "xor", id, xy[0], xy[1]);
            
            String poolId = getBPMNElementPool(bpmnXml, id);
            for(PL place:ge.placeList)
                place.addInfo("poolId", poolId);
            for(TR transition:ge.transitionList)
                transition.addInfo("poolId", poolId);
            
            //map dependent
            ge.placeList[0].addInfo("isEntryPoint", "true");
        }
        
        NodeList eventGNodeList =  (NodeList) XMLUtils.execXPath(bpmnXml.getDocumentElement(), eventGatewayQuery, XPathConstants.NODESET);
        for(int i=0;i<eventGNodeList.getLength();i++){
            String id = eventGNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            float[] xy = getBPMNElementCoordinatesXY(bpmnXml, id);
            GeneratedElements ge = pnm.processElement(id, "eventG", id, xy[0], xy[1]);
            
            String poolId = getBPMNElementPool(bpmnXml, id);
            for(PL place:ge.placeList)
                place.addInfo("poolId", poolId);
            for(TR transition:ge.transitionList)
                transition.addInfo("poolId", poolId);
            
            //map dependent
            ge.placeList[0].addInfo("isEntryPoint", "true");
        }
        
        NodeList inclusiveComplexGNodeList =  (NodeList) XMLUtils.execXPath(bpmnXml.getDocumentElement(), inclusiveComplexGatewayQuery, XPathConstants.NODESET);
        for(int i=0;i<inclusiveComplexGNodeList.getLength();i++){
            String id = inclusiveComplexGNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            String defaultSequenceFlowId = "";
            if(inclusiveComplexGNodeList.item(i).getAttributes().getNamedItem("default")!=null)
                defaultSequenceFlowId = inclusiveComplexGNodeList.item(i).getAttributes().getNamedItem("default").getNodeValue();
            float[] xy = getBPMNElementCoordinatesXY(bpmnXml, id);
            GeneratedElements ge = pnm.processElement(id, "inclusiveComplexG", id, xy[0], xy[1]);
            if(ge.placeList.length==1 && ge.placeList[0]!=null)
                ge.placeList[0].addInfo("defaultSequenceFlowId", defaultSequenceFlowId);
            
            String poolId = getBPMNElementPool(bpmnXml, id);
            for(PL place:ge.placeList)
                place.addInfo("poolId", poolId);
            for(TR transition:ge.transitionList)
                transition.addInfo("poolId", poolId);
            
            //map dependent
            ge.placeList[0].addInfo("isEntryPoint", "true");
        }
        
        NodeList boundaryTaskNodeList =  (NodeList) XMLUtils.execXPath(bpmnXml.getDocumentElement(), boundaryTaskQuery, XPathConstants.NODESET);
        for(int i=0;i<boundaryTaskNodeList.getLength();i++){
            String id = boundaryTaskNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            float[] xy = getBPMNElementCoordinatesXY(bpmnXml, id);
            String sourceId = boundaryTaskNodeList.item(i).getAttributes().getNamedItem("attachedToRef").getNodeValue();
            if(sourceId.isEmpty())
                throw new Exception("ERROR: Attribute 'attachedToRef' not defined for the object " + id);
            
            GeneratedElements ge = pnm.processElement(id, "bound", id, xy[0], xy[1]);
            GeneratedElements ge1 = pnm.processRelation(id, "bound", sourceId, id);    
            
            String poolId = getBPMNElementPool(bpmnXml, id);
            for(PL place:ge.placeList)
                place.addInfo("poolId", poolId);
            for(TR transition:ge.transitionList)
                transition.addInfo("poolId", poolId);
            for(PL place:ge1.placeList)
                place.addInfo("poolId", poolId);
            for(TR transition:ge1.transitionList)
                transition.addInfo("poolId", poolId);
            
            //map dependent
            ge.transitionList[0].addInfo("isEntryPoint", "true");
        }
        
        NodeList sequenceFlowNodeList =  (NodeList) XMLUtils.execXPath(bpmnXml.getDocumentElement(), sequenceFlowQuery, XPathConstants.NODESET);
        for(int i=0;i<sequenceFlowNodeList.getLength();i++){
            String id = sequenceFlowNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            String sourceId = sequenceFlowNodeList.item(i).getAttributes().getNamedItem("sourceRef").getNodeValue();
            String targetId = sequenceFlowNodeList.item(i).getAttributes().getNamedItem("targetRef").getNodeValue();    
            String sourceType =  ((Node) XMLUtils.execXPath(bpmnXml.getDocumentElement(), "//*[@id="+XMLUtils.escapeXPathField(sourceId)+"]", XPathConstants.NODE)).getLocalName();
            String targetType =  ((Node) XMLUtils.execXPath(bpmnXml.getDocumentElement(), "//*[@id="+XMLUtils.escapeXPathField(targetId)+"]", XPathConstants.NODE)).getLocalName();
            
            if(sourceId.isEmpty()) throw new Exception("ERROR: Attribute 'sourceRef' missing for the relation " + id);
            if(targetId.isEmpty()) throw new Exception("ERROR: Attribute 'targetRef' missing for the relation " + id);
            if(sourceType.isEmpty()) throw new Exception("ERROR: Can not identify the element " + sourceId);
            if(targetType.isEmpty()) throw new Exception("ERROR: Can not identify the element " + targetId);
            
            if(sequenceFlowExcludeFromToElemList.contains(sourceType) || sequenceFlowExcludeFromToElemList.contains(targetType))
                continue;
            
            GeneratedElements ge = pnm.processRelation(id, "sequence", sourceId, targetId);
            
            String poolId = getBPMNElementPool(bpmnXml, id);
            for(PL place:ge.placeList)
                place.addInfo("poolId", poolId);
            for(TR transition:ge.transitionList)
                transition.addInfo("poolId", poolId);
        }
        
        NodeList messageFlowNodeList =  (NodeList) XMLUtils.execXPath(bpmnXml.getDocumentElement(), messageFlowQuery, XPathConstants.NODESET);
        for(int i=0;i<messageFlowNodeList.getLength();i++){
            String id = messageFlowNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            String sourceId = messageFlowNodeList.item(i).getAttributes().getNamedItem("sourceRef").getNodeValue();
            String targetId = messageFlowNodeList.item(i).getAttributes().getNamedItem("targetRef").getNodeValue();
            String sourceType =  ((Node) XMLUtils.execXPath(bpmnXml.getDocumentElement(), "//*[@id="+XMLUtils.escapeXPathField(sourceId)+"]", XPathConstants.NODE)).getLocalName();
            String targetType =  ((Node) XMLUtils.execXPath(bpmnXml.getDocumentElement(), "//*[@id="+XMLUtils.escapeXPathField(targetId)+"]", XPathConstants.NODE)).getLocalName();

            if(sourceId.isEmpty()) throw new Exception("ERROR: Attribute 'sourceRef' missing for the relation " + id);
            if(targetId.isEmpty()) throw new Exception("ERROR: Attribute 'targetRef' missing for the relation " + id);
            if(sourceType.isEmpty()) throw new Exception("ERROR: Can not identify the element " + sourceId);
            if(targetType.isEmpty()) throw new Exception("ERROR: Can not identify the element " + targetId);
            
            if(messageFlowExcludeFromToElemList.contains(sourceType) || messageFlowExcludeFromToElemList.contains(targetType))
                continue;
            
            GeneratedElements genEl = pnm.processRelation(id, "message", sourceId, targetId);
            if(genEl.placeList.length>0)
                genEl.placeList[0].excludeFromDeadlockCheck = true;
            
        }
        
        PetriNet pn = pnm.generatePN(modelId);
        postProcessEventGateways(pn, "eventG", "message");
        postProcessInclusiveComplexGateways(pn, "inclusiveComplexG");
        pn.updateStartListCheckingFlow(); //richiamando questa funzione sistemo i bpmn fatti male che iniziano senza uno startevent necessario quando un processo inizia ad es da un intermediate event che parte da un segnale o da un altro processo
        return pn;
    }
    

    private static float[] getBPMNElementCoordinatesXY(Document bpmnXml, String elementId) throws Exception{
        String x = (String) XMLUtils.execXPath(bpmnXml.getDocumentElement(), "//*[local-name()='BPMNShape' and @bpmnElement=" + XMLUtils.escapeXPathField(elementId) + "]/*[local-name()='Bounds']/@x", XPathConstants.STRING);
        String y = (String) XMLUtils.execXPath(bpmnXml.getDocumentElement(), "//*[local-name()='BPMNShape' and @bpmnElement=" + XMLUtils.escapeXPathField(elementId) + "]/*[local-name()='Bounds']/@y", XPathConstants.STRING);
        if(x.isEmpty()) x = "0";
        if(y.isEmpty()) y = "0";
        return new float[]{Float.valueOf(x), Float.valueOf(y)};
    }
    
    private static String getBPMNElementPool(Document bpmnXml, String elementId) throws Exception{
        return (String) XMLUtils.execXPath(bpmnXml.getDocumentElement(), "//*[local-name()='process'][.//*[@id=" + XMLUtils.escapeXPathField(elementId) + "]]/@id", XPathConstants.STRING);
    }
    
    /**
     * Generate a list of PetriNets, one for each BPMN model (modeltype=Business process diagram (BPMN 2.0)) inside the Adoxx xml provided.
     * 
     * @param bpmnXml The Adoxx modelset containing BPMN models
     * @return The PetriNet list
     * @throws Exception
     */
    public static PetriNet[] generateFromAdoxxBPMN(Document adoxxXml) throws Exception{
        /* To Remember:
         * - id are unique between all the models
         * - name are unique only inside a model. Es: 2 model can have a task with the same name.
         * */
        if(!isADOXX(adoxxXml))
            throw new Exception("ERROR: The provided model is not a valid ADOXX model");
        
        PNMapping pnm = new PNMapping();
        
        pnm.addMapping("task : p>t ; in:sequence=p, message=t ; out:sequence=t, message=t, bound=p");
        pnm.addMapping("start: p(1)>t ; in: ; out:sequence=t");
        pnm.addMapping("startMsg: p>t ; in: message=p ; out:sequence=t");
        pnm.addMapping("end|terminateEventDefinition|errorEventDefinition: p ; in: sequence=p ; out: ");
        pnm.addMapping("endMsg|terminateEventDefinitionMsg|errorEventDefinitionMsg: p>t,t>p1 ; in: sequence=p ; out: message=t");
        pnm.addMapping("loop: p>t0,t0>p0,p0>t,p0>t1,t1>p ; in:sequence=p, message=t0 ; out:sequence=t, message=t0, bound=p");
        pnm.addMapping("xor|inclusiveComplexG|eventG : p ; in:sequence=p ; out:sequence=p");
        pnm.addMapping("and : t ; in:sequence=t ; out:sequence=t");
        pnm.addMapping("bound : t ; in:bound=t ; out:sequence=t");
        
        String startQuery = ".//*[@id!='' and @class='Start Event']";
        String endQuery = ".//*[@id!='' and @class='End Event']";
        String anyTaskQuery = ".//*[@id!='' and @class='Task']|.//*[@id!='' and @class='Intermediate Event (sequence flow)']|.//*[@id!='' and @class='Sub-Process']";
        String anyTaskLoopQuery = "./*[@name='Loop type' and text()!='Not specified']";
        String boundaryTaskQuery = ".//*[@id!='' and @class='Intermediate Event (boundary)']";
        String andQuery = ".//*[@id!='' and @class='Non-exclusive Gateway']|.//*[@id!='' and @class='Non-exclusive Gateway (converging)']";
        String xorQuery = ".//*[@id!='' and @class='Exclusive Gateway']";
        
        String eventGatewayQuery = ".//*[@name='Type']";
        String inclusiveComplexGatewayQuery = ".//*[@name='Gateway type']";
        String sequenceFlowQuery = ".//*[@id!='' and @class='Subsequent']";
        String messageFlowQuery = ".//*[@id!='' and @class='Message Flow']";
        String sequenceFlowExcludeFromToElemList = ""; //Se ci sono sequence flow da/verso una pool allora non li considero 
        String messageFlowExcludeFromToElemList = "Pool (collapsed) Lane"; //Se ci sono messaggi da/verso una pool allora non li considero in quanto per la verifica si assumerebbe che il messaggio sia inviato/ricevuto sempre perci� � come se non ci fosse; se si toglie, vanno mappati a parte un place con un token ed una transizione per ogni messaggio
        
        NodeList bpmnModelElList =  (NodeList) XMLUtils.execXPath(adoxxXml.getDocumentElement(), "//*[@modeltype='Business process diagram (BPMN 2.0)']", XPathConstants.NODESET);
        PetriNet[] ret = new PetriNet[bpmnModelElList.getLength()];
        
        for(int modelIndex=0;modelIndex<bpmnModelElList.getLength();modelIndex++) {
            
            pnm.resetProcessed();
            Node bpmnModelEl = bpmnModelElList.item(modelIndex);
            String modelId = bpmnModelEl.getAttributes().getNamedItem("id").getNodeValue();
            
            
            NodeList startEventNodeList =  (NodeList) XMLUtils.execXPath(bpmnModelEl, startQuery, XPathConstants.NODESET);
            for(int i=0;i<startEventNodeList.getLength();i++){
                String id = startEventNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
                String name = startEventNodeList.item(i).getAttributes().getNamedItem("name").getNodeValue();
                
                boolean isMessageStart = false;
                NodeList messagesToStartNodeList =  (NodeList) XMLUtils.execXPath(bpmnModelEl, ".//*[@id!='' and @class='Message Flow' and (.//@instance="+XMLUtils.escapeXPathField(name)+")]", XPathConstants.NODESET);
                for(int x=0;x<messagesToStartNodeList.getLength();x++){
                    String sourceType = (String) XMLUtils.execXPath(messagesToStartNodeList.item(x), "./*[local-name()='FROM' or local-name()='from']/@class", XPathConstants.STRING);
                    if(!messageFlowExcludeFromToElemList.contains(sourceType))
                        isMessageStart = true;
                }
                
                String elemType = "start";
                if(isMessageStart)
                    elemType += "Msg";
                float[] xy = getAdoxxElementCoordinatesXY(adoxxXml, id);
                GeneratedElements ge = pnm.processElement(id, elemType, id, xy[0], xy[1]);
                
                String poolId = getAdoxxElementPool(adoxxXml, id);
                for(PL place:ge.placeList)
                    place.addInfo("poolId", poolId);
                for(TR transition:ge.transitionList)
                    transition.addInfo("poolId", poolId);
                
                //map dependent
                ge.transitionList[0].addInfo("isEntryPoint", "true");
            }
            
            NodeList endEventNodeList =  (NodeList) XMLUtils.execXPath(bpmnModelEl, endQuery, XPathConstants.NODESET);
            for(int i=0;i<endEventNodeList.getLength();i++){
                String id = endEventNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
                String name = endEventNodeList.item(i).getAttributes().getNamedItem("name").getNodeValue();
                
                boolean isMessageEnd = false;
                NodeList messegesFromEndNodeList =  (NodeList) XMLUtils.execXPath(bpmnModelEl, ".//*[@id!='' and @class='Message Flow' and (.//@instance="+XMLUtils.escapeXPathField(name)+")]", XPathConstants.NODESET);
                for(int x=0;x<messegesFromEndNodeList.getLength();x++){
                    String targetType = (String) XMLUtils.execXPath(messegesFromEndNodeList.item(x), "./*[local-name()='TO' or local-name()='to']/@class", XPathConstants.STRING);
                    if(!messageFlowExcludeFromToElemList.contains(targetType))
                        isMessageEnd = true;
                }
                
                String elemType = "end";
                if(isMessageEnd)
                    elemType += "Msg";
                float[] xy = getAdoxxElementCoordinatesXY(adoxxXml, id);
                GeneratedElements ge = pnm.processElement(id, elemType, id, xy[0], xy[1]);
                
                String poolId = getAdoxxElementPool(adoxxXml, id);
                for(PL place:ge.placeList)
                    place.addInfo("poolId", poolId);
                for(TR transition:ge.transitionList)
                    transition.addInfo("poolId", poolId);
                
                //map dependent
                if(elemType.equals("endMsg"))
                    ge.transitionList[0].addInfo("isEntryPoint", "true");
                else
                    ge.placeList[0].addInfo("isEntryPoint", "true");
            }
            
            NodeList anyTaskNodeList =  (NodeList) XMLUtils.execXPath(bpmnModelEl, anyTaskQuery, XPathConstants.NODESET);
            for(int i=0;i<anyTaskNodeList.getLength();i++){
                String id = anyTaskNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
                String elemType = "task";
                NodeList taskLoopDefinitionNodeList =  (NodeList) XMLUtils.execXPath(anyTaskNodeList.item(i), anyTaskLoopQuery, XPathConstants.NODESET);
                if(taskLoopDefinitionNodeList.getLength()>0)
                    elemType = "loop";
                float[] xy = getAdoxxElementCoordinatesXY(adoxxXml, id);
                GeneratedElements ge = pnm.processElement(id, elemType, id, xy[0], xy[1]);
                
                String poolId = getAdoxxElementPool(adoxxXml, id);
                for(PL place:ge.placeList)
                    place.addInfo("poolId", poolId);
                for(TR transition:ge.transitionList)
                    transition.addInfo("poolId", poolId);
                
                //map dependent
                if(elemType.equals("task"))
                    ge.transitionList[0].addInfo("isEntryPoint", "true");
                else
                    for(TR transition:ge.transitionList)
                        if(transition.name.startsWith("t0"))
                            transition.addInfo("isEntryPoint", "true");
                
            }
            
            NodeList andNodeList =  (NodeList) XMLUtils.execXPath(bpmnModelEl, andQuery, XPathConstants.NODESET);
            for(int i=0;i<andNodeList.getLength();i++){
                String id = andNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
                String name = andNodeList.item(i).getAttributes().getNamedItem("name").getNodeValue();
                
                float[] xy = getAdoxxElementCoordinatesXY(adoxxXml, id);
                
                String gatewayType =  (String) XMLUtils.execXPath(andNodeList.item(i), inclusiveComplexGatewayQuery, XPathConstants.STRING);
                GeneratedElements ge = null;
                if(gatewayType.equals("Inclusive") || gatewayType.equals("Complex")){
                    String defaultSequenceFlowId =  (String) XMLUtils.execXPath(bpmnModelEl, ".//*[local-name()='CONNECTOR' or local-name()='connector'][./*[local-name()='FROM' or local-name()='from']/@instance="+XMLUtils.escapeXPathField(name)+" and ./*[local-name()='ATTRIBUTE' or local-name()='attribute'][@name='Default']='Yes']/@id", XPathConstants.STRING);
                    ge = pnm.processElement(id, "inclusiveComplexG", id, xy[0], xy[1]);
                    if(ge.placeList.length==1 && ge.placeList[0]!=null)
                        ge.placeList[0].addInfo("defaultSequenceFlowId", defaultSequenceFlowId);
                    //map dependent
                    ge.placeList[0].addInfo("isEntryPoint", "true");
                }else{
                    ge = pnm.processElement(id, "and", id, xy[0], xy[1]);
                    //map dependent
                    ge.transitionList[0].addInfo("isEntryPoint", "true");
                }
                String poolId = getAdoxxElementPool(adoxxXml, id);
                for(PL place:ge.placeList)
                    place.addInfo("poolId", poolId);
                for(TR transition:ge.transitionList)
                    transition.addInfo("poolId", poolId);
            }
            
            NodeList xorNodeList =  (NodeList) XMLUtils.execXPath(bpmnModelEl, xorQuery, XPathConstants.NODESET);
            for(int i=0;i<xorNodeList.getLength();i++){
                String id = xorNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
                float[] xy = getAdoxxElementCoordinatesXY(adoxxXml, id);
                
                String gatewayType =  (String) XMLUtils.execXPath(xorNodeList.item(i), eventGatewayQuery, XPathConstants.STRING);
                GeneratedElements ge = null;
                if(gatewayType.toLowerCase().contains("event"))
                    ge = pnm.processElement(id, "eventG", id, xy[0], xy[1]);
                else
                    ge = pnm.processElement(id, "xor", id, xy[0], xy[1]);
                
                String poolId = getAdoxxElementPool(adoxxXml, id);
                for(PL place:ge.placeList)
                    place.addInfo("poolId", poolId);
                for(TR transition:ge.transitionList)
                    transition.addInfo("poolId", poolId);
                
                //map dependent
                ge.placeList[0].addInfo("isEntryPoint", "true");
            }
            
            NodeList boundaryTaskNodeList =  (NodeList) XMLUtils.execXPath(bpmnModelEl, boundaryTaskQuery, XPathConstants.NODESET);
            for(int i=0;i<boundaryTaskNodeList.getLength();i++){
                String id = boundaryTaskNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
                float[] xy = getAdoxxElementCoordinatesXY(adoxxXml, id);               
                String sourceName = (String) XMLUtils.execXPath(boundaryTaskNodeList.item(i), "./*[@name='Attached to']//@tobjname", XPathConstants.STRING);
                if(sourceName.isEmpty()) throw new Exception("ERROR: Attribute 'Attached to' not defined for the object " + id);
                
                String sourceId = (String) XMLUtils.execXPath(bpmnModelEl, ".//*[@id!='' and @name="+XMLUtils.escapeXPathField(sourceName)+"]/@id", XPathConstants.STRING);
                if(sourceId.isEmpty()) throw new Exception("ERROR: Can not find the object with name " + sourceName);
                
                GeneratedElements ge = pnm.processElement(id, "bound", id, xy[0], xy[1]);
                GeneratedElements ge1 = pnm.processRelation(id, "bound", sourceId, id);  
                String poolId = getAdoxxElementPool(adoxxXml, id);
                for(PL place:ge.placeList)
                    place.addInfo("poolId", poolId);
                for(TR transition:ge.transitionList)
                    transition.addInfo("poolId", poolId);
                
                for(PL place:ge1.placeList)
                    place.addInfo("poolId", poolId);
                for(TR transition:ge1.transitionList)
                    transition.addInfo("poolId", poolId);
                //map dependent
                ge.transitionList[0].addInfo("isEntryPoint", "true");
            }
            
            NodeList sequenceFlowNodeList =  (NodeList) XMLUtils.execXPath(bpmnModelEl, sequenceFlowQuery, XPathConstants.NODESET);
            for(int i=0;i<sequenceFlowNodeList.getLength();i++){
                String id = sequenceFlowNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
                
                String sourceName = (String) XMLUtils.execXPath(sequenceFlowNodeList.item(i), "./*[local-name()='FROM' or local-name()='from']/@instance", XPathConstants.STRING);
                String sourceType = (String) XMLUtils.execXPath(sequenceFlowNodeList.item(i), "./*[local-name()='FROM' or local-name()='from']/@class", XPathConstants.STRING);
                String targetName = (String) XMLUtils.execXPath(sequenceFlowNodeList.item(i), "./*[local-name()='TO' or local-name()='to']/@instance", XPathConstants.STRING);
                String targetType = (String) XMLUtils.execXPath(sequenceFlowNodeList.item(i), "./*[local-name()='TO' or local-name()='to']/@class", XPathConstants.STRING);
                
                String sourceId = (String) XMLUtils.execXPath(bpmnModelEl, ".//*[@id!='' and @name="+XMLUtils.escapeXPathField(sourceName)+"]/@id", XPathConstants.STRING);
                String targetId = (String) XMLUtils.execXPath(bpmnModelEl, ".//*[@id!='' and @name="+XMLUtils.escapeXPathField(targetName)+"]/@id", XPathConstants.STRING);

                if(sourceId.isEmpty()) throw new Exception("ERROR: Can not identify the element with name " + sourceName + " for the relation " + id);
                if(targetId.isEmpty()) throw new Exception("ERROR: Can not identify the element with name " + targetName + " for the relation " + id);
                
                if(sequenceFlowExcludeFromToElemList.contains(sourceType) || sequenceFlowExcludeFromToElemList.contains(targetType))
                    continue;
                
                pnm.processRelation(id, "sequence", sourceId, targetId);
            }
            
            NodeList messageFlowNodeList =  (NodeList) XMLUtils.execXPath(bpmnModelEl, messageFlowQuery, XPathConstants.NODESET);
            for(int i=0;i<messageFlowNodeList.getLength();i++){
                String id = messageFlowNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
                
                String sourceName = (String) XMLUtils.execXPath(messageFlowNodeList.item(i), "./*[local-name()='FROM' or local-name()='from']/@instance", XPathConstants.STRING);
                String sourceType = (String) XMLUtils.execXPath(messageFlowNodeList.item(i), "./*[local-name()='FROM' or local-name()='from']/@class", XPathConstants.STRING);
                String targetName = (String) XMLUtils.execXPath(messageFlowNodeList.item(i), "./*[local-name()='TO' or local-name()='to']/@instance", XPathConstants.STRING);
                String targetType = (String) XMLUtils.execXPath(messageFlowNodeList.item(i), "./*[local-name()='TO' or local-name()='to']/@class", XPathConstants.STRING);

                String sourceId = (String) XMLUtils.execXPath(bpmnModelEl, ".//*[@id!='' and @name="+XMLUtils.escapeXPathField(sourceName)+"]/@id", XPathConstants.STRING);
                String targetId = (String) XMLUtils.execXPath(bpmnModelEl, ".//*[@id!='' and @name="+XMLUtils.escapeXPathField(targetName)+"]/@id", XPathConstants.STRING);

                if(sourceId.isEmpty()) throw new Exception("ERROR: Can not identify the element with name " + sourceName + " for the relation " + id);
                if(targetId.isEmpty()) throw new Exception("ERROR: Can not identify the element with name " + targetName + " for the relation " + id);
                
                if(messageFlowExcludeFromToElemList.contains(sourceType) || messageFlowExcludeFromToElemList.contains(targetType))
                    continue;
                
                GeneratedElements genEl = pnm.processRelation(id, "message", sourceId, targetId);
                if(genEl.placeList.length>0)
                    genEl.placeList[0].excludeFromDeadlockCheck = true;
                
            }
        
            ret[modelIndex] = pnm.generatePN(modelId);
            postProcessEventGateways(ret[modelIndex], "eventG", "message");
            postProcessInclusiveComplexGateways(ret[modelIndex], "inclusiveComplexG");
            ret[modelIndex].updateStartListCheckingFlow(); //richiamando questa funzione sistemo i bpmn fatti male che iniziano senza uno startevent necessario quando un processo inizia ad es da un intermediate event che parte da un segnale o da un altro processo
        }
        
        return ret;
    }
    
    private static float[] getAdoxxElementCoordinatesXY(Document adoxxXml, String elementId) throws Exception{
        String position = (String) XMLUtils.execXPath(adoxxXml.getDocumentElement(), "//*[@id=" + XMLUtils.escapeXPathField(elementId) + "]/*[@name='Position']", XPathConstants.STRING);
        String x = position.substring(position.indexOf("x:")+2);
        x = x.substring(0, x.indexOf("cm"));
        String y = position.substring(position.indexOf("y:")+2);
        y = y.substring(0, y.indexOf("cm"));
        return new float[]{Float.valueOf(x)*29, Float.valueOf(y)*29};
    }
    
    private static String getAdoxxElementPool(Document adoxxXml, String elementId) throws Exception{
        String elementName = (String) XMLUtils.execXPath(adoxxXml.getDocumentElement(), "//*[@id=" + XMLUtils.escapeXPathField(elementId) + "]/@name", XPathConstants.STRING);
        Node bpmnModelEl =  (Node) XMLUtils.execXPath(adoxxXml.getDocumentElement(), "//*[@modeltype='Business process diagram (BPMN 2.0)' and .//@id=" + XMLUtils.escapeXPathField(elementId) + "]", XPathConstants.NODE);
        String elementPoolName = (String) XMLUtils.execXPath(bpmnModelEl, ".//*[@class='Is inside'][(./*[local-name()='TO' or local-name()='to']/@class='Pool') or (./*[local-name()='TO' or local-name()='to']/@class='Pool (collapsed)')][./*[local-name()='FROM' or local-name()='from']/@instance=" + XMLUtils.escapeXPathField(elementName) + "]/*[local-name()='TO' or local-name()='to']/@instance", XPathConstants.STRING);
        String elementPoolId = (String) XMLUtils.execXPath(bpmnModelEl, ".//*[@name=" + XMLUtils.escapeXPathField(elementPoolName) + "]/@id", XPathConstants.STRING);
        return elementPoolId;
    }

    /*
    Per ogni event gateway vengono controllati tutti i task collegati in outgoing. Se questi task hanno uno o piu messaggi in input, questi vengono staccati dalla transition del task e riattaccati alla transition del gateway. In questo modo il gateway sceglie il task da far partire sulla base del messaggio arrivato.
    Es: p0(è eventG)>t0,p0(è eventG)>t1,t0>p1,t1>p2,p1>t2,p3>t2(è messaggio) diventa p0(è eventG)>t0,p0(è eventG)>t1,t0>p1,t1>p2,p1>t2,p3>t0(è messaggio su eventG)
    */
   private static void postProcessEventGateways(PetriNet pn, String mappingNameForEventGateway, String mappingNameForMessageRelations) throws Exception{
       for(PL place:pn.getPlaceList_safe()){
          if(!mappingNameForEventGateway.equals(place.additionalInfoList.get("elementType")))
              continue;
          for(TR nextTransition:place.getNextList_safe()) {
              if(nextTransition.nextList.size()==1)
                  if(nextTransition.nextList.get(0).nextList.size()==1){
                      TR transitionToCheck = nextTransition.nextList.get(0).nextList.get(0);
                      for(PL prevOfTransitionToCheck:transitionToCheck.getPreviousList_safe())
                          if(mappingNameForMessageRelations.equals(pn.getConnection(prevOfTransitionToCheck, transitionToCheck).additionalInfoList.get("relationType"))){
                              pn.delConnection(prevOfTransitionToCheck, transitionToCheck);
                              PT conn = pn.connect(prevOfTransitionToCheck, nextTransition);
                              conn.addInfo("relationType", mappingNameForMessageRelations);
                          }
                  }
          }
      }
   }
   
   /*
    Per ogni inclusive o complex gateway aggiungo transizioni in uscita in modo da prevedere tutte le possibili combinazioni di partenza di output flow.
    */
   private static void postProcessInclusiveComplexGateways(PetriNet pn, String mappingNameForInclusiveComplexGateway) throws Exception{
       for(PL place:pn.getPlaceList_safe()){
           if(!mappingNameForInclusiveComplexGateway.equals(place.additionalInfoList.get("elementType")))
               continue;
           String defaultSequenceFlowId = place.additionalInfoList.get("defaultSequenceFlowId");
           if(defaultSequenceFlowId==null)
               defaultSequenceFlowId = "";

           ArrayList<TR> nextTransitionList = place.getNextList_safe();
           
           if(!defaultSequenceFlowId.isEmpty()){
               for(TR nextTransition:place.nextList)
                   if(defaultSequenceFlowId.equals(pn.getConnection(place, nextTransition).additionalInfoList.get("relationId")))
                       nextTransitionList.remove(nextTransition);
           }
           int[][] binMap = Utils.generateBinaryMatrix(nextTransitionList.size());
           for(int iRow=0;iRow<binMap.length;iRow++){
               int sum=0;
               for(int iColumn=0;iColumn<binMap[iRow].length;iColumn++)
                   sum+=binMap[iRow][iColumn];
               if(sum<=1)
                   continue;
               
               TR newTr = pn.addTransition("t"+iRow+place.name);
               newTr.description = place.name;
               newTr.x = place.x;
               newTr.y = (Float.valueOf(place.y) + Float.valueOf(place.h)*(iRow+1) + 20) + "";
               pn.connect(place, newTr);
               
               for(int iColumn=0;iColumn<binMap[iRow].length;iColumn++){
                   if(binMap[iRow][iColumn]==0)
                       continue;
                   for(PL nextPlace:nextTransitionList.get(iColumn).nextList)
                       pn.connect(newTr, nextPlace);
               }
           }
       }
    }
    
    
    public static PetriNet[] generateFromAdoxxPetriNet(Document adoxxXml) throws Exception{
        
        if(!isADOXX(adoxxXml))
            throw new Exception("ERROR: The provided model is not a valid ADOXX model");
        
        PNMapping pnm = new PNMapping();
        pnm.addMapping("p : p ; in:connection=p ; out:connection=p");
        pnm.addMapping("t : t ; in:connection=t ; out:connection=t");        
        
        String placeQuery = ".//*[@id!='' and @class='Place']";
        String transitionQuery = ".//*[@id!='' and @class='Transition']";
        String relationQuery = ".//*[@id!='' and (@class='P2TRelation' or @class='T2PRelation')]";
        
        NodeList pnModelElList =  (NodeList) XMLUtils.execXPath(adoxxXml.getDocumentElement(), "//*[@modeltype='Petri Net']", XPathConstants.NODESET);
        PetriNet[] ret = new PetriNet[pnModelElList.getLength()];
        
        for(int modelIndex=0;modelIndex<pnModelElList.getLength();modelIndex++) {
            
            pnm.resetProcessed();
            Node pnModelEl = pnModelElList.item(modelIndex);
            String modelId = pnModelEl.getAttributes().getNamedItem("id").getNodeValue();
            
            
            NodeList placeNodeList =  (NodeList) XMLUtils.execXPath(pnModelEl, placeQuery, XPathConstants.NODESET);
            for(int i=0;i<placeNodeList.getLength();i++){
                String id = placeNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
                float[] xy = getAdoxxElementCoordinatesXY(adoxxXml, id);
                String nTokenS = (String) XMLUtils.execXPath(placeNodeList.item(i), "./*[@name='NumOfTokens']", XPathConstants.STRING);
                int nToken = 0;
                try{
                    nToken = Integer.parseInt(nTokenS);
                }catch(Exception ex){}
                GeneratedElements genList = pnm.processElement(id, "p", id, xy[0], xy[1]);
                
                if(genList.placeList.length>0)
                    genList.placeList[0].numToken = nToken;
            }
            
            NodeList transitionNodeList =  (NodeList) XMLUtils.execXPath(pnModelEl, transitionQuery, XPathConstants.NODESET);
            for(int i=0;i<transitionNodeList.getLength();i++){
                String id = transitionNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
                float[] xy = getAdoxxElementCoordinatesXY(adoxxXml, id);
                pnm.processElement(id, "t", id, xy[0], xy[1]);
            }
            
            NodeList relationNodeList =  (NodeList) XMLUtils.execXPath(pnModelEl, relationQuery, XPathConstants.NODESET);
            for(int i=0;i<relationNodeList.getLength();i++){
                String id = relationNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
                
                String sourceName = (String) XMLUtils.execXPath(relationNodeList.item(i), "./*[local-name()='FROM' or local-name()='from']/@instance", XPathConstants.STRING);
                String targetName = (String) XMLUtils.execXPath(relationNodeList.item(i), "./*[local-name()='TO' or local-name()='to']/@instance", XPathConstants.STRING);
                String sourceId = (String) XMLUtils.execXPath(pnModelEl, ".//*[@id!='' and @name="+XMLUtils.escapeXPathField(sourceName)+"]/@id", XPathConstants.STRING);
                String targetId = (String) XMLUtils.execXPath(pnModelEl, ".//*[@id!='' and @name="+XMLUtils.escapeXPathField(targetName)+"]/@id", XPathConstants.STRING);

                String weight = (String) XMLUtils.execXPath(relationNodeList.item(i), "./*[@name='Weight']", XPathConstants.STRING);
                int weightN = 1;
                try{
                    weightN = Integer.parseInt(weight);
                }catch(Exception ex){}
                if(sourceId.isEmpty()) throw new Exception("ERROR: Can not identify the element with name " + sourceName + " for the relation " + id);
                if(targetId.isEmpty()) throw new Exception("ERROR: Can not identify the element with name " + targetName + " for the relation " + id);
                
                GeneratedElements elList = pnm.processRelation(id, "connection", sourceId, targetId);
                if(elList.ptList.length>0)
                    elList.ptList[0].weight = weightN;
                if(elList.tpList.length>0)
                    elList.tpList[0].weight = weightN;
            }
        
            ret[modelIndex] = pnm.generatePN(modelId);
        }
        
        return ret;
    }
    
    public static PetriNet generateFromPNML(Document pnmlXml) throws Exception{
        
        if(!isPNML(pnmlXml))
            throw new Exception("ERROR: The provided model is not a valid PNML model");
        
        PNMapping pnm = new PNMapping();
        pnm.addMapping("p : p ; in:connection=p ; out:connection=p");
        pnm.addMapping("t : t ; in:connection=t ; out:connection=t");        
        
        String placeQuery = "//*[local-name()='place']";
        String transitionQuery = "//*[local-name()='transition']";
        String relationQuery = "//*[local-name()='arc']";
        
        Node netEl = (Node) XMLUtils.execXPath(pnmlXml.getDocumentElement(), "//*[local-name()='net']", XPathConstants.NODE);
        String netId = netEl.getAttributes().getNamedItem("id").getNodeValue();
        
        NodeList placeNodeList =  (NodeList) XMLUtils.execXPath(pnmlXml.getDocumentElement(), placeQuery, XPathConstants.NODESET);
        for(int i=0;i<placeNodeList.getLength();i++){
            String id = placeNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            float[] xy = getPNMLElementCoordinatesXY(pnmlXml, id);
            String nTokenS = (String) XMLUtils.execXPath(placeNodeList.item(i), "./*[local-name()='initialMarking']/*[local-name()='text']", XPathConstants.STRING);
            int nToken = 0;
            try{
                nToken = Integer.parseInt(nTokenS);
            }catch(Exception ex){}
            GeneratedElements genList = pnm.processElement(id, "p", id, xy[0], xy[1]);
            
            if(genList.placeList.length>0)
                genList.placeList[0].numToken = nToken;
        }
        
        NodeList transitionNodeList =  (NodeList) XMLUtils.execXPath(pnmlXml.getDocumentElement(), transitionQuery, XPathConstants.NODESET);
        for(int i=0;i<transitionNodeList.getLength();i++){
            String id = transitionNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            float[] xy = getPNMLElementCoordinatesXY(pnmlXml, id);
            pnm.processElement(id, "t", id, xy[0], xy[1]);
        }
        
        NodeList relationNodeList =  (NodeList) XMLUtils.execXPath(pnmlXml.getDocumentElement(), relationQuery, XPathConstants.NODESET);
        for(int i=0;i<relationNodeList.getLength();i++){
            String id = relationNodeList.item(i).getAttributes().getNamedItem("id").getNodeValue();
            
            String sourceId = relationNodeList.item(i).getAttributes().getNamedItem("source").getNodeValue();
            String targetId = relationNodeList.item(i).getAttributes().getNamedItem("target").getNodeValue();

            String weight = (String) XMLUtils.execXPath(relationNodeList.item(i), "./*[local-name()='inscription']/*[local-name()='text']", XPathConstants.STRING);
            int weightN = 1;
            try{
                weightN = Integer.parseInt(weight);
            }catch(Exception ex){}

            GeneratedElements elList = pnm.processRelation(id, "connection", sourceId, targetId);
            if(elList.ptList.length>0)
                elList.ptList[0].weight = weightN;
            if(elList.tpList.length>0)
                elList.tpList[0].weight = weightN;
        }

        return pnm.generatePN(netId);
    }
    
    private static float[] getPNMLElementCoordinatesXY(Document pnmlXml, String elementId) throws Exception{
        Node position = (Node) XMLUtils.execXPath(pnmlXml.getDocumentElement(), "//*[@id=" + XMLUtils.escapeXPathField(elementId) + "]/*[local-name()='graphics']/*[local-name()='position']", XPathConstants.NODE);
        String x = position.getAttributes().getNamedItem("x").getNodeValue();
        String y = position.getAttributes().getNamedItem("y").getNodeValue();
        return new float[]{Float.valueOf(x), Float.valueOf(y)};
    }
    
    /*
    public static void main(String[] args) {
        try {
            String modelUrl = "D:\\LAVORO\\PROGETTI\\PNToolkit\\testModels\\asd.pnml";
            PetriNet[] pnList = new PetriNet[]{generateFromPNML(XMLUtils.getXmlDocFromURI(modelUrl))};
            //PetriNet[] pnList = new PetriNet[]{generateFromBPMN(XMLUtils.getXmlDocFromURI(modelUrl))};
            //PetriNet[] pnList = generateFromAdoxxBPMN(XMLUtils.getXmlDocFromURI(modelUrl));
            //PetriNet[] pnList = generateFromAdoxxPetriNet(XMLUtils.getXmlDocFromURI(modelUrl));
            //System.out.println(PNExport.exportToEldaricaP(pn));
            //System.out.println(PNExport.exportToEldaricaP_propertyDeadlockPresence(pn));
            //System.out.println(PNExport.exportToEldaricaP_propertyEndReachability(pn));
            for(PetriNet pn: pnList)
                System.out.println(PNExport.exportTo_PNML(pn));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    */
}