View Javadoc
1   package com.atlassian.plugin.manager;
2   
3   import com.atlassian.plugin.ModuleDescriptor;
4   import com.atlassian.plugin.PluginController;
5   import org.slf4j.Logger;
6   import org.slf4j.LoggerFactory;
7   
8   import java.util.List;
9   import java.util.Objects;
10  import java.util.stream.Collectors;
11  
12  import static java.util.stream.StreamSupport.stream;
13  
14  /**
15   * Safely extracts the module instance from module descriptors,
16   * handling exceptions and disabling broken plugins as appropriate.
17   *
18   * @since 4.0
19   */
20  public class SafeModuleExtractor {
21      private static final Logger log = LoggerFactory.getLogger(SafeModuleExtractor.class);
22  
23      private final PluginController pluginController;
24  
25      public SafeModuleExtractor(PluginController pluginController) {
26          this.pluginController = pluginController;
27      }
28  
29      /**
30       * Safely extracts the module instance from the given module descriptors. This method will disable any plugin it
31       * can't successfully extract the module instance from.
32       */
33      public <M> List<M> getModules(final Iterable<? extends ModuleDescriptor<M>> moduleDescriptors) {
34          return stream(moduleDescriptors.spliterator(), false)
35                  .map(this::getModule)
36                  .filter(Objects::nonNull)
37                  .collect(Collectors.toList());
38      }
39  
40      /**
41       * Safely extracts the module instance from the given module descriptor. This method will disable any plugin it
42       * can't successfully extract the module instance from.
43       *
44       * @since 5.0.0
45       */
46      <M> M getModule(ModuleDescriptor<M> descriptor) {
47          if (descriptor == null || descriptor.isBroken()) {
48              return null;
49          }
50  
51          try {
52              return descriptor.getModule();
53          } catch (final RuntimeException ex) {
54              final String pluginKey = descriptor.getPlugin().getKey();
55  
56              log.error("Exception when retrieving plugin module {}, disabling plugin {}",
57                      descriptor.getCompleteKey(), pluginKey, ex);
58  
59              descriptor.setBroken();
60              // Don't persist: don't want to create a snowflake config in Cloud instance,
61              // and the module might work following restart if something has changed.
62              pluginController.disablePluginWithoutPersisting(pluginKey);
63              return null;
64          }
65      }
66  }