View Javadoc
1   package com.atlassian.plugin.manager;
2   
3   import com.atlassian.plugin.ModuleDescriptor;
4   import com.atlassian.plugin.Plugin;
5   import com.atlassian.plugin.PluginRestartState;
6   
7   import java.util.HashMap;
8   import java.util.HashSet;
9   import java.util.Map;
10  import java.util.Set;
11  
12  import static com.atlassian.plugin.manager.PluginEnabledState.UNKNOWN_ENABLED_TIME;
13  import static com.atlassian.plugin.manager.PluginEnabledState.getPluginEnabledStateWithCurrentTime;
14  import static com.atlassian.plugin.manager.PluginPersistentState.Util.RESTART_STATE_SEPARATOR;
15  import static com.atlassian.plugin.manager.PluginPersistentState.Util.buildStateKey;
16  import static java.util.stream.Collectors.toMap;
17  
18  /**
19   * Interface that represents a configuration state for plugins and plugin modules. The configuration state (enabled
20   * or disabled) is separate from the plugins and modules themselves because a plugin may have multiple
21   * states depending on the context.
22   *
23   * @author anatoli
24   * @since 2.2.0
25   */
26  public interface PluginPersistentState {
27      /**
28       * Get the map of all states. Deprecated since 4.5.0
29       * @deprecated please use {@link PluginPersistentState#getStatesMap} instead
30       * @return The map that maps plugins and modules' keys to an actual enabled state (Boolean.True/Boolean.False).
31       */
32      @Deprecated
33      default Map<String, Boolean> getMap() {
34          return getStatesMap().entrySet().stream().collect(toMap(Map.Entry::getKey, e -> e.getValue().isEnabled()));
35      }
36  
37      /**
38       * Get the map of all states with the update timestamp for each of them.
39       * @since 4.5.0
40       * @return The map that maps plugins and modules' keys to an actual state {@link PluginEnabledState}
41       */
42      Map<String, PluginEnabledState> getStatesMap();
43  
44      /**
45       * Whether or not a plugin is enabled, calculated from it's current state AND default state.
46       */
47      boolean isEnabled(final Plugin plugin);
48  
49      /**
50       * Whether or not a given plugin module is enabled in this state, calculated from it's current state AND default state.
51       */
52      boolean isEnabled(final ModuleDescriptor<?> pluginModule);
53  
54      /**
55       * Get state map of the given plugin and its modules. Deprecated since 4.5.0
56       *
57       * @param plugin the plugin
58       * @deprecated please use {@link PluginPersistentState#getPluginEnabledStateMap(Plugin)} instead
59       * @return The map that maps the plugin and its modules' keys to plugin state (Boolean.TRUE/Boolean.FALSE).
60       */
61      @Deprecated
62      default Map<String, Boolean> getPluginStateMap(final Plugin plugin) {
63          return getPluginEnabledStateMap(plugin).entrySet().stream()
64                  .collect(toMap(Map.Entry::getKey, e -> e.getValue().isEnabled()));
65      }
66  
67      /**
68       * Get state map of the given plugin and its modules.
69       * @since 4.5.0
70       * @param plugin the plugin
71       * @return The map that maps the plugin and its modules' keys to plugin state {@link PluginEnabledState}
72       */
73      Map<String, PluginEnabledState> getPluginEnabledStateMap(final Plugin plugin);
74  
75      /**
76       * Gets whether the plugin is expected to be upgraded, installed, or removed on next restart
77       *
78       * @param pluginKey The plugin to query
79       * @return The state of the plugin on restart
80       */
81      PluginRestartState getPluginRestartState(String pluginKey);
82  
83      /**
84       * Builder for {@link PluginPersistentState} instances.
85       * <p>
86       * This class is <strong>not thread safe</strong>. It should
87       * only be used in a method local context.
88       *
89       * @since 2.3.0
90       */
91      final class Builder {
92  
93          public static Builder create() {
94              return new Builder();
95          }
96  
97          public static Builder create(final PluginPersistentState state) {
98              return new Builder(state);
99          }
100 
101         private final Map<String, PluginEnabledState> map = new HashMap<>();
102 
103         Builder() {
104         }
105 
106         Builder(final PluginPersistentState state) {
107             map.putAll(state.getStatesMap());
108         }
109 
110         public PluginPersistentState toState() {
111             return new DefaultPluginPersistentState(map, true);
112         }
113 
114         public Builder setEnabled(final ModuleDescriptor<?> pluginModule, final boolean isEnabled) {
115             setEnabled(pluginModule.getCompleteKey(), isEnabled);
116             return this;
117         }
118 
119         public Builder setEnabled(final Plugin plugin, final boolean isEnabled) {
120             setEnabled(plugin.getKey(), isEnabled);
121             return this;
122         }
123 
124         private Builder setEnabled(final String completeKey, final boolean isEnabled) {
125             map.put(completeKey, getPluginEnabledStateWithCurrentTime(isEnabled));
126             return this;
127         }
128 
129         /**
130          * reset all plugin's state.
131          */
132         public Builder setState(final PluginPersistentState state) {
133             map.clear();
134             map.putAll(state.getStatesMap());
135             return this;
136         }
137 
138         /**
139          * Add the plugin state.
140          */
141         public Builder addPluginEnabledState(final Map<String, PluginEnabledState> state) {
142             map.putAll(state);
143             return this;
144         }
145 
146         /**
147          * Add the plugin state.
148          */
149         @Deprecated
150         public Builder addState(final Map<String, Boolean> state) {
151             map.putAll(state.entrySet().stream().collect(toMap(Map.Entry::getKey, e -> new PluginEnabledState(e.getValue(), UNKNOWN_ENABLED_TIME))));
152             return this;
153         }
154 
155         /**
156          * Remove a plugin's state.
157          */
158         public Builder removeState(final String key) {
159             map.remove(key);
160             return this;
161         }
162 
163         public Builder setPluginRestartState(final String pluginKey, final PluginRestartState state) {
164             // Remove existing state, if any
165             for (final PluginRestartState st : PluginRestartState.values()) {
166                 map.remove(buildStateKey(pluginKey, st));
167             }
168 
169             if (state != PluginRestartState.NONE) {
170                 map.put(buildStateKey(pluginKey, state), getPluginEnabledStateWithCurrentTime(true));
171             }
172             return this;
173         }
174 
175         public Builder clearPluginRestartState() {
176             final Set<String> keys = new HashSet<>(map.keySet());
177             for (final String key : keys) {
178                 if (key.contains(RESTART_STATE_SEPARATOR)) {
179                     map.remove(key);
180                 }
181             }
182             return this;
183         }
184     }
185 
186     class Util {
187         public static final String RESTART_STATE_SEPARATOR = "--";
188 
189         static String buildStateKey(final String pluginKey, final PluginRestartState state) {
190             final StringBuilder sb = new StringBuilder();
191             sb.append(state.name());
192             sb.append(RESTART_STATE_SEPARATOR);
193             sb.append(pluginKey);
194             return sb.toString();
195         }
196     }
197 }