Package org.apache.beehive.netui.pageflow

Source Code of org.apache.beehive.netui.pageflow.PageFlowPageFilter

/*
* Copyright 2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* $Header:$
*/
package org.apache.beehive.netui.pageflow;

import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;
import java.util.Map;

import org.apache.struts.util.RequestUtils;
import org.apache.struts.util.MessageResources;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.Globals;

import org.apache.beehive.netui.core.urls.URLRewriterService;
import org.apache.beehive.netui.util.logging.Logger;
import org.apache.beehive.netui.util.internal.FileUtils;
import org.apache.beehive.netui.util.internal.ServletUtils;
import org.apache.beehive.netui.pageflow.internal.DefaultURLRewriter;
import org.apache.beehive.netui.pageflow.internal.JavaControlUtils;
import org.apache.beehive.netui.pageflow.internal.InternalUtils;
import org.apache.beehive.netui.pageflow.internal.InternalConstants;
import org.apache.beehive.netui.pageflow.internal.AdapterManager;
import org.apache.beehive.netui.pageflow.internal.PageFlowRequestWrapper;
import org.apache.beehive.netui.pageflow.handler.Handlers;
import org.apache.beehive.netui.script.common.ImplicitObjectUtil;


/**
* Base class for Servlet Filters that run before Page Flow page requests.
*/
public abstract class PageFlowPageFilter implements Filter
{
    private ServletContext _servletContext;
    private ServletContainerAdapter _servletContainerAdapter;
    private FlowControllerFactory _flowControllerFactory;
   
    private static final Logger _log = Logger.getInstance( PageFlowPageFilter.class );
   
    private static final String PREVENT_CACHE_ATTR = InternalConstants.ATTR_PREFIX + "preventCache";
   
   
    protected PageFlowPageFilter()
    {
    }
   
    PageFlowPageFilter( ServletContext servletContext )
    {
        _servletContext = servletContext;
        _servletContainerAdapter = AdapterManager.getServletContainerAdapter( _servletContext );
        _flowControllerFactory = FlowControllerFactory.get( servletContext );
    }

    public void init( FilterConfig filterConfig ) throws ServletException
    {
        _servletContext = filterConfig.getServletContext();
       
        if ( ! PageFlowContextListener.isInit( _servletContext ) )
        {
            PageFlowContextListener.performInitializations( _servletContext );
        }
       
        _servletContainerAdapter = AdapterManager.getServletContainerAdapter( _servletContext );
        _flowControllerFactory = FlowControllerFactory.get( _servletContext );
    }
   
    protected abstract Set getValidFileExtensions();
   
