1
2
3
4
5 package org.rcfaces.core.internal.tools;
6
7 import java.io.IOException;
8 import java.lang.reflect.Array;
9 import java.util.ArrayList;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.StringTokenizer;
14
15 import javax.faces.application.FacesMessage;
16 import javax.faces.component.NamingContainer;
17 import javax.faces.component.UICommand;
18 import javax.faces.component.UIComponent;
19 import javax.faces.component.UIInput;
20 import javax.faces.component.UIViewRoot;
21 import javax.faces.context.FacesContext;
22 import javax.faces.convert.Converter;
23 import javax.faces.convert.ConverterException;
24 import javax.faces.event.ActionEvent;
25 import javax.faces.event.ActionListener;
26 import javax.faces.event.FacesEvent;
27 import javax.faces.event.FacesListener;
28 import javax.faces.event.PhaseId;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.rcfaces.core.component.capability.IAsyncDecodeModeCapability;
33 import org.rcfaces.core.component.capability.IPrependIdCapability;
34 import org.rcfaces.core.internal.RcfacesContext;
35 import org.rcfaces.core.internal.adapter.IAdapterManager;
36 import org.rcfaces.core.internal.capability.IComponentEngine;
37 import org.rcfaces.core.internal.lang.StringAppender;
38 import org.rcfaces.core.internal.listener.IScriptListener;
39 import org.rcfaces.core.internal.renderkit.WriterException;
40 import org.rcfaces.core.internal.util.ComponentIterators;
41 import org.rcfaces.core.lang.IAdaptable;
42 import org.rcfaces.core.lang.provider.ICursorProvider;
43
44
45
46
47
48
49 public final class ComponentTools extends ComponentTools0 {
50 private static final String REVISION = "$Revision: 1.18 $";
51
52 private static final Log LOG = LogFactory.getLog(ComponentTools.class);
53
54 public static final String[] STRING_EMPTY_ARRAY = new String[0];
55
56 static final String VARIABLE_SCOPE_VALUE = "org.rcfaces.core.internal.VARIABLE_SCOPE_VALUE";
57
58 static final String NONE_VARIABLE_SCOPE = "##~NONE~"
59 + System.currentTimeMillis();
60
61 private static final UIComponent[] COMPONENT_EMPTY_ARRAY = new UIComponent[0];
62
63 public static final String PARTIAL_ASYNC_DECODE_PROPERTY = "org.rcfaces.async.partial";
64
65 public static final boolean isAnonymousComponentId(String componentId) {
66 if (componentId == null) {
67 return false;
68 }
69
70 int idx = componentId.lastIndexOf(NamingContainer.SEPARATOR_CHAR);
71 if (idx >= 0) {
72 componentId = componentId.substring(idx + 1);
73 }
74
75 return componentId.startsWith(UIViewRoot.UNIQUE_ID_PREFIX);
76 }
77
78 public static final void encodeRecursive(FacesContext context,
79 UIComponent component) throws WriterException {
80 if (component.isRendered() == false) {
81 return;
82 }
83
84 try {
85 component.encodeBegin(context);
86
87 if (component.getRendersChildren()) {
88 component.encodeChildren(context);
89
90 } else {
91 encodeChildrenRecursive(context, component);
92 }
93
94 component.encodeEnd(context);
95
96 } catch (WriterException ex) {
97 throw ex;
98
99 } catch (IOException ex) {
100 throw new WriterException("Can not encode component '"
101 + component.getId() + "'.", ex, component);
102 }
103 }
104
105 public static final void encodeChildrenRecursive(FacesContext context,
106 UIComponent component) throws WriterException {
107 Iterator children = component.getChildren().iterator();
108
109 for (; children.hasNext();) {
110 UIComponent child = (UIComponent) children.next();
111 if (child.isRendered() == false) {
112 continue;
113 }
114
115 try {
116 child.encodeBegin(context);
117
118 if (child.getRendersChildren()) {
119 child.encodeChildren(context);
120
121 } else {
122 encodeChildrenRecursive(context, child);
123 }
124
125 child.encodeEnd(context);
126
127 } catch (WriterException ex) {
128 throw ex;
129
130 } catch (IOException ex) {
131 throw new WriterException("Can not encode child component '"
132 + child.getId() + "'.", ex, child);
133 }
134 }
135 }
136
137 public static UIComponent getForComponent(FacesContext context,
138 String forComponent, UIComponent component) {
139 if (forComponent == null || forComponent.length() < 1) {
140 return null;
141 }
142
143 try {
144
145
146
147 for (UIComponent currentParent = component; currentParent != null; currentParent = currentParent
148 .getParent()) {
149
150 try {
151 UIComponent result = currentParent
152 .findComponent(forComponent);
153 if (result != null) {
154 if (LOG.isDebugEnabled()) {
155 LOG.debug("Get for component '" + forComponent
156 + "' returns " + result.getId());
157 }
158 return result;
159 }
160
161 } catch (IllegalArgumentException ex) {
162 LOG.error("Compute for component '" + component.getId()
163 + "'", ex);
164
165 break;
166 }
167 }
168
169 return findUIComponentBelow(context.getViewRoot(), forComponent);
170
171 } catch (RuntimeException ex) {
172 LOG.error("Compute for component '" + component.getId() + "'", ex);
173
174 throw ex;
175 }
176 }
177
178 private static UIComponent findUIComponentBelow(UIComponent startPoint,
179 String forComponent) {
180 List children = startPoint.getChildren();
181
182 if (LOG.isDebugEnabled()) {
183 LOG.debug("Find component below '" + startPoint.getId() + "' to '"
184 + forComponent + "'.");
185 }
186
187 int size = children.size();
188 for (int i = 0; i < size; i++) {
189 UIComponent comp = (UIComponent) children.get(i);
190
191 boolean nc = (comp instanceof NamingContainer);
192 if (nc) {
193 if (comp instanceof IPrependIdCapability) {
194 nc = ((IPrependIdCapability) comp).isPrependId();
195 }
196 }
197
198 if (nc) {
199 try {
200 UIComponent retComp = comp.findComponent(forComponent);
201
202 if (retComp != null) {
203 if (LOG.isDebugEnabled()) {
204 LOG.debug("Find component below '" + forComponent
205 + "' returns " + retComp.getId());
206 }
207
208 return retComp;
209 }
210
211 } catch (IllegalArgumentException ex) {
212 LOG.error("Find component below '" + startPoint.getId()
213 + "' to '" + forComponent + "' exception:", ex);
214 }
215 }
216
217 if (comp.getChildCount() > 0) {
218 UIComponent retComp = findUIComponentBelow(comp, forComponent);
219 if (retComp != null) {
220 return retComp;
221 }
222 }
223 }
224
225 return null;
226 }
227
228 public static UIViewRoot getViewRoot(UIComponent component) {
229 for (; component != null;) {
230
231 if (component instanceof UIViewRoot) {
232 return (UIViewRoot) component;
233 }
234
235 component = component.getParent();
236 }
237
238 return null;
239 }
240
241 public static Converter createConverter(FacesContext facesContext,
242 String converterId) {
243 if (facesContext == null) {
244 facesContext = FacesContext.getCurrentInstance();
245 }
246
247 Converter converter = facesContext.getApplication().createConverter(
248 converterId);
249
250 if (LOG.isDebugEnabled()) {
251 LOG.debug("Get converter id=" + converterId + "' object="
252 + converter);
253 }
254
255 return converter;
256 }
257
258
259
260
261
262
263 private static class Entry implements Map.Entry {
264 private final Object key;
265
266 private Object value;
267
268
269
270
271 Entry(Object k, Object v) {
272 value = v;
273 key = k;
274 }
275
276 public Object getKey() {
277 return key;
278 }
279
280 public Object getValue() {
281 return value;
282 }
283
284 public boolean equals(Object o) {
285 if (!(o instanceof Map.Entry)) {
286 return false;
287 }
288
289 Map.Entry e = (Map.Entry) o;
290 Object k1 = getKey();
291 Object k2 = e.getKey();
292 if (k1 == k2 || (k1 != null && k1.equals(k2))) {
293 Object v1 = getValue();
294 Object v2 = e.getValue();
295 if (v1 == v2 || (v1 != null && v1.equals(v2))) {
296 return true;
297 }
298 }
299 return false;
300 }
301
302 public int hashCode() {
303 return key.hashCode() ^ (value == null ? 0 : value.hashCode());
304 }
305
306 public String toString() {
307 return getKey() + "=" + getValue();
308 }
309
310 public Object setValue(Object value) {
311 throw new UnsupportedOperationException("Not implemented !");
312 }
313 }
314
315 public static UIComponent findComponent(UIComponent startPoint, Class clazz) {
316 UIComponent retComp = null;
317 List children = startPoint.getChildren();
318
319 int size = children.size();
320 for (int i = 0; i < size; i++) {
321 UIComponent comp = (UIComponent) children.get(i);
322
323 if (clazz.isInstance(comp)) {
324 return comp;
325 }
326
327 if (comp.getChildCount() > 0) {
328 retComp = findComponent(comp, clazz);
329 if (retComp != null) {
330 return retComp;
331 }
332 }
333 }
334
335 return null;
336 }
337
338
339
340
341
342
343 public interface IVarScope {
344 void popVar(FacesContext facesContext);
345 }
346
347
348
349
350
351
352 static class VarScope implements IVarScope {
353 private static final String REVISION = "$Revision: 1.18 $";
354
355 private final String var;
356
357 private final Object previousObject;
358
359 public VarScope(String var, Object previousObject) {
360 this.var = var;
361 this.previousObject = previousObject;
362 }
363
364 public void popVar(FacesContext facesContext) {
365 Map requestMap = facesContext.getExternalContext().getRequestMap();
366
367 if (previousObject == null) {
368 requestMap.remove(var);
369 return;
370 }
371
372 requestMap.put(var, previousObject);
373 }
374 }
375
376 public static void broadcast(UIComponent component, FacesEvent facesEvent,
377 FacesListener listeners[]) {
378
379 if (facesEvent == null) {
380 throw new NullPointerException("Event is null");
381 }
382
383 if (listeners == null || listeners.length < 1) {
384 return;
385 }
386
387 for (int i = 0; i < listeners.length; i++) {
388 FacesListener listener = listeners[i];
389
390 if (facesEvent.isAppropriateListener(listener) == false) {
391 continue;
392 }
393
394 if (listener instanceof IScriptListener) {
395 continue;
396 }
397
398 facesEvent.processListener(listener);
399 }
400 }
401
402 public static Object getCursorValue(Object value, UIComponent component,
403 FacesContext facesContext) {
404 if (value == null) {
405 return null;
406 }
407
408 ICursorProvider cursorProvider = null;
409
410 if (value instanceof IAdaptable) {
411 cursorProvider = (ICursorProvider) ((IAdaptable) value).getAdapter(
412 ICursorProvider.class, component);
413
414 if (LOG.isDebugEnabled()) {
415 LOG.debug("Try to adapt '" + value + "' to ICursorProvider => "
416 + cursorProvider);
417 }
418 }
419
420 if (cursorProvider == null) {
421 IAdapterManager adapterManager = RcfacesContext.getInstance(
422 facesContext).getAdapterManager();
423
424 cursorProvider = (ICursorProvider) adapterManager.getAdapter(value,
425 ICursorProvider.class, component);
426
427 if (LOG.isDebugEnabled()) {
428 LOG.debug("Ask adapterManager to adapt '" + value
429 + "' to ICursorProvider => " + cursorProvider);
430 }
431 }
432
433 if (cursorProvider == null) {
434 return null;
435 }
436
437 return cursorProvider.getCursorValue();
438 }
439
440 public static void addConversionErrorMessage(FacesContext context,
441 UIInput input, ConverterException ce, Object submittedValue) {
442 FacesMessage message = ce.getFacesMessage();
443 if (message == null) {
444 message = new FacesMessage("Conversion error !");
445
446
447 if (message.getDetail() == null) {
448 message.setDetail(ce.getMessage());
449 }
450 }
451
452 message.setSeverity(FacesMessage.SEVERITY_ERROR);
453 context.addMessage(input.getClientId(context), message);
454
455 }
456
457 public static void broadcastCommand(UICommand component,
458 ActionEvent facesEvent, FacesListener listeners[]) {
459
460 if (facesEvent == null) {
461 throw new NullPointerException("Event is null");
462 }
463
464 boolean found = false;
465
466 FacesContext facesContext = FacesContext.getCurrentInstance();
467
468 if (listeners != null && listeners.length > 0) {
469 for (int i = 0; i < listeners.length; i++) {
470 FacesListener listener = listeners[i];
471
472 if (listener instanceof IScriptListener) {
473 continue;
474 }
475
476 if (facesEvent.isAppropriateListener(listener) == false) {
477 continue;
478 }
479
480 facesEvent.processListener(listener);
481
482 found = true;
483
484
485
486
487
488 }
489 }
490
491 if (found == false) {
492 BindingTools.invokeActionListener(facesContext, component,
493 facesEvent);
494
495
496 ActionListener listener = facesContext.getApplication()
497 .getActionListener();
498 if (listener != null) {
499 listener.processAction(facesEvent);
500 }
501 }
502
503 if (facesContext.getRenderResponse()) {
504 return;
505 }
506
507 broadcastActionCommand(facesContext, component);
508 }
509
510 public static UIComponent[] listChildren(FacesContext facesContext,
511 UIComponent component, IComponentEngine engine, Class childClass,
512 String propertyName) {
513
514 String ids = engine.getStringProperty(propertyName, facesContext);
515
516 return listChildren(facesContext, component, ids, childClass);
517 }
518
519 public static UIComponent[] listChildren(FacesContext facesContext,
520 UIComponent component, String ids, Class childClass) {
521
522 if (ids == null) {
523 if (childClass == null || childClass == UIComponent.class) {
524 return COMPONENT_EMPTY_ARRAY;
525 }
526 return (UIComponent[]) Array.newInstance(childClass, 0);
527 }
528
529 StringTokenizer st = new StringTokenizer(ids, ",");
530
531 if (st.hasMoreTokens() == false) {
532 if (childClass == null || childClass == UIComponent.class) {
533 return COMPONENT_EMPTY_ARRAY;
534 }
535 return (UIComponent[]) Array.newInstance(childClass, 0);
536 }
537
538 Object children[] = ComponentIterators.list(component, childClass)
539 .toArray();
540
541 List l = new ArrayList(st.countTokens());
542
543 for (; st.hasMoreTokens();) {
544 String id = st.nextToken().trim();
545
546 if (id.startsWith("#")) {
547 int idx = Integer.parseInt(id.substring(1));
548
549 if (idx >= children.length) {
550 continue;
551 }
552
553 UIComponent child = (UIComponent) children[idx];
554
555 l.add(child);
556 continue;
557 }
558
559 for (int i = 0; i < children.length; i++) {
560 UIComponent child = (UIComponent) children[i];
561
562 if (id.equals(child.getId()) == false) {
563 continue;
564 }
565
566 l.add(child);
567 break;
568 }
569 }
570
571 if (childClass == null) {
572 childClass = UIComponent.class;
573 }
574
575 return (UIComponent[]) l.toArray((UIComponent[]) Array.newInstance(
576 childClass, l.size()));
577 }
578
579 public static void setChildren(UIComponent component,
580 IComponentEngine engine, Class classOfChild,
581 UIComponent[] children, String propertyName) {
582
583 String list = createStringFromList(children, classOfChild, component);
584
585 engine.setProperty(propertyName, list);
586 }
587
588 private static String createStringFromList(UIComponent[] components,
589 Class classOfChild, UIComponent component) {
590 if (components == null) {
591 return null;
592 }
593
594 if (components.length < 1) {
595 return "";
596 }
597
598 Object children[] = null;
599
600 StringAppender sa = new StringAppender(components.length * 32);
601 for (int i = 0; i < components.length; i++) {
602 UIComponent child = components[i];
603
604 if (classOfChild.isInstance(child) == false) {
605 continue;
606 }
607
608 if (sa.length() > 0) {
609 sa.append(',');
610 }
611
612 String id = child.getId();
613
614 if (id.startsWith(UIViewRoot.UNIQUE_ID_PREFIX)) {
615 int childIndex = -1;
616
617 if (children == null) {
618 children = ComponentIterators.list(component, classOfChild)
619 .toArray();
620 }
621
622 for (int j = 0; j < children.length; j++) {
623 if (children[j] != child) {
624 continue;
625 }
626
627 childIndex = j;
628 break;
629 }
630 if (childIndex < 0) {
631 LOG.error("Can not find index of component '" + child
632 + "'.");
633 continue;
634 }
635
636 sa.append('#').append(childIndex);
637 continue;
638 }
639
640 sa.append(child.getId());
641 }
642
643 return sa.toString();
644 }
645
646 public static boolean hasValidationServerListeners(
647 FacesListener facesListeners[]) {
648 for (int i = 0; i < facesListeners.length; i++) {
649 FacesListener facesListener = facesListeners[i];
650
651 if (facesListener instanceof IScriptListener) {
652 continue;
653 }
654
655 return true;
656 }
657
658 return false;
659 }
660
661 public static boolean verifyAsyncDecode(FacesContext facesContext,
662 IAsyncDecodeModeCapability asyncDecodeModeCapability,
663 PhaseId phaseId) {
664
665 if (asyncDecodeModeCapability.getAsyncDecodeMode() != IAsyncDecodeModeCapability.PARTIAL_ASYNC_DECODE_MODE) {
666 return true;
667 }
668
669 Map parameters = facesContext.getExternalContext()
670 .getRequestParameterMap();
671
672 UIComponent component = (UIComponent) asyncDecodeModeCapability;
673
674 String clientId = component.getClientId(facesContext);
675
676 String value = (String) parameters.get(PARTIAL_ASYNC_DECODE_PROPERTY
677 + "." + clientId);
678
679 if (value != null) {
680 if (LOG.isDebugEnabled()) {
681 LOG.debug("Partial async decode enabled for component '"
682 + clientId + "' phase='" + phaseId + "'.");
683 }
684
685 return true;
686 }
687
688 if (LOG.isDebugEnabled()) {
689 LOG.debug("Partial async decode DISABLED for component '"
690 + clientId + "' phase='" + phaseId + "'.");
691 }
692 return false;
693 }
694 }