Package com.ocpsoft.pretty

Source Code of com.ocpsoft.pretty.PrettyFilter

/*
* Copyright 2010 Lincoln Baxter, III
*
* 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.
*/
package com.ocpsoft.pretty;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ocpsoft.pretty.faces.config.PrettyConfig;
import com.ocpsoft.pretty.faces.config.PrettyConfigurator;
import com.ocpsoft.pretty.faces.config.mapping.PathParameter;
import com.ocpsoft.pretty.faces.config.rewrite.Redirect;
import com.ocpsoft.pretty.faces.config.rewrite.RewriteRule;
import com.ocpsoft.pretty.faces.rewrite.RewriteEngine;
import com.ocpsoft.pretty.faces.servlet.PrettyFacesWrappedRequest;
import com.ocpsoft.pretty.faces.servlet.PrettyFacesWrappedResponse;
import com.ocpsoft.pretty.faces.url.QueryString;
import com.ocpsoft.pretty.faces.url.URL;
import com.ocpsoft.pretty.faces.util.StringUtils;

/**
* @author Lincoln Baxter, III <lincoln@ocpsoft.com>
*/
public class PrettyFilter implements Filter
{
   private static final Log log = LogFactory.getLog(PrettyFilter.class);

   private static final String REWRITE_OCCURRED_KEY = "com.ocpsoft.pretty.rewrite";

   private ServletContext servletContext;

   /**
    * Determine if the current request is mapped using PrettyFaces. If it is, process the pattern, storing parameters
    * into the request map, then forward the request to the specified viewId.
    */
   public void doFilter(final ServletRequest req, final ServletResponse resp, final FilterChain chain)
            throws IOException, ServletException
   {
      HttpServletRequest request = (HttpServletRequest) req;

      HttpServletResponse response = new PrettyFacesWrappedResponse(request.getContextPath(), request,
               (HttpServletResponse) resp, getConfig());
      req.setAttribute(PrettyContext.CONFIG_KEY, getConfig());

      PrettyContext context = PrettyContext.newDetachedInstance(request);

      rewrite(request, response);

      if (resp.isCommitted())
      {
         log.trace("Rewrite occurred, reponse is committed - ending request.");
      }
      else
      {
         URL url = context.getRequestURL();
         if (getConfig().isURLMapped(url))
         {
            PrettyContext.setCurrentContext(request, context); // set

            String viewId = context.getCurrentViewId();
            if (!response.isCommitted())
            {
               if (context.shouldProcessDynaview())
               {
                  log.trace("Forwarding mapped request [" + url.toURL() + "] to dynaviewId [" + viewId + "]");
                  req.getRequestDispatcher(context.getDynaViewId()).forward(req, response);
               }
               else
               {
                  List<PathParameter> params = context.getCurrentMapping().getPatternParser().parse(url);
                  QueryString query = QueryString.build(params);

                  ServletRequest wrappedRequest = new PrettyFacesWrappedRequest(request,
                              query.getParameterMap());

                  log.trace("Sending mapped request [" + url.toURL() + "] to resource [" + viewId + "]");
                  if (url.decode().toURL().matches(viewId))
                  {
                     chain.doFilter(wrappedRequest, response);
                  }
                  else
                  {
                     req.getRequestDispatcher(viewId).forward(wrappedRequest, response);
                  }
               }
            }
         }
         else
         {
            log.trace("Request is not mapped using PrettyFaces. Continue.");
            chain.doFilter(req, response);
         }
      }
   }

