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