1 package org.jbpm.jpdl.xml; 2 3 import java.io.IOException ; 4 import java.io.Reader ; 5 import java.util.ArrayList ; 6 import java.util.Collection ; 7 import java.util.Iterator ; 8 import java.util.List ; 9 import java.util.StringTokenizer ; 10 11 import org.apache.commons.logging.Log; 12 import org.apache.commons.logging.LogFactory; 13 import org.dom4j.Document; 14 import org.dom4j.Element; 15 import org.jbpm.context.def.VariableAccess; 16 import org.jbpm.db.JbpmSession; 17 import org.jbpm.graph.action.ActionTypes; 18 import org.jbpm.graph.def.Action; 19 import org.jbpm.graph.def.Event; 20 import org.jbpm.graph.def.ExceptionHandler; 21 import org.jbpm.graph.def.GraphElement; 22 import org.jbpm.graph.def.Node; 23 import org.jbpm.graph.def.NodeCollection; 24 import org.jbpm.graph.def.ProcessDefinition; 25 import org.jbpm.graph.def.Transition; 26 import org.jbpm.graph.node.NodeTypes; 27 import org.jbpm.graph.node.StartState; 28 import org.jbpm.graph.node.TaskNode; 29 import org.jbpm.instantiation.Delegation; 30 import org.jbpm.jpdl.JpdlException; 31 import org.jbpm.scheduler.def.CancelTimerAction; 32 import org.jbpm.scheduler.def.CreateTimerAction; 33 import org.jbpm.taskmgmt.def.Swimlane; 34 import org.jbpm.taskmgmt.def.Task; 35 import org.jbpm.taskmgmt.def.TaskController; 36 import org.jbpm.taskmgmt.def.TaskMgmtDefinition; 37 38 39 public class JpdlXmlReader { 40 41 Reader reader = null; 42 List problems = new ArrayList (); 43 JbpmSession jbpmSession = null; 44 ProcessDefinition processDefinition = null; 45 Collection unresolvedTransitionDestinations = null; 46 Collection unresolvedActionReferences = null; 47 48 private static final String JPDL_SCHEMA_NAME = "jpdl-3.0.xsd"; 49 50 public JpdlXmlReader(Reader reader) { 51 this.reader = reader; 52 } 53 54 public JpdlXmlReader(Reader reader, JbpmSession jbpmSession) { 55 this.reader = reader; 56 this.jbpmSession = jbpmSession; 57 } 58 59 public JbpmSession getJbpmSession() { 60 return jbpmSession; 61 } 62 63 public void close() throws IOException { 64 reader.close(); 65 } 66 67 public int read(char[] cbuf, int off, int len) throws IOException { 68 return reader.read(cbuf, off, len); 69 } 70 71 public ProcessDefinition getProcessDefinition() { 72 return processDefinition; 73 } 74 75 public void addProblem(Problem p) { 76 problems.add(p); 77 } 78 79 public void addError(String description) { 80 log.error("invalid process xml: "+description); 81 addProblem(new Problem(Problem.LEVEL_ERROR, description)); 82 } 83 84 public void addError(String description, Throwable exception) { 85 log.error("invalid process xml: "+description, exception); 86 addProblem(new Problem(Problem.LEVEL_ERROR, description, exception)); 87 } 88 89 public void addWarning(String description) { 90 log.warn("process xml warning: "+description); 91 addProblem(new Problem(Problem.LEVEL_WARNING, description)); 92 } 93 94 public ProcessDefinition readProcessDefinition() { 95 processDefinition = ProcessDefinition.createNewProcessDefinition(); 97 98 problems = new ArrayList (); 100 unresolvedTransitionDestinations = new ArrayList (); 101 unresolvedActionReferences = new ArrayList (); 102 103 Document document = null; 105 106 SchemaValidationHelper helper = new SchemaValidationHelper(reader, JPDL_SCHEMA_NAME, "process definition"); 108 109 if (helper.isValid()) { 110 document = helper.getDocument(); 111 112 } else { for (Iterator i = helper.getProblems().iterator(); i.hasNext();) { 114 Problem problem = (Problem) i.next(); 115 this.addProblem(problem); 116 log.debug(problem.getDescription()); 117 } 118 119 throw new JpdlException(problems); 120 } 121 122 Element root = document.getRootElement(); 123 124 processDefinition.setName(root.attributeValue("name")); 126 127 readSwimlanes(root); 129 readActions(root, null, null); 130 readNodes(root, processDefinition); 131 readEvents(root, processDefinition); 132 readExceptionHandlers(root, processDefinition); 133 readTasks(root, null); 134 135 resolveTransitionDestinations(); 137 resolveActionReferences(); 138 verifySwimlaneAssignments(); 139 140 if (Problem.containsProblemsOfLevel(problems, Problem.LEVEL_ERROR)) { 141 throw new JpdlException(problems); 142 } 143 144 return processDefinition; 145 } 146 147 private void readSwimlanes(Element processDefinitionElement) { 148 Iterator iter = processDefinitionElement.elementIterator("swimlane"); 149 TaskMgmtDefinition taskMgmtDefinition = processDefinition.getTaskMgmtDefinition(); 150 while (iter.hasNext()) { 151 Element swimlaneElement = (Element) iter.next(); 152 String swimlaneName = swimlaneElement.attributeValue("name"); 153 if (swimlaneName==null) { 154 addWarning("there's a swimlane without a name"); 155 } else { 156 Swimlane swimlane = new Swimlane(swimlaneName); 157 Element assignmentElement = swimlaneElement.element("assignment"); 158 159 if (assignmentElement!=null) { 160 Delegation assignmentDelegation = readAssignmentDelegation(assignmentElement); 161 swimlane.setAssignmentDelegation(assignmentDelegation); 162 163 } else { 164 Task startTask = taskMgmtDefinition.getStartTask(); 165 if ( (startTask==null) 166 || (startTask.getSwimlane()!=swimlane) 167 ) { 168 addWarning("swimlane '"+swimlaneName+"' does not have an assignment"); 169 } 170 } 171 taskMgmtDefinition.addSwimlane(swimlane); 172 } 173 } 174 } 175 176 public void readNodes(Element element, NodeCollection nodeCollection) { 177 Iterator nodeElementIter = element.elementIterator(); 178 while (nodeElementIter.hasNext()) { 179 Element nodeElement = (Element) nodeElementIter.next(); 180 String nodeName = nodeElement.getName(); 181 Class nodeType = NodeTypes.getNodeType(nodeName); 183 if (nodeType!=null) { 184 try { 185 Node node = (Node) nodeType.newInstance(); 187 node.setProcessDefinition(processDefinition); 188 readNode(nodeElement, node, nodeCollection); 190 191 node.read(nodeElement, this); 195 196 } catch (Exception e) { 197 log.error("couldn't instantiate node '"+nodeName+"', of type '"+nodeType.getName()+"'", e); 198 } 199 } 200 } 201 } 202 203 public void readTasks(Element element, TaskNode taskNode) { 204 List elements = element.elements("task"); 205 TaskMgmtDefinition tmd = (TaskMgmtDefinition) processDefinition.getDefinition(TaskMgmtDefinition.class); 206 if (elements.size()>0) { 207 if (tmd==null) { 208 tmd = new TaskMgmtDefinition(); 209 } 210 processDefinition.addDefinition(tmd); 211 212 Iterator iter = elements.iterator(); 213 while (iter.hasNext()) { 214 Element taskElement = (Element) iter.next(); 215 readTask(taskElement, tmd, taskNode); 216 } 217 } 218 } 219 220 public Task readTask(Element taskElement, TaskMgmtDefinition taskMgmtDefinition, TaskNode taskNode) { 221 Task task = new Task(); 222 task.setProcessDefinition(processDefinition); 223 224 String name = taskElement.attributeValue("name"); 226 if (name!=null) { 227 task.setName(name); 228 taskMgmtDefinition.addTask(task); 229 } else if (taskNode!=null) { 230 task.setName(taskNode.getName()); 231 taskMgmtDefinition.addTask(task); 232 } 233 234 readTaskTimers(taskElement, task); 236 readEvents(taskElement, task); 237 readExceptionHandlers(taskElement, task); 238 239 task.setDescription(taskElement.attributeValue("description")); 241 task.setDueDate(taskElement.attributeValue("dueDate")); 242 String priorityText = taskElement.attributeValue("priority"); 243 if (priorityText!=null) { 244 task.setPriority(Task.parsePriority(priorityText)); 245 } 246 247 if (taskNode!=null) { 249 taskNode.addTask(task); 250 } 251 252 String blockingText = taskElement.attributeValue("blocking"); 254 if (blockingText!=null) { 255 if ( ("true".equalsIgnoreCase(blockingText)) 256 || ("yes".equalsIgnoreCase(blockingText)) 257 || ("on".equalsIgnoreCase(blockingText)) ) { 258 task.setBlocking(true); 259 } 260 } 261 262 String swimlaneName = taskElement.attributeValue("swimlane"); 264 Element assignmentElement = taskElement.element("assignment"); 265 266 if (swimlaneName!=null) { 268 Swimlane swimlane = taskMgmtDefinition.getSwimlane(swimlaneName); 269 if (swimlane==null) { 270 addWarning("task references unknown swimlane '"+swimlaneName+"':"+taskElement.asXML()); 271 } else { 272 task.setSwimlane(swimlane); 273 } 274 275 } else if (assignmentElement!=null) { 277 Delegation assignmentDelegation = readAssignmentDelegation(assignmentElement); 278 task.setAssignmentDelegation(assignmentDelegation); 279 280 } else { 282 addWarning("warning: no swimlane or assignment specified for task '"+taskElement.asXML()+"'"); 284 } 285 286 Element taskControllerElement = taskElement.element("controller"); 288 if (taskControllerElement!=null) { 289 task.setTaskController(readTaskController(taskControllerElement)); 290 } 291 292 return task; 293 } 294 295 private Delegation readAssignmentDelegation(Element assignmentElement) { 296 Delegation assignmentDelegation = new Delegation(); 297 String expression = assignmentElement.attributeValue("expression"); 298 if (expression!=null) { 299 assignmentDelegation.setProcessDefinition(processDefinition); 300 assignmentDelegation.setClassName("org.jbpm.identity.assignment.ExpressionAssignmentHandler"); 301 assignmentDelegation.setConfiguration("<expression>"+expression+"</expression>"); 302 303 } else { 304 assignmentDelegation.read(assignmentElement, this); 305 } 306 return assignmentDelegation; 307 } 308 309 private TaskController readTaskController(Element taskControllerElement) { 310 TaskController taskController = new TaskController(); 311 312 if (taskControllerElement.attributeValue("class")!=null) { 313 Delegation taskControllerDelegation = new Delegation(); 314 taskControllerDelegation.read(taskControllerElement, this); 315 taskController.setTaskControllerDelegation(taskControllerDelegation); 316 317 } else { 318 List variableAccesses = readVariableAccesses(taskControllerElement); 319 taskController.setVariableAccesses(variableAccesses); 320 } 321 return taskController; 322 } 323 324 public List readVariableAccesses(Element element) { 325 List variableAccesses = new ArrayList (); 326 Iterator iter = element.elementIterator("variable"); 327 while (iter.hasNext()) { 328 Element variableElement = (Element) iter.next(); 329 330 String variableName = variableElement.attributeValue("name"); 331 if (variableName==null) { 332 addProblem(new Problem(Problem.LEVEL_WARNING, "the name attribute of a variable element is required: "+variableElement.asXML())); 333 } 334 String access = variableElement.attributeValue("access", "read,write"); 335 String mappedName = variableElement.attributeValue("mapped-name"); 336 337 variableAccesses.add(new VariableAccess(variableName, access, mappedName)); 338 } 339 return variableAccesses; 340 } 341 342 public void readStartStateTask(Element startTaskElement, StartState startState) { 343 TaskMgmtDefinition taskMgmtDefinition = processDefinition.getTaskMgmtDefinition(); 344 Task startTask = readTask(startTaskElement, taskMgmtDefinition, null); 345 startTask.setStartState(startState); 346 if (startTask.getName()==null) { 347 startTask.setName(startState.getName()); 348 } 349 taskMgmtDefinition.setStartTask(startTask); 350 } 351 352 public void readNode(Element nodeElement, Node node, NodeCollection nodeCollection) { 353 String name = nodeElement.attributeValue("name"); 355 if (name!=null) { 356 node.setName(name); 357 } 358 359 nodeCollection.addNode(node); 361 362 readNodeTimers(nodeElement, node); 364 readEvents(nodeElement, node); 365 readExceptionHandlers(nodeElement, node); 366 367 addUnresolvedTransitionDestination(nodeElement, node); 369 } 370 371 private void readNodeTimers(Element nodeElement, Node node) { 372 Iterator iter = nodeElement.elementIterator("timer"); 373 while (iter.hasNext()) { 374 Element timerElement = (Element) iter.next(); 375 readNodeTimer(timerElement, node); 376 } 377 } 378 379 private void readNodeTimer(Element timerElement, Node node) { 380 String name = timerElement.attributeValue("name", node.getName()); 381 382 CreateTimerAction createTimerAction = new CreateTimerAction(); 383 createTimerAction.read(timerElement, this); 384 createTimerAction.setTimerName(name); 385 createTimerAction.setTimerAction(readSingleAction(timerElement)); 386 addAction(node, Event.EVENTTYPE_NODE_ENTER, createTimerAction); 387 388 CancelTimerAction cancelTimerAction = new CancelTimerAction(); 389 cancelTimerAction.setTimerName(name); 390 addAction(node, Event.EVENTTYPE_NODE_LEAVE, cancelTimerAction); 391 } 392 393 private void readTaskTimers(Element taskElement, Task task) { 394 Iterator iter = taskElement.elementIterator("timer"); 395 while (iter.hasNext()) { 396 Element timerElement = (Element) iter.next(); 397 readTaskTimer(timerElement, task); 398 } 399 } 400 401 private void readTaskTimer(Element timerElement, Task task) { 402 String name = timerElement.attributeValue("name", task.getName()); 403 if (name==null) name = "timer-for-task-"+task.getId(); 404 405 CreateTimerAction createTimerAction = new CreateTimerAction(); 406 createTimerAction.read(timerElement, this); 407 createTimerAction.setTimerName(name); 408 createTimerAction.setTimerAction(readSingleAction(timerElement)); 409 addAction(task, Event.EVENTTYPE_TASK_CREATE, createTimerAction); 410 411 Collection cancelEventTypes = new ArrayList (); 413 414 String cancelEventTypeText = timerElement.attributeValue("cancel-event"); 415 if (cancelEventTypeText!=null) { 416 StringTokenizer tokenizer = new StringTokenizer (cancelEventTypeText, ","); 418 while (tokenizer.hasMoreTokens()) { 419 cancelEventTypes.add(tokenizer.nextToken().trim()); 420 } 421 } else { 422 cancelEventTypes.add(Event.EVENTTYPE_TASK_END); 424 } 425 426 Iterator iter = cancelEventTypes.iterator(); 427 while (iter.hasNext()) { 428 String cancelEventType = (String ) iter.next(); 429 CancelTimerAction cancelTimerAction = new CancelTimerAction(); 430 cancelTimerAction.setTimerName(name); 431 addAction(task, cancelEventType, cancelTimerAction); 432 } 433 } 434 435 private void readEvents(Element parentElement, GraphElement graphElement) { 436 Iterator iter = parentElement.elementIterator("event"); 437 while (iter.hasNext()) { 438 Element eventElement = (Element) iter.next(); 439 String eventType = eventElement.attributeValue("type"); 440 if (!graphElement.hasEvent(eventType)) { 441 graphElement.addEvent(new Event(eventType)); 442 } 443 readActions(eventElement, graphElement, eventType); 444 } 445 } 446 447 public void readActions(Element eventElement, GraphElement graphElement, String eventType) { 448 Iterator nodeElementIter = eventElement.elementIterator(); 450 while (nodeElementIter.hasNext()) { 451 Element actionElement = (Element) nodeElementIter.next(); 452 String actionName = actionElement.getName(); 453 if (ActionTypes.hasActionName(actionName)) { 454 Action action = createAction(actionElement); 455 if ( (graphElement!=null) 456 && (eventType!=null) 457 ) { 458 addAction(graphElement, eventType, action); 460 } 461 } 462 } 463 } 464 465 private void addAction(GraphElement graphElement, String eventType, Action action) { 466 Event event = graphElement.getEvent(eventType); 467 if (event==null) { 468 event = new Event(eventType); 469 graphElement.addEvent(event); 470 } 471 event.addAction(action); 472 } 473 474 public Action readSingleAction(Element nodeElement) { 475 Action action = null; 476 Iterator iter = nodeElement.elementIterator(); 478 while (iter.hasNext() && (action==null)) { 479 Element candidate = (Element) iter.next(); 480 if (ActionTypes.hasActionName(candidate.getName())) { 481 action = createAction(candidate); 483 } 484 } 485 return action; 486 } 487 488 public Action createAction(Element actionElement) { 489 Action action = null; 491 String actionName = actionElement.getName(); 492 Class actionType = ActionTypes.getActionType(actionName); 493 try { 494 action = (Action) actionType.newInstance(); 495 } catch (Exception e) { 496 log.error("couldn't instantiate action '"+actionName+"', of type '"+actionType.getName()+"'", e); 497 } 498 499 readAction(actionElement, action); 501 502 return action; 503 } 504 505 public void readAction(Element element, Action action) { 506 String actionName = element.attributeValue("name"); 508 if (actionName!=null) { 509 action.setName(actionName); 510 processDefinition.addAction(action); 512 } 513 514 action.read(element, this); 517 } 518 519 private void readExceptionHandlers(Element graphElementElement, GraphElement graphElement) { 520 Iterator iter = graphElementElement.elementIterator("exception-handler"); 521 while (iter.hasNext()) { 522 Element exceptionHandlerElement = (Element) iter.next(); 523 readExceptionHandler(exceptionHandlerElement, graphElement); 524 } 525 } 526 527 private void readExceptionHandler(Element exceptionHandlerElement, GraphElement graphElement) { 528 ExceptionHandler exceptionHandler = new ExceptionHandler(); 530 exceptionHandler.setExceptionClassName(exceptionHandlerElement.attributeValue("exception-class")); 531 graphElement.addExceptionHandler(exceptionHandler); 533 534 Iterator iter = exceptionHandlerElement.elementIterator(); 536 while (iter.hasNext()) { 537 Element childElement = (Element) iter.next(); 538 if (ActionTypes.hasActionName(childElement.getName())) { 539 Action action = createAction(childElement); 540 exceptionHandler.addAction(action); 541 } 542 } 543 } 544 545 547 public void addUnresolvedTransitionDestination(Element nodeElement, Node node) { 548 unresolvedTransitionDestinations.add(new Object []{nodeElement, node}); 549 } 550 551 public void resolveTransitionDestinations() { 552 Iterator iter = unresolvedTransitionDestinations.iterator(); 553 while (iter.hasNext()) { 554 Object [] unresolvedTransition = (Object []) iter.next(); 555 Element nodeElement = (Element) unresolvedTransition[0]; 556 Node node = (Node) unresolvedTransition[1]; 557 resolveTransitionDestinations(nodeElement.elements("transition"), node); 558 } 559 } 560 561 public void resolveTransitionDestinations(List transitionElements, Node node) { 562 Iterator iter = transitionElements.iterator(); 563 while (iter.hasNext()) { 564 Element transitionElement = (Element) iter.next(); 565 resolveTransitionDestination(transitionElement, node); 566 } 567 } 568 569 public void resolveTransitionDestination(Element transitionElement, Node node) { 570 Transition transition = new Transition(); 571 transition.setProcessDefinition(processDefinition); 572 573 String name = transitionElement.attributeValue("name"); 575 if (name!=null) { 576 transition.setName(name); 577 } 578 579 node.addLeavingTransition(transition); 581 582 String toName = transitionElement.attributeValue("to"); 584 if (toName==null) { 585 addWarning("node '"+node.getFullyQualifiedName()+"' has a transition without a 'to'-attribute to specify its destinationNode"); 586 } else { 587 Node to = ((NodeCollection)node.getParent()).findNode(toName); 588 if (to==null) { 589 addWarning("transition to='"+toName+"' on node '"+node.getFullyQualifiedName()+"' cannot be resolved"); 590 } else { 591 to.addArrivingTransition(transition); 592 } 593 } 594 595 readActions(transitionElement, transition, Event.EVENTTYPE_TRANSITION); 597 598 readExceptionHandlers(transitionElement, transition); 599 } 600 601 603 public void addUnresolvedActionReference(Element actionElement, Action action) { 604 unresolvedActionReferences.add(new Object []{actionElement, action}); 605 } 606 607 public void resolveActionReferences() { 608 Iterator iter = unresolvedActionReferences.iterator(); 609 while (iter.hasNext()) { 610 Object [] unresolvedActionReference = (Object []) iter.next(); 611 Element actionElement = (Element) unresolvedActionReference[0]; 612 Action action = (Action) unresolvedActionReference[1]; 613 String referencedActionName = actionElement.attributeValue("ref-name"); 614 Action referencedAction = processDefinition.getAction(referencedActionName); 615 if (referencedAction==null) { 616 addWarning("couldn't resolve action reference in "+actionElement.asXML()); 617 } 618 action.setReferencedAction(referencedAction); 619 } 620 } 621 622 public void verifySwimlaneAssignments() { 624 TaskMgmtDefinition taskMgmtDefinition = processDefinition.getTaskMgmtDefinition(); 625 if ( (taskMgmtDefinition!=null) 626 && (taskMgmtDefinition.getSwimlanes()!=null) 627 ) { 628 Iterator iter = taskMgmtDefinition.getSwimlanes().values().iterator(); 629 while (iter.hasNext()) { 630 Swimlane swimlane = (Swimlane) iter.next(); 631 632 Task startTask = taskMgmtDefinition.getStartTask(); 633 Swimlane startTaskSwimlane = (startTask!=null ? startTask.getSwimlane() : null); 634 635 if ( (swimlane.getAssignmentDelegation()==null) 636 && (swimlane!=startTaskSwimlane) 637 ) { 638 addWarning("swimlane '"+swimlane.getName()+"' does not have an assignment"); 639 } 640 } 641 } 642 } 643 644 private static final Log log = LogFactory.getLog(JpdlXmlReader.class); 645 } 646 | Popular Tags |