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
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

Standard Generated SVG

The LayoutManager has now been extended to include the methods :
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

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.
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.

The information used within the page is obtained from the following BPEL Persistence / Monitoring tables:
To create this Page, I will assume we have a project, you will need to do the following:

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.

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.
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.
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.
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.
Related Articles
- Generating SVG From BPEL 2 Files.
- BPEL 2 SVG Update.
- BPEL 2 SVG Documentation.
- Simple Web Based BPEL 2 SVG Monitor Implementation.
Resources
- BPEL2SVGMonitorWebApplication.war.
- BPEL2SVGMonitorWebApplication Project.
- BPEL2SVGJavaLibrary.
- SVGJavaLibrary.
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

Standard Generated SVG

The LayoutManager has now been extended to include the methods :
- public synchronized void setProcessedActivities(Properties processedActivities)
- public synchronized Properties getProcessedActivities()
| 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

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.

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:
- Create a JDBC Data Source that points to the BPEL Persistence / Monitoring Database
- Rename the exiting Page2 to BPELMonitorPage
- Open BPELMonitorPage
- Drag a Grid Panel onto the Page
- Add Grid Panel
- Add Label
- Add DropDown : refreshDD
- Add Message Group
- Add Table
- Drag MONITORBPELINSTANCE from the Database connection and drop it onto the Table and modify to include the following:
- New Column : Button - showSVGBtn
- New Column : StaticText - BPELName
- Status
- Start Time
- End Time
- Update Time
- Instance Id
- Add Table
- New Column: StaticText - Activity
- Iteration
- Status
- Start Time
- End Time
- Add Markup Tag (we have a number of options here)
- iframe
- embed

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.
- Create a new Page
- Drag the SERVICEUNIT table onto the canvas (rename in the
SessionBean to suZipArchive)
- Drag the MONITORBPELACTIVITY onto the canvas and within the dialog create a new SessionBean row set called activityXPathRowSet
- Save
- Delete the page.
- Link Bpel Name (Instance Table) to bpelName property.
- Link Activity Name (Activity Table) to the activityName Property
- Set the extendedAttributes for the Markup tag as follows
- iframe tag : src="#{SessionBean1.svgFilename}" width="#{SessionBean1.svgWidth}" height="#{SessionBean1.svgHeight}"
- embed tag : src="#{SessionBean1.svgFilename}" width="#{SessionBean1.svgWidth}" height="#{SessionBean1.svgHeight}" type="image/svg+xml" pluginspage="http://www.adobe.com/svg/viewer/install/"
- Set the Column styles on the tables to the appropriate properties (see example code)

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()); } } |
zipFile.entries(); e.hasMoreElements()







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 #