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
80
81
82
83 protected void loadClass(Plugin plugin, Element element) throws PluginParseException {
84 String clazz = element.attributeValue("class");
85 try
86 {
87 if (clazz != null)
88 {
89
90 moduleClass = plugin.loadClass(clazz, getClass());
91
92
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
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
127
128
129
130
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
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
165
166
167
168 protected boolean isSingletonByDefault()
169 {
170 return true;
171 }
172
173
174
175
176
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;
226 }
227
228 public String getDescriptionKey()
229 {
230 return descriptionKey;
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
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
272
273 public void setPlugin(Plugin plugin)
274 {
275 this.completeKey = buildCompleteKey(plugin, key);
276 this.plugin = plugin;
277 }
278
279
280
281
282 public Plugin getPlugin()
283 {
284 return plugin;
285 }
286
287 public String toString()
288 {
289 return getCompleteKey() + " (" + getDescription() + ")";
290 }
291 }