Open ESB: The Solution for the Open Minded The Crooked Stick

My Other Crooked Stick (Archery)

Bookmark and Share

Wednesday Nov 05, 2008

Extending on my recent blog entries around the BPEL 2 SVG Generator I have extended the functionality so that it will now generate highlighted paths through the SVG file by setting the various opacities of the Complex and Simple activities. The net result of this is that is is now easy to quickly generate SVG file on the fly from any given Open ESB BPEL 2 file. To showcase this new functionality I have built a small Visual Web Pack page that is linked to the BPEL 2 persistence tables and will display the SVG based on the selected BPEL process. This Visual Web Pack Application can be installed as a self contained application on any Glassfish instance it requires only the existing jdbc/bpelseNonXA JDBC connection pool definition to the persistence database and will provide a Graphical BPEL Monitor.


Related Articles


Resources

New Functionality


In the original version of the BPEL 2 SVG Generator I was simply generating an SVG file from a given BPEL file and this worked fine as far as it went. I add additional features for Adam to initially set the image opacities. He would then parse the resulting SVG at runtime and change the opacities of the processed Activities. Given that this processing was require and the speed at which the actual generation of the SVG from the BPEL I decided to extend the Generator to do all this in a single pass. So now given a set of processed Activities the Generator will create an SVG file on-the-fly and highlight the processed activities.

If we take the following BPEL processes and run it through the standard BPEL 2 SVG Generator, i.e. with no processed Activities, the "Standard Generated SVG" SVG file below. As you can see all Activities within the SVG have the default Opacity of 25%.

BPEL 2 Process
BPEL

Standard Generated SVG
On The Fly 1

The LayoutManager has now been extended to include the methods :
  • public synchronized void setProcessedActivities(Properties processedActivities)
  • public synchronized Properties getProcessedActivities()
These methods allow the user to get and set the activities that have been processed within the given BPEL and hence the, to be, generated SVG file. The Properties file passed to the LayoutManager must contain the processed Activities as the key and the opacity to be used as the value, as below.
 
Properties processedActivities = new Properties();

processedActivities.put("Scope1","1.00");
processedActivities.put("LDAPServiceSearch","1.00");
processedActivities.put("Assign2","1.00");
processedActivities.put("Assign1","1.00");
processedActivities.put("ForEach1","1.00");
processedActivities.put("Sequence5","1.00");
processedActivities.put("ReadReply","1.00");
processedActivities.put("ServiceCRUDPick","1.00");
processedActivities.put("Sequence1","1.00");
        
layoutManager.setProcessedActivities(processedActivities);

The internal ActivityImpl methods that retrieve the Opacity for a given SimpleActivity or ComplexActivity have been modifies so that they first check the supplied Properties and if the Activity Id (name in BPEL file) is found they will use the specified opacity otherwise they will use the default. The net result for the above properties can be seen below in "SVG With Highlighted Path" image.

SVG With Highlighted Path
On The Fly 2

Given this functionality we can now generate a new SVG file that displays the appropriate Processing Path rapidly based on a varying list of Processed Activities. In the Section below I will show how this can be simply linked to the BPEL Persistence / Monitoring tables.

Simple Web Based Monitor


The simple Web based Monitor is not designed as a replacement for Adams but simply as a method of testing my modifications to the underlying BPEL 2 SVG Generator code. It is very simple, I have not spent any time tarting up the GUI, and simply hooks directly into the existing BPEL 2 Monitoring / Persistence database tables using the existing jdbc/bpelseNonXA JDBC Resource. The generated war file is self contained and should run on any Glassfish ESb / Open ESB Application server where Persistence / Monitoring is enabled.

The section will briefly described the single Web page application and the required functionality, below, that I created to dynamically display the status of Open ESB BPEL 2 processes.

BPEL Monitor

The information used within the page is obtained from the following BPEL Persistence / Monitoring tables:
  • SERVICEUNIT : This table contains a list of all deployed Composite Application and the key column within this table is the SUZIPARCHIVE which contain a zipped version of the deployed components.
  • MONITORBPELINSTANCE : This table contain a list of all running instances of all BPEL Processes and will be used to display the top table of the page that allows the user to select the processing BPEL to be displayed.
  • MONITORBPELACTIVITY : Table contains all processing / processed Activities for a given BPEL processing Instance. This information will be restricted on the selected BPEL Instance and displayed within the second table whilst the Activity list will be passed to the BPEL 2 SVG Generator.

Creating the page


