KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > webflow > engine > support > TransitionExecutingStateExceptionHandler


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.support;
17
18 import java.util.HashMap JavaDoc;
19 import java.util.Map JavaDoc;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.springframework.core.JdkVersion;
24 import org.springframework.core.NestedRuntimeException;
25 import org.springframework.core.style.ToStringCreator;
26 import org.springframework.util.Assert;
27 import org.springframework.webflow.engine.ActionList;
28 import org.springframework.webflow.engine.FlowExecutionExceptionHandler;
29 import org.springframework.webflow.engine.RequestControlContext;
30 import org.springframework.webflow.engine.TargetStateResolver;
31 import org.springframework.webflow.engine.Transition;
32 import org.springframework.webflow.execution.FlowExecutionException;
33 import org.springframework.webflow.execution.ViewSelection;
34
35 /**
36  * A flow execution exception handler that maps the occurence of a specific type of
37  * exception to a transition to a new {@link org.springframework.webflow.engine.State}.
38  *
39  * @author Keith Donald
40  */

41 public class TransitionExecutingStateExceptionHandler implements FlowExecutionExceptionHandler {
42
43     private static final Log logger = LogFactory.getLog(TransitionExecutingStateExceptionHandler.class);
44
45     /**
46      * The name of the attribute to expose a handled exception under in
47      * flash scope.
48      */

49     public static final String JavaDoc STATE_EXCEPTION_ATTRIBUTE = "stateException";
50
51     /**
52      * The name of the attribute to expose a root cause of a handled exception
53      * under in flash scope.
54      */

55     public static final String JavaDoc ROOT_CAUSE_EXCEPTION_ATTRIBUTE = "rootCauseException";
56
57     /**
58      * The exceptionType->targetStateResolver map.
59      */

60     private Map JavaDoc exceptionTargetStateMappings = new HashMap JavaDoc();
61
62     /**
63      * The list of actions to execute when this handler handles an exception.
64      */

65     private ActionList actionList = new ActionList();
66
67     /**
68      * Adds an exception->state mapping to this handler.
69      * @param exceptionClass the type of exception to map
70      * @param targetStateId the id of the state to transition to if the
71      * specified type of exception is handled
72      * @return this handler, to allow for adding multiple mappings in a single
73      * statement
74      */

75     public TransitionExecutingStateExceptionHandler add(Class JavaDoc exceptionClass, String JavaDoc targetStateId) {
76         return add(exceptionClass, new DefaultTargetStateResolver(targetStateId));
77     }
78
79     /**
80      * Adds a exception->state mapping to this handler.
81      * @param exceptionClass the type of exception to map
82      * @param targetStateResolver the resolver to calculate the state to
83      * transition to if the specified type of exception is handled
84      * @return this handler, to allow for adding multiple mappings in a single
85      * statement
86      */

87     public TransitionExecutingStateExceptionHandler add(Class JavaDoc exceptionClass, TargetStateResolver targetStateResolver) {
88         Assert.notNull(exceptionClass, "The exception class is required");
89         Assert.notNull(targetStateResolver, "The target state resolver is required");
90         exceptionTargetStateMappings.put(exceptionClass, targetStateResolver);
91         return this;
92     }
93     
94     /**
95      * Returns the list of actions to execute when this handler handles an exception.
96      * The returned list is mutable.
97      */

98     public ActionList getActionList() {
99         return actionList;
100     }
101
102     public boolean handles(FlowExecutionException e) {
103         return getTargetStateResolver(e) != null;
104     }
105
106     public ViewSelection handle(FlowExecutionException e, RequestControlContext context) {
107         if (logger.isDebugEnabled()) {
108             logger.debug("Handling state exception " + e);
109         }
110         // expose state exception in flash scope so it's available for response rendering
111
context.getFlashScope().put(STATE_EXCEPTION_ATTRIBUTE, e);
112         Throwable JavaDoc rootCause = findRootCause(e);
113         if (logger.isDebugEnabled()) {
114             logger.debug("Exposing state exception root cause " + rootCause + " under attribute '"
115                     + ROOT_CAUSE_EXCEPTION_ATTRIBUTE + "'");
116         }
117         // expose root cause in flash scope so it's available for response rendering
118
context.getFlashScope().put(ROOT_CAUSE_EXCEPTION_ATTRIBUTE, rootCause);
119         actionList.execute(context);
120         return context.execute(new Transition(getTargetStateResolver(e)));
121     }
122
123     // helpers
124

125     /**
126      * Find the mapped target state resolver for given exception. Returns
127      * <code>null</code> if no mapping can be found for given exception. Will
128      * try all exceptions in the exception cause chain.
129      */

130     protected TargetStateResolver getTargetStateResolver(FlowExecutionException e) {
131         if (JdkVersion.getMajorJavaVersion() == JdkVersion.JAVA_13) {
132             return getTargetStateResolver13(e);
133         }
134         else {
135             return getTargetStateResolver14(e);
136         }
137     }
138
139     /**
140      * Internal getTargetStateResolver implementation for use with JDK 1.3.
141      */

142     private TargetStateResolver getTargetStateResolver13(NestedRuntimeException e) {
143         TargetStateResolver targetStateResolver;
144         if (isRootCause13(e)) {
145             return findTargetStateResolver(e.getClass());
146         }
147         else {
148             targetStateResolver = (TargetStateResolver)exceptionTargetStateMappings.get(e.getClass());
149             if (targetStateResolver != null) {
150                 return targetStateResolver;
151             }
152             else {
153                 if (e.getCause() instanceof NestedRuntimeException) {
154                     return getTargetStateResolver13((NestedRuntimeException)e.getCause());
155                 }
156                 else {
157                     return null;
158                 }
159             }
160         }
161     }
162
163     /**
164      * Internal getTargetStateResolver implementation for use with JDK 1.4 or later.
165      */

166     private TargetStateResolver getTargetStateResolver14(Throwable JavaDoc t) {
167         TargetStateResolver targetStateResolver;
168         if (isRootCause14(t)) {
169             return findTargetStateResolver(t.getClass());
170         }
171         else {
172             targetStateResolver = (TargetStateResolver)exceptionTargetStateMappings.get(t.getClass());
173             if (targetStateResolver != null) {
174                 return targetStateResolver;
175             }
176             else {
177                 return getTargetStateResolver14(t.getCause());
178             }
179         }
180     }
181
182     /**
183      * Check if given exception is the root of the exception cause chain.
184      * For use with JDK 1.3.
185      */

186     private boolean isRootCause13(NestedRuntimeException e) {
187         return e.getCause() == null;
188     }
189
190     /**
191      * Check if given exception is the root of the exception cause chain.
192      * For use with JDK 1.4 or later.
193      */

194     private boolean isRootCause14(Throwable JavaDoc t) {
195         return t.getCause() == null;
196     }
197
198     /**
199      * Try to find a mapped target state resolver for given exception type. Will
200      * also try to lookup using the class hierarchy of given exception type.
201      * @param exceptionType the exception type to lookup
202      * @return the target state id or null if not found
203      */

204     private TargetStateResolver findTargetStateResolver(Class JavaDoc exceptionType) {
205         while (exceptionType != null && exceptionType.getClass() != Object JavaDoc.class) {
206             if (exceptionTargetStateMappings.containsKey(exceptionType)) {
207                 return (TargetStateResolver)exceptionTargetStateMappings.get(exceptionType);
208             }
209             else {
210                 exceptionType = exceptionType.getSuperclass();
211             }
212         }
213         return null;
214     }
215
216     /**
217      * Find the root cause of given throwable.
218      */

219     protected Throwable JavaDoc findRootCause(Throwable JavaDoc t) {
220         if (JdkVersion.getMajorJavaVersion() == JdkVersion.JAVA_13) {
221             return findRootCause13(t);
222         }
223         else {
224             return findRootCause14(t);
225         }
226     }
227
228     /**
229      * Find the root cause of given throwable. For use on JDK 1.3.
230      */

231     private Throwable JavaDoc findRootCause13(Throwable JavaDoc t) {
232         if (t instanceof NestedRuntimeException) {
233             NestedRuntimeException nre = (NestedRuntimeException)t;
234             Throwable JavaDoc cause = nre.getCause();
235             if (cause == null) {
236                 return nre;
237             }
238             else {
239                 return findRootCause13(cause);
240             }
241         }
242         else {
243             return t;
244         }
245     }
246
247     /**
248      * Find the root cause of given throwable. For use on JDK 1.4 or later.
249      */

250     private Throwable JavaDoc findRootCause14(Throwable JavaDoc e) {
251         Throwable JavaDoc cause = e.getCause();
252         if (cause == null) {
253             return e;
254         }
255         else {
256             return findRootCause14(cause);
257         }
258     }
259
260     public String JavaDoc toString() {
261         return new ToStringCreator(this).append("exceptionTargetStateMappings", exceptionTargetStateMappings)
262                 .toString();
263     }
264 }
Popular Tags