1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.resource.servlet

File RoutingFilter.java

 

Coverage histogram

../../../../img/srcFileCovDistChart9.png
38% of files have more coverage

Code metrics

8
50
7
1
217
127
17
0.34
7.14
7
2.43

Classes

Class Line # Actions
RoutingFilter 65 50 0% 17 7
0.892307789.2%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.resource.servlet;
21   
22    import java.io.IOException;
23    import java.net.MalformedURLException;
24    import java.net.URL;
25    import java.util.Collections;
26   
27    import javax.servlet.Filter;
28    import javax.servlet.FilterChain;
29    import javax.servlet.FilterConfig;
30    import javax.servlet.ServletContext;
31    import javax.servlet.ServletException;
32    import javax.servlet.ServletRequest;
33    import javax.servlet.ServletResponse;
34    import javax.servlet.http.HttpServletRequest;
35   
36    import org.apache.commons.lang3.StringUtils;
37    import org.xwiki.component.manager.ComponentLookupException;
38    import org.xwiki.component.manager.ComponentManager;
39    import org.xwiki.component.util.DefaultParameterizedType;
40    import org.xwiki.resource.CreateResourceReferenceException;
41    import org.xwiki.resource.ResourceReferenceHandlerManager;
42    import org.xwiki.resource.ResourceType;
43    import org.xwiki.resource.ResourceTypeResolver;
44    import org.xwiki.resource.resources.ResourcesResourceReference;
45    import org.xwiki.resource.skins.SkinsResourceReference;
46    import org.xwiki.url.ExtendedURL;
47   
48    /**
49    * Decides how to route an incoming URL into the XWiki system. There are various possibilities:
50    * <ul>
51    * <li>If there's a registered component of type {@link org.xwiki.resource.ResourceReferenceHandler} matching the
52    * {@link ResourceType} passed in the URL (for example when using the {@code standard} URL scheme, the Resource
53    * Type is the segment path just after the Context Path, i.e. {@code bin} in
54    * {@code http://<server>/xwiki/bin/view/Space/Page}), then the {@code resourceReferenceHandler} Servlet is
55    * called to handle it.</li>
56    * <li>If not, then continue executing the rest of the {@code web.xml} file, thus bridging to the old system,
57    * including the existing Struts Action Servlet.</li>
58    * </ul>
59    * As time progresses it is expected that more and more Resource Types will have registered
60    * {@link org.xwiki.resource.ResourceReferenceHandler}.
61    *
62    * @version $Id: 9e647da294c1b9154170a4880201e9246c7ec0ff $
63    * @since 7.1M1
64    */
 
