View Javadoc

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>&lt;context, {@link
35   * ch.elca.el4j.services.exceptionhandler.ExceptionConfiguration}&gt;</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>&lt;bean id="contextExceptionHandlerInterceptor"
50   *       class="ch.elca.el4j.services.exceptionhandler.ContextExceptionHandlerInterceptor"&gt;
51   *       &lt;property name="policies"&gt;
52   *           &lt;map&gt;
53   *               &lt;entry key="gui"&gt;
54   *                   &lt;list&gt;
55   *                       &lt;ref local="guiExceptionConfiguration"/&gt;
56   *                   &lt;/list&gt;
57   *               &lt;/entry&gt;
58   *               &lt;entry key="batch"&gt;
59   *                   &lt;list&gt;
60   *                       &lt;ref local="batchExceptionConfiguration"/&gt;
61   *                   &lt;/list&gt;
62   *               &lt;/entry&gt;
63   *           &lt;/map&gt;
64   *       &lt;/property&gt;
65   *   &lt;/bean&gt;</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 }