1 package com.atlassian.sal.core.features;
2
3 import com.atlassian.sal.api.features.SiteDarkFeaturesStorage;
4 import com.atlassian.sal.api.pluginsettings.PluginSettings;
5 import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory;
6 import com.atlassian.util.concurrent.ResettableLazyReference;
7 import com.google.common.base.Function;
8 import com.google.common.collect.ImmutableSet;
9 import org.apache.commons.lang.StringUtils;
10
11 import javax.annotation.Nullable;
12 import java.util.ArrayList;
13 import java.util.LinkedList;
14 import java.util.List;
15
16 import static com.google.common.base.Preconditions.checkNotNull;
17
18
19
20
21
22
23
24
25 public class DefaultSiteDarkFeaturesStorage implements SiteDarkFeaturesStorage {
26 private static final String SITE_WIDE_DARK_FEATURES = "atlassian.sitewide.dark.features";
27
28 private final ResettableLazyReference<ImmutableSet<String>> cache = new ResettableLazyReference<ImmutableSet<String>>() {
29 @Override
30 protected ImmutableSet<String> create() throws Exception {
31 return ImmutableSet.copyOf(load());
32 }
33 };
34
35 private final PluginSettingsFactory pluginSettingsFactory;
36
37 public DefaultSiteDarkFeaturesStorage(final PluginSettingsFactory pluginSettingsFactory) {
38 this.pluginSettingsFactory = pluginSettingsFactory;
39 }
40
41 @Override
42 public void enable(final String featureKey) {
43 final String trimmedFeatureKey = checkNotNull(StringUtils.trimToNull(featureKey), "featureKey must not be blank");
44 if (!cache.get().contains(trimmedFeatureKey)) {
45 update(addFeatureKey(trimmedFeatureKey));
46 cache.reset();
47 }
48 }
49
50 @Override
51 public void disable(final String featureKey) {
52 final String trimmedFeatureKey = checkNotNull(StringUtils.trimToNull(featureKey), "featureKey must not be blank");
53 if (cache.get().contains(trimmedFeatureKey)) {
54 update(removeFeatureKey(trimmedFeatureKey));
55 cache.reset();
56 }
57 }
58
59 @Override
60 public ImmutableSet<String> getEnabledDarkFeatures() {
61 return cache.get();
62 }
63
64
65
66
67
68
69
70
71
72
73
74 private synchronized void update(final Function<List<String>, List<String>> transformer) {
75
76
77
78
79 final List<String> storedFeatureKeys = load();
80 final List<String> updatedFeatureKeys = transformer.apply(storedFeatureKeys);
81 store(updatedFeatureKeys);
82 }
83
84 private synchronized List<String> load() {
85 final PluginSettings globalSettings = pluginSettingsFactory.createGlobalSettings();
86 final Object value = globalSettings.get(SITE_WIDE_DARK_FEATURES);
87 return extractFeatureKeys(value);
88 }
89
90 private List<String> extractFeatureKeys(@Nullable final Object value) {
91 final LinkedList<String> storedFeatureKeys = new LinkedList<String>();
92 if (value instanceof List) {
93 final List list = List.class.cast(value);
94 for (final Object listItem : list) {
95 if (listItem instanceof String) {
96 storedFeatureKeys.addLast(String.class.cast(listItem));
97 }
98 }
99 }
100 return storedFeatureKeys;
101 }
102
103 private synchronized void store(final List<String> updatedFeatureKeys) {
104 final PluginSettings globalSettings = pluginSettingsFactory.createGlobalSettings();
105 globalSettings.put(SITE_WIDE_DARK_FEATURES, updatedFeatureKeys);
106 }
107
108 private Function<List<String>, List<String>> addFeatureKey(final String featureKey) {
109 return new Function<List<String>, List<String>>() {
110 @Override
111 public List<String> apply(@Nullable final List<String> storedFeatureKeys) {
112 if (storedFeatureKeys == null) {
113 return storedFeatureKeys;
114 }
115
116 final List<String> result = new ArrayList<String>(storedFeatureKeys);
117 if (!storedFeatureKeys.contains(featureKey)) {
118 result.add(featureKey);
119 }
120 return result;
121 }
122 };
123 }
124
125 private Function<List<String>, List<String>> removeFeatureKey(final String featureKey) {
126 return new Function<List<String>, List<String>>() {
127 @Override
128 public List<String> apply(@Nullable final List<String> storedFeatureKeys) {
129 if (storedFeatureKeys == null) {
130 return storedFeatureKeys;
131 }
132
133 final List<String> result = new ArrayList<String>(storedFeatureKeys);
134 result.remove(featureKey);
135 return result;
136 }
137 };
138 }
139 }