View Javadoc
1   package com.atlassian.plugin.util;
2   
3   import com.atlassian.plugin.Application;
4   import com.atlassian.plugin.InstallationMode;
5   import com.atlassian.plugin.ModuleDescriptor;
6   import com.atlassian.plugin.Plugin;
7   import com.atlassian.plugin.descriptors.RequiresRestart;
8   import com.google.common.base.Joiner;
9   import com.google.common.base.MoreObjects;
10  import org.dom4j.Element;
11  import org.slf4j.Logger;
12  import org.slf4j.LoggerFactory;
13  
14  import java.util.HashSet;
15  import java.util.Set;
16  import java.util.stream.Collectors;
17  
18  import static com.google.common.base.Preconditions.checkNotNull;
19  
20  /**
21   * General plugin utility methods
22   *
23   * @since 2.1
24   */
25  public class PluginUtils {
26      private static final Logger logger = LoggerFactory.getLogger(PluginUtils.class);
27  
28      public static final String ATLASSIAN_DEV_MODE = "atlassian.dev.mode";
29  
30      /**
31       * System property for storing and retrieving the time the plugin system will wait for the enabling of a plugin in
32       * seconds.
33       *
34       * @see #DEFAULT_ATLASSIAN_PLUGINS_ENABLE_WAIT_SECONDS
35       * @since 2.3.6
36       */
37      public static final String ATLASSIAN_PLUGINS_ENABLE_WAIT = "atlassian.plugins.enable.wait";
38  
39      /**
40       * The default number of seconds that a plugin should wait for its dependencies to become enabled. Currently 300s.
41       *
42       * @see #ATLASSIAN_PLUGINS_ENABLE_WAIT
43       * @since 3.1.0
44       */
45      public static final String DEFAULT_ATLASSIAN_PLUGINS_ENABLE_WAIT_SECONDS = "300";
46  
47      /**
48       * Used to customise the size of the LRU cache for batch web resources.
49       * This effectively controls how many files will be created
50       * by the file cache. Providing a negative number results in undefined behaviour.
51       *
52       * @since 2.13.0
53       */
54      public static final String WEBRESOURCE_FILE_CACHE_SIZE = new String("atlassian.webresource.file.cache.size");
55  
56      /**
57       * Used to disable the file cache should that be desired. Setting this value to true will disable the
58       * file caching completely for all places it is used.
59       *
60       * @since 2.13.0
61       */
62      public static final String WEBRESOURCE_DISABLE_FILE_CACHE = new String("atlassian.webresource.file.cache.disable");
63  
64      /**
65       * Determines if a plugin requires a restart after being installed at runtime. Looks for the annotation
66       * {@link RequiresRestart} on the plugin's module descriptors.
67       *
68       * @param plugin The plugin that was just installed at runtime, but not yet enabled
69       * @return True if a restart is required
70       * @since 2.1
71       */
72      public static boolean doesPluginRequireRestart(final Plugin plugin) {
73          //PLUG-451: When in dev mode, plugins should not require a restart.
74          if (isAtlassianDevMode()) {
75              return false;
76          }
77  
78          for (final ModuleDescriptor<?> descriptor : plugin.getModuleDescriptors()) {
79              if (descriptor.getClass().getAnnotation(RequiresRestart.class) != null) {
80                  return true;
81              }
82          }
83          return false;
84      }
85  
86      /**
87       * Gets a list of all the module keys in a plugin that require restart. Looks for the annotation
88       * {@link RequiresRestart} on the plugin's module descriptors.
89       *
90       * @param plugin The plugin
91       * @return A unique set of module keys
92       * @since 2.5.0
93       */
94      public static Set<String> getPluginModulesThatRequireRestart(final Plugin plugin) {
95          final Set<String> keys = new HashSet<>();
96          for (final ModuleDescriptor<?> descriptor : plugin.getModuleDescriptors()) {
97              if (descriptor.getClass().getAnnotation(RequiresRestart.class) != null) {
98                  keys.add(descriptor.getKey());
99              }
100         }
101         return keys;
102     }
103 
104     /**
105      * Determines if a module element applies to the current application by matching the 'application' attribute
106      * to the set of applications. If the application is specified, but isn't in the set, we return false
107      *
108      * @param element      The module element
109      * @param applications The set of application applications
110      * @return True if it should apply, false otherwise
111      * @since 2.2.0
112      */
113     public static boolean doesModuleElementApplyToApplication(final Element element,
114                                                               final Set<Application> applications,
115                                                               final InstallationMode installationMode) {
116         checkNotNull(element);
117         checkNotNull(applications);
118 
119         final ModuleRestricts restricts = ModuleRestricts.parse(element);
120         final boolean valid = restricts.isValidFor(applications, installationMode);
121         if (!valid && logger.isDebugEnabled()) {
122             logger.debug("Module '{}' with key '{}' is restricted to the following " +
123                             "applications {} and therefore does not apply to applications {}",
124                     element.getName(), element.attributeValue("key"), restricts, asString(applications));
125         }
126         return valid;
127     }
128 
129     private static String asString(final Set<Application> applications) {
130         return "[" + Joiner.on(",").join(applications.stream()
131                 .map(app -> MoreObjects.toStringHelper(app.getKey())
132                         .add("version", app.getVersion())
133                         .add("build", app.getBuildNumber())
134                         .toString()).collect(Collectors.toList())) + "]";
135     }
136 
137     /**
138      * @return The default enabling waiting period in seconds
139      * @since 2.3.6
140      */
141     public static int getDefaultEnablingWaitPeriod() {
142         return Integer.parseInt(System.getProperty(ATLASSIAN_PLUGINS_ENABLE_WAIT,
143                 DEFAULT_ATLASSIAN_PLUGINS_ENABLE_WAIT_SECONDS));
144     }
145 
146     public static boolean isAtlassianDevMode() {
147         return Boolean.getBoolean(ATLASSIAN_DEV_MODE);
148     }
149 }