Friday, October 19, 2012

Processing BPMN xml with javascript

My Code
Require: xml2json(xml, tab) from http://goessner.net/. Modified to not use @

var xmlDoc; // used for debug
var myjson; // used for debug
function dummyBPMNTest() {

 function parseXml(xml) {
  console.log('xml = ' + xml);
  var json = eval('(' + xml2json(xml, "") + ')');
  console.log(json);
  myjson = json;
  console.log('Looking for start event.');
  var startEvent = json.definitions.process.startEvent; 
//  var endEvent = json.definitions.process.endEvent; 
  var processProperties = {};
  if( isArray(json.definitions.process.property)) {
   for(var i in json.definitions.process.property) {
    processProperties[json.definitions.process.property[i].id] = null; // not type 
   }
  } else {
   processProperties[json.definitions.process.property.id] = null;
  }
  console.log(processProperties);
  
  function loopSequenceFlow(id) {
   console.log('looking for next node.');
   var nextSequence = [];
//   console.log(json.definitions.process.sequenceFlow);
   for(var i in json.definitions.process.sequenceFlow) {
    var sequence = json.definitions.process.sequenceFlow[i];
//    console.log('sequence.sourceRef = ' + sequence.sourceRef + ', startEvent.id = ' + startEvent.id);
    if(sequence.sourceRef == id) {
     nextSequence.push(sequence);
    }
   }
   if(nextSequence.length < 1) {
    console.log('No more task to run.');
    return;
   }
   console.log(nextSequence);
   var nextNode = null;
   // sort
   nextSequence.sort(function(a, b){
    return a['tns:priority']  -  b['tns:priority'];
   });
   console.log('After sort.');
   console.log(nextSequence);
   // process
   if(nextSequence.length > 1){
    for(var i in nextSequence) {
//     try the conditionaExpression
     if(nextSequence[i].conditionExpression) {
      console.log(nextSequence[i].conditionExpression['#text']);
      var r = eval(nextSequence[i].conditionExpression['#text']);
      console.log('r = ' + r);
      if(r) {
       console.log('next node id = ' + nextSequence[i].targetRef);
       nextNode = eval('(' + xml2json(xml.getElementById(nextSequence[i].targetRef), "") + ')');
       break;
      }
     }
    }
   } else {
    console.log('next node id = ' + nextSequence[0].targetRef);
    nextNode = eval('(' + xml2json(xml.getElementById(nextSequence[0].targetRef), "") + ')');
   }
   
   console.log(nextNode);
   if(nextNode == null) {
    return;
   }
   var nodeType = null;
   for(x in nextNode) {
    nodeType = x;
//    console.log('object is a ' + x);
   }
   var node = nextNode[nodeType];
   console.log('Running [' + nodeType + ']:' + node.name);
   switch(nodeType) {
   case 'scriptTask':
//    console.log('Running ' + nodeType + ':' + nextNode[nodeType].name);
//    console.log('         ' + nextNode[nodeType].script);
    if(isArray(nextNode[nodeType].script)) {
     for(var i in nextNode[nodeType].script) {
      eval(nextNode[nodeType].script[i]);
     }
    } else {
     eval(nextNode[nodeType].script); 
    }
    break;
   case 'exclusiveGateway':
    break;
   case 'userTask':
    // creating task variables
    var dataInput = {};
    if( isArray( node.ioSpecification.dataInput)) {
     for(var i in node.ioSpecification.dataInput) {
      dataInput[node.ioSpecification.dataInput[i].id] = {name: node.ioSpecification.dataInput[i].name, value:null};
     }
    } else {
     dataInput[node.ioSpecification.dataInput.id] = {name: node.ioSpecification.dataInput.name, value:null};
    }
    var dataOutput = {};
    if( isArray( node.ioSpecification.dataOutput)) {
     for(var i in node.ioSpecification.dataOutput) {
      dataOutput[node.ioSpecification.dataOutput[i].id] = {name: node.ioSpecification.dataOutput[i].name, value:null};
     }
    } else {
     dataOutput[node.ioSpecification.dataOutput.id] = {name: node.ioSpecification.dataOutput.name, value:null};
    }
    console.log(dataInput);
    console.log(dataOutput);
    // Associate dataInput
    var dataInputAssociation = node.dataInputAssociation;
    if(dataInputAssociation != null) {
     function associateDataInput(o) {
      if(o.sourceRef != null) {
       dataInput[o.targetRef].value = processProperties[o.sourceRef];
      }
      if(o.assignment != null) {
       dataInput[o.targetRef].value = o.assignment.from['#text'];
      }
     }
     if(isArray(dataInputAssociation)) {
      for( var i in dataInputAssociation) {
       var o = dataInputAssociation[i];
       associateDataInput(o);
      }
     } else {
      var o = dataInputAssociation;
      associateDataInput(o);
     }
    }
    console.log('After association.');
    console.log(dataInput);
    
    function getDataInput(name) {
     for(var i in dataInput) {
      if(dataInput[i].name == name) {
       return dataInput[i].value;
      }
     }
    }
    eval(node.extensionElements['tns:onEntry-script'].script );
    // TODO write your own handler function to handle user task.
    // What if we want to map more than 1 value? --> use eval() to call a function.
    // How the user return more than one value? --> use object
    var userResponse = eval(getDataInput('Content'));
    console.log(userResponse);
    // map the response to dataOutput
    for(var i in dataOutput) {
     for(var j in userResponse) {
      if(dataOutput[i].name == j) {
       console.log('mapping userResponse.' + j + ' to dataOutput.' + i);
       dataOutput[i].value = userResponse[j];
      }
     }
    }
    console.log('After map response');
    console.log(dataOutput);
    // Associate dataOutput to processProperties
    var dataOutputAssociation = node.dataOutputAssociation;
    if(dataOutputAssociation != null) {
     function associateDataOutput(o) {
      if(o.sourceRef != null) {
       console.log('assigning value from ' + o.sourceRef + ' to ' + o.targetRef);
//       dataOutput[o.targetRef].value = processProperties[o.sourceRef];
       processProperties[o.targetRef] = dataOutput[o.sourceRef].value;
      }
      if(o.assignment != null) {
       dataOutput[o.targetRef].value = o.assignment.from['#text'];
      }
     }
     if(isArray(dataOutputAssociation)) {
      for( var i in dataOutputAssociation) {
       var o = dataOutputAssociation[i];
       associateDataOutput(o);
      }
     } else {
      var o = dataOutputAssociation;
      associateDataOutput(o);
     }
    }
    console.log(processProperties);
    
    // onExit script
    eval(node.extensionElements['tns:onExit-script'].script );
    break;
   case 'endEvent':
    console.log('reach end event.');
    return;
   }
   loopSequenceFlow(nextNode[nodeType].id);
  }
  
  loopSequenceFlow(startEvent.id);
  
 }

 $.ajax({
  type : "GET",
  url : "ScanCage.bpmn.xml",
  dataType : "xml",
  success : parseXml
 });

}