To create this Page, I will assume we have a project, you will need to do the following:
  1. Create a JDBC Data Source that points to the BPEL Persistence / Monitoring Database
  2. Rename the exiting Page2 to BPELMonitorPage
  3. Open BPELMonitorPage
  4. Drag a Grid Panel onto the Page
    1. Add Grid Panel
      1. Add Label
      2. Add DropDown : refreshDD
    2. Add Message Group
    3. Add Table
      1. Drag MONITORBPELINSTANCE from the Database connection and drop it onto the Table and modify to include the following:
        1. New Column : Button - showSVGBtn
        2. New Column : StaticText - BPELName
        3. Status
        4. Start Time
        5. End Time
        6. Update Time
        7. Instance Id
    4. Add Table
      1. New Column: StaticText - Activity
      2. Iteration
      3. Status
      4. Start Time
      5. End Time
    5. Add Markup Tag (we have a number of options here)
      1. iframe
      2. embed
The page show look like the one below.

Page designer

This will create a number of data providers and associated row sets in addition to the ones currently created we will need two additional row sets and these can be simply created in the SessionBean as follows.
  1. Create a new Page
  2. Drag the SERVICEUNIT table onto the canvas (rename in the SessionBean to suZipArchive)
  3. Drag the MONITORBPELACTIVITY onto the canvas and within the dialog create a new SessionBean row set called activityXPathRowSet
  4. Save
  5. Delete the page.
Once the additional methods have been added to the SessionBean and BPELMonitor then the following can be done:
  1. Link Bpel Name (Instance Table) to bpelName property.
  2. Link Activity Name (Activity Table) to the activityName Property
  3. Set the extendedAttributes for the Markup tag as follows
    1. iframe tag : src="#{SessionBean1.svgFilename}" width="#{SessionBean1.svgWidth}" height="#{SessionBean1.svgHeight}"
    2. embed tag : src="#{SessionBean1.svgFilename}" width="#{SessionBean1.svgWidth}" height="#{SessionBean1.svgHeight}" type="image/svg+xml" pluginspage="http://www.adobe.com/svg/viewer/install/"
  4. Set the Column styles on the tables to the appropriate properties (see example code)
Finally you will need to modify the JNDI name for the generated (JDBC) resource reference as follows; this will allow the page to connect to the BPEL Persistence / Monitor databse using the existing resource.

Resource

Key Code


The following code fragments are key to generating the SVG file correctly.

SessionBean

getActivityName(String xp)

