View Javadoc

1   package com.atlassian.plugins.rest.module.servlet;
2   
3   import static com.google.common.collect.Ordering.natural;
4   
5   import com.atlassian.plugin.Plugin;
6   import com.atlassian.plugin.event.PluginEventManager;
7   import com.atlassian.plugin.servlet.DefaultServletModuleManager;
8   import com.atlassian.plugin.servlet.ServletModuleManager;
9   import com.atlassian.plugin.servlet.descriptors.ServletFilterModuleDescriptor;
10  import com.atlassian.plugin.servlet.descriptors.ServletModuleDescriptor;
11  import com.atlassian.plugin.servlet.filter.FilterDispatcherCondition;
12  import com.atlassian.plugin.servlet.filter.FilterLocation;
13  import com.atlassian.plugin.servlet.util.DefaultPathMapper;
14  import com.atlassian.plugin.servlet.util.PathMapper;
15  import com.atlassian.plugins.rest.module.RestApiContext;
16  import com.atlassian.plugins.rest.module.RestServletFilterModuleDescriptor;
17  import com.google.common.collect.Multimaps;
18  import com.google.common.collect.SortedSetMultimap;
19  import com.google.common.collect.TreeMultimap;
20  
21  import org.apache.commons.lang.StringUtils;
22  
23  import javax.servlet.Filter;
24  import javax.servlet.FilterConfig;
25  import javax.servlet.ServletConfig;
26  import javax.servlet.ServletContext;
27  import javax.servlet.ServletException;
28  import javax.servlet.http.HttpServlet;
29  
30  import java.util.Comparator;
31  import java.util.SortedSet;
32  
33  /**
34   * <p>Servlet module manager to handle REST servlets.</p>
35   */
36  public class DefaultRestServletModuleManager implements RestServletModuleManager {
37      private static final RestServletFilterModuleDescriptorComparator VALUE_COMPARATOR = new RestServletFilterModuleDescriptorComparator();
38  
39      /**
40       * Multimap of filter module descriptors, the key is the "api path" of the REST module descriptor.
41       */
42      private final SortedSetMultimap<String, RestServletFilterModuleDescriptor> filterModuleDescriptors =
43              Multimaps.synchronizedSortedSetMultimap(TreeMultimap.<String, RestServletFilterModuleDescriptor>create(natural(), VALUE_COMPARATOR));
44  
45      private final ServletModuleManager delegateModuleManager;
46      private final PathMapper filterPathMapper;
47      private final String path;
48  
49      public DefaultRestServletModuleManager(PluginEventManager pluginEventManager, String path) {
50          this.filterPathMapper = new DefaultPathMapper();
51          this.delegateModuleManager = new DefaultServletModuleManager(pluginEventManager, new DefaultPathMapper(), filterPathMapper);
52          this.path = StringUtils.isNotBlank(path) ? path : "";
53      }
54  
55      DefaultRestServletModuleManager(ServletModuleManager delegate, PathMapper filterPathMapper, String path) {
56          this.filterPathMapper = filterPathMapper;
57          this.delegateModuleManager = delegate;
58          this.path = StringUtils.isNotBlank(path) ? path : "";
59      }
60  
61      @Override
62      public void addServlet(Plugin plugin, String servletName, String className) {
63          delegateModuleManager.addServlet(plugin, servletName, className);
64      }
65  
66      @Override
67      public void addServlet(Plugin plugin, String servletName, HttpServlet servlet, ServletContext servletContext) {
68          delegateModuleManager.addServlet(plugin, servletName, servlet, servletContext);
69      }
70  
71      @Override
72      public void addServletModule(ServletModuleDescriptor descriptor) {
73          delegateModuleManager.addServletModule(descriptor);
74      }
75  
76      @Override
77      public HttpServlet getServlet(String path, ServletConfig servletConfig) throws ServletException {
78          return delegateModuleManager.getServlet(path, servletConfig);
79      }
80  
81      @Override
82      public void removeServletModule(ServletModuleDescriptor descriptor) {
83          delegateModuleManager.removeServletModule(descriptor);
84      }
85  
86      @Override
87      public void addFilterModule(ServletFilterModuleDescriptor descriptor) {
88          if (descriptor instanceof RestServletFilterModuleDescriptor) {
89              final RestServletFilterModuleDescriptor restServletFilterModuleDescriptor = (RestServletFilterModuleDescriptor) descriptor;
90              final RestServletFilterModuleDescriptor latest = getRestServletFilterModuleDescriptorForLatest(restServletFilterModuleDescriptor.getBasePath());
91              if (VALUE_COMPARATOR.compare(latest, restServletFilterModuleDescriptor) < 0) {
92                  if (latest != null) {
93                      filterPathMapper.put(latest.getCompleteKey(), null);
94                      for (String path : latest.getPaths()) {
95                          filterPathMapper.put(latest.getCompleteKey(), path);
96                      }
97                  }
98                  filterPathMapper.put(descriptor.getCompleteKey(), getPathPattern(restServletFilterModuleDescriptor.getBasePath()));
99              }
100             filterModuleDescriptors.put(restServletFilterModuleDescriptor.getBasePath(), restServletFilterModuleDescriptor);
101         }
102         delegateModuleManager.addFilterModule(descriptor);
103     }
104 
105     private RestServletFilterModuleDescriptor getRestServletFilterModuleDescriptorForLatest(String path) {
106         if (path == null) {
107             return null;
108         }
109 
110         final SortedSet<RestServletFilterModuleDescriptor> moduleDescriptors = filterModuleDescriptors.get(path);
111         return moduleDescriptors.isEmpty() ? null : moduleDescriptors.last();
112     }
113 
114     @Override
115     public Iterable<Filter> getFilters(FilterLocation location, String pathInfo, FilterConfig filterConfig) throws ServletException {
116         return delegateModuleManager.getFilters(location, pathInfo, filterConfig);
117     }
118 
119     @Override
120     public Iterable<Filter> getFilters(FilterLocation location, String pathInfo, FilterConfig filterConfig, FilterDispatcherCondition filterDispatcherCondition) throws ServletException {
121         return delegateModuleManager.getFilters(location, StringUtils.removeStart(pathInfo, path), filterConfig, filterDispatcherCondition);
122     }
123 
124     @Override
125     public void removeFilterModule(ServletFilterModuleDescriptor descriptor) {
126         if (descriptor instanceof RestServletFilterModuleDescriptor) {
127             final RestServletFilterModuleDescriptor restServletFilterModuleDescriptor = (RestServletFilterModuleDescriptor) descriptor;
128 
129             // check if it was the latest, before removing from the MultiMap
130             RestServletFilterModuleDescriptor latest = getRestServletFilterModuleDescriptorForLatest(restServletFilterModuleDescriptor.getBasePath());
131             filterModuleDescriptors.remove(restServletFilterModuleDescriptor.getBasePath(), restServletFilterModuleDescriptor);
132 
133             if (latest != null && latest.getCompleteKey().equals(descriptor.getCompleteKey())) {
134                 // latest has changed as we have removed an item from the multimap
135                 latest = getRestServletFilterModuleDescriptorForLatest(restServletFilterModuleDescriptor.getBasePath());
136                 if (latest != null) {
137                     filterPathMapper.put(latest.getCompleteKey(), getPathPattern(latest.getBasePath()));
138                 }
139             }
140         }
141 
142         // remaing mapping of the descriptor will be removed by this call.
143         delegateModuleManager.removeFilterModule(descriptor);
144     }
145 
146     String getPathPattern(String basePath) {
147         return basePath + RestApiContext.LATEST + RestApiContext.ANY_PATH_PATTERN;
148     }
149 
150     private static final class RestServletFilterModuleDescriptorComparator implements Comparator<RestServletFilterModuleDescriptor> {
151         public int compare(RestServletFilterModuleDescriptor descriptor1, RestServletFilterModuleDescriptor descriptor2) {
152             if (descriptor1 == null) {
153                 return -1;
154             }
155             if (descriptor2 == null) {
156                 return +1;
157             }
158             return descriptor1.getVersion().compareTo(descriptor2.getVersion());
159         }
160     }
161 }