1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.render;
20
21
22 import java.beans.Beans;
23
24 import java.io.IOException;
25
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32
33 import javax.faces.application.ResourceHandler;
34 import javax.faces.component.UIComponent;
35 import javax.faces.component.UIParameter;
36 import javax.faces.component.UIViewRoot;
37 import javax.faces.component.behavior.ClientBehavior;
38 import javax.faces.component.behavior.ClientBehaviorContext;
39 import javax.faces.component.behavior.ClientBehaviorHolder;
40 import javax.faces.component.visit.VisitCallback;
41 import javax.faces.component.visit.VisitContext;
42 import javax.faces.component.visit.VisitResult;
43 import javax.faces.context.FacesContext;
44 import javax.faces.render.Renderer;
45
46 import org.apache.myfaces.trinidad.bean.FacesBean;
47 import org.apache.myfaces.trinidad.component.UIXComponent;
48 import org.apache.myfaces.trinidad.context.Agent;
49 import org.apache.myfaces.trinidad.context.PartialPageContext;
50 import org.apache.myfaces.trinidad.context.RenderingContext;
51 import org.apache.myfaces.trinidad.context.RequestContext;
52 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
53
54
55
56
57
58
59 public class CoreRenderer extends Renderer
60 {
61
62 static public final char CHAR_UNDEFINED = (char) -1;
63 static public final int NO_CHILD_INDEX = -1;
64
65 protected CoreRenderer()
66 {
67 }
68
69
70
71
72
73
74
75
76
77
78
79 public Iterator<UIComponent> getRenderedFacetsAndChildren(
80 FacesContext facesContext,
81 UIComponent component)
82 {
83 return component.getFacetsAndChildren();
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 public VisitResult partialEncodeVisit(
106 VisitContext visitContext,
107 PartialPageContext partialContext,
108 UIComponent component,
109 VisitCallback callback)
110 {
111 if (partialContext.isPossiblePartialTarget(component.getId()) &&
112 partialContext.isPartialTarget(component.getClientId(visitContext.getFacesContext())))
113 {
114
115 return callback.visit(visitContext, component);
116 }
117 else
118 {
119
120
121
122 return VisitResult.ACCEPT;
123 }
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 public void setupEncodingContext(
141 FacesContext context,
142 RenderingContext rc,
143 UIComponent component)
144 {
145
146 if (component instanceof UIXComponent)
147 setupEncodingContext(context, rc, (UIXComponent)component);
148
149 }
150
151
152 @Deprecated
153 public void setupEncodingContext(
154 @SuppressWarnings("unused") FacesContext context,
155 @SuppressWarnings("unused") RenderingContext rc,
156 @SuppressWarnings("unused") UIXComponent component)
157 {
158 }
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 public void setupChildrenEncodingContext(
175 @SuppressWarnings("unused") FacesContext context,
176 @SuppressWarnings("unused") RenderingContext rc,
177 @SuppressWarnings("unused") UIComponent component)
178 {
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196 public void tearDownEncodingContext(
197 FacesContext context,
198 RenderingContext rc,
199 UIComponent component)
200 {
201
202 if (component instanceof UIXComponent)
203 tearDownEncodingContext(context, rc, (UIXComponent)component);
204 }
205
206
207
208
209
210
211
212
213
214
215
216 public boolean visitChildrenForEncoding(
217 UIXComponent component,
218 VisitContext visitContext,
219 VisitCallback callback)
220 {
221
222 Iterator<UIComponent> kids = getRenderedFacetsAndChildren(
223 visitContext.getFacesContext(), component);
224
225 while (kids.hasNext())
226 {
227
228 if (kids.next().visitTree(visitContext, callback))
229 {
230 return true;
231 }
232 }
233
234 return false;
235 }
236
237
238 @Deprecated
239 public void tearDownEncodingContext(
240 @SuppressWarnings("unused") FacesContext context,
241 @SuppressWarnings("unused") RenderingContext rc,
242 @SuppressWarnings("unused") UIXComponent component)
243 {
244 }
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261 public void tearDownChildrenEncodingContext(
262 @SuppressWarnings("unused") FacesContext context,
263 @SuppressWarnings("unused") RenderingContext rc,
264 @SuppressWarnings("unused") UIComponent component)
265 {
266 }
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281 @Override
282 public final void decode(
283 FacesContext facesContext,
284 UIComponent component)
285 {
286 FacesBean facesBean = getFacesBean(component);
287 String clientId = null;
288 if (facesBean != null)
289 {
290 clientId = decodeBehaviors(facesContext, component, facesBean);
291 }
292 decode(facesContext, component, facesBean, clientId);
293 }
294
295
296
297
298
299
300
301
302
303
304
305 protected void decode(
306 @SuppressWarnings("unused") FacesContext facesContext,
307 @SuppressWarnings("unused") UIComponent component,
308 @SuppressWarnings("unused") FacesBean facesBean,
309 @SuppressWarnings("unused") String clientId)
310 {
311
312 }
313
314
315
316
317
318
319
320
321 static public String toString(Object o)
322 {
323 if (o == null)
324 return null;
325 return o.toString();
326 }
327
328
329
330
331 static public String toResourceUri(FacesContext fc, Object o)
332 {
333 if (o == null)
334 return null;
335
336 String uri = o.toString();
337
338
339
340
341
342
343 if (uri.length() == 0)
344 {
345 return null;
346 }
347
348
349
350
351
352 if (uri.contains(ResourceHandler.RESOURCE_IDENTIFIER))
353 {
354 return uri;
355 }
356
357
358 if (uri.startsWith("//"))
359 {
360 return uri.substring(1);
361 }
362 else
363 {
364
365
366
367 return fc.getApplication().getViewHandler().getResourceURL(fc, uri);
368 }
369 }
370
371
372
373
374 static public String toActionUri(FacesContext fc, Object o)
375 {
376 if (o == null)
377 return null;
378
379 String uri = o.toString();
380
381
382 if (uri.startsWith("//"))
383 {
384 return uri.substring(1);
385 }
386 else
387 {
388 return fc.getApplication().getViewHandler().getActionURL(fc, uri);
389 }
390 }
391
392
393
394
395
396 @Deprecated
397 static public String toUri(Object o)
398 {
399 return toResourceUri(FacesContext.getCurrentInstance(),o);
400 }
401
402
403
404
405
406
407 static public int toInt(Object o)
408 {
409 return ((Number) o).intValue();
410 }
411
412
413
414
415
416
417 static public long toLong(Object o)
418 {
419 return ((Number) o).longValue();
420 }
421
422
423
424
425
426 static public char toChar(Object o)
427 {
428 if (o == null)
429 return CHAR_UNDEFINED;
430
431 char c;
432 if (o instanceof Character)
433 {
434 c = ((Character) o).charValue();
435 }
436 else
437 {
438
439
440 CharSequence cs;
441 if (o instanceof CharSequence)
442 {
443 cs = (CharSequence) o;
444 }
445 else
446 {
447 cs = o.toString();
448 }
449
450 if (cs.length() == 0)
451 c = CHAR_UNDEFINED;
452 else
453 c = cs.charAt(0);
454 }
455
456
457
458 if (c == '\u0000')
459 c = CHAR_UNDEFINED;
460
461 return c;
462 }
463
464 @Override
465 public final void encodeBegin(
466 FacesContext context,
467 UIComponent component
468 ) throws IOException
469 {
470 if (!getRendersChildren())
471 {
472 RenderingContext rc = RenderingContext.getCurrentInstance();
473 if (rc == null)
474 throw new IllegalStateException(_LOG.getMessage(
475 "NO_RENDERINGCONTEXT"));
476
477 FacesBean bean = getFacesBean(component);
478
479 beforeEncode(context, rc, component, bean);
480 encodeBegin(context, rc, component, bean);
481 }
482 }
483
484 @Override
485 public final void encodeChildren(
486 FacesContext context,
487 UIComponent component)
488 {
489
490
491 }
492
493 @Override
494 public final void encodeEnd(
495 FacesContext context,
496 UIComponent component
497 ) throws IOException
498 {
499 RenderingContext rc = RenderingContext.getCurrentInstance();
500 if (rc == null)
501 throw new IllegalStateException(_LOG.getMessage(
502 "NO_RENDERINGCONTEXT"));
503
504 FacesBean bean = getFacesBean(component);
505 RuntimeException re = null;
506 try
507 {
508 if (getRendersChildren())
509 {
510 beforeEncode(context, rc, component, bean);
511 encodeAll(context, rc, component, bean);
512 }
513 else
514 {
515 encodeEnd(context, rc, component, bean);
516 }
517 }
518 catch (RuntimeException ex)
519 {
520 re = ex;
521 }
522 finally
523 {
524 try
525 {
526 afterEncode(context, rc, component, bean);
527 }
528 catch (RuntimeException ex)
529 {
530 if (re == null)
531 {
532 throw ex;
533 }
534 _LOG.warning(ex);
535 }
536
537 if (re != null)
538 {
539 throw re;
540 }
541 }
542 }
543
544
545
546
547
548 protected void encodeBegin(
549 FacesContext context,
550 RenderingContext rc,
551 UIComponent component,
552 FacesBean bean
553 ) throws IOException
554 {
555 if (getRendersChildren())
556 throw new IllegalStateException();
557 }
558
559
560
561
562
563
564
565
566 protected final void encodeComponentResources(
567 FacesContext context,
568 String target
569 ) throws IOException
570 {
571 if(target != null)
572 {
573 UIViewRoot viewRoot = context.getViewRoot();
574 for(UIComponent componentResource : viewRoot.getComponentResources(context, target))
575 {
576 componentResource.encodeAll(context);
577 }
578 }
579 }
580
581
582
583
584
585 protected void encodeEnd(
586 FacesContext context,
587 RenderingContext rc,
588 UIComponent component,
589 FacesBean bean
590 ) throws IOException
591 {
592 if (getRendersChildren())
593 throw new IllegalStateException();
594 }
595
596
597
598
599
600 protected void encodeAll(
601 FacesContext context,
602 RenderingContext rc,
603 UIComponent component,
604 FacesBean bean
605 ) throws IOException
606 {
607 if (!getRendersChildren())
608 throw new IllegalStateException();
609 }
610
611
612
613
614
615
616
617 @SuppressWarnings("unchecked")
618 protected void encodeChild(
619 FacesContext context,
620 UIComponent child
621 ) throws IOException
622 {
623 assert(child.isRendered());
624 child.encodeAll(context);
625 }
626
627 @SuppressWarnings("unchecked")
628 protected void encodeAllChildren(
629 FacesContext context,
630 UIComponent component
631 ) throws IOException
632 {
633 int childCount = component.getChildCount();
634 if (childCount == 0)
635 return;
636
637 for (UIComponent child : (List<UIComponent>)component.getChildren())
638 {
639 if (child.isRendered())
640 {
641 encodeChild(context, child);
642 }
643 }
644 }
645
646 protected void delegateRenderer(
647 FacesContext context,
648 RenderingContext rc,
649 UIComponent component,
650 FacesBean bean,
651 CoreRenderer renderer
652 ) throws IOException
653 {
654 if (renderer.getRendersChildren())
655 {
656 renderer.encodeAll(context, rc, component, bean);
657 }
658 else
659 {
660 throw new IllegalStateException();
661 }
662 }
663
664 protected void delegateRendererBegin(
665 FacesContext context,
666 RenderingContext rc,
667 UIComponent component,
668 FacesBean bean,
669 CoreRenderer renderer
670 ) throws IOException
671 {
672 if (renderer.getRendersChildren())
673 {
674 throw new IllegalStateException();
675 }
676 else
677 {
678 renderer.encodeBegin(context, rc, component, bean);
679 }
680 }
681
682 protected void delegateRendererEnd(
683 FacesContext context,
684 RenderingContext rc,
685 UIComponent component,
686 FacesBean bean,
687 CoreRenderer renderer
688 ) throws IOException
689 {
690 if (renderer.getRendersChildren())
691 {
692 throw new IllegalStateException();
693 }
694 else
695 {
696 renderer.encodeEnd(context, rc, component, bean);
697 }
698 }
699
700
701
702
703 protected void renderId(
704 FacesContext context,
705 UIComponent component
706 ) throws IOException
707 {
708 if (shouldRenderId(context, component))
709 {
710 String clientId = getClientId(context, component);
711 context.getResponseWriter().writeAttribute("id", clientId, "id");
712 }
713 }
714
715
716
717
718
719 protected String getClientId(
720 FacesContext context,
721 UIComponent component)
722 {
723 return component.getClientId(context);
724 }
725
726
727
728
729
730
731 protected boolean shouldRenderId(
732 FacesContext context,
733 UIComponent component)
734 {
735 String id = component.getId();
736
737
738 if (id == null)
739 return false;
740
741
742 if (id.startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
743 return false;
744
745 return true;
746 }
747
748 protected boolean skipDecode(
749 FacesContext context)
750 {
751 return false;
752 }
753
754 protected FacesBean getFacesBean(
755 UIComponent component)
756 {
757 return ((UIXComponent) component).getFacesBean();
758 }
759
760 static protected final Object getRenderingProperty(
761 RenderingContext rc,
762 Object key)
763 {
764 return rc.getProperties().get(key);
765 }
766
767 static protected final Object setRenderingProperty(
768 RenderingContext rc,
769 Object key,
770 Object value)
771 {
772 return rc.getProperties().put(key, value);
773 }
774
775
776
777
778 static public UIComponent getFacet(
779 UIComponent component,
780 String name)
781 {
782 UIComponent facet = component.getFacet(name);
783 if ((facet == null) || !facet.isRendered())
784 return null;
785
786 return facet;
787 }
788
789
790
791
792
793 @SuppressWarnings("unchecked")
794 static public boolean hasRenderedChildren(
795 UIComponent component)
796 {
797 int count = component.getChildCount();
798 if (count == 0)
799 return false;
800
801 for(UIComponent child : (List<UIComponent>)component.getChildren())
802 {
803 if (child.isRendered())
804 {
805 return true;
806 }
807 }
808
809 return false;
810 }
811
812
813
814
815 @SuppressWarnings("unchecked")
816 static public int getRenderedChildCount(
817 UIComponent component)
818 {
819 int count = component.getChildCount();
820 if (count == 0)
821 return 0;
822
823 int total = 0;
824 for(UIComponent child : (List<UIComponent>)component.getChildren())
825 {
826 if (child.isRendered())
827 {
828 total++;
829 }
830 }
831
832 return total;
833 }
834
835
836
837
838
839
840
841 public static int getNextRenderedChildIndex(
842 List<UIComponent> components,
843 int afterChildIndex
844 )
845 {
846 int childIndex = afterChildIndex + 1;
847 Iterator<UIComponent> iter = components.listIterator(childIndex);
848 for(; iter.hasNext(); childIndex++)
849 {
850 if(iter.next().isRendered())
851 {
852 return childIndex;
853 }
854 }
855
856 return NO_CHILD_INDEX;
857 }
858
859
860
861
862
863 static public boolean isDesktop(RenderingContext rc)
864 {
865 return (Agent.TYPE_DESKTOP.equals(rc.getAgent().getType()));
866 }
867
868 static public boolean isPDA(RenderingContext rc)
869 {
870 return (Agent.TYPE_PDA.equals(rc.getAgent().getType()));
871 }
872
873 static public boolean isIE(RenderingContext rc)
874 {
875 return (Agent.AGENT_IE.equals(rc.getAgent().getAgentName()));
876 }
877
878 static public boolean isKonqueror(RenderingContext rc)
879 {
880 return (Agent.AGENT_KONQUEROR.equals(rc.getAgent().getAgentName()));
881 }
882
883 static public boolean isGecko(RenderingContext rc)
884 {
885 return (Agent.AGENT_GECKO.equals(rc.getAgent().getAgentName()));
886 }
887
888 static public boolean isWebKit(RenderingContext rc)
889 {
890 return (Agent.AGENT_WEBKIT.equals(rc.getAgent().getAgentName()));
891 }
892
893 static public boolean isOpera(RenderingContext rc)
894 {
895 return (Agent.AGENT_OPERA.equals(rc.getAgent().getAgentName()));
896 }
897
898 static public boolean isIPhone(RenderingContext rc)
899 {
900 return (Agent.PLATFORM_IPHONE.equals(rc.getAgent().getPlatformName()));
901 }
902
903 static public boolean isGenericPDA(RenderingContext rc)
904 {
905 return (Agent.PLATFORM_GENERICPDA.equals(rc.getAgent().getPlatformName()));
906 }
907
908
909
910
911
912
913 static public boolean isNokiaS60(RenderingContext rc)
914 {
915 return (Agent.PLATFORM_NOKIA_S60.equals(rc.getAgent().getPlatformName()));
916 }
917
918 static public boolean isInaccessibleMode(RenderingContext rc)
919 {
920 return (rc.getAccessibilityMode() ==
921 RequestContext.Accessibility.INACCESSIBLE);
922 }
923
924 static public boolean isScreenReaderMode(RenderingContext rc)
925 {
926 return (rc.getAccessibilityMode() ==
927 RequestContext.Accessibility.SCREEN_READER);
928 }
929
930
931
932
933
934
935
936
937
938
939
940 protected void beforeEncode(
941 FacesContext context,
942 RenderingContext rc,
943 UIComponent component,
944 FacesBean bean)
945 {
946 setupEncodingContext(context, rc, component);
947 }
948
949
950
951
952
953
954
955 protected void afterEncode(
956 FacesContext context,
957 RenderingContext rc,
958 UIComponent component,
959 FacesBean bean)
960 {
961 tearDownEncodingContext(context, rc, component);
962 }
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978 protected final String decodeBehaviors(
979 FacesContext facesContext,
980 UIComponent component,
981 FacesBean bean)
982 {
983 if (!(component instanceof ClientBehaviorHolder))
984 {
985 return null;
986 }
987
988
989
990 Map<String, List<ClientBehavior>> behaviorsMap = ((ClientBehaviorHolder)component).getClientBehaviors();
991 if (behaviorsMap.isEmpty())
992 {
993 return null;
994 }
995
996
997 Map<String, String> requestParams = facesContext.getExternalContext().getRequestParameterMap();
998 String event = requestParams.get(_BEHAVIOR_EVENT_KEY);
999 if (event == null)
1000 {
1001 return null;
1002 }
1003
1004
1005 List<ClientBehavior> behaviors = behaviorsMap.get(event);
1006 if (behaviors == null || behaviors.isEmpty())
1007 {
1008 return null;
1009 }
1010
1011
1012 String clientId = component.getClientId(facesContext);
1013 String sourceClientId = requestParams.get("javax.faces.source");
1014 if (clientId.equals(sourceClientId))
1015 {
1016
1017 for (ClientBehavior behavior: behaviors)
1018 {
1019 behavior.decode(facesContext, component);
1020 }
1021 }
1022
1023 return clientId;
1024 }
1025
1026
1027
1028
1029
1030
1031
1032 public static Collection<ClientBehaviorContext.Parameter> getBehaviorParameters(
1033 UIComponent component)
1034 {
1035 int childCount = component.getChildCount();
1036 if (childCount > 0)
1037 {
1038 List<ClientBehaviorContext.Parameter> list = null;
1039 for (UIComponent child : component.getChildren())
1040 {
1041 if (!(child instanceof UIParameter)) { continue; }
1042
1043 if (list == null)
1044 {
1045
1046 list = new ArrayList<ClientBehaviorContext.Parameter>(childCount);
1047 }
1048 UIParameter param = (UIParameter) child;
1049 list.add(new ClientBehaviorContext.Parameter(param.getName(), param.getValue()));
1050 }
1051
1052 if (list != null)
1053 {
1054 return list;
1055 }
1056 }
1057
1058 return Collections.<ClientBehaviorContext.Parameter>emptyList();
1059 }
1060
1061 protected void renderEncodedActionURI(
1062 FacesContext context,
1063 String name,
1064 Object value) throws IOException
1065 {
1066 if (value != null)
1067 {
1068 value = context.getExternalContext().encodeActionURL(value.toString());
1069 context.getResponseWriter().writeURIAttribute(name, value, null);
1070 }
1071 }
1072
1073 protected void renderEncodedResourceURI(
1074 FacesContext context,
1075 String name,
1076 Object value) throws IOException
1077 {
1078 if (value != null)
1079 {
1080 value = context.getExternalContext().encodeResourceURL(value.toString());
1081 context.getResponseWriter().writeURIAttribute(name, value, null);
1082 }
1083 }
1084
1085
1086
1087
1088
1089
1090
1091
1092 static public void renderStyleClass(
1093 FacesContext context,
1094 RenderingContext rc,
1095 String styleClass) throws IOException
1096 {
1097 if (styleClass != null)
1098 {
1099 String compressedStyleClass = rc.getStyleClass(styleClass);
1100 context.getResponseWriter().writeAttribute("class", compressedStyleClass, null);
1101
1102 if (rc.isDesignTime())
1103 context.getResponseWriter().writeAttribute("rawClass", styleClass, null);
1104 }
1105 }
1106
1107
1108
1109
1110
1111
1112 static public void renderStyleClasses(
1113 FacesContext context,
1114 RenderingContext rc,
1115 String[] styleClasses) throws IOException
1116 {
1117 int length = styleClasses.length;
1118 if (length == 0)
1119 return;
1120
1121 String value;
1122
1123 if (length == 1)
1124 {
1125 value = rc.getStyleClass(styleClasses[0]);
1126 }
1127
1128 else
1129 {
1130
1131
1132
1133
1134 StringBuilder builder =
1135 new StringBuilder((_COMPRESSED_LENGTH + 1) * length);
1136 for (int i = 0; i < length; i++)
1137 {
1138 if (styleClasses[i] != null)
1139 {
1140 String styleClass = rc.getStyleClass(styleClasses[i]);
1141 if (styleClass != null)
1142 {
1143 if (builder.length() != 0)
1144 builder.append(' ');
1145 builder.append(styleClass);
1146 }
1147 }
1148 }
1149
1150 if (builder.length() == 0)
1151 value = null;
1152 else
1153 value = builder.toString();
1154 }
1155
1156 context.getResponseWriter().writeAttribute("class", value, null);
1157
1158 if (rc.isDesignTime())
1159 {
1160 StringBuilder builder = new StringBuilder();
1161 for (int i = 0; i < length; i++)
1162 {
1163 if (styleClasses[i] != null)
1164 {
1165 String styleClass = styleClasses[i];
1166 if (styleClass != null)
1167 {
1168 if (builder.length() != 0)
1169 builder.append(' ');
1170 builder.append(styleClass);
1171 }
1172 }
1173 }
1174
1175 if (builder.length() > 0)
1176 context.getResponseWriter().writeAttribute("rawClass", builder.toString(), null);
1177 }
1178
1179 }
1180
1181
1182 private static final int _COMPRESSED_LENGTH = 4;
1183
1184 private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
1185 CoreRenderer.class);
1186 private static final String _BEHAVIOR_EVENT_KEY = "javax.faces.behavior.event";
1187 }