1 package com.atlassian.plugin.metadata;
2
3 import com.atlassian.plugin.ModuleDescriptor;
4 import com.atlassian.plugin.Plugin;
5 import com.atlassian.plugin.descriptors.CannotDisable;
6
7 import javax.annotation.concurrent.Immutable;
8
9 import static com.google.common.base.Preconditions.checkNotNull;
10
11 /**
12 * A default implementation that uses the {@link com.atlassian.plugin.metadata.ClasspathFilePluginMetadata}
13 * plugin metadata implementation to resolve the application provided plugin metadata.
14 *
15 * @since 2.6
16 */
17 @Immutable
18 public final class DefaultPluginMetadataManager implements PluginMetadataManager {
19 private final PluginMetadata metadata;
20
21 /**
22 * Production ctor. Loads from the class path.
23 */
24 public DefaultPluginMetadataManager() {
25 this(new ClasspathFilePluginMetadata());
26 }
27
28 /**
29 * Test ctor.
30 */
31 DefaultPluginMetadataManager(final PluginMetadata metadata) {
32 this.metadata = checkNotNull(metadata, "metadata");
33 }
34
35 /**
36 * A plugin is determined to be non-user if
37 * {@link com.atlassian.plugin.Plugin#isBundledPlugin()} is true or if the
38 * host application has indicated to the plugins system that a plugin was
39 * provided by it.
40 * <p>
41 * <strong>NOTE:</strong> If a user has upgraded a bundled plugin then the
42 * decision of whether it is user installed plugin is determined by if the
43 * application has indicated to the plugins system that a plugin was
44 * provided or not.
45 */
46 public boolean isUserInstalled(final Plugin plugin) {
47 checkNotNull(plugin, "plugin");
48 // It is user installed if it has not been marked as provided by the
49 // application and it was not bundled.
50 return !plugin.isBundledPlugin() && !metadata.applicationProvided(plugin);
51 }
52
53 /**
54 * A plugin is determined to be "system" if
55 * {@link #isUserInstalled(com.atlassian.plugin.Plugin)} is false.
56 */
57 public boolean isSystemProvided(Plugin plugin) {
58 return !isUserInstalled(plugin);
59 }
60
61 /**
62 * A plugin is determined to be optional if the host application has not
63 * indicated to the plugins system that it is required or if any of its
64 * modules have been flagged as not optional.
65 */
66 public boolean isOptional(final Plugin plugin) {
67 checkNotNull(plugin, "plugin");
68 // If the application has marked the plugin as required then we know we
69 // are required
70 if (!optionalAccordingToHostApplication(plugin)) {
71 return false;
72 }
73
74 // We need to check if any of the plugins modules are not optional
75 for (final ModuleDescriptor<?> moduleDescriptor : plugin.getModuleDescriptors()) {
76 if (!optionalAccordingToHostApplication(moduleDescriptor)) {
77 return false;
78 }
79 }
80 return true;
81 }
82
83 /**
84 * A module is determined to be optional if the host application has not
85 * indicated to the plugins system that it is required. If the call to
86 * {@code isOptional} with the module descriptor's plugin is {@code false},
87 * then this method will also return {@code false}. Also if the module
88 * descriptor is annotated with
89 * {@link com.atlassian.plugin.descriptors.CannotDisable} then it can not be
90 * optional.
91 */
92 public boolean isOptional(final ModuleDescriptor<?> moduleDescriptor) {
93 checkNotNull(moduleDescriptor, "moduleDescriptor");
94 // It is not optional if the host application has marked it as required
95 if (!optionalAccordingToHostApplication(moduleDescriptor)) {
96 return false;
97 }
98
99 // A module can not be optional if it is marked
100 // by the CannotDisable annotation
101 if (!optionalAccordingToModuleDescriptorType(moduleDescriptor)) {
102 return false;
103 }
104
105 // A module can only be optional if its parent plugin is not declared by
106 // the host application as required
107 return optionalAccordingToHostApplication(moduleDescriptor.getPlugin());
108 }
109
110 private boolean optionalAccordingToHostApplication(final Plugin plugin) {
111 return !metadata.required(plugin);
112 }
113
114 private boolean optionalAccordingToHostApplication(final ModuleDescriptor<?> moduleDescriptor) {
115 return !metadata.required(moduleDescriptor);
116 }
117
118 private boolean optionalAccordingToModuleDescriptorType(final ModuleDescriptor<?> moduleDescriptor) {
119 return !moduleDescriptor.getClass().isAnnotationPresent(CannotDisable.class);
120 }
121 }