1 package org.apache.velocity.app.event;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.util.ArrayList;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Set;
27
28 import org.apache.velocity.context.Context;
29 import org.apache.velocity.context.InternalEventContext;
30 import org.apache.velocity.runtime.RuntimeServices;
31 import org.apache.velocity.util.RuntimeServicesAware;
32
33 /**
34 * Stores the event handlers. Event handlers can be assigned on a per
35 * VelocityEngine instance basis by specifying the class names in the
36 * velocity.properties file. Event handlers may also be assigned on a per-page
37 * basis by creating a new instance of EventCartridge, adding the event
38 * handlers, and then calling attachToContext. For clarity, it's recommended
39 * that one approach or the other be followed, as the second method is primarily
40 * presented for backwards compatibility.
41 *
42 * <P>
43 * Note that Event Handlers follow a filter pattern, with multiple event
44 * handlers allowed for each event. When the appropriate event occurs, all the
45 * appropriate event handlers are called in the sequence they were added to the
46 * Event Cartridge. See the javadocs of the specific event handler interfaces
47 * for more details.
48 *
49 * @author <a href="mailto:wglass@wglass@forio.com">Will Glass-Husain </a>
50 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr. </a>
51 * @author <a href="mailto:j_a_fernandez@yahoo.com">Jose Alberto Fernandez </a>
52 * @version $Id: EventCartridge.java 470256 2006-11-02 07:20:36Z wglass $
53 */
54 public class EventCartridge
55 {
56 private List referenceHandlers = new ArrayList();
57 private List nullSetHandlers = new ArrayList();
58 private List methodExceptionHandlers = new ArrayList();
59 private List includeHandlers = new ArrayList();
60 private List invalidReferenceHandlers = new ArrayList();
61
62 /**
63 * Ensure that handlers are not initialized more than once.
64 */
65 Set initializedHandlers = new HashSet();
66
67 /**
68 * Adds an event handler(s) to the Cartridge. This method
69 * will find all possible event handler interfaces supported
70 * by the passed in object.
71 *
72 * @param ev object impementing a valid EventHandler-derived interface
73 * @return true if a supported interface, false otherwise or if null
74 */
75 public boolean addEventHandler( EventHandler ev )
76 {
77 if (ev == null)
78 {
79 return false;
80 }
81
82 boolean found = false;
83
84 if ( ev instanceof ReferenceInsertionEventHandler)
85 {
86 addReferenceInsertionEventHandler( (ReferenceInsertionEventHandler) ev );
87 found = true;
88 }
89
90 if ( ev instanceof NullSetEventHandler )
91 {
92 addNullSetEventHandler( (NullSetEventHandler) ev );
93 found = true;
94 }
95
96 if ( ev instanceof MethodExceptionEventHandler )
97 {
98 addMethodExceptionHandler( (MethodExceptionEventHandler) ev );
99 found = true;
100 }
101
102 if ( ev instanceof IncludeEventHandler )
103 {
104 addIncludeEventHandler( (IncludeEventHandler) ev );
105 found = true;
106 }
107
108 if ( ev instanceof InvalidReferenceEventHandler )
109 {
110 addInvalidReferenceEventHandler( (InvalidReferenceEventHandler) ev );
111 found = true;
112 }
113
114 return found;
115 }
116
117 /**
118 * Add a reference insertion event handler to the Cartridge.
119 *
120 * @param ev ReferenceInsertionEventHandler
121 */
122 public void addReferenceInsertionEventHandler( ReferenceInsertionEventHandler ev )
123 {
124 referenceHandlers.add( ev );
125 }
126
127 /**
128 * Add a null set event handler to the Cartridge.
129 *
130 * @param ev NullSetEventHandler
131 */
132 public void addNullSetEventHandler( NullSetEventHandler ev )
133 {
134 nullSetHandlers.add( ev );
135 }
136
137 /**
138 * Add a method exception event handler to the Cartridge.
139 *
140 * @param ev MethodExceptionEventHandler
141 */
142 public void addMethodExceptionHandler( MethodExceptionEventHandler ev )
143 {
144 methodExceptionHandlers.add( ev );
145 }
146
147 /**
148 * Add an include event handler to the Cartridge.
149 *
150 * @param ev IncludeEventHandler
151 */
152 public void addIncludeEventHandler( IncludeEventHandler ev )
153 {
154 includeHandlers.add( ev );
155 }
156
157 /**
158 * Add an invalid reference event handler to the Cartridge.
159 *
160 * @param ev InvalidReferenceEventHandler
161 */
162 public void addInvalidReferenceEventHandler( InvalidReferenceEventHandler ev )
163 {
164 invalidReferenceHandlers.add( ev );
165 }
166
167
168 /**
169 * Removes an event handler(s) from the Cartridge. This method will find all
170 * possible event handler interfaces supported by the passed in object and
171 * remove them.
172 *
173 * @param ev object impementing a valid EventHandler-derived interface
174 * @return true if event handler was previously registered, false if not
175 * found
176 */
177 public boolean removeEventHandler( EventHandler ev )
178 {
179 if ( ev == null )
180 {
181 return false;
182 }
183
184 boolean found = false;
185
186 if ( ev instanceof ReferenceInsertionEventHandler )
187 return referenceHandlers.remove( ev );
188
189 if ( ev instanceof NullSetEventHandler )
190 return nullSetHandlers.remove( ev );
191
192 if ( ev instanceof MethodExceptionEventHandler )
193 return methodExceptionHandlers.remove(ev );
194
195 if ( ev instanceof IncludeEventHandler )
196 return includeHandlers.remove( ev );
197
198 if ( ev instanceof InvalidReferenceEventHandler )
199 return invalidReferenceHandlers.remove( ev );
200
201 return found;
202 }
203
204 /**
205 * Iterate through all the stored ReferenceInsertionEventHandler objects
206 *
207 * @return iterator of handler objects
208 */
209 public Iterator getReferenceInsertionEventHandlers()
210 {
211 return referenceHandlers.iterator();
212 }
213
214 /**
215 * Iterate through all the stored NullSetEventHandler objects
216 *
217 * @return iterator of handler objects
218 */
219 public Iterator getNullSetEventHandlers()
220 {
221 return nullSetHandlers.iterator();
222 }
223
224 /**
225 * Iterate through all the stored MethodExceptionEventHandler objects
226 *
227 * @return iterator of handler objects
228 */
229 public Iterator getMethodExceptionEventHandlers()
230 {
231 return methodExceptionHandlers.iterator();
232 }
233
234 /**
235 * Iterate through all the stored IncludeEventHandlers objects
236 *
237 * @return iterator of handler objects
238 */
239 public Iterator getIncludeEventHandlers()
240 {
241 return includeHandlers.iterator();
242 }
243
244 /**
245 * Iterate through all the stored InvalidReferenceEventHandlers objects
246 *
247 * @return iterator of handler objects
248 */
249 public Iterator getInvalidReferenceEventHandlers()
250 {
251 return invalidReferenceHandlers.iterator();
252 }
253
254 /**
255 * Attached the EventCartridge to the context
256 *
257 * Final because not something one should mess with lightly :)
258 *
259 * @param context context to attach to
260 * @return true if successful, false otherwise
261 */
262 public final boolean attachToContext( Context context )
263 {
264 if ( context instanceof InternalEventContext )
265 {
266 InternalEventContext iec = (InternalEventContext) context;
267
268 iec.attachEventCartridge( this );
269
270 /**
271 * while it's tempting to call setContext on each handler from here,
272 * this needs to be done before each method call. This is
273 * because the specific context will change as inner contexts
274 * are linked in through macros, foreach, or directly by the user.
275 */
276
277 return true;
278 }
279 else
280 {
281 return false;
282 }
283 }
284
285 /**
286 * Initialize the handlers. For global handlers this is called when Velocity
287 * is initialized. For local handlers this is called when the first handler
288 * is executed. Handlers will not be initialized more than once.
289 *
290 * @param rs
291 * @throws Exception
292 */
293 public void initialize (RuntimeServices rs) throws Exception
294 {
295
296 for ( Iterator i = referenceHandlers.iterator(); i.hasNext(); )
297 {
298 EventHandler eh = ( EventHandler ) i.next();
299 if ( (eh instanceof RuntimeServicesAware) &&
300 !initializedHandlers.contains(eh) )
301 {
302 ((RuntimeServicesAware) eh).setRuntimeServices ( rs );
303 initializedHandlers.add( eh );
304 }
305 }
306
307 for ( Iterator i = nullSetHandlers.iterator(); i.hasNext(); )
308 {
309 EventHandler eh = ( EventHandler ) i.next();
310 if ( (eh instanceof RuntimeServicesAware) &&
311 !initializedHandlers.contains(eh) )
312 {
313 ((RuntimeServicesAware) eh).setRuntimeServices ( rs );
314 initializedHandlers.add( eh );
315 }
316 }
317
318 for ( Iterator i = methodExceptionHandlers.iterator(); i.hasNext(); )
319 {
320 EventHandler eh = ( EventHandler ) i.next();
321 if ( (eh instanceof RuntimeServicesAware) &&
322 !initializedHandlers.contains(eh) )
323 {
324 ((RuntimeServicesAware) eh).setRuntimeServices ( rs );
325 initializedHandlers.add( eh );
326 }
327 }
328
329 for ( Iterator i = includeHandlers.iterator(); i.hasNext(); )
330 {
331 EventHandler eh = ( EventHandler ) i.next();
332 if ( (eh instanceof RuntimeServicesAware) &&
333 !initializedHandlers.contains(eh) )
334 {
335 ((RuntimeServicesAware) eh).setRuntimeServices ( rs );
336 initializedHandlers.add( eh );
337 }
338 }
339
340 for ( Iterator i = invalidReferenceHandlers.iterator(); i.hasNext(); )
341 {
342 EventHandler eh = ( EventHandler ) i.next();
343 if ( (eh instanceof RuntimeServicesAware) &&
344 !initializedHandlers.contains(eh) )
345 {
346 ((RuntimeServicesAware) eh).setRuntimeServices ( rs );
347 initializedHandlers.add( eh );
348 }
349 }
350
351 }
352
353
354 }