   /**
    * Apply the given list of {@link RewriteRule}s to the URL (in order,) perform a redirect/forward if required.
    * Canonicalization is only invoked if it has not previously been invoked on this request. This method operates on
    * the requestUri, excluding contextPath.
    *
    * @return True if forward/redirect occurred, false if not.
    */
   private void rewrite(final HttpServletRequest req, final HttpServletResponse resp)
   {
      /*
       * FIXME Refactor this horrible method.
       */
      if (!rewriteOccurred(req))
      {
         RewriteEngine rewriteEngine = new RewriteEngine();
         URL url = PrettyContext.getCurrentInstance(req).getRequestURL();

         try
         {

            String queryString = req.getQueryString();
            if ((queryString != null) && !"".equals(queryString))
            {
               queryString = "?" + queryString;
            }
            else if (queryString == null)
            {
               queryString = "";
            }

            // TODO test this now that query string is included in rewrites
            String originalUrl = url.toURL() + queryString;
            String newUrl = originalUrl;
            for (RewriteRule rule : getConfig().getGlobalRewriteRules())
            {
               if (rule.matches(newUrl))
               {
                  newUrl = rewriteEngine.processInbound(req, resp, rule, newUrl);
                  if (!Redirect.CHAIN.equals(rule.getRedirect()))
                  {

                     /*
                      * An HTTP redirect has been triggered; issue one if we have a URL or if the current URL has been
                      * modified.
                      */

                     String redirectURL = null;

                     /*
                      * The rewrite changed the URL and no 'url' attribute has been set for the rule.
                      */
                     if (StringUtils.isBlank(rule.getUrl()) && !originalUrl.equals(newUrl))
                     {

                        /*
                         * Add context path and encode request using encodeRedirectURL().
                         */
                        redirectURL = resp.encodeRedirectURL(req.getContextPath() + newUrl);
                     }
                     else if (StringUtils.isNotBlank(rule.getUrl()))
                     {

                        /*
                         * This is a custom location - don't call encodeRedirectURL() and don't add context path, just
                         * redirect to the encoded URL
                         */
                        redirectURL = newUrl.trim();

                     }

                     // we have to send a redirect
                     if (redirectURL != null)
                     {

                        // try to encode the redirect target
                        String encodedRedirectURL = encodeUrlWithQueryString(redirectURL);

                        // send redirect
                        resp.setHeader("Location", encodedRedirectURL);
                        resp.setStatus(rule.getRedirect().getStatus());
                        resp.flushBuffer();
                        break;

                     }

                  }
               }
            }

            if (!originalUrl.equals(newUrl) && !resp.isCommitted())
            {
               /*
                * The URL was modified, but no redirect occurred; forward instead.
                */
               req.getRequestDispatcher(newUrl).forward(req, resp);
            }

         }
         catch (Exception e)
         {
            throw new PrettyException("Error occurred during canonicalization of request <[" + url + "]>", e);
         }
         finally
         {
            setRewriteOccurred(req);
         }
      }
   }

   /**
    * Helper method that encodes an URL including a query string. If encoding is not possible due to errors related to
    * the input URL, the method will return the unencoded input URL.
    *
    * @param url URL to encode (may contain a query string)
    * @return encoded representation of the URL
    */
   private String encodeUrlWithQueryString(final String url)
   {

      // we must take care of URISyntax exceptions
      try
      {

         // split the input into the base URL and the query string.
         String[] urlParts = url.split("\\?", 2);

         // use the URI class to encode the base part of the url
         String baseUrlEncoded = new URI(urlParts[0]).toASCIIString();

         // is there a query string
         if ((urlParts.length > 1) && StringUtils.isNotBlank(urlParts[1]))
         {
            // return encoded base URL + the encoded query string
            return baseUrlEncoded + QueryString.build(urlParts[1]).toQueryString();
         }
         else
         {
            // no query string -> just return the encoded URL
            return baseUrlEncoded;
         }

      }
      catch (URISyntaxException e)
      {
         // warn and return input URL
         log.warn("Failed to encode URL '" + url + "': " + e.getMessage());
         return url;

      }

   }

   private void setRewriteOccurred(final ServletRequest req)
   {
      req.setAttribute(REWRITE_OCCURRED_KEY, true);
   }

   private boolean rewriteOccurred(final ServletRequest req)
   {
      return Boolean.TRUE.equals(req.getAttribute(REWRITE_OCCURRED_KEY));
   }

   public PrettyConfig getConfig()
   {
      if ((servletContext == null) || (servletContext.getAttribute(PrettyContext.CONFIG_KEY) == null))
      {
         log.warn("PrettyFilter is not registered in web.xml, but is registered with JSF "
                  + "Navigation and Action handlers -- this could cause unpredictable behavior.");
         return new PrettyConfig();
      }
      return (PrettyConfig) servletContext.getAttribute(PrettyContext.CONFIG_KEY);
   }

   /**
    * Load and cache configurations
    */
   public void init(final FilterConfig filterConfig) throws ServletException
   {
      log.info("PrettyFilter starting up...");
      servletContext = filterConfig.getServletContext();

      PrettyConfigurator configurator = new PrettyConfigurator(servletContext);
      configurator.configure();

      log.info("PrettyFilter initialized.");
   }

   public void destroy()
   {
      log.info("PrettyFilter shutting down...");
   }
}
TOP

Related Classes of com.ocpsoft.pretty.PrettyFilter

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.