1 16 package org.springframework.webflow.engine.support; 17 18 import java.util.HashMap ; 19 import java.util.Map ; 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 41 public class TransitionExecutingStateExceptionHandler implements FlowExecutionExceptionHandler { 42 43 private static final Log logger = LogFactory.getLog(TransitionExecutingStateExceptionHandler.class); 44 45 49 public static final String STATE_EXCEPTION_ATTRIBUTE = "stateException"; 50 51 55 public static final String ROOT_CAUSE_EXCEPTION_ATTRIBUTE = "rootCauseException"; 56 57 60 private Map exceptionTargetStateMappings = new HashMap (); 61 62 65 private ActionList actionList = new ActionList(); 66 67 75 public TransitionExecutingStateExceptionHandler add(Class exceptionClass, String targetStateId) { 76 return add(exceptionClass, new DefaultTargetStateResolver(targetStateId)); 77 } 78 79 87 public TransitionExecutingStateExceptionHandler add(Class 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 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 context.getFlashScope().put(STATE_EXCEPTION_ATTRIBUTE, e); 112 Throwable 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 context.getFlashScope().put(ROOT_CAUSE_EXCEPTION_ATTRIBUTE, rootCause); 119 actionList.execute(context); 120 return context.execute(new Transition(getTargetStateResolver(e))); 121 } 122 123 125 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 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 166 private TargetStateResolver getTargetStateResolver14(Throwable 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 186 private boolean isRootCause13(NestedRuntimeException e) { 187 return e.getCause() == null; 188 } 189 190 194 private boolean isRootCause14(Throwable t) { 195 return t.getCause() == null; 196 } 197 198 204 private TargetStateResolver findTargetStateResolver(Class exceptionType) { 205 while (exceptionType != null && exceptionType.getClass() != Object .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 219 protected Throwable findRootCause(Throwable t) { 220 if (JdkVersion.getMajorJavaVersion() == JdkVersion.JAVA_13) { 221 return findRootCause13(t); 222 } 223 else { 224 return findRootCause14(t); 225 } 226 } 227 228 231 private Throwable findRootCause13(Throwable t) { 232 if (t instanceof NestedRuntimeException) { 233 NestedRuntimeException nre = (NestedRuntimeException)t; 234 Throwable 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 250 private Throwable findRootCause14(Throwable e) { 251 Throwable cause = e.getCause(); 252 if (cause == null) { 253 return e; 254 } 255 else { 256 return findRootCause14(cause); 257 } 258 } 259 260 public String toString() { 261 return new ToStringCreator(this).append("exceptionTargetStateMappings", exceptionTargetStateMappings) 262 .toString(); 263 } 264 } | Popular Tags |