KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > opensymphony > workflow > loader > WorkflowDescriptor


1 /*
2  * Copyright (c) 2002-2003 by OpenSymphony
3  * All rights reserved.
4  */

5 package com.opensymphony.workflow.loader;
6
7 import com.opensymphony.workflow.InvalidWorkflowDescriptorException;
8 import com.opensymphony.workflow.util.Validatable;
9
10 import org.w3c.dom.Element JavaDoc;
11 import org.w3c.dom.Node JavaDoc;
12 import org.w3c.dom.NodeList JavaDoc;
13
14 import org.xml.sax.*;
15
16 import java.io.*;
17
18 import java.util.*;
19
20 import javax.xml.parsers.DocumentBuilder JavaDoc;
21 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
22
23
24 /**
25  * Describes a single workflow
26  *
27  * @author <a HREF="mailto:plightbo@hotmail.com">Pat Lightbody</a>
28  * @version $Revision: 1.19 $
29  */

30 public class WorkflowDescriptor extends AbstractDescriptor implements Validatable {
31     //~ Static fields/initializers /////////////////////////////////////////////
32

33     public static final String JavaDoc XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
34     public static final String JavaDoc DOCTYPE_DECL = "<!DOCTYPE workflow PUBLIC \"-//OpenSymphony Group//DTD OSWorkflow 2.7//EN\" \"http://www.opensymphony.com/osworkflow/workflow_2_7.dtd\">";
35
36     //~ Instance fields ////////////////////////////////////////////////////////
37

38     protected List JavaDoc commonActionsList = new ArrayList(); // for preserving order
39
protected List JavaDoc globalActions = new ArrayList();
40     protected List JavaDoc initialActions = new ArrayList();
41     protected List JavaDoc joins = new ArrayList();
42     protected List JavaDoc registers = new ArrayList();
43     protected List JavaDoc splits = new ArrayList();
44     protected List JavaDoc steps = new ArrayList();
45     protected Map commonActions = new HashMap();
46     protected Map metaAttributes = new HashMap();
47     protected Map timerFunctions = new HashMap();
48
49     //~ Constructors ///////////////////////////////////////////////////////////
50

51     public WorkflowDescriptor() {
52     }
53
54     public WorkflowDescriptor(Element JavaDoc root) {
55         init(root);
56     }
57
58     //~ Methods ////////////////////////////////////////////////////////////////
59

60     public ActionDescriptor getAction(int id) {
61         // check global actions
62
for (Iterator iterator = globalActions.iterator(); iterator.hasNext();) {
63             ActionDescriptor actionDescriptor = (ActionDescriptor) iterator.next();
64
65             if (actionDescriptor.getId() == id) {
66                 return actionDescriptor;
67             }
68         }
69
70         // check steps
71
for (Iterator iterator = steps.iterator(); iterator.hasNext();) {
72             StepDescriptor stepDescriptor = (StepDescriptor) iterator.next();
73             ActionDescriptor actionDescriptor = stepDescriptor.getAction(id);
74
75             if (actionDescriptor != null) {
76                 return actionDescriptor;
77             }
78         }
79
80         return null;
81     }
82
83     /**
84      * Get a Map of the common actions specified, keyed on actionId (an Integer)
85      * @return A list of {@link ActionDescriptor} objects
86      */

87     public Map getCommonActions() {
88         return commonActions;
89     }
90
91     /**
92      * Get a List of the global actions specified
93      * @return A list of {@link ActionDescriptor} objects
94      */

95     public List JavaDoc getGlobalActions() {
96         return globalActions;
97     }
98
99     public ActionDescriptor getInitialAction(int id) {
100         for (Iterator iterator = initialActions.iterator(); iterator.hasNext();) {
101             ActionDescriptor actionDescriptor = (ActionDescriptor) iterator.next();
102
103             if (actionDescriptor.getId() == id) {
104                 return actionDescriptor;
105             }
106         }
107
108         return null;
109     }
110
111     /**
112      * Get a List of initial steps for this workflow
113      * @return A list of {@link ActionDescriptor} objects
114      */

115     public List JavaDoc getInitialActions() {
116         return initialActions;
117     }
118
119     public JoinDescriptor getJoin(int id) {
120         for (Iterator iterator = joins.iterator(); iterator.hasNext();) {
121             JoinDescriptor joinDescriptor = (JoinDescriptor) iterator.next();
122
123             if (joinDescriptor.getId() == id) {
124                 return joinDescriptor;
125             }
126         }
127
128         return null;
129     }
130
131     /**
132      * Get a List of initial steps for this workflow
133      * @return A list of {@link JoinDescriptor} objects
134      */

135     public List JavaDoc getJoins() {
136         return joins;
137     }
138
139     public Map getMetaAttributes() {
140         return metaAttributes;
141     }
142
143     public List JavaDoc getRegisters() {
144         return registers;
145     }
146
147     public SplitDescriptor getSplit(int id) {
148         for (Iterator iterator = splits.iterator(); iterator.hasNext();) {
149             SplitDescriptor splitDescriptor = (SplitDescriptor) iterator.next();
150
151             if (splitDescriptor.getId() == id) {
152                 return splitDescriptor;
153             }
154         }
155
156         return null;
157     }
158
159     /**
160      * Get a List of initial steps for this workflow
161      * @return A list of {@link SplitDescriptor} objects
162      */

163     public List JavaDoc getSplits() {
164         return splits;
165     }
166
167     public StepDescriptor getStep(int id) {
168         for (Iterator iterator = steps.iterator(); iterator.hasNext();) {
169             StepDescriptor step = (StepDescriptor) iterator.next();
170
171             if (step.getId() == id) {
172                 return step;
173             }
174         }
175
176         return null;
177     }
178
179     /**
180      * Get a List of steps in this workflow
181      * @return a List of {@link StepDescriptor} objects
182      */

183     public List JavaDoc getSteps() {
184         return steps;
185     }
186
187     /**
188      * Update a trigger function
189      * @param id The id for the trigger function
190      * @param descriptor The descriptor for the trigger function
191      * @return The old trigger function with the specified ID, if any existed
192      */

193     public FunctionDescriptor setTriggerFunction(int id, FunctionDescriptor descriptor) {
194         return (FunctionDescriptor) timerFunctions.put(new Integer JavaDoc(id), descriptor);
195     }
196
197     public FunctionDescriptor getTriggerFunction(int id) {
198         return (FunctionDescriptor) this.timerFunctions.get(new Integer JavaDoc(id));
199     }
200
201     /**
202      * Get a Map of all trigger functions in this workflow
203      * @return a Map with Integer keys and {@link FunctionDescriptor} values
204      */

205     public Map getTriggerFunctions() {
206         return timerFunctions;
207     }
208
209     /**
210      * Add a common action
211      * @param descriptor The action descriptor to add
212      * @throws IllegalArgumentException if the descriptor's ID already exists in the workflow
213      */

214     public void addCommonAction(ActionDescriptor descriptor) {
215         addAction(commonActions, descriptor);
216         addAction(commonActionsList, descriptor);
217     }
218
219     /**
220      * Add a global action
221      * @param descriptor The action descriptor to add
222      * @throws IllegalArgumentException if the descriptor's ID already exists in the workflow
223      */

224     public void addGlobalAction(ActionDescriptor descriptor) {
225         addAction(globalActions, descriptor);
226     }
227
228     /**
229      * Add an initial action
230      * @param descriptor The action descriptor to add
231      * @throws IllegalArgumentException if the descriptor's ID already exists in the workflow
232      */

233     public void addInitialAction(ActionDescriptor descriptor) {
234         addAction(initialActions, descriptor);
235     }
236
237     /**
238      * Add a join
239      * @param descriptor The join descriptor to add
240      * @throws IllegalArgumentException if the descriptor's ID already exists in the workflow
241      */

242     public void addJoin(JoinDescriptor descriptor) {
243         if (getJoin(descriptor.getId()) != null) {
244             throw new IllegalArgumentException JavaDoc("Join with id " + descriptor.getId() + " already exists");
245         }
246
247         joins.add(descriptor);
248     }
249
250     /**
251      * Add a split
252      * @param descriptor The split descriptor to add
253      * @throws IllegalArgumentException if the descriptor's ID already exists in the workflow
254      */

255     public void addSplit(SplitDescriptor descriptor) {
256         if (getSplit(descriptor.getId()) != null) {
257             throw new IllegalArgumentException JavaDoc("Split with id " + descriptor.getId() + " already exists");
258         }
259
260         splits.add(descriptor);
261     }
262
263     /**
264      * Add a step
265      * @param descriptor The step descriptor to add
266      * @throws IllegalArgumentException if the descriptor's ID already exists in the workflow
267      */

268     public void addStep(StepDescriptor descriptor) {
269         if (getStep(descriptor.getId()) != null) {
270             throw new IllegalArgumentException JavaDoc("Step with id " + descriptor.getId() + " already exists");
271         }
272
273         steps.add(descriptor);
274     }
275
276     /**
277      * Remove an action from this workflow completely.
278      * <p>
279      * This method will check global actions and all steps.
280      *
281      * @return true if the action was successfully removed, false if it was not found
282      */

283     public boolean removeAction(ActionDescriptor actionToRemove) {
284         // global actions
285
for (Iterator iterator = getGlobalActions().iterator();
286                 iterator.hasNext();) {
287             ActionDescriptor actionDescriptor = (ActionDescriptor) iterator.next();
288
289             if (actionDescriptor.getId() == actionToRemove.getId()) {
290                 getGlobalActions().remove(actionDescriptor);
291
292                 return true;
293             }
294         }
295
296         // steps
297
for (Iterator iterator = getSteps().iterator(); iterator.hasNext();) {
298             StepDescriptor stepDescriptor = (StepDescriptor) iterator.next();
299             ActionDescriptor actionDescriptor = stepDescriptor.getAction(actionToRemove.getId());
300
301             if (actionDescriptor != null) {
302                 stepDescriptor.getActions().remove(actionDescriptor);
303
304                 return true;
305             }
306         }
307
308         return false;
309     }
310
311     public void validate() throws InvalidWorkflowDescriptorException {
312         ValidationHelper.validate(this.getRegisters());
313         ValidationHelper.validate(this.getTriggerFunctions().values());
314         ValidationHelper.validate(this.getGlobalActions());
315         ValidationHelper.validate(this.getInitialActions());
316         ValidationHelper.validate(this.getCommonActions().values());
317         ValidationHelper.validate(this.getSteps());
318         ValidationHelper.validate(this.getSplits());
319         ValidationHelper.validate(this.getJoins());
320
321         Set actions = new HashSet();
322         Iterator i = globalActions.iterator();
323
324         while (i.hasNext()) {
325             ActionDescriptor action = (ActionDescriptor) i.next();
326             actions.add(new Integer JavaDoc(action.getId()));
327         }
328
329         i = getSteps().iterator();
330
331         while (i.hasNext()) {
332             StepDescriptor step = (StepDescriptor) i.next();
333             Iterator j = step.getActions().iterator();
334
335             while (j.hasNext()) {
336                 ActionDescriptor action = (ActionDescriptor) j.next();
337
338                 // check to see if it's a common action (dups are ok)
339
if (!this.getCommonActions().containsKey(new Integer JavaDoc(action.getId()))) {
340                     if (!actions.add(new Integer JavaDoc(action.getId()))) {
341                         throw new InvalidWorkflowDescriptorException("Duplicate occurance of action ID " + action.getId() + " found in step " + step.getId());
342                     }
343                 }
344             }
345         }
346
347         validateDTD();
348     }
349
350     public void writeXML(PrintWriter out, int indent) {
351         XMLUtil.printIndent(out, indent++);
352         out.println("<workflow>");
353
354         Iterator iter = metaAttributes.entrySet().iterator();
355
356         while (iter.hasNext()) {
357             Map.Entry entry = (Map.Entry) iter.next();
358             XMLUtil.printIndent(out, indent);
359             out.print("<meta name=\"");
360             out.print(entry.getKey());
361             out.print("\">");
362             out.print(entry.getValue());
363             out.println("</meta>");
364         }
365
366         if (registers.size() > 0) {
367             XMLUtil.printIndent(out, indent++);
368             out.println("<registers>");
369
370             for (int i = 0; i < registers.size(); i++) {
371                 RegisterDescriptor register = (RegisterDescriptor) registers.get(i);
372                 register.writeXML(out, indent);
373             }
374
375             XMLUtil.printIndent(out, --indent);
376             out.println("</registers>");
377         }
378
379         XMLUtil.printIndent(out, indent++);
380         out.println("<initial-actions>");
381
382         for (int i = 0; i < initialActions.size(); i++) {
383             ActionDescriptor action = (ActionDescriptor) initialActions.get(i);
384             action.writeXML(out, indent);
385         }
386
387         XMLUtil.printIndent(out, --indent);
388         out.println("</initial-actions>");
389
390         if (globalActions.size() > 0) {
391             XMLUtil.printIndent(out, indent++);
392             out.println("<global-actions>");
393
394             for (int i = 0; i < globalActions.size(); i++) {
395                 ActionDescriptor action = (ActionDescriptor) globalActions.get(i);
396                 action.writeXML(out, indent);
397             }
398
399             XMLUtil.printIndent(out, --indent);
400             out.println("</global-actions>");
401         }
402
403         if (commonActions.size() > 0) {
404             XMLUtil.printIndent(out, indent++);
405             out.println("<common-actions>");
406
407             Iterator commonActionsItr = getCommonActions().values().iterator();
408
409             while (commonActionsItr.hasNext()) {
410                 ActionDescriptor action = (ActionDescriptor) commonActionsItr.next();
411                 action.writeXML(out, indent);
412             }
413
414             XMLUtil.printIndent(out, --indent);
415             out.println("</common-actions>");
416         }
417
418         XMLUtil.printIndent(out, indent++);
419         out.println("<steps>");
420
421         for (int i = 0; i < steps.size(); i++) {
422             StepDescriptor step = (StepDescriptor) steps.get(i);
423             step.writeXML(out, indent);
424         }
425
426         XMLUtil.printIndent(out, --indent);
427         out.println("</steps>");
428
429         if (splits.size() > 0) {
430             XMLUtil.printIndent(out, indent++);
431             out.println("<splits>");
432
433             for (int i = 0; i < splits.size(); i++) {
434                 SplitDescriptor split = (SplitDescriptor) splits.get(i);
435                 split.writeXML(out, indent);
436             }
437
438             XMLUtil.printIndent(out, --indent);
439             out.println("</splits>");
440         }
441
442         if (joins.size() > 0) {
443             XMLUtil.printIndent(out, indent++);
444             out.println("<joins>");
445
446             for (int i = 0; i < joins.size(); i++) {
447                 JoinDescriptor join = (JoinDescriptor) joins.get(i);
448                 join.writeXML(out, indent);
449             }
450
451             XMLUtil.printIndent(out, --indent);
452             out.println("</joins>");
453         }
454
455         XMLUtil.printIndent(out, --indent);
456         out.println("</workflow>");
457     }
458
459     protected void init(Element JavaDoc root) {
460         NodeList JavaDoc children = root.getChildNodes();
461
462         for (int i = 0; i < children.getLength(); i++) {
463             Node JavaDoc child = (Node JavaDoc) children.item(i);
464
465             if (child.getNodeName().equals("meta")) {
466                 Element JavaDoc meta = (Element JavaDoc) child;
467                 String JavaDoc value = XMLUtil.getText(meta);
468                 this.metaAttributes.put(meta.getAttribute("name"), value);
469             }
470         }
471
472         // handle registers - OPTIONAL
473
Element JavaDoc r = XMLUtil.getChildElement(root, "registers");
474
475         if (r != null) {
476             List JavaDoc registers = XMLUtil.getChildElements(r, "register");
477
478             for (int i = 0; i < registers.size(); i++) {
479                 Element JavaDoc register = (Element JavaDoc) registers.get(i);
480                 RegisterDescriptor registerDescriptor = new RegisterDescriptor(register);
481                 registerDescriptor.setParent(this);
482                 this.registers.add(registerDescriptor);
483             }
484         }
485
486         // handle initial-steps - REQUIRED
487
Element JavaDoc intialActionsElement = XMLUtil.getChildElement(root, "initial-actions");
488         List JavaDoc initialActions = XMLUtil.getChildElements(intialActionsElement, "action");
489
490         for (int i = 0; i < initialActions.size(); i++) {
491             Element JavaDoc initialAction = (Element JavaDoc) initialActions.get(i);
492             ActionDescriptor actionDescriptor = new ActionDescriptor(initialAction);
493             actionDescriptor.setParent(this);
494             this.initialActions.add(actionDescriptor);
495         }
496
497         // handle global-actions - OPTIONAL
498
Element JavaDoc globalActionsElement = XMLUtil.getChildElement(root, "global-actions");
499
500         if (globalActionsElement != null) {
501             List JavaDoc globalActions = XMLUtil.getChildElements(globalActionsElement, "action");
502
503             for (int i = 0; i < globalActions.size(); i++) {
504                 Element JavaDoc globalAction = (Element JavaDoc) globalActions.get(i);
505                 ActionDescriptor actionDescriptor = new ActionDescriptor(globalAction);
506                 actionDescriptor.setParent(this);
507                 this.globalActions.add(actionDescriptor);
508             }
509         }
510
511         // handle common-actions - OPTIONAL
512
// - Store actions in HashMap for now. When parsing Steps, we'll resolve
513
// any common actions into local references.
514
Element JavaDoc commonActionsElement = XMLUtil.getChildElement(root, "common-actions");
515
516         if (commonActionsElement != null) {
517             List JavaDoc commonActions = XMLUtil.getChildElements(commonActionsElement, "action");
518
519             for (int i = 0; i < commonActions.size(); i++) {
520                 Element JavaDoc commonAction = (Element JavaDoc) commonActions.get(i);
521                 ActionDescriptor actionDescriptor = new ActionDescriptor(commonAction);
522                 actionDescriptor.setParent(this);
523                 addCommonAction(actionDescriptor);
524             }
525         }
526
527         // handle timer-functions - OPTIONAL
528
Element JavaDoc timerFunctionsElement = XMLUtil.getChildElement(root, "trigger-functions");
529
530         if (timerFunctionsElement != null) {
531             List JavaDoc timerFunctions = XMLUtil.getChildElements(timerFunctionsElement, "trigger-function");
532
533             for (int i = 0; i < timerFunctions.size(); i++) {
534                 Element JavaDoc timerFunction = (Element JavaDoc) timerFunctions.get(i);
535                 Integer JavaDoc id = new Integer JavaDoc(timerFunction.getAttribute("id"));
536                 FunctionDescriptor function = new FunctionDescriptor(XMLUtil.getChildElement(timerFunction, "function"));
537                 function.setParent(this);
538                 this.timerFunctions.put(id, function);
539             }
540         }
541
542         // handle steps - REQUIRED
543
Element JavaDoc stepsElement = XMLUtil.getChildElement(root, "steps");
544         List JavaDoc steps = XMLUtil.getChildElements(stepsElement, "step");
545
546         for (int i = 0; i < steps.size(); i++) {
547             Element JavaDoc step = (Element JavaDoc) steps.get(i);
548             StepDescriptor stepDescriptor = new StepDescriptor(step, this);
549             this.steps.add(stepDescriptor);
550         }
551
552         // handle splits - OPTIONAL
553
Element JavaDoc splitsElement = XMLUtil.getChildElement(root, "splits");
554
555         if (splitsElement != null) {
556             List JavaDoc split = XMLUtil.getChildElements(splitsElement, "split");
557
558             for (int i = 0; i < split.size(); i++) {
559                 Element JavaDoc s = (Element JavaDoc) split.get(i);
560                 SplitDescriptor splitDescriptor = new SplitDescriptor(s);
561                 splitDescriptor.setParent(this);
562                 this.splits.add(splitDescriptor);
563             }
564         }
565
566         // handle joins - OPTIONAL:
567
Element JavaDoc joinsElement = XMLUtil.getChildElement(root, "joins");
568
569         if (joinsElement != null) {
570             List JavaDoc join = XMLUtil.getChildElements(joinsElement, "join");
571
572             for (int i = 0; i < join.size(); i++) {
573                 Element JavaDoc s = (Element JavaDoc) join.get(i);
574                 JoinDescriptor joinDescriptor = new JoinDescriptor(s);
575                 joinDescriptor.setParent(this);
576                 this.joins.add(joinDescriptor);
577             }
578         }
579     }
580
581     // refactored this out from the three addAction methods above
582
private void addAction(Object JavaDoc actionsCollectionOrMap, ActionDescriptor descriptor) {
583         if (getAction(descriptor.getId()) != null) {
584             throw new IllegalArgumentException JavaDoc("action with id " + descriptor.getId() + " already exists for this step.");
585         }
586
587         if (actionsCollectionOrMap instanceof Map) {
588             ((Map) actionsCollectionOrMap).put(new Integer JavaDoc(descriptor.getId()), descriptor);
589         } else {
590             ((Collection) actionsCollectionOrMap).add(descriptor);
591         }
592     }
593
594     private void validateDTD() throws InvalidWorkflowDescriptorException {
595         DocumentBuilderFactory JavaDoc dbf = DocumentBuilderFactory.newInstance();
596         dbf.setNamespaceAware(true);
597         dbf.setValidating(true);
598
599         StringWriter sw = new StringWriter();
600         PrintWriter writer = new PrintWriter(sw);
601         writer.println(XML_HEADER);
602         writer.println(DOCTYPE_DECL);
603         writeXML(writer, 0);
604
605         try {
606             DocumentBuilder JavaDoc db = dbf.newDocumentBuilder();
607             db.setEntityResolver(new DTDEntityResolver());
608
609             WorkflowLoader.AllExceptionsErrorHandler errorHandler = new WorkflowLoader.AllExceptionsErrorHandler();
610             db.setErrorHandler(errorHandler);
611             db.parse(new InputSource(new StringReader(sw.toString())));
612
613             if (errorHandler.getExceptions().size() > 0) {
614                 throw new InvalidWorkflowDescriptorException(errorHandler.getExceptions().toString());
615             }
616         } catch (InvalidWorkflowDescriptorException e) {
617             throw e;
618         } catch (Exception JavaDoc e) {
619             throw new InvalidWorkflowDescriptorException(e.toString());
620         }
621     }
622 }
623
Popular Tags