1 package com.atlassian.plugin;
2
3 import java.io.InputStream;
4 import java.net.URL;
5 import java.util.Collection;
6 import java.util.Comparator;
7 import java.util.Date;
8 import java.util.List;
9 import java.util.Set;
10
11 import javax.annotation.Nullable;
12
13 import com.atlassian.annotations.ExperimentalApi;
14
15 public interface Plugin extends Resourced, Comparable<Plugin>
16 {
17 /**
18 * This is the historical version of plugins. Which is mostly static plugins loaded from the same classpath to the
19 * application.
20 */
21 static final int VERSION_1 = 1;
22
23 /**
24 * This is the version of plugins which introduced dynamic plugins for all. Based on OSGi and Spring DM. Those plugins
25 * undergo some transformations to make the plugin artifact compatible with the OSGi + Spring DM container.
26 */
27 static final int VERSION_2 = 2;
28
29 /**
30 * This is the versions of plugins that adds remotes plugins (developed outside of the plugin framework itself).
31 * Plugins version 3 don't undergo any transformation so it is up to the plugin developer to write their own Spring
32 * configuration files if this is their chosen framework, but other frameworks can be introduced.
33 */
34 static final int VERSION_3 = 3;
35
36 /**
37 * @deprecated since 2.2.0. This comparator only takes into account the plugin name and assumes it is not null,
38 * yet a) that constraint is not validated anywhere in plugin loading and b) the plugin could have used the i18n
39 * name, and only the application can resolve that to a name useful for comparisons.
40 */
41 public static final Comparator<Plugin> NAME_COMPARATOR = new PluginNameComparator();
42
43 /**
44 * Gets the version of the plugins system to handle this plugin
45 * @return The plugins version. If undefined, assumed to be 1.
46 */
47 int getPluginsVersion();
48
49 /**
50 * Sets the version of the plugins system
51 * @param version The version
52 */
53 void setPluginsVersion(int version);
54
55 /**
56 * Returns the non-localised name of this plugin if defined.
57 *
58 * <p> This corresponds to the value of the {@code name} field in the plugin's XML configuration file.
59 *
60 * <p> You would expect a plugin developer to fill in one of either {@code name}, or {@code i18n-name-key},
61 * but the framework does no validation and makes no guarantees that this is the case.
62 *
63 * @return the non-localised name of this plugin if defined, or null.
64 * @see #getI18nNameKey()
65 */
66 String getName();
67
68 /**
69 * Sets the non-localised name of this plugin.
70 *
71 * @param name the name.
72 * @see #getName()
73 */
74 void setName(String name);
75
76 /**
77 * Returns the i18nKey used to get an internationalised name for this plugin.
78 *
79 * <p> This corresponds to the value of the {@code i18n-name-key} field in the plugin's XML configuration file.
80 *
81 * <p> You would expect a plugin developer to fill in one of either {@code name}, or {@code i18n-name-key},
82 * but the framework does no validation and makes no guarantees that this is the case.
83 *
84 * @return the i18n Name Key for this plugin if defined, or null.
85 * @see #getName()
86 */
87 String getI18nNameKey();
88
89 /**
90 * Sets the i18nKey used to get an internationalised name for this plugin.
91 *
92 * @param i18nNameKey the i18n Name Key.
93 * @see #getI18nNameKey()
94 */
95 void setI18nNameKey(String i18nNameKey);
96
97 String getKey();
98
99 void setKey(String aPackage);
100
101 void addModuleDescriptor(ModuleDescriptor<?> moduleDescriptor);
102
103 /**
104 * Get the {@link Collection} of {@link ModuleDescriptor descriptors}.
105 *
106 * <p> The iteration order of the collection is
107 * the order that the modules will be enabled, and should be the same order that the modules appear in the
108 * plugin descriptor.
109 *
110 * @return the modules contained by this plugin in the order they are to be enabled
111 */
112 Collection<ModuleDescriptor<?>> getModuleDescriptors();
113
114 /**
115 * Get the {@link ModuleDescriptor} for a particular key. Returns <tt>null</tt> if the plugin does not exist.
116 * <p>
117 * Note: The {@link ModuleDescriptor#getModule()} may throw {@link ClassCastException} if the expected type is incorrect.
118 *
119 * @param key the {@link String} complete key of the module, in the form "org.example.plugin:module-key".
120 * @return the {@link ModuleDescriptor} of the expected type.
121 */
122 ModuleDescriptor<?> getModuleDescriptor(String key);
123
124 /**
125 * Get the {@link ModuleDescriptor descriptors} whose module class implements or is assignable from the supplied {@link Class}.
126 * <p>
127 * Note: The {@link ModuleDescriptor#getModule()} may throw {@link ClassCastException} if the expected type is incorrect.
128 * Normally this method would not be supplied with anything other than {@link Object} or <?>, unless you are
129 * confident in the super type of the module classes this {@link Plugin} provides.
130 *
131 * @param <M> The expected module type of the returned {@link ModuleDescriptor descriptors}.
132 * @param moduleClass the {@link Class super class} the {@link ModuleDescriptor descriptors} return.
133 * @return the {@link List} of {@link ModuleDescriptor descriptors} of the expected type.
134 */
135 <M> List<ModuleDescriptor<M>> getModuleDescriptorsByModuleClass(Class<M> moduleClass);
136
137 /**
138 * Gets the installation mode
139 * @return the plugin's installation mode, local or remote.
140 *
141 * @since 3.0
142 */
143 InstallationMode getInstallationMode();
144
145 boolean isEnabledByDefault();
146
147 void setEnabledByDefault(boolean enabledByDefault);
148
149 PluginInformation getPluginInformation();
150
151 void setPluginInformation(PluginInformation pluginInformation);
152
153 void setResources(Resourced resources);
154
155 /**
156 * Returns this plugin's current state.
157 *
158 * @return the current state of the plugin.
159 * @since 2.2.0
160 */
161 PluginState getPluginState();
162
163 /**
164 * @deprecated since 2.2.0, use {@link #getPluginState()} instead
165 * @return {@code true} if this plugin is enabled.
166 */
167 boolean isEnabled();
168
169
170 /**
171 * Whether the plugin is a "system" plugin that shouldn't be made visible to the user.
172 *
173 * @return {@code true} if this plugin is a "system" plugin.
174 * @deprecated since 2.6.0 use {@link com.atlassian.plugin.metadata.PluginMetadataManager#isSystemProvided(Plugin)}}
175 * instead.
176 */
177 boolean isSystemPlugin();
178
179 /**
180 * @param system whether the plugin is a "system" plugin that shouldn't be made visible to the user.
181 * @deprecated since 2.6.0 provide {@link com.atlassian.plugin.metadata.PluginMetadataManager} with information about the
182 * plugin instead. There is no way to programatically set this value now.
183 */
184 void setSystemPlugin(boolean system);
185
186 boolean containsSystemModule();
187
188 /**
189 * Whether the plugin is a "bundled" plugin that can't be removed.
190 *
191 * @return {@code true} if this plugin is a "bundled" plugin.
192 */
193 boolean isBundledPlugin();
194
195 /**
196 * The date this plugin was loaded into the system.
197 *
198 * @return The date this plugin was loaded into the system.
199 */
200 Date getDateLoaded();
201
202
203 /**
204 * The date this plugin was installed into the system, is the same as the loaded date for non artifact backed plugins
205 *
206 * @return The date this plugin was installed into the system
207 * @since 3.0.0
208 */
209 Date getDateInstalled();
210
211 /**
212 * Whether or not this plugin can be 'uninstalled'.
213 *
214 * @return {@code true} if this plugin can be 'uninstalled'.
215 */
216 boolean isUninstallable();
217
218 /**
219 * Should the plugin file be deleted on uninstall?
220 *
221 * @return {@code true} if this plugin file should be deleted on uninstall.
222 */
223 boolean isDeleteable();
224
225 /**
226 * Whether or not this plugin is loaded dynamically at runtime.
227 *
228 * @return {@code true} if this plugin is loaded dynamically at runtime.
229 */
230 boolean isDynamicallyLoaded();
231
232 /**
233 * Get the plugin to load a specific class.
234 *
235 * @param clazz The name of the class to be loaded
236 * @param callingClass The class calling the loading (used to help find a classloader)
237 * @return The loaded class.
238 * @throws ClassNotFoundException if the class cannot be located.
239 */
240 <T> Class<T> loadClass(String clazz, Class<?> callingClass) throws ClassNotFoundException;
241
242 /**
243 * Get the classloader for the plugin.
244 *
245 * @return The classloader used to load classes for this plugin
246 */
247 ClassLoader getClassLoader();
248
249 /**
250 * Retrieve the URL of the resource from the plugin.
251 *
252 * @param path the name of the resource to be loaded
253 * @return The URL to the resource, or null if the resource is not found
254 */
255 URL getResource(String path);
256
257 /**
258 * Load a given resource from the plugin. Plugins that are loaded dynamically will need
259 * to implement this in a way that loads the resource from the same context as the plugin.
260 * Static plugins can just pull them from their own classloader.
261 *
262 * @param name The name of the resource to be loaded.
263 * @return An InputStream for the resource, or null if the resource is not found.
264 */
265 InputStream getResourceAsStream(String name);
266
267 /**
268 * @param enabled new enabled state
269 * @deprecated Since 2.2.0, use {@link #enable()} or {@link #disable()} instead
270 */
271 void setEnabled(boolean enabled);
272
273 /**
274 * Free any resources held by this plugin. To be called during uninstallation of the {@link Plugin}.
275 * @deprecated Since 2.2.0, use {@link #uninstall()} instead
276 */
277 void close();
278
279 /**
280 * Installs the plugin into any internal, managing container. This method will be called on every startup. Unless
281 * an exception is thrown, the plugin should be in the {@link PluginState#INSTALLED} state. If the plugin is already
282 * in the {@link PluginState#INSTALLED} state, nothing will happen.
283 *
284 * @since 2.2.0
285 * @throws PluginException If the plugin could not be installed
286 */
287 void install() throws PluginException;
288
289 /**
290 * Uninstalls the plugin from any internal container. This method will be called on every shutdown. Unless an
291 * exception is thrown, the plugin should be in the {@link PluginState#UNINSTALLED} state. If the plugin is already
292 * in the {@link PluginState#UNINSTALLED} state, nothing will happen.
293 *
294 * @since 2.2.0
295 * @throws PluginException If the plugin could not be uninstalled
296 */
297 void uninstall() throws PluginException;
298
299 /**
300 * Enables the plugin. Unless an exception is thrown, the plugin should then be in either the
301 * {@link PluginState#ENABLING} or {@link PluginState#ENABLED} state. If the plugin is already in the
302 * {@link PluginState#ENABLING} or {@link PluginState#ENABLED} state, nothing will happen.
303 *
304 *
305 * @since 2.2.0
306 * @throws PluginException If the plugin could not be enabled
307 */
308 void enable() throws PluginException;
309
310 /**
311 * Disables the plugin. Unless an exception is thrown, the plugin should be in the {@link PluginState#DISABLED}
312 * state. If the plugin is already in the {@link PluginState#DISABLED} state, nothing will happen.
313 *
314 * @since 2.2.0 If the plugin could not be disabled
315 * @throws PluginException If the plugin could not be disabled
316 */
317 void disable() throws PluginException;
318
319 /**
320 * @return A list of plugin keys that this plugin is dependent upon, or an empty list if none
321 * @since 2.2.0
322 */
323 Set<String> getRequiredPlugins();
324
325 /**
326 * @return the list of permissions currently valid for the plugin
327 * @since 3.0
328 */
329 Set<String> getActivePermissions();
330
331 /**
332 * @return {@code true} if the plugin has all the permissions
333 * @since 3.0
334 */
335 boolean hasAllPermissions();
336
337 /**
338 * Extension interface for plugins to request resolution before enable.
339 */
340 @ExperimentalApi
341 interface Resolvable
342 {
343 /**
344 * Perform any required resolution.
345 *
346 * This is a hook to allow the plugin system to perform a resolution pass over a group of modules
347 * before the enable pass.
348 */
349 void resolve();
350
351 /**
352 * Host to default implementation of {@link Resolvable}.
353 */
354 class Default
355 {
356 /**
357 * Default implementation of {@link Resolvable#resolve()} which forwards to plugin.resolve() if available,
358 * and otherwise does nothing.
359 *
360 * @param plugin the plugin to resolve.
361 */
362 public static void resolve(final Plugin plugin)
363 {
364 if (plugin instanceof Resolvable)
365 {
366 ((Resolvable) plugin).resolve();
367 }
368 // else do nothing, plugin does not support resolution
369 }
370 }
371 }
372
373 /**
374 * Extension interface providing access to enable time metrics.
375 *
376 * @since 3.2.0
377 */
378 @ExperimentalApi
379 interface EnabledMetricsSource
380 {
381 /**
382 * Obtain the date that the plugin system most recently commenced enabling this plugin.
383 *
384 * This may return null if the plugin has never commenced enabling, or if the value is
385 * unavailable for other reasons, such as wrappers around legacy implementations.
386 *
387 * @return the date that the plugin most recently entered {@link PluginState#ENABLING}.
388 */
389 @Nullable Date getDateEnabling();
390
391 /**
392 * Obtain the date that the plugin system most recently completed enabling of this plugin.
393 *
394 * This will return null if the plugin has never been enabled, has not completed enabling
395 * since it most recently started enabling, or if the value is unavailable for any other
396 * reason, such as wrappers around legacy implementations.
397 *
398 * @return the date that the plugin most recently entered {@link PluginState#ENABLED},
399 * if this was not before the most recent {@link PluginState#ENABLING}, otherwise null.
400 */
401 @Nullable Date getDateEnabled();
402
403 /**
404 * Host to default implementations of the {@link EnabledMetricsSource} methods.
405 */
406 class Default
407 {
408 /**
409 * Default implementation for {@link EnabledMetricsSource#getDateEnabling}.
410 *
411 * @param plugin the plugin to query, which may implement EnabledMetricsSource.
412 * @return plugin.getDateEnabling if available, otherwise null.
413 */
414 public static @Nullable Date getDateEnabling(final Plugin plugin)
415 {
416 if (plugin instanceof EnabledMetricsSource)
417 {
418 return ((EnabledMetricsSource) plugin).getDateEnabling();
419 }
420 else
421 {
422 return null;
423 }
424 }
425
426 /**
427 * Default implementation for {@link EnabledMetricsSource#getDateEnabled}.
428 *
429 * @param plugin the plugin to query, which may implement EnabledMetricsSource.
430 * @return plugin.getDateEnabled if available, otherwise null.
431 */
432 public static @Nullable Date getDateEnabled(final Plugin plugin)
433 {
434 if (plugin instanceof EnabledMetricsSource)
435 {
436 return ((EnabledMetricsSource) plugin).getDateEnabled();
437 }
438 else
439 {
440 return null;
441 }
442 }
443 }
444 }
445 }