1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.view.facelets.tag.jsf.core;
20
21 import java.io.IOException;
22 import java.io.Serializable;
23 import java.util.Collection;
24 import java.util.Iterator;
25
26 import javax.el.ELContext;
27 import javax.el.ELException;
28 import javax.el.MethodExpression;
29 import javax.el.MethodNotFoundException;
30 import javax.faces.FacesException;
31 import javax.faces.component.PartialStateHolder;
32 import javax.faces.component.UIComponent;
33 import javax.faces.component.UIViewRoot;
34 import javax.faces.context.FacesContext;
35 import javax.faces.event.ComponentSystemEvent;
36 import javax.faces.event.ComponentSystemEventListener;
37 import javax.faces.event.PostAddToViewEvent;
38 import javax.faces.event.PreRenderViewEvent;
39 import javax.faces.view.facelets.ComponentHandler;
40 import javax.faces.view.facelets.FaceletContext;
41 import javax.faces.view.facelets.FaceletException;
42 import javax.faces.view.facelets.TagAttribute;
43 import javax.faces.view.facelets.TagAttributeException;
44 import javax.faces.view.facelets.TagConfig;
45 import javax.faces.view.facelets.TagHandler;
46
47 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
48 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
49 import org.apache.myfaces.config.RuntimeConfig;
50 import org.apache.myfaces.view.facelets.FaceletCompositionContext;
51 import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;
52 import org.apache.myfaces.view.facelets.el.CompositeComponentELUtils;
53 import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
54 import org.apache.myfaces.view.facelets.util.ReflectionUtil;
55
56
57
58
59 @JSFFaceletTag(
60 name = "f:event",
61 bodyContent = "empty")
62 public final class EventHandler extends TagHandler
63 {
64
65 private static final Class<?>[] COMPONENT_SYSTEM_EVENT_PARAMETER = new Class<?>[] { ComponentSystemEvent.class };
66 private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
67
68 @JSFFaceletAttribute(name="listener",
69 className="javax.el.MethodExpression",
70 deferredMethodSignature=
71 "public void listener(javax.faces.event.ComponentSystemEvent evt) "
72 + "throws javax.faces.event.AbortProcessingException")
73 private TagAttribute listener;
74
75 @JSFFaceletAttribute(name="type",
76 className="javax.el.ValueExpression",
77 deferredValueType="java.lang.String")
78 private TagAttribute type;
79
80 private Class<?> eventClassLiteral;
81
82 private boolean listenerIsCompositeComponentME;
83
84 public EventHandler (TagConfig tagConfig)
85 {
86 super (tagConfig);
87
88 listener = getRequiredAttribute("listener");
89 if (!listener.isLiteral())
90 {
91 listenerIsCompositeComponentME
92 = CompositeComponentELUtils.isCompositeComponentExpression(listener.getValue());
93 }
94 else
95 {
96 listenerIsCompositeComponentME = false;
97 }
98 type = getRequiredAttribute("type");
99 }
100
101 public void apply (FaceletContext ctx, UIComponent parent)
102 throws ELException, FacesException, FaceletException, IOException
103 {
104
105 if (!ComponentHandler.isNew(parent))
106 {
107 return;
108 }
109 if (parent instanceof UIViewRoot)
110 {
111 if (FaceletCompositionContext.getCurrentInstance(ctx).isRefreshingTransientBuild())
112 {
113 return;
114 }
115 else if (!FaceletViewDeclarationLanguage.isBuildingViewMetadata(ctx.getFacesContext()) &&
116 UIViewRoot.METADATA_FACET_NAME.equals((String) parent.getAttributes().get(FacetHandler.KEY)))
117 {
118
119 return;
120 }
121 }
122
123 Class<? extends ComponentSystemEvent> eventClass = getEventClass(ctx);
124
125
126
127 MethodExpression methodExpOneArg
128 = listener.getMethodExpression(ctx, void.class, COMPONENT_SYSTEM_EVENT_PARAMETER);
129 MethodExpression methodExpZeroArg
130 = listener.getMethodExpression(ctx, void.class, EMPTY_CLASS_ARRAY);
131
132 if (eventClass == PreRenderViewEvent.class)
133 {
134
135 UIViewRoot viewRoot = ComponentSupport.getViewRoot(ctx, parent);
136 if (listenerIsCompositeComponentME)
137 {
138
139
140
141 UIComponent parentCompositeComponent
142 = FaceletCompositionContext.getCurrentInstance(ctx).getCompositeComponentFromStack();
143 parentCompositeComponent.subscribeToEvent(PostAddToViewEvent.class,
144 new SubscribeEventListener(eventClass, methodExpOneArg, methodExpZeroArg,
145 (eventClass == PreRenderViewEvent.class) ? null : parent));
146 }
147 else
148 {
149 viewRoot.subscribeToEvent(eventClass, new Listener(methodExpOneArg, methodExpZeroArg));
150 }
151 }
152 else
153 {
154
155 parent.subscribeToEvent(eventClass, new Listener(methodExpOneArg, methodExpZeroArg));
156 }
157 }
158
159
160
161
162
163
164
165
166 @SuppressWarnings("unchecked")
167 private Class<? extends ComponentSystemEvent> getEventClass (FaceletContext context)
168 {
169 Class<?> eventClass = null;
170 String value = null;
171
172 if (type.isLiteral() && eventClassLiteral != null)
173 {
174
175 return (Class<? extends ComponentSystemEvent>) eventClassLiteral;
176 }
177
178 if (type.isLiteral())
179 {
180 value = type.getValue();
181 }
182 else
183 {
184 value = (String) type.getValueExpression (context, String.class).
185 getValue (context.getFacesContext().getELContext());
186 }
187
188 Collection<Class<? extends ComponentSystemEvent>> events;
189
190
191
192 events = RuntimeConfig.getCurrentInstance(
193 context.getFacesContext().getExternalContext()).
194 getNamedEventManager().getNamedEvent(value);
195
196 if (events == null)
197 {
198 try
199 {
200 eventClass = ReflectionUtil.forName (value);
201 if (type.isLiteral())
202 {
203 eventClassLiteral = eventClass;
204 }
205 }
206 catch (Throwable e)
207 {
208 throw new TagAttributeException (type, "Couldn't create event class", e);
209 }
210 }
211 else if (events.size() > 1)
212 {
213 StringBuilder classNames = new StringBuilder ("[");
214 Iterator<Class<? extends ComponentSystemEvent>> eventIterator = events.iterator();
215
216
217
218
219
220
221
222
223
224 while (eventIterator.hasNext())
225 {
226 classNames.append (eventIterator.next().getName());
227
228 if (eventIterator.hasNext())
229 {
230 classNames.append (", ");
231 }
232 else
233 {
234 classNames.append ("]");
235 }
236 }
237
238 throw new FacesException ("The event name '" + value + "' is mapped to more than one " +
239 " event class: " + classNames.toString());
240 }
241 else
242 {
243 eventClass = events.iterator().next();
244 }
245
246 if (!ComponentSystemEvent.class.isAssignableFrom (eventClass))
247 {
248 throw new TagAttributeException (type, "Event class " + eventClass.getName() +
249 " is not of type javax.faces.event.ComponentSystemEvent");
250 }
251
252 return (Class<? extends ComponentSystemEvent>) eventClass;
253 }
254
255 public static class Listener implements ComponentSystemEventListener, Serializable
256 {
257
258 private static final long serialVersionUID = 7318240026355007052L;
259
260 private MethodExpression methodExpOneArg;
261 private MethodExpression methodExpZeroArg;
262
263 public Listener()
264 {
265 super();
266 }
267
268
269
270
271
272
273
274 private Listener(MethodExpression methodExpOneArg, MethodExpression methodExpZeroArg)
275 {
276 this.methodExpOneArg = methodExpOneArg;
277 this.methodExpZeroArg = methodExpZeroArg;
278 }
279
280 public void processEvent(ComponentSystemEvent event)
281 {
282 ELContext elContext = FacesContext.getCurrentInstance().getELContext();
283 try
284 {
285
286 this.methodExpOneArg.invoke(elContext, new Object[] { event });
287 }
288 catch (MethodNotFoundException mnfeOneArg)
289 {
290 try
291 {
292
293 this.methodExpZeroArg.invoke(elContext, new Object[0]);
294 }
295 catch (MethodNotFoundException mnfeZeroArg)
296 {
297
298 throw mnfeOneArg;
299 }
300 }
301 }
302 }
303
304 public static class CompositeComponentRelativeListener implements ComponentSystemEventListener, Serializable
305 {
306
307
308
309 private static final long serialVersionUID = 3822330995358746099L;
310
311 private String _compositeComponentExpression;
312 private MethodExpression methodExpOneArg;
313 private MethodExpression methodExpZeroArg;
314
315 public CompositeComponentRelativeListener()
316 {
317 super();
318 }
319
320 public CompositeComponentRelativeListener(MethodExpression methodExpOneArg,
321 MethodExpression methodExpZeroArg,
322 String compositeComponentExpression)
323 {
324 this.methodExpOneArg = methodExpOneArg;
325 this.methodExpZeroArg = methodExpZeroArg;
326 this._compositeComponentExpression = compositeComponentExpression;
327 }
328
329 public void processEvent(ComponentSystemEvent event)
330 {
331 FacesContext facesContext = FacesContext.getCurrentInstance();
332 UIComponent cc = facesContext.getViewRoot().findComponent(_compositeComponentExpression);
333
334 if (cc != null)
335 {
336 pushAllComponentsIntoStack(facesContext, cc);
337 cc.pushComponentToEL(facesContext, cc);
338 try
339 {
340 ELContext elContext = facesContext.getELContext();
341 try
342 {
343
344 this.methodExpOneArg.invoke(elContext, new Object[] { event });
345 }
346 catch (MethodNotFoundException mnfeOneArg)
347 {
348 try
349 {
350
351 this.methodExpZeroArg.invoke(elContext, new Object[0]);
352 }
353 catch (MethodNotFoundException mnfeZeroArg)
354 {
355
356 throw mnfeOneArg;
357 }
358 }
359 }
360 finally
361 {
362 popAllComponentsIntoStack(facesContext, cc);
363 }
364 }
365 else
366 {
367 throw new NullPointerException("Composite Component associated with expression cannot be found");
368 }
369 }
370
371 private void pushAllComponentsIntoStack(FacesContext facesContext, UIComponent component)
372 {
373 UIComponent parent = component.getParent();
374 if (parent != null)
375 {
376 pushAllComponentsIntoStack(facesContext, parent);
377 }
378 component.pushComponentToEL(facesContext, component);
379 }
380
381 private void popAllComponentsIntoStack(FacesContext facesContext, UIComponent component)
382 {
383 UIComponent parent = component.getParent();
384 component.popComponentFromEL(facesContext);
385 if (parent != null)
386 {
387 popAllComponentsIntoStack(facesContext, parent);
388 }
389 }
390 }
391
392 public static final class SubscribeEventListener implements ComponentSystemEventListener, PartialStateHolder
393 {
394 private MethodExpression methodExpOneArg;
395 private MethodExpression methodExpZeroArg;
396 private Class<? extends ComponentSystemEvent> eventClass;
397 private UIComponent _targetComponent;
398 private String _targetFindComponentExpression;
399
400 private boolean markInitialState;
401
402 public SubscribeEventListener()
403 {
404 }
405
406 public SubscribeEventListener(
407 Class<? extends ComponentSystemEvent> eventClass,
408 MethodExpression methodExpOneArg,
409 MethodExpression methodExpZeroArg,
410 UIComponent targetComponent)
411 {
412
413 this.eventClass = eventClass;
414 this.methodExpOneArg = methodExpOneArg;
415 this.methodExpZeroArg = methodExpZeroArg;
416 this._targetComponent = targetComponent;
417 }
418
419 public void processEvent(ComponentSystemEvent event)
420 {
421 UIComponent parentCompositeComponent = event.getComponent();
422 FacesContext facesContext = FacesContext.getCurrentInstance();
423
424 String findComponentExpression
425 = ComponentSupport.getFindComponentExpression(facesContext, parentCompositeComponent);
426
427
428
429 if (eventClass == PreRenderViewEvent.class)
430 {
431
432 UIViewRoot viewRoot = facesContext.getViewRoot();
433 viewRoot.subscribeToEvent(eventClass, new CompositeComponentRelativeListener(methodExpOneArg,
434 methodExpZeroArg, findComponentExpression));
435 }
436 else
437 {
438 if (_targetComponent == null)
439 {
440 if (_targetFindComponentExpression.startsWith(findComponentExpression) )
441 {
442 _targetComponent = ComponentSupport.findComponentChildOrFacetFrom(
443 facesContext, parentCompositeComponent,
444 _targetFindComponentExpression.substring(findComponentExpression.length()));
445 }
446 else
447 {
448 _targetComponent = facesContext.getViewRoot().findComponent(_targetFindComponentExpression);
449 }
450 }
451
452 _targetComponent.subscribeToEvent(eventClass,
453 new CompositeComponentRelativeListener(methodExpOneArg, methodExpZeroArg,
454 findComponentExpression));
455 }
456 }
457
458 public Object saveState(FacesContext context)
459 {
460 if (!initialStateMarked())
461 {
462 Object[] values = new Object[4];
463 values[0] = (String) ( (_targetComponent != null && _targetFindComponentExpression == null) ?
464 ComponentSupport.getFindComponentExpression(context, _targetComponent) :
465 _targetFindComponentExpression );
466 values[1] = eventClass;
467 values[2] = methodExpZeroArg;
468 values[3] = methodExpOneArg;
469 return values;
470 }
471
472
473 return null;
474 }
475
476 public void restoreState(FacesContext context, Object state)
477 {
478 if (state == null)
479 {
480 return;
481 }
482 Object[] values = (Object[])state;
483 _targetFindComponentExpression = (String) values[0];
484 eventClass = (Class) values[1];
485 methodExpZeroArg = (MethodExpression) values[2];
486 methodExpOneArg = (MethodExpression) values[3];
487 }
488
489 public boolean isTransient()
490 {
491 return false;
492 }
493
494 public void setTransient(boolean newTransientValue)
495 {
496
497 }
498
499 public void clearInitialState()
500 {
501 markInitialState = false;
502 }
503
504 public boolean initialStateMarked()
505 {
506 return markInitialState;
507 }
508
509 public void markInitialState()
510 {
511 markInitialState = true;
512 }
513 }
514 }