Save This Page
Home » sitemesh-2.3 » com.opensymphony.module » sitemesh » filter » [javadoc | source]
    1   /* This software is published under the terms of the OpenSymphony Software
    2    * License version 1.1, of which a copy has been included with this
    3    * distribution in the LICENSE.txt file. */
    4   package com.opensymphony.module.sitemesh.filter;
    5   
    6   import com.opensymphony.module.sitemesh;
    7   import com.opensymphony.module.sitemesh.util.Container;
    8   
    9   import javax.servlet;
   10   import javax.servlet.http.HttpServletRequest;
   11   import javax.servlet.http.HttpServletResponse;
   12   import java.io.IOException;
   13   import java.io.PrintWriter;
   14   
   15   /**
   16    * Main SiteMesh filter for applying Decorators to entire Pages.
   17    *
   18    * @author <a href="joe@truemesh.com">Joe Walnes</a>
   19    * @author <a href="scott@atlassian.com">Scott Farquhar</a>
   20    * @version $Revision: 1.12 $
   21    */
   22   public class PageFilter implements Filter, RequestConstants {
   23       private FilterConfig filterConfig = null;
   24       private Factory factory = null;
   25   
   26       /**
   27        * Main method of the Filter.
   28        *
   29        * <p>Checks if the Filter has been applied this request. If not, parses the page
   30        * and applies {@link com.opensymphony.module.sitemesh.Decorator} (if found).
   31        */
   32       public void doFilter(ServletRequest rq, ServletResponse rs, FilterChain chain)
   33               throws IOException, ServletException {
   34   
   35           HttpServletRequest request = (HttpServletRequest) rq;
   36   
   37           if (rq.getAttribute(FILTER_APPLIED) != null || factory.isPathExcluded(extractRequestPath(request))) {
   38               // ensure that filter is only applied once per request
   39               chain.doFilter(rq, rs);
   40           }
   41           else {
   42               request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
   43   
   44               // force creation of the session now because Tomcat 4 had problems with
   45               // creating sessions after the response had been committed
   46               if (Container.get() == Container.TOMCAT) {
   47                   request.getSession(true);
   48               }
   49               HttpServletResponse response = (HttpServletResponse) rs;
   50   
   51               // parse data into Page object (or continue as normal if Page not parseable)
   52               Page page = parsePage(request, response, chain);
   53   
   54               if (page != null) {
   55                   page.setRequest(request);
   56   
   57                   Decorator decorator = factory.getDecoratorMapper().getDecorator(request, page);
   58                   if (decorator != null && decorator.getPage() != null) {
   59                       applyDecorator(page, decorator, request, response);
   60                       page = null;
   61                       return;
   62                   }
   63   
   64                   // if we got here, an exception occured or the decorator was null,
   65                   // what we don't want is an exception printed to the user, so
   66                   // we write the original page
   67                   writeOriginal(request, response, page);
   68                   page = null;
   69               }
   70           }
   71       }
   72   
   73       private String extractRequestPath(HttpServletRequest request) {
   74           String servletPath = request.getServletPath();
   75           String pathInfo = request.getPathInfo();
   76           String query = request.getQueryString();
   77           return (servletPath == null ? "" : servletPath)
   78                   + (pathInfo == null ? "" : pathInfo)
   79                   + (query == null ? "" : ("?" + query));
   80       }
   81   
   82       /** Set FilterConfig, and get instance of {@link com.opensymphony.module.sitemesh.DecoratorMapper}. */
   83       public void init(FilterConfig filterConfig) {
   84           if (filterConfig != null) {
   85               this.filterConfig = filterConfig;
   86               factory = Factory.getInstance(new Config(filterConfig));
   87           }
   88           else {
   89               destroy();
   90           }
   91       }
   92   
   93       /** @deprecated Not needed in final version of Servlet 2.3 API - replaced by init(). */
   94       // NOTE: SiteMesh doesn't work with Orion 1.5.2 without this method
   95       public FilterConfig getFilterConfig() {
   96           return filterConfig;
   97       }
   98   
   99       /** @deprecated Not needed in final version of Servlet 2.3 API - replaced by init(). */
  100       // NOTE: SiteMesh doesn't work with Orion 1.5.2 without this method
  101       public void setFilterConfig(FilterConfig filterConfig) {
  102           init(filterConfig);
  103       }
  104   
  105       /** Shutdown filter. */
  106       public void destroy() {
  107           factory = null;
  108       }
  109   
  110       /**
  111        * Continue in filter-chain, writing all content to buffer and parsing
  112        * into returned {@link com.opensymphony.module.sitemesh.Page} object. If
  113        * {@link com.opensymphony.module.sitemesh.Page} is not parseable, null is returned.
  114        */
  115       protected Page parsePage(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
  116           try {
  117               PageResponseWrapper pageResponse = new PageResponseWrapper(response, factory);
  118               chain.doFilter(request, pageResponse);
  119               // check if another servlet or filter put a page object to the request
  120               Page result = (Page)request.getAttribute(PAGE);
  121               if (result == null) {
  122                   // parse the page
  123                   result = pageResponse.getPage();
  124               }
  125               request.setAttribute(USING_STREAM, new Boolean(pageResponse.isUsingStream()));
  126               return result;
  127           }
  128           catch (IllegalStateException e) {
  129               // weblogic throws an IllegalStateException when an error page is served.
  130               // it's ok to ignore this, however for all other containers it should be thrown
  131               // properly.
  132               if (Container.get() != Container.WEBLOGIC) throw e;
  133               return null;
  134           }
  135       }
  136   
  137       /**
  138        * Apply {@link com.opensymphony.module.sitemesh.Decorator} to
  139        * {@link com.opensymphony.module.sitemesh.Page} and write to the response.
  140        */
  141       protected void applyDecorator(Page page, Decorator decorator, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  142           try {
  143               request.setAttribute(PAGE, page);
  144               ServletContext context = filterConfig.getServletContext();
  145               // see if the URI path (webapp) is set
  146               if (decorator.getURIPath() != null) {
  147                   // in a security conscious environment, the servlet container
  148                   // may return null for a given URL
  149                   if (context.getContext(decorator.getURIPath()) != null) {
  150                       context = context.getContext(decorator.getURIPath());
  151                   }
  152               }
  153               // get the dispatcher for the decorator
  154               RequestDispatcher dispatcher = context.getRequestDispatcher(decorator.getPage());
  155               // create a wrapper around the response
  156               dispatcher.include(request, response);
  157   
  158               // set the headers specified as decorator init params
  159               while (decorator.getInitParameterNames().hasNext()) {
  160                   String initParam = (String) decorator.getInitParameterNames().next();
  161                   if (initParam.startsWith("header.")) {
  162                       response.setHeader(initParam.substring(initParam.indexOf('.')), decorator.getInitParameter(initParam));
  163                   }
  164               }
  165   
  166               request.removeAttribute(PAGE);
  167           }
  168           catch (RuntimeException e) {
  169               // added a print message here because otherwise Tomcat swallows
  170               // the error and you never see it = bad!
  171               if (Container.get() == Container.TOMCAT)
  172                   e.printStackTrace();
  173   
  174               throw e;
  175           }
  176       }
  177   
  178       /** Write the original page data to the response. */
  179       private void writeOriginal(HttpServletRequest request, HttpServletResponse response, Page page) throws IOException {
  180           response.setContentLength(page.getContentLength());
  181           if (request.getAttribute(USING_STREAM).equals(Boolean.TRUE))
  182           {
  183               PrintWriter writer = new PrintWriter(response.getOutputStream());
  184               page.writePage(writer);
  185               //flush writer to underlying outputStream
  186               writer.flush();
  187               response.getOutputStream().flush();
  188           }
  189           else
  190           {
  191               page.writePage(response.getWriter());
  192               response.getWriter().flush();
  193           }
  194       }
  195   }

Save This Page
Home » sitemesh-2.3 » com.opensymphony.module » sitemesh » filter » [javadoc | source]