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   import com.atlassian.plugin.StoredPluginState;
7   
8   import java.util.HashMap;
9   import java.util.HashSet;
10  import java.util.Map;
11  import java.util.Set;
12  
13  import static com.atlassian.plugin.manager.PluginEnabledState.UNKNOWN_ENABLED_TIME;
14  import static com.atlassian.plugin.manager.PluginEnabledState.getPluginEnabledStateWithCurrentTime;
15  import static com.atlassian.plugin.manager.PluginPersistentState.Util.RESTART_STATE_SEPARATOR;
16  import static com.atlassian.plugin.manager.PluginPersistentState.Util.buildStateKey;
17  import static java.util.stream.Collectors.toMap;
18  
19  /**
20   * Interface that represents a configuration state for plugins and plugin modules. The configuration state (enabled
21   * or disabled) is separate from the plugins and modules themselves because a plugin may have multiple
22   * states depending on the context.
23   *
24   * @since 2.2.0
25   */
26  public interface PluginPersistentState extends StoredPluginState {
27  
28      /**
29       * @return a new builder
30       * @since 5.0
31       */
32      static Builder builder() {
33          return new Builder();
34      }
35  
36      /**
37       * @return a new builder that is initialized with the provided {@code state}
38       * @since 5.0
39       */
40      static Builder builder(PluginPersistentState state) {
41          return new Builder(state);
42      }
43  
44      /**
45       * Get the map of all states. Deprecated since 4.5.0
46       * @deprecated please use {@link PluginPersistentState#getStatesMap} instead
47       * @return The map that maps plugins and modules' keys to an actual enabled state (Boolean.True/Boolean.False).
48       */
49      @Deprecated
50      default Map<String, Boolean> getMap() {
51          return getStatesMap().entrySet().stream().collect(toMap(Map.Entry::getKey, e -> e.getValue().isEnabled()));
52      }
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       * Builder for {@link PluginPersistentState} instances.
69       * <p>
70       * This class is <strong>not thread safe</strong>. It should
71       * only be used in a method local context.
72       *
73       * @since 2.3.0
74       */
75      final class Builder {
76  
77          public static Builder create() {
78              return new Builder();
79          }
80  
81          public static Builder create(final PluginPersistentState state) {
82              return new Builder(state);
83          }
84  
85          private final Map<String, PluginEnabledState> map = new HashMap<>();
86  
87          Builder() {
88          }
89  
90          Builder(final PluginPersistentState state) {
91              map.putAll(state.getStatesMap());
92          }
93  
94          public PluginPersistentState toState() {
95              return new DefaultPluginPersistentState(map, true);
96          }
97  
98          public Builder setEnabled(final ModuleDescriptor<?> pluginModule, final boolean isEnabled) {
99              setEnabled(pluginModule.getCompleteKey(), isEnabled);
100             return this;
101         }
102 
103         public Builder setEnabled(final Plugin plugin, final boolean isEnabled) {
104             setEnabled(plugin.getKey(), isEnabled);
105             return this;
106         }
107 
108         private Builder setEnabled(final String completeKey, final boolean isEnabled) {
109             map.put(completeKey, getPluginEnabledStateWithCurrentTime(isEnabled));
110             return this;
111         }
112 
113         /**
114          * reset all plugin's state.
115          */
116         public Builder setState(final PluginPersistentState state) {
117             map.clear();
118             map.putAll(state.getStatesMap());
119             return this;
120         }
121 
122         /**
123          * Add the plugin state.
124          */
125         public Builder addPluginEnabledState(final Map<String, PluginEnabledState> state) {
126             map.putAll(state);
127             return this;
128         }
129 
130         /**
131          * Add the plugin state.
132          * @deprecated in 4.5.0 for removal in 6.0. Use {@link #addPluginEnabledState(Map)} instead
133          */
134         @Deprecated
135         public Builder addState(final Map<String, Boolean> state) {
136             map.putAll(state.entrySet().stream().collect(toMap(Map.Entry::getKey, e -> new PluginEnabledState(e.getValue(), UNKNOWN_ENABLED_TIME))));
137             return this;
138         }
139 
140         /**
141          * Remove a plugin's state.
142          */
143         public Builder removeState(final String key) {
144             map.remove(key);
145             return this;
146         }
147 
148         public Builder setPluginRestartState(final String pluginKey, final PluginRestartState state) {
149             // Remove existing state, if any
150             for (final PluginRestartState st : PluginRestartState.values()) {
151                 map.remove(buildStateKey(pluginKey, st));
152             }
153 
154             if (state != PluginRestartState.NONE) {
155                 map.put(buildStateKey(pluginKey, state), getPluginEnabledStateWithCurrentTime(true));
156             }
157             return this;
158         }
159 
160         public Builder clearPluginRestartState() {
161             final Set<String> keys = new HashSet<>(map.keySet());
162             for (final String key : keys) {
163                 if (key.contains(RESTART_STATE_SEPARATOR)) {
164                     map.remove(key);
165                 }
166             }
167             return this;
168         }
169     }
170 
171     class Util {
172         public static final String RESTART_STATE_SEPARATOR = "--";
173 
174         static String buildStateKey(final String pluginKey, final PluginRestartState state) {
175             return state.name() + RESTART_STATE_SEPARATOR + pluginKey;
176         }
177     }
178 }