View Javadoc

1   package com.atlassian.plugin.servlet;
2   
3   import java.util.Iterator;
4   
5   import javax.servlet.http.HttpServletRequest;
6   import javax.servlet.http.HttpServletRequestWrapper;
7   
8   import com.atlassian.plugin.servlet.descriptors.BaseServletModuleDescriptor;
9   
10  /**
11   * A request wrapper for requests bound for servlets declared in plugins.  Does the necessary path
12   * munging for requests so that they look like they are 
13   */
14  public class PluginHttpRequestWrapper extends HttpServletRequestWrapper
15  {
16      private final String basePath;
17  
18      public PluginHttpRequestWrapper(HttpServletRequest request, BaseServletModuleDescriptor<?> descriptor)
19      {
20          super(request);
21          this.basePath = findBasePath(descriptor);
22      }
23  
24      public String getServletPath()
25      {
26          String servletPath = super.getServletPath();
27          if (basePath != null)
28          {
29              servletPath += basePath;
30          }
31          return servletPath;
32      }
33  
34      public String getPathInfo()
35      {
36          String pathInfo = super.getPathInfo();
37          if (pathInfo != null && basePath != null)
38              return pathInfo.substring(basePath.length());
39          return pathInfo;
40      }
41      
42      /**
43       * A <a href="http://bluxte.net/blog/2006-03/29-40-33.html">commenter</a> based on the 
44       * <a href="http://java.sun.com/products/servlet/2.1/html/introduction.fm.html#1499">servlet mapping spec</a>
45       *  defined the mapping processing as:
46       *  
47       * <ol>
48       *   <li>A string beginning with a '/' character and ending with a '/*' postfix is used for path mapping.</li>
49       *   <li>A string beginning with a'*.' prefix is used as an extension mapping.</li>
50       *   <li>A string containing only the '/' character indicates the "default" servlet of the application. In this 
51       *       case the servlet path is the request URI minus the context path and the path info is null.</li>
52       *   <li>All other strings are used for exact matches only.</li>
53       * </ol>
54       * 
55       * To find the base path we're really only interested in the first case.  Everything else will just get a null
56       * base path.  So we'll iterate through the list of paths specified and for the ones that match (1) above, check if
57       * the path info returned by the super class matches.  If it does, we return that base path, otherwise we move onto
58       * the next one.  
59       */
60      private String findBasePath(BaseServletModuleDescriptor<?> descriptor)
61      {
62          String pathInfo = super.getPathInfo();
63          if (pathInfo != null)
64          {
65              for (Iterator<String> pathIterator = descriptor.getPaths().iterator(); pathIterator.hasNext(); )
66              {
67                  String basePath = pathIterator.next();
68                  if (isPathMapping(basePath) && pathInfo.startsWith(getMappingRootPath(basePath)))
69                  {
70                      return getMappingRootPath(basePath);
71                  }
72              }
73          }
74          return null;
75      }
76      
77      private boolean isPathMapping(String path)
78      {
79          return path.startsWith("/") && path.endsWith("/*");
80      }
81      
82      private String getMappingRootPath(String pathMapping)
83      {
84          return pathMapping.substring(0, pathMapping.length() - 2);
85      }
86  }