View Javadoc
1   package com.atlassian.plugin.manager.store;
2   
3   import com.atlassian.plugin.manager.PluginEnabledState;
4   import com.atlassian.plugin.manager.PluginPersistentStateModifier;
5   import com.atlassian.plugin.manager.PluginPersistentStateStore;
6   import org.slf4j.Logger;
7   import org.slf4j.LoggerFactory;
8   
9   import java.util.HashMap;
10  import java.util.Map;
11  
12  import static com.atlassian.plugin.manager.PluginPersistentState.Util.RESTART_STATE_SEPARATOR;
13  
14  /**
15   * Contains tasks that are specific to migrating data in the product's PluginPersistentStateStore.
16   *
17   * @since v4.2
18   */
19  public class PluginPersistentStateStoreMigrator {
20      private static final Logger log = LoggerFactory.getLogger(PluginPersistentStateStoreMigrator.class);
21  
22      private PluginPersistentStateStoreMigrator() {}
23  
24      /**
25       * Removes directives (e.g. ;singleton:=true) from the plugin keys currently stored in the product's
26       * PluginPersistentStateStore.
27       *
28       * <p><b>It is responsibility of the product</b> to initiate and call when needed this util method in order
29       * to migrate its PluginPersistentStateStore(s).
30       *
31       * @param store the product PluginPersistentStateStore
32       */
33      public static void removeDirectives(final PluginPersistentStateStore store) {
34          new PluginPersistentStateModifier(store).apply(builder -> {
35              Map<String, PluginEnabledState> state = builder.toState().getStatesMap();
36              Map<String, PluginEnabledState> newState = new HashMap<>(state.size());
37              for (Map.Entry<String, PluginEnabledState> entry : state.entrySet()) {
38                  String key = entry.getKey();
39                  String newKey = removeDirectivesFromKey(key);
40                  if (newKey == null) {
41                      continue;
42                  }
43  
44                  builder.removeState(key);
45                  if (state.containsKey(newKey)) {
46                      log.warn("{} contains both {} and {}", store, key, newKey);
47                  }
48                  newState.put(newKey, entry.getValue());
49              }
50              builder.addPluginEnabledState(newState);
51          });
52      }
53  
54      /**
55       *
56       * Removes any directives if they are part of the key. E.g. if the key is foo;singleton:=true-1.0.0
57       * than it will become foo-1.0.0. If the key doesn't contain any directives, then {@code null} is returned,
58       * i.e., {@code null} indicates no-change/no-migration is needed for this key.
59       *
60       * @param key the original key that needs to be processed
61       * @return see above
62       */
63      public static String removeDirectivesFromKey(String key) {
64          if (key.contains(RESTART_STATE_SEPARATOR)) {
65              return null;
66          }
67  
68          int versionBeg = key.indexOf('-');
69          if (versionBeg == -1) {
70              versionBeg = key.length();
71          }
72  
73          int directiveBeg = key.indexOf(';');
74          if (directiveBeg > -1 && directiveBeg < versionBeg) {
75              return key.substring(0, directiveBeg) + key.substring(versionBeg);
76          }
77          return null;
78      }
79  }