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