65    public class RoutingFilter implements Filter
66    {
67    static final String RESOURCE_TYPE_NAME = "resourceType";
68    static final String RESOURCE_EXTENDEDURL = "resourceURL";
69   
70    private ComponentManager rootComponentManager;
71   
72    private ServletContext servletContext;
73   
 
74  32 toggle @Override
75    public void init(FilterConfig filterConfig) throws ServletException
76    {
77    // Get the Component Manager which has been initialized first in a Servlet Context Listener.
78  32 this.rootComponentManager =
79    (ComponentManager) filterConfig.getServletContext().getAttribute(ComponentManager.class.getName());
80    // Save the Servlet Context to be able to do forwards later on
81  32 this.servletContext = filterConfig.getServletContext();
82    }
83   
 
84  14118 toggle @Override
85    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
86    throws IOException, ServletException
87    {
88    // Only handle HTTP Servlet requests...
89  14099 if (!(request instanceof HttpServletRequest)) {
90  0 chain.doFilter(request, response);
91  0 return;
92    }
93   
94  14057 HttpServletRequest httpRequest = (HttpServletRequest) request;
95   
96    // Step 1: Construct an ExtendedURL to make it easy to manipulate the URL segments
97  14079 ExtendedURL extendedURL = constructExtendedURL(httpRequest);
98   
99    // Step 2: Extract the Resource Type from the ExtendedURL
100  14109 ResourceTypeResolver<ExtendedURL> urlResourceTypeResolver = getResourceTypeResolver();
101  14092 ResourceType resourceType;
102  14092 try {
103  14099 resourceType = urlResourceTypeResolver.resolve(extendedURL, Collections.<String, Object>emptyMap());
104    } catch (Exception e) {
105    // Failed to resolve the passed ExtendedURL. This means it's not a URL that should be handled by a Resource
106    // Reference Handler and we let it go through so that the next Filter or Servlet from web.xml will handle
107    // it. Note that since some URL schemes may want to handle features like short URLs where the Resource Type
108    // is omitted, this catch will not be called in this case and this is why we need Step 2 below in order
109    // to recognize static resources and serve them!
110  1 chain.doFilter(request, response);
111  1 return;
112    }
113   
114    // Step 3: Handle static resources simply by letting them go through so that the Servlet Container will use its
115    // default Servlet to serve static content.
116    // Note: This step is a performance optimization only as it would also work to go directly at step 4 since there
117    // would be no handler found for static resources and thus the Servlet Container would continue processing the
118    // content of web.xml and would serve static files using its File Servlet.
119  14097 if (resourceType.equals(ResourcesResourceReference.TYPE) || resourceType.equals(SkinsResourceReference.TYPE)) {
120  1080 chain.doFilter(request, response);
121  1106 return;
122    }
123   
124    // Step 4: Check if there's a Handler available for the Resource Type
125  12990 ResourceReferenceHandlerManager<ResourceType> resourceReferenceHandlerManager =
126    getResourceReferenceHandlerManager();
127    // Note that ATM the EntityResourceReferenceHandler is configured to NOT handle "bin" Resource Types. See
128    // the comment in EntityResourceReferenceHandler#getSupportedResourceReferences() for more details. This allows
129    // to fallback on the Filter/Servlet chain as defined by the web.xml and have XWikiAction be called to handle
130    // "bin" Resource Types. It also allows other mappings to be used to handle other resource types such as
131    // "rest", "webdav" and "xmlrpc" Resource Types.
132  12999 if (!resourceReferenceHandlerManager.canHandle(resourceType)) {
133    // Let it go through so that the next Filter or Servlet from web.xml will handle it.
134  11274 chain.doFilter(request, response);
135  11307 return;
136    }
137   
138    // Step 4: There is a Handler to handle our request, call the Resource Handler Servlet. Note that calling a
139    // Sevlet gives us more flexibility if we wish to execute some more Filters before the Servlet executes for
140    // example.
141    //
142    // However before doing that, we save the Resource Type so that the Servlet doesn't have to extract it again!
143    // We also save the URL since we don't want to have to compute the full URL again in the Resource Reference
144    // Handler Servlet!
145  1706 request.setAttribute(RESOURCE_TYPE_NAME, resourceType);
146  1712 request.setAttribute(RESOURCE_EXTENDEDURL, extendedURL);
147  1714 this.servletContext.getNamedDispatcher("resourceReferenceHandler").forward(request, response);
148    }
149   
 
150  32 toggle @Override
151    public void destroy()
152    {
153  32 this.rootComponentManager = null;
154  32 this.servletContext = null;
155    }
156   
 
157  12935 toggle private ResourceReferenceHandlerManager<ResourceType> getResourceReferenceHandlerManager() throws ServletException
158    {
159  12960 ResourceReferenceHandlerManager<ResourceType> resourceReferenceHandlerManager;
160  12987 try {
161  13000 resourceReferenceHandlerManager = this.rootComponentManager.getInstance(
162    new DefaultParameterizedType(null, ResourceReferenceHandlerManager.class, ResourceType.class));
163    } catch (ComponentLookupException e) {
164    // Should not happen since a Resource Reference Handler should always exist on the system.
165  0 throw new ServletException("Failed to locate a Resource Reference Handler Manager component", e);
166    }
167  13017 return resourceReferenceHandlerManager;
168    }
169   
 
170  14075 toggle private ResourceTypeResolver<ExtendedURL> getResourceTypeResolver() throws ServletException
171    {
172  14086 ResourceTypeResolver<ExtendedURL> urlResourceTypeResolver;
173  14106 try {
174  14107 urlResourceTypeResolver = this.rootComponentManager.getInstance(
175    new DefaultParameterizedType(null, ResourceTypeResolver.class, ExtendedURL.class));
176    } catch (ComponentLookupException e) {
177    // Should not happen since an ExtendedURL Resource Type Resolver should exist on the system.
178  0 throw new ServletException("Failed to locate an ExtendedURL Resource Type Resolver component", e);
179    }
180  14118 return urlResourceTypeResolver;
181    }
182   
 
183  14057 toggle private ExtendedURL constructExtendedURL(HttpServletRequest httpRequest) throws ServletException
184    {
185  14066 ExtendedURL extendedURL;
186  14071 URL url = getRequestURL(httpRequest);
187  14105 try {
188  14113 extendedURL = new ExtendedURL(url, httpRequest.getContextPath());
189    } catch (CreateResourceReferenceException e) {
190  0 throw new ServletException(String.format("Invalid URL [%s]", url), e);
191    }
192  14108 return extendedURL;
193    }
194   
195    /**
196    * Reconstruct the full URL since the Servlet API doesn't provide a way to access it directly.
197    */
 
198  13967 toggle private URL getRequestURL(HttpServletRequest request) throws ServletException
199    {
200  13974 URL url;
201  14014 try {
202  14077 StringBuffer requestURL = request.getRequestURL();
203  14119 String qs = request.getQueryString();
204  14093 if (!StringUtils.isEmpty(qs)) {
205  9435 url = new URL(requestURL.toString() + "?" + qs);
206    } else {
207  4648 url = new URL(requestURL.toString());
208    }
209    } catch (MalformedURLException e) {
210    // Shouldn't happen normally!
211  0 throw new ServletException(
212    String.format("Failed to reconstruct URL from HTTP Servlet Request (URL [%s], Query String [%s])",
213    request.getRequestURL(), request.getQueryString()), e);
214    }
215  14095 return url;
216    }
217    }