001: /*
002: * Copyright (c) 2002-2003 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.workflow.loader;
006:
007: import com.opensymphony.workflow.InvalidWorkflowDescriptorException;
008: import com.opensymphony.workflow.util.Validatable;
009:
010: import org.w3c.dom.*;
011:
012: import org.xml.sax.*;
013:
014: import java.io.*;
015:
016: import java.util.*;
017:
018: import javax.xml.parsers.DocumentBuilder;
019: import javax.xml.parsers.DocumentBuilderFactory;
020:
021: /**
022: * Describes a single workflow
023: *
024: * @author <a href="mailto:plightbo@hotmail.com">Pat Lightbody</a>
025: */
026: public class WorkflowDescriptor extends AbstractDescriptor implements
027: Validatable {
028: //~ Static fields/initializers /////////////////////////////////////////////
029:
030: public static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
031: public static final String DOCTYPE_DECL = "<!DOCTYPE workflow PUBLIC \"-//OpenSymphony Group//DTD OSWorkflow 2.8//EN\" \"http://www.opensymphony.com/osworkflow/workflow_2_8.dtd\">";
032:
033: //~ Instance fields ////////////////////////////////////////////////////////
034:
035: protected ConditionsDescriptor globalConditions = null;
036: protected List commonActionsList = new ArrayList(); // for preserving order
037: protected List globalActions = new ArrayList();
038: protected List initialActions = new ArrayList();
039: protected List joins = new ArrayList();
040: protected List registers = new ArrayList();
041: protected List splits = new ArrayList();
042: protected List steps = new ArrayList();
043: protected Map commonActions = new HashMap();
044: protected Map metaAttributes = new HashMap();
045: protected Map timerFunctions = new HashMap();
046: protected String workflowName = null;
047:
048: //~ Constructors ///////////////////////////////////////////////////////////
049:
050: /**
051: * @deprecated use {@link DescriptorFactory} instead
052: */
053: public WorkflowDescriptor() {
054: }
055:
056: /**
057: * @deprecated use {@link DescriptorFactory} instead
058: */
059: public WorkflowDescriptor(Element root) {
060: init(root);
061: }
062:
063: //~ Methods ////////////////////////////////////////////////////////////////
064:
065: public ActionDescriptor getAction(int id) {
066: // check global actions
067: for (Iterator iterator = globalActions.iterator(); iterator
068: .hasNext();) {
069: ActionDescriptor actionDescriptor = (ActionDescriptor) iterator
070: .next();
071:
072: if (actionDescriptor.getId() == id) {
073: return actionDescriptor;
074: }
075: }
076:
077: // check steps
078: for (Iterator iterator = steps.iterator(); iterator.hasNext();) {
079: StepDescriptor stepDescriptor = (StepDescriptor) iterator
080: .next();
081: ActionDescriptor actionDescriptor = stepDescriptor
082: .getAction(id);
083:
084: if (actionDescriptor != null) {
085: return actionDescriptor;
086: }
087: }
088:
089: //check initial actions, which we now must have unique id's
090: for (Iterator iterator = initialActions.iterator(); iterator
091: .hasNext();) {
092: ActionDescriptor actionDescriptor = (ActionDescriptor) iterator
093: .next();
094:
095: if (actionDescriptor.getId() == id) {
096: return actionDescriptor;
097: }
098: }
099:
100: return null;
101: }
102:
103: /**
104: * Get a Map of the common actions specified, keyed on actionId (an Integer)
105: * @return A list of {@link ActionDescriptor} objects
106: */
107: public Map getCommonActions() {
108: return commonActions;
109: }
110:
111: /**
112: * Get a List of the global actions specified
113: * @return A list of {@link ActionDescriptor} objects
114: */
115: public List getGlobalActions() {
116: return globalActions;
117: }
118:
119: public ConditionsDescriptor getGlobalConditions() {
120: return globalConditions;
121: }
122:
123: public ActionDescriptor getInitialAction(int id) {
124: for (Iterator iterator = initialActions.iterator(); iterator
125: .hasNext();) {
126: ActionDescriptor actionDescriptor = (ActionDescriptor) iterator
127: .next();
128:
129: if (actionDescriptor.getId() == id) {
130: return actionDescriptor;
131: }
132: }
133:
134: return null;
135: }
136:
137: /**
138: * Get a List of initial steps for this workflow
139: * @return A list of {@link ActionDescriptor} objects
140: */
141: public List getInitialActions() {
142: return initialActions;
143: }
144:
145: public JoinDescriptor getJoin(int id) {
146: for (Iterator iterator = joins.iterator(); iterator.hasNext();) {
147: JoinDescriptor joinDescriptor = (JoinDescriptor) iterator
148: .next();
149:
150: if (joinDescriptor.getId() == id) {
151: return joinDescriptor;
152: }
153: }
154:
155: return null;
156: }
157:
158: /**
159: * Get a List of initial steps for this workflow
160: * @return A list of {@link JoinDescriptor} objects
161: */
162: public List getJoins() {
163: return joins;
164: }
165:
166: public Map getMetaAttributes() {
167: return metaAttributes;
168: }
169:
170: public void setName(String name) {
171: workflowName = name;
172: }
173:
174: public String getName() {
175: return workflowName;
176: }
177:
178: public List getRegisters() {
179: return registers;
180: }
181:
182: public SplitDescriptor getSplit(int id) {
183: for (Iterator iterator = splits.iterator(); iterator.hasNext();) {
184: SplitDescriptor splitDescriptor = (SplitDescriptor) iterator
185: .next();
186:
187: if (splitDescriptor.getId() == id) {
188: return splitDescriptor;
189: }
190: }
191:
192: return null;
193: }
194:
195: /**
196: * Get a List of initial steps for this workflow
197: * @return A list of {@link SplitDescriptor} objects
198: */
199: public List getSplits() {
200: return splits;
201: }
202:
203: public StepDescriptor getStep(int id) {
204: for (Iterator iterator = steps.iterator(); iterator.hasNext();) {
205: StepDescriptor step = (StepDescriptor) iterator.next();
206:
207: if (step.getId() == id) {
208: return step;
209: }
210: }
211:
212: return null;
213: }
214:
215: /**
216: * Get a List of steps in this workflow
217: * @return a List of {@link StepDescriptor} objects
218: */
219: public List getSteps() {
220: return steps;
221: }
222:
223: /**
224: * Update a trigger function
225: * @param id The id for the trigger function
226: * @param descriptor The descriptor for the trigger function
227: * @return The old trigger function with the specified ID, if any existed
228: */
229: public FunctionDescriptor setTriggerFunction(int id,
230: FunctionDescriptor descriptor) {
231: return (FunctionDescriptor) timerFunctions.put(new Integer(id),
232: descriptor);
233: }
234:
235: public FunctionDescriptor getTriggerFunction(int id) {
236: return (FunctionDescriptor) this .timerFunctions
237: .get(new Integer(id));
238: }
239:
240: /**
241: * Get a Map of all trigger functions in this workflow
242: * @return a Map with Integer keys and {@link FunctionDescriptor} values
243: */
244: public Map getTriggerFunctions() {
245: return timerFunctions;
246: }
247:
248: /**
249: * Add a common action
250: * @param descriptor The action descriptor to add
251: * @throws IllegalArgumentException if the descriptor's ID already exists in the workflow
252: */
253: public void addCommonAction(ActionDescriptor descriptor) {
254: descriptor.setCommon(true);
255: addAction(commonActions, descriptor);
256: addAction(commonActionsList, descriptor);
257: }
258:
259: /**
260: * Add a global action
261: * @param descriptor The action descriptor to add
262: * @throws IllegalArgumentException if the descriptor's ID already exists in the workflow
263: */
264: public void addGlobalAction(ActionDescriptor descriptor) {
265: addAction(globalActions, descriptor);
266: }
267:
268: /**
269: * Add an initial action
270: * @param descriptor The action descriptor to add
271: * @throws IllegalArgumentException if the descriptor's ID already exists in the workflow
272: */
273: public void addInitialAction(ActionDescriptor descriptor) {
274: addAction(initialActions, descriptor);
275: }
276:
277: /**
278: * Add a join
279: * @param descriptor The join descriptor to add
280: * @throws IllegalArgumentException if the descriptor's ID already exists in the workflow
281: */
282: public void addJoin(JoinDescriptor descriptor) {
283: if (getJoin(descriptor.getId()) != null) {
284: throw new IllegalArgumentException("Join with id "
285: + descriptor.getId() + " already exists");
286: }
287:
288: joins.add(descriptor);
289: }
290:
291: /**
292: * Add a split
293: * @param descriptor The split descriptor to add
294: * @throws IllegalArgumentException if the descriptor's ID already exists in the workflow
295: */
296: public void addSplit(SplitDescriptor descriptor) {
297: if (getSplit(descriptor.getId()) != null) {
298: throw new IllegalArgumentException("Split with id "
299: + descriptor.getId() + " already exists");
300: }
301:
302: splits.add(descriptor);
303: }
304:
305: /**
306: * Add a step
307: * @param descriptor The step descriptor to add
308: * @throws IllegalArgumentException if the descriptor's ID already exists in the workflow
309: */
310: public void addStep(StepDescriptor descriptor) {
311: if (getStep(descriptor.getId()) != null) {
312: throw new IllegalArgumentException("Step with id "
313: + descriptor.getId() + " already exists");
314: }
315:
316: steps.add(descriptor);
317: }
318:
319: /**
320: * Remove an action from this workflow completely.
321: * <p>
322: * This method will check global actions and all steps.
323: *
324: * @return true if the action was successfully removed, false if it was not found
325: */
326: public boolean removeAction(ActionDescriptor actionToRemove) {
327: // global actions
328: for (Iterator iterator = getGlobalActions().iterator(); iterator
329: .hasNext();) {
330: ActionDescriptor actionDescriptor = (ActionDescriptor) iterator
331: .next();
332:
333: if (actionDescriptor.getId() == actionToRemove.getId()) {
334: getGlobalActions().remove(actionDescriptor);
335:
336: return true;
337: }
338: }
339:
340: // steps
341: for (Iterator iterator = getSteps().iterator(); iterator
342: .hasNext();) {
343: StepDescriptor stepDescriptor = (StepDescriptor) iterator
344: .next();
345: ActionDescriptor actionDescriptor = stepDescriptor
346: .getAction(actionToRemove.getId());
347:
348: if (actionDescriptor != null) {
349: stepDescriptor.getActions().remove(actionDescriptor);
350:
351: return true;
352: }
353: }
354:
355: return false;
356: }
357:
358: public void validate() throws InvalidWorkflowDescriptorException {
359: ValidationHelper.validate(this .getRegisters());
360: ValidationHelper.validate(this .getTriggerFunctions().values());
361: ValidationHelper.validate(this .getGlobalActions());
362: ValidationHelper.validate(this .getInitialActions());
363: ValidationHelper.validate(this .getCommonActions().values());
364: ValidationHelper.validate(this .getSteps());
365: ValidationHelper.validate(this .getSplits());
366: ValidationHelper.validate(this .getJoins());
367:
368: Set actions = new HashSet();
369: Iterator i = globalActions.iterator();
370:
371: while (i.hasNext()) {
372: ActionDescriptor action = (ActionDescriptor) i.next();
373: actions.add(new Integer(action.getId()));
374: }
375:
376: i = getSteps().iterator();
377:
378: while (i.hasNext()) {
379: StepDescriptor step = (StepDescriptor) i.next();
380: Iterator j = step.getActions().iterator();
381:
382: while (j.hasNext()) {
383: ActionDescriptor action = (ActionDescriptor) j.next();
384:
385: // check to see if it's a common action (dups are ok, since that's the point of common actions!)
386: if (!action.isCommon()) {
387: if (!actions.add(new Integer(action.getId()))) {
388: throw new InvalidWorkflowDescriptorException(
389: "Duplicate occurance of action ID "
390: + action.getId()
391: + " found in step "
392: + step.getId());
393: }
394: }
395: }
396: }
397:
398: //now we have all our unique actions, let's check that no common action id's exist in them
399: i = commonActions.keySet().iterator();
400:
401: while (i.hasNext()) {
402: Integer action = (Integer) i.next();
403:
404: if (actions.contains(action)) {
405: throw new InvalidWorkflowDescriptorException(
406: "common-action ID " + action
407: + " is duplicated in a step action");
408: }
409: }
410:
411: i = initialActions.iterator();
412:
413: while (i.hasNext()) {
414: ActionDescriptor action = (ActionDescriptor) i.next();
415:
416: if (actions.contains(new Integer(action.getId()))) {
417: throw new InvalidWorkflowDescriptorException(
418: "initial-action ID " + action
419: + " is duplicated in a step action");
420: }
421: }
422:
423: validateDTD();
424: }
425:
426: public void writeXML(PrintWriter out, int indent) {
427: XMLUtil.printIndent(out, indent++);
428: out.println("<workflow>");
429:
430: Iterator iter = metaAttributes.entrySet().iterator();
431:
432: while (iter.hasNext()) {
433: Map.Entry entry = (Map.Entry) iter.next();
434: XMLUtil.printIndent(out, indent);
435: out.print("<meta name=\"");
436: out.print(XMLUtil.encode(entry.getKey()));
437: out.print("\">");
438: out.print(XMLUtil.encode(entry.getValue()));
439: out.println("</meta>");
440: }
441:
442: if (registers.size() > 0) {
443: XMLUtil.printIndent(out, indent++);
444: out.println("<registers>");
445:
446: for (int i = 0; i < registers.size(); i++) {
447: RegisterDescriptor register = (RegisterDescriptor) registers
448: .get(i);
449: register.writeXML(out, indent);
450: }
451:
452: XMLUtil.printIndent(out, --indent);
453: out.println("</registers>");
454: }
455:
456: if (timerFunctions.size() > 0) {
457: XMLUtil.printIndent(out, indent++);
458: out.println("<trigger-functions>");
459:
460: Iterator iterator = timerFunctions.entrySet().iterator();
461:
462: while (iterator.hasNext()) {
463: Map.Entry entry = (Map.Entry) iterator.next();
464: XMLUtil.printIndent(out, indent++);
465: out.println("<trigger-function id=\"" + entry.getKey()
466: + "\">");
467:
468: FunctionDescriptor trigger = (FunctionDescriptor) entry
469: .getValue();
470: trigger.writeXML(out, indent);
471: XMLUtil.printIndent(out, --indent);
472: out.println("</trigger-function>");
473: }
474:
475: while (iterator.hasNext()) {
476: }
477:
478: XMLUtil.printIndent(out, --indent);
479: out.println("</trigger-functions>");
480: }
481:
482: if (getGlobalConditions() != null) {
483: XMLUtil.printIndent(out, indent++);
484: out.println("<global-conditions>");
485:
486: getGlobalConditions().writeXML(out, indent);
487:
488: out.println("</global-conditions>");
489: }
490:
491: XMLUtil.printIndent(out, indent++);
492: out.println("<initial-actions>");
493:
494: for (int i = 0; i < initialActions.size(); i++) {
495: ActionDescriptor action = (ActionDescriptor) initialActions
496: .get(i);
497: action.writeXML(out, indent);
498: }
499:
500: XMLUtil.printIndent(out, --indent);
501: out.println("</initial-actions>");
502:
503: if (globalActions.size() > 0) {
504: XMLUtil.printIndent(out, indent++);
505: out.println("<global-actions>");
506:
507: for (int i = 0; i < globalActions.size(); i++) {
508: ActionDescriptor action = (ActionDescriptor) globalActions
509: .get(i);
510: action.writeXML(out, indent);
511: }
512:
513: XMLUtil.printIndent(out, --indent);
514: out.println("</global-actions>");
515: }
516:
517: if (commonActions.size() > 0) {
518: XMLUtil.printIndent(out, indent++);
519: out.println("<common-actions>");
520:
521: Iterator iterator = getCommonActions().values().iterator();
522:
523: while (iterator.hasNext()) {
524: ActionDescriptor action = (ActionDescriptor) iterator
525: .next();
526: action.writeXML(out, indent);
527: }
528:
529: XMLUtil.printIndent(out, --indent);
530: out.println("</common-actions>");
531: }
532:
533: XMLUtil.printIndent(out, indent++);
534: out.println("<steps>");
535:
536: for (int i = 0; i < steps.size(); i++) {
537: StepDescriptor step = (StepDescriptor) steps.get(i);
538: step.writeXML(out, indent);
539: }
540:
541: XMLUtil.printIndent(out, --indent);
542: out.println("</steps>");
543:
544: if (splits.size() > 0) {
545: XMLUtil.printIndent(out, indent++);
546: out.println("<splits>");
547:
548: for (int i = 0; i < splits.size(); i++) {
549: SplitDescriptor split = (SplitDescriptor) splits.get(i);
550: split.writeXML(out, indent);
551: }
552:
553: XMLUtil.printIndent(out, --indent);
554: out.println("</splits>");
555: }
556:
557: if (joins.size() > 0) {
558: XMLUtil.printIndent(out, indent++);
559: out.println("<joins>");
560:
561: for (int i = 0; i < joins.size(); i++) {
562: JoinDescriptor join = (JoinDescriptor) joins.get(i);
563: join.writeXML(out, indent);
564: }
565:
566: XMLUtil.printIndent(out, --indent);
567: out.println("</joins>");
568: }
569:
570: XMLUtil.printIndent(out, --indent);
571: out.println("</workflow>");
572: }
573:
574: protected void init(Element root) {
575: NodeList children = root.getChildNodes();
576:
577: for (int i = 0; i < children.getLength(); i++) {
578: Node child = children.item(i);
579:
580: if (child.getNodeName().equals("meta")) {
581: Element meta = (Element) child;
582: String value = XMLUtil.getText(meta);
583: this .metaAttributes.put(meta.getAttribute("name"),
584: value);
585: }
586: }
587:
588: // handle registers - OPTIONAL
589: Element r = XMLUtil.getChildElement(root, "registers");
590:
591: if (r != null) {
592: List registers = XMLUtil.getChildElements(r, "register");
593:
594: for (int i = 0; i < registers.size(); i++) {
595: Element register = (Element) registers.get(i);
596: RegisterDescriptor registerDescriptor = DescriptorFactory
597: .getFactory()
598: .createRegisterDescriptor(register);
599: registerDescriptor.setParent(this );
600: this .registers.add(registerDescriptor);
601: }
602: }
603:
604: // handle global-conditions - OPTIONAL
605: Element globalConditionsElement = XMLUtil.getChildElement(root,
606: "global-conditions");
607:
608: if (globalConditionsElement != null) {
609: Element globalConditions = XMLUtil.getChildElement(
610: globalConditionsElement, "conditions");
611:
612: ConditionsDescriptor conditionsDescriptor = DescriptorFactory
613: .getFactory().createConditionsDescriptor(
614: globalConditions);
615: conditionsDescriptor.setParent(this );
616: this .globalConditions = conditionsDescriptor;
617: }
618:
619: // handle initial-steps - REQUIRED
620: Element intialActionsElement = XMLUtil.getChildElement(root,
621: "initial-actions");
622: List initialActions = XMLUtil.getChildElements(
623: intialActionsElement, "action");
624:
625: for (int i = 0; i < initialActions.size(); i++) {
626: Element initialAction = (Element) initialActions.get(i);
627: ActionDescriptor actionDescriptor = DescriptorFactory
628: .getFactory().createActionDescriptor(initialAction);
629: actionDescriptor.setParent(this );
630: this .initialActions.add(actionDescriptor);
631: }
632:
633: // handle global-actions - OPTIONAL
634: Element globalActionsElement = XMLUtil.getChildElement(root,
635: "global-actions");
636:
637: if (globalActionsElement != null) {
638: List globalActions = XMLUtil.getChildElements(
639: globalActionsElement, "action");
640:
641: for (int i = 0; i < globalActions.size(); i++) {
642: Element globalAction = (Element) globalActions.get(i);
643: ActionDescriptor actionDescriptor = DescriptorFactory
644: .getFactory().createActionDescriptor(
645: globalAction);
646: actionDescriptor.setParent(this );
647: this .globalActions.add(actionDescriptor);
648: }
649: }
650:
651: // handle common-actions - OPTIONAL
652: // - Store actions in HashMap for now. When parsing Steps, we'll resolve
653: // any common actions into local references.
654: Element commonActionsElement = XMLUtil.getChildElement(root,
655: "common-actions");
656:
657: if (commonActionsElement != null) {
658: List commonActions = XMLUtil.getChildElements(
659: commonActionsElement, "action");
660:
661: for (int i = 0; i < commonActions.size(); i++) {
662: Element commonAction = (Element) commonActions.get(i);
663: ActionDescriptor actionDescriptor = DescriptorFactory
664: .getFactory().createActionDescriptor(
665: commonAction);
666: actionDescriptor.setParent(this );
667: addCommonAction(actionDescriptor);
668: }
669: }
670:
671: // handle timer-functions - OPTIONAL
672: Element timerFunctionsElement = XMLUtil.getChildElement(root,
673: "trigger-functions");
674:
675: if (timerFunctionsElement != null) {
676: List timerFunctions = XMLUtil.getChildElements(
677: timerFunctionsElement, "trigger-function");
678:
679: for (int i = 0; i < timerFunctions.size(); i++) {
680: Element timerFunction = (Element) timerFunctions.get(i);
681: Integer id = new Integer(timerFunction
682: .getAttribute("id"));
683: FunctionDescriptor function = DescriptorFactory
684: .getFactory().createFunctionDescriptor(
685: XMLUtil.getChildElement(timerFunction,
686: "function"));
687: function.setParent(this );
688: this .timerFunctions.put(id, function);
689: }
690: }
691:
692: // handle steps - REQUIRED
693: Element stepsElement = XMLUtil.getChildElement(root, "steps");
694: List steps = XMLUtil.getChildElements(stepsElement, "step");
695:
696: for (int i = 0; i < steps.size(); i++) {
697: Element step = (Element) steps.get(i);
698: StepDescriptor stepDescriptor = DescriptorFactory
699: .getFactory().createStepDescriptor(step, this );
700: this .steps.add(stepDescriptor);
701: }
702:
703: // handle splits - OPTIONAL
704: Element splitsElement = XMLUtil.getChildElement(root, "splits");
705:
706: if (splitsElement != null) {
707: List split = XMLUtil.getChildElements(splitsElement,
708: "split");
709:
710: for (int i = 0; i < split.size(); i++) {
711: Element s = (Element) split.get(i);
712: SplitDescriptor splitDescriptor = DescriptorFactory
713: .getFactory().createSplitDescriptor(s);
714: splitDescriptor.setParent(this );
715: this .splits.add(splitDescriptor);
716: }
717: }
718:
719: // handle joins - OPTIONAL:
720: Element joinsElement = XMLUtil.getChildElement(root, "joins");
721:
722: if (joinsElement != null) {
723: List join = XMLUtil.getChildElements(joinsElement, "join");
724:
725: for (int i = 0; i < join.size(); i++) {
726: Element s = (Element) join.get(i);
727: JoinDescriptor joinDescriptor = DescriptorFactory
728: .getFactory().createJoinDescriptor(s);
729: joinDescriptor.setParent(this );
730: this .joins.add(joinDescriptor);
731: }
732: }
733: }
734:
735: // refactored this out from the three addAction methods above
736: private void addAction(Object actionsCollectionOrMap,
737: ActionDescriptor descriptor) {
738: if (getAction(descriptor.getId()) != null) {
739: throw new IllegalArgumentException("action with id "
740: + descriptor.getId()
741: + " already exists for this step.");
742: }
743:
744: if (actionsCollectionOrMap instanceof Map) {
745: ((Map) actionsCollectionOrMap).put(new Integer(descriptor
746: .getId()), descriptor);
747: } else {
748: ((Collection) actionsCollectionOrMap).add(descriptor);
749: }
750: }
751:
752: private void validateDTD()
753: throws InvalidWorkflowDescriptorException {
754: DocumentBuilderFactory dbf = DocumentBuilderFactory
755: .newInstance();
756: dbf.setNamespaceAware(true);
757: dbf.setValidating(true);
758:
759: StringWriter sw = new StringWriter();
760: PrintWriter writer = new PrintWriter(sw);
761: writer.println(XML_HEADER);
762: writer.println(DOCTYPE_DECL);
763: writeXML(writer, 0);
764:
765: WorkflowLoader.AllExceptionsErrorHandler errorHandler = new WorkflowLoader.AllExceptionsErrorHandler();
766:
767: try {
768: DocumentBuilder db = dbf.newDocumentBuilder();
769: db.setEntityResolver(new DTDEntityResolver());
770:
771: db.setErrorHandler(errorHandler);
772: db.parse(new InputSource(new StringReader(sw.toString())));
773:
774: if (errorHandler.getExceptions().size() > 0) {
775: throw new InvalidWorkflowDescriptorException(
776: errorHandler.getExceptions().toString());
777: }
778: } catch (InvalidWorkflowDescriptorException e) {
779: throw e;
780: } catch (Exception e) {
781: throw new InvalidWorkflowDescriptorException(e.toString());
782: }
783: }
784: }
|