    public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain )
            throws IOException, ServletException
    {
        if ( request instanceof HttpServletRequest && response instanceof HttpServletResponse )
        {
            HttpServletRequest httpRequest = ( HttpServletRequest ) request;
            HttpServletResponse httpResponse = ( HttpServletResponse ) response;
           
            //
            // Don't do the filter if the request is in error.
            //
            Object errStatusCode = request.getAttribute( "javax.servlet.error.status_code" );
            if ( errStatusCode != null )
            {
                if ( _log.isDebugEnabled() )
                {
                    _log.debug( "Request has error status code " + errStatusCode + ".  Skipping filter." );
                }
               
                continueChainNoWrapper( request, response, chain );
                return;          
            }
           
            String servletPath = InternalUtils.getDecodedServletPath( httpRequest );
            String extension = FileUtils.getFileExtension( servletPath );
            Set validFileExtensions = getValidFileExtensions();
           
            if ( validFileExtensions != null && ! validFileExtensions.contains( extension ) )
            {
                if ( _log.isDebugEnabled() )
                {
                    _log.debug( "Path " + servletPath +
                                " does not have an appropriate file extension.  Skipping filter." );
                }
               
                continueChainNoWrapper( request, response, chain );
                return;
            }
           
            if ( _log.isDebugEnabled() ) _log.debug( "Filtering request for path " + servletPath );
           
            //
            // If at an earlier stage in the request we determined that we should prevent caching,
            // actually write the appropriate headers to the response now.
            //
            if ( request.getAttribute( PREVENT_CACHE_ATTR ) != null ) ServletUtils.preventCache( httpResponse );
           
            //
            // Initialize the ServletContext in the request.  Often, we need access to the ServletContext when we only
            // have a ServletRequest.
            //
            InternalUtils.setServletContext( httpRequest, _servletContext );
           
            //
            // Callback to the server adapter.
            //
            PageFlowEventReporter er = _servletContainerAdapter.getEventReporter();
            _servletContainerAdapter.beginRequest( httpRequest, httpResponse );
            RequestContext requestContext = new RequestContext( request, response );
            er.beginPageRequest( requestContext );
            long startTime = System.currentTimeMillis();
           
            //
            // Initialize the ControlBeanContext in the session.
            //
            JavaControlUtils.initializeControlContext( httpRequest, httpResponse, _servletContext );

            //
            // Register the default URLRewriter
            //
            URLRewriterService.registerURLRewriter( 0, request, new DefaultURLRewriter() );

            PageFlowRequestWrapper rw = PageFlowRequestWrapper.unwrap( request );
            boolean isForwardedRequest = rw != null && rw.isForwardedRequest();
           
            try
            {
                ModuleConfig prevModuleConfig = RequestUtils.getRequestModuleConfig( httpRequest );
                MessageResources prevMessageResources = ( MessageResources ) request.getAttribute( Globals.MESSAGES_KEY );
                if ( rw == null || ! rw.isStayInCurrentModule() ) initializeModule( httpRequest, httpResponse );
               
                try
                {
                    //
                    // Initialize shared flows for the current request.
                    //
                    Map/*< String, SharedFlowController >*/ sharedFlows =
                            _flowControllerFactory.getSharedFlowsForRequest( requestContext );
                    ImplicitObjectUtil.loadSharedFlow( request, sharedFlows );
                    ImplicitObjectUtil.loadGlobalApp( request, PageFlowUtils.getGlobalApp( httpRequest ) );
                   
                    //
                    // Make sure that the current PageFlowController is set up for this request.
                    //
                    PageFlowController curJpf;
                    if ( rw != null && rw.isStayInCurrentModule() )
                    {
                        rw.setStayInCurrentModule( false );
                        curJpf = PageFlowUtils.getCurrentPageFlow( httpRequest, _servletContext );
                    }
                    else
                    {
                        curJpf = _flowControllerFactory.getPageFlowForRequest( requestContext );
                    }
                   
                    //
                    // If there is no pageflow for the current Struts module, than fall back to default
                    // Struts behavior, which is *not* to allow a page request to set the current module.
                    //
                    if ( curJpf == null )
                    {
                        InternalUtils.setCurrentModule( prevModuleConfig, request );
                        request.setAttribute( Globals.MESSAGES_KEY, prevMessageResources );
                    }
                   
                   
                    if ( _log.isDebugEnabled() )
                    {
                        _log.debug( "Current PageFlowController is: " + curJpf );
                        _log.debug( "Continuing with filter chain..." );
                    }
                   
                    runPage( curJpf, httpRequest, httpResponse, chain );
                }
                catch ( ClassNotFoundException e )
                {
                    throw new ServletException( e );
                }
                catch ( InstantiationException e )
                {
                    throw new ServletException( e );
                }
                catch ( IllegalAccessException e )
                {
                    throw new ServletException( e );
                }
            }
            finally
            {
                //
                // Clean up the ControlBeanContext in the session.
                //
                JavaControlUtils.uninitializeControlContext( httpRequest, httpResponse, _servletContext );
               
                //
                // Callback to the server adapter.
                //
                _servletContainerAdapter.endRequest( httpRequest, httpResponse );
                long timeTaken = System.currentTimeMillis() - startTime;
                er.endPageRequest( requestContext, timeTaken );
               
                //
                // If this is not a forwarded request, then commit any session-scoped changes that were stored in the
                // request.
                //
                if ( ! isForwardedRequest )
                {
                    Handlers.get( _servletContext ).getStorageHandler().applyChanges( requestContext );
                }
            }
        }
        else
        {
            continueChainNoWrapper( request, response, chain );
        }
    }
   
    private void runPage( PageFlowController curJpf, HttpServletRequest request, HttpServletResponse response,
                          FilterChain chain )
        throws IOException, ServletException
    {
        //
        // Make sure that the pageflow's getRequest() and getResponse() will work while the page
        // is being rendered, since methods on the pageflow may be called (through databinding
        // or tags, or through direct reference).
        //
        if ( curJpf != null )
        {
            //
            // We're going to bail out if there are too many concurrent requests for the same JPF.
            // This prevents an attack that takes advantage of the fact that we synchronize requests
            // to the same pageflow.
            //
            if ( curJpf.incrementRequestCount( request, response, _servletContext ) )
            {
                try
                {
                    //
                    // Any databinding calls, indirect calls to getRequest(), etc. must be protected
                    // against conflicts from running action methods at the same time as rendering
                    // the page here.  Synchronize on the JPF.
                    //
                    synchronized ( curJpf )
                    {
                        FlowController.PerRequestState newState =
                                new FlowController.PerRequestState( request, response, null );
                        FlowController.PerRequestState prevState = curJpf.setPerRequestState( newState );
                        ImplicitObjectUtil.loadImplicitObjects( request, response, _servletContext, curJpf );
                               
                        //
                        // Tell the page flow that we're about to display a page so it can manage settings,
                        // such as previous page information, if needed in advance.
                        //
                        curJpf.beforePage();
                               
                        try
                        {
                            chain.doFilter( request, response );
                        }
                        catch ( ServletException servletEx )
                        {
                            //
                            // If a ServletException escapes out of the page, let the current FlowController handle it.
                            //
                            if ( ! handleException( servletEx, curJpf, request, response ) ) throw servletEx;
                        }
                        catch ( IOException ioe )
                        {
                            //
                            // If an IOException escapes out of the page, let the current FlowController handle it.
                            //
                            if ( ! handleException( ioe, curJpf, request, response ) ) throw ioe;
                        }
                        catch ( Throwable th )
                        {
                            //
                            // If a Throwable escapes out of the page, let the current FlowController handle it.
                            //
                            if ( ! handleException( th, curJpf, request, response ) )
                            {
                                if ( th instanceof Error ) throw ( Error ) th;
                                throw new ServletException( th );
                            }
                        }
                        finally
                        {
                            curJpf.setPerRequestState( prevState );
                        }
                    }
                }
                finally
                {
                    curJpf.decrementRequestCount( request );
                }
            }
        }
        else
        {
            ImplicitObjectUtil.loadImplicitObjects( request, response, _servletContext, null );
            continueChainNoWrapper( request, response, chain );
        }
    }
   
    private static void continueChainNoWrapper( ServletRequest request, ServletResponse response, FilterChain chain )
        throws IOException, ServletException
    {
        //
        // Remove our request wrapper -- the page doesn't need to see this.
        //
        if ( request instanceof PageFlowRequestWrapper )
        {
            request = ( ( PageFlowRequestWrapper ) request ).getHttpRequest();
        }
       
        chain.doFilter( request, response );
    }
   
    private boolean handleException( Throwable th, FlowController fc, HttpServletRequest request,
                                     HttpServletResponse response )
    {
        try
        {
            ActionMapping mapping = InternalUtils.getCurrentActionMapping( request );
            ActionForm form = InternalUtils.getCurrentActionForm( request );
            ActionForward fwd = fc.handleException( th, mapping, form, request, response );
            fc.getRequestProcessor().doActionForward( request, response, fwd );
            return true;
        }
        catch ( Throwable t )
        {
            _log.error( "Exception while handling exception " + th.getClass().getName()
                        + ".  The original exception will be thrown.", th );
            return false;
        }
    }
   
    private void initializeModule( HttpServletRequest request, HttpServletResponse response )
        throws IOException, ServletException
    {
        //
        // Ensure that the right Struts module is selected, for use by the tags.
        //
        String curModulePath = PageFlowUtils.getModulePath( request );
        ActionServlet as = InternalUtils.getActionServlet( _servletContext );
               
        if ( as instanceof AutoRegisterActionServlet )
        {
            AutoRegisterActionServlet das = ( AutoRegisterActionServlet ) as;
            das.ensureModuleRegistered( curModulePath, request );
        }
               
        ModuleConfig mc = InternalUtils.selectModule( curModulePath, request, _servletContext );
                   
        if ( mc == null )
        {
            //
            // If we still haven't had success in selecting the module, see if we can dynamically register one.
            //
            if ( as instanceof AutoRegisterActionServlet )
            {
                AutoRegisterActionServlet das = ( AutoRegisterActionServlet ) as;
                das.ensureModuleSelected( curModulePath, request, response );
            }
        }
    }
   
    /**
     * Make sure that when this page is rendered, it will set headers in the response to prevent caching.
     * Because these headers are lost on server forwards, we set a request attribute to cause the headers
     * to be set right before the page is rendered.
     */
    static void preventCache( HttpServletRequest request )
    {
        request.setAttribute( PREVENT_CACHE_ATTR, Boolean.TRUE );
    }
   
    public void destroy()
    {
        _servletContext = null;
    }
}
TOP

Related Classes of org.apache.beehive.netui.pageflow.PageFlowPageFilter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.