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
26
27
28 class RestDelegatingServletFilter implements Filter
29 {
30
31
32
33 private static final Slf4jBridge.Helper SLF4J_BRIDGE = Slf4jBridge.createHelper();
34
35
36
37
38 private final ServletContainer servletContainer;
39 private final ResourceConfigManager resourceConfigManager;
40
41
42
43
44
45
46
47
48
49
50 private volatile ClassLoader chainingClassLoader;
51
52 RestDelegatingServletFilter(OsgiPlugin plugin, RestApiContext restContextPath)
53 {
54 resourceConfigManager = new ResourceConfigManager(plugin, plugin.getBundle());
55 this.servletContainer = new JerseyOsgiServletContainer(plugin, restContextPath, resourceConfigManager);
56 }
57
58 public void init(FilterConfig config) throws ServletException
59 {
60 initChainingClassLoader();
61 initServletContainer(config);
62 }
63
64 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
65 {
66 ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
67 Thread.currentThread().setContextClassLoader(chainingClassLoader);
68 try
69 {
70 servletContainer.doFilter(request, response, chain);
71 }
72 finally
73 {
74 Thread.currentThread().setContextClassLoader(currentThreadClassLoader);
75 }
76 }
77
78 public void destroy()
79 {
80 destroyServletContainer();
81 resourceConfigManager.destroy();
82 }
83
84 private void initChainingClassLoader()
85 {
86 chainingClassLoader = new ChainingClassLoader(RestModuleDescriptor.class.getClassLoader(), Thread.currentThread().getContextClassLoader());
87 }
88
89 private void initServletContainer(FilterConfig config) throws ServletException
90 {
91 ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
92 Thread.currentThread().setContextClassLoader(chainingClassLoader);
93 try
94 {
95 SLF4J_BRIDGE.install();
96 servletContainer.init(config);
97 }
98 finally
99 {
100 Thread.currentThread().setContextClassLoader(currentThreadClassLoader);
101 }
102 }
103
104 private void destroyServletContainer()
105 {
106 ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
107 Thread.currentThread().setContextClassLoader(chainingClassLoader);
108 try
109 {
110 servletContainer.destroy();
111 SLF4J_BRIDGE.uninstall();
112 }
113 finally
114 {
115 Thread.currentThread().setContextClassLoader(currentThreadClassLoader);
116 }
117 }
118
119
120
121
122 private static class JerseyOsgiServletContainer extends ServletContainer
123 {
124 private final OsgiPlugin plugin;
125 private final RestApiContext restApiContext;
126 private final ResourceConfigManager resourceConfigManager;
127
128 private static final String PARAM_EXTENSION_FILTER_EXCLUDES = "extension.filter.excludes";
129
130 public JerseyOsgiServletContainer(OsgiPlugin plugin, RestApiContext restApiContext, final ResourceConfigManager resourceConfigManager)
131 {
132 this.resourceConfigManager = Preconditions.checkNotNull(resourceConfigManager);
133 this.plugin = Preconditions.checkNotNull(plugin);
134 this.restApiContext = Preconditions.checkNotNull(restApiContext);
135 }
136
137 @Override
138 protected ResourceConfig getDefaultResourceConfig(Map<String, Object> props, WebConfig webConfig) throws ServletException
139 {
140
141 final String deprecatedName = "com.atlassian.plugins.rest.module.filter.ExtensionJerseyFilter" + "#excludes";
142 final String excludeParam = webConfig.getInitParameter(deprecatedName) != null ?
143 webConfig.getInitParameter(deprecatedName) : webConfig.getInitParameter(PARAM_EXTENSION_FILTER_EXCLUDES);
144
145 final String[] excludes = StringUtils.split(excludeParam, " ,;");
146
147 return resourceConfigManager.createResourceConfig(props, excludes, restApiContext.getPackages());
148 }
149
150 @Override
151 public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
152 throws IOException, ServletException
153 {
154
155 String baseUriPath;
156 if (request.getRequestURI().contains(restApiContext.getPathToLatest()))
157 {
158 baseUriPath = request.getContextPath() + restApiContext.getPathToLatest();
159 }
160 else
161 {
162 baseUriPath = request.getContextPath() + restApiContext.getPathToVersion();
163 }
164 final UriBuilder absoluteUriBuilder = UriBuilder.fromUri(request.getRequestURL().toString());
165
166 final URI baseUri = absoluteUriBuilder.replacePath(baseUriPath).path("/").build();
167
168 final URI requestUri = absoluteUriBuilder.replacePath(request.getRequestURI()).replaceQuery(
169 request.getQueryString()).build();
170
171 service(baseUri, requestUri, request, response);
172 }
173
174 @Override
175 protected void initiate(ResourceConfig resourceConfig, WebApplication webApplication)
176 {
177 webApplication.initiate(resourceConfig, new OsgiComponentProviderFactory(resourceConfig, plugin));
178 }
179 }
180 }