Coverage Report - org.apache.tiles.web.util.TilesDecorationFilter
 
Classes in this File Line Coverage Branch Coverage Complexity
TilesDecorationFilter
87%
56/64
56%
17/30
3.375
TilesDecorationFilter$DefaultMutator
0%
0/6
N/A
3.375
 
 1  
 /*
 2  
  * $Id: TilesDecorationFilter.java 1058093 2011-01-12 11:49:02Z apetrelli $
 3  
  *
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  * http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 package org.apache.tiles.web.util;
 22  
 
 23  
 import java.io.IOException;
 24  
 import java.util.Enumeration;
 25  
 import java.util.HashMap;
 26  
 import java.util.Map;
 27  
 
 28  
 import javax.servlet.Filter;
 29  
 import javax.servlet.FilterChain;
 30  
 import javax.servlet.FilterConfig;
 31  
 import javax.servlet.ServletContext;
 32  
 import javax.servlet.ServletException;
 33  
 import javax.servlet.ServletResponse;
 34  
 import javax.servlet.http.HttpServletRequest;
 35  
 import javax.servlet.http.HttpServletResponse;
 36  
 
 37  
 import org.apache.tiles.Attribute;
 38  
 import org.apache.tiles.AttributeContext;
 39  
 import org.apache.tiles.TilesContainer;
 40  
 import org.apache.tiles.access.TilesAccess;
 41  
 import org.apache.tiles.request.ApplicationContext;
 42  
 import org.apache.tiles.request.Request;
 43  
 import org.apache.tiles.request.reflect.CannotInstantiateObjectException;
 44  
 import org.apache.tiles.request.reflect.ClassUtil;
 45  
 import org.apache.tiles.request.servlet.ServletRequest;
 46  
 import org.slf4j.Logger;
 47  
 import org.slf4j.LoggerFactory;
 48  
 
 49  
 /**
 50  
  * Decoration Filter.  Intercepts all requests and decorates them
 51  
  * with the configured definition.
 52  
  * <p/>
 53  
  * For example, given the following config:
 54  
  * &lt;xmp&gt;
 55  
  * &lt;filter&gt;
 56  
  * &lt;filter-name&gt;Tiles Decoration Filter&lt;/filter-name&gt;
 57  
  * &lt;filter-class&gt;org.apache.tiles.web.TilesDecorationFilter&lt;/filter-class&gt;
 58  
  * &lt;init-param&gt;
 59  
  * &lt;param-name&gt;definition&lt;/param-name&gt;
 60  
  * &lt;param-value&gt;test.definition&lt;/param-value&gt;
 61  
  * &lt;/init-param&gt;
 62  
  * &lt;init-param&gt;
 63  
  * &lt;param-name&gt;attribute-name&lt;/param-name&gt;
 64  
  * &lt;param-value&gt;body&lt;/param-value&gt;
 65  
  * &lt;/init-param&gt;
 66  
  * &lt;init-param&gt;
 67  
  * &lt;param-name&gt;prevent-token&lt;/param-name&gt;
 68  
  * &lt;param-value&gt;layout&lt;/param-value&gt;
 69  
  * &lt;/init-param&gt;
 70  
  * &lt;/filter&gt;
 71  
  * <p/>
 72  
  * &lt;filter-mapping&gt;
 73  
  * &lt;filter-name&gt;Tiles Decoration Filter&lt;/filter-name&gt;
 74  
  * &lt;url-pattern&gt;/testdecorationfilter.jsp&lt;/url-pattern&gt;
 75  
  * &lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt;
 76  
  * &lt;/filter-mapping&gt;
 77  
  * &lt;/xmp&gt;
 78  
  * The filter will intercept all requests to the indicated url pattern
 79  
  * store the initial request path as the "body"  attribute and then render the
 80  
  * "test.definition" definition.  The filter will only redecorate those requests
 81  
  * which do not contain the request attribute associated with the prevent token
 82  
  * "layout".
 83  
  */
 84  1
 public class TilesDecorationFilter implements Filter {
 85  
 
 86  
     /**
 87  
      * Init parameter to define the key of the container to use.
 88  
      *
 89  
      * @since 2.1.2
 90  
      */
 91  
     public static final String CONTAINER_KEY_INIT_PARAMETER =
 92  
         "org.apache.tiles.web.util.TilesDecorationFilter.CONTAINER_KEY";
 93  
 
 94  
     /**
 95  
      * The logging object.
 96  
      */
 97  1
     private Logger log = LoggerFactory.getLogger(TilesDecorationFilter.class);
 98  
 
 99  
     /**
 100  
      * Filter configuration.
 101  
      */
 102  
     private FilterConfig filterConfig;
 103  
 
 104  
     /**
 105  
      * The key under which the container is stored.
 106  
      */
 107  
     private String containerKey;
 108  
 
 109  
     /**
 110  
      * The name of the definition attribute used to
 111  
      * pass on the request.
 112  
      */
 113  1
     private String definitionAttributeName = "content";
 114  
 
 115  
     /**
 116  
      * The definition name to use.
 117  
      */
 118  1
     private String definitionName = "layout";
 119  
 
 120  
     /**
 121  
      * Token used to prevent re-decoration of requests.
 122  
      * This token is used to prevent infinate loops on
 123  
      * filters configured to match wildcards.
 124  
      */
 125  
     private String preventDecorationToken;
 126  
 
 127  
     /**
 128  
      * Stores a map of the type "mask -> definition": when a definition name
 129  
      * mask is identified, it is substituted with the configured definition.
 130  
      */
 131  
     private Map<String, String> alternateDefinitions;
 132  
 
 133  
     /**
 134  
      * The object that will mutate the attribute context so that it uses
 135  
      * different attributes.
 136  
      */
 137  1
     private AttributeContextMutator mutator = null;
 138  
 
 139  
     /**
 140  
      * The servlet context.
 141  
      */
 142  
     private ServletContext servletContext;
 143  
 
 144  
     /** {@inheritDoc} */
 145  
     public void init(FilterConfig config) throws ServletException {
 146  1
         filterConfig = config;
 147  1
         servletContext = filterConfig.getServletContext();
 148  
 
 149  1
         containerKey = filterConfig
 150  
                 .getInitParameter(CONTAINER_KEY_INIT_PARAMETER);
 151  
 
 152  1
         String temp = config.getInitParameter("attribute-name");
 153  1
         if (temp != null) {
 154  1
             definitionAttributeName = temp;
 155  
         }
 156  
 
 157  1
         temp = config.getInitParameter("definition");
 158  1
         if (temp != null) {
 159  1
             definitionName = temp;
 160  
         }
 161  
 
 162  1
         temp = config.getInitParameter("prevent-token");
 163  1
         preventDecorationToken = "org.apache.tiles.decoration.PREVENT:"
 164  
                 + (temp == null ? definitionName : temp);
 165  
 
 166  1
         alternateDefinitions = parseAlternateDefinitions();
 167  
 
 168  1
         temp = config.getInitParameter("mutator");
 169  1
         if (temp != null) {
 170  
             try {
 171  1
                 mutator = (AttributeContextMutator) ClassUtil.instantiate(temp);
 172  0
             } catch (CannotInstantiateObjectException e) {
 173  0
                 throw new ServletException("Unable to instantiate specified context mutator.", e);
 174  1
             }
 175  
         } else {
 176  0
             mutator = new DefaultMutator();
 177  
         }
 178  1
     }
 179  
 
 180  
     /**
 181  
      * Creates the alternate definitions map, to map a mask of definition names
 182  
      * to a configured definition.
 183  
      *
 184  
      * @return The alternate definitions map.
 185  
      */
 186  
     @SuppressWarnings("unchecked")
 187  
     protected Map<String, String> parseAlternateDefinitions() {
 188  1
         Map<String, String> map = new HashMap<String, String>();
 189  1
         Enumeration<String> e = filterConfig.getInitParameterNames();
 190  2
         while (e.hasMoreElements()) {
 191  1
             String parm = e.nextElement();
 192  1
             if (parm.startsWith("definition(") && parm.endsWith("*)")) {
 193  1
                 String value = filterConfig.getInitParameter(parm);
 194  1
                 String mask = parm.substring("definition(".length());
 195  1
                 mask = mask.substring(0, mask.lastIndexOf("*)"));
 196  1
                 map.put(mask, value);
 197  1
                 log.info("Mapping all requests matching '" + mask
 198  
                         + "*' to definition '" + value + "'");
 199  
             }
 200  1
         }
 201  1
         return map;
 202  
     }
 203  
 
 204  
     /** {@inheritDoc} */
 205  
     public void destroy() {
 206  0
         filterConfig = null;
 207  0
     }
 208  
 
 209  
 
 210  
     /**
 211  
      * {@inheritDoc}
 212  
      */
 213  
     public void doFilter(javax.servlet.ServletRequest req, ServletResponse res, FilterChain filterChain)
 214  
             throws IOException, ServletException {
 215  
         // If the request contains the prevent token, we must not reapply the definition.
 216  
         // This is used to ensure that filters mapped to wild cards do not infinately
 217  
         // loop.
 218  1
         if (!isPreventTokenPresent(req)) {
 219  1
             ApplicationContext applicationContext = org.apache.tiles.request.servlet.ServletUtil
 220  
                     .getApplicationContext(servletContext);
 221  1
             Request request = new ServletRequest(applicationContext,
 222  
                     (HttpServletRequest) req, (HttpServletResponse) res);
 223  1
             TilesContainer container = TilesAccess.getContainer(applicationContext,
 224  
                     containerKey);
 225  1
             mutator.mutate(container.getAttributeContext(request), req);
 226  1
             if (preventDecorationToken != null) {
 227  1
                 req.setAttribute(preventDecorationToken, Boolean.TRUE);
 228  
             }
 229  1
             String definitionName = getDefinitionForRequest(req);
 230  1
             container.render(definitionName, request);
 231  
         }
 232  1
         filterChain.doFilter(req, res);
 233  1
     }
 234  
 
 235  
     /**
 236  
      * Returns the final definition to render for the given request.
 237  
      *
 238  
      * @param request The request object.
 239  
      * @return The final definition name.
 240  
      */
 241  
     private String getDefinitionForRequest(javax.servlet.ServletRequest request) {
 242  1
         if (alternateDefinitions.size() < 1) {
 243  0
             return definitionName;
 244  
         }
 245  1
         String base = getRequestBase(request);
 246  1
         for (Map.Entry<String, String> pair : alternateDefinitions.entrySet()) {
 247  1
             if (base.startsWith(pair.getKey())) {
 248  0
                 return pair.getValue();
 249  
             }
 250  1
         }
 251  1
         return definitionName;
 252  
     }
 253  
 
 254  
     /**
 255  
      * Returns the request base, i.e. the the URL to calculate all the relative
 256  
      * paths.
 257  
      *
 258  
      * @param request The request object to use.
 259  
      * @return The request base.
 260  
      */
 261  
     private String getRequestBase(javax.servlet.ServletRequest request) {
 262  
         // Included Path
 263  1
         String include = (String) request.getAttribute("javax.servlet.include.servlet_path");
 264  1
         if (include != null) {
 265  0
             return include;
 266  
         }
 267  
 
 268  
         // As opposed to includes, if a forward occurs, it will update the servletPath property
 269  
         // and include the original as the request attribute.
 270  1
         return ((HttpServletRequest) request).getServletPath();
 271  
     }
 272  
 
 273  
     /**
 274  
      * The default attribute context mutator to use.
 275  
      */
 276  0
     class DefaultMutator implements AttributeContextMutator {
 277  
 
 278  
         /** {@inheritDoc} */
 279  
         public void mutate(AttributeContext ctx, javax.servlet.ServletRequest req) {
 280  0
             Attribute attr = new Attribute();
 281  0
             attr.setRenderer("template");
 282  0
             attr.setValue(getRequestBase(req));
 283  0
             ctx.putAttribute(definitionAttributeName, attr);
 284  0
         }
 285  
     }
 286  
 
 287  
     /**
 288  
      * Checks if the prevent evaluation token is present.
 289  
      *
 290  
      * @param request The HTTP request object.
 291  
      * @return <code>true</code> if the token is present.
 292  
      */
 293  
     private boolean isPreventTokenPresent(javax.servlet.ServletRequest request) {
 294  1
         return preventDecorationToken != null && request.getAttribute(preventDecorationToken) != null;
 295  
     }
 296  
 }