View Javadoc

1   /*
2    * $Id: InterceptorDelegate.java,v 1.5 2004/06/22 17:57:24 eelco12 Exp $
3    * $Revision: 1.5 $
4    * $Date: 2004/06/22 17:57:24 $
5    *
6    * ====================================================================
7    * Copyright (c) 2003
8    * All rights reserved.
9    */
10  package nl.openedge.baritus;
11  
12  import java.io.IOException;
13  
14  import javax.servlet.RequestDispatcher;
15  import javax.servlet.ServletException;
16  import javax.servlet.http.HttpServletRequest;
17  
18  import nl.openedge.baritus.interceptors.AfterPerformInterceptor;
19  import nl.openedge.baritus.interceptors.AfterPopulationInterceptor;
20  import nl.openedge.baritus.interceptors.BeforeMakeFormBeanInterceptor;
21  import nl.openedge.baritus.interceptors.BeforePopulationInterceptor;
22  import nl.openedge.baritus.interceptors.DispatchNowFlowException;
23  import nl.openedge.baritus.interceptors.FlowException;
24  import nl.openedge.baritus.interceptors.Interceptor;
25  import nl.openedge.baritus.interceptors.PerformExceptionInterceptor;
26  import nl.openedge.baritus.interceptors.PopulationErrorInterceptor;
27  import nl.openedge.baritus.interceptors.ReturnNowFlowException;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.infohazard.maverick.flow.ControllerContext;
32  
33  /***
34   * Delegate for handling interceptor actions.
35   * 
36   * @author Eelco Hillenius
37   */
38  final class InterceptorDelegate
39  {
40  	/* handle to interceptor registry */	
41  	private InterceptorRegistry interceptorRegistry = null;
42      
43      /* interception logger */
44      private static Log intercLog = LogFactory.getLog(LogConstants.INTERCEPTION_LOG);
45  	
46  	private final static int LEVEL_BEFORE_MAKE_FORMBEAN = 0;
47  	private final static int LEVEL_BEFORE_POPULATION = 1;
48  	private final static int LEVEL_POPULATION_ERROR = 2;
49  	private final static int LEVEL_AFTER_POPULATION = 3;
50  	private final static int LEVEL_PERFORM_EXCEPTION = 4;
51  	private final static int LEVEL_AFTER_PERFORM = 5;
52  
53  	/***
54  	 * Construct the delegate with an instance of the interceptor registry.
55  	 * 
56  	 * @param interceptorRegistry the interceptor registry
57  	 */
58  	public InterceptorDelegate(InterceptorRegistry interceptorRegistry)
59  	{
60  		this.interceptorRegistry = interceptorRegistry;
61  	}
62  
63  	//***************************** interceptors ******************************************/
64  	
65  	// NOTE: it would be possible to have just two methods instead of the
66  	// next bulk of methods using introspection. To keep it straightforward to
67  	// read though, and have a small performance edge I just coded the methods.
68  	
69  	
70  	
71  	//-------------------------- interceptors -----------------------------/
72  	
73  	/***
74  	 * Called before any handling like form population etc.
75  	 * 
76  	 * @param cctx maverick context
77  	 * @param formBeanContext context with unpopulated formBean
78  	 * @throws ServletException
79  	 */
80  	public void doInterceptBeforeMakeFormBean(
81  		ControllerContext cctx,
82  		FormBeanContext formBeanContext) 
83          throws ServletException, FlowException
84  	{
85          internalDoInterceptBeforeMakeFormBean(cctx, formBeanContext, true);
86  	}
87      
88      private void internalDoInterceptBeforeMakeFormBean(
89          ControllerContext cctx,
90          FormBeanContext formBeanContext,
91          boolean handleFlowExceptions) 
92          throws ServletException, FlowException
93      {
94          Interceptor[] commands = interceptorRegistry.getInterceptors(
95              BeforeMakeFormBeanInterceptor.class);
96  
97          internalDoExecute(commands, 0, cctx, formBeanContext, 
98              handleFlowExceptions, LEVEL_BEFORE_MAKE_FORMBEAN, null);
99      }
100 	
101 	/***
102 	 * Called before any handling like form population etc. but after makeFormBean.
103 	 * 
104 	 * @param cctx maverick context
105 	 * @param formBeanContext context with unpopulated formBean
106 	 * @throws ServletException
107 	 */
108 	public void doInterceptBeforePopulation(
109 		ControllerContext cctx,
110 		FormBeanContext formBeanContext) 
111         throws ServletException, FlowException
112 	{
113         internalDoInterceptBeforePopulation(cctx, formBeanContext, true);
114 	}
115     
116     public void internalDoInterceptBeforePopulation(
117         ControllerContext cctx,
118         FormBeanContext formBeanContext,
119         boolean handleFlowExceptions) 
120         throws ServletException, FlowException
121     {
122         Interceptor[] commands = interceptorRegistry.getInterceptors(
123             BeforePopulationInterceptor.class);
124 
125         internalDoExecute(commands, 0, cctx, formBeanContext, 
126             handleFlowExceptions, LEVEL_BEFORE_POPULATION, null);
127     }
128 	
129 	/***
130 	 * Called if population or validation failed.
131 	 * 
132 	 * @param cctx maverick context
133 	 * @param formBeanContext context with form bean that failed to populate
134      * @param cause possibly the cause of the population error
135 	 * @throws ServletException
136 	 */
137 	public void doInterceptPopulationError(
138 		ControllerContext cctx, 
139 		FormBeanContext formBeanContext,
140         Exception cause)
141         throws ServletException, FlowException
142 	{
143         internalDoInterceptPopulationError(cctx, formBeanContext, cause, true);
144 	}
145     
146     public void internalDoInterceptPopulationError(
147         ControllerContext cctx, 
148         FormBeanContext formBeanContext,
149         Exception cause,
150         boolean handleFlowExceptions)
151         throws ServletException, FlowException
152     {
153         Interceptor[] commands = interceptorRegistry.getInterceptors(
154             PopulationErrorInterceptor.class);
155             
156         internalDoExecute(commands, 0, cctx, formBeanContext, 
157             handleFlowExceptions, LEVEL_POPULATION_ERROR, cause);
158     }
159 	
160 	/***
161 	 * Called after population but before executing the command method.
162 	 * 
163 	 * @param cctx maverick context
164 	 * @param formBeanContext context with unpopulated formBean
165 	 * @throws ServletException
166 	 */
167 	public void doInterceptAfterPopulation(
168 		ControllerContext cctx,
169 		FormBeanContext formBeanContext) 
170         throws ServletException, FlowException
171 	{
172         internalDoInterceptAfterPopulation(cctx, formBeanContext, true);
173 	}
174     
175     public void internalDoInterceptAfterPopulation(
176         ControllerContext cctx,
177         FormBeanContext formBeanContext,
178         boolean handleFlowExceptions) 
179         throws ServletException, FlowException
180     {
181         Interceptor[] commands = interceptorRegistry.getInterceptors(
182             AfterPopulationInterceptor.class);
183             
184         internalDoExecute(commands, 0, cctx, formBeanContext, 
185             handleFlowExceptions, LEVEL_AFTER_POPULATION, null);
186     }
187 	
188 	/***
189 	 * Called when an unhandled exception occured during the execution of the command method.
190 	 * 
191 	 * @param cctx maverick context
192 	 * @param formBeanContext context with populated (if succesful) formBean
193      * @param cause the exception that occured during perform
194 	 * @throws ServletException
195 	 */
196 	public void doInterceptPerformException(
197 		ControllerContext cctx,
198 		FormBeanContext formBeanContext,
199         Exception cause) 
200         throws ServletException, FlowException
201 	{
202         internalDoInterceptPerformException(cctx, formBeanContext, cause, true);
203 	}
204     
205     public void internalDoInterceptPerformException(
206         ControllerContext cctx,
207         FormBeanContext formBeanContext,
208         Exception cause,
209         boolean handleFlowExceptions) 
210         throws ServletException, FlowException
211     {
212         Interceptor[] commands = interceptorRegistry.getInterceptors(
213             PerformExceptionInterceptor.class);
214             
215         internalDoExecute(commands, 0, cctx, formBeanContext, 
216             handleFlowExceptions, LEVEL_PERFORM_EXCEPTION, cause);  
217     }
218 	
219 	/***
220 	 * Called after the command method is executed.
221 	 * 
222 	 * @param cctx maverick context
223 	 * @param formBeanContext context with populated (if succesful) formBean
224 	 * @throws ServletException
225 	 */
226 	public void doInterceptAfterPerform(
227 		ControllerContext cctx,
228 		FormBeanContext formBeanContext) 
229         throws ServletException, FlowException
230 	{
231         internalDoInterceptAfterPerform(cctx, formBeanContext, true);
232 	}
233     
234     public void internalDoInterceptAfterPerform(
235         ControllerContext cctx,
236         FormBeanContext formBeanContext,
237         boolean handleFlowExceptions) 
238         throws ServletException, FlowException
239     {
240         Interceptor[] commands = interceptorRegistry.getInterceptors(
241             AfterPerformInterceptor.class);
242             
243         internalDoExecute(commands, 0, cctx, formBeanContext, 
244             handleFlowExceptions, LEVEL_AFTER_PERFORM, null);  
245     }
246 
247     private void internalDoExecute(
248         Interceptor[] commands,
249         int fromPos,
250         ControllerContext cctx,
251         FormBeanContext formBeanContext,
252         boolean handleFlowExceptions,
253         int level,
254         Exception exception)
255         throws ServletException, FlowException
256     {
257         if(commands == null) return;
258         
259         int nbrcmds = commands.length;
260         if(fromPos >= nbrcmds) return;
261 
262         for(int i = fromPos; i < nbrcmds; i++)
263         {
264             if(intercLog.isDebugEnabled())
265             {
266                 intercLog.debug("calling interceptor " + commands[i]);
267             }
268             try
269             {
270                 switch(level) // just a bit more efficient than instanceof, and we need level anyway
271                 {
272                     case LEVEL_BEFORE_MAKE_FORMBEAN: 
273                     ((BeforeMakeFormBeanInterceptor)commands[i])
274                             .doBeforeMakeFormBean(cctx, formBeanContext);
275                         break;
276                     case LEVEL_BEFORE_POPULATION: 
277                         ((BeforePopulationInterceptor)commands[i])
278                             .doBeforePopulation(cctx, formBeanContext);
279                         break;
280                     case LEVEL_POPULATION_ERROR: 
281                         ((PopulationErrorInterceptor)commands[i])
282                             .doOnPopulationError(cctx, formBeanContext, exception);
283                         break;
284                     case LEVEL_AFTER_POPULATION: 
285                         ((AfterPopulationInterceptor)commands[i])
286                             .doAfterPopulation(cctx, formBeanContext);
287                         break;
288                     case LEVEL_PERFORM_EXCEPTION: 
289                         ((PerformExceptionInterceptor)commands[i])
290                             .doOnPerformException(cctx, formBeanContext, exception);
291                         break;
292                     case LEVEL_AFTER_PERFORM: 
293                         ((AfterPerformInterceptor)commands[i])
294                             .doAfterPerform(cctx, formBeanContext);
295                         break;
296                     
297                     default: throw new ServletException("invalid interception level " + level);
298                 }
299                 
300             }
301             catch (FlowException e)
302             {
303                 if(intercLog.isDebugEnabled())
304                 {
305                     intercLog.debug(e + " was thrown by interceptor " + commands[i]); 
306                 }
307                 if(handleFlowExceptions) 
308                 {
309                     handleFlowException(
310                         cctx, formBeanContext, e, level, commands, i); 
311                 }
312                 throw e;
313             }
314         }       
315     }
316     
317     /*
318      * Do handling of flow exceptions
319      */
320 	private void handleFlowException(
321         ControllerContext cctx,
322         FormBeanContext formBeanContext,
323 		FlowException flowException,
324 		int level,        
325         Interceptor[] currentCommandStack, 
326         int currentCommandStackPos)
327         throws ServletException
328 	{
329 		String view = null;
330 		if(flowException != null)
331 		{
332 			if(flowException instanceof ReturnNowFlowException)
333 			{
334                 ReturnNowFlowException e = (ReturnNowFlowException)flowException;
335 				view = e.getView();
336 				if(intercLog.isDebugEnabled())
337 				{
338 				    intercLog.debug("returning view " + view);
339 				}
340 			}
341 			else if(flowException instanceof DispatchNowFlowException)
342 			{
343                 DispatchNowFlowException e = (DispatchNowFlowException)flowException;
344 				// dispatch request
345 				try
346 				{
347 					HttpServletRequest request = cctx.getRequest(); 
348 					String dispatchPath = e.getDispatchPath(); 
349 					if(intercLog.isDebugEnabled())
350 					{
351 					    intercLog.debug("trying dispatch to " + dispatchPath);
352 					}
353 					RequestDispatcher disp = request.getRequestDispatcher(dispatchPath);
354                     if(disp == null)
355                     {
356                         String msg = "dispatcher not found for path " + dispatchPath;
357                         ServletException ex = new ServletException(msg);
358                         intercLog.error(msg, ex);
359                         throw ex;  
360                     }
361 					disp.forward(request, cctx.getResponse());	
362 				}
363 				catch (IOException ex)
364 				{
365                     intercLog.error(ex.getMessage(), ex);
366 					throw new ServletException(e);
367 				}	
368 			}
369 		}
370         
371         possiblyHandleOtherInterceptors(
372             cctx, formBeanContext, flowException, level, currentCommandStack, currentCommandStackPos);
373 	}
374 	
375 	/* if result.isExecuteOtherNonFlowInterceptors, handle some other interceptors */
376 	private void possiblyHandleOtherInterceptors(
377         ControllerContext cctx,
378         FormBeanContext formBeanContext,
379         FlowException flowException,
380         int level,
381         Interceptor[] currentCommandStack, 
382         int currentCommandStackPos)
383         throws ServletException
384 	{
385 		if(flowException.isExecuteOtherInterceptors())
386 		{
387 			if(intercLog.isDebugEnabled())
388 			{
389 			    intercLog.debug("handling other interceptors before handling flowexception...");
390 			}
391             // handle current level
392 			try
393 			{
394 				internalDoExecute(currentCommandStack, (currentCommandStackPos + 1), 
395 				    cctx, formBeanContext, false, level, null);
396 			}
397 			catch (FlowException e)
398 			{
399 				// never occurs
400                 intercLog.error(e.getMessage(), e); // but... just in case
401 			}
402             
403 			if(level == LEVEL_BEFORE_MAKE_FORMBEAN)
404 			{
405 				try
406 				{
407 					internalDoInterceptBeforePopulation(cctx, formBeanContext, false);
408 				}
409 				catch (Exception e)
410 				{
411                     intercLog.error(e.getMessage(), e);
412                     // ignore rest
413 				}
414 			}
415 			if(level != LEVEL_AFTER_PERFORM)
416 			{	
417                 try
418                 {
419                     internalDoInterceptAfterPerform(cctx, formBeanContext, false);
420                 }
421                 catch (Exception e)
422                 {
423                     intercLog.error(e.getMessage(), e);
424                     // ignore rest
425                 }
426 			}
427 		}
428 	}
429 
430 }