1 /*
2 * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3 * the spring framework, http://el4j.sf.net
4 * Copyright (C) 2005 by ELCA Informatique SA, Av. de la Harpe 22-24,
5 * 1000 Lausanne, Switzerland, http://www.elca.ch
6 *
7 * EL4J is published under the GNU Lesser General Public License (LGPL)
8 * Version 2.1. See http://www.gnu.org/licenses/
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * For alternative licensing, please contact info@elca.ch
16 */
17
18 package ch.elca.el4j.services.exceptionhandler;
19
20 import java.util.List;
21 import java.util.Map;
22
23 import org.aopalliance.intercept.MethodInvocation;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28 * This class allows to handle exceptions centrally. Realized as an interceptor,
29 * it can be added to an arbitrary bean using a proxy. The handler supports
30 * different contexts which allows to handle a particular exception in different
31 * fashions, depending on the current context.
32 *
33 * <p>This class is configured with different policies, one for each context.
34 * A policy is an <code><context, {@link
35 * ch.elca.el4j.services.exceptionhandler.ExceptionConfiguration}></code>
36 * pair.
37 *
38 * <p><b>Important</b>: The context is stored in a {@link
39 * java.lang.ThreadLocal}, allowing to use this class in multi threading
40 * environments. Since it's considered cumbersome to set the context before
41 * each invocation it isn't reset. <b>The programmer is responsible to set the
42 * context appropriately.</b>
43 *
44 * <p>Don't use this interceptor directly. Instead use the {@link
45 * ch.elca.el4j.services.exceptionhandler.ContextExceptionHandlerFactoryBean}.
46 *
47 * <p><b>Example</b>: Let's assume the exception configurations are
48 * initialized properly.
49 * <pre><bean id="contextExceptionHandlerInterceptor"
50 * class="ch.elca.el4j.services.exceptionhandler.ContextExceptionHandlerInterceptor">
51 * <property name="policies">
52 * <map>
53 * <entry key="gui">
54 * <list>
55 * <ref local="guiExceptionConfiguration"/>
56 * </list>
57 * </entry>
58 * <entry key="batch">
59 * <list>
60 * <ref local="batchExceptionConfiguration"/>
61 * </list>
62 * </entry>
63 * </map>
64 * </property>
65 * </bean></pre>
66 * And the Java fragment:
67 * <pre>
68 * ContextExceptionHandlerInterceptor.setContext("gui");
69 * foo(); // an exception is handled by the gui policy
70 *
71 * ContextExceptionHandlerInterceptor.setContext("batch");
72 * foo(); // an exception is handled by the batch policy
73 *
74 * foo(); // an exception is handled by the batch policy
75 * </pre>
76 *
77 * @svnLink $Revision: 3873 $;$Date: 2009-08-04 13:59:45 +0200 (Di, 04. Aug 2009) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/exception_handling/src/main/java/ch/elca/el4j/services/exceptionhandler/ContextExceptionHandlerInterceptor.java $
78 *
79 * @author Andreas Bur (ABU)
80 * @see ch.elca.el4j.services.exceptionhandler.ContextExceptionHandlerFactoryBean
81 */
82 public class ContextExceptionHandlerInterceptor
83 extends AbstractExceptionHandlerInterceptor {
84
85 /** The static logger. */
86 private static Logger s_logger
87 = LoggerFactory.getLogger(ContextExceptionHandlerInterceptor.class);
88
89 /** The thread specific context. */
90 private static ThreadLocal s_context = new ThreadLocal();
91
92 /** The policies. */
93 private Map m_policies;
94
95 /**
96 * Default constructor. Configures the interceptor to handle only those
97 * exceptions that are <b>not</b> defined in the signature (excluding
98 * unchecked exceptions, which are handled always).
99 */
100 public ContextExceptionHandlerInterceptor() {
101 super();
102 // change this behaviour in the ContextExceptionHandlerFactoryBean too
103 // (to be done manually since Java doesn't support multi inheritance).
104 setForwardSignatureExceptions(true);
105 setHandleRTSignatureExceptions(true);
106 }
107
108 /**
109 * Sets the current thread's context.
110 *
111 * @param context
112 * The context to set.
113 *
114 * @return Returns the previous context.
115 */
116 public static Object setContext(Object context) {
117 Object curContext = s_context.get();
118 s_context.set(context);
119 return curContext;
120 }
121
122 /**
123 * Sets the policies.
124 *
125 * @param policies
126 * The policies to set.
127 */
128 public void setPolicies(Map policies) {
129 m_policies = policies;
130 }
131
132 /**
133 * {@inheritDoc}
134 */
135 protected Object handleException(Throwable t, MethodInvocation invocation)
136 throws Throwable {
137
138 handleInterfaceExceptions(invocation, t);
139
140 Object context = s_context.get();
141 if (context == null) {
142 s_logger.error(
143 "No context has been set.");
144 throw new MissingContextException("No context has been set.", t);
145 }
146
147 List list = (List) m_policies.get(context);
148
149 ExceptionConfiguration[] config = (ExceptionConfiguration[]) list.
150 toArray(new ExceptionConfiguration[list.size()]);
151 return doHandleException(t, invocation, config);
152 }
153 }