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.StateAware;
8 import com.atlassian.plugin.elements.ResourceDescriptor;
9 import com.atlassian.plugin.elements.ResourceLocation;
10 import com.atlassian.plugin.loaders.LoaderUtils;
11 import com.atlassian.plugin.util.JavaVersionUtils;
12
13 import org.dom4j.Element;
14
15 import java.lang.reflect.Constructor;
16 import java.util.List;
17 import java.util.Map;
18
19 public abstract class AbstractModuleDescriptor<T> implements ModuleDescriptor<T>, StateAware
20 {
21 protected Plugin plugin;
22 String key;
23 String name;
24 String moduleClassName;
25 Class<T> moduleClass;
26 String description;
27 boolean enabledByDefault = true;
28 boolean systemModule = false;
29 protected boolean singleton = true;
30 Map<String, String> params;
31 protected Resources resources = Resources.EMPTY_RESOURCES;
32 private Float minJavaVersion;
33 private String i18nNameKey;
34 private String descriptionKey;
35 private String completeKey;
36 boolean enabled = false;
37
38 public void init(final Plugin plugin, final Element element) throws PluginParseException
39 {
40 this.plugin = plugin;
41 this.key = element.attributeValue("key");
42 this.name = element.attributeValue("name");
43 this.i18nNameKey = element.attributeValue("i18n-name-key");
44 this.completeKey = buildCompleteKey(plugin, key);
45 this.description = element.elementTextTrim("description");
46 this.moduleClassName = element.attributeValue("class");
47 final Element descriptionElement = element.element("description");
48 this.descriptionKey = (descriptionElement != null) ? descriptionElement.attributeValue("key") : null;
49 params = LoaderUtils.getParams(element);
50
51 if ("disabled".equalsIgnoreCase(element.attributeValue("state")))
52 {
53 enabledByDefault = false;
54 }
55
56 if ("true".equalsIgnoreCase(element.attributeValue("system")))
57 {
58 systemModule = true;
59 }
60
61 if (element.element("java-version") != null)
62 {
63 minJavaVersion = Float.valueOf(element.element("java-version").attributeValue("min"));
64 }
65
66 if ("false".equalsIgnoreCase(element.attributeValue("singleton")))
67 {
68 singleton = false;
69 }
70 else if ("true".equalsIgnoreCase(element.attributeValue("singleton")))
71 {
72 singleton = true;
73 }
74 else
75 {
76 singleton = isSingletonByDefault();
77 }
78
79 resources = Resources.fromXml(element);
80 }
81
82
83
84
85
86
87
88 @Deprecated
89 protected void loadClass(final Plugin plugin, final Element element) throws PluginParseException
90 {
91 loadClass(plugin, element.attributeValue("class"));
92 }
93
94
95
96
97
98
99
100 protected void loadClass(final Plugin plugin, final String clazz) throws PluginParseException
101 {
102 try
103 {
104 if (clazz != null)
105 {
106
107 @SuppressWarnings("unchecked")
108 final Class<T> loadedClass = (Class<T>) plugin.loadClass(clazz, getClass());
109 moduleClass = loadedClass;
110
111
112 try
113 {
114 final Constructor<T> noargConstructor = moduleClass.getConstructor(new Class[] {});
115 if (noargConstructor != null)
116 {
117 moduleClass.newInstance();
118 }
119 }
120 catch (final NoSuchMethodException e)
121 {
122
123 }
124 }
125 }
126 catch (final ClassNotFoundException e)
127 {
128 throw new PluginParseException("Could not load class: " + clazz, e);
129 }
130 catch (final NoClassDefFoundError e)
131 {
132 throw new PluginParseException("Error retrieving dependency of class: " + clazz + ". Missing class: " + e.getMessage());
133 }
134 catch (final UnsupportedClassVersionError e)
135 {
136 throw new PluginParseException("Class version is incompatible with current JVM: " + clazz, e);
137 }
138 catch (final Throwable t)
139 {
140 throw new PluginParseException(t);
141 }
142 }
143
144
145
146
147
148
149
150
151 private String buildCompleteKey(final Plugin plugin, final String moduleKey)
152 {
153 if (plugin == null)
154 {
155 return null;
156 }
157
158 final StringBuffer completeKeyBuffer = new StringBuffer(32);
159 completeKeyBuffer.append(plugin.getKey()).append(":").append(moduleKey);
160 return completeKeyBuffer.toString();
161 }
162
163
164
165
166 public void destroy(final Plugin plugin)
167 {}
168
169 public boolean isEnabledByDefault()
170 {
171 return enabledByDefault && satisfiesMinJavaVersion();
172 }
173
174 public boolean isSystemModule()
175 {
176 return systemModule;
177 }
178
179 public boolean isSingleton()
180 {
181 return singleton;
182 }
183
184
185
186
187
188
189 protected boolean isSingletonByDefault()
190 {
191 return true;
192 }
193
194
195
196
197
198
199 final protected void assertModuleClassImplements(final Class<T> requiredModuleClazz) throws PluginParseException
200 {
201 if (!enabled)
202 {
203 throw new PluginParseException("Plugin module " + getKey() + " not enabled");
204 }
205 if (!requiredModuleClazz.isAssignableFrom(getModuleClass()))
206 {
207 throw new PluginParseException(
208 "Given module class: " + getModuleClass().getName() + " does not implement " + requiredModuleClazz.getName());
209 }
210 }
211
212 public String getCompleteKey()
213 {
214 return completeKey;
215 }
216
217 public String getPluginKey()
218 {
219 return plugin.getKey();
220 }
221
222 public String getKey()
223 {
224 return key;
225 }
226
227 public String getName()
228 {
229 return name;
230 }
231
232 public Class<T> getModuleClass()
233 {
234 return moduleClass;
235 }
236
237 public abstract T getModule();
238
239 public String getDescription()
240 {
241 return description;
242 }
243
244 public Map<String, String> getParams()
245 {
246 return params;
247 }
248
249 public String getI18nNameKey()
250 {
251 return i18nNameKey;
252 }
253
254 public String getDescriptionKey()
255 {
256 return descriptionKey;
257 }
258
259 public List<ResourceDescriptor> getResourceDescriptors()
260 {
261 return resources.getResourceDescriptors();
262 }
263
264 public List<ResourceDescriptor> getResourceDescriptors(final String type)
265 {
266 return resources.getResourceDescriptors(type);
267 }
268
269 public ResourceLocation getResourceLocation(final String type, final String name)
270 {
271 return resources.getResourceLocation(type, name);
272 }
273
274 public ResourceDescriptor getResourceDescriptor(final String type, final String name)
275 {
276 return resources.getResourceDescriptor(type, name);
277 }
278
279 public Float getMinJavaVersion()
280 {
281 return minJavaVersion;
282 }
283
284 public boolean satisfiesMinJavaVersion()
285 {
286 if (minJavaVersion != null)
287 {
288 return JavaVersionUtils.satisfiesMinVersion(minJavaVersion);
289 }
290 return true;
291 }
292
293
294
295
296 public void setPlugin(final Plugin plugin)
297 {
298 this.completeKey = buildCompleteKey(plugin, key);
299 this.plugin = plugin;
300 }
301
302
303
304
305 public Plugin getPlugin()
306 {
307 return plugin;
308 }
309
310 @Override
311 public String toString()
312 {
313 return getCompleteKey() + " (" + getDescription() + ")";
314 }
315
316
317
318
319
320
321
322 public void enabled()
323 {
324 loadClass(plugin, moduleClassName);
325 enabled = true;
326 }
327
328
329
330
331
332 public void disabled()
333 {
334 enabled = false;
335 moduleClass = null;
336 }
337 }