/** * Execute the target view. If the HTTP status code range is not 2xx, then return true to indicate * the response should be immediately flushed by the caller so that conditions such as 404 are * properly handled. * * @param context the <code>FacesContext</code> for the current request * @param viewToExecute the view to build * @return <code>true</code> if the response should be immediately flushed to the client, * otherwise <code>false</code> * @throws java.io.IOException if an error occurs executing the page */ private boolean executePageToBuildView(FacesContext context, UIViewRoot viewToExecute) throws IOException { if (null == context) { String message = MessageUtils.getExceptionMessageString( MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "context"); throw new NullPointerException(message); } if (null == viewToExecute) { String message = MessageUtils.getExceptionMessageString( MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "viewToExecute"); throw new NullPointerException(message); } ExternalContext extContext = context.getExternalContext(); if ("/*".equals(RequestStateManager.get(context, RequestStateManager.INVOCATION_PATH))) { throw new FacesException( MessageUtils.getExceptionMessageString(MessageUtils.FACES_SERVLET_MAPPING_INCORRECT_ID)); } String requestURI = viewToExecute.getViewId(); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("About to execute view " + requestURI); } // update the JSTL locale attribute in request scope so that JSTL // picks up the locale from viewRoot. This attribute must be updated // before the JSTL setBundle tag is called because that is when the // new LocalizationContext object is created based on the locale. if (extContext.getRequest() instanceof ServletRequest) { Config.set( (ServletRequest) extContext.getRequest(), Config.FMT_LOCALE, context.getViewRoot().getLocale()); } if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("Before dispacthMessage to viewId " + requestURI); } // save the original response Object originalResponse = extContext.getResponse(); // replace the response with our wrapper ViewHandlerResponseWrapper wrapped = getWrapper(extContext); extContext.setResponse(wrapped); try { // build the view by executing the page extContext.dispatch(requestURI); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("After dispacthMessage to viewId " + requestURI); } } finally { // replace the original response extContext.setResponse(originalResponse); } // Follow the JSTL 1.2 spec, section 7.4, // on handling status codes on a forward if (wrapped.getStatus() < 200 || wrapped.getStatus() > 299) { // flush the contents of the wrapper to the response // this is necessary as the user may be using a custom // error page - this content should be propagated wrapped.flushContentToWrappedResponse(); return true; } // Put the AFTER_VIEW_CONTENT into request scope // temporarily RequestStateManager.set(context, RequestStateManager.AFTER_VIEW_CONTENT, wrapped); return false; }
/** * @see javax.faces.view.ViewDeclarationLanguage#renderView(javax.faces.context.FacesContext, * javax.faces.component.UIViewRoot) */ public void renderView(FacesContext context, UIViewRoot view) throws IOException { // suppress rendering if "rendered" property on the component is // false if (!view.isRendered() || context.getResponseComplete()) { return; } ExternalContext extContext = context.getExternalContext(); if (!Util.isViewPopulated(context, view)) { buildView(context, view); } // set up the ResponseWriter RenderKitFactory renderFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY); RenderKit renderKit = renderFactory.getRenderKit(context, view.getRenderKitId()); ResponseWriter oldWriter = context.getResponseWriter(); WriteBehindStateWriter stateWriter = new WriteBehindStateWriter( extContext.getResponseOutputWriter(), context, responseBufferSize); ResponseWriter newWriter; if (null != oldWriter) { newWriter = oldWriter.cloneWithWriter(stateWriter); } else { newWriter = renderKit.createResponseWriter( stateWriter, null, extContext.getRequestCharacterEncoding()); } context.setResponseWriter(newWriter); // Don't call startDoc and endDoc on a partial response if (context.getPartialViewContext().isPartialRequest()) { doRenderView(context, view); try { extContext.getFlash().doPostPhaseActions(context); } catch (UnsupportedOperationException uoe) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine( "ExternalContext.getFlash() throw UnsupportedOperationException -> Flash unavailable"); } } } else { // render the view to the response newWriter.startDocument(); doRenderView(context, view); try { extContext.getFlash().doPostPhaseActions(context); } catch (UnsupportedOperationException uoe) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine( "ExternalContext.getFlash() throw UnsupportedOperationException -> Flash unavailable"); } } newWriter.endDocument(); } // replace markers in the body content and write it to response. // flush directly to the response if (stateWriter.stateWritten()) { stateWriter.flushToWriter(); } // clear the ThreadLocal reference. stateWriter.release(); if (null != oldWriter) { context.setResponseWriter(oldWriter); } // write any AFTER_VIEW_CONTENT to the response // side effect: AFTER_VIEW_CONTENT removed ViewHandlerResponseWrapper wrapper = (ViewHandlerResponseWrapper) RequestStateManager.remove(context, RequestStateManager.AFTER_VIEW_CONTENT); if (null != wrapper) { wrapper.flushToWriter( extContext.getResponseOutputWriter(), extContext.getResponseCharacterEncoding()); } extContext.responseFlushBuffer(); }