1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.renderkit.html;
20
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.RandomAccess;
26
27 import javax.faces.FacesException;
28 import javax.faces.component.ActionSource;
29 import javax.faces.component.EditableValueHolder;
30 import javax.faces.component.UIComponent;
31 import javax.faces.component.behavior.AjaxBehavior;
32 import javax.faces.component.behavior.ClientBehavior;
33 import javax.faces.component.behavior.ClientBehaviorContext;
34 import javax.faces.context.FacesContext;
35 import javax.faces.event.AjaxBehaviorEvent;
36 import javax.faces.event.PhaseId;
37 import javax.faces.render.ClientBehaviorRenderer;
38 import org.apache.myfaces.shared.renderkit.html.util.SharedStringBuilder;
39
40
41
42
43
44 public class HtmlAjaxBehaviorRenderer extends ClientBehaviorRenderer
45 {
46
47 private static final String QUOTE = "'";
48 private static final String BLANK = " ";
49
50 private static final String AJAX_KEY_ONERROR = "onerror";
51 private static final String AJAX_KEY_ONEVENT = "onevent";
52 private static final String AJAX_KEY_EXECUTE = "execute";
53 private static final String AJAX_KEY_RENDER = "render";
54 private static final String AJAX_KEY_DELAY = "delay";
55 private static final String AJAX_KEY_RESETVALUES = "resetValues";
56
57 private static final String AJAX_VAL_THIS = "this";
58 private static final String AJAX_VAL_EVENT = "event";
59 private static final String JS_AJAX_REQUEST = "jsf.ajax.request";
60
61 private static final String COLON = ":";
62 private static final String EMPTY = "";
63 private static final String COMMA = ",";
64
65 private static final String ERR_NO_AJAX_BEHAVIOR = "The behavior must be an instance of AjaxBehavior";
66 private static final String L_PAREN = "(";
67 private static final String R_PAREN = ")";
68
69
70
71 private static final String BEHAVIOR_EVENT = "javax.faces.behavior.event";
72 private static final String IDENTIFYER_MARKER = "@";
73
74 private static final String AJAX_SB = "oam.renderkit.AJAX_SB";
75 private static final String AJAX_PARAM_SB = "oam.renderkit.AJAX_PARAM_SB";
76
77 public void decode(FacesContext context, UIComponent component,
78 ClientBehavior behavior)
79 {
80 assertBehavior(behavior);
81 AjaxBehavior ajaxBehavior = (AjaxBehavior) behavior;
82 if (ajaxBehavior.isDisabled() || !component.isRendered())
83 {
84 return;
85 }
86
87 dispatchBehaviorEvent(component, ajaxBehavior);
88 }
89
90
91 public String getScript(ClientBehaviorContext behaviorContext,
92 ClientBehavior behavior)
93 {
94 assertBehavior(behavior);
95 AjaxBehavior ajaxBehavior = (AjaxBehavior) behavior;
96
97 if (ajaxBehavior.isDisabled())
98 {
99 return null;
100 }
101
102 return makeAjax(behaviorContext, ajaxBehavior).toString();
103 }
104
105
106 private final void dispatchBehaviorEvent(UIComponent component, AjaxBehavior ajaxBehavior)
107 {
108 AjaxBehaviorEvent event = new AjaxBehaviorEvent(component, ajaxBehavior);
109
110 boolean isImmediate = false;
111 if (ajaxBehavior.isImmediateSet())
112 {
113 isImmediate = ajaxBehavior.isImmediate();
114 }
115 else
116 {
117 isImmediate = isComponentImmediate(component);
118 }
119 PhaseId phaseId = isImmediate ?
120 PhaseId.APPLY_REQUEST_VALUES :
121 PhaseId.INVOKE_APPLICATION;
122
123 event.setPhaseId(phaseId);
124
125 component.queueEvent(event);
126 }
127
128
129 private final boolean isComponentImmediate(UIComponent component)
130 {
131 boolean isImmediate = false;
132 if (component instanceof EditableValueHolder)
133 {
134 isImmediate = ((EditableValueHolder)component).isImmediate();
135 }
136 else if (component instanceof ActionSource)
137 {
138 isImmediate = ((ActionSource)component).isImmediate();
139 }
140 return isImmediate;
141 }
142
143
144
145
146
147
148
149
150
151
152 private final StringBuilder makeAjax(ClientBehaviorContext context, AjaxBehavior behavior)
153 {
154 StringBuilder retVal = SharedStringBuilder.get(context.getFacesContext(), AJAX_SB, 60);
155 StringBuilder paramBuffer = SharedStringBuilder.get(context.getFacesContext(), AJAX_PARAM_SB, 20);
156
157 String executes = mapToString(context, paramBuffer, AJAX_KEY_EXECUTE, behavior.getExecute());
158 String render = mapToString(context, paramBuffer, AJAX_KEY_RENDER, behavior.getRender());
159
160 String onError = behavior.getOnerror();
161 if (onError != null && !onError.trim().equals(EMPTY))
162 {
163
164 paramBuffer.setLength(0);
165 paramBuffer.append(AJAX_KEY_ONERROR);
166 paramBuffer.append(COLON);
167 paramBuffer.append(onError);
168 onError = paramBuffer.toString();
169 }
170 else
171 {
172 onError = null;
173 }
174 String onEvent = behavior.getOnevent();
175 if (onEvent != null && !onEvent.trim().equals(EMPTY))
176 {
177 paramBuffer.setLength(0);
178 paramBuffer.append(AJAX_KEY_ONEVENT);
179 paramBuffer.append(COLON);
180 paramBuffer.append(onEvent);
181 onEvent = paramBuffer.toString();
182 }
183 else
184 {
185 onEvent = null;
186 }
187
188
189
190 String delay = behavior.getDelay();
191 if (delay != null && !delay.trim().equals(EMPTY))
192 {
193 paramBuffer.setLength(0);
194 paramBuffer.append(AJAX_KEY_DELAY);
195 paramBuffer.append(COLON);
196 if ("none".equals(delay))
197 {
198 paramBuffer.append('\'');
199 paramBuffer.append(delay);
200 paramBuffer.append('\'');
201 }
202 else
203 {
204 paramBuffer.append(delay);
205 }
206 delay = paramBuffer.toString();
207 }
208 else
209 {
210 delay = null;
211 }
212
213
214
215 String resetValues = Boolean.toString(behavior.isResetValues());
216 if (resetValues.equals("true"))
217 {
218 paramBuffer.setLength(0);
219 paramBuffer.append(AJAX_KEY_RESETVALUES);
220 paramBuffer.append(COLON);
221 paramBuffer.append(resetValues);
222 resetValues = paramBuffer.toString();
223 }
224 else
225 {
226 resetValues = null;
227 }
228
229 String sourceId = null;
230 if (context.getSourceId() == null)
231 {
232 sourceId = AJAX_VAL_THIS;
233 }
234 else
235 {
236 paramBuffer.setLength(0);
237 paramBuffer.append('\'');
238 paramBuffer.append(context.getSourceId());
239 paramBuffer.append('\'');
240 sourceId = paramBuffer.toString();
241
242 if (!context.getSourceId().trim().equals(
243 context.getComponent().getClientId(context.getFacesContext())))
244 {
245
246 UIComponent ref = context.getComponent();
247 ref = (ref.getParent() == null) ? ref : ref.getParent();
248 UIComponent instance = null;
249 try
250 {
251 instance = ref.findComponent(context.getSourceId());
252 }
253 catch (IllegalArgumentException e)
254 {
255
256 }
257 if (instance == null && executes == null)
258 {
259
260
261 List<String> list = new ArrayList<String>();
262 list.add(context.getComponent().getClientId(context.getFacesContext()));
263 executes = mapToString(context, paramBuffer, AJAX_KEY_EXECUTE, list);
264 }
265 }
266 }
267
268
269 String event = context.getEventName();
270
271 retVal.append(JS_AJAX_REQUEST);
272 retVal.append(L_PAREN);
273 retVal.append(sourceId);
274 retVal.append(COMMA);
275 retVal.append(AJAX_VAL_EVENT);
276 retVal.append(COMMA);
277
278 Collection<ClientBehaviorContext.Parameter> params = context.getParameters();
279 int paramSize = (params != null) ? params.size() : 0;
280
281 List<String> parameterList = new ArrayList<String>(paramSize + 2);
282 if (executes != null)
283 {
284 parameterList.add(executes);
285 }
286 if (render != null)
287 {
288 parameterList.add(render);
289 }
290 if (onError != null)
291 {
292 parameterList.add(onError);
293 }
294 if (onEvent != null)
295 {
296 parameterList.add(onEvent);
297 }
298
299
300
301 if (delay != null)
302 {
303 parameterList.add(delay);
304 }
305
306
307
308 if (resetValues != null)
309 {
310 parameterList.add(resetValues);
311 }
312 if (paramSize > 0)
313 {
314
315
316
317
318
319
320 if (params instanceof RandomAccess)
321 {
322 List<ClientBehaviorContext.Parameter> list = (List<ClientBehaviorContext.Parameter>) params;
323 for (int i = 0, size = list.size(); i < size; i++)
324 {
325 ClientBehaviorContext.Parameter param = list.get(i);
326 append(paramBuffer, parameterList, param);
327 }
328 }
329 else
330 {
331 for (ClientBehaviorContext.Parameter param : params)
332 {
333 append(paramBuffer, parameterList, param);
334 }
335 }
336 }
337
338
339 paramBuffer.setLength(0);
340 paramBuffer.append(QUOTE);
341 paramBuffer.append(BEHAVIOR_EVENT);
342 paramBuffer.append(QUOTE);
343 paramBuffer.append(COLON);
344 paramBuffer.append(QUOTE);
345 paramBuffer.append(event);
346 paramBuffer.append(QUOTE);
347 parameterList.add(paramBuffer.toString());
348
349
350
351
352
353
354 retVal.append(buildOptions(paramBuffer, parameterList));
355
356 retVal.append(R_PAREN);
357
358 return retVal;
359 }
360
361 private void append(StringBuilder paramBuffer, List<String> parameterList, ClientBehaviorContext.Parameter param)
362 {
363
364
365
366
367
368 paramBuffer.setLength(0);
369 paramBuffer.append(QUOTE);
370 paramBuffer.append(param.getName());
371 paramBuffer.append(QUOTE);
372 paramBuffer.append(COLON);
373 paramBuffer.append(QUOTE);
374 paramBuffer.append(param.getValue().toString());
375 paramBuffer.append(QUOTE);
376 parameterList.add(paramBuffer.toString());
377 }
378
379
380 private StringBuilder buildOptions(StringBuilder retVal, List<String> options)
381 {
382 retVal.setLength(0);
383
384 retVal.append("{");
385
386 boolean first = true;
387
388 for (int i = 0, size = options.size(); i < size; i++)
389 {
390 String option = options.get(i);
391 if (option != null && !option.trim().equals(EMPTY))
392 {
393 if (!first)
394 {
395 retVal.append(COMMA);
396 }
397 else
398 {
399 first = false;
400 }
401 retVal.append(option);
402 }
403 }
404 retVal.append("}");
405 return retVal;
406 }
407
408 private final String mapToString(ClientBehaviorContext context, StringBuilder retVal,
409 String target, Collection<String> dataHolder)
410 {
411
412 retVal.setLength(0);
413
414 if (dataHolder == null)
415 {
416 dataHolder = Collections.emptyList();
417 }
418 int executeSize = dataHolder.size();
419 if (executeSize > 0)
420 {
421
422 retVal.append(target);
423 retVal.append(COLON);
424 retVal.append(QUOTE);
425
426 int cnt = 0;
427
428
429
430
431
432
433 if (dataHolder instanceof RandomAccess)
434 {
435 List<String> list = (List<String>) dataHolder;
436 for (; cnt < executeSize; cnt++)
437 {
438 String strVal = list.get(cnt);
439 build(context, executeSize, retVal, cnt, strVal);
440 }
441 }
442 else
443 {
444 for (String strVal : dataHolder)
445 {
446 cnt++;
447 build(context, executeSize, retVal, cnt, strVal);
448 }
449 }
450
451 retVal.append(QUOTE);
452 return retVal.toString();
453 }
454 return null;
455
456 }
457
458 public void build(ClientBehaviorContext context,
459 int size, StringBuilder retVal, int cnt,
460 String strVal)
461 {
462 strVal = strVal.trim();
463 if (!EMPTY.equals(strVal))
464 {
465 if (!strVal.startsWith(IDENTIFYER_MARKER))
466 {
467 String componentId = getComponentId(context, strVal);
468 retVal.append(componentId);
469 }
470 else
471 {
472
473
474
475 if (strVal.equalsIgnoreCase("@this"))
476 {
477 retVal.append(context.getComponent().getClientId(context.getFacesContext()));
478 }
479 else
480 {
481 retVal.append(strVal);
482 }
483 }
484 if (cnt < size)
485 {
486 retVal.append(BLANK);
487 }
488 }
489 }
490
491 private final String getComponentId(ClientBehaviorContext context, String id)
492 {
493
494 UIComponent contextComponent = context.getComponent();
495 UIComponent target = contextComponent.findComponent(id);
496 if (target == null)
497 {
498 target = contextComponent.findComponent(
499 context.getFacesContext().getNamingContainerSeparatorChar() + id);
500 }
501 if (target != null)
502 {
503 return target.getClientId(context.getFacesContext());
504 }
505 throw new FacesException("Component with id:" + id + " not found");
506 }
507
508 private final void assertBehavior(ClientBehavior behavior)
509 {
510 if (!(behavior instanceof AjaxBehavior))
511 {
512 throw new FacesException(ERR_NO_AJAX_BEHAVIOR);
513 }
514 }
515
516 }