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.PluginPersistentState.Util.RESTART_STATE_SEPARATOR;
13  import static com.atlassian.plugin.manager.PluginPersistentState.Util.buildStateKey;
14  
15  /**
16   * Interface that represents a configuration state for plugins and plugin modules. The configuration state (enabled
17   * or disabled) is separate from the plugins and modules themselves because a plugin may have multiple
18   * states depending on the context.
19   *
20   * @author anatoli
21   * @since 2.2.0
22   */
23  public interface PluginPersistentState {
24      /**
25       * Get the map of all states.
26       *
27       * @return The map that maps plugins and modules' keys to a state (Boolean.True/Boolean.False). State stored in this map represents only
28       * the <i>differences</i> between the current state and the default state configured in the plugin(module).
29       */
30      Map<String, Boolean> getMap();
31  
32      /**
33       * Whether or not a plugin is enabled, calculated from it's current state AND default state.
34       */
35      boolean isEnabled(final Plugin plugin);
36  
37      /**
38       * Whether or not a given plugin module is enabled in this state, calculated from it's current state AND default state.
39       */
40      boolean isEnabled(final ModuleDescriptor<?> pluginModule);
41  
42      /**
43       * Get state map of the given plugin and its modules
44       *
45       * @param plugin the plugin
46       * @return The map that maps the plugin and its modules' keys to plugin state (Boolean.TRUE/Boolean.FALSE). State stored in this map represents only
47       * the <i>differences</i> between the current state and the default state configured in the plugin(module).
48       */
49      Map<String, Boolean> getPluginStateMap(final Plugin plugin);
50  
51      /**
52       * Gets whether the plugin is expected to be upgraded, installed, or removed on next restart
53       *
54       * @param pluginKey The plugin to query
55       * @return The state of the plugin on restart
56       */
57      PluginRestartState getPluginRestartState(String pluginKey);
58  
59      /**
60       * Builder for {@link PluginPersistentState} instances.
61       * <p>
62       * This class is <strong>not thread safe</strong>. It should
63       * only be used in a method local context.
64       *
65       * @since 2.3.0
66       */
67      final class Builder {
68          public static Builder create() {
69              return new Builder();
70          }
71  
72          public static Builder create(final PluginPersistentState state) {
73              return new Builder(state);
74          }
75  
76          private final Map<String, Boolean> map = new HashMap<>();
77  
78          Builder() {
79          }
80  
81          Builder(final PluginPersistentState state) {
82              map.putAll(state.getMap());
83          }
84  
85          public PluginPersistentState toState() {
86              return new DefaultPluginPersistentState(map, true);
87          }
88  
89          public Builder setEnabled(final ModuleDescriptor<?> pluginModule, final boolean isEnabled) {
90              setEnabled(pluginModule.getCompleteKey(), pluginModule.isEnabledByDefault(), isEnabled);
91              return this;
92          }
93  
94          public Builder setEnabled(final Plugin plugin, final boolean isEnabled) {
95              setEnabled(plugin.getKey(), plugin.isEnabledByDefault(), isEnabled);
96              return this;
97          }
98  
99          private Builder setEnabled(final String completeKey, final boolean enabledByDefault, final boolean isEnabled) {
100             if (isEnabled == enabledByDefault) {
101                 map.remove(completeKey);
102             } else {
103                 map.put(completeKey, isEnabled);
104             }
105             return this;
106         }
107 
108         /**
109          * reset all plugin's state.
110          */
111         public Builder setState(final PluginPersistentState state) {
112             map.clear();
113             map.putAll(state.getMap());
114             return this;
115         }
116 
117         /**
118          * Add the plugin state.
119          */
120         public Builder addState(final Map<String, Boolean> state) {
121             map.putAll(state);
122             return this;
123         }
124 
125         /**
126          * Remove a plugin's state.
127          */
128         public Builder removeState(final String key) {
129             map.remove(key);
130             return this;
131         }
132 
133         public Builder setPluginRestartState(final String pluginKey, final PluginRestartState state) {
134             // Remove existing state, if any
135             for (final PluginRestartState st : PluginRestartState.values()) {
136                 map.remove(buildStateKey(pluginKey, st));
137             }
138 
139             if (state != PluginRestartState.NONE) {
140                 map.put(buildStateKey(pluginKey, state), true);
141             }
142             return this;
143         }
144 
145         public Builder clearPluginRestartState() {
146             final Set<String> keys = new HashSet<>(map.keySet());
147             for (final String key : keys) {
148                 if (key.contains(RESTART_STATE_SEPARATOR)) {
149                     map.remove(key);
150                 }
151             }
152             return this;
153         }
154     }
155 
156     class Util {
157         public static final String RESTART_STATE_SEPARATOR = "--";
158 
159         static String buildStateKey(final String pluginKey, final PluginRestartState state) {
160             final StringBuilder sb = new StringBuilder();
161             sb.append(state.name());
162             sb.append(RESTART_STATE_SEPARATOR);
163             sb.append(pluginKey);
164             return sb.toString();
165         }
166     }
167 }