KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > webflow > engine > builder > xml > XmlFlowBuilder


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.springframework.webflow.engine.builder.xml;
17
18 import java.io.IOException JavaDoc;
19 import java.util.Arrays JavaDoc;
20 import java.util.Collections JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.LinkedList JavaDoc;
23 import java.util.List JavaDoc;
24
25 import javax.xml.parsers.ParserConfigurationException JavaDoc;
26
27 import org.springframework.beans.factory.BeanFactory;
28 import org.springframework.binding.convert.ConversionExecutor;
29 import org.springframework.binding.convert.ConversionService;
30 import org.springframework.binding.expression.Expression;
31 import org.springframework.binding.expression.ExpressionParser;
32 import org.springframework.binding.expression.SettableExpression;
33 import org.springframework.binding.expression.support.CollectionAddingExpression;
34 import org.springframework.binding.mapping.AttributeMapper;
35 import org.springframework.binding.mapping.DefaultAttributeMapper;
36 import org.springframework.binding.mapping.Mapping;
37 import org.springframework.binding.mapping.RequiredMapping;
38 import org.springframework.binding.method.MethodSignature;
39 import org.springframework.binding.method.Parameter;
40 import org.springframework.binding.method.Parameters;
41 import org.springframework.core.io.Resource;
42 import org.springframework.util.Assert;
43 import org.springframework.util.StringUtils;
44 import org.springframework.util.xml.DomUtils;
45 import org.springframework.webflow.action.ActionResultExposer;
46 import org.springframework.webflow.action.EvaluateAction;
47 import org.springframework.webflow.action.SetAction;
48 import org.springframework.webflow.core.collection.AttributeMap;
49 import org.springframework.webflow.core.collection.LocalAttributeMap;
50 import org.springframework.webflow.core.collection.MutableAttributeMap;
51 import org.springframework.webflow.engine.AnnotatedAction;
52 import org.springframework.webflow.engine.Flow;
53 import org.springframework.webflow.engine.FlowAttributeMapper;
54 import org.springframework.webflow.engine.FlowExecutionExceptionHandler;
55 import org.springframework.webflow.engine.FlowVariable;
56 import org.springframework.webflow.engine.TargetStateResolver;
57 import org.springframework.webflow.engine.Transition;
58 import org.springframework.webflow.engine.TransitionCriteria;
59 import org.springframework.webflow.engine.ViewSelector;
60 import org.springframework.webflow.engine.builder.BaseFlowBuilder;
61 import org.springframework.webflow.engine.builder.FlowArtifactFactory;
62 import org.springframework.webflow.engine.builder.FlowBuilderException;
63 import org.springframework.webflow.engine.builder.FlowServiceLocator;
64 import org.springframework.webflow.engine.support.AttributeExpression;
65 import org.springframework.webflow.engine.support.BeanFactoryFlowVariable;
66 import org.springframework.webflow.engine.support.BooleanExpressionTransitionCriteria;
67 import org.springframework.webflow.engine.support.SimpleFlowVariable;
68 import org.springframework.webflow.engine.support.TransitionCriteriaChain;
69 import org.springframework.webflow.engine.support.TransitionExecutingStateExceptionHandler;
70 import org.springframework.webflow.execution.Action;
71 import org.springframework.webflow.execution.ScopeType;
72 import org.springframework.webflow.util.ResourceHolder;
73 import org.w3c.dom.Document JavaDoc;
74 import org.w3c.dom.Element JavaDoc;
75 import org.w3c.dom.Node JavaDoc;
76 import org.w3c.dom.NodeList JavaDoc;
77 import org.xml.sax.SAXException JavaDoc;
78
79 /**
80  * Flow builder that builds flows as defined in an XML document. The XML document
81  * should adhere to the following format:
82  *
83  * <pre>
84  * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
85  * &lt;flow xmlns=&quot;http://www.springframework.org/schema/webflow&quot;
86  * xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
87  * xsi:schemaLocation=&quot;http://www.springframework.org/schema/webflow
88  * http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd&quot;&gt;
89  *
90  * &lt;!-- Define your states here --&gt;
91  *
92  * &lt;/flow&gt;
93  * </pre>
94  *
95  * <p>
96  * Consult the <a
97  * HREF="http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">webflow
98  * XML schema</a> for more information on the XML-based flow definition format.
99  * <p>
100  * This builder will setup a flow-local bean factory for the flow being
101  * constructed. That flow-local bean factory will be populated with XML bean
102  * definitions contained in files referenced using the "import" element. The
103  * flow-local bean factory will use the bean factory defing this flow builder as
104  * a parent. As such, the flow can access artifacts in either its flow-local
105  * bean factory or in the parent bean factory hierarchy, e.g. the bean factory
106  * of the dispatcher.
107  *
108  * @author Erwin Vervaet
109  * @author Keith Donald
110  */

111 public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
112
113     // recognized XML elements and attributes
114

