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