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