001: package org.apache.velocity.app.event;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.util.Iterator;
023:
024: import org.apache.velocity.context.InternalContextAdapter;
025: import org.apache.velocity.runtime.RuntimeServices;
026: import org.apache.velocity.util.ExceptionUtils;
027: import org.apache.velocity.util.introspection.Info;
028:
029: /**
030: * Calls on request all registered event handlers for a particular event. Each
031: * method accepts two event cartridges (typically one from the application and
032: * one from the context). All appropriate event handlers are executed in order
033: * until a stopping condition is met. See the docs for the individual methods to
034: * see what the stopping condition is for that method.
035: *
036: * @author <a href="mailto:wglass@wglass@forio.com">Will Glass-Husain </a>
037: * @version $Id: EventHandlerUtil.java 470256 2006-11-02 07:20:36Z wglass $
038: */
039: public class EventHandlerUtil {
040:
041: /**
042: * Called before a reference is inserted. All event handlers are called in
043: * sequence. The default implementation inserts the reference as is.
044: *
045: * @param reference reference from template about to be inserted
046: * @param value value about to be inserted (after toString() )
047: * @param rsvc current instance of RuntimeServices
048: * @param context The internal context adapter.
049: * @return Object on which toString() should be called for output.
050: */
051: public static Object referenceInsert(RuntimeServices rsvc,
052: InternalContextAdapter context, String reference,
053: Object value) {
054: // app level cartridges have already been initialized
055: EventCartridge ev1 = rsvc.getApplicationEventCartridge();
056: Iterator applicationEventHandlerIterator = (ev1 == null) ? null
057: : ev1.getReferenceInsertionEventHandlers();
058:
059: EventCartridge ev2 = context.getEventCartridge();
060: initializeEventCartridge(rsvc, ev2);
061: Iterator contextEventHandlerIterator = (ev2 == null) ? null
062: : ev2.getReferenceInsertionEventHandlers();
063:
064: try {
065: EventHandlerMethodExecutor methodExecutor = new ReferenceInsertionEventHandler.referenceInsertExecutor(
066: context, reference, value);
067:
068: callEventHandlers(applicationEventHandlerIterator,
069: contextEventHandlerIterator, methodExecutor);
070:
071: return methodExecutor.getReturnValue();
072: } catch (RuntimeException e) {
073: throw e;
074: } catch (Exception e) {
075: throw ExceptionUtils.createRuntimeException(
076: "Exception in event handler.", e);
077: }
078: }
079:
080: /**
081: * Called when a null is evaluated during a #set. All event handlers are
082: * called in sequence until a false is returned. The default implementation
083: * always returns true.
084: *
085: * @param lhs Left hand side of the expression.
086: * @param rhs Right hand side of the expression.
087: * @param rsvc current instance of RuntimeServices
088: * @param context The internal context adapter.
089: * @return true if to be logged, false otherwise
090: */
091: public static boolean shouldLogOnNullSet(RuntimeServices rsvc,
092: InternalContextAdapter context, String lhs, String rhs) {
093: // app level cartridges have already been initialized
094: EventCartridge ev1 = rsvc.getApplicationEventCartridge();
095: Iterator applicationEventHandlerIterator = (ev1 == null) ? null
096: : ev1.getNullSetEventHandlers();
097:
098: EventCartridge ev2 = context.getEventCartridge();
099: initializeEventCartridge(rsvc, ev2);
100: Iterator contextEventHandlerIterator = (ev2 == null) ? null
101: : ev2.getNullSetEventHandlers();
102:
103: try {
104: EventHandlerMethodExecutor methodExecutor = new NullSetEventHandler.ShouldLogOnNullSetExecutor(
105: context, lhs, rhs);
106:
107: callEventHandlers(applicationEventHandlerIterator,
108: contextEventHandlerIterator, methodExecutor);
109:
110: return ((Boolean) methodExecutor.getReturnValue())
111: .booleanValue();
112: } catch (RuntimeException e) {
113: throw e;
114: } catch (Exception e) {
115: throw ExceptionUtils.createRuntimeException(
116: "Exception in event handler.", e);
117: }
118: }
119:
120: /**
121: * Called when a method exception is generated during Velocity merge. Only
122: * the first valid event handler in the sequence is called. The default
123: * implementation simply rethrows the exception.
124: *
125: * @param claz
126: * Class that is causing the exception
127: * @param method
128: * method called that causes the exception
129: * @param e
130: * Exception thrown by the method
131: * @param rsvc current instance of RuntimeServices
132: * @param context The internal context adapter.
133: * @return Object to return as method result
134: * @throws Exception
135: * to be wrapped and propogated to app
136: */
137: public static Object methodException(RuntimeServices rsvc,
138: InternalContextAdapter context, Class claz, String method,
139: Exception e) throws Exception {
140: // app level cartridges have already been initialized
141: EventCartridge ev1 = rsvc.getApplicationEventCartridge();
142: Iterator applicationEventHandlerIterator = (ev1 == null) ? null
143: : ev1.getMethodExceptionEventHandlers();
144:
145: EventCartridge ev2 = context.getEventCartridge();
146: initializeEventCartridge(rsvc, ev2);
147: Iterator contextEventHandlerIterator = (ev2 == null) ? null
148: : ev2.getMethodExceptionEventHandlers();
149:
150: EventHandlerMethodExecutor methodExecutor = new MethodExceptionEventHandler.MethodExceptionExecutor(
151: context, claz, method, e);
152:
153: if (((applicationEventHandlerIterator == null) || !applicationEventHandlerIterator
154: .hasNext())
155: && ((contextEventHandlerIterator == null) || !contextEventHandlerIterator
156: .hasNext())) {
157: throw e;
158: }
159:
160: callEventHandlers(applicationEventHandlerIterator,
161: contextEventHandlerIterator, methodExecutor);
162:
163: return methodExecutor.getReturnValue();
164: }
165:
166: /**
167: * Called when an include-type directive is encountered (#include or
168: * #parse). All the registered event handlers are called unless null is
169: * returned. The default implementation always processes the included
170: * resource.
171: *
172: * @param includeResourcePath
173: * the path as given in the include directive.
174: * @param currentResourcePath
175: * the path of the currently rendering template that includes the
176: * include directive.
177: * @param directiveName
178: * name of the directive used to include the resource. (With the
179: * standard directives this is either "parse" or "include").
180: * @param rsvc current instance of RuntimeServices
181: * @param context The internal context adapter.
182: *
183: * @return a new resource path for the directive, or null to block the
184: * include from occurring.
185: */
186: public static String includeEvent(RuntimeServices rsvc,
187: InternalContextAdapter context, String includeResourcePath,
188: String currentResourcePath, String directiveName) {
189: // app level cartridges have already been initialized
190: EventCartridge ev1 = rsvc.getApplicationEventCartridge();
191: Iterator applicationEventHandlerIterator = (ev1 == null) ? null
192: : ev1.getIncludeEventHandlers();
193:
194: EventCartridge ev2 = context.getEventCartridge();
195: initializeEventCartridge(rsvc, ev2);
196: Iterator contextEventHandlerIterator = (ev2 == null) ? null
197: : ev2.getIncludeEventHandlers();
198:
199: try {
200: EventHandlerMethodExecutor methodExecutor = new IncludeEventHandler.IncludeEventExecutor(
201: context, includeResourcePath, currentResourcePath,
202: directiveName);
203:
204: callEventHandlers(applicationEventHandlerIterator,
205: contextEventHandlerIterator, methodExecutor);
206:
207: return (String) methodExecutor.getReturnValue();
208: } catch (RuntimeException e) {
209: throw e;
210: } catch (Exception e) {
211: throw ExceptionUtils.createRuntimeException(
212: "Exception in event handler.", e);
213: }
214: }
215:
216: /**
217: * Called when an invalid get method is encountered.
218: *
219: * @param rsvc current instance of RuntimeServices
220: * @param context the context when the reference was found invalid
221: * @param reference complete invalid reference
222: * @param object object from reference, or null if not available
223: * @param property name of property, or null if not relevant
224: * @param info contains info on template, line, col
225: * @return substitute return value for missing reference, or null if no substitute
226: */
227: public static Object invalidGetMethod(RuntimeServices rsvc,
228: InternalContextAdapter context, String reference,
229: Object object, String property, Info info) {
230: return invalidReferenceHandlerCall(
231: new InvalidReferenceEventHandler.InvalidGetMethodExecutor(
232: context, reference, object, property, info),
233: rsvc, context);
234: }
235:
236: /**
237: * Called when an invalid set method is encountered.
238: *
239: * @param rsvc current instance of RuntimeServices
240: * @param context the context when the reference was found invalid
241: * @param leftreference left reference being assigned to
242: * @param rightreference invalid reference on the right
243: * @param info contains info on template, line, col
244: */
245: public static void invalidSetMethod(RuntimeServices rsvc,
246: InternalContextAdapter context, String leftreference,
247: String rightreference, Info info) {
248: /**
249: * ignore return value
250: */
251: invalidReferenceHandlerCall(
252: new InvalidReferenceEventHandler.InvalidSetMethodExecutor(
253: context, leftreference, rightreference, info),
254: rsvc, context);
255: }
256:
257: /**
258: * Called when an invalid method is encountered.
259: *
260: * @param rsvc current instance of RuntimeServices
261: * @param context the context when the reference was found invalid
262: * @param reference complete invalid reference
263: * @param object object from reference, or null if not available
264: * @param method name of method, or null if not relevant
265: * @param info contains info on template, line, col
266: * @return substitute return value for missing reference, or null if no substitute
267: */
268: public static Object invalidMethod(RuntimeServices rsvc,
269: InternalContextAdapter context, String reference,
270: Object object, String method, Info info) {
271: return invalidReferenceHandlerCall(
272: new InvalidReferenceEventHandler.InvalidMethodExecutor(
273: context, reference, object, method, info),
274: rsvc, context);
275: }
276:
277: /**
278: * Calls event handler method with appropriate chaining across event handlers.
279: *
280: * @param methodExecutor
281: * @param rsvc current instance of RuntimeServices
282: * @param context The current context
283: * @return return value from method, or null if no return value
284: */
285: public static Object invalidReferenceHandlerCall(
286: EventHandlerMethodExecutor methodExecutor,
287: RuntimeServices rsvc, InternalContextAdapter context) {
288: // app level cartridges have already been initialized
289: EventCartridge ev1 = rsvc.getApplicationEventCartridge();
290: Iterator applicationEventHandlerIterator = (ev1 == null) ? null
291: : ev1.getInvalidReferenceEventHandlers();
292:
293: EventCartridge ev2 = context.getEventCartridge();
294: initializeEventCartridge(rsvc, ev2);
295: Iterator contextEventHandlerIterator = (ev2 == null) ? null
296: : ev2.getInvalidReferenceEventHandlers();
297:
298: try {
299: callEventHandlers(applicationEventHandlerIterator,
300: contextEventHandlerIterator, methodExecutor);
301:
302: return methodExecutor.getReturnValue();
303: } catch (RuntimeException e) {
304: throw e;
305: } catch (Exception e) {
306: throw ExceptionUtils.createRuntimeException(
307: "Exception in event handler.", e);
308: }
309:
310: }
311:
312: /**
313: * Initialize the event cartridge if appropriate.
314: *
315: * @param rsvc current instance of RuntimeServices
316: * @param eventCartridge the event cartridge to be initialized
317: */
318: private static void initializeEventCartridge(RuntimeServices rsvc,
319: EventCartridge eventCartridge) {
320: if (eventCartridge != null) {
321: try {
322: eventCartridge.initialize(rsvc);
323: } catch (Exception e) {
324: throw ExceptionUtils.createRuntimeException(
325: "Couldn't initialize event cartridge : ", e);
326: }
327: }
328: }
329:
330: /**
331: * Loop through both the application level and context-attached event handlers.
332: *
333: * @param applicationEventHandlerIterator Iterator that loops through all global event handlers declared at application level
334: * @param contextEventHandlerIterator Iterator that loops through all global event handlers attached to context
335: * @param eventExecutor Strategy object that executes event handler method
336: * @exception Exception generic exception potentially thrown by event handlers
337: */
338: private static void callEventHandlers(
339: Iterator applicationEventHandlerIterator,
340: Iterator contextEventHandlerIterator,
341: EventHandlerMethodExecutor eventExecutor) throws Exception {
342: /**
343: * First loop through the event handlers configured at the app level
344: * in the properties file.
345: */
346: iterateOverEventHandlers(applicationEventHandlerIterator,
347: eventExecutor);
348:
349: /**
350: * Then loop through the event handlers attached to the context.
351: */
352: iterateOverEventHandlers(contextEventHandlerIterator,
353: eventExecutor);
354: }
355:
356: /**
357: * Loop through a given iterator of event handlers.
358: *
359: * @param handlerIterator Iterator that loops through event handlers
360: * @param eventExecutor Strategy object that executes event handler method
361: * @exception Exception generic exception potentially thrown by event handlers
362: */
363: private static void iterateOverEventHandlers(
364: Iterator handlerIterator,
365: EventHandlerMethodExecutor eventExecutor) throws Exception {
366: if (handlerIterator != null) {
367: for (Iterator i = handlerIterator; i.hasNext();) {
368: EventHandler eventHandler = (EventHandler) i.next();
369:
370: if (!eventExecutor.isDone()) {
371: eventExecutor.execute(eventHandler);
372: }
373: }
374: }
375: }
376:
377: }
|