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.UINamingContainer;
32 import javax.faces.component.behavior.AjaxBehavior;
33 import javax.faces.component.behavior.ClientBehavior;
34 import javax.faces.component.behavior.ClientBehaviorContext;
35 import javax.faces.context.FacesContext;
36 import javax.faces.event.AjaxBehaviorEvent;
37 import javax.faces.event.PhaseId;
38 import javax.faces.render.ClientBehaviorRenderer;
39 import org.apache.myfaces.shared.renderkit.html.util.SharedStringBuilder;
40
41
42
43
44
45 public class HtmlAjaxBehaviorRenderer extends ClientBehaviorRenderer
46 {
47
48 private static final String QUOTE = "'";
49 private static final String BLANK = " ";
50
51 private static final String AJAX_KEY_ONERROR = "onerror";
52 private static final String AJAX_KEY_ONEVENT = "onevent";
53 private static final String AJAX_KEY_EXECUTE = "execute";
54 private static final String AJAX_KEY_RENDER = "render";
55
56 private static final String AJAX_VAL_THIS = "this";
57 private static final String AJAX_VAL_EVENT = "event";
58 private static final String JS_AJAX_REQUEST = "jsf.ajax.request";
59
60 private static final String COLON = ":";
61 private static final String EMPTY = "";
62 private static final String COMMA = ",";
63
64 private static final String ERR_NO_AJAX_BEHAVIOR = "The behavior must be an instance of AjaxBehavior";
65 private static final String L_PAREN = "(";
66 private static final String R_PAREN = ")";
67
68
69
70 private static final String BEHAVIOR_EVENT = "javax.faces.behavior.event";
71 private static final String IDENTIFYER_MARKER = "@";
72
73 private static final String AJAX_SB = "oam.renderkit.AJAX_SB";
74 private static final String AJAX_PARAM_SB = "oam.renderkit.AJAX_PARAM_SB";
75
76 public void decode(FacesContext context, UIComponent component,
77 ClientBehavior behavior)
78 {
79 assertBehavior(behavior);
80 AjaxBehavior ajaxBehavior = (AjaxBehavior) behavior;
81 if (ajaxBehavior.isDisabled() || !component.isRendered())
82 {
83 return;
84 }
85
86 dispatchBehaviorEvent(component, ajaxBehavior);
87 }
88
89
90 public String getScript(ClientBehaviorContext behaviorContext,
91 ClientBehavior behavior)
92 {
93 assertBehavior(behavior);
94 AjaxBehavior ajaxBehavior = (AjaxBehavior) behavior;
95
96 if (ajaxBehavior.isDisabled())
97 {
98 return null;
99 }
100
101 return makeAjax(behaviorContext, ajaxBehavior).toString();
102 }
103
104
105 private final void dispatchBehaviorEvent(UIComponent component, AjaxBehavior ajaxBehavior)
106 {
107 AjaxBehaviorEvent event = new AjaxBehaviorEvent(component, ajaxBehavior);
108
109 boolean isImmediate = false;
110 if (ajaxBehavior.isImmediateSet())
111 {
112 isImmediate = ajaxBehavior.isImmediate();
113 }
114 else
115 {
116 isImmediate = isComponentImmediate(component);
117 }
118 PhaseId phaseId = isImmediate ?
119 PhaseId.APPLY_REQUEST_VALUES :
120 PhaseId.INVOKE_APPLICATION;
121
122 event.setPhaseId(phaseId);
123
124 component.queueEvent(event);
125 }
126
127
128 private final boolean isComponentImmediate(UIComponent component)
129 {
130 boolean isImmediate = false;
131 if (component instanceof EditableValueHolder)
132 {
133 isImmediate = ((EditableValueHolder)component).isImmediate();
134 }
135 else if (component instanceof ActionSource)
136 {
137 isImmediate = ((ActionSource)component).isImmediate();
138 }
139 return isImmediate;
140 }
141
142
143
144
145
146
147
148
149
150
151 private final StringBuilder makeAjax(ClientBehaviorContext context, AjaxBehavior behavior)
152 {
153 StringBuilder retVal = SharedStringBuilder.get(context.getFacesContext(), AJAX_SB, 60);
154 StringBuilder paramBuffer = SharedStringBuilder.get(context.getFacesContext(), AJAX_PARAM_SB, 20);
155
156 String executes = mapToString(context, paramBuffer, AJAX_KEY_EXECUTE, behavior.getExecute());
157 String render = mapToString(context, paramBuffer, AJAX_KEY_RENDER, behavior.getRender());
158
159 String onError = behavior.getOnerror();
160 if (onError != null && !onError.trim().equals(EMPTY))
161 {
162
163 paramBuffer.setLength(0);
164 paramBuffer.append(AJAX_KEY_ONERROR);
165 paramBuffer.append(COLON);
166 paramBuffer.append(onError);
167 onError = paramBuffer.toString();
168 }
169 else
170 {
171 onError = null;
172 }
173 String onEvent = behavior.getOnevent();
174 if (onEvent != null && !onEvent.trim().equals(EMPTY))
175 {
176 paramBuffer.setLength(0);
177 paramBuffer.append(AJAX_KEY_ONEVENT);
178 paramBuffer.append(COLON);
179 paramBuffer.append(onEvent);
180 onEvent = paramBuffer.toString();
181 }
182 else
183 {
184 onEvent = null;
185 }
186
187 String sourceId = null;
188 if (context.getSourceId() == null)
189 {
190 sourceId = AJAX_VAL_THIS;
191 }
192 else
193 {
194 paramBuffer.setLength(0);
195 paramBuffer.append('\'');
196 paramBuffer.append(context.getSourceId());
197 paramBuffer.append('\'');
198 sourceId = paramBuffer.toString();
199 }
200 String event = context.getEventName();
201
202 retVal.append(JS_AJAX_REQUEST);
203 retVal.append(L_PAREN);
204 retVal.append(sourceId);
205 retVal.append(COMMA);
206 retVal.append(AJAX_VAL_EVENT);
207 retVal.append(COMMA);
208
209 Collection<ClientBehaviorContext.Parameter> params = context.getParameters();
210 int paramSize = (params != null) ? params.size() : 0;
211
212 List<String> parameterList = new ArrayList<String>(paramSize + 2);
213 if (executes != null)
214 {
215 parameterList.add(executes.toString());
216 }
217 if (render != null)
218 {
219 parameterList.add(render.toString());
220 }
221 if (onError != null)
222 {
223 parameterList.add(onError);
224 }
225 if (onEvent != null)
226 {
227 parameterList.add(onEvent);
228 }
229 if (paramSize > 0)
230 {
231
232
233
234
235
236
237 if (params instanceof RandomAccess)
238 {
239 List<ClientBehaviorContext.Parameter> list = (List<ClientBehaviorContext.Parameter>) params;
240 for (int i = 0, size = list.size(); i < size; i++)
241 {
242 ClientBehaviorContext.Parameter param = list.get(i);
243 append(paramBuffer, parameterList, param);
244 }
245 }
246 else
247 {
248 for (ClientBehaviorContext.Parameter param : params)
249 {
250 append(paramBuffer, parameterList, param);
251 }
252 }
253 }
254
255
256 paramBuffer.setLength(0);
257 paramBuffer.append(QUOTE);
258 paramBuffer.append(BEHAVIOR_EVENT);
259 paramBuffer.append(QUOTE);
260 paramBuffer.append(COLON);
261 paramBuffer.append(QUOTE);
262 paramBuffer.append(event);
263 paramBuffer.append(QUOTE);
264 parameterList.add(paramBuffer.toString());
265
266
267
268
269
270
271 retVal.append(buildOptions(context.getFacesContext(), paramBuffer, parameterList));
272
273 retVal.append(R_PAREN);
274
275 return retVal;
276 }
277
278 private void append(StringBuilder paramBuffer, List<String> parameterList, ClientBehaviorContext.Parameter param)
279 {
280
281
282
283
284
285 paramBuffer.setLength(0);
286 paramBuffer.append(QUOTE);
287 paramBuffer.append(param.getName());
288 paramBuffer.append(QUOTE);
289 paramBuffer.append(COLON);
290 paramBuffer.append(QUOTE);
291 paramBuffer.append(param.getValue().toString());
292 paramBuffer.append(QUOTE);
293 parameterList.add(paramBuffer.toString());
294 }
295
296
297 private StringBuilder buildOptions(FacesContext facesContext, StringBuilder retVal, List<String> options)
298 {
299 retVal.setLength(0);
300
301 retVal.append("{");
302
303 boolean first = true;
304
305 for (int i = 0, size = options.size(); i < size; i++)
306 {
307 String option = options.get(i);
308 if (option != null && !option.trim().equals(EMPTY))
309 {
310 if (!first)
311 {
312 retVal.append(COMMA);
313 }
314 else
315 {
316 first = false;
317 }
318 retVal.append(option);
319 }
320 }
321 retVal.append("}");
322 return retVal;
323 }
324
325 private final String mapToString(ClientBehaviorContext context, StringBuilder retVal,
326 String target, Collection<String> dataHolder)
327 {
328
329 retVal.setLength(0);
330
331 if (dataHolder == null)
332 {
333 dataHolder = Collections.emptyList();
334 }
335 int executeSize = dataHolder.size();
336 if (executeSize > 0)
337 {
338
339 retVal.append(target);
340 retVal.append(COLON);
341 retVal.append(QUOTE);
342
343 int cnt = 0;
344
345
346
347
348
349
350 if (dataHolder instanceof RandomAccess)
351 {
352 List<String> list = (List<String>) dataHolder;
353 for (; cnt < executeSize; cnt++)
354 {
355 String strVal = list.get(cnt);
356 build(context, executeSize, retVal, cnt, strVal);
357 }
358 }
359 else
360 {
361 for (String strVal : dataHolder)
362 {
363 cnt++;
364 build(context, executeSize, retVal, cnt, strVal);
365 }
366 }
367
368 retVal.append(QUOTE);
369 return retVal.toString();
370 }
371 return null;
372
373 }
374
375 public void build(ClientBehaviorContext context,
376 int size, StringBuilder retVal, int cnt,
377 String strVal)
378 {
379 strVal = strVal.trim();
380 if (!EMPTY.equals(strVal))
381 {
382 if (!strVal.startsWith(IDENTIFYER_MARKER))
383 {
384 String componentId = getComponentId(context, strVal);
385 retVal.append(componentId);
386 }
387 else
388 {
389 retVal.append(strVal);
390 }
391 if (cnt < size)
392 {
393 retVal.append(BLANK);
394 }
395 }
396 }
397
398 private final String getComponentId(ClientBehaviorContext context, String id)
399 {
400
401 UIComponent contextComponent = context.getComponent();
402 UIComponent target = contextComponent.findComponent(id);
403 if (target == null)
404 {
405 target = contextComponent.findComponent(UINamingContainer.getSeparatorChar(context.getFacesContext()) + id);
406 }
407 if (target != null)
408 {
409 return target.getClientId(context.getFacesContext());
410 }
411 throw new FacesException("Component with id:" + id + " not found");
412 }
413
414 private final void assertBehavior(ClientBehavior behavior)
415 {
416 if (!(behavior instanceof AjaxBehavior))
417 {
418 throw new FacesException(ERR_NO_AJAX_BEHAVIOR);
419 }
420 }
421
422 }