View Javadoc

1   package com.atlassian.plugins.rest.module;
2   
3   import com.atlassian.plugin.ModuleDescriptor;
4   import com.atlassian.plugin.Plugin;
5   import com.atlassian.plugin.PluginManager;
6   import com.atlassian.plugin.PluginParseException;
7   import com.atlassian.plugin.descriptors.AbstractModuleDescriptor;
8   import com.atlassian.plugin.module.ModuleFactory;
9   import com.atlassian.plugin.osgi.factory.OsgiPlugin;
10  import com.atlassian.plugin.servlet.filter.FilterLocation;
11  import com.atlassian.plugins.rest.module.servlet.RestServletModuleManager;
12  import com.google.common.base.Preconditions;
13  import org.dom4j.Element;
14  import org.osgi.framework.ServiceRegistration;
15  
16  import java.util.Collection;
17  import java.util.HashSet;
18  import java.util.Set;
19  
20  /**
21   * <p>The REST module descriptor.</p>
22   * <p>Example configuration in your {@link PluginManager#PLUGIN_DESCRIPTOR_FILENAME plugin descriptor}:</p>
23   * &lt;rest key="module-key"&gt;<br/>
24   * &nbsp;&nbsp;&nbsp;&nbsp;&lt;url-pattern&gt;/myapi/*&lt;/url-pattern&gt;<br/>
25   * &lt;/rest&gt;<br/>
26   * <p>Your REST apis will then be available at <code>/context/rest/myapi</code></p>
27   */
28  public class RestModuleDescriptor extends AbstractModuleDescriptor<Object> {
29      private final RestServletModuleManager servletModuleManager;
30      /**
31       * This is the context path of REST APIs.
32       * <p>
33       * Typically if the application lives at {@code http://localhost:9090/app} and the REST context path is {@code /rest}, then APIs will be available at {@code http://localhost:9090/app/rest}
34       */
35      private final String restContext;
36  
37      private RestApiContext restApiContext;
38  
39      private ServiceRegistration serviceRegistration;
40      private RestServletFilterModuleDescriptor restServletFilterModuleDescriptor;
41      private OsgiPlugin osgiPlugin;
42      private Element element;
43  
44      public RestModuleDescriptor(ModuleFactory moduleFactory, RestServletModuleManager servletModuleManager, String restContext) {
45          super(moduleFactory);
46          this.servletModuleManager = Preconditions.checkNotNull(servletModuleManager);
47          this.restContext = Preconditions.checkNotNull(restContext);
48      }
49  
50      @Override
51      public void init(Plugin plugin, Element element) throws PluginParseException {
52          super.init(plugin, element);
53  
54          this.restApiContext = new RestApiContext(restContext, parsePath(element), parseVersion(element), parsePackages(element));
55  
56          osgiPlugin = (OsgiPlugin) plugin;
57  
58          this.element = element;
59      }
60  
61      public RestApiContext getRestApiContext() {
62          return restApiContext;
63      }
64  
65      private String parsePath(Element element) {
66          return element.attributeValue("path");
67      }
68  
69      private Set<String> parsePackages(Element rootElement) {
70          Set<String> packages = new HashSet<String>();
71          for (Element pkgElement : (Collection<Element>) rootElement.elements("package")) {
72              packages.add(pkgElement.getTextTrim());
73          }
74          return packages;
75      }
76  
77      private ApiVersion parseVersion(Element element) {
78          try {
79              return new ApiVersion(element.attributeValue("version"));
80          } catch (InvalidVersionException e) {
81              // rethrowing the exception with more information
82              throw new InvalidVersionException(plugin, this, e);
83          }
84      }
85  
86      private Element updateElementForFilterConfiguration(final Element element) {
87          final Element copy = element.createCopy();
88  
89          // adding the default location
90          copy.addAttribute("location", FilterLocation.BEFORE_DISPATCH.name());
91  
92          // adding the url-pattern
93          copy.addElement("url-pattern").addText(restApiContext.getContextlessPathToVersion() + RestApiContext.ANY_PATH_PATTERN);
94  
95          copy.addAttribute("key", copy.attributeValue("key") + "-filter");
96          return copy;
97      }
98  
99      /**
100      * @return <code>null</code>, the REST module descriptor doesn't instansiate any module.
101      */
102     public Object getModule() {
103         return null;
104     }
105 
106     @Override
107     public boolean equals(Object o) {
108         if (o == null) {
109             return false;
110         }
111         if (this == o) {
112             return true;
113         }
114         if (this.getClass() != o.getClass()) {
115             return false;
116         }
117 
118         final RestModuleDescriptor that = (RestModuleDescriptor) o;
119         return that.getCompleteKey().equals(getCompleteKey());
120     }
121 
122     @Override
123     public int hashCode() {
124         return getCompleteKey().hashCode();
125     }
126 
127     @Override
128     public String toString() {
129         return super.toString() +
130                 '/' + restContext +
131                 (restApiContext != null
132                         ? '/' + restApiContext.getApiPath() + '/' + restApiContext.getVersion()
133                         : "");
134     }
135 
136     @Override
137     public void disabled() {
138         if (restServletFilterModuleDescriptor != null) {
139             restServletFilterModuleDescriptor.disabled();
140             restServletFilterModuleDescriptor = null;
141         }
142 
143         restApiContext.disabled();
144 
145         if (serviceRegistration != null) {
146             try {
147                 serviceRegistration.unregister();
148             } catch (IllegalStateException ex) {
149                 // this has
150             }
151             serviceRegistration = null;
152         }
153 
154         super.disabled();
155     }
156 
157     @Override
158     public void enabled() {
159         super.enabled();
160         restServletFilterModuleDescriptor = new RestServletFilterModuleDescriptor(osgiPlugin, moduleFactory, servletModuleManager, restApiContext);
161         restServletFilterModuleDescriptor.init(plugin, updateElementForFilterConfiguration(element));
162         restServletFilterModuleDescriptor.enabled();
163 
164         // dynamically register the servlet filter that serves the REST API requests
165         serviceRegistration = osgiPlugin.getBundle().getBundleContext().registerService(
166                 new String[]{
167                         restServletFilterModuleDescriptor.getClass().getName(),
168                         ModuleDescriptor.class.getName(),
169                 }, restServletFilterModuleDescriptor, null);
170     }
171 }