View Javadoc

1   package com.atlassian.plugin.servlet;
2   
3   import com.atlassian.plugin.Plugin;
4   
5   import javax.servlet.Filter;
6   import javax.servlet.FilterRegistration;
7   import javax.servlet.RequestDispatcher;
8   import javax.servlet.Servlet;
9   import javax.servlet.ServletContext;
10  import javax.servlet.ServletException;
11  import javax.servlet.ServletRegistration;
12  import javax.servlet.SessionCookieConfig;
13  import javax.servlet.SessionTrackingMode;
14  import javax.servlet.descriptor.JspConfigDescriptor;
15  import java.io.InputStream;
16  import java.lang.reflect.InvocationTargetException;
17  import java.lang.reflect.Method;
18  import java.net.MalformedURLException;
19  import java.net.URL;
20  import java.util.Collection;
21  import java.util.Collections;
22  import java.util.Enumeration;
23  import java.util.EventListener;
24  import java.util.HashSet;
25  import java.util.Map;
26  import java.util.Set;
27  import java.util.concurrent.ConcurrentMap;
28  
29  /**
30   * A wrapper around servlet context that allows plugin servlets to add
31   * attributes which will not be shared/clobbered by other plugins.
32   */
33  public class PluginServletContextWrapper implements ServletContext
34  {
35      private final Plugin plugin;
36      private final ServletContext context;
37      private final ConcurrentMap<String, Object> attributes;
38      private final Map<String, String> initParams;
39      
40      private final Method methodGetContextPath;
41      
42      public PluginServletContextWrapper(Plugin plugin, ServletContext context, ConcurrentMap<String, Object> attributes, Map<String, String> initParams)
43      {
44          Method tmpMethod = null;
45          this.plugin = plugin;
46          this.context = context;
47          this.attributes = attributes;
48          this.initParams = initParams;
49  
50          Class<?> cls = context.getClass();
51          try
52          {
53              tmpMethod = cls.getMethod("getContextPath");
54          } catch (NoSuchMethodException e)
55          {
56              // no problem, Servlet 2.4 or earlier found
57          }
58          methodGetContextPath = tmpMethod;
59      }
60  
61      /**
62       * <p>Gets the named attribute.  The attribute is first looked for in the local
63       * attribute map, if it is not found there it is looked for in the wrapped
64       * contexts attribute map.  If it is not there, null is returned.</p>
65       * 
66       * <p>A consequence of this ordering is that servlets may, in their own
67       * context, override but not overwrite attributes from the wrapped context.</p>
68       */
69      @Override
70      public Object getAttribute(String name)
71      {
72          Object attr = attributes.get(name);
73          if (attr == null)
74              attr = context.getAttribute(name);
75  
76          return attr;
77      }
78  
79      /**
80       * @return an enumeration of all the attributes from the wrapped 
81       *         context as well as the local attributes.
82       */
83      @Override
84      public Enumeration<String> getAttributeNames()
85      {
86          Collection<String> names = new HashSet<String>();
87          names.addAll(attributes.keySet());
88          names.addAll(Collections.list(context.getAttributeNames()));
89          return Collections.enumeration(names);
90      }
91  
92      /**
93       * Removes an attribute from the local context.  Leaves the wrapped context
94       * completely untouched.
95       */
96      @Override
97      public void removeAttribute(String name)
98      {
99          attributes.remove(name);
100     }
101 
102     /**
103      * <p>Sets an attribute in the local attribute map, leaving the wrapped
104      * context untouched.</p>
105      * 
106      * <p>Servlets may use this and the lookup ordering of the
107      * <code>getAttribute()</code> method to effectively override the value
108      * of an attribute in the wrapped servlet context with their own value and 
109      * this overridden value will only be seen in the plugins own scope.</p>
110      */
111     @Override
112     public void setAttribute(String name, Object object)
113     {
114         attributes.put(name, object);
115     }
116 
117     /**
118      * @return the init parameter from the servlet module descriptor.
119      */
120     @Override
121     public String getInitParameter(String name)
122     {
123         return initParams.get(name);
124     }
125 
126     /**
127      * @return an enumeration of the init parameters from the servlet module
128      * descriptor.
129      */
130     @Override
131     public Enumeration<String> getInitParameterNames()
132     {
133         return Collections.enumeration(initParams.keySet());
134     }
135 
136     /**
137      * @return the resource from the plugin classloader if it exists, otherwise the 
138      *         resource is looked up from the wrapped context and returned
139      */
140     @Override
141     public URL getResource(String path) throws MalformedURLException
142     {
143         URL url = plugin.getResource(path);
144         if (url == null)
145         {
146             url = context.getResource(path);
147         }
148         return url;
149     }
150 
151     /**
152      * @return the resource stream from the plugin classloader if it exists, otherwise
153      *         the resource stream is attempted to be retrieved from the wrapped context
154      */
155     @Override
156     public InputStream getResourceAsStream(String path)
157     {
158         InputStream in = plugin.getResourceAsStream(path);
159         if (in == null)
160         {
161             in = context.getResourceAsStream(path);
162         }
163         return in;
164     }
165 
166     /**
167      * @return null so that servlet plugins can't escape their box
168      */
169     @Override
170     public ServletContext getContext(String uripath)
171     {
172         return null;
173     }
174 
175     @Override
176     public String getContextPath() {
177 
178         // all this crap to deal with Servlet 2.4 containers better
179         if (methodGetContextPath != null)
180         {
181             try
182             {
183                 return (String) methodGetContextPath.invoke(context);
184             } catch (IllegalAccessException e)
185             {
186                 throw new RuntimeException("Cannot access this method", e);
187             } catch (InvocationTargetException e)
188             {
189                 throw new RuntimeException("Unable to execute getContextPath()", e.getCause());
190             }
191         } else
192         {
193             throw new UnsupportedOperationException("This servlet context doesn't support 2.5 methods");
194         }
195 
196     }
197 
198     //---- All methods below simply delegate to the wrapped servlet context ----
199 
200     @Override
201     public int getMajorVersion()
202     {
203         return context.getMajorVersion();
204     }
205 
206     @Override
207     public String getMimeType(String file)
208     {
209         return context.getMimeType(file);
210     }
211 
212     @Override
213     public int getMinorVersion()
214     {
215         return context.getMinorVersion();
216     }
217 
218     @Override
219     public RequestDispatcher getNamedDispatcher(String name)
220     {
221         return context.getNamedDispatcher(name);
222     }
223 
224     @Override
225     public String getRealPath(String path)
226     {
227         return context.getRealPath(path);
228     }
229 
230     @Override
231     public RequestDispatcher getRequestDispatcher(String path)
232     {
233         return context.getRequestDispatcher(path);
234     }
235 
236     @Override
237     public Set<String> getResourcePaths(String arg0)
238     {
239         return context.getResourcePaths(arg0);
240     }
241 
242     @Override
243     public String getServerInfo()
244     {
245         return context.getServerInfo();
246     }
247 
248     @Override
249     public Servlet getServlet(String name) throws ServletException
250     {
251         return context.getServlet(name);
252     }
253 
254     @Override
255     public String getServletContextName()
256     {
257         return context.getServletContextName();
258     }
259 
260     @Override
261     public Enumeration<String> getServletNames()
262     {
263         return context.getServletNames();
264     }
265 
266     @Override
267     public Enumeration<Servlet> getServlets()
268     {
269         return context.getServlets();
270     }
271 
272     @Override
273     public void log(Exception exception, String msg)
274     {
275         context.log(exception, msg);
276     }
277 
278     @Override
279     public void log(String message, Throwable throwable)
280     {
281         context.log(message, throwable);
282     }
283 
284     @Override
285     public void log(String msg)
286     {
287         context.log(msg);
288     }
289 
290     //---- Servlet 3.0 methods ----
291 
292     @Override
293     public boolean setInitParameter(String name, String value)
294     {
295         if (initParams.containsKey(name))
296         {
297             return false;
298         }
299         initParams.put(name, value);
300         return true;
301     }
302 
303     @Override
304     public int getEffectiveMajorVersion()
305     {
306         return context.getEffectiveMajorVersion();
307     }
308 
309     @Override
310     public int getEffectiveMinorVersion()
311     {
312         return context.getEffectiveMinorVersion();
313     }
314 
315     @Override
316     public SessionCookieConfig getSessionCookieConfig()
317     {
318         return context.getSessionCookieConfig();
319     }
320 
321     @Override
322     public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
323     {
324         context.setSessionTrackingModes(sessionTrackingModes);
325     }
326 
327     @Override
328     public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
329     {
330         return context.getDefaultSessionTrackingModes();
331     }
332 
333     @Override
334     public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
335     {
336         return context.getEffectiveSessionTrackingModes();
337     }
338 
339     @Override
340     public JspConfigDescriptor getJspConfigDescriptor()
341     {
342         return context.getJspConfigDescriptor();
343     }
344 
345     @Override
346     public ClassLoader getClassLoader()
347     {
348         return context.getClassLoader();
349     }
350 
351     @Override
352     public void declareRoles(String... roleNames)
353     {
354         context.declareRoles(roleNames);
355     }
356 
357     @Override
358     public ServletRegistration.Dynamic addServlet(String servletName, String className)
359     {
360         throw new UnsupportedOperationException();
361     }
362 
363     @Override
364     public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)
365     {
366         throw new UnsupportedOperationException();
367     }
368 
369     @Override
370     public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass)
371     {
372         throw new UnsupportedOperationException();
373     }
374 
375     @Override
376     public <T extends Servlet> T createServlet(Class<T> clazz)
377     {
378         throw new UnsupportedOperationException();
379     }
380 
381     @Override
382     public ServletRegistration getServletRegistration(String servletName)
383     {
384         throw new UnsupportedOperationException();
385     }
386 
387     @Override
388     public Map<String, ? extends ServletRegistration> getServletRegistrations()
389     {
390         throw new UnsupportedOperationException();
391     }
392 
393     @Override
394     public FilterRegistration.Dynamic addFilter(String filterName, String className)
395     {
396         throw new UnsupportedOperationException();
397     }
398 
399     @Override
400     public FilterRegistration.Dynamic addFilter(String filterName, Filter filter)
401     {
402         throw new UnsupportedOperationException();
403     }
404 
405     @Override
406     public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> filterClass)
407     {
408         throw new UnsupportedOperationException();
409     }
410 
411     @Override
412     public <T extends Filter> T createFilter(Class<T> clazz)
413     {
414         throw new UnsupportedOperationException();
415     }
416 
417     @Override
418     public FilterRegistration getFilterRegistration(String filterName)
419     {
420         throw new UnsupportedOperationException();
421     }
422 
423     @Override
424     public Map<String, ? extends FilterRegistration> getFilterRegistrations()
425     {
426         throw new UnsupportedOperationException();
427     }
428 
429     @Override
430     public void addListener(String className)
431     {
432         throw new UnsupportedOperationException();
433     }
434 
435     @Override
436     public <T extends EventListener> void addListener(T t)
437     {
438         throw new UnsupportedOperationException();
439     }
440 
441     @Override
442     public void addListener(Class<? extends EventListener> listenerClass)
443     {
444         throw new UnsupportedOperationException();
445     }
446 
447     @Override
448     public <T extends EventListener> T createListener(Class<T> clazz)
449     {
450         throw new UnsupportedOperationException();
451     }
452 }