KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > facelets > FaceletViewHandler


1 /**
2  * Licensed under the Common Development and Distribution License,
3  * you may not use this file except in compliance with the License.
4  * You may obtain a copy of the License at
5  *
6  * http://www.sun.com/cddl/
7  *
8  * Unless required by applicable law or agreed to in writing, software
9  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */

14
15 package com.sun.facelets;
16
17 import java.io.FileNotFoundException JavaDoc;
18 import java.io.IOException JavaDoc;
19 import java.io.Writer JavaDoc;
20 import java.net.MalformedURLException JavaDoc;
21 import java.net.URL JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Locale JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.logging.Level JavaDoc;
29 import java.util.logging.Logger JavaDoc;
30
31 import javax.el.ELException;
32 import javax.faces.FacesException;
33 import javax.faces.application.StateManager;
34 import javax.faces.application.ViewHandler;
35 import javax.faces.component.UIComponent;
36 import javax.faces.component.UIViewRoot;
37 import javax.faces.context.ExternalContext;
38 import javax.faces.context.FacesContext;
39 import javax.faces.context.ResponseWriter;
40 import javax.faces.render.RenderKit;
41 import javax.portlet.PortletResponse;
42 import javax.servlet.ServletRequest JavaDoc;
43 import javax.servlet.ServletResponse JavaDoc;
44 import javax.servlet.http.HttpServletRequest JavaDoc;
45 import javax.servlet.http.HttpServletResponse JavaDoc;
46
47 import com.sun.facelets.compiler.Compiler;
48 import com.sun.facelets.compiler.SAXCompiler;
49 import com.sun.facelets.compiler.TagLibraryConfig;
50 import com.sun.facelets.impl.DefaultFaceletFactory;
51 import com.sun.facelets.impl.DefaultResourceResolver;
52 import com.sun.facelets.impl.ResourceResolver;
53 import com.sun.facelets.tag.TagDecorator;
54 import com.sun.facelets.tag.TagLibrary;
55 import com.sun.facelets.tag.jsf.ComponentSupport;
56 import com.sun.facelets.tag.ui.UIDebug;
57 import com.sun.facelets.util.DevTools;
58 import com.sun.facelets.util.FacesAPI;
59 import com.sun.facelets.util.FastWriter;
60 import com.sun.facelets.util.Resource;
61
62 /**
63  * ViewHandler implementation for Facelets
64  *
65  * @author Jacob Hookom
66  * @version $Id: FaceletViewHandler.java,v 1.49.2.6 2006/03/20 07:22:00 jhook
67  * Exp $
68  */