115     private static final String JavaDoc ID_ATTRIBUTE = "id";
116
117     private static final String JavaDoc IDREF_ATTRIBUTE = "idref";
118
119     private static final String JavaDoc BEAN_ATTRIBUTE = "bean";
120
121     private static final String JavaDoc FLOW_ELEMENT = "flow";
122
123     private static final String JavaDoc START_STATE_ELEMENT = "start-state";
124
125     private static final String JavaDoc ACTION_STATE_ELEMENT = "action-state";
126
127     private static final String JavaDoc ACTION_ELEMENT = "action";
128
129     private static final String JavaDoc NAME_ATTRIBUTE = "name";
130
131     private static final String JavaDoc METHOD_ATTRIBUTE = "method";
132
133     private static final String JavaDoc BEAN_ACTION_ELEMENT = "bean-action";
134
135     private static final String JavaDoc METHOD_ARGUMENTS_ELEMENT = "method-arguments";
136
137     private static final String JavaDoc ARGUMENT_ELEMENT = "argument";
138
139     private static final String JavaDoc EXPRESSION_ATTRIBUTE = "expression";
140
141     private static final String JavaDoc PARAMETER_TYPE_ATTRIBUTE = "parameter-type";
142
143     private static final String JavaDoc METHOD_RESULT_ELEMENT = "method-result";
144
145     private static final String JavaDoc EVALUATE_ACTION_ELEMENT = "evaluate-action";
146
147     private static final String JavaDoc SET_ELEMENT = "set";
148
149     private static final String JavaDoc ATTRIBUTE_ATTRIBUTE = "attribute";
150
151     private static final String JavaDoc EVALUATION_RESULT_ELEMENT = "evaluation-result";
152
153     private static final String JavaDoc DEFAULT_VALUE = "default";
154
155     private static final String JavaDoc VIEW_STATE_ELEMENT = "view-state";
156
157     private static final String JavaDoc VIEW_ATTRIBUTE = "view";
158
159     private static final String JavaDoc DECISION_STATE_ELEMENT = "decision-state";
160
161     private static final String JavaDoc IF_ELEMENT = "if";
162
163     private static final String JavaDoc TEST_ATTRIBUTE = "test";
164
165     private static final String JavaDoc THEN_ATTRIBUTE = "then";
166
167     private static final String JavaDoc ELSE_ATTRIBUTE = "else";
168
169     private static final String JavaDoc SUBFLOW_STATE_ELEMENT = "subflow-state";
170
171     private static final String JavaDoc FLOW_ATTRIBUTE = "flow";
172
173     private static final String JavaDoc ATTRIBUTE_MAPPER_ELEMENT = "attribute-mapper";
174
175     private static final String JavaDoc OUTPUT_MAPPER_ELEMENT = "output-mapper";
176
177     private static final String JavaDoc OUTPUT_ATTRIBUTE_ELEMENT = "output-attribute";
178
179     private static final String JavaDoc INPUT_MAPPER_ELEMENT = "input-mapper";
180
181     private static final String JavaDoc INPUT_ATTRIBUTE_ELEMENT = "input-attribute";
182
183     private static final String JavaDoc MAPPING_ELEMENT = "mapping";
184
185     private static final String JavaDoc SOURCE_ATTRIBUTE = "source";
186
187     private static final String JavaDoc TARGET_ATTRIBUTE = "target";
188
189     private static final String JavaDoc FROM_ATTRIBUTE = "from";
190
191     private static final String JavaDoc TO_ATTRIBUTE = "to";
192
193     private static final String JavaDoc REQUIRED_ATTRIBUTE = "required";
194
195     private static final String JavaDoc TARGET_COLLECTION_ATTRIBUTE = "target-collection";
196
197     private static final String JavaDoc END_STATE_ELEMENT = "end-state";
198
199     private static final String JavaDoc TRANSITION_ELEMENT = "transition";
200
201     private static final String JavaDoc GLOBAL_TRANSITIONS_ELEMENT = "global-transitions";
202
203     private static final String JavaDoc ON_ATTRIBUTE = "on";
204
205     private static final String JavaDoc ON_EXCEPTION_ATTRIBUTE = "on-exception";
206
207     private static final String JavaDoc ATTRIBUTE_ELEMENT = "attribute";
208
209     private static final String JavaDoc TYPE_ATTRIBUTE = "type";
210
211     private static final String JavaDoc VALUE_ELEMENT = "value";
212
213     private static final String JavaDoc VALUE_ATTRIBUTE = "value";
214
215     private static final String JavaDoc VAR_ELEMENT = "var";
216
217     private static final String JavaDoc SCOPE_ATTRIBUTE = "scope";
218
219     private static final String JavaDoc CLASS_ATTRIBUTE = "class";
220
221     private static final String JavaDoc START_ACTIONS_ELEMENT = "start-actions";
222
223     private static final String JavaDoc END_ACTIONS_ELEMENT = "end-actions";
224
225     private static final String JavaDoc ENTRY_ACTIONS_ELEMENT = "entry-actions";
226
227     private static final String JavaDoc RENDER_ACTIONS_ELEMENT = "render-actions";
228
229     private static final String JavaDoc EXIT_ACTIONS_ELEMENT = "exit-actions";
230
231     private static final String JavaDoc EXCEPTION_HANDLER_ELEMENT = "exception-handler";
232
233     private static final String JavaDoc INLINE_FLOW_ELEMENT = "inline-flow";
234
235     private static final String JavaDoc IMPORT_ELEMENT = "import";
236
237     private static final String JavaDoc RESOURCE_ATTRIBUTE = "resource";
238
239     /**
240      * The resource from which the document element being parsed was read. Used
241      * as a location for relative resource lookup.
242      */

243     protected Resource location;
244
245     /**
246      * A flow service locator local to this builder that first looks in a
247      * locally-managed Spring application context for services before searching
248      * the externally managed {@link #getFlowServiceLocator()}.
249      */

250     private LocalFlowServiceLocator localFlowServiceLocator;
251
252     /**
253      * The loader for loading the flow definition resource XML document.
254      */

255     private DocumentLoader documentLoader = new DefaultDocumentLoader();
256
257     /**
258      * The in-memory document object model (DOM) of the XML Document read from
259      * the flow definition resource.
260      */

261     private Document JavaDoc document;
262
263     /**
264      * Create a new XML flow builder parsing the document at the specified
265      * location.
266      * @param location the location of the XML-based flow definition resource
267      */

268     public XmlFlowBuilder(Resource location) {
269         setLocation(location);
270     }
271
272     /**
273      * Create a new XML flow builder parsing the document at the specified
274      * location, using the provided service locator to access externally managed
275      * flow artifacts.
276      * @param location the location of the XML-based flow definition resource
277      * @param flowServiceLocator the locator for services needed by this builder
278      * to build its Flow
279      */

280     public XmlFlowBuilder(Resource location, FlowServiceLocator flowServiceLocator) {
281         super(flowServiceLocator);
282         setLocation(location);
283     }
284
285     /**
286      * Returns the resource from which the document element was loaded. This is
287      * used for location relative loading of other resources.
288      */

289     public Resource getLocation() {
290         return location;
291     }
292
293     /**
294      * Sets the resource from which the document element was loaded. This is
295      * used for location relative loading of other resources.
296      */

297     public void setLocation(Resource location) {
298         Assert.notNull(location, "The resource location of the XML-based flow definition is required");
299         this.location = location;
300     }
301
302     /**
303      * Sets the loader that will load the XML-based flow definition document.
304      * Optional, defaults to {@link DefaultDocumentLoader}.
305      * @param documentLoader the document loader
306      */

307     public void setDocumentLoader(DocumentLoader documentLoader) {
308         Assert.notNull(documentLoader, "The XML document loader is required");
309         this.documentLoader = documentLoader;
310     }
311
312     // implementing FlowBuilder
313

