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;
20
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.Writer;
24 import java.net.URL;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Locale;
28 import java.util.Map;
29 import java.util.logging.Level;
30 import java.util.logging.Logger;
31
32 import javax.el.ELException;
33 import javax.faces.FacesException;
34 import javax.faces.application.ProjectStage;
35 import javax.faces.application.StateManager;
36 import javax.faces.application.ViewHandler;
37 import javax.faces.component.UIViewRoot;
38 import javax.faces.context.ExternalContext;
39 import javax.faces.context.FacesContext;
40 import javax.faces.context.ResponseWriter;
41 import javax.faces.render.RenderKit;
42 import javax.faces.view.facelets.ResourceResolver;
43 import javax.faces.view.facelets.TagDecorator;
44 import javax.servlet.ServletRequest;
45 import javax.servlet.ServletResponse;
46 import javax.servlet.http.HttpServletRequest;
47 import javax.servlet.http.HttpServletResponse;
48
49 import org.apache.myfaces.view.facelets.compiler.Compiler;
50 import org.apache.myfaces.view.facelets.compiler.SAXCompiler;
51 import org.apache.myfaces.view.facelets.compiler.TagLibraryConfig;
52 import org.apache.myfaces.view.facelets.impl.DefaultFaceletFactory;
53 import org.apache.myfaces.view.facelets.impl.DefaultResourceResolver;
54 import org.apache.myfaces.view.facelets.tag.TagLibrary;
55 import org.apache.myfaces.view.facelets.tag.ui.UIDebug;
56 import org.apache.myfaces.view.facelets.util.ReflectionUtil;
57
58
59
60
61
62
63
64
65 @Deprecated
66 public class FaceletViewHandler extends ViewHandler
67 {
68
69
70 protected final static Logger log = Logger.getLogger(FaceletViewHandler.class.getName());
71
72 public final static long DEFAULT_REFRESH_PERIOD = 2;
73 public final static long DEFAULT_REFRESH_PERIOD_PRODUCTION = -1;
74
75 public final static String PARAM_REFRESH_PERIOD = "facelets.REFRESH_PERIOD";
76
77
78
79
80
81
82 public final static String PARAM_REFRESH_PERIO = PARAM_REFRESH_PERIOD;
83
84 public final static String PARAM_SKIP_COMMENTS = "facelets.SKIP_COMMENTS";
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 public final static String PARAM_VIEW_MAPPINGS = "facelets.VIEW_MAPPINGS";
112
113 public final static String PARAM_LIBRARIES = "facelets.LIBRARIES";
114
115 public final static String PARAM_DECORATORS = "facelets.DECORATORS";
116
117 public final static String PARAM_DEVELOPMENT = "facelets.DEVELOPMENT";
118
119 public final static String PARAM_RESOURCE_RESOLVER = "facelets.RESOURCE_RESOLVER";
120
121 public final static String PARAM_BUILD_BEFORE_RESTORE = "facelets.BUILD_BEFORE_RESTORE";
122
123 public final static String PARAM_BUFFER_SIZE = "facelets.BUFFER_SIZE";
124
125 private final static String STATE_KEY = "~facelets.VIEW_STATE~";
126
127 private final static int STATE_KEY_LEN = STATE_KEY.length();
128
129 private final ViewHandler parent;
130
131 private boolean developmentMode = false;
132
133 private boolean buildBeforeRestore = false;
134
135 private int bufferSize;
136
137 private String defaultSuffix;
138
139 private FaceletFactory faceletFactory;
140
141
142 private String[] extensionsArray;
143
144
145 private String[] prefixesArray;
146
147
148
149
150 public FaceletViewHandler(ViewHandler parent)
151 {
152 this.parent = parent;
153 }
154
155
156
157
158 protected void initialize(FacesContext context)
159 {
160 synchronized (this)
161 {
162 if (this.faceletFactory == null)
163 {
164 log.fine("Initializing");
165 Compiler c = this.createCompiler();
166 this.initializeCompiler(c);
167 this.faceletFactory = this.createFaceletFactory(c);
168
169 this.initializeMappings(context);
170 this.initializeMode(context);
171 this.initializeBuffer(context);
172
173 log.fine("Initialization Successful");
174 }
175 }
176 }
177
178 private void initializeMode(FacesContext context)
179 {
180 ExternalContext external = context.getExternalContext();
181 String param = external.getInitParameter(PARAM_DEVELOPMENT);
182 this.developmentMode = "true".equals(param);
183
184 String restoreMode = external.getInitParameter(PARAM_BUILD_BEFORE_RESTORE);
185 this.buildBeforeRestore = "true".equals(restoreMode);
186 }
187
188 private void initializeBuffer(FacesContext context)
189 {
190 ExternalContext external = context.getExternalContext();
191 String param = external.getInitParameter(PARAM_BUFFER_SIZE);
192 this.bufferSize = (param != null && !"".equals(param)) ? Integer.parseInt(param) : -1;
193 }
194
195
196
197
198 private void initializeMappings(FacesContext context)
199 {
200 ExternalContext external = context.getExternalContext();
201 String viewMappings = external.getInitParameter(PARAM_VIEW_MAPPINGS);
202 if ((viewMappings != null) && (viewMappings.length() > 0))
203 {
204 String[] mappingsArray = viewMappings.split(";");
205
206 List<String> extensionsList = new ArrayList<String>(mappingsArray.length);
207 List<String> prefixesList = new ArrayList<String>(mappingsArray.length);
208
209 for (int i = 0; i < mappingsArray.length; i++)
210 {
211 String mapping = mappingsArray[i].trim();
212 int mappingLength = mapping.length();
213 if (mappingLength <= 1)
214 {
215 continue;
216 }
217
218 if (mapping.charAt(0) == '*')
219 {
220 extensionsList.add(mapping.substring(1));
221 }
222 else if (mapping.charAt(mappingLength - 1) == '*')
223 {
224 prefixesList.add(mapping.substring(0, mappingLength - 1));
225 }
226 }
227
228 extensionsArray = new String[extensionsList.size()];
229 extensionsList.toArray(extensionsArray);
230
231 prefixesArray = new String[prefixesList.size()];
232 prefixesList.toArray(prefixesArray);
233 }
234 }
235
236 protected FaceletFactory createFaceletFactory(Compiler c)
237 {
238
239
240 FacesContext ctx = FacesContext.getCurrentInstance();
241 long refreshPeriod;
242
243 if(ctx.isProjectStage(ProjectStage.Production))
244 {
245 refreshPeriod = DEFAULT_REFRESH_PERIOD_PRODUCTION;
246 }
247 else
248 {
249 refreshPeriod = DEFAULT_REFRESH_PERIOD;
250 }
251
252 String userPeriod = ctx.getExternalContext().getInitParameter(PARAM_REFRESH_PERIOD);
253 if (userPeriod != null && userPeriod.length() > 0)
254 {
255 refreshPeriod = Long.parseLong(userPeriod);
256 }
257
258
259 ResourceResolver resolver = new DefaultResourceResolver();
260 String resolverName = ctx.getExternalContext().getInitParameter(PARAM_RESOURCE_RESOLVER);
261 if (resolverName != null && resolverName.length() > 0)
262 {
263 try
264 {
265 resolver = (ResourceResolver) ReflectionUtil.forName(resolverName).newInstance();
266 }
267 catch (Exception e)
268 {
269 throw new FacesException("Error Initializing ResourceResolver[" + resolverName + "]", e);
270 }
271 }
272
273
274 return new DefaultFaceletFactory(c, resolver, refreshPeriod);
275 }
276
277 protected Compiler createCompiler()
278 {
279 return new SAXCompiler();
280 }
281
282 protected void initializeCompiler(Compiler c)
283 {
284 FacesContext ctx = FacesContext.getCurrentInstance();
285 ExternalContext ext = ctx.getExternalContext();
286
287
288 String libParam = ext.getInitParameter(PARAM_LIBRARIES);
289 if (libParam != null)
290 {
291 libParam = libParam.trim();
292 String[] libs = libParam.split(";");
293 URL src;
294 TagLibrary libObj;
295 for (int i = 0; i < libs.length; i++)
296 {
297 try
298 {
299 src = ext.getResource(libs[i].trim());
300 if (src == null)
301 {
302 throw new FileNotFoundException(libs[i]);
303 }
304 libObj = TagLibraryConfig.create(ctx, src);
305 c.addTagLibrary(libObj);
306 log.fine("Successfully Loaded Library: " + libs[i]);
307 }
308 catch (IOException e)
309 {
310 log.log(Level.SEVERE, "Error Loading Library: " + libs[i], e);
311 }
312 }
313 }
314
315
316 String decParam = ext.getInitParameter(PARAM_DECORATORS);
317 if (decParam != null)
318 {
319 decParam = decParam.trim();
320 String[] decs = decParam.split(";");
321 TagDecorator decObj;
322 for (int i = 0; i < decs.length; i++)
323 {
324 try
325 {
326 decObj = (TagDecorator) ReflectionUtil.forName(decs[i]).newInstance();
327 c.addTagDecorator(decObj);
328 log.fine("Successfully Loaded Decorator: " + decs[i]);
329 }
330 catch (Exception e)
331 {
332 log.log(Level.SEVERE, "Error Loading Decorator: " + decs[i], e);
333 }
334 }
335 }
336
337
338 String skipParam = ext.getInitParameter(PARAM_SKIP_COMMENTS);
339 if (skipParam != null && "true".equals(skipParam))
340 {
341 c.setTrimmingComments(true);
342 }
343 }
344
345 public UIViewRoot restoreView(FacesContext context, String viewId)
346 {
347 if (UIDebug.debugRequest(context))
348 {
349 return new UIViewRoot();
350 }
351
352 if (!this.buildBeforeRestore || !handledByFacelets(viewId))
353 {
354 return this.parent.restoreView(context, viewId);
355 }
356
357 if (this.faceletFactory == null)
358 {
359 this.initialize(context);
360 }
361
362
363
364
365
366
367 ViewHandler outerViewHandler = context.getApplication().getViewHandler();
368 String renderKitId = outerViewHandler.calculateRenderKitId(context);
369
370 UIViewRoot viewRoot = createView(context, viewId);
371 context.setViewRoot(viewRoot);
372 try
373 {
374 this.buildView(context, viewRoot);
375 }
376 catch (IOException ioe)
377 {
378 log.log(Level.SEVERE, "Error Building View", ioe);
379 }
380 context.getApplication().getStateManager().restoreView(context, viewId, renderKitId);
381 return viewRoot;
382 }
383
384
385
386
387
388
389 protected ViewHandler getWrapped()
390 {
391 return this.parent;
392 }
393
394 protected ResponseWriter createResponseWriter(FacesContext context) throws IOException, FacesException
395 {
396 ExternalContext extContext = context.getExternalContext();
397 RenderKit renderKit = context.getRenderKit();
398
399
400 if (renderKit == null)
401 {
402 String id = context.getViewRoot().getRenderKitId();
403 throw new IllegalStateException("No render kit was available for id \"" + id + "\"");
404 }
405
406 ServletResponse response = (ServletResponse) extContext.getResponse();
407
408
409 if (this.bufferSize != -1)
410 {
411 response.setBufferSize(this.bufferSize);
412 }
413
414
415 String contentType = (String) context.getAttributes().get("facelets.ContentType");
416
417
418 String encoding = (String) context.getAttributes().get("facelets.Encoding");
419
420 ResponseWriter writer;
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465 protected String getResponseEncoding(FacesContext context, String orig)
466 {
467 String encoding = orig;
468
469
470 Map<Object, Object> m = context.getAttributes();
471 Map<String, Object> sm = context.getExternalContext().getSessionMap();
472
473
474 if (m.containsKey("facelets.Encoding"))
475 {
476 encoding = (String) m.get("facelets.Encoding");
477 if (log.isLoggable(Level.FINEST))
478 {
479 log.finest("Facelet specified alternate encoding '" + encoding + "'");
480 }
481 sm.put(CHARACTER_ENCODING_KEY, encoding);
482 }
483
484
485 Object request = context.getExternalContext().getRequest();
486 if (encoding == null && request instanceof ServletRequest)
487 {
488 encoding = ((ServletRequest) request).getCharacterEncoding();
489 }
490
491
492 if (encoding == null)
493 {
494 encoding = (String) sm.get(CHARACTER_ENCODING_KEY);
495 if (log.isLoggable(Level.FINEST))
496 {
497 log.finest("Session specified alternate encoding '" + encoding + "'");
498 }
499 }
500
501
502 if (encoding == null)
503 {
504 encoding = "UTF-8";
505 if (log.isLoggable(Level.FINEST))
506 {
507 log.finest("ResponseWriter created had a null CharacterEncoding, defaulting to UTF-8");
508 }
509 }
510
511 return encoding;
512 }
513
514
515
516
517
518
519
520
521 protected String getResponseContentType(FacesContext context, String orig)
522 {
523 String contentType = orig;
524
525
526 Map<Object, Object> m = context.getAttributes();
527 if (m.containsKey("facelets.ContentType"))
528 {
529 contentType = (String) m.get("facelets.ContentType");
530 if (log.isLoggable(Level.FINEST))
531 {
532 log.finest("Facelet specified alternate contentType '" + contentType + "'");
533 }
534 }
535
536
537 if (contentType == null)
538 {
539 contentType = "text/html";
540 if (log.isLoggable(Level.FINEST))
541 {
542 log.finest("ResponseWriter created had a null ContentType, defaulting to text/html");
543 }
544 }
545
546 return contentType;
547 }
548
549 protected void buildView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException
550 {
551
552 String renderedViewId = this.getRenderedViewId(context, viewToRender.getViewId());
553 viewToRender.setViewId(renderedViewId);
554
555 if (log.isLoggable(Level.FINE))
556 {
557 log.fine("Building View: " + renderedViewId);
558 }
559
560
561 Facelet f = null;
562 FaceletFactory.setInstance(this.faceletFactory);
563 try
564 {
565 f = this.faceletFactory.getFacelet(viewToRender.getViewId());
566 }
567 finally
568 {
569 FaceletFactory.setInstance(null);
570 }
571
572
573 long time = System.currentTimeMillis();
574 f.apply(context, viewToRender);
575 time = System.currentTimeMillis() - time;
576 if (log.isLoggable(Level.FINE))
577 {
578 log.fine("Took " + time + "ms to build view: " + viewToRender.getViewId());
579 }
580 }
581
582 public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException
583 {
584
585
586 if (this.faceletFactory == null)
587 {
588 this.initialize(context);
589 }
590
591
592 if (!viewToRender.isRendered())
593 {
594 return;
595 }
596
597
598 if (!handledByFacelets(viewToRender.getViewId()))
599 {
600 this.parent.renderView(context, viewToRender);
601 return;
602 }
603
604
605 if (log.isLoggable(Level.FINE))
606 {
607 log.fine("Rendering View: " + viewToRender.getViewId());
608 }
609
610 StateWriter stateWriter = null;
611 try
612 {
613
614
615
616
617
618
619
620 if (!this.buildBeforeRestore || viewToRender.getChildren().isEmpty())
621 {
622 this.buildView(context, viewToRender);
623 }
624
625
626 ResponseWriter origWriter = this.createResponseWriter(context);
627
628 ExternalContext extContext = context.getExternalContext();
629 Writer outputWriter = extContext.getResponseOutputWriter();
630
631
632
633
634 stateWriter = new StateWriter(outputWriter, this.bufferSize != -1 ? this.bufferSize : 1024);
635
636 ResponseWriter writer = origWriter.cloneWithWriter(stateWriter);
637 context.setResponseWriter(writer);
638
639
640 StateManager stateMgr = context.getApplication().getStateManager();
641 if (!stateMgr.isSavingStateInClient(context))
642 {
643 extContext.getSession(true);
644 }
645
646 long time = System.currentTimeMillis();
647
648
649 writer.startDocument();
650 viewToRender.encodeAll(context);
651 writer.endDocument();
652
653
654 writer.close();
655
656 boolean writtenState = stateWriter.isStateWritten();
657
658 if (writtenState)
659 {
660 String content = stateWriter.getAndResetBuffer();
661 int end = content.indexOf(STATE_KEY);
662
663
664 if (end >= 0)
665 {
666
667 Object stateObj = stateMgr.saveSerializedView(context);
668 String stateStr;
669 if (stateObj == null)
670 {
671 stateStr = null;
672 }
673 else
674 {
675 stateMgr.writeState(context, (StateManager.SerializedView) stateObj);
676 stateStr = stateWriter.getAndResetBuffer();
677 }
678
679 int start = 0;
680
681 while (end != -1)
682 {
683 origWriter.write(content, start, end - start);
684 if (stateStr != null)
685 {
686 origWriter.write(stateStr);
687 }
688 start = end + STATE_KEY_LEN;
689 end = content.indexOf(STATE_KEY, start);
690 }
691 origWriter.write(content, start, content.length() - start);
692
693
694 }
695 else
696 {
697 origWriter.write(content);
698 }
699 }
700
701 time = System.currentTimeMillis() - time;
702 if (log.isLoggable(Level.FINE))
703 {
704 log.fine("Took " + time + "ms to render view: " + viewToRender.getViewId());
705 }
706
707 }
708 catch (FileNotFoundException fnfe)
709 {
710 this.handleFaceletNotFound(context, viewToRender.getViewId());
711 }
712 catch (Exception e)
713 {
714 this.handleRenderException(context, e);
715 }
716 finally
717 {
718 if (stateWriter != null)
719 {
720 stateWriter.release();
721 }
722 }
723 }
724
725 protected void handleRenderException(FacesContext context, Exception e)
726 throws IOException, ELException, FacesException
727 {
728 UIViewRoot root = context.getViewRoot();
729 StringBuffer sb = new StringBuffer(64);
730 sb.append("Error Rendering View");
731 if (root != null)
732 {
733 sb.append('[');
734 sb.append(root.getViewId());
735 sb.append(']');
736 }
737
738 log.log(Level.SEVERE, sb.toString(), e);
739
740
741 if (e instanceof RuntimeException)
742 {
743 throw (RuntimeException) e;
744 }
745 else if (e instanceof IOException)
746 {
747 throw (IOException) e;
748 }
749 else
750 {
751 throw new FacesException(e.getMessage(), e);
752 }
753 }
754
755 protected void handleFaceletNotFound(FacesContext context, String viewId) throws FacesException, IOException
756 {
757 String actualId = this.getActionURL(context, viewId);
758 Object respObj = context.getExternalContext().getResponse();
759 if (respObj instanceof HttpServletResponse)
760 {
761 HttpServletResponse respHttp = (HttpServletResponse) respObj;
762 respHttp.sendError(HttpServletResponse.SC_NOT_FOUND, actualId);
763 context.responseComplete();
764 }
765 }
766
767
768
769
770 private boolean handledByFacelets(String viewId)
771 {
772
773
774 if ((extensionsArray == null) && (prefixesArray == null))
775 {
776 return true;
777 }
778
779 if (extensionsArray != null)
780 {
781 for (int i = 0; i < extensionsArray.length; i++)
782 {
783 String extension = extensionsArray[i];
784 if (viewId.endsWith(extension))
785 {
786 return true;
787 }
788 }
789 }
790
791 if (prefixesArray != null)
792 {
793 for (int i = 0; i < prefixesArray.length; i++)
794 {
795 String prefix = prefixesArray[i];
796 if (viewId.startsWith(prefix))
797 {
798 return true;
799 }
800 }
801 }
802
803 return false;
804 }
805
806 public String getDefaultSuffix(FacesContext context) throws FacesException
807 {
808 if (this.defaultSuffix == null)
809 {
810 ExternalContext extCtx = context.getExternalContext();
811 String viewSuffix = extCtx.getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME);
812 this.defaultSuffix = (viewSuffix != null) ? viewSuffix : ViewHandler.DEFAULT_SUFFIX;
813 }
814 return this.defaultSuffix;
815 }
816
817 protected String getRenderedViewId(FacesContext context, String actionId)
818 {
819 ExternalContext extCtx = context.getExternalContext();
820 String viewId = actionId;
821 if (extCtx.getRequestPathInfo() == null)
822 {
823 String viewSuffix = this.getDefaultSuffix(context);
824 viewId = new StringBuffer(viewId).replace(viewId.lastIndexOf('.'), viewId.length(), viewSuffix).toString();
825 }
826 if (log.isLoggable(Level.FINE))
827 {
828 log.fine("ActionId -> ViewId: " + actionId + " -> " + viewId);
829 }
830 return viewId;
831 }
832
833 public void writeState(FacesContext context) throws IOException
834 {
835 if (handledByFacelets(context.getViewRoot().getViewId()))
836 {
837
838 StateWriter.getCurrentInstance().writingState();
839
840
841
842
843 context.getResponseWriter().write(STATE_KEY);
844 }
845 else
846 {
847 this.parent.writeState(context);
848 }
849 }
850
851 public Locale calculateLocale(FacesContext context)
852 {
853 return this.parent.calculateLocale(context);
854 }
855
856 public String calculateRenderKitId(FacesContext context)
857 {
858 return this.parent.calculateRenderKitId(context);
859 }
860
861 public UIViewRoot createView(FacesContext context, String viewId)
862 {
863 if (UIDebug.debugRequest(context))
864 {
865 return new UIViewRoot();
866 }
867 return this.parent.createView(context, viewId);
868 }
869
870 public String getActionURL(FacesContext context, String viewId)
871 {
872 return this.parent.getActionURL(context, viewId);
873 }
874
875 public String getResourceURL(FacesContext context, String path)
876 {
877 return this.parent.getResourceURL(context, path);
878 }
879
880 protected static class NullWriter extends Writer
881 {
882
883 static final NullWriter Instance = new NullWriter();
884
885 public void write(char[] buffer)
886 {
887 }
888
889 public void write(char[] buffer, int off, int len)
890 {
891 }
892
893 public void write(String str)
894 {
895 }
896
897 public void write(int c)
898 {
899 }
900
901 public void write(String str, int off, int len)
902 {
903 }
904
905 public void close()
906 {
907 }
908
909 public void flush()
910 {
911 }
912 }
913 }