View Javadoc
1   package com.atlassian.plugin.manager;
2   
3   import com.atlassian.plugin.ModuleCompleteKey;
4   import com.atlassian.plugin.ModuleDescriptor;
5   import com.atlassian.plugin.ModuleDescriptorFactory;
6   import com.atlassian.plugin.Plugin;
7   import com.atlassian.plugin.PluginAccessor;
8   import com.atlassian.plugin.PluginInternal;
9   import com.atlassian.plugin.PluginRegistry;
10  import com.atlassian.plugin.PluginRestartState;
11  import com.atlassian.plugin.PluginState;
12  import com.atlassian.plugin.classloader.PluginsClassLoader;
13  import com.atlassian.plugin.event.PluginEventManager;
14  import com.atlassian.plugin.predicate.EnabledModulePredicate;
15  import com.atlassian.plugin.predicate.ModuleOfClassPredicate;
16  import com.atlassian.plugin.scope.ScopeManager;
17  import org.slf4j.Logger;
18  import org.slf4j.LoggerFactory;
19  
20  import javax.annotation.Nullable;
21  import java.io.InputStream;
22  import java.util.Collection;
23  import java.util.List;
24  import java.util.Objects;
25  import java.util.function.Predicate;
26  import java.util.stream.Collectors;
27  import java.util.stream.Stream;
28  
29  import static com.atlassian.plugin.util.Assertions.notNull;
30  
31  public class ProductPluginAccessorBase implements PluginAccessor {
32      private static final Logger log = LoggerFactory.getLogger(ProductPluginAccessorBase.class);
33  
34      private final PluginRegistry.ReadOnly pluginRegistry;
35      private final ModuleDescriptorFactory moduleDescriptorFactory;
36      private final ClassLoader classLoader;
37      private final PluginPersistentStateStore store;
38  
39      public ProductPluginAccessorBase(final PluginRegistry.ReadOnly pluginRegistry,
40                                       final PluginPersistentStateStore store,
41                                       final ModuleDescriptorFactory moduleDescriptorFactory,
42                                       final PluginEventManager pluginEventManager) {
43          this.pluginRegistry = pluginRegistry;
44          this.moduleDescriptorFactory = notNull("ModuleDescriptorFactory", moduleDescriptorFactory);
45          this.classLoader = new PluginsClassLoader(null, this, pluginEventManager);
46          this.store = notNull("PluginPersistentStateStore", store);
47      }
48  
49      /**
50       * @deprecated in 5.0 for removal in 6.0 when {@link ScopeManager} will be removed. Use
51       *             {@link ProductPluginAccessor(com.atlassian.plugin.PluginRegistry.ReadOnly, PluginPersistentStateStore,
52       *             ModuleDescriptorFactory, PluginEventManager)} instead.
53       */
54      @Deprecated
55      public ProductPluginAccessorBase(final PluginRegistry.ReadOnly pluginRegistry,
56                                       final PluginPersistentStateStore store,
57                                       final ModuleDescriptorFactory moduleDescriptorFactory,
58                                       final PluginEventManager pluginEventManager,
59                                       final ScopeManager ignored) {
60          this(pluginRegistry, store, moduleDescriptorFactory, pluginEventManager);
61      }
62  
63      @Override
64      public Collection<Plugin> getPlugins() {
65          return pluginRegistry.getAll();
66      }
67  
68      @Override
69      public Collection<Plugin> getPlugins(final Predicate<Plugin> pluginPredicate) {
70          notNull("pluginPredicate", pluginPredicate);
71          return getPlugins().stream()
72                  .filter(pluginPredicate)
73                  .collect(Collectors.toList());
74      }
75  
76      @Override
77      public Collection<Plugin> getEnabledPlugins() {
78          return getPlugins((Predicate<Plugin>) p -> PluginState.ENABLED.equals(p.getPluginState()));
79      }
80  
81      /**
82       * Get the modules of all the given descriptor. If any of the getModule() calls fails, the error is recorded in the
83       * logs
84       *
85       * @param moduleDescriptors the collection of module descriptors to get the modules from.
86       * @return a {@link Collection} modules that can be any type of object. This collection will not contain any null
87       * value.
88       */
89      private <M> Stream<M> getModules(final Stream<ModuleDescriptor<M>> moduleDescriptors) {
90          return moduleDescriptors
91                  .filter(Objects::nonNull)
92                  .map(md -> {
93                      try {
94                          return md.getModule();
95                      } catch (final RuntimeException ex) {
96                          log.error("Exception when retrieving plugin module {}", md.getCompleteKey(), ex);
97                          md.setBroken();
98                          return null;
99                      }
100                 })
101                 .filter(Objects::nonNull);
102     }
103 
104     /**
105      * Get the all the module descriptors from the given collection of plugins, filtered by the predicate.
106      * <p>
107      * Be careful, your predicate must filter ModuleDescriptors that are not M, this method does not guarantee that the
108      * descriptors are of the correct type by itself.
109      *
110      * @param plugins a collection of {@link Plugin}s
111      * @return a stream of {@link ModuleDescriptor descriptors}
112      */
113     private <M> Stream<ModuleDescriptor<M>> getModuleDescriptors(final Collection<Plugin> plugins,
114                                                                  final Predicate<ModuleDescriptor<M>> predicate) {
115         return plugins.stream()
116                 .flatMap(p -> p.getModuleDescriptors().stream())
117                 .map(m -> {
118                     // hack way to get typed descriptors from plugin and
119                     // keep generics happy
120                     @SuppressWarnings("unchecked")
121                     final ModuleDescriptor<M> cast = (ModuleDescriptor<M>) m;
122                     return cast;
123                 })
124                 .filter(predicate);
125     }
126 
127     @Override
128     public <M> Collection<M> getModules(final Predicate<ModuleDescriptor<M>> predicate) {
129         notNull("moduleDescriptorPredicate", predicate);
130         return getModules(getModuleDescriptors(getPlugins(), predicate))
131                 .collect(Collectors.toList());
132     }
133 
134     @Override
135     public <M> Collection<ModuleDescriptor<M>> getModuleDescriptors(final Predicate<ModuleDescriptor<M>> predicate) {
136         notNull("moduleDescriptorPredicate", predicate);
137         return getModuleDescriptors(getPlugins(), predicate).collect(Collectors.toList());
138     }
139 
140     @Override
141     public Plugin getPlugin(final String key) {
142         return pluginRegistry.get(notNull("Plugin key ", key));
143     }
144 
145     @Override
146     public Plugin getEnabledPlugin(final String pluginKey) {
147         if (!isPluginEnabled(pluginKey)) {
148             return null;
149         }
150         return getPlugin(pluginKey);
151     }
152 
153     private ModuleDescriptor<?> getPluginModule(final ModuleCompleteKey key) {
154         final Plugin plugin = getPlugin(key.getPluginKey());
155         if (plugin == null) {
156             return null;
157         }
158         return plugin.getModuleDescriptor(key.getModuleKey());
159     }
160 
161     @Override
162     public ModuleDescriptor<?> getPluginModule(@Nullable final String completeKey) {
163         return getPluginModule(new ModuleCompleteKey(completeKey));
164     }
165 
166     private boolean isPluginModuleEnabled(final ModuleCompleteKey key) {
167         if (!isPluginEnabled(key.getPluginKey())) {
168             return false;
169         }
170         final ModuleDescriptor<?> pluginModule = getPluginModule(key);
171         return (pluginModule != null) && pluginModule.isEnabled();
172     }
173 
174     @Override
175     public ModuleDescriptor<?> getEnabledPluginModule(@Nullable final String completeKey) {
176         final ModuleCompleteKey key = new ModuleCompleteKey(completeKey);
177 
178         // If it's disabled, return null
179         if (!isPluginModuleEnabled(key)) {
180             return null;
181         }
182 
183         return getEnabledPlugin(key.getPluginKey()).getModuleDescriptor(key.getModuleKey());
184     }
185 
186     @Override
187     public boolean isPluginEnabled(final String key) throws IllegalArgumentException {
188         final Plugin plugin = pluginRegistry.get(notNull("Plugin key", key));
189 
190         return plugin != null && plugin.getPluginState() == PluginState.ENABLED;
191     }
192 
193     @Override
194     public boolean isPluginModuleEnabled(@Nullable final String completeKey) {
195         return (completeKey != null) && isPluginModuleEnabled(new ModuleCompleteKey(completeKey));
196     }
197 
198     /**
199      * Get all module descriptor that are enabled and for which the module is an instance of the given class.
200      *
201      * @param moduleClass the class of the module within the module descriptor.
202      * @return a stream of {@link ModuleDescriptor}s
203      */
204     private <M> Stream<ModuleDescriptor<M>> getEnabledModuleDescriptorsByModuleClass(final Class<M> moduleClass) {
205         final ModuleOfClassPredicate<M> ofType = new ModuleOfClassPredicate<>(moduleClass);
206         final EnabledModulePredicate enabled = new EnabledModulePredicate();
207         return getModuleDescriptors(getEnabledPlugins(), ofType.and(enabled));
208     }
209 
210     @Override
211     public <M> List<M> getEnabledModulesByClass(final Class<M> moduleClass) {
212         return getModules(getEnabledModuleDescriptorsByModuleClass(moduleClass))
213                 .collect(Collectors.toList());
214     }
215 
216     @Override
217     public <D extends ModuleDescriptor<?>> List<D> getEnabledModuleDescriptorsByClass(final Class<D> descriptorClazz) {
218         notNull("Descriptor class", descriptorClazz);
219         return getEnabledPlugins().stream()
220                 .flatMap(p -> p.getModuleDescriptors().stream())
221                 .filter(descriptorClazz::isInstance)
222                 .filter(new EnabledModulePredicate())
223                 .map(descriptorClazz::cast)
224                 .collect(Collectors.toList());
225     }
226 
227     @Override
228     public InputStream getDynamicResourceAsStream(final String resourcePath) {
229         return getClassLoader().getResourceAsStream(resourcePath);
230     }
231 
232     @Override
233     public ClassLoader getClassLoader() {
234         return classLoader;
235     }
236 
237     @Override
238     public boolean isSystemPlugin(final String key) {
239         final Plugin plugin = getPlugin(key);
240         return (plugin != null) && plugin.isSystemPlugin();
241     }
242 
243     @Override
244     public PluginRestartState getPluginRestartState(final String key) {
245         return store.load().getPluginRestartState(key);
246     }
247 
248     @Override
249     public Iterable<ModuleDescriptor<?>> getDynamicModules(final Plugin plugin) {
250         // check the type
251         if (plugin instanceof PluginInternal) {
252             return ((PluginInternal) plugin).getDynamicModuleDescriptors();
253         }
254         throw new IllegalArgumentException(plugin + " does not implement com.atlassian.plugin.PluginInternal it is a " + plugin.getClass().getCanonicalName());
255     }
256 }