314     public void init(String JavaDoc id, AttributeMap attributes) throws FlowBuilderException {
315         localFlowServiceLocator = new LocalFlowServiceLocator(getFlowServiceLocator());
316         try {
317             document = documentLoader.loadDocument(location);
318         }
319         catch (IOException JavaDoc e) {
320             throw new FlowBuilderException("Could not access the XML flow definition resource at " + location, e);
321         }
322         catch (ParserConfigurationException JavaDoc e) {
323             throw new FlowBuilderException("Could not configure the parser to parse the XML flow definition at "
324                     + location, e);
325         }
326         catch (SAXException JavaDoc e) {
327             throw new FlowBuilderException("Could not parse the XML flow definition document at " + location, e);
328         }
329         setFlow(parseFlow(id, attributes, getDocumentElement()));
330     }
331
332     public void buildVariables() throws FlowBuilderException {
333         parseAndAddFlowVariables(getDocumentElement(), getFlow());
334     }
335
336     public void buildInputMapper() throws FlowBuilderException {
337         getFlow().setInputMapper(parseInputMapper(getDocumentElement()));
338     }
339
340     public void buildStartActions() throws FlowBuilderException {
341         parseAndAddStartActions(getDocumentElement(), getFlow());
342     }
343
344     public void buildInlineFlows() throws FlowBuilderException {
345         parseAndAddInlineFlowDefinitions(getDocumentElement(), getFlow());
346     }
347
348     public void buildStates() throws FlowBuilderException {
349         parseAndAddStateDefinitions(getDocumentElement(), getFlow());
350     }
351
352     public void buildGlobalTransitions() throws FlowBuilderException {
353         parseAndAddGlobalTransitions(getDocumentElement(), getFlow());
354     }
355
356     public void buildEndActions() throws FlowBuilderException {
357         parseAndAddEndActions(getDocumentElement(), getFlow());
358     }
359
360     public void buildOutputMapper() throws FlowBuilderException {
361         getFlow().setOutputMapper(parseOutputMapper(getDocumentElement()));
362     }
363
364     public void buildExceptionHandlers() throws FlowBuilderException {
365         getFlow().getExceptionHandlerSet().addAll(parseExceptionHandlers(getDocumentElement()));
366     }
367
368     public void dispose() {
369         super.dispose();
370         localFlowServiceLocator.diposeOfAnyRegistries();
371         document = null;
372     }
373
374     // implementing ResourceHolder
375

376     public Resource getResource() {
377         return location;
378     }
379     
380     // helpers
381

382     /**
383      * Returns the DOM document parsed from the XML file.
384      */

385     protected Document JavaDoc getDocument() {
386         return document;
387     }
388
389     /**
390      * Returns the root document element.
391      */

392     protected Element JavaDoc getDocumentElement() {
393         return document.getDocumentElement();
394     }
395
396     /**
397      * Returns the flow service locator local to this builder.
398      */

399     protected FlowServiceLocator getLocalFlowServiceLocator() {
400         return localFlowServiceLocator;
401     }
402
403     /**
404      * Returns the artifact factory of the flow service locator local
405      * to this builder.
406      */

407     protected FlowArtifactFactory getFlowArtifactFactory() {
408         return getLocalFlowServiceLocator().getFlowArtifactFactory();
409     }
410
411     // utility (from Spring 2.x DomUtils)
412

413     /**
414      * Utility method that returns the first child element identified by its
415      * name.
416      * @param ele the DOM element to analyze
417      * @param childEleName the child element name to look for
418      * @return the <code>org.w3c.dom.Element</code> instance, or
419      * <code>null</code> if none found
420      */

421     protected Element JavaDoc getChildElementByTagName(Element JavaDoc ele, String JavaDoc childEleName) {
422         NodeList JavaDoc nl = ele.getChildNodes();
423         for (int i = 0; i < nl.getLength(); i++) {
424             Node JavaDoc node = nl.item(i);
425             if (node instanceof Element JavaDoc && nodeNameEquals(node, childEleName)) {
426                 return (Element JavaDoc)node;
427             }
428         }
429         return null;
430     }
431
432     /**
433      * Namespace-aware equals comparison. Returns <code>true</code> if either
434      * {@link Node#getLocalName} or {@link Node#getNodeName} equals
435      * <code>desiredName</code>, otherwise returns <code>false</code>.
436      */

437     protected boolean nodeNameEquals(Node JavaDoc node, String JavaDoc desiredName) {
438         return desiredName.equals(node.getNodeName()) || desiredName.equals(node.getLocalName());
439     }
440
441     // internal parsing logic
442