function dummyFunction1() {
 var answer =  prompt('What are you thinking??');
 var somevalue = '123456789';
 return {answer: answer, somevalue: somevalue};
}

dummyBPMNTest();
 


  
  
  
  
  

  

    
     
     
     
    
    
    
    
    
    
    

    
    
    
      
    
    
      
    
    
        
    
    
      
        
          
        
        
          
        
      
      
        
        
        
        
        
        
        
        
          _5_ContentInput
          _5_CommentInput
          _5_SkippableInput
          _5_TaskNameInput
          _5_ContentInput
          _5_PriorityInput
        
        
          _5_answerOutput
        
      
      
        userComms
        _5_ContentInput
      
      
        _5_CommentInput
        
          
          _5_CommentInput
        
      
      
        _5_SkippableInput
        
          true
          _5_SkippableInput
        
      
      
        _5_TaskNameInput
        
          Scan Cage
          _5_TaskNameInput
        
      
      
        _5_ContentInput
        
          dummyFunction1()
          _5_ContentInput
        
      
      
        _5_PriorityInput
        
          
          _5_PriorityInput
        
      
      
        _5_answerOutput
        answer
      
      
        
          #{actor}
        
      
    
    
    

    
    
    
      eval(true)
    
    
    
    
    
    
      
        processProperties.answer != '32123'
      
    

  

  
    
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
        
      
      
        
        
      
      
        
        
      
      
        
        
      
      
        
        
      
      
        
        
      
      
        
        
      
    
  

No comments: