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'
      
    

  

  
    
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
        
      
      
        
        
      
      
        
        
      
      
        
        
      
      
        
        
      
      
        
        
      
      
        
        
      
    
  

Wednesday, June 20, 2012

Installing s3fs on Mac

I'm not a Mac guy but was instructed to do so. Ran through a few web site, try to install pkg-config, fuse, glib, ... ... and end up with the simplest solution.

Step 1:
Install MacPorts from http://www.macports.org/

Step 2:
Install s3fs with MacPorts.
port install s3fs

Done.
Thanks to MacPorts

Thursday, May 17, 2012

Manually Sort an ArrayList in Java

Just like to paste this code:

        List sorted = new ArrayList();
        RackPosition temp = null;
        int remove_index = -1;

        while(original.size() > 0) {    
            temp = original.get(0);
            for (int i = 0; i < original.size(); i++ ) {
                RackPosition rp2 = original.get(i);
                if(temp.getPositionNumber().compareTo(rp2.getPositionNumber()) > 0) {
                    temp = rp2;
                    remove_index = i;
                }
            }
            System.out.println("Adding " + temp.getPositionNumber());
            sorted.add(temp);
//          original.remove(temp);
            if(remove_index >= 0) {
                original.remove(remove_index);
            }
            remove_index = 0;
        }

Wednesday, March 21, 2012

Generate S3 Pre-signed URL in Java

I googled, not happy, so post it myself.

import java.util.Calendar;
import java.util.Date;

import com.amazonaws.HttpMethod;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;

public class PreSignURLGenerator {

    private final static String BUCKET_NAME = "this-is-not-porn";
    private final static String FILE_NAME = "not-porn-media-files/0146ce52-bbd5-4998-9378-35c20ece0000.jpg";
    private final static String ACCESS_KEY = "not-telling-you";
    private final static String SECRET_KEY = "it-s-a-secret";

    /**
     * @param args
     */
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.SECOND, 1000);
        Date expDate = cal.getTime();
        try {
            BasicAWSCredentials cre = new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY);
            AmazonS3 s3 = new AmazonS3Client(cre);
     String url = s3.generatePresignedUrl(BUCKET_NAME, FILE_NAME, expDate, HttpMethod.GET).toString();
            System.out.println(url);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


FYI:







and required access to Internet/AWS.

Do feedback if you really like this post.

Wednesday, February 29, 2012

jBPM - How to trace a lifecycle of a process

Just need to add a ProcesEventListener() to the ksession.
KnowledgeBase kbase = readKnowledgeBase();
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

CustomProcessEventListener customProcessEventListener = new CustomProcessEventListener();
ksession.addEventListener(customProcessEventListener);
...
...

ksession.startProcess("com.sample.MyTaskFlow", params);
And here is the sample CustomProcessEventListener();
private static class CustomProcessEventListener implements ProcessEventListener {

 @Override
 public void afterNodeLeft(ProcessNodeLeftEvent arg0) {
  // TODO Auto-generated method stub
  
 }

 @Override
 public void afterNodeTriggered(ProcessNodeTriggeredEvent arg0) {
  // TODO Auto-generated method stub
 }

 @Override
 public void afterProcessCompleted(ProcessCompletedEvent arg0) {
  // TODO Auto-generated method stub
  logger.debug("Process has completed.");
  System.exit(0);
 }

 @Override
 public void afterProcessStarted(ProcessStartedEvent arg0) {
  // TODO Auto-generated method stub
 }

 @Override
 public void afterVariableChanged(ProcessVariableChangedEvent arg0) {
  // TODO Auto-generated method stub
   
  }

 @Override
 public void beforeNodeLeft(ProcessNodeLeftEvent arg0) {
  // TODO Auto-generated method stub
   
 }

 @Override
 public void beforeNodeTriggered(ProcessNodeTriggeredEvent arg0) {
  // TODO Auto-generated method stub
   
 }

 @Override
 public void beforeProcessCompleted(ProcessCompletedEvent arg0) {
  // TODO Auto-generated method stub
  logger.debug("Process is going to be completed.");
 }

 @Override
 public void beforeProcessStarted(ProcessStartedEvent arg0) {
  // TODO Auto-generated method stub
  
 }

 @Override
 public void beforeVariableChanged(ProcessVariableChangedEvent arg0) {
  // TODO Auto-generated method stub
  
 }
 
}
As you can see, you can do many things on every stage of a process.

Tuesday, February 28, 2012

Drools again, example for beginner

Who would foresee that I will get my hand dirty again with drools? Well, after 13 months, here I am, looking at drools, again... now with jbpm too.
Anyway, it was good. Got better understanding about it and yeah, as usual, share.

I successfully made this:

I am not posting the codes here, you can request for it if you want.

The first process flow (can be in .rf or .bpmn) shows how to use Script Tasks. In the "Question" script, I ran these:


System.out.println("Who is the smartest man in the world?");

java.io.BufferedReader br = new java.io.BufferedReader(new 
                         java.io.InputStreamReader(System.in));

String name = null;

try {
name = br.readLine();
} catch (java.io.IOException e) {
System.out.println("Error!");
}

kcontext.setVariable("smart_guy", name);


The gateway after the "Question" script I check for this:


return smart_guy.equals("frank");


The "Error message" script just print error message. I ran the process.


ksession.startProcess("interactiveJava");


It will keep on asking you who the question until you say "frank". Pretty basic but it gives you better understand about how things run.

Here is the sample output.

The learning issues here will be:

  • Define variable "smart_guy" in the flow/process.



  • In the "Question" script, we set the user input to the process variable. 



     kcontext.setVariable("smart_guy", name);




  • In the gateway constraint:


     return smart_guy.equals("frank");


For beginners, you should try it out your self.

Many thanks to Drools/jBPM development team and the community for their hard work. Many helpful resources are now available online compare to last year.

Wednesday, January 25, 2012

Can you cook an egg in your car? Yes you can!

Today I ran a very crazy experiment with my car. Because it was very very hot today, 40°. So I want to see if I can cook an egg inside the car dashboard. And here is the result.
Too bad I didn't record the temperature inside the car, but it IS hot enough to cook an egg.