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