1 2 Previous Next 16 Replies Latest reply on Nov 30, 2010 2:21 AM by Giovanni Marigi

    Workflow process visual rapresentation

    paolo di tommaso Newbie

      In my JBPM based application, I would like to show a visual representation of teh current status of a ProcessInstance (like the reference web console provided application).

      I see that the process .par file contains the processimage.jpg image, but hot to render the ProcessInstance status on it? Is there an API to do it ? Where to start?


      Thank you, Paolo

        • 1. Re: Workflow process visual rapresentation
          Ronald van Kuijk Master

          look at the implementation of the webconsole.... the source IS open you know....

          • 2. Re: Workflow process visual rapresentation
            paolo di tommaso Newbie

            ProcessImageTag.java ... I suppose ..

            • 3. Re: Workflow process visual rapresentation
              Ronald van Kuijk Master

              correct (out of the top of my head)

              • 4. Re: Workflow process visual rapresentation
                David Roberts Apprentice

                Does JBPM 3.2.1 still use ProcessImageTag.java?

                I noticed in 3.2.1, the jbpm-console diagrams have blue borders etc, and the active nodes have a "running" state. I would like use this sort of diagram in my own app, and I have used ProcessImageTag.java in my own app, but all I get on my websale diagram is a red box around one of the forks, which doesn't even fit properly, but using the jbpm-console on the same websale, it looks quite nice, with the blue borders and running state etc.

                I have tried looking at the JBPM 3.2.1 console source code, but can't seem to find how the diagram is created. Can anyone point me in the right direction please?[/img]

                • 5. Re: Workflow process visual rapresentation
                  Ronald van Kuijk Master

                  no, it uses jbpm4jsf tags. This is a 'subproject' in the jbpm 3.2.1 source

                  • 6. Re: Workflow process visual rapresentation
                    David Roberts Apprentice

                    Thanks. Is there a Wiki, or do you know where I may be able to get help on how to implement this same feature using my own webapp? I am not using any JSF. Looking at the jbpm4jsf source code is quite difficult when you haven't used JSF before.

                    • 7. Re: Workflow process visual rapresentation
                      Ronald van Kuijk Master

                      no, unfortunately there is no wiki or any docs that describe how to do this in another way.

                      • 8. Re: Workflow process visual representation
                        David Roberts Apprentice

                        Okay, I have managed to get the Process Diagram (and current status etc) working in my own webapp, that does NOT use JSF. So basically, if you want to display the JBPM 3.2.1 web console diagram in your own, normal JSP page, you can do the following:

                        1) Use the ProcessImageServlet.java in your own web application. Code below:

                        public class ProcessImageServlet extends HttpServlet {
                        
                         private static final long serialVersionUID = 1L;
                        
                         protected void doGet(HttpServletRequest request, HttpServletResponse response)
                         throws ServletException, IOException {
                         long processDefinitionId = Long.parseLong( request.getParameter( "definitionId" ) );
                         JbpmContext jbpmContext = null;
                         try{
                         jbpmContext = StaticVariables.jbpmConfiguration.createJbpmContext();
                         ProcessDefinition processDefinition = jbpmContext.getGraphSession().loadProcessDefinition(processDefinitionId);
                         byte[] bytes = processDefinition.getFileDefinition().getBytes("processimage.jpg");
                         OutputStream out = response.getOutputStream();
                         out.write(bytes);
                         out.flush();
                         }
                         catch (Exception e) {
                         e.printStackTrace();
                         }
                         finally {
                         jbpmContext.close();
                         }
                        
                         // leave this in. it is in case we want to set the mime type later.
                         // get the mime type
                         // String contentType = URLConnection.getFileNameMap().getContentTypeFor( fileName );
                         // set the content type (=mime type)
                         // response.setContentType( contentType );
                         }
                        


                        2) Add the ProcessImageServlet to your web.xml file, code below:
                        <!-- This is the process image servlet -->
                         <servlet>
                         <servlet-name>Process Image Servlet</servlet-name>
                         <servlet-class>za.co.mycompany.workflow.webapp.servlet.ProcessImageServlet</servlet-class>
                         <load-on-startup>1</load-on-startup>
                         </servlet>
                        
                         <servlet-mapping>
                         <servlet-name>Process Image Servlet</servlet-name>
                         <url-pattern>/processImage</url-pattern>
                         </servlet-mapping>
                        


                        3) In my action class, I have the following method. (Remember that I have supplied the processInstanceId as a parameter).
                        public ActionForward viewProcessInstanceImage(ActionMapping mapping, ActionForm form,
                         HttpServletRequest request,
                         HttpServletResponse response)
                         throws Exception {
                         String processInstanceId = request.getParameter("processInstanceId");
                         JbpmContext jbpmContext = null;
                         try {
                         jbpmContext = StaticVariables.jbpmConfiguration.createJbpmContext();
                         GraphSession graphSession = jbpmContext.getGraphSession();
                         ProcessInstance processInstance = graphSession.getProcessInstance(Long.parseLong(processInstanceId));
                         ProcessDefinition processDefinition = processInstance.getProcessDefinition();
                         processImage(request, processDefinition);
                         List processInstanceTokens = processInstance.findAllTokens();
                         for(int x = 0; x < processInstanceTokens.size(); x++) {
                         Token token = (Token)processInstanceTokens.get(x);
                         token.getNode().getName(); //avoids LazyInitializationException on jsp page.
                         }
                         request.setAttribute("processInstanceTokens", processInstanceTokens);
                         request.setAttribute("processInstanceId", processInstanceId);
                         request.setAttribute("processDefinitionId", processDefinition.getId()+"");
                         }
                         catch (Exception e) {
                         e.printStackTrace();
                         }
                         finally {
                         jbpmContext.close();
                         }
                        
                         return mapping.findForward("processInstanceImage"); //directs to processInstanceImage.jsp
                         }
                        


                        public void processImage(HttpServletRequest request, ProcessDefinition processDefinition) {
                         try {
                         final FileDefinition fileDefinition = processDefinition.getFileDefinition();
                         if (! fileDefinition.hasFile("gpd.xml")) {
                         //return;
                         }
                         Document document = XmlUtil.parseXmlInputStream(fileDefinition.getInputStream("gpd.xml"));
                         Element processDiagramElement = document.getDocumentElement();
                         final String widthString = processDiagramElement.getAttribute("width");
                         final String heightString = processDiagramElement.getAttribute("height");
                         final List diagramNodeInfoList = new ArrayList();
                         final NodeList nodeNodeList = processDiagramElement.getElementsByTagName("node");
                         final int nodeNodeListLength = nodeNodeList.getLength();
                         for (int i = 0; i < nodeNodeListLength; i ++) {
                         final Node nodeNode = nodeNodeList.item(i);
                         if (nodeNode instanceof Node && nodeNode.getParentNode() == processDiagramElement) {
                         final Element nodeElement = (Element) nodeNode;
                         final String nodeName = nodeElement.getAttribute("name");
                         final String nodeXString = nodeElement.getAttribute("x");
                         final String nodeYString = nodeElement.getAttribute("y");
                         final String nodeWidthString = nodeElement.getAttribute("width");
                         final String nodeHeightString = nodeElement.getAttribute("height");
                         final DiagramNodeInfo nodeInfo = new DiagramNodeInfo(
                         nodeName,
                         Integer.parseInt(nodeXString),
                         Integer.parseInt(nodeYString),
                         Integer.parseInt(nodeWidthString),
                         Integer.parseInt(nodeHeightString)
                         );
                         diagramNodeInfoList.add(nodeInfo);
                         }
                         }
                         final DiagramInfo diagramInfo = new DiagramInfo(
                         Integer.parseInt(heightString),
                         Integer.parseInt(widthString),
                         diagramNodeInfoList
                         );
                         request.setAttribute("diagramInfo", diagramInfo);
                         } catch (Exception ex) {
                         ex.printStackTrace();
                         }
                         }
                        

                        public static final class DiagramInfo implements Serializable {
                         private static final long serialVersionUID = 1L;
                        
                         private final int width;
                         private final int height;
                         private final Map nodeMap;
                        
                         public DiagramInfo(final int height, final int width, final List/*<DiagramNodeInfo>*/ nodeList) {
                         this.height = height;
                         this.width = width;
                         final LinkedHashMap map = new LinkedHashMap();
                         for (int x = 0; x < nodeList.size(); x++) {
                         DiagramNodeInfo nodeInfo = (DiagramNodeInfo)nodeList.get(x);
                         map.put(nodeInfo.getName(), nodeInfo);
                         }
                         nodeMap = Collections.unmodifiableMap(map);
                         }
                         public int getHeight() {
                         return height;
                         }
                         public Map getNodeMap() {
                         return nodeMap;
                         }
                         public List getNodes() {
                         return Collections.unmodifiableList(new ArrayList(nodeMap.values()));
                         }
                         public int getWidth() {
                         return width;
                         }
                         }
                        
                         public static final class DiagramNodeInfo implements Serializable {
                         private static final long serialVersionUID = 1L;
                        
                         private final String name;
                         private final int x;
                         private final int y;
                         private final int width;
                         private final int height;
                        
                         public DiagramNodeInfo(final String name, final int x, final int y, final int width, final int height) {
                         this.height = height;
                         this.name = name;
                         this.width = width;
                         this.x = x;
                         this.y = y;
                         }
                         public int getHeight() {
                         return height;
                         }
                         public String getName() {
                         return name;
                         }
                         public int getWidth() {
                         return width;
                         }
                         public int getX() {
                         return x;
                         }
                         public int getY() {
                         return y;
                         }
                         }
                        


                        4) That action method mentioned above will return me to a jsp page which will display the image. JSP code below:
                        <%DiagramInfo diagramInfo = (DiagramInfo)request.getAttribute("diagramInfo");%>
                        <%if (diagramInfo != null) { %>
                         <%String processDefinitionId = (String)request.getAttribute("processDefinitionId");%>
                         <%String style="position:relative;height:"+diagramInfo.getHeight()+"px;width:"+diagramInfo.getWidth()+"px;";%>
                         <div style="<%=style%>">
                         <img alt="Process Diagram"
                         src="processImage?definitionId=<%=processDefinitionId%>"
                         style="position:absolute;top:0;left:0"/>
                         <%List tokenList = (List)request.getAttribute("processInstanceTokens"); %>
                         <%for (int x = 0; x < tokenList.size(); x++) { %>
                         <%Token token = (Token)tokenList.get(x);%>
                         <%DiagramNodeInfo node = (DiagramNodeInfo)diagramInfo.getNodeMap().get(token.getNode().getName());%>
                         <%style="top:"+(node.getY()-12)+"px;left:"+(node.getX()+2)+"px;width:"+(node.getWidth()-3)+"px;height:"+(node.getHeight()+11)+"px";%>
                         <%
                         String styleClass = "pboxs";
                         if (token.getEnd() != null) {
                         styleClass = "pboxs_e";
                         }
                         if (token.isSuspended()) {
                         styleClass = "pboxs_s";
                         }
                         %>
                         <div style="<%=style%>" class="<%=styleClass%>">
                         </div>
                         <%style = "top:"+node.getY()+"px;left:"+node.getX()+"px;width:"+(node.getWidth()-3)+"px;height:"+(node.getHeight()-3)+"px";%>
                         <%
                         styleClass = "pbox";
                         if (token.getEnd() != null) {
                         styleClass = "pbox_e";
                         }
                         if (token.isSuspended()) {
                         styleClass = "pbox_s";
                         }
                         %>
                         <div style="<%=style%>" class="<%=styleClass%>">
                         </div>
                         <%style = "top:"+(node.getY()-14)+"px;left:"+node.getX()+"px;width:"+(node.getWidth()-1)+"px";%>
                         <%
                         styleClass = "pboxc";
                         if (token.getEnd() != null) {
                         styleClass = "pboxc_e";
                         }
                         if (token.isSuspended()) {
                         styleClass = "pboxc_s";
                         }
                         %>
                         <div style="<%=style%>" class="pboxce">
                         <div class="<%=styleClass%>">
                         <%
                         String status = "";
                         if (token.getEnd() == null && !token.isSuspended()) {
                         status = "Running";
                         }
                         if (token.getEnd() == null && token.isSuspended()) {
                         status = "Suspended";
                         }
                         if (token.getEnd() != null) {
                         status = "Ended";
                         }
                         if (token.getName() != null) {
                         status += " \""+token.getName()+"\"" ;
                         }
                         %>
                         <a href="tokens.html?id=<%=(token.getId()+"")%>">
                         <%=status%>
                         </a>
                         </div>
                         </div>
                         <%}//end for loop%>
                         </div>
                        <%}%>
                        


                        5) In my webapps stylesheet, I added the following:
                        /*JBPM Process Image classes------------------------------------------------*/
                        div.pbox, div.pbox_s, div.pbox_e {
                         position:absolute;
                         border-width:1px;
                         border-style:solid;
                        }
                        
                        div.pbox {
                         border-color:#0000ff;
                        }
                        
                        div.pbox_s {
                         border-color:#aa6600;
                        }
                        
                        div.pbox_e {
                         border-color:#cc0000;
                        }
                        
                        div.pboxs, div.pboxs_s, div.pboxs_e {
                         position:absolute;
                         border-right-width:1px;
                         border-right-style:solid;
                         border-bottom-width:1px;
                         border-bottom-style:solid;
                        }
                        
                        div.pboxs {
                         border-right-color:#9999ff;
                         border-bottom-color:#9999ff;
                        }
                        
                        div.pboxs_s {
                         border-right-color:#ffaa99;
                         border-bottom-color:#ffaa99;
                        }
                        
                        div.pboxs_e {
                         border-right-color:#660000;
                         border-bottom-color:#660000;
                        }
                        
                        div.pboxce {
                         position:absolute;
                         overflow:hidden;
                        }
                        
                        div.pboxc, div.pboxc_s, div.pboxc_e {
                         cursor:default;
                         font-size:10px;
                         white-space:nowrap;
                         color:#ffffff;
                         padding-left:3px;
                         padding-right:3px;
                         border-width:1px;
                         border-style:solid;
                        }
                        
                        div.pboxc {
                         border-color:#0000ff;
                         background-color:#0000ff;
                        }
                        
                        div.pboxc_s {
                         border-color:#aa6600;
                         background-color:#aa6600;
                        }
                        
                        div.pboxc_e {
                         border-color:#cc0000;
                         background-color:#cc0000;
                        }
                        
                        div.pboxc a, div.pboxc_s a, div.pboxc_e a {
                         color:#ffffff;
                         text-decoration:none;
                        }
                        
                        div.pboxc a:hover, div.pboxc_s a:hover, div.pboxc_e a:hover {
                         text-decoration:underline;
                        }
                        /*---------------------------------------------END JBPM Process Image classes*/
                        


                        I think that's it. This displayed the process instance diagram I asked for, exactly as is displayed on the JBPM 3.2.1 jbpm-console app. This should hopefully help some of you that don't use JSF to integrate the functionality into your own webapp. I haven't optimized my code yet, as I did this in a hurry, but I'm sure you will get the idea. Please feel free to post comments on anything I did wrong, or anything I could of done better.

                        Please note that most of the code above was taken/adapted from the JBPM 3.2.1 jbpm-console source code. I had to modify the DiagramInfo and DiagramNodeInfo classes slightly to be jdk 1.4 compatible, as that's what im using.

                        • 9. Re: Workflow process visual rapresentation
                          Peter Ottomanelli Newbie

                          Where is the Tokens.html page you are referencing there?

                          • 10. Re: Workflow process visual rapresentation
                            David Roberts Apprentice

                             

                            Where is the Tokens.html page you are referencing there?

                            I haven't created that yet. The jbpm-console has a link from the image to the token, so I was going to do something similair. You can just remove that link, or create your own link to a servlet or something that you might want that text to link to.

                            • 11. Re: Workflow process visual rapresentation
                              Alan Nisbet Newbie

                              Excellent post dleerob, followed you're instructions and got this working relatively easily.

                              However now I need to be able to click on a node within the diagram and display node information, and other application specific information such as the messages sent / recevied as a result of the action performed within this node!

                              Does the JBPM Console implement such functionality, and if it does can anyone point me towards the code that does it. I have been searching about the code for quite some time and cannot seem to locate anything.

                              Hopefully someone is still watching this thread!

                              • 12. Re: Workflow process visual rapresentation
                                Ronald van Kuijk Master

                                 

                                Does the JBPM Console implement such functionality


                                No


                                • 13. Re: Workflow process visual rapresentation
                                  Davide Cavestro Newbie

                                  Thank you dleerob, you did a very good job!

                                  • 14. Re: Workflow process visual rapresentation
                                    Hugo Wurzelbutz Newbie

                                    hi

                                    i'd need a visual representation of my workflows too.
                                    my problem is that i can't find the jbpm-console sources. i looked at the SNV Repo( http://anonsvn.jboss.org/repos/jbpm/jbpm3/trunk/ ) but didnt find the console there.

                                    i also read that there should be a SEAM based jbpm console ( http://sfwk.org/Community/JBPMConsoleInSeam ) which i would like to see caus my application is based on SEAM. and again i cant find the sources :/

                                    1 2 Previous Next