View Javadoc

1   package com.atlassian.plugins.rest.module;
2   
3   import com.atlassian.plugin.osgi.factory.OsgiPlugin;
4   import com.google.common.base.Preconditions;
5   import com.sun.jersey.api.core.ResourceConfig;
6   import com.sun.jersey.spi.container.WebApplication;
7   import com.sun.jersey.spi.container.servlet.ServletContainer;
8   import com.sun.jersey.spi.container.servlet.WebConfig;
9   import org.apache.commons.lang.StringUtils;
10  
11  import javax.servlet.Filter;
12  import javax.servlet.FilterChain;
13  import javax.servlet.FilterConfig;
14  import javax.servlet.ServletException;
15  import javax.servlet.ServletRequest;
16  import javax.servlet.ServletResponse;
17  import javax.servlet.http.HttpServletRequest;
18  import javax.servlet.http.HttpServletResponse;
19  import javax.ws.rs.core.UriBuilder;
20  import java.io.IOException;
21  import java.net.URI;
22  import java.util.Map;
23  
24  /**
25   * A delegating servlet that swaps the context class loader with a {@link ChainingClassLoader} that delegates to both
26   * the class loader of the {@link RestModuleDescriptor} and the current context class loader.
27   */
28  class RestDelegatingServletFilter implements Filter
29  {
30      /**
31       * Overridden servlet container to use our own {@link OsgiResourceConfig}.
32       */
33      private final ServletContainer servletContainer;
34      private final ResourceConfigManager resourceConfigManager;
35  
36      RestDelegatingServletFilter(OsgiPlugin plugin, RestApiContext restContextPath)
37      {
38          resourceConfigManager = new ResourceConfigManager(plugin, plugin.getBundle());
39          this.servletContainer = new JerseyOsgiServletContainer(plugin, restContextPath, resourceConfigManager);
40      }
41  
42      public void init(FilterConfig config) throws ServletException
43      {
44          final ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
45          try
46          {
47              Thread.currentThread().setContextClassLoader(new ChainingClassLoader(RestModuleDescriptor.class.getClassLoader(), currentThreadClassLoader));
48              servletContainer.init(config);
49          }
50          finally
51          {
52              Thread.currentThread().setContextClassLoader(currentThreadClassLoader);
53          }
54      }
55  
56      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
57      {
58          final ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
59          try
60          {
61              Thread.currentThread().setContextClassLoader(new ChainingClassLoader(RestModuleDescriptor.class.getClassLoader(), currentThreadClassLoader));
62              servletContainer.doFilter(request, response, chain);
63          }
64          finally
65          {
66              Thread.currentThread().setContextClassLoader(currentThreadClassLoader);
67          }
68      }
69  
70      public void destroy()
71      {
72          servletContainer.destroy();
73          resourceConfigManager.destroy();
74      }
75  
76      /**
77       *
78       */
79      private static class JerseyOsgiServletContainer extends ServletContainer
80      {
81          private final OsgiPlugin plugin;
82          private final RestApiContext restApiContext;
83          private final ResourceConfigManager resourceConfigManager;
84  
85          private static final String PARAM_EXTENSION_FILTER_EXCLUDES = "extension.filter.excludes";
86  
87          public JerseyOsgiServletContainer(OsgiPlugin plugin, RestApiContext restApiContext, final ResourceConfigManager resourceConfigManager)
88          {
89              this.resourceConfigManager = Preconditions.checkNotNull(resourceConfigManager);
90              this.plugin = Preconditions.checkNotNull(plugin);
91              this.restApiContext = Preconditions.checkNotNull(restApiContext);
92          }
93  
94          @Override
95          protected ResourceConfig getDefaultResourceConfig(Map<String, Object> props, WebConfig webConfig) throws ServletException
96          {
97              // get the excludes parameter: support the old param name for Atlassian Gadgets
98              final String deprecatedName = "com.atlassian.plugins.rest.module.filter.ExtensionJerseyFilter" + "#excludes";
99              final String excludeParam = webConfig.getInitParameter(deprecatedName) != null ?
100                     webConfig.getInitParameter(deprecatedName) : webConfig.getInitParameter(PARAM_EXTENSION_FILTER_EXCLUDES);
101 
102             final String[] excludes = StringUtils.split(excludeParam, " ,;");
103 
104             return resourceConfigManager.createResourceConfig(props, excludes, restApiContext.getPackages());
105         }
106 
107         @Override
108         public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
109                 throws IOException, ServletException
110         {
111             // This is overridden so that we can change the base URI, and keep the context path the same
112             String baseUriPath;
113             if (request.getRequestURI().contains(restApiContext.getPathToLatest()))
114             {
115                  baseUriPath = request.getContextPath() + restApiContext.getPathToLatest();
116             }
117             else
118             {
119                 baseUriPath = request.getContextPath() + restApiContext.getPathToVersion();
120             }
121             final UriBuilder absoluteUriBuilder = UriBuilder.fromUri(request.getRequestURL().toString());
122 
123             final URI baseUri = absoluteUriBuilder.replacePath(baseUriPath).path("/").build();
124 
125             final URI requestUri = absoluteUriBuilder.replacePath(request.getRequestURI()).replaceQuery(
126                     request.getQueryString()).build();
127 
128             service(baseUri, requestUri, request, response);
129         }
130 
131         @Override
132         protected void initiate(ResourceConfig resourceConfig, WebApplication webApplication)
133         {
134             webApplication.initiate(resourceConfig, new OsgiComponentProviderFactory(resourceConfig, plugin));
135         }
136     }
137 }