View Javadoc

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