You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mm...@apache.org on 2007/09/28 09:19:28 UTC

svn commit: r580235 - /myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/application/jsp/JspViewHandlerImpl.java

Author: mmarinschek
Date: Fri Sep 28 00:19:27 2007
New Revision: 580235

URL: http://svn.apache.org/viewvc?rev=580235&view=rev
Log:
https://issues.apache.org/jira/browse/MYFACES-1728 (MYFACES-1728): JspViewHandlerImpl improperly flushing writer. Thanks to Timothy Braun for his help on this.

Modified:
    myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/application/jsp/JspViewHandlerImpl.java

Modified: myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/application/jsp/JspViewHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/application/jsp/JspViewHandlerImpl.java?rev=580235&r1=580234&r2=580235&view=diff
==============================================================================
--- myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/application/jsp/JspViewHandlerImpl.java (original)
+++ myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/application/jsp/JspViewHandlerImpl.java Fri Sep 28 00:19:27 2007
@@ -248,21 +248,12 @@
         response.setLocale(locale);
         Config.set(request, Config.FMT_LOCALE, facesContext.getViewRoot().getLocale());
 
-        ViewResponseWrapper wrappedResponse = new ViewResponseWrapper((HttpServletResponse) response);
-
-        externalContext.setResponse(wrappedResponse);
-        externalContext.dispatch(viewId);
-        externalContext.setResponse(response);
-
-        boolean errorResponse = wrappedResponse.getStatus() < 200 || wrappedResponse.getStatus() > 299;
-        if (errorResponse)
-        {
-            wrappedResponse.flushToWrappedResponse();
+        if(!buildView(response, externalContext, viewId)) {
+            //building the view was unsuccessful - an exception occurred during rendering
+            //we need to jump out
+            return;
         }
 
-        // store the wrapped response in the request, so it is thread-safe
-        externalContext.getRequestMap().put(AFTER_VIEW_TAG_CONTENT_PARAM, wrappedResponse);
-
         // handle character encoding as of section 2.5.2.2 of JSF 1.1
         if (externalContext.getRequest() instanceof HttpServletRequest)
         {
@@ -279,70 +270,130 @@
         RenderKitFactory renderFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
         RenderKit renderKit = renderFactory.getRenderKit(facesContext, viewToRender.getRenderKitId());
 
-        ResponseWriter newResponseWriter;
         StateMarkerAwareWriter stateAwareWriter = new StateMarkerAwareWriter();
 
-        // If the FacesContext has a non-null ResponseWriter create a new writer using its
-        // cloneWithWriter() method, passing the response's Writer as the argument.
-        // Otherwise, use the current RenderKit to create a new ResponseWriter.
+        // Create a new response-writer using as an underlying writer the stateAwareWriter
+        // Effectively, all output will be buffered in the stateAwareWriter so that later
+        // this writer can replace the state-markers with the actual state.
         ResponseWriter oldResponseWriter = facesContext.getResponseWriter();
-        if (oldResponseWriter != null)
-        {
-            newResponseWriter = oldResponseWriter.cloneWithWriter(stateAwareWriter);
-        }
-        else
+        ResponseWriter newResponseWriter = hookInStateAwareWriter(
+                oldResponseWriter, stateAwareWriter, renderKit, externalContext);
+
+
+        actuallyRenderView(facesContext, newResponseWriter, oldResponseWriter, viewToRender);
+
+        //We're done with the document - now we can write all content
+        //to the response, properly replacing the state-markers on the way out
+        //by using the stateAwareWriter
+        stateAwareWriter.flushToWriter(response.getWriter());
+
+        // Final step - we output any content in the wrappedResponse response from above to the response,
+        // removing the wrappedResponse response from the request, we don't need it anymore
+        ViewResponseWrapper afterViewTagResponse = (ViewResponseWrapper) externalContext.getRequestMap().get(
+                AFTER_VIEW_TAG_CONTENT_PARAM);
+        externalContext.getRequestMap().remove(AFTER_VIEW_TAG_CONTENT_PARAM);
+
+        if (afterViewTagResponse != null)
         {
-            if (log.isTraceEnabled())
-                log.trace("Creating new ResponseWriter");
-            newResponseWriter = renderKit.createResponseWriter(stateAwareWriter, null,
-                    ((HttpServletRequest) externalContext.getRequest()).getCharacterEncoding());
+            afterViewTagResponse.flushToWriter(response.getWriter());
         }
 
+        response.flushBuffer();
+    }
+
+    /**Render the view now - properly setting and resetting the response writer
+     *
+     * @param facesContext
+     * @param newResponseWriter
+     * @param viewToRender
+     * @throws IOException
+     */
+    private void actuallyRenderView(FacesContext facesContext,
+                                    ResponseWriter newResponseWriter, ResponseWriter oldResponseWriter,
+                                    UIViewRoot viewToRender) throws IOException {
         // Set the new ResponseWriter into the FacesContext, saving the old one aside.
         facesContext.setResponseWriter(newResponseWriter);
 
+        //Now we actually render the document
         // Call startDocument() on the ResponseWriter.
         newResponseWriter.startDocument();
 
         // Call encodeAll() on the UIViewRoot
         viewToRender.encodeAll(facesContext);
 
-        ResponseWriter responseWriter;
+        // Call endDocument() on the ResponseWriter
+        newResponseWriter.endDocument();
+
+        newResponseWriter.flush();
+
+        // If the old ResponseWriter was not null, place the old ResponseWriter back
+        // into the FacesContext.
+        if (oldResponseWriter != null)
+        {
+            facesContext.setResponseWriter(oldResponseWriter);
+        }
+    }
+
+    /**Create a new response-writer using as an underlying writer the stateAwareWriter
+     * Effectively, all output will be buffered in the stateAwareWriter so that later
+     * this writer can replace the state-markers with the actual state.
+     *
+     * If the FacesContext has a non-null ResponseWriter create a new writer using its
+     * cloneWithWriter() method, passing the response's Writer as the argument.
+     * Otherwise, use the current RenderKit to create a new ResponseWriter.
+     *
+     * @param oldResponseWriter
+     * @param stateAwareWriter
+     * @param renderKit
+     * @param externalContext
+     * @return
+     */
+    private ResponseWriter hookInStateAwareWriter(ResponseWriter oldResponseWriter, StateMarkerAwareWriter stateAwareWriter, RenderKit renderKit, ExternalContext externalContext) {
+        ResponseWriter newResponseWriter;
         if (oldResponseWriter != null)
         {
-            responseWriter = oldResponseWriter.cloneWithWriter(response.getWriter());
+            newResponseWriter = oldResponseWriter.cloneWithWriter(stateAwareWriter);
         }
         else
         {
-            responseWriter = newResponseWriter.cloneWithWriter(response.getWriter());
+            if (log.isTraceEnabled())
+                log.trace("Creating new ResponseWriter");
+            newResponseWriter = renderKit.createResponseWriter(stateAwareWriter, null,
+                    ((HttpServletRequest) externalContext.getRequest()).getCharacterEncoding());
         }
-        facesContext.setResponseWriter(responseWriter);
+        return newResponseWriter;
+    }
 
-        // response.getWriter().write(stateAwareWriter.parseResponse());
-        stateAwareWriter.flushToWriter(response.getWriter());
+    /**Build the view-tree before rendering.
+     * This is done by dispatching to the underlying JSP-page, effectively processing it, creating
+     * components out of any text in between JSF components (not rendering the text to the output of course, this
+     * will happen later while rendering), attaching these components
+     * to the component tree, and buffering any content after the view-root.
+     *
+     * @param response The current response - it will be replaced while the view-building happens (we want the text in the component tree, not on the actual servlet output stream)
+     * @param externalContext The external context where the response will be replaced while building
+     * @param viewId The view-id to dispatch to
+     * @return true if successfull, false if an error occurred during rendering
+     * @throws IOException
+     */
+    private boolean buildView(ServletResponse response, ExternalContext externalContext, String viewId) throws IOException {
+        ViewResponseWrapper wrappedResponse = new ViewResponseWrapper((HttpServletResponse) response);
 
-        // Output any content in the wrappedResponse response from above to the response, removing the
-        // wrappedResponse response from the thread-safe storage.
-        ViewResponseWrapper afterViewTagResponse = (ViewResponseWrapper) externalContext.getRequestMap().get(
-                AFTER_VIEW_TAG_CONTENT_PARAM);
-        externalContext.getRequestMap().remove(AFTER_VIEW_TAG_CONTENT_PARAM);
+        externalContext.setResponse(wrappedResponse);
+        externalContext.dispatch(viewId);
+        externalContext.setResponse(response);
 
-        if (afterViewTagResponse != null)
+        boolean errorResponse = wrappedResponse.getStatus() < 200 || wrappedResponse.getStatus() > 299;
+        if (errorResponse)
         {
-            afterViewTagResponse.flushToWriter(response.getWriter());
+            wrappedResponse.flushToWrappedResponse();
+            return false;
         }
 
-        // Call endDocument() on the ResponseWriter
-        newResponseWriter.endDocument();
-
-        // If the old ResponseWriter was not null, place the old ResponseWriter back
-        // into the FacesContext.
-        if (oldResponseWriter != null)
-        {
-            facesContext.setResponseWriter(oldResponseWriter);
-        }
+        // store the wrapped response in the request, so it is thread-safe
+        externalContext.getRequestMap().put(AFTER_VIEW_TAG_CONTENT_PARAM, wrappedResponse);
 
-        response.flushBuffer();
+        return true;
     }
 
     public UIViewRoot restoreView(FacesContext facesContext, String viewId)