View Javadoc

1   package com.atlassian.plugin.descriptors;
2   
3   import com.atlassian.plugin.ModuleDescriptor;
4   import com.atlassian.plugin.Plugin;
5   import com.atlassian.plugin.PluginParseException;
6   import com.atlassian.plugin.Resources;
7   import com.atlassian.plugin.elements.ResourceLocation;
8   import com.atlassian.plugin.elements.ResourceDescriptor;
9   import com.atlassian.plugin.loaders.LoaderUtils;
10  import com.atlassian.plugin.util.JavaVersionUtils;
11  import org.dom4j.Element;
12  
13  import java.lang.reflect.Constructor;
14  import java.util.List;
15  import java.util.Map;
16  
17  public abstract class AbstractModuleDescriptor implements ModuleDescriptor
18  {
19      protected Plugin plugin;
20      String key;
21      String name;
22      Class moduleClass;
23      String description;
24      boolean enabledByDefault = true;
25      boolean systemModule = false;
26      protected boolean singleton = true;
27      Map params;
28      protected Resources resources = Resources.EMPTY_RESOURCES;
29      private Float minJavaVersion;
30      private String i18nNameKey;
31      private String descriptionKey;
32  	private String completeKey;
33  
34      public void init(Plugin plugin, Element element) throws PluginParseException
35      {
36          this.plugin = plugin;
37          this.key = element.attributeValue("key");
38          this.name = element.attributeValue("name");
39          this.i18nNameKey = element.attributeValue("i18n-name-key");
40          this.completeKey = buildCompleteKey(plugin, key);
41          loadClass(plugin, element);
42          this.description = element.elementTextTrim("description");
43          Element descriptionElement = element.element("description");
44          this.descriptionKey = (descriptionElement != null) ? descriptionElement.attributeValue("key") : null;
45          params = LoaderUtils.getParams(element);
46  
47          if ("disabled".equalsIgnoreCase(element.attributeValue("state")))
48          {
49              enabledByDefault = false;
50          }
51  
52          if ("true".equalsIgnoreCase(element.attributeValue("system")))
53          {
54              systemModule = true;
55          }
56  
57          if (element.element("java-version") != null)
58          {
59              minJavaVersion = Float.valueOf(element.element("java-version").attributeValue("min"));
60          }
61  
62          if ("false".equalsIgnoreCase(element.attributeValue("singleton")))
63          {
64              singleton = false;
65          }
66          else if ("true".equalsIgnoreCase(element.attributeValue("singleton")))
67          {
68              singleton = true;
69          }
70          else
71          {
72              singleton = isSingletonByDefault();
73          }
74  
75          resources = Resources.fromXml(element);
76      }
77  
78      /**
79       * Override this for module descriptors which don't expect to be able to load a class successfully
80       * @param plugin
81       * @param element
82       */
83      protected void loadClass(Plugin plugin, Element element) throws PluginParseException {
84          String clazz = element.attributeValue("class");
85          try
86          {
87              if (clazz != null)  //not all plugins have to have a class
88              {
89                  // First try and load the class, to make sure the class exists
90                  moduleClass = plugin.loadClass(clazz, getClass());
91  
92                  // Then instantiate the class, so we can see if there are any dependencies that aren't satisfied
93                  try
94                  {
95                      Constructor noargConstructor = moduleClass.getConstructor(new Class[]{});
96                      if(noargConstructor != null)
97                      {
98                          moduleClass.newInstance();
99                      }
100                 }
101                 catch (NoSuchMethodException e)
102                 {
103                     // If there is no "noarg" constructor then don't do the check
104                 }
105             }
106         }
107         catch (ClassNotFoundException e)
108         {
109             throw new PluginParseException("Could not load class: " + clazz, e);
110         }
111         catch (NoClassDefFoundError e)
112         {
113             throw new PluginParseException("Error retrieving dependency of class: " + clazz + ". Missing class: " + e.getMessage());
114         }
115         catch (UnsupportedClassVersionError e)
116         {
117             throw new PluginParseException("Class version is incompatible with current JVM: " + clazz, e);
118         }
119         catch (Throwable t)
120         {
121             throw new PluginParseException(t);
122         }
123     }
124 
125     /**
126      * Build the complete key based on the provided plugin and module key. This method has no
127      * side effects.
128      * @param plugin The plugin for which the module belongs
129      * @param moduleKey The key for the module
130      * @return A newly constructed complete key, null if the plugin is null
131      */
132     private String buildCompleteKey(Plugin plugin, String moduleKey)
133     {
134         if (plugin == null)
135             return null;
136 
137         final StringBuffer completeKeyBuffer = new StringBuffer(32);
138         completeKeyBuffer.append(plugin.getKey()).append(":").append(moduleKey);
139         return completeKeyBuffer.toString();
140     }
141 
142     /**
143      * Override this if your plugin needs to clean up when it's been removed.
144      */
145     public void destroy(Plugin plugin)
146     {}
147 
148     public boolean isEnabledByDefault()
149     {
150         return enabledByDefault && satisfiesMinJavaVersion();
151     }
152 
153     public boolean isSystemModule()
154     {
155         return systemModule;
156     }
157 
158     public boolean isSingleton()
159     {
160         return singleton;
161     }
162 
163     /**
164      * Override this method if you want your module descriptor to be or not be a singleton by default.
165      * <p>
166      * Default is "true" - ie all plugin modules are singletons by default.
167      */
168     protected boolean isSingletonByDefault()
169     {
170         return true;
171     }
172 
173     /**
174      * Check that the module class of this descriptor implements a given interface, or extends a given class.
175      * @param requiredModuleClazz The class this module's class must implement or extend.
176      * @throws PluginParseException If the module class does not implement or extend the given class.
177      */
178     final protected void assertModuleClassImplements(Class requiredModuleClazz) throws PluginParseException
179     {
180         if (!requiredModuleClazz.isAssignableFrom(getModuleClass()))
181         {
182             throw new PluginParseException("Given module class: " + getModuleClass().getName() + " does not implement " + requiredModuleClazz.getName());
183         }
184     }
185 
186     public String getCompleteKey() 
187 	{
188         return completeKey;
189     }
190 
191     public String getPluginKey()
192     {
193         return plugin.getKey();
194     }
195 
196     public String getKey()
197     {
198         return key;
199     }
200 
201     public String getName()
202     {
203         return name;
204     }
205 
206     public Class getModuleClass()
207     {
208         return moduleClass;
209     }
210 
211     public abstract Object getModule();
212 
213     public String getDescription()
214     {
215         return description;
216     }
217 
218     public Map getParams()
219     {
220         return params;
221     }
222 
223     public String getI18nNameKey()
224     {
225         return i18nNameKey;  //To change body of implemented methods use File | Settings | File Templates.
226     }
227 
228     public String getDescriptionKey()
229     {
230         return descriptionKey;  //To change body of implemented methods use File | Settings | File Templates.
231     }
232 
233     public List getResourceDescriptors()
234     {
235         return resources.getResourceDescriptors();
236     }
237 
238     public List getResourceDescriptors(String type)
239     {
240         return resources.getResourceDescriptors(type);
241     }
242 
243     public ResourceLocation getResourceLocation(String type, String name)
244     {
245         return resources.getResourceLocation(type, name);
246     }
247 
248     /**
249      * @deprecated
250      */
251     public ResourceDescriptor getResourceDescriptor(String type, String name)
252     {
253         return resources.getResourceDescriptor(type, name);
254     }
255 
256     public Float getMinJavaVersion()
257     {
258         return minJavaVersion;
259     }
260 
261     public boolean satisfiesMinJavaVersion()
262     {
263         if(minJavaVersion != null)
264         {
265             return JavaVersionUtils.satisfiesMinVersion(minJavaVersion.floatValue());
266         }
267         return true;
268     }
269 
270     /**
271      * Sets the plugin for the ModuleDescriptor
272      */
273     public void setPlugin(Plugin plugin)
274     {
275         this.completeKey = buildCompleteKey(plugin, key);
276         this.plugin = plugin;
277     }
278 
279     /**
280      * @return The plugin this module descriptor is associated with
281      */
282     public Plugin getPlugin()
283     {
284         return plugin;
285     }
286 
287     public String toString()
288     {
289         return getCompleteKey() + " (" + getDescription() + ")";
290     }
291 }