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.component.PartialStateHolder;
28 import javax.faces.component.UIComponent;
29 import javax.faces.component.UniqueIdVendor;
30 import javax.faces.component.behavior.AjaxBehavior;
31 import javax.faces.component.behavior.ClientBehavior;
32 import javax.faces.component.behavior.ClientBehaviorHolder;
33 import javax.faces.context.FacesContext;
34 import javax.faces.event.AbortProcessingException;
35 import javax.faces.event.AjaxBehaviorEvent;
36 import javax.faces.event.AjaxBehaviorListener;
37 import javax.faces.view.BehaviorHolderAttachedObjectHandler;
38 import javax.faces.view.facelets.ComponentHandler;
39 import javax.faces.view.facelets.FaceletContext;
40 import javax.faces.view.facelets.FaceletHandler;
41 import javax.faces.view.facelets.TagAttribute;
42 import javax.faces.view.facelets.TagAttributeException;
43 import javax.faces.view.facelets.TagConfig;
44 import javax.faces.view.facelets.TagException;
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.shared.renderkit.JSFAttr;
50 import org.apache.myfaces.shared.renderkit.html.util.ResourceUtils;
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 private final boolean _wrapMode;
158
159 public AjaxHandler(TagConfig config)
160 {
161 super(config);
162 _disabled = getAttribute("disabled");
163 _event = getAttribute("event");
164 _execute = getAttribute("execute");
165 _immediate = getAttribute("immediate");
166 _listener = getAttribute("listener");
167 _onerror = getAttribute("onerror");
168 _onevent = getAttribute("onevent");
169 _render = getAttribute("render");
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184 Collection<FaceletHandler> compHandlerList =
185 TagHandlerUtils.findNextByType(nextHandler, ComponentHandler.class,
186 InsertChildrenHandler.class, InsertHandler.class, DecorateHandler.class, IncludeHandler.class);
187
188 _wrapMode = !compHandlerList.isEmpty();
189 }
190
191 public void apply(FaceletContext ctx, UIComponent parent)
192 throws IOException
193 {
194
195 if (!ComponentHandler.isNew(parent))
196 {
197 if (_wrapMode)
198 {
199 AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
200
201
202
203 actx.pushAjaxHandlerToStack(this);
204 nextHandler.apply(ctx, parent);
205 actx.popAjaxHandlerToStack();
206 }
207 return;
208 }
209 if (_wrapMode)
210 {
211 AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
212
213
214
215
216
217
218
219 actx.pushAjaxHandlerToStack(this);
220 nextHandler.apply(ctx, parent);
221 actx.popAjaxHandlerToStack();
222 }
223 else
224 {
225 if (parent instanceof ClientBehaviorHolder)
226 {
227
228 applyAttachedObject(ctx.getFacesContext(), parent);
229 }
230 else if (UIComponent.isCompositeComponent(parent))
231 {
232 FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
233
234
235
236
237
238
239
240
241 mctx.addAttachedObjectHandler(
242 parent, this);
243 }
244 else
245 {
246 throw new TagException(this.tag,
247 "Parent is not composite component or of type ClientBehaviorHolder, type is: "
248 + parent);
249 }
250 }
251
252 registerJsfAjaxDefaultResource(ctx, parent);
253 }
254
255 public static void registerJsfAjaxDefaultResource(FaceletContext ctx, UIComponent parent)
256 {
257
258
259
260
261
262
263
264
265
266 FacesContext facesContext = ctx.getFacesContext();
267 if (!facesContext.getAttributes().containsKey(STANDARD_JSF_AJAX_LIBRARY_LOADED))
268 {
269 UIComponent outputScript = facesContext.getApplication().
270 createComponent(facesContext, "javax.faces.Output", "javax.faces.resource.Script");
271 outputScript.getAttributes().put(JSFAttr.NAME_ATTR, ResourceUtils.JSF_JS_RESOURCE_NAME);
272 outputScript.getAttributes().put(JSFAttr.LIBRARY_ATTR, ResourceUtils.JAVAX_FACES_LIBRARY_NAME);
273 outputScript.getAttributes().put(JSFAttr.TARGET_ATTR, "head");
274
275
276
277
278
279
280 UniqueIdVendor uniqueIdVendor = ComponentSupport.getViewRoot(ctx, parent);
281
282
283 String uid = uniqueIdVendor.createUniqueId(ctx.getFacesContext(),null);
284 outputScript.setId(uid);
285
286 parent.getChildren().add(outputScript);
287
288 if (FaceletCompositionContext.getCurrentInstance(ctx).isMarkInitialState())
289 {
290
291 outputScript.markInitialState();
292 }
293 facesContext.getAttributes().put(STANDARD_JSF_AJAX_LIBRARY_LOADED, Boolean.TRUE);
294 }
295 }
296
297
298
299
300
301 public String getEventName()
302 {
303 if (_event == null)
304 {
305 return null;
306 }
307 else
308 {
309 return _event.getValue();
310 }
311 }
312
313
314
315
316
317
318
319
320
321 public void applyAttachedObject(FacesContext context, UIComponent parent)
322 {
323
324 FaceletContext faceletContext = (FaceletContext) context
325 .getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
326
327
328 ClientBehaviorHolder cvh = (ClientBehaviorHolder) parent;
329
330 String eventName = getEventName();
331 if (eventName == null)
332 {
333 eventName = cvh.getDefaultEventName();
334 if (eventName == null)
335 {
336 if (_wrapMode)
337 {
338
339
340
341
342 return;
343 }
344 else
345 {
346 throw new TagAttributeException(_event,
347 "eventName could not be defined for f:ajax tag with no wrap mode.");
348 }
349 }
350 }
351 else if (!cvh.getEventNames().contains(eventName))
352 {
353 if (_wrapMode)
354 {
355
356
357
358
359 return;
360 }
361 else
362 {
363 throw new TagAttributeException(_event,
364 "event it is not a valid eventName defined for this component");
365 }
366 }
367
368 Map<String, List<ClientBehavior>> clientBehaviors = cvh.getClientBehaviors();
369
370 List<ClientBehavior> clientBehaviorList = clientBehaviors.get(eventName);
371 if (clientBehaviorList != null && !clientBehaviorList.isEmpty())
372 {
373 for (ClientBehavior cb : clientBehaviorList)
374 {
375 if (cb instanceof AjaxBehavior)
376 {
377
378
379
380
381 return;
382 }
383 }
384 }
385
386 AjaxBehavior ajaxBehavior = createBehavior(context);
387
388 if (_disabled != null)
389 {
390 if (_disabled.isLiteral())
391 {
392 ajaxBehavior.setDisabled(_disabled.getBoolean(faceletContext));
393 }
394 else
395 {
396 ajaxBehavior.setValueExpression("disabled", _disabled
397 .getValueExpression(faceletContext, Boolean.class));
398 }
399 }
400 if (_execute != null)
401 {
402 ajaxBehavior.setValueExpression("execute", _execute
403 .getValueExpression(faceletContext, Object.class));
404 }
405 if (_immediate != null)
406 {
407 if (_immediate.isLiteral())
408 {
409 ajaxBehavior
410 .setImmediate(_immediate.getBoolean(faceletContext));
411 }
412 else
413 {
414 ajaxBehavior.setValueExpression("immediate", _immediate
415 .getValueExpression(faceletContext, Boolean.class));
416 }
417 }
418 if (_listener != null)
419 {
420 MethodExpression expr = _listener.getMethodExpression(
421 faceletContext, Void.TYPE, AJAX_BEHAVIOR_LISTENER_SIG);
422 AjaxBehaviorListener abl = new AjaxBehaviorListenerImpl(expr);
423 ajaxBehavior.addAjaxBehaviorListener(abl);
424 }
425 if (_onerror != null)
426 {
427 if (_onerror.isLiteral())
428 {
429 ajaxBehavior.setOnerror(_onerror.getValue(faceletContext));
430 }
431 else
432 {
433 ajaxBehavior.setValueExpression("onerror", _onerror
434 .getValueExpression(faceletContext, String.class));
435 }
436 }
437 if (_onevent != null)
438 {
439 if (_onevent.isLiteral())
440 {
441 ajaxBehavior.setOnevent(_onevent.getValue(faceletContext));
442 }
443 else
444 {
445 ajaxBehavior.setValueExpression("onevent", _onevent
446 .getValueExpression(faceletContext, String.class));
447 }
448 }
449 if (_render != null)
450 {
451 ajaxBehavior.setValueExpression("render", _render
452 .getValueExpression(faceletContext, Object.class));
453 }
454
455 cvh.addClientBehavior(eventName, ajaxBehavior);
456 }
457
458 protected AjaxBehavior createBehavior(FacesContext context)
459 {
460 return (AjaxBehavior) context.getApplication().createBehavior(AjaxBehavior.BEHAVIOR_ID);
461 }
462
463
464
465
466
467
468 public String getFor()
469 {
470 return null;
471 }
472
473
474
475
476 public final static class AjaxBehaviorListenerImpl implements
477 AjaxBehaviorListener, PartialStateHolder
478 {
479 private MethodExpression _expr;
480 private boolean _transient;
481 private boolean _initialStateMarked;
482
483 public AjaxBehaviorListenerImpl ()
484 {
485 }
486
487 public AjaxBehaviorListenerImpl(MethodExpression expr)
488 {
489 _expr = expr;
490 }
491
492 public void processAjaxBehavior(AjaxBehaviorEvent event)
493 throws AbortProcessingException
494 {
495 _expr.invoke(FacesContext.getCurrentInstance().getELContext(),
496 new Object[] { event });
497 }
498
499 public boolean isTransient()
500 {
501 return _transient;
502 }
503
504 public void restoreState(FacesContext context, Object state)
505 {
506 if (state == null)
507 {
508 return;
509 }
510 _expr = (MethodExpression) state;
511 }
512
513 public Object saveState(FacesContext context)
514 {
515 if (initialStateMarked())
516 {
517 return null;
518 }
519 return _expr;
520 }
521
522 public void setTransient(boolean newTransientValue)
523 {
524 _transient = newTransientValue;
525 }
526
527 public void clearInitialState()
528 {
529 _initialStateMarked = false;
530 }
531
532 public boolean initialStateMarked()
533 {
534 return _initialStateMarked;
535 }
536
537 public void markInitialState()
538 {
539 _initialStateMarked = true;
540 }
541 }
542 }