69 public class FaceletViewHandler extends ViewHandler {
70
71     protected final static Logger JavaDoc log = Logger
72             .getLogger("facelets.viewhandler");
73
74     public final static long DEFAULT_REFRESH_PERIOD = 2;
75
76     public final static String JavaDoc PARAM_REFRESH_PERIO = "facelets.REFRESH_PERIOD";
77
78     public final static String JavaDoc PARAM_SKIP_COMMENTS = "facelets.SKIP_COMMENTS";
79
80     /**
81      * Context initialization parameter for defining what viewIds should be
82      * handled by Facelets, and what should not. When left unset, all URLs will
83      * be handled by Facelets. When set, it must be a semicolon separated list
84      * of either extension mappings or prefix mappings. For example:
85      *
86      * <pre>
87      *
88      *
89      *
90      * &lt;context-param&gt;
91      * &lt;param-name&gt;facelets.VIEW_MAPPINGS&lt;/param-name&gt;
92      * &lt;param-value&gt;/demos/*; *.xhtml&lt;/param-value&gt;
93      * &lt;/context-param&gt;
94      *
95      *
96      *
97      * </pre>
98      *
99      * would use Facelets for processing all viewIds in the "/demos" directory
100      * or that end in .xhtml, and use the standard JSP engine for all other
101      * viewIds.
102      * <p>
103      * <strong>NOTE</strong>: when using this parameter, you need to use
104      * prefix-mapping for the <code>FacesServlet</code> (that is,
105      * <code>/faces/*</code>, not <code>*.jsf</code>).
106      * </p>
107      */

108     public final static String JavaDoc PARAM_VIEW_MAPPINGS = "facelets.VIEW_MAPPINGS";
109
110     public final static String JavaDoc PARAM_LIBRARIES = "facelets.LIBRARIES";
111
112     public final static String JavaDoc PARAM_DECORATORS = "facelets.DECORATORS";
113
114     public final static String JavaDoc PARAM_DEVELOPMENT = "facelets.DEVELOPMENT";
115
116     public final static String JavaDoc PARAM_RESOURCE_RESOLVER = "facelets.RESOURCE_RESOLVER";
117
118     public final static String JavaDoc PARAM_BUILD_BEFORE_RESTORE = "facelets.BUILD_BEFORE_RESTORE";
119
120     public final static String JavaDoc PARAM_BUFFER_SIZE = "facelets.BUFFER_SIZE";
121
122     private final static String JavaDoc STATE_KEY = "~facelets.VIEW_STATE~";
123
124     private final static int STATE_KEY_LEN = STATE_KEY.length();
125
126     private final static Object JavaDoc STATE_NULL = new Object JavaDoc();
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 JavaDoc defaultSuffix;
137
138     private FaceletFactory faceletFactory;
139
140     // Array of viewId extensions that should be handled by Facelets
141
private String JavaDoc[] extensionsArray;
142
143     // Array of viewId prefixes that should be handled by Facelets
144
private String JavaDoc[] prefixesArray;
145
146     /**
147      *
148      */

149     public FaceletViewHandler(ViewHandler parent) {
150         this.parent = parent;
151     }
152
153     /**
154      * Initialize the ViewHandler during its first request.
155      */

156     protected void initialize(FacesContext context) {
157         synchronized (this) {
158             if (this.faceletFactory == null) {
159                 log.fine("Initializing");
160                 Compiler JavaDoc c = this.createCompiler();
161                 this.initializeCompiler(c);
162                 this.faceletFactory = this.createFaceletFactory(c);
163
164                 this.initializeMappings(context);
165                 this.initializeMode(context);
166                 this.initializeBuffer(context);
167
168                 log.fine("Initialization Successful");
169             }
170         }
171     }
172
173     private void initializeMode(FacesContext context) {
174         ExternalContext external = context.getExternalContext();
175         String JavaDoc param = external.getInitParameter(PARAM_DEVELOPMENT);
176         this.developmentMode = "true".equals(param);
177
178         String JavaDoc restoreMode = external
179                 .getInitParameter(PARAM_BUILD_BEFORE_RESTORE);
180         this.buildBeforeRestore = "true".equals(restoreMode);
181     }
182
183     private void initializeBuffer(FacesContext context) {
184         ExternalContext external = context.getExternalContext();
185         String JavaDoc param = external.getInitParameter(PARAM_BUFFER_SIZE);
186         this.bufferSize = (param != null && !"".equals(param)) ? Integer
187                 .parseInt(param) : -1;
188     }
189
190     /**
191      * Initialize mappings, during the first request.
192      */

193     private void initializeMappings(FacesContext context) {
194         ExternalContext external = context.getExternalContext();
195         String JavaDoc viewMappings = external.getInitParameter(PARAM_VIEW_MAPPINGS);
196         if ((viewMappings != null) && (viewMappings.length() > 0)) {
197             String JavaDoc[] mappingsArray = viewMappings.split(";");
198
199             List JavaDoc extensionsList = new ArrayList JavaDoc(mappingsArray.length);
200             List JavaDoc prefixesList = new ArrayList JavaDoc(mappingsArray.length);
201
202             for (int i = 0; i < mappingsArray.length; i++) {
203                 String JavaDoc mapping = mappingsArray[i].trim();
204                 int mappingLength = mapping.length();
205                 if (mappingLength <= 1) {
206                     continue;
207                 }
208
209                 if (mapping.charAt(0) == '*') {
210                     extensionsList.add(mapping.substring(1));
211                 } else if (mapping.charAt(mappingLength - 1) == '*') {
212                     prefixesList.add(mapping.substring(0, mappingLength - 1));
213                 }
214             }
215
216             extensionsArray = new String JavaDoc[extensionsList.size()];
217             extensionsList.toArray(extensionsArray);
218
219             prefixesArray = new String JavaDoc[prefixesList.size()];
220             prefixesList.toArray(prefixesArray);
221         }
222     }
223
224     protected FaceletFactory createFaceletFactory(Compiler JavaDoc c) {
225
226         // refresh period
227
long refreshPeriod = DEFAULT_REFRESH_PERIOD;
228         FacesContext ctx = FacesContext.getCurrentInstance();
229         String JavaDoc userPeriod = ctx.getExternalContext().getInitParameter(
230                 PARAM_REFRESH_PERIO);
231         if (userPeriod != null && userPeriod.length() > 0) {
232             refreshPeriod = Long.parseLong(userPeriod);
233         }
234
235         // resource resolver
236
ResourceResolver resolver = new DefaultResourceResolver();
237         String JavaDoc resolverName = ctx.getExternalContext().getInitParameter(
238                 PARAM_RESOURCE_RESOLVER);
239         if (resolverName != null && resolverName.length() > 0) {
240             try {
241                 resolver = (ResourceResolver) Class.forName(resolverName, true,
242                         Thread.currentThread().getContextClassLoader())
243                         .newInstance();
244             } catch (Exception JavaDoc e) {
245                 throw new FacesException("Error Initializing ResourceResolver["
246                         + resolverName + "]", e);
247             }
248         }
249
250         // Resource.getResourceUrl(ctx,"/")
251
return new DefaultFaceletFactory(c, resolver, refreshPeriod);
252     }
253
254     protected Compiler JavaDoc createCompiler() {
255         return new SAXCompiler();
256     }
257
258     protected void initializeCompiler(Compiler JavaDoc c) {
259         FacesContext ctx = FacesContext.getCurrentInstance();
260         ExternalContext ext = ctx.getExternalContext();
261
262         // load libraries
263
String JavaDoc libParam = ext.getInitParameter(PARAM_LIBRARIES);
264         if (libParam != null) {
265             libParam = libParam.trim();
266             String JavaDoc[] libs = libParam.split(";");
267             URL JavaDoc src;
268             TagLibrary libObj;
269             for (int i = 0; i < libs.length; i++) {
270                 try {
271                     src = ext.getResource(libs[i].trim());
272                     if (src == null) {
273                         throw new FileNotFoundException JavaDoc(libs[i]);
274                     }
275                     libObj = TagLibraryConfig.create(src);
276                     c.addTagLibrary(libObj);
277                     log.fine("Successfully Loaded Library: " + libs[i]);
278                 } catch (IOException JavaDoc e) {
279                     log.log(Level.SEVERE, "Error Loading Library: " + libs[i],
280                             e);
281                 }
282             }
283         }
284
285         // load decorators
286
String JavaDoc decParam = ext.getInitParameter(PARAM_DECORATORS);
287         if (decParam != null) {
288             decParam = decParam.trim();
289             String JavaDoc[] decs = decParam.split(";");
290             TagDecorator decObj;
291             for (int i = 0; i < decs.length; i++) {
292                 try {
293                     decObj = (TagDecorator) Class.forName(decs[i])
294                             .newInstance();
295                     c.addTagDecorator(decObj);
296                     log.fine("Successfully Loaded Decorator: " + decs[i]);
297                 } catch (Exception JavaDoc e) {
298                     log.log(Level.SEVERE,
299                             "Error Loading Decorator: " + decs[i], e);
300                 }
301             }
302         }
303
304         // skip params?
305
String JavaDoc skipParam = ext.getInitParameter(PARAM_SKIP_COMMENTS);
306         if (skipParam != null && "true".equals(skipParam)) {
307             c.setTrimmingComments(true);
308         }
309     }
310
311     public UIViewRoot restoreView(FacesContext context, String JavaDoc viewId) {
312 System.out.println("FaceletViewHandler.restoreView() viewId: " + viewId);
313         if (UIDebug.debugRequest(context)) {
314             return new UIViewRoot();
315         }
316
317         if (!this.buildBeforeRestore || !handledByFacelets(viewId)) {
318             UIViewRoot root = this.parent.restoreView(context, viewId);
319 System.out.println("FaceletViewHandler.restoreView() !this.buildBeforeRestore || !handledByFacelets(viewId) -> parent.restoreView: " + (root == null ? "null" : Integer.toString(root.getChildCount())));
320             return root;
321         }
322
323         if (this.faceletFactory == null) {
324             this.initialize(context);
325         }
326
327         // In JSF 1.2, restoreView() will only be called on postback.
328
// But in JSF 1.1, it will be called for an initial request too,
329
// in which case we must return null in order to fall through
330
// to createView()
331
System.out.println("FaceletViewHandler.restoreView() FacesAPI.version: " + FacesAPI.getVersion() + " isPostback11: " + isPostback11(context));
332         if (FacesAPI.getVersion() < 12) {
333             if (!isPostback11(context)) {
334 System.out.println("FaceletViewHandler.restoreView() FacesAPI.version < 12 && !isPostback11 -> return null");
335                 return null;
336             }
337         }
338
339         ViewHandler outerViewHandler = context.getApplication()
340                 .getViewHandler();
341         String JavaDoc renderKitId = outerViewHandler.calculateRenderKitId(context);
342
343 System.out.println("FaceletViewHandler.restoreView() Before createView");
344         UIViewRoot viewRoot = createView(context, viewId);
345 System.out.println("FaceletViewHandler.restoreView() After createView viewRoot: " + (viewRoot == null ? "null" : Integer.toString(viewRoot.getChildCount())));
346         context.setViewRoot(viewRoot);
347         try {
348 System.out.println("FaceletViewHandler.restoreView() Before buildView");
349             this.buildView(context, viewRoot);
350 System.out.println("FaceletViewHandler.restoreView() After buildView viewRoot: " + (viewRoot == null ? "null" : Integer.toString(viewRoot.getChildCount())));
351         } catch (IOException JavaDoc ioe) {
352             log.log(Level.SEVERE, "Error Building View", ioe);
353         }
354         context.getApplication().getStateManager().restoreView(context, viewId,
355                 renderKitId);
356 System.out.println("FaceletViewHandler.restoreView() return viewRoot: " + (viewRoot == null ? "null" : Integer.toString(viewRoot.getChildCount())));
357         return viewRoot;
358     }
359
360     /*
361      * (non-Javadoc)
362      *
363      * @see javax.faces.application.ViewHandlerWrapper#getWrapped()
364      */

365     protected ViewHandler getWrapped() {
366         return this.parent;
367     }
368
369     protected ResponseWriter createResponseWriter(FacesContext context)
370             throws IOException JavaDoc, FacesException {
371         ExternalContext extContext = context.getExternalContext();
372         RenderKit renderKit = context.getRenderKit();
373         // Avoid a cryptic NullPointerException when the renderkit ID
374
// is incorrectly set
375
if (renderKit == null) {
376             String JavaDoc id = context.getViewRoot().getRenderKitId();
377             throw new IllegalStateException JavaDoc(
378                     "No render kit was available for id \"" + id + "\"");
379         }
380
381         ServletResponse JavaDoc response = (ServletResponse JavaDoc) extContext.getResponse();
382
383         // set the buffer for content
384
if (this.bufferSize != -1) {
385             response.setBufferSize(this.bufferSize);
386         }
387
388         // get our content type
389
String JavaDoc contentType = null;
390
391         // get the encoding
392
String JavaDoc encoding = null;
393
394         // Create a dummy ResponseWriter with a bogus writer,
395
// so we can figure out what content type the ReponseWriter
396
// is really going to ask for
397
ResponseWriter writer = renderKit.createResponseWriter(
398                 NullWriter.Instance, contentType, encoding);
399
400         contentType = getResponseContentType(context, writer.getContentType());
401         encoding = getResponseEncoding(context, writer.getCharacterEncoding());
402
403         // apply them to the response
404
response.setContentType(contentType + "; charset=" + encoding);
405
406         // removed 2005.8.23 to comply with J2EE 1.3
407
// response.setCharacterEncoding(encoding);
408

409         // Now, clone with the real writer
410
writer = writer.cloneWithWriter(response.getWriter());
411
412         return writer;
413     }
414
415     /**
416      * Generate the encoding
417      *
418      * @param context
419      * @param orig
420      * @return
421      */

422     protected String JavaDoc getResponseEncoding(FacesContext context, String JavaDoc orig) {
423         String JavaDoc encoding = orig;
424
425         // see if we need to override the encoding
426
Map JavaDoc m = context.getExternalContext().getRequestMap();
427         Map JavaDoc sm = context.getExternalContext().getSessionMap();
428
429         // 1. check the request attribute
430
if (m.containsKey("facelets.Encoding")) {
431             encoding = (String JavaDoc) m.get("facelets.Encoding");
432             if (log.isLoggable(Level.FINEST)) {
433                 log.finest("Facelet specified alternate encoding '" + encoding
434                         + "'");
435             }
436             sm.put(CHARACTER_ENCODING_KEY, encoding);
437         }
438
439         // 2. get it from request
440
Object JavaDoc request = context.getExternalContext().getRequest();
441         if (encoding == null && request instanceof ServletRequest JavaDoc) {
442             encoding = ((ServletRequest JavaDoc) request).getCharacterEncoding();
443         }
444
445         // 3. get it from the session
446
if (encoding == null) {
447             encoding = (String JavaDoc) sm.get(CHARACTER_ENCODING_KEY);
448             if (log.isLoggable(Level.FINEST)) {
449                 log.finest("Session specified alternate encoding '" + encoding
450                         + "'");
451             }
452         }
453
454         // 4. default it
455
if (encoding == null) {
456             encoding = "UTF-8";
457             if (log.isLoggable(Level.FINEST)) {
458                 log
459                         .finest("ResponseWriter created had a null CharacterEncoding, defaulting to UTF-8");
460             }
461         }
462
463         return encoding;
464     }
465
466     /**
467      * Generate the content type
468      *
469      * @param context
470      * @param orig
471      * @return
472      */

473     protected String JavaDoc getResponseContentType(FacesContext context, String JavaDoc orig) {
474         String JavaDoc contentType = orig;
475
476         // see if we need to override the contentType
477
Map JavaDoc m = context.getExternalContext().getRequestMap();
478         if (m.containsKey("facelets.ContentType")) {
479             contentType = (String JavaDoc) m.get("facelets.ContentType");
480             if (log.isLoggable(Level.FINEST)) {
481                 log.finest("Facelet specified alternate contentType '"
482                         + contentType + "'");
483             }
484         }
485
486         // safety check
487
if (contentType == null) {
488             contentType = "text/html";
489             if (log.isLoggable(Level.FINEST)) {
490                 log
491                         .finest("ResponseWriter created had a null ContentType, defaulting to text/html");
492             }
493         }
494
495         return contentType;
496     }
497
498     protected void buildView(FacesContext context, UIViewRoot viewToRender)
499             throws IOException JavaDoc, FacesException {
500         // setup our viewId
501
String JavaDoc renderedViewId = this.getRenderedViewId(context, viewToRender
502                 .getViewId());
503         viewToRender.setViewId(renderedViewId);
504 System.out.println("FaceletViewHandler.buildView() renderedViewId: " + renderedViewId);
505
506         if (log.isLoggable(Level.FINE)) {
507             log.fine("Building View: " + renderedViewId);
508         }
509
510         // grab our FaceletFactory and create a Facelet
511
Facelet f = null;
512         FaceletFactory.setInstance(this.faceletFactory);
513         try {
514             f = this.faceletFactory.getFacelet(viewToRender.getViewId());
515         } finally {
516             FaceletFactory.setInstance(null);
517         }
518
519         // populate UIViewRoot
520
long time = System.currentTimeMillis();
521 System.out.println("FaceletViewHandler.buildView() Before apply viewToRender: " + (viewToRender == null ? "null" : Integer.toString(viewToRender.getChildCount())));
522         f.apply(context, viewToRender);
523 System.out.println("FaceletViewHandler.buildView() After apply viewToRender: " + (viewToRender == null ? "null" : Integer.toString(viewToRender.getChildCount())));
524         time = System.currentTimeMillis() - time;
525         if (log.isLoggable(Level.FINE)) {
526             log.fine("Took " + time + "ms to build view: "
527                     + viewToRender.getViewId());
528         }
529     }
530
531     public void renderView(FacesContext context, UIViewRoot viewToRender)
532             throws IOException JavaDoc, FacesException {
533
534 System.out.println("FaceletViewHandler.renderView() viewToRender: " + (viewToRender == null ? "null" : Integer.toString(viewToRender.getChildCount())));
535         // lazy initialize so we have a FacesContext to use
536
if (this.faceletFactory == null) {
537             this.initialize(context);
538         }
539
540         // exit if the view is not to be rendered
541
if (!viewToRender.isRendered()) {
542             return;
543         }
544
545         // if facelets is not supposed to handle this request
546
if (!handledByFacelets(viewToRender.getViewId())) {
547 System.out.println("FaceletViewHandler.renderView() !handledByFacelets: " + viewToRender.getViewId() + " -> parent.renderView");
548             this.parent.renderView(context, viewToRender);
549             return;
550         }
551
552         // log request
553
if (log.isLoggable(Level.FINE)) {
554             log.fine("Rendering View: " + viewToRender.getViewId());
555         }
556
557         StateWriter stateWriter = null;
558         try {
559             // build view - but not if we're in "buildBeforeRestore"
560
// land and we've already got a populated view. Note
561
// that this optimizations breaks if there's a "c:if" in
562
// the page that toggles as a result of request processing -
563
// should that be handled? Or
564
// is this optimization simply so minor that it should just
565
// be trimmed altogether?
566
if (!this.buildBeforeRestore
567                     || viewToRender.getChildren().isEmpty()) {
568 System.out.println("FaceletViewHandler.renderView() Before buildView viewToRender: " + (viewToRender == null ? "null" : Integer.toString(viewToRender.getChildCount())));
569                 this.buildView(context, viewToRender);
570 System.out.println("FaceletViewHandler.renderView() After buildView viewToRender: " + (viewToRender == null ? "null" : Integer.toString(viewToRender.getChildCount())));
571             }
572
573             // setup writer and assign it to the context
574
ResponseWriter origWriter = this.createResponseWriter(context);
575             // QUESTION: should we use bufferSize? Or, since the
576
// StateWriter usually only needs a small bit at the end,
577
// should we always use a much smaller size?
578
stateWriter = new StateWriter(origWriter,
579                     this.bufferSize != -1 ? this.bufferSize : 1024);
580
581             ResponseWriter writer = origWriter.cloneWithWriter(stateWriter);
582             context.setResponseWriter(writer);
583
584             // force creation of session if saving state there
585
StateManager stateMgr = context.getApplication().getStateManager();
586             if (!stateMgr.isSavingStateInClient(context)) {
587                 context.getExternalContext().getSession(true);
588             }
589
590             long time = System.currentTimeMillis();
591
592             // render the view to the response
593
writer.startDocument();
594             if (FacesAPI.getVersion() >= 12) {
595                 viewToRender.encodeAll(context);
596             } else {
597                 ComponentSupport.encodeRecursive(context, viewToRender);
598             }
599             writer.endDocument();
600
601             // finish writing
602
writer.close();
603
604             // remove transients for older versions
605
if (FacesAPI.getVersion() < 12) {
606                 ComponentSupport.removeTransient(viewToRender);
607             }
608
609             boolean writtenState = stateWriter.isStateWritten();
610             // flush to origWriter
611
if (writtenState) {
612                 String JavaDoc content = stateWriter.getAndResetBuffer();
613                 int end = content.indexOf(STATE_KEY);
614                 // See if we can find any trace of the saved state.
615
// If so, we need to perform token replacement
616
if (end >= 0) {
617                     // save state
618
Object JavaDoc stateObj = stateMgr.saveSerializedView(context);
619                     String JavaDoc stateStr;
620                     if (stateObj == null) {
621                         stateStr = null;
622                     } else {
623                         stateMgr.writeState(context,
624                                        (StateManager.SerializedView) stateObj);
625                         stateStr = stateWriter.getAndResetBuffer();
626                     }
627
628                     int start = 0;
629
630                     while (end != -1) {
631                         origWriter.write(content, start, end - start);
632                         if (stateStr != null) {
633                             origWriter.write(stateStr);
634                         }
635                         start = end + STATE_KEY_LEN;
636                         end = content.indexOf(STATE_KEY, start);
637                     }
638                     origWriter.write(content, start, content.length() - start);
639                 // No trace of any saved state, so we just need to flush
640
// the buffer
641
} else {
642                     origWriter.write(content);
643                     // But for JSF 1.1 (actually, just 1.1_01 RI), if we didn't
644
// detect any saved state, force a call to
645
// saveSerializedView() in case we're using the old
646
// pure-server-side state saving
647
if ((FacesAPI.getVersion() < 12)
648                         && !stateMgr.isSavingStateInClient(context)) {
649                         stateMgr.saveSerializedView(context);
650                     }
651                 }
652             }
653
654             time = System.currentTimeMillis() - time;
655             if (log.isLoggable(Level.FINE)) {
656                 log.fine("Took " + time + "ms to render view: "
657                         + viewToRender.getViewId());
658             }
659
660         } catch (FileNotFoundException JavaDoc fnfe) {
661             this.handleFaceletNotFound(context, viewToRender.getViewId());
662         } catch (Exception JavaDoc e) {
663             this.handleRenderException(context, e);
664         } finally {
665             if (stateWriter != null)
666                 stateWriter.release();
667         }
668     }
669
670     protected void handleRenderException(FacesContext context, Exception JavaDoc e)
671             throws IOException JavaDoc, ELException, FacesException {
672         Object JavaDoc resp = context.getExternalContext().getResponse();
673
674         // always log
675
if (log.isLoggable(Level.SEVERE)) {
676             UIViewRoot root = context.getViewRoot();
677             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(64);
678             sb.append("Error Rendering View");
679             if (root != null) {
680                 sb.append('[');
681                 sb.append(root.getViewId());
682                 sb.append(']');
683             }
684             log.log(Level.SEVERE, sb.toString(), e);
685         }
686
687         // handle dev response
688
if (this.developmentMode && !context.getResponseComplete()
689                 && resp instanceof HttpServletResponse JavaDoc) {
690             HttpServletResponse JavaDoc httpResp = (HttpServletResponse JavaDoc) resp;
691             httpResp.reset();
692             httpResp.setContentType("text/html; charset=UTF-8");
693             Writer JavaDoc w = httpResp.getWriter();
694             DevTools.debugHtml(w, context, e);
695             w.flush();
696             context.responseComplete();
697         } else if (e instanceof RuntimeException JavaDoc) {
698             throw (RuntimeException JavaDoc) e;
699         } else if (e instanceof IOException JavaDoc) {
700             throw (IOException JavaDoc) e;
701         } else {
702             throw new FacesException(e.getMessage(), e);
703         }
704     }
705
706     protected void handleFaceletNotFound(FacesContext context, String JavaDoc viewId)
707             throws FacesException, IOException JavaDoc {
708         String JavaDoc actualId = this.getActionURL(context, viewId);
709         Object JavaDoc respObj = context.getExternalContext().getResponse();
710         if (respObj instanceof HttpServletResponse JavaDoc) {
711             HttpServletResponse JavaDoc respHttp = (HttpServletResponse JavaDoc) respObj;
712             respHttp.sendError(HttpServletResponse.SC_NOT_FOUND, actualId);
713             context.responseComplete();
714         }
715     }
716
717     /**
718      * Determine if Facelets needs to handle this request.
719      */

720     private boolean handledByFacelets(String JavaDoc viewId) {
721         // If there's no extensions array or prefixes array, then
722
// just make Facelets handle everything
723
if ((extensionsArray == null) && (prefixesArray == null)) {
724             return true;
725         }
726
727         if (extensionsArray != null) {
728             for (int i = 0; i < extensionsArray.length; i++) {
729                 String JavaDoc extension = extensionsArray[i];
730                 if (viewId.endsWith(extension)) {
731                     return true;
732                 }
733             }
734         }
735
736         if (prefixesArray != null) {
737             for (int i = 0; i < prefixesArray.length; i++) {
738                 String JavaDoc prefix = prefixesArray[i];
739                 if (viewId.startsWith(prefix)) {
740                     return true;
741                 }
742             }
743         }
744
745         return false;
746     }
747
748     public String JavaDoc getDefaultSuffix(FacesContext context) throws FacesException {
749         if (this.defaultSuffix == null) {
750             ExternalContext extCtx = context.getExternalContext();
751             String JavaDoc viewSuffix = extCtx
752                     .getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME);
753             this.defaultSuffix = (viewSuffix != null) ? viewSuffix
754                     : ViewHandler.DEFAULT_SUFFIX;
755         }
756         return this.defaultSuffix;
757     }
758
759     protected String JavaDoc getRenderedViewId(FacesContext context, String JavaDoc actionId) {
760         ExternalContext extCtx = context.getExternalContext();
761         String JavaDoc viewId = actionId;
762         if (extCtx.getRequestPathInfo() == null) {
763             String JavaDoc facesSuffix = actionId.substring(actionId.lastIndexOf('.'));
764             String JavaDoc viewSuffix = this.getDefaultSuffix(context);
765             viewId = actionId.replaceFirst(facesSuffix, viewSuffix);
766         }
767         if (log.isLoggable(Level.FINE)) {
768             log.fine("ActionId -> ViewId: " + actionId + " -> " + viewId);
769         }
770         return viewId;
771     }
772
773     public void writeState(FacesContext context) throws IOException JavaDoc {
774         if (handledByFacelets(context.getViewRoot().getViewId())) {
775             // Tell the StateWriter that we're about to write state
776
StateWriter.getCurrentInstance().writingState();
777             // Write the STATE_KEY out. Unfortunately, this will
778
// be wasteful for pure server-side state managers where nothing
779
// is actually written into the output, but this cannot
780
// programatically be discovered
781
context.getResponseWriter().write(STATE_KEY);
782         } else {
783             this.parent.writeState(context);
784         }
785     }
786
787     public Locale JavaDoc calculateLocale(FacesContext context) {
788         return this.parent.calculateLocale(context);
789     }
790
791     public String JavaDoc calculateRenderKitId(FacesContext context) {
792         return this.parent.calculateRenderKitId(context);
793     }
794
795     public UIViewRoot createView(FacesContext context, String JavaDoc viewId) {
796         if (UIDebug.debugRequest(context)) {
797             return new UIViewRoot();
798         }
799         UIViewRoot root = this.parent.createView(context, viewId);
800 System.out.println("FaceletViewHandler.createView() root: " + (root == null ? "null" : Integer.toString(root.getChildCount())));
801         return root;
802     }
803
804     public String JavaDoc getActionURL(FacesContext context, String JavaDoc viewId) {
805         return this.parent.getActionURL(context, viewId);
806     }
807
808     public String JavaDoc getResourceURL(FacesContext context, String JavaDoc path) {
809         return this.parent.getResourceURL(context, path);
810     }
811
812     /**
813      * Try to guess if this is a postback request. In JSF 1.2, this method is
814      * not needed, since ResponseStateManager can identify postbacks. We use a
815      * simple heuristic: for HttpServletRequests, "POST" and "PUT" are
816      * postbacks. For anything that isn't an HttpServletRequest, just guess that
817      * if there's a request parameter, it's probably a postback.
818      */

819     static private boolean isPostback11(FacesContext context) {
820         Object JavaDoc reqObject = context.getExternalContext().getRequest();
821         if (reqObject instanceof HttpServletRequest JavaDoc) {
822             HttpServletRequest JavaDoc request = (HttpServletRequest JavaDoc) reqObject;
823
824             String JavaDoc method = request.getMethod();
825
826             // Is this a POST or PUT request?
827
if ("POST".equals(method) || "PUT".equals(method)) {
828                 return true;
829             }
830
831             return false;
832         } else {
833             Map JavaDoc paramMap = context.getExternalContext()
834                     .getRequestParameterMap();
835             return !paramMap.isEmpty();
836         }
837     }
838
839     protected static class NullWriter extends Writer JavaDoc {
840
841         static final NullWriter Instance = new NullWriter();
842
843         public void write(char[] buffer) {
844         }
845
846         public void write(char[] buffer, int off, int len) {
847         }
848
849         public void write(String JavaDoc str) {
850         }
851
852         public void write(int c) {
853         }
854
855         public void write(String JavaDoc str, int off, int len) {
856         }
857
858         public void close() {
859         }
860
861         public void flush() {
862         }
863     }
864 }
865
Popular Tags