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