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.util.Collection;
23 import java.util.List;
24 import java.util.Map;
25
26 import javax.el.MethodExpression;
27 import javax.faces.application.ResourceHandler;
28 import javax.faces.component.PartialStateHolder;
29 import javax.faces.component.UIComponent;
30 import javax.faces.component.UniqueIdVendor;
31 import javax.faces.component.behavior.AjaxBehavior;
32 import javax.faces.component.behavior.ClientBehavior;
33 import javax.faces.component.behavior.ClientBehaviorHolder;
34 import javax.faces.context.FacesContext;
35 import javax.faces.event.AbortProcessingException;
36 import javax.faces.event.AjaxBehaviorEvent;
37 import javax.faces.event.AjaxBehaviorListener;
38 import javax.faces.view.BehaviorHolderAttachedObjectHandler;
39 import javax.faces.view.facelets.ComponentHandler;
40 import javax.faces.view.facelets.FaceletContext;
41 import javax.faces.view.facelets.FaceletHandler;
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.TagException;
46 import javax.faces.view.facelets.TagHandler;
47
48 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
49 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
50 import org.apache.myfaces.shared.renderkit.JSFAttr;
51 import org.apache.myfaces.view.facelets.AbstractFaceletContext;
52 import org.apache.myfaces.view.facelets.FaceletCompositionContext;
53 import org.apache.myfaces.view.facelets.tag.TagHandlerUtils;
54 import org.apache.myfaces.view.facelets.tag.composite.InsertChildrenHandler;
55 import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
56 import org.apache.myfaces.view.facelets.tag.ui.DecorateHandler;
57 import org.apache.myfaces.view.facelets.tag.ui.IncludeHandler;
58 import org.apache.myfaces.view.facelets.tag.ui.InsertHandler;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 @JSFFaceletTag(name = "f:ajax")
86 public class AjaxHandler extends TagHandler implements
87 BehaviorHolderAttachedObjectHandler
88 {
89
90 public final static Class<?>[] AJAX_BEHAVIOR_LISTENER_SIG = new Class<?>[] { AjaxBehaviorEvent.class };
91
92
93
94
95
96
97 public final static String STANDARD_JSF_AJAX_LIBRARY_LOADED
98 = "org.apache.myfaces.STANDARD_JSF_AJAX_LIBRARY_LOADED";
99
100
101
102
103 @JSFFaceletAttribute(name = "disabled", className = "javax.el.ValueExpression",
104 deferredValueType = "java.lang.Boolean")
105 private final TagAttribute _disabled;
106
107
108
109
110 @JSFFaceletAttribute(name = "event", className = "javax.el.ValueExpression",
111 deferredValueType = "java.lang.String")
112 private final TagAttribute _event;
113
114
115
116
117 @JSFFaceletAttribute(name = "execute", className = "javax.el.ValueExpression",
118 deferredValueType = "java.lang.Object")
119 private final TagAttribute _execute;
120
121
122
123
124 @JSFFaceletAttribute(name = "immediate", className = "javax.el.ValueExpression",
125 deferredValueType = "java.lang.Boolean")
126 private final TagAttribute _immediate;
127
128
129
130
131 @JSFFaceletAttribute(name = "listener", className = "javax.el.MethodExpression",
132 deferredMethodSignature = "public void m(javax.faces.event.AjaxBehaviorEvent evt) "
133 + "throws javax.faces.event.AbortProcessingException")
134 private final TagAttribute _listener;
135
136
137
138
139 @JSFFaceletAttribute(name = "onevent", className = "javax.el.ValueExpression",
140 deferredValueType = "java.lang.String")
141 private final TagAttribute _onevent;
142
143
144
145
146 @JSFFaceletAttribute(name = "onerror", className = "javax.el.ValueExpression",
147 deferredValueType = "java.lang.String")
148 private final TagAttribute _onerror;
149
150
151
152
153 @JSFFaceletAttribute(name = "render", className = "javax.el.ValueExpression",
154 deferredValueType = "java.lang.Object")
155 private final TagAttribute _render;
156
157
158
159 @JSFFaceletAttribute(name = "delay", className = "javax.el.ValueExpression",
160 deferredValueType = "java.lang.String")
161 private final TagAttribute _delay;
162
163 @JSFFaceletAttribute(name = "resetValues", className = "javax.el.ValueExpression",
164 deferredValueType = "java.lang.Boolean")
165 private final TagAttribute _resetValues;
166
167 private final boolean _wrapMode;
168
169 public AjaxHandler(TagConfig config)
170 {
171 super(config);
172 _disabled = getAttribute("disabled");
173 _event = getAttribute("event");
174 _execute = getAttribute("execute");
175 _immediate = getAttribute("immediate");
176 _listener = getAttribute("listener");
177 _onerror = getAttribute("onerror");
178 _onevent = getAttribute("onevent");
179 _render = getAttribute("render");
180 _delay = getAttribute("delay");
181 _resetValues = getAttribute("resetValues");
182
183
184
185
186
187
188
189
190
191
192
193
194
195 Collection<FaceletHandler> compHandlerList =
196 TagHandlerUtils.findNextByType(nextHandler, ComponentHandler.class,
197 InsertChildrenHandler.class, InsertHandler.class, DecorateHandler.class, IncludeHandler.class);
198
199 _wrapMode = !compHandlerList.isEmpty();
200 }
201
202 public void apply(FaceletContext ctx, UIComponent parent)
203 throws IOException
204 {
205
206 if (!ComponentHandler.isNew(parent))
207 {
208 if (_wrapMode)
209 {
210 AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
211
212
213
214 actx.pushAjaxHandlerToStack(this);
215 nextHandler.apply(ctx, parent);
216 actx.popAjaxHandlerToStack();
217 }
218 return;
219 }
220 if (_wrapMode)
221 {
222 AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
223
224
225
226
227
228
229 actx.pushAjaxHandlerToStack(this);
230 nextHandler.apply(ctx, parent);
231 actx.popAjaxHandlerToStack();
232 }
233 else
234 {
235 if (parent instanceof ClientBehaviorHolder)
236 {
237
238 applyAttachedObject(ctx.getFacesContext(), parent);
239 }
240 else if (UIComponent.isCompositeComponent(parent))
241 {
242 FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
243
244
245
246
247
248
249
250
251 mctx.addAttachedObjectHandler(
252 parent, this);
253 }
254 else
255 {
256 throw new TagException(this.tag,
257 "Parent is not composite component or of type ClientBehaviorHolder, type is: "
258 + parent);
259 }
260 }
261
262 registerJsfAjaxDefaultResource(ctx, parent);
263 }
264
265 public static void registerJsfAjaxDefaultResource(FaceletContext ctx, UIComponent parent)
266 {
267
268
269
270
271
272
273
274
275
276 FacesContext facesContext = ctx.getFacesContext();
277 if (!facesContext.getAttributes().containsKey(STANDARD_JSF_AJAX_LIBRARY_LOADED))
278 {
279 UIComponent outputScript = facesContext.getApplication().
280 createComponent(facesContext, "javax.faces.Output", "javax.faces.resource.Script");
281 outputScript.getAttributes().put(JSFAttr.NAME_ATTR, ResourceHandler.JSF_SCRIPT_RESOURCE_NAME);
282 outputScript.getAttributes().put(JSFAttr.LIBRARY_ATTR, ResourceHandler.JSF_SCRIPT_LIBRARY_NAME);
283 outputScript.getAttributes().put(JSFAttr.TARGET_ATTR, "head");
284
285
286
287
288
289
290 UniqueIdVendor uniqueIdVendor = ComponentSupport.getViewRoot(ctx, parent);
291
292
293 String uid = uniqueIdVendor.createUniqueId(ctx.getFacesContext(),null);
294 outputScript.setId(uid);
295
296 parent.getChildren().add(outputScript);
297
298 if (FaceletCompositionContext.getCurrentInstance(ctx).isMarkInitialState())
299 {
300
301 outputScript.markInitialState();
302 }
303 facesContext.getAttributes().put(STANDARD_JSF_AJAX_LIBRARY_LOADED, Boolean.TRUE);
304 }
305 }
306
307
308
309
310
311 public String getEventName()
312 {
313 if (_event == null)
314 {
315 return null;
316 }
317 else
318 {
319 if (_event.isLiteral())
320 {
321 return _event.getValue();
322 }
323 else
324 {
325 FaceletContext faceletContext = (FaceletContext) FacesContext.getCurrentInstance().
326 getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
327 return (String) _event.getValueExpression(faceletContext, String.class).getValue(faceletContext);
328 }
329 }
330 }
331
332
333
334
335
336
337
338
339
340 public void applyAttachedObject(FacesContext context, UIComponent parent)
341 {
342
343 FaceletContext faceletContext = (FaceletContext) context
344 .getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
345
346
347 ClientBehaviorHolder cvh = (ClientBehaviorHolder) parent;
348
349
350 String eventName = null;
351 if (_event != null)
352 {
353 if (_event.isLiteral())
354 {
355 eventName = _event.getValue();
356 }
357 else
358 {
359 eventName = (String) _event.getValueExpression(faceletContext, String.class).getValue(faceletContext);
360 }
361 }
362 if (eventName == null)
363 {
364 eventName = cvh.getDefaultEventName();
365 if (eventName == null)
366 {
367 if (_wrapMode)
368 {
369
370
371
372
373 return;
374 }
375 else
376 {
377 throw new TagAttributeException(_event,
378 "eventName could not be defined for f:ajax tag with no wrap mode.");
379 }
380 }
381 }
382 else if (!cvh.getEventNames().contains(eventName))
383 {
384 if (_wrapMode)
385 {
386
387
388
389
390 return;
391 }
392 else
393 {
394 throw new TagAttributeException(_event,
395 "event it is not a valid eventName defined for this component");
396 }
397 }
398
399 Map<String, List<ClientBehavior>> clientBehaviors = cvh.getClientBehaviors();
400
401 List<ClientBehavior> clientBehaviorList = clientBehaviors.get(eventName);
402 if (clientBehaviorList != null && !clientBehaviorList.isEmpty())
403 {
404 for (ClientBehavior cb : clientBehaviorList)
405 {
406 if (cb instanceof AjaxBehavior)
407 {
408
409
410
411
412 return;
413 }
414 }
415 }
416
417 AjaxBehavior ajaxBehavior = createBehavior(context);
418
419 if (_disabled != null)
420 {
421 if (_disabled.isLiteral())
422 {
423 ajaxBehavior.setDisabled(_disabled.getBoolean(faceletContext));
424 }
425 else
426 {
427 ajaxBehavior.setValueExpression("disabled", _disabled
428 .getValueExpression(faceletContext, Boolean.class));
429 }
430 }
431 if (_execute != null)
432 {
433 ajaxBehavior.setValueExpression("execute", _execute
434 .getValueExpression(faceletContext, Object.class));
435 }
436 if (_immediate != null)
437 {
438 if (_immediate.isLiteral())
439 {
440 ajaxBehavior
441 .setImmediate(_immediate.getBoolean(faceletContext));
442 }
443 else
444 {
445 ajaxBehavior.setValueExpression("immediate", _immediate
446 .getValueExpression(faceletContext, Boolean.class));
447 }
448 }
449 if (_listener != null)
450 {
451 MethodExpression expr = _listener.getMethodExpression(
452 faceletContext, Void.TYPE, AJAX_BEHAVIOR_LISTENER_SIG);
453 AjaxBehaviorListener abl = new AjaxBehaviorListenerImpl(expr);
454 ajaxBehavior.addAjaxBehaviorListener(abl);
455 }
456 if (_onerror != null)
457 {
458 if (_onerror.isLiteral())
459 {
460 ajaxBehavior.setOnerror(_onerror.getValue(faceletContext));
461 }
462 else
463 {
464 ajaxBehavior.setValueExpression("onerror", _onerror
465 .getValueExpression(faceletContext, String.class));
466 }
467 }
468 if (_onevent != null)
469 {
470 if (_onevent.isLiteral())
471 {
472 ajaxBehavior.setOnevent(_onevent.getValue(faceletContext));
473 }
474 else
475 {
476 ajaxBehavior.setValueExpression("onevent", _onevent
477 .getValueExpression(faceletContext, String.class));
478 }
479 }
480 if (_render != null)
481 {
482 ajaxBehavior.setValueExpression("render", _render
483 .getValueExpression(faceletContext, Object.class));
484 }
485 if (_delay != null)
486 {
487 if (_delay.isLiteral())
488 {
489 ajaxBehavior.setDelay(_delay.getValue(faceletContext));
490 }
491 else
492 {
493 ajaxBehavior.setValueExpression("delay", _delay
494 .getValueExpression(faceletContext, String.class));
495 }
496 }
497 if (_resetValues != null)
498 {
499 if (_resetValues.isLiteral())
500 {
501 ajaxBehavior
502 .setResetValues(_resetValues.getBoolean(faceletContext));
503 }
504 else
505 {
506 ajaxBehavior.setValueExpression("resetValues", _resetValues
507 .getValueExpression(faceletContext, Boolean.class));
508 }
509 }
510 cvh.addClientBehavior(eventName, ajaxBehavior);
511 }
512
513 protected AjaxBehavior createBehavior(FacesContext context)
514 {
515 return (AjaxBehavior) context.getApplication().createBehavior(AjaxBehavior.BEHAVIOR_ID);
516 }
517
518
519
520
521
522
523 public String getFor()
524 {
525 return null;
526 }
527
528
529
530
531 public final static class AjaxBehaviorListenerImpl implements
532 AjaxBehaviorListener, PartialStateHolder
533 {
534 private MethodExpression _expr;
535 private boolean _transient;
536 private boolean _initialStateMarked;
537
538 public AjaxBehaviorListenerImpl ()
539 {
540 }
541
542 public AjaxBehaviorListenerImpl(MethodExpression expr)
543 {
544 _expr = expr;
545 }
546
547 public void processAjaxBehavior(AjaxBehaviorEvent event)
548 throws AbortProcessingException
549 {
550 _expr.invoke(FacesContext.getCurrentInstance().getELContext(),
551 new Object[] { event });
552 }
553
554 public boolean isTransient()
555 {
556 return _transient;
557 }
558
559 public void restoreState(FacesContext context, Object state)
560 {
561 if (state == null)
562 {
563 return;
564 }
565 _expr = (MethodExpression) state;
566 }
567
568 public Object saveState(FacesContext context)
569 {
570 if (initialStateMarked())
571 {
572 return null;
573 }
574 return _expr;
575 }
576
577 public void setTransient(boolean newTransientValue)
578 {
579 _transient = newTransientValue;
580 }
581
582 public void clearInitialState()
583 {
584 _initialStateMarked = false;
585 }
586
587 public boolean initialStateMarked()
588 {
589 return _initialStateMarked;
590 }
591
592 public void markInitialState()
593 {
594 _initialStateMarked = true;
595 }
596 }
597 }