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