This method takes an XPath  (obtained from the  MONITORBPELATTRIBUTE) table and searches the Instances BPEL for the actual name of the Activity and returns this. This is called from the page to set the values of the Activity name in the Table. In addition to finding the XPath within the BPEL it will also store it in a local Hashtable for easy reference on subsequent calls. The method uses standard javax.xml.xpath and javax.xml.parsers classes to parse the BPEL.

    public String getActivityName(String xp) {
        String name = "Not Found";
        if (xp != null) {
            String nameAttribute = "/@name";
            String path = xp.replaceAll("bpws:", "") + nameAttribute;
            name = (String) activityMap.get(path);
            ByteArrayInputStream byteInputStream = null;
            if (name == null) {
                try {
//                    System.out.println("*** APH-I1 : XPath " + path);
                    String bpelStr = (String) getBpelFileAsString().get(getBpelFilename());
                    byteInputStream = new ByteArrayInputStream(bpelStr.getBytes());
                    XPathFactory xPathFactory = XPathFactory.newInstance();
                    XPath xPath = xPathFactory.newXPath();
                    DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
                    DocumentBuilder builder = documentFactory.newDocumentBuilder();
                    Document document = builder.parse(byteInputStream);
                    name = (String) xPath.evaluate(path, document);
                    if (name != null && name.length() > 0) {
                        activityMap.put(path, name);
                    }
//                    System.out.println("*** APH-I1 : result " + result.getClass().getSimpleName() + " " + result.toString());
//                    System.out.println("*** APH-I2 : name " + name);
                } catch (SAXException ex) {
                    Logger.getLogger(SessionBean1.class.getName()).log(Level.SEVERE, null, ex);
                } catch (ParserConfigurationException ex) {
                    Logger.getLogger(SessionBean1.class.getName()).log(Level.SEVERE, null, ex);
                } catch (XPathExpressionException ex) {
                    Logger.getLogger(SessionBean1.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IOException ex) {
                    Logger.getLogger(SessionBean1.class.getName()).log(Level.SEVERE, null, ex);
                } finally {
                    try {
                        byteInputStream.close();
                    } catch (Exception e) {
                    }
                }
            }
        }
        return name;
    }

getProcessedActivities()

This method will use the previously create activityXPathRowSet to read all the processed activities for a given BPEL Instance and then return them as a Properties file with the predefined processed opacity. This method will be executed each time an Instance is selected on the BPEL Instance table and hence the DB will be re-queried to see if any new Activities have been processes.

    public Properties getProcessedActivities(String id) {
        Properties activities = new Properties();
        String sqlCommand = ACTIVITY_SQLCOMMAND + "'" + id + "'";
        String activityXPath = "";
        String activityName = "";

        try {
            getActivityXPathRowSet().setCommand(sqlCommand);
            getActivityXPathRowSet().execute();
            while (getActivityXPathRowSet().next()) {
                activityXPath = getActivityXPathRowSet().getString(1);
//                System.out.println("*** APH-I1 : XPath " + activityXPath);
                activityName = getActivityName(activityXPath);
                activities.put(activityName, PROCESSED_OPACITY);
            }
            getActivityXPathRowSet().release();
        } catch (SQLException ex) {
            Logger.getLogger(BPELMonitorPage.class.getName()).log(Level.SEVERE, null, ex);
        }

        return activities;
    }

    public Properties getProcessedActivities() {
        return getProcessedActivities(getBpelInstanceId());
    } 

loadBPELFiles()

Although this is the SessionBean it should be defined as a cached solution based on last update time of the ServiceUnit within the ApplicationBean for simplicity I have not done this just used the SessionBean instead. This method is used to read all the rows within the SERVICEUNIT Table and then extract the BPEL files from the stored ZIPARCHIVE. The BPEL files are store as a String in a Hshtable and keyed by the BPEL name. Therefore they other methods can simple retrieve the BPEL String based on the BPEL name.


    protected void loadBPELFiles() {
        try {

            getSuZipArchiveRowSet().execute();
            while (getSuZipArchiveRowSet().next()) {
                SerialBlob suArchiveBlob = (SerialBlob) getSuZipArchiveRowSet().getBlob("SUZIPARCHIVE");
                File file = null;
                FileOutputStream fos = null;
                int length = 0;
                ZipFile zipFile = null;
                ZipEntry zipEntry = null;
                String zipEntryName = null;
                BufferedReader br = null;
                InputStreamReader isr = null;
                InputStream is = null;
                String line = null;
                StringBuffer bpelSB = new StringBuffer();
                String bpelName = null;
                int idx = 0;

                try {
                    file = File.createTempFile("suArchive", ".zip");
//                        System.out.println("*** APH-I1 : Temp File " + file.getAbsolutePath());
//                        System.out.println("*** APH-I1 : Temp File " + file.getName());
                    file.deleteOnExit();
                    length = (int) suArchiveBlob.length();
                    fos = new FileOutputStream(file);
                    fos.write(suArchiveBlob.getBytes(1L, length));
                    zipFile = new ZipFile(file);
//                        System.out.println("*** APH-I1 : Zip Entries " + zipFile.size());
                    for (Enumeration<ZipEntry> e = (Enumeration<ZipEntry>;) zipFile.entries(); e.hasMoreElements();) {
                        zipEntry = e.nextElement();
                        zipEntryName = zipEntry.getName();
//                            System.out.println("*** APH-I2 : Name = " + zipEntryName);
                        if (zipEntryName.endsWith(".bpel")) {
                           
bpelSB = new StringBuffer();
                            is = zipFile.getInputStream(zipEntry);
                            isr = new InputStreamReader(is);
                            br = new BufferedReader(isr);
                            while ((line = br.readLine()) != null) {
//                                    System.out.println(line);
                                bpelSB.append(line + "\n");
                            }
                            idx = zipEntryName.lastIndexOf("/");
                            bpelName = zipEntryName.substring(idx + 1);
//                                System.out.println("*** APH-I3 : Zip Entry Name " + zipEntryName + " BPEL Name " + bpelName);
//                                System.out.println("*** APH-I3 : BPEL String "+bpelSB.toString());
                            bpelFileAsString.put(bpelName, bpelSB.toString());
                        }
                    }
                } catch (FileNotFoundException ex) {
                    Logger.getLogger(BPELMonitorPage.class.getName()).log(Level.SEVERE, null, ex);
                } catch (ZipException ex) {
                    Logger.getLogger(BPELMonitorPage.class.getName()).log(Level.SEVERE, null, ex);
                } catch (SerialException ex) {
                    Logger.getLogger(BPELMonitorPage.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IOException ex) {
                    Logger.getLogger(BPELMonitorPage.class.getName()).log(Level.SEVERE, null, ex);
                } finally {
                    try {
                        fos.close();
                    } catch (Exception e) {
                    }
                    try {
                        is.close();
                    } catch (Exception e) {
                    }
                    file.delete();
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(SessionBean1.class.getName()).log(Level.SEVERE, null, ex);
        }
    }


BPELMonitor

This page contains a number of methods and properties that I will not describe because they provide nice to have functionality but the methods below are of interest.

generateSVG

This method will be called when the "Show SVG Button" is pressed in the Instance table. It will read the BPEL String for the current BPEL file name and then generate the SVG. It should be noted that I set the IconSource to a local icons directory factory.setIconSource("icons"); define the processed activities layoutManager.setProcessedActivities(processedActivities); to those read from the Activities table and set the orientation to horizontal (i.e. not vertical) and then generate the file.

    protected void generateSVG() {
        BPELInterface bpel = new BPELImpl();
        String bpelStr = (String) getSessionBean1().getBpelFileAsString().get(getSessionBean1().getBpelFilename());
//        System.out.println("*** APH-I1 : BPEL String " + bpelStr);
        if (bpelStr != null) {
            // Get the processed Activities
            Properties processedActivities = getSessionBean1().getProcessedActivities();
            // Define Layout Properties
            BPEL2SVGFactory factory = BPEL2SVGFactory.getInstance();
            factory.setIconSource("icons");
            LayoutManager layoutManager = factory.getLayoutManager();
            layoutManager.setProcessedActivities(processedActivities);
            // Set Horizontal
            layoutManager.setVerticalLayout(false);
            // Process BPEL
            bpel.processBpelString(bpelStr);
            // Layout SVG
            layoutManager.layoutSVG(bpel.getRootActivity());
            // Write SVG
            SVGInterface svg = new SVGImpl();
            svg.setRootActivity(bpel.getRootActivity());
//            System.out.println("*** APH-I2 : SVG String " + bpel.getRootActivity().getSVGString());
            // Generate New Filename
            getSessionBean1().resetSvgFilename();
            svg.store(getSessionBean1().getSvgFile());
            getSessionBean1().setSvgHeight(layoutManager.getSvgHeight());
            getSessionBean1().setSvgWidth(layoutManager.getSvgWidth());
        }
    }


Bookmark and Share
Comments:

Hi,

I try your simple monitoring application. Looks great and idea is fantastic ! But there is one problem when in one SERVICEUNIT is deployed mode bpel processes.
When this is the situation the monitor fails !
Here is simple exception trace:
org.xml.sax.SAXParseException: The processing instruction target matching "[xX][mM][lL]" is not allowed.

Because in the zip file there are more bpel processes the <xml .... > tak occured multiple time and this can not be parsed.

Do you have the solution about this problem ?

BRs,
Martin Novoty

Posted by Martin Novoty on February 02, 2009 at 03:06 PM GMT #

Hi,

The previous problem is solved !
In the method:
protected void loadBPELFiles() ...
StringBuffer bpelSB has to be deleted when going to next *.bpel file in the service unit:

"bpelFileAsString.put(bpelName, bpelSB.toString());
bpelSB.setLenght(0);"

BRs,
I.

Posted by Ivan Budzel on February 02, 2009 at 04:42 PM GMT #

Thanks I've modified the code

Posted by Andrew on February 02, 2009 at 06:17 PM GMT #

Hi,
I did some small changes, which are maybe interesting for other persons too.
http://drop.io/vt2u50t
The BPEL Instance screen now is showing the Sec difference between Start and End time, the BPEL Activity window now has additionally the difference in seconds and milliseconds.

Here is the source folder http://drop.io/246tpma .

Best regards
Johannes Holzer

Posted by Johannes Holzer on July 16, 2009 at 05:44 AM GMT #

Hi,

Your monitor is very interessant.

BPEL2SVGMonitorWebApplication.war is good and it is useful and I want to add function for my api
but BPEL2SVGMonitorWebApplication Project want the two following libraries :
- BPEL2SVGJavaLibrary
- SVGJavaLibrary
These libraries are not the good to build the project (I have take these 2 libraries here in the same page of the war file)

Please where is the good version ?

Posted by Yvon on August 19, 2009 at 01:16 PM GMT #

Yvon,

The two attached files are NetBeans Projects with all the Source code so if you extract the zip files into an appropriately named directory you should be able to build the jars

If you still have an issue let me know and I will put some pre-built jars on the wiki entry.

Posted by Andrew on August 19, 2009 at 02:29 PM GMT #

Thanks Andrew , all it's ok now !
But I precise to the beginner that we must replace in SessionBean1.java and BPELMonitorPage.java all the import com.tox.aph.... by com.sun.aph

Thanks again andrew

Posted by Yvon on August 20, 2009 at 06:09 AM GMT #

Post a Comment:
  • HTML Syntax: NOT allowed