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 {
27 private static final String SITE_WIDE_DARK_FEATURES = "atlassian.sitewide.dark.features";
28
29 private final ResettableLazyReference<ImmutableSet<String>> cache = new ResettableLazyReference<ImmutableSet<String>>()
30 {
31 @Override
32 protected ImmutableSet<String> create() throws Exception
33 {
34 return ImmutableSet.copyOf(load());
35 }
36 };
37
38 private final PluginSettingsFactory pluginSettingsFactory;
39
40 public DefaultSiteDarkFeaturesStorage(final PluginSettingsFactory pluginSettingsFactory)
41 {
42 this.pluginSettingsFactory = pluginSettingsFactory;
43 }
44
45 @Override
46 public void enable(final String featureKey)
47 {
48 final String trimmedFeatureKey = checkNotNull(StringUtils.trimToNull(featureKey), "featureKey must not be blank");
49 if (!cache.get().contains(trimmedFeatureKey))
50 {
51 update(addFeatureKey(trimmedFeatureKey));
52 cache.reset();
53 }
54 }
55
56 @Override
57 public void disable(final String featureKey)
58 {
59 final String trimmedFeatureKey = checkNotNull(StringUtils.trimToNull(featureKey), "featureKey must not be blank");
60 if (cache.get().contains(trimmedFeatureKey))
61 {
62 update(removeFeatureKey(trimmedFeatureKey));
63 cache.reset();
64 }
65 }
66
67 @Override
68 public ImmutableSet<String> getEnabledDarkFeatures()
69 {
70 return cache.get();
71 }
72
73
74
75
76
77
78
79
80
81
82 private synchronized void update(final Function<List<String>, List<String>> transformer)
83 {
84
85
86
87
88 final List<String> storedFeatureKeys = load();
89 final List<String> updatedFeatureKeys = transformer.apply(storedFeatureKeys);
90 store(updatedFeatureKeys);
91 }
92
93 private synchronized List<String> load()
94 {
95 final PluginSettings globalSettings = pluginSettingsFactory.createGlobalSettings();
96 final Object value = globalSettings.get(SITE_WIDE_DARK_FEATURES);
97 return extractFeatureKeys(value);
98 }
99
100 private List<String> extractFeatureKeys(@Nullable final Object value)
101 {
102 final LinkedList<String> storedFeatureKeys = new LinkedList<String>();
103 if (value instanceof List)
104 {
105 final List list = List.class.cast(value);
106 for (final Object listItem : list)
107 {
108 if (listItem instanceof String)
109 {
110 storedFeatureKeys.addLast(String.class.cast(listItem));
111 }
112 }
113 }
114 return storedFeatureKeys;
115 }
116
117 private synchronized void store(final List<String> updatedFeatureKeys)
118 {
119 final PluginSettings globalSettings = pluginSettingsFactory.createGlobalSettings();
120 globalSettings.put(SITE_WIDE_DARK_FEATURES, updatedFeatureKeys);
121 }
122
123 private Function<List<String>, List<String>> addFeatureKey(final String featureKey)
124 {
125 return new Function<List<String>, List<String>>()
126 {
127 @Override
128 public List<String> apply(@Nullable final List<String> storedFeatureKeys)
129 {
130 if (storedFeatureKeys == null)
131 {
132 return storedFeatureKeys;
133 }
134
135 final List<String> result = new ArrayList<String>(storedFeatureKeys);
136 if (!storedFeatureKeys.contains(featureKey))
137 {
138 result.add(featureKey);
139 }
140 return result;
141 }
142 };
143 }
144
145 private Function<List<String>, List<String>> removeFeatureKey(final String featureKey)
146 {
147 return new Function<List<String>, List<String>>()
148 {
149 @Override
150 public List<String> apply(@Nullable final List<String> storedFeatureKeys)
151 {
152 if (storedFeatureKeys == null)
153 {
154 return storedFeatureKeys;
155 }
156
157 final List<String> result = new ArrayList<String>(storedFeatureKeys);
158 result.remove(featureKey);
159 return result;
160 }
161 };
162 }
163 }