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          this.element = element;
58      }
59  
60      private String parsePath(Element element) {
61          return element.attributeValue("path");
62      }
63  
64      private Set<String> parsePackages(Element rootElement) {
65          Set<String> packages = new HashSet<String>();
66          for (Element pkgElement : (Collection<Element>) rootElement.elements("package")) {
67              packages.add(pkgElement.getTextTrim());
68          }
69          return packages;
70      }
71  
72      private ApiVersion parseVersion(Element element) {
73          try {
74              return new ApiVersion(element.attributeValue("version"));
75          } catch (InvalidVersionException e) {
76              // rethrowing the exception with more information
77              throw new InvalidVersionException(plugin, this, e);
78          }
79      }
80  
81      private Element updateElementForFilterConfiguration(final Element element) {
82          final Element copy = element.createCopy();
83  
84          // adding the default location
85          copy.addAttribute("location", FilterLocation.BEFORE_DISPATCH.name());
86  
87          // adding the url-pattern
88          copy.addElement("url-pattern").addText(restApiContext.getContextlessPathToVersion() + RestApiContext.ANY_PATH_PATTERN);
89  
90          copy.addAttribute("key", copy.attributeValue("key") + "-filter");
91          return copy;
92      }
93  
94      /**
95       * @return <code>null</code>, the REST module descriptor doesn't instansiate any module.
96       */
97      public Object getModule() {
98          return null;
99      }
100 
101     @Override
102     public boolean equals(Object o) {
103         if (o == null) {
104             return false;
105         }
106         if (this == o) {
107             return true;
108         }
109         if (this.getClass() != o.getClass()) {
110             return false;
111         }
112 
113         final RestModuleDescriptor that = (RestModuleDescriptor) o;
114         return that.getCompleteKey().equals(getCompleteKey());
115     }
116 
117     @Override
118     public int hashCode() {
119         return getCompleteKey().hashCode();
120     }
121 
122     @Override
123     public void disabled() {
124         if (restServletFilterModuleDescriptor != null) {
125             restServletFilterModuleDescriptor.disabled();
126             restServletFilterModuleDescriptor = null;
127         }
128 
129         if (serviceRegistration != null) {
130             try {
131                 serviceRegistration.unregister();
132             } catch (IllegalStateException ex) {
133                 // this has
134             }
135             serviceRegistration = null;
136         }
137 
138         super.disabled();
139     }
140 
141     @Override
142     public void enabled() {
143         super.enabled();
144         restServletFilterModuleDescriptor = new RestServletFilterModuleDescriptor(osgiPlugin, moduleFactory, servletModuleManager, restApiContext);
145         restServletFilterModuleDescriptor.init(plugin, updateElementForFilterConfiguration(element));
146         restServletFilterModuleDescriptor.enabled();
147 
148         // dynamically register the servlet filter that serves the REST API requests
149         serviceRegistration = osgiPlugin.getBundle().getBundleContext().registerService(
150                 new String[]{
151                         restServletFilterModuleDescriptor.getClass().getName(),
152                         ModuleDescriptor.class.getName(),
153                 }, restServletFilterModuleDescriptor, null);
154     }
155 }