/** * OpenKM, Open Document Management System (http://www.openkm.com) * Copyright (c) 2006-2011 Paco Avila & Josep Llort * * No bytes were intentionally harmed during the development of this application. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package com.openkm.util; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.hibernate.Hibernate; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.openkm.bean.workflow.Comment; import com.openkm.bean.workflow.ProcessDefinition; import com.openkm.bean.workflow.ProcessInstance; import com.openkm.bean.workflow.TaskInstance; import com.openkm.bean.workflow.Token; import com.openkm.bean.workflow.Transition; public class WorkflowUtils { /** * Copy process definition */ @SuppressWarnings("rawtypes") public static ProcessDefinition copy(org.jbpm.graph.def.ProcessDefinition pd) { ProcessDefinition vo = new ProcessDefinition(); vo.setName(pd.getName()); vo.setDescription(pd.getDescription()); vo.setId(pd.getId()); vo.setVersion(pd.getVersion()); ArrayList<String> al = new ArrayList<String>(); for (Iterator it = pd.getNodes().iterator(); it.hasNext(); ) { org.jbpm.graph.def.Node n = (org.jbpm.graph.def.Node) it.next(); al.add(n.getName()); } vo.setNodes(al); return vo; } /** * Copy process instance */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static ProcessInstance copy(org.jbpm.graph.exe.ProcessInstance pi) { ProcessInstance vo = new ProcessInstance(); if (pi.getStart() != null) { Calendar start = Calendar.getInstance(); start.setTime(pi.getStart()); vo.setStart(start); } if (pi.getEnd() != null) { Calendar end = Calendar.getInstance(); end.setTime(pi.getEnd()); vo.setEnd(end); } vo.setId(pi.getId()); vo.setVersion(pi.getVersion()); vo.setKey(pi.getKey()); vo.setEnded(pi.hasEnded()); vo.setSuspended(pi.isSuspended()); // TODO https://jira.jboss.org/jira/browse/JBPM-1778 if (pi.getContextInstance().getVariables() != null) { vo.setVariables(pi.getContextInstance().getVariables()); // Workaround for LazyInitializationException for (String key : vo.getVariables().keySet()) { Hibernate.initialize(vo.getVariables().get(key)); } } else { vo.setVariables(new HashMap<String, Object>()); } ArrayList<Token> al = new ArrayList<Token>(); for (Iterator it = pi.findAllTokens().iterator(); it.hasNext(); ) { org.jbpm.graph.exe.Token tk = (org.jbpm.graph.exe.Token) it.next(); al.add(copy(tk)); } vo.setAllTokens(al); vo.setRootToken(copy(pi.getRootToken())); vo.setProcessDefinition(copy(pi.getProcessDefinition())); return vo; } /** * Copy task instance */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static TaskInstance copy(org.jbpm.taskmgmt.exe.TaskInstance ti) { TaskInstance vo = new TaskInstance(); if (ti.getCreate() != null) { Calendar create = Calendar.getInstance(); create.setTime(ti.getCreate()); vo.setCreate(create); } if (ti.getStart() != null) { Calendar start = Calendar.getInstance(); start.setTime(ti.getStart()); vo.setStart(start); } if (ti.getEnd() != null) { Calendar end = Calendar.getInstance(); end.setTime(ti.getEnd()); vo.setEnd(end); } if (ti.getDueDate() != null) { Calendar dueDate = Calendar.getInstance(); dueDate.setTime(ti.getDueDate()); vo.setDueDate(dueDate); } vo.setId(ti.getId()); vo.setName(ti.getName()); vo.setDescription(ti.getDescription()); vo.setVariables(ti.getVariables()); ArrayList<Comment> al = new ArrayList<Comment>(); for (Iterator it = ti.getComments().iterator(); it.hasNext(); ) { org.jbpm.graph.exe.Comment c = (org.jbpm.graph.exe.Comment) it.next(); Comment tc = new Comment(); tc.setActorId(c.getActorId()); tc.setMessage(c.getMessage()); Calendar time = Calendar.getInstance(); time.setTime(c.getTime()); tc.setTime(time); al.add(tc); } vo.setComments(al); vo.setActorId(ti.getActorId()); vo.setOpen(ti.isOpen()); vo.setLast(ti.isLast()); vo.setSuspended(ti.isSuspended()); vo.setStartTaskInstance(ti.isStartTaskInstance()); HashSet<String> hs = new HashSet<String>(); for (Iterator it = ti.getPooledActors().iterator(); it.hasNext(); ) { hs.add(it.next().toString()); } vo.setPooledActors(hs); ArrayList<Transition> alT = new ArrayList<Transition>(); // TODO http://www.jboss.com/index.html?module=bb&op=viewtopic&t=144049 if (ti.getEnd() == null) { for (Iterator it = ti.getAvailableTransitions().iterator(); it.hasNext(); ) { org.jbpm.graph.def.Transition tr = (org.jbpm.graph.def.Transition) it.next(); alT.add(copy(tr)); } } // Sort Collections.sort(alT); vo.setAvailableTransitions(alT); vo.setToken(copy(ti.getToken())); vo.setProcessInstance(copy(ti.getProcessInstance())); return vo; } /** * Copy token */ @SuppressWarnings("rawtypes") public static Token copy(org.jbpm.graph.exe.Token t) { Token vo = null; if (t != null) { vo = new Token(); vo.setName(t.getName()); vo.setId(t.getId()); vo.setSuspended(t.isSuspended()); ArrayList<Comment> alC = new ArrayList<Comment>(); if (t.getComments() != null) { for (Iterator it = t.getComments().iterator(); it.hasNext(); ) { org.jbpm.graph.exe.Comment c = (org.jbpm.graph.exe.Comment) it.next(); alC.add(copy(c)); } } vo.setComments(alC); vo.setParent(copy(t.getParent())); vo.setNode(t.getNode().getName()); if (t.getStart() != null) { Calendar start = Calendar.getInstance(); start.setTime(t.getStart()); vo.setStart(start); } if (t.getEnd() != null) { Calendar end = Calendar.getInstance(); end.setTime(t.getEnd()); vo.setEnd(end); } ArrayList<Transition> alT = new ArrayList<Transition>(); for (Iterator it = t.getAvailableTransitions().iterator(); it.hasNext(); ) { org.jbpm.graph.def.Transition tr = (org.jbpm.graph.def.Transition) it.next(); alT.add(copy(tr)); } // Sort Collections.sort(alT); vo.setAvailableTransitions(alT); // Causes recursion //vo.setProcessInstance(copy(t.getProcessInstance())); } return vo; } /** * Copy comment */ public static Comment copy(org.jbpm.graph.exe.Comment c) { Comment vo = new Comment(); vo.setActorId(c.getActorId()); vo.setMessage(c.getMessage()); Calendar time = Calendar.getInstance(); time.setTime(c.getTime()); vo.setTime(time); return vo; } /** * Copy transition */ public static Transition copy(org.jbpm.graph.def.Transition t) { Transition vo = new Transition(); vo.setId(t.getId()); vo.setName(t.getName()); vo.setFrom(t.getFrom().getName()); vo.setTo(t.getTo().getName()); return vo; } /** * Get diagram info */ public static WorkflowUtils.DiagramInfo getDiagramInfo(InputStream is) { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setFeature("http://xml.org/sax/features/validation", false); dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); DocumentBuilder db = dbf.newDocumentBuilder(); if (is != null) { Document doc = db.parse(is); doc.getDocumentElement().normalize(); Element processDiagramElement = doc.getDocumentElement(); final String widthString = processDiagramElement.getAttribute("width"); final String heightString = processDiagramElement.getAttribute("height"); final List<DiagramNodeInfo> diagramNodeInfoList = new ArrayList<DiagramNodeInfo>(); 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 ); return diagramInfo; } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } /** * Diagram info helper */ public static final class DiagramInfo implements Serializable { private static final long serialVersionUID = 1L; private final int width; private final int height; private final Map<String,DiagramNodeInfo> nodeMap; public DiagramInfo(final int height, final int width, final List<DiagramNodeInfo> nodeList) { this.height = height; this.width = width; final LinkedHashMap<String, DiagramNodeInfo> map = new LinkedHashMap<String, DiagramNodeInfo>(); for (DiagramNodeInfo nodeInfo : nodeList) { map.put(nodeInfo.getName(), nodeInfo); } nodeMap = Collections.unmodifiableMap(map); } public int getHeight() { return height; } public Map<String, DiagramNodeInfo> getNodeMap() { return nodeMap; } public List<DiagramNodeInfo> getNodes() { return Collections.unmodifiableList(new ArrayList<DiagramNodeInfo>(nodeMap.values())); } public int getWidth() { return width; } } /** * Diagram node info */ 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; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("{"); sb.append("name="); sb.append(name); sb.append(", x="); sb.append(x); sb.append(", y="); sb.append(y); sb.append(", width="); sb.append(width); sb.append(", height="); sb.append(height); sb.append("}"); return sb.toString(); } } }