443     private Flow parseFlow(String JavaDoc id, AttributeMap attributes, Element JavaDoc flowElement) {
444         if (!isFlowElement(flowElement)) {
445             throw new IllegalStateException JavaDoc("This is not the '" + FLOW_ELEMENT + "' element");
446         }
447         Flow flow = getFlowArtifactFactory().createFlow(id, parseAttributes(flowElement).union(attributes));
448         initLocalServiceRegistry(flowElement, flow);
449         return flow;
450     }
451
452     private boolean isFlowElement(Element JavaDoc flowElement) {
453         return FLOW_ELEMENT.equals(flowElement.getTagName());
454     }
455
456     private void initLocalServiceRegistry(Element JavaDoc flowElement, Flow flow) {
457         List JavaDoc importElements = DomUtils.getChildElementsByTagName(flowElement, IMPORT_ELEMENT);
458         Resource[] resources = new Resource[importElements.size()];
459         for (int i = 0; i < importElements.size(); i++) {
460             Element JavaDoc importElement = (Element JavaDoc)importElements.get(i);
461             try {
462                 resources[i] = getLocation().createRelative(importElement.getAttribute(RESOURCE_ATTRIBUTE));
463             }
464             catch (IOException JavaDoc e) {
465                 throw new FlowBuilderException("Could not access flow-relative artifact resource '"
466                         + importElement.getAttribute(RESOURCE_ATTRIBUTE) + "'", e);
467             }
468         }
469         localFlowServiceLocator.push(new LocalFlowServiceRegistry(flow, resources));
470     }
471
472     private void destroyLocalServiceRegistry(Flow flow) {
473         localFlowServiceLocator.pop();
474     }
475
476     private void parseAndAddFlowVariables(Element JavaDoc flowElement, Flow flow) {
477         List JavaDoc varElements = DomUtils.getChildElementsByTagName(flowElement, VAR_ELEMENT);
478         for (Iterator JavaDoc it = varElements.iterator(); it.hasNext();) {
479             flow.addVariable(parseVariable((Element JavaDoc)it.next()));
480         }
481     }
482
483     private FlowVariable parseVariable(Element JavaDoc element) {
484         ScopeType scope = parseScope(element, ScopeType.FLOW);
485         if (StringUtils.hasText(element.getAttribute(BEAN_ATTRIBUTE))) {
486             BeanFactory beanFactory = getLocalFlowServiceLocator().getBeanFactory();
487             return new BeanFactoryFlowVariable(element.getAttribute(NAME_ATTRIBUTE),
488                     element.getAttribute(BEAN_ATTRIBUTE), beanFactory, scope);
489         }
490         else {
491             if (StringUtils.hasText(element.getAttribute(CLASS_ATTRIBUTE))) {
492                 Class JavaDoc variableClass = (Class JavaDoc)fromStringTo(Class JavaDoc.class).execute(element.getAttribute(CLASS_ATTRIBUTE));
493                 return new SimpleFlowVariable(element.getAttribute(NAME_ATTRIBUTE), variableClass, scope);
494             }
495             else {
496                 BeanFactory beanFactory = getLocalFlowServiceLocator().getBeanFactory();
497                 return new BeanFactoryFlowVariable(element.getAttribute(NAME_ATTRIBUTE), null, beanFactory, scope);
498             }
499         }
500     }
501
502     private void parseAndAddStartActions(Element JavaDoc element, Flow flow) {
503         Element JavaDoc startElement = getChildElementByTagName(element, START_ACTIONS_ELEMENT);
504         if (startElement != null) {
505             flow.getStartActionList().addAll(parseAnnotatedActions(startElement));
506         }
507     }
508
509     private void parseAndAddEndActions(Element JavaDoc element, Flow flow) {
510         Element JavaDoc endElement = getChildElementByTagName(element, END_ACTIONS_ELEMENT);
511         if (endElement != null) {
512             flow.getEndActionList().addAll(parseAnnotatedActions(endElement));
513         }
514     }
515
516     private void parseAndAddGlobalTransitions(Element JavaDoc element, Flow flow) {
517         Element JavaDoc globalTransitionsElement = getChildElementByTagName(element, GLOBAL_TRANSITIONS_ELEMENT);
518         if (globalTransitionsElement != null) {
519             flow.getGlobalTransitionSet().addAll(parseTransitions(globalTransitionsElement));
520         }
521     }
522
523     private void parseAndAddInlineFlowDefinitions(Element JavaDoc parentFlowElement, Flow flow) {
524         List JavaDoc inlineFlowElements = DomUtils.getChildElementsByTagName(parentFlowElement, INLINE_FLOW_ELEMENT);
525         for (Iterator JavaDoc it = inlineFlowElements.iterator(); it.hasNext();) {
526             Element JavaDoc inlineFlowElement = (Element JavaDoc)it.next();
527             String JavaDoc inlineFlowId = inlineFlowElement.getAttribute(ID_ATTRIBUTE);
528             Element JavaDoc flowElement = getChildElementByTagName(inlineFlowElement, FLOW_ATTRIBUTE);
529             Flow inlineFlow = parseFlow(inlineFlowId, null, flowElement);
530             buildInlineFlow(flowElement, inlineFlow);
531             flow.addInlineFlow(inlineFlow);
532         }
533     }
534
535     private void buildInlineFlow(Element JavaDoc flowElement, Flow inlineFlow) {
536         parseAndAddFlowVariables(flowElement, inlineFlow);
537         inlineFlow.setInputMapper(parseInputMapper(flowElement));
538         parseAndAddStartActions(flowElement, inlineFlow);
539         parseAndAddInlineFlowDefinitions(flowElement, inlineFlow);
540         parseAndAddStateDefinitions(flowElement, inlineFlow);
541         parseAndAddGlobalTransitions(flowElement, inlineFlow);
542         parseAndAddEndActions(flowElement, inlineFlow);
543         inlineFlow.setOutputMapper(parseOutputMapper(flowElement));
544         inlineFlow.getExceptionHandlerSet().addAll(parseExceptionHandlers(flowElement));
545         
546         destroyLocalServiceRegistry(inlineFlow);
547     }
548
549     private void parseAndAddStateDefinitions(Element JavaDoc flowElement, Flow flow) {
550         NodeList JavaDoc childNodeList = flowElement.getChildNodes();
551         for (int i = 0; i < childNodeList.getLength(); i++) {
552             Node JavaDoc childNode = childNodeList.item(i);
553             if (childNode instanceof Element JavaDoc) {
554                 Element JavaDoc stateElement = (Element JavaDoc)childNode;
555                 if (nodeNameEquals(stateElement, ACTION_STATE_ELEMENT)) {
556                     parseAndAddActionState(stateElement, flow);
557                 }
558                 else if (nodeNameEquals(stateElement, VIEW_STATE_ELEMENT)) {
559                     parseAndAddViewState(stateElement, flow);
560                 }
561                 else if (nodeNameEquals(stateElement, DECISION_STATE_ELEMENT)) {
562                     parseAndAddDecisionState(stateElement, flow);
563                 }
564                 else if (nodeNameEquals(stateElement, SUBFLOW_STATE_ELEMENT)) {
565                     parseAndAddSubflowState(stateElement, flow);
566                 }
567                 else if (nodeNameEquals(stateElement, END_STATE_ELEMENT)) {
568                     parseAndAddEndState(stateElement, flow);
569                 }
570             }
571         }
572         parseAndSetStartState(flowElement, flow);
573     }
574
575     private void parseAndSetStartState(Element JavaDoc element, Flow flow) {
576         String JavaDoc startStateId = getStartStateId(element);
577         flow.setStartState(startStateId);
578     }
579
580     private String JavaDoc getStartStateId(Element JavaDoc element) {
581         Element JavaDoc startStateElement = getChildElementByTagName(element, START_STATE_ELEMENT);
582         return startStateElement.getAttribute(IDREF_ATTRIBUTE);
583     }
584
585     private void parseAndAddActionState(Element JavaDoc element, Flow flow) {
586         getFlowArtifactFactory().createActionState(parseId(element), flow, parseEntryActions(element),
587                 parseAnnotatedActions(element), parseTransitions(element), parseExceptionHandlers(element),
588                 parseExitActions(element), parseAttributes(element));
589     }
590
591     private void parseAndAddViewState(Element JavaDoc element, Flow flow) {
592         getFlowArtifactFactory().createViewState(parseId(element), flow, parseEntryActions(element),
593                 parseViewSelector(element), parseRenderActions(element), parseTransitions(element),
594                 parseExceptionHandlers(element), parseExitActions(element), parseAttributes(element));
595     }
596
597     private void parseAndAddDecisionState(Element JavaDoc element, Flow flow) {
598         getFlowArtifactFactory().createDecisionState(
599                 parseId(element), flow, parseEntryActions(element), parseIfs(element),
600                 parseExceptionHandlers(element), parseExitActions(element), parseAttributes(element));
601     }
602
603     private void parseAndAddSubflowState(Element JavaDoc element, Flow flow) {
604         getFlowArtifactFactory().createSubflowState(parseId(element), flow, parseEntryActions(element),
605                 parseSubflow(element), parseFlowAttributeMapper(element), parseTransitions(element),
606                 parseExceptionHandlers(element), parseExitActions(element), parseAttributes(element));
607     }
608
609     private void parseAndAddEndState(Element JavaDoc element, Flow flow) {
610         getFlowArtifactFactory().createEndState(parseId(element), flow, parseEntryActions(element),
611                 parseViewSelector(element), parseOutputMapper(element), parseExceptionHandlers(element),
612                 parseAttributes(element));
613     }
614
615     private String JavaDoc parseId(Element JavaDoc element) {
616         return element.getAttribute(ID_ATTRIBUTE);
617     }
618
619     private Action[] parseEntryActions(Element JavaDoc element) {
620         Element JavaDoc entryActionsElement = getChildElementByTagName(element, ENTRY_ACTIONS_ELEMENT);
621         if (entryActionsElement != null) {
622             return parseAnnotatedActions(entryActionsElement);
623         }
624         else {
625             return null;
626         }
627     }
628
629     private Action[] parseRenderActions(Element JavaDoc element) {
630         Element JavaDoc renderActionsElement = getChildElementByTagName(element, RENDER_ACTIONS_ELEMENT);
631         if (renderActionsElement != null) {
632             return parseAnnotatedActions(renderActionsElement);
633         }
634         else {
635             return null;
636         }
637     }
638
639     private Action[] parseExitActions(Element JavaDoc element) {
640         Element JavaDoc exitActionsElement = getChildElementByTagName(element, EXIT_ACTIONS_ELEMENT);
641         if (exitActionsElement != null) {
642             return parseAnnotatedActions(exitActionsElement);
643         }
644         else {
645             return null;
646         }
647     }
648
649     private Transition[] parseTransitions(Element JavaDoc element) {
650         List JavaDoc transitions = new LinkedList JavaDoc();
651         List JavaDoc transitionElements = DomUtils.getChildElementsByTagName(element, TRANSITION_ELEMENT);
652         for (Iterator JavaDoc it = transitionElements.iterator(); it.hasNext();) {
653             Element JavaDoc transitionElement = (Element JavaDoc)it.next();
654             if (!StringUtils.hasText(transitionElement.getAttribute(ON_EXCEPTION_ATTRIBUTE))) {
655                 transitions.add(parseTransition(transitionElement));
656             }
657         }
658         return (Transition[])transitions.toArray(new Transition[transitions.size()]);
659     }
660
661     private Transition parseTransition(Element JavaDoc element) {
662         TransitionCriteria matchingCriteria = (TransitionCriteria)fromStringTo(TransitionCriteria.class).execute(
663                 element.getAttribute(ON_ATTRIBUTE));
664         TargetStateResolver targetStateResolver = (TargetStateResolver)fromStringTo(TargetStateResolver.class).execute(
665                 element.getAttribute(TO_ATTRIBUTE));
666         TransitionCriteria executionCriteria = TransitionCriteriaChain.criteriaChainFor(parseAnnotatedActions(element));
667         return getFlowArtifactFactory().createTransition(targetStateResolver, matchingCriteria, executionCriteria,
668                 parseAttributes(element));
669     }
670
671     private ViewSelector parseViewSelector(Element JavaDoc element) {
672         String JavaDoc viewName = element.getAttribute(VIEW_ATTRIBUTE);
673         return (ViewSelector)fromStringTo(ViewSelector.class).execute(viewName);
674     }
675
676     private Flow parseSubflow(Element JavaDoc element) {
677         return getLocalFlowServiceLocator().getSubflow(element.getAttribute(FLOW_ATTRIBUTE));
678     }
679
680     private AnnotatedAction[] parseAnnotatedActions(Element JavaDoc element) {
681         List JavaDoc actions = new LinkedList JavaDoc();
682         NodeList JavaDoc childNodeList = element.getChildNodes();
683         for (int i=0; i < childNodeList.getLength(); i++) {
684             Node JavaDoc childNode = childNodeList.item(i);
685             if (!(childNode instanceof Element JavaDoc)) {
686                 continue;
687             }
688             
689             if (nodeNameEquals(childNode, ACTION_ELEMENT)) {
690                 // parse standard action
691
actions.add(parseAnnotatedAction((Element JavaDoc)childNode));
692             }
693             else if (nodeNameEquals(childNode, BEAN_ACTION_ELEMENT)) {
694                 // parse bean invoking action
695
actions.add(parseAnnotatedBeanInvokingAction((Element JavaDoc)childNode));
696             }
697             else if (nodeNameEquals(childNode, EVALUATE_ACTION_ELEMENT)) {
698                 // parse evaluate action
699
actions.add(parseAnnotatedEvaluateAction((Element JavaDoc)childNode));
700             }
701             else if (nodeNameEquals(childNode, SET_ELEMENT)) {
702                 // parse set action
703
actions.add(parseAnnotatedSetAction((Element JavaDoc)childNode));
704             }
705         }
706         return (AnnotatedAction[])actions.toArray(new AnnotatedAction[actions.size()]);
707     }
708
709     private AnnotatedAction parseAnnotatedAction(Element JavaDoc element) {
710         AnnotatedAction annotated = new AnnotatedAction(parseAction(element));
711         parseCommonProperties(element, annotated);
712         if (element.hasAttribute(METHOD_ATTRIBUTE)) {
713             annotated.setMethod(element.getAttribute(METHOD_ATTRIBUTE));
714         }
715         return annotated;
716     }
717
718     private Action parseAction(Element JavaDoc element) {
719         String JavaDoc actionId = element.getAttribute(BEAN_ATTRIBUTE);
720         return getLocalFlowServiceLocator().getAction(actionId);
721     }
722
723     private AnnotatedAction parseCommonProperties(Element JavaDoc element, AnnotatedAction annotated) {
724         if (element.hasAttribute(NAME_ATTRIBUTE)) {
725             annotated.setName(element.getAttribute(NAME_ATTRIBUTE));
726         }
727         annotated.getAttributeMap().putAll(parseAttributes(element));
728         return annotated;
729     }
730
731     private AnnotatedAction parseAnnotatedBeanInvokingAction(Element JavaDoc element) {
732         AnnotatedAction annotated = new AnnotatedAction(parseBeanInvokingAction(element));
733         return parseCommonProperties(element, annotated);
734     }
735
736     private Action parseBeanInvokingAction(Element JavaDoc element) {
737         String JavaDoc beanId = element.getAttribute(BEAN_ATTRIBUTE);
738         String JavaDoc methodName = element.getAttribute(METHOD_ATTRIBUTE);
739         Parameters parameters = parseMethodParameters(element);
740         MethodSignature methodSignature = new MethodSignature(methodName, parameters);
741         ActionResultExposer resultExposer = parseMethodResultExposer(element);
742         return getLocalFlowServiceLocator().getBeanInvokingActionFactory().createBeanInvokingAction(beanId,
743                 getLocalFlowServiceLocator().getBeanFactory(), methodSignature, resultExposer,
744                 getLocalFlowServiceLocator().getConversionService(), null);
745     }
746
747     private Parameters parseMethodParameters(Element JavaDoc element) {
748         Element JavaDoc methodArgumentsElement = getChildElementByTagName(element, METHOD_ARGUMENTS_ELEMENT);
749         if (methodArgumentsElement == null) {
750             return Parameters.NONE;
751         }
752         Parameters parameters = new Parameters();
753         Iterator JavaDoc it = DomUtils.getChildElementsByTagName(methodArgumentsElement, ARGUMENT_ELEMENT).iterator();
754         while (it.hasNext()) {
755             Element JavaDoc argumentElement = (Element JavaDoc)it.next();
756             Expression name = getLocalFlowServiceLocator().getExpressionParser()
757                 .parseExpression(argumentElement.getAttribute(EXPRESSION_ATTRIBUTE));
758             Class JavaDoc type = null;
759             if (argumentElement.hasAttribute(PARAMETER_TYPE_ATTRIBUTE)) {
760                 type = (Class JavaDoc)fromStringTo(Class JavaDoc.class).execute(argumentElement.getAttribute(PARAMETER_TYPE_ATTRIBUTE));
761             }
762             parameters.add(new Parameter(type, name));
763         }
764         return parameters;
765     }
766
767     private ActionResultExposer parseMethodResultExposer(Element JavaDoc element) {
768         Element JavaDoc resultElement = getChildElementByTagName(element, METHOD_RESULT_ELEMENT);
769         if (resultElement != null) {
770             return parseActionResultExposer(resultElement);
771         }
772         else {
773             return null;
774         }
775     }
776
777     private ActionResultExposer parseActionResultExposer(Element JavaDoc element) {
778         String JavaDoc resultName = element.getAttribute(NAME_ATTRIBUTE);
779         return new ActionResultExposer(resultName, parseScope(element, ScopeType.REQUEST));
780     }
781
782     private AnnotatedAction parseAnnotatedEvaluateAction(Element JavaDoc element) {
783         AnnotatedAction annotated = new AnnotatedAction(parseEvaluateAction(element));
784         return parseCommonProperties(element, annotated);
785     }
786
787     private Action parseEvaluateAction(Element JavaDoc element) {
788         String JavaDoc expressionString = element.getAttribute(EXPRESSION_ATTRIBUTE);
789         Expression expression = getLocalFlowServiceLocator().getExpressionParser()
790             .parseExpression(expressionString);
791         return new EvaluateAction(expression, parseEvaluationResultExposer(element));
792     }
793
794     private ActionResultExposer parseEvaluationResultExposer(Element JavaDoc element) {
795         Element JavaDoc resultElement = getChildElementByTagName(element, EVALUATION_RESULT_ELEMENT);
796         if (resultElement != null) {
797             return parseActionResultExposer(resultElement);
798         }
799         else {
800             return null;
801         }
802     }
803
804     private AnnotatedAction parseAnnotatedSetAction(Element JavaDoc element) {
805         AnnotatedAction annotated = new AnnotatedAction(parseSetAction(element));
806         return parseCommonProperties(element, annotated);
807     }
808
809     private Action parseSetAction(Element JavaDoc element) {
810         String JavaDoc attributeExpressionString = element.getAttribute(ATTRIBUTE_ATTRIBUTE);
811         SettableExpression attributeExpression = getLocalFlowServiceLocator().getExpressionParser()
812             .parseSettableExpression(attributeExpressionString);
813         Expression valueExpression = getLocalFlowServiceLocator().getExpressionParser()
814             .parseExpression(element.getAttribute(VALUE_ATTRIBUTE));
815         return new SetAction(attributeExpression, parseScope(element, ScopeType.REQUEST), valueExpression);
816     }
817
818     private ScopeType parseScope(Element JavaDoc element, ScopeType defaultValue) {
819         if (element.hasAttribute(SCOPE_ATTRIBUTE) && !element.getAttribute(SCOPE_ATTRIBUTE).equals(DEFAULT_VALUE)) {
820             return (ScopeType)fromStringTo(ScopeType.class).execute(element.getAttribute(SCOPE_ATTRIBUTE));
821         }
822         else {
823             return defaultValue;
824         }
825     }
826
827     private AttributeMap parseAttributes(Element JavaDoc element) {
828         LocalAttributeMap attributes = new LocalAttributeMap();
829         List JavaDoc propertyElements = DomUtils.getChildElementsByTagName(element, ATTRIBUTE_ELEMENT);
830         for (int i = 0; i < propertyElements.size(); i++) {
831             parseAndSetAttribute((Element JavaDoc)propertyElements.get(i), attributes);
832         }
833         return attributes;
834     }
835
836     private void parseAndSetAttribute(Element JavaDoc element, MutableAttributeMap attributes) {
837         String JavaDoc name = element.getAttribute(NAME_ATTRIBUTE);
838         String JavaDoc value = null;
839         if (element.hasAttribute(VALUE_ATTRIBUTE)) {
840             value = element.getAttribute(VALUE_ATTRIBUTE);
841         }
842         else {
843             List JavaDoc valueElements = DomUtils.getChildElementsByTagName(element, VALUE_ELEMENT);
844             Assert.state(valueElements.size() == 1, "A property value should be specified for property '" + name + "'");
845             value = DomUtils.getTextValue((Element JavaDoc)valueElements.get(0));
846         }
847         attributes.put(name, convertPropertyValue(element, value));
848     }
849
850     private Object JavaDoc convertPropertyValue(Element JavaDoc element, String JavaDoc stringValue) {
851         if (element.hasAttribute(TYPE_ATTRIBUTE)) {
852             ConversionExecutor executor = fromStringTo(element.getAttribute(TYPE_ATTRIBUTE));
853             if (executor != null) {
854                 // convert string value to instance of aliased type
855
return executor.execute(stringValue);
856             }
857             else {
858                 Class JavaDoc targetClass = (Class JavaDoc)fromStringTo(Class JavaDoc.class).execute(element.getAttribute(TYPE_ATTRIBUTE));
859                 // convert string value to instance of target class
860
return fromStringTo(targetClass).execute(stringValue);
861             }
862         }
863         else {
864             return stringValue;
865         }
866     }
867
868     private Transition[] parseIfs(Element JavaDoc element) {
869         List JavaDoc transitions = new LinkedList JavaDoc();
870         List JavaDoc transitionElements = DomUtils.getChildElementsByTagName(element, IF_ELEMENT);
871         for (Iterator JavaDoc it = transitionElements.iterator(); it.hasNext();) {
872             transitions.addAll(Arrays.asList(parseIf((Element JavaDoc)it.next())));
873         }
874         return (Transition[])transitions.toArray(new Transition[transitions.size()]);
875     }
876
877     private Transition[] parseIf(Element JavaDoc element) {
878         Transition thenTransition = parseThen(element);
879         if (StringUtils.hasText(element.getAttribute(ELSE_ATTRIBUTE))) {
880             Transition elseTransition = parseElse(element);
881             return new Transition[] { thenTransition, elseTransition };
882         }
883         else {
884             return new Transition[] { thenTransition };
885         }
886     }
887
888     private Transition parseThen(Element JavaDoc element) {
889         Expression expression = getLocalFlowServiceLocator().getExpressionParser()
890             .parseExpression(element.getAttribute(TEST_ATTRIBUTE));
891         TransitionCriteria matchingCriteria = new BooleanExpressionTransitionCriteria(expression);
892         TargetStateResolver targetStateResolver = (TargetStateResolver)fromStringTo(TargetStateResolver.class).execute(
893                 element.getAttribute(THEN_ATTRIBUTE));
894         return getFlowArtifactFactory().createTransition(targetStateResolver, matchingCriteria, null, null);
895     }
896
897     private Transition parseElse(Element JavaDoc element) {
898         TargetStateResolver targetStateResolver = (TargetStateResolver)fromStringTo(TargetStateResolver.class).execute(
899                 element.getAttribute(ELSE_ATTRIBUTE));
900         return getFlowArtifactFactory().createTransition(targetStateResolver, null, null, null);
901     }
902
903     private FlowAttributeMapper parseFlowAttributeMapper(Element JavaDoc element) {
904         Element JavaDoc mapperElement = getChildElementByTagName(element, ATTRIBUTE_MAPPER_ELEMENT);
905         if (mapperElement == null) {
906             return null;
907         }
908         if (StringUtils.hasText(mapperElement.getAttribute(BEAN_ATTRIBUTE))) {
909             return getLocalFlowServiceLocator().getAttributeMapper(mapperElement.getAttribute(BEAN_ATTRIBUTE));
910         }
911         else {
912             return new ImmutableFlowAttributeMapper(parseInputMapper(mapperElement), parseOutputMapper(mapperElement));
913         }
914     }
915
916     private AttributeMapper parseInputMapper(Element JavaDoc element) {
917         Element JavaDoc mapperElement = getChildElementByTagName(element, INPUT_MAPPER_ELEMENT);
918         if (mapperElement != null) {
919             DefaultAttributeMapper mapper = new DefaultAttributeMapper();
920             parseSimpleAttributeMappings(mapper,
921                     DomUtils.getChildElementsByTagName(mapperElement, INPUT_ATTRIBUTE_ELEMENT));
922             parseMappings(mapper, mapperElement);
923             return mapper;
924         }
925         else {
926             return null;
927         }
928     }
929
930     private AttributeMapper parseOutputMapper(Element JavaDoc element) {
931         Element JavaDoc mapperElement = getChildElementByTagName(element, OUTPUT_MAPPER_ELEMENT);
932         if (mapperElement != null) {
933             DefaultAttributeMapper mapper = new DefaultAttributeMapper();
934             parseSimpleAttributeMappings(mapper,
935                     DomUtils.getChildElementsByTagName(mapperElement, OUTPUT_ATTRIBUTE_ELEMENT));
936             parseMappings(mapper, mapperElement);
937             return mapper;
938         }
939         else {
940             return null;
941         }
942     }
943
944     private void parseMappings(DefaultAttributeMapper mapper, Element JavaDoc element) {
945         ExpressionParser parser = getLocalFlowServiceLocator().getExpressionParser();
946         List JavaDoc mappingElements = DomUtils.getChildElementsByTagName(element, MAPPING_ELEMENT);
947         for (Iterator JavaDoc it = mappingElements.iterator(); it.hasNext();) {
948             Element JavaDoc mappingElement = (Element JavaDoc)it.next();
949             Expression source = parser.parseExpression(mappingElement.getAttribute(SOURCE_ATTRIBUTE));
950             SettableExpression target = null;
951             if (StringUtils.hasText(mappingElement.getAttribute(TARGET_ATTRIBUTE))) {
952                 target = parser.parseSettableExpression(mappingElement.getAttribute(TARGET_ATTRIBUTE));
953             }
954             else if (StringUtils.hasText(mappingElement.getAttribute(TARGET_COLLECTION_ATTRIBUTE))) {
955                 target = new CollectionAddingExpression(
956                         parser.parseSettableExpression(mappingElement.getAttribute(TARGET_COLLECTION_ATTRIBUTE)));
957             }
958             if (getRequired(mappingElement, false)) {
959                 mapper.addMapping(new RequiredMapping(source, target, parseTypeConverter(mappingElement)));
960             }
961             else {
962                 mapper.addMapping(new Mapping(source, target, parseTypeConverter(mappingElement)));
963             }
964         }
965     }
966
967     private void parseSimpleAttributeMappings(DefaultAttributeMapper mapper, List JavaDoc elements) {
968         ExpressionParser parser = getLocalFlowServiceLocator().getExpressionParser();
969         for (Iterator JavaDoc it = elements.iterator(); it.hasNext();) {
970             Element JavaDoc element = (Element JavaDoc)it.next();
971             SettableExpression attribute = parser.parseSettableExpression(element.getAttribute(NAME_ATTRIBUTE));
972             SettableExpression expression = new AttributeExpression(attribute, parseScope(element, ScopeType.FLOW));
973             if (getRequired(element, false)) {
974                 mapper.addMapping(new RequiredMapping(expression, expression, null));
975             }
976             else {
977                 mapper.addMapping(new Mapping(expression, expression, null));
978             }
979         }
980     }
981
982     private boolean getRequired(Element JavaDoc element, boolean defaultValue) {
983         if (StringUtils.hasText(element.getAttribute(REQUIRED_ATTRIBUTE))) {
984             return ((Boolean JavaDoc)fromStringTo(Boolean JavaDoc.class).execute(element.getAttribute(REQUIRED_ATTRIBUTE)))
985                     .booleanValue();
986         }
987         else {
988             return defaultValue;
989         }
990     }
991
992     private ConversionExecutor parseTypeConverter(Element JavaDoc element) {
993         String JavaDoc from = element.getAttribute(FROM_ATTRIBUTE);
994         String JavaDoc to = element.getAttribute(TO_ATTRIBUTE);
995         if (StringUtils.hasText(from)) {
996             if (StringUtils.hasText(to)) {
997                 ConversionService service = getLocalFlowServiceLocator().getConversionService();
998                 return service.getConversionExecutor(service.getClassByAlias(from), service.getClassByAlias(to));
999             }
1000            else {
1001                throw new IllegalArgumentException JavaDoc("Use of the 'from' attribute requires use of the 'to' attribute");
1002            }
1003        }
1004        else {
1005            Assert.isTrue(!StringUtils.hasText(to), "Use of the 'to' attribute requires use of the 'from' attribute");
1006        }
1007        return null;
1008    }
1009
1010    private FlowExecutionExceptionHandler[] parseExceptionHandlers(Element JavaDoc element) {
1011        FlowExecutionExceptionHandler[] transitionExecutingHandlers = parseTransitionExecutingExceptionHandlers(element);
1012        FlowExecutionExceptionHandler[] customHandlers = parseCustomExceptionHandlers(element);
1013        FlowExecutionExceptionHandler[] exceptionHandlers =
1014            new FlowExecutionExceptionHandler[transitionExecutingHandlers.length + customHandlers.length];
1015        System.arraycopy(transitionExecutingHandlers, 0, exceptionHandlers, 0, transitionExecutingHandlers.length);
1016        System.arraycopy(customHandlers, 0, exceptionHandlers, transitionExecutingHandlers.length,
1017            customHandlers.length);
1018        return exceptionHandlers;
1019    }
1020
1021    private FlowExecutionExceptionHandler[] parseTransitionExecutingExceptionHandlers(Element JavaDoc element) {
1022        List JavaDoc transitionElements = Collections.EMPTY_LIST;
1023        if (isFlowElement(element)) {
1024            Element JavaDoc globalTransitionsElement = getChildElementByTagName(element, GLOBAL_TRANSITIONS_ELEMENT);
1025            if (globalTransitionsElement != null) {
1026                transitionElements = DomUtils.getChildElementsByTagName(globalTransitionsElement, TRANSITION_ELEMENT);
1027            }
1028        }
1029        else {
1030            transitionElements = DomUtils.getChildElementsByTagName(element, TRANSITION_ELEMENT);
1031        }
1032        List JavaDoc exceptionHandlers = new LinkedList JavaDoc();
1033        for (Iterator JavaDoc it = transitionElements.iterator(); it.hasNext();) {
1034            Element JavaDoc transitionElement = (Element JavaDoc)it.next();
1035            if (StringUtils.hasText(transitionElement.getAttribute(ON_EXCEPTION_ATTRIBUTE))) {
1036                exceptionHandlers.add(parseTransitionExecutingExceptionHandler(transitionElement));
1037            }
1038        }
1039        return (FlowExecutionExceptionHandler[])exceptionHandlers
1040                .toArray(new FlowExecutionExceptionHandler[exceptionHandlers.size()]);
1041    }
1042
1043    private FlowExecutionExceptionHandler parseTransitionExecutingExceptionHandler(Element JavaDoc element) {
1044        TransitionExecutingStateExceptionHandler handler = new TransitionExecutingStateExceptionHandler();
1045        Class JavaDoc exceptionClass = (Class JavaDoc)fromStringTo(Class JavaDoc.class).execute(element.getAttribute(ON_EXCEPTION_ATTRIBUTE));
1046        handler.add(exceptionClass, element.getAttribute(TO_ATTRIBUTE));
1047        handler.getActionList().addAll(parseAnnotatedActions(element));
1048        return handler;
1049    }
1050
1051    private FlowExecutionExceptionHandler[] parseCustomExceptionHandlers(Element JavaDoc element) {
1052        List JavaDoc exceptionHandlers = new LinkedList JavaDoc();
1053        List JavaDoc handlerElements = DomUtils.getChildElementsByTagName(element, EXCEPTION_HANDLER_ELEMENT);
1054        for (int i = 0; i < handlerElements.size(); i++) {
1055            Element JavaDoc handlerElement = (Element JavaDoc)handlerElements.get(i);
1056            exceptionHandlers.add(parseCustomExceptionHandler(handlerElement));
1057        }
1058        return (FlowExecutionExceptionHandler[])exceptionHandlers
1059                .toArray(new FlowExecutionExceptionHandler[exceptionHandlers.size()]);
1060    }
1061
1062    private FlowExecutionExceptionHandler parseCustomExceptionHandler(Element JavaDoc element) {
1063        return getLocalFlowServiceLocator().getExceptionHandler(element.getAttribute(BEAN_ATTRIBUTE));
1064    }
1065}
Popular Tags