All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.faces.application.view.JspViewHandlingStrategy Maven / Gradle / Ivy

There is a newer version: 4.1.0-M1
Show newest version
/*
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.faces.application.view;

import static com.sun.faces.config.WebConfiguration.WebContextInitParameter.ResponseBufferSize;
import static com.sun.faces.util.RequestStateManager.AFTER_VIEW_CONTENT;
import static com.sun.faces.util.Util.isViewPopulated;
import static com.sun.faces.util.Util.setViewPopulated;
import static java.lang.Integer.parseInt;
import static java.util.logging.Level.FINE;
import static javax.faces.FactoryFinder.RENDER_KIT_FACTORY;

import java.beans.BeanInfo;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;

import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.application.Resource;
import javax.faces.application.ViewVisitOption;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.PostAddToViewEvent;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.faces.view.StateManagementStrategy;
import javax.faces.view.ViewMetadata;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.jstl.core.Config;

import com.sun.faces.application.ViewHandlerResponseWrapper;
import com.sun.faces.util.FacesLogger;
import com.sun.faces.util.MessageUtils;
import com.sun.faces.util.RequestStateManager;

/**
 * This {@link ViewHandlingStrategy} handles JSP-based views.
 */
public class JspViewHandlingStrategy extends ViewHandlingStrategy {

    private static final Logger LOGGER = FacesLogger.APPLICATION.getLogger();
    private int responseBufferSize;


    // ------------------------------------------------------------ Constructors


    public JspViewHandlingStrategy() {

        try {
            responseBufferSize = parseInt(webConfig.getOptionValue(ResponseBufferSize));
        } catch (NumberFormatException nfe) {
            responseBufferSize = parseInt(ResponseBufferSize.getDefaultValue());
        }
    }


    // ------------------------------------ Methods from ViewDeclarationLanguage


    /**
     * 

* Not supported in JSP-based views. *

* * @see javax.faces.view.ViewDeclarationLanguage#getViewMetadata(javax.faces.context.FacesContext, String) */ @Override public ViewMetadata getViewMetadata(FacesContext context, String viewId) { return null; } /** * @see javax.faces.view.ViewDeclarationLanguage#buildView(javax.faces.context.FacesContext, javax.faces.component.UIViewRoot) * @param context * @param view * @throws IOException */ @Override public void buildView(FacesContext context, UIViewRoot view) throws IOException { if (isViewPopulated(context, view)) { return; } try { if (executePageToBuildView(context, view)) { context.getExternalContext().responseFlushBuffer(); if (associate != null) { associate.responseRendered(); } context.responseComplete(); return; } } catch (IOException e) { throw new FacesException(e); } if (LOGGER.isLoggable(FINE)) { LOGGER.log(FINE, "Completed building view for : \n" + view.getViewId()); } context.getApplication().publishEvent(context, PostAddToViewEvent.class, UIViewRoot.class, view); setViewPopulated(context, view); } /** * @see javax.faces.view.ViewDeclarationLanguage#renderView(javax.faces.context.FacesContext, javax.faces.component.UIViewRoot) */ @Override 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 (!isViewPopulated(context, view)) { buildView(context, view); } // Set up the ResponseWriter RenderKitFactory renderFactory = (RenderKitFactory) FactoryFinder.getFactory(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(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(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, AFTER_VIEW_CONTENT); if (null != wrapper) { wrapper.flushToWriter( extContext.getResponseOutputWriter(), extContext.getResponseCharacterEncoding()); } extContext.responseFlushBuffer(); } @Override public StateManagementStrategy getStateManagementStrategy(FacesContext context, String viewId) { return null; } /** *

* Not supported in JSP-based views. *

* * @see javax.faces.view.ViewDeclarationLanguage#getComponentMetadata(javax.faces.context.FacesContext, javax.faces.application.Resource) */ @Override public BeanInfo getComponentMetadata(FacesContext context, Resource componentResource) { throw new UnsupportedOperationException(); } /** *

* Not supported in JSP-based views. *

* * @see javax.faces.view.ViewDeclarationLanguage#getScriptComponentResource(javax.faces.context.FacesContext, javax.faces.application.Resource) */ @Override public Resource getScriptComponentResource(FacesContext context, Resource componentResource) { throw new UnsupportedOperationException(); } /** *

* Not supported in JSP-based views. *

* * @see javax.faces.view.ViewDeclarationLanguage#getViews(FacesContext, String, ViewVisitOption...) */ @Override public Stream getViews(FacesContext context, String path, ViewVisitOption... options) { return Stream.empty(); } /** *

* Not supported in JSP-based views. *

* * @see javax.faces.view.ViewDeclarationLanguage#getViews(FacesContext, String, int, ViewVisitOption...) */ @Override public Stream getViews(FacesContext context, String path, int maxDepth, ViewVisitOption... options) { return Stream.empty(); } // --------------------------------------- Methods from ViewHandlingStrategy /** * This {@link ViewHandlingStrategy} should be the last one queried * and as such we return true. * * @see com.sun.faces.application.view.ViewHandlingStrategy#handlesViewId(String) */ @Override public boolean handlesViewId(String viewId) { return true; } @Override public String getId() { return JSP_VIEW_DECLARATION_LANGUAGE_ID; } // --------------------------------------------------------- Private Methods /** * 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 FacesContext for the current request * @param viewToExecute the view to build * @return true if the response should be immediately flushed * to the client, otherwise false * @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; } /** *

This is a separate method to account for handling the content * after the view tag.

* *

Create a new ResponseWriter around this response's Writer. * Set it into the FacesContext, saving the old one aside.

* *

call encodeBegin(), encodeChildren(), encodeEnd() on the * argument UIViewRoot.

* *

Restore the old ResponseWriter into the FacesContext.

* *

Write out the after view content to the response's writer.

* *

Flush the response buffer, and remove the after view content * from the request scope.

* * @param context the FacesContext for the current request * @param viewToRender the view to render * @throws java.io.IOException if an error occurs rendering the view to the client * @throws javax.faces.FacesException if some error occurs within the framework * processing */ private void doRenderView(FacesContext context, UIViewRoot viewToRender) throws IOException { if (null != associate) { associate.responseRendered(); } if (LOGGER.isLoggable(FINE)) { LOGGER.log(FINE, "About to render view " + viewToRender.getViewId()); } viewToRender.encodeAll(context); } /** *

* Simple utility method to wrap the current response with the * {@link ViewHandlerResponseWrapper}. *

* @param extContext the {@link ExternalContext} for this request * @return the current response wrapped with ViewHandlerResponseWrapper */ private static ViewHandlerResponseWrapper getWrapper(ExternalContext extContext) { Object response = extContext.getResponse(); if (response instanceof HttpServletResponse) { return new ViewHandlerResponseWrapper((HttpServletResponse) response); } throw new IllegalArgumentException(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy