View Javadoc

1   package com.atlassian.sal.core.features;
2   
3   import com.atlassian.sal.api.features.DarkFeatureManager;
4   import com.google.common.base.Functions;
5   import com.google.common.base.Predicate;
6   import com.google.common.collect.Collections2;
7   import com.google.common.collect.ImmutableSet;
8   import com.google.common.collect.Maps;
9   import com.google.common.collect.Sets;
10  
11  import java.io.File;
12  import java.io.FileReader;
13  import java.io.IOException;
14  import java.util.Collection;
15  import java.util.Collections;
16  import java.util.HashMap;
17  import java.util.HashSet;
18  import java.util.Map;
19  import java.util.Properties;
20  import java.util.Set;
21  
22  public class SystemDarkFeatureInitializer
23  {
24      /**
25       * Get the dark features enabled and disabled on startup. Reads from system properties and from a "atlassian-darkfeatures.properties" file.
26       * File name can be overridden with darkfeatures.properties.file system property.
27       *
28       * @return A SystemDarkFeatures containing two sets of strings: one containing enabled dark feature keys and one containing those disabled.
29       */
30      public static SystemDarkFeatures getSystemStartupDarkFeatures()
31      {
32          final String propertiesFile = System.getProperty(DarkFeatureManager.DARKFEATURES_PROPERTIES_FILE_PROPERTY, DarkFeatureManager.DARKFEATURES_PROPERTIES_FILE_PROPERTY_DEFAULT);
33  
34          final String disableAllPropertiesFlag = System.getProperty(DarkFeatureManager.DISABLE_ALL_DARKFEATURES_PROPERTY);
35          if (Boolean.parseBoolean(disableAllPropertiesFlag))
36          {
37              return SystemDarkFeatures.disableAll();
38          }
39  
40          final Set<String> enabledPropertyDarkFeatures = getPropertyDarkFeaturesWithValue(true);
41          final Set<String> enabledPropertiesFileDarkFeatures = getPropertiesFileDarkFeatures(propertiesFile, true);
42  
43          final Set<String> disabledPropertyDarkFeatures = getPropertyDarkFeaturesWithValue(false);
44          final Set<String> disabledPropertiesFileDarkFeatures = getPropertiesFileDarkFeatures(propertiesFile, false);
45  
46          // System properties override property file
47          Set<String> enabled = Sets.union(Sets.difference(enabledPropertiesFileDarkFeatures, disabledPropertyDarkFeatures), enabledPropertyDarkFeatures);
48          Set<String> disabled = Sets.union(Sets.difference(disabledPropertiesFileDarkFeatures, enabledPropertyDarkFeatures), disabledPropertyDarkFeatures);
49  
50          return SystemDarkFeatures.darkFeatures(enabled, disabled);
51      }
52  
53      private static Set<String> getPropertiesFileDarkFeatures(String filename, boolean b)
54      {
55          final File propertiesFile = new File(filename);
56  
57          Properties properties = new Properties();
58          try
59          {
60              properties.load(new FileReader(propertiesFile));
61          }
62          catch (IOException e)
63          {
64              return Collections.emptySet();
65          }
66  
67          return new HashSet<String>(getKeysForBooleanValue(filterOnAndStripKeyPrefix(properties), b));
68      }
69  
70      private static Set<String> getPropertyDarkFeaturesWithValue(boolean b)
71      {
72          return new HashSet<String>(getKeysForBooleanValue(filterOnAndStripKeyPrefix(System.getProperties()), b));
73      }
74  
75      private static Collection<String> getKeysForBooleanValue(final Map<Object, Object> properties, final Boolean b)
76      {
77          return Collections2.transform(Maps.filterValues(properties, new Predicate<Object>()
78          {
79              @Override
80              public boolean apply(Object input)
81              {
82                  // don't want to match things with neither true nor false - should be ignored
83                  return input.toString().toLowerCase().matches(b.toString());
84              }
85          }).keySet(), Functions.toStringFunction());
86      }
87  
88      private static Map<Object, Object> filterOnAndStripKeyPrefix(Map<Object, Object> properties)
89      {
90          final Set<Map.Entry<Object, Object>> entries = Maps.filterKeys(properties, new Predicate<Object>()
91          {
92              @Override
93              public boolean apply(Object entry)
94              {
95                  return entry.toString().startsWith(DarkFeatureManager.ATLASSIAN_DARKFEATURE_PREFIX);
96              }
97          }).entrySet();
98  
99          Map<Object, Object> prefixStrippedEntries = new HashMap<Object, Object>();
100         for (Map.Entry<Object, Object> entry : entries)
101         {
102             prefixStrippedEntries.put(entry.getKey().toString().substring(DarkFeatureManager.ATLASSIAN_DARKFEATURE_PREFIX.length()), entry.getValue());
103         }
104 
105         return prefixStrippedEntries;
106     }
107 
108     public static class SystemDarkFeatures
109     {
110         private final Set<String> enabled;
111         private final Set<String> disabled;
112         private final boolean disableAll;
113 
114         private SystemDarkFeatures(Set<String> enabled, Set<String> disabled, boolean disableAll)
115         {
116             this.enabled = ImmutableSet.copyOf(enabled);
117             this.disabled = ImmutableSet.copyOf(disabled);
118             this.disableAll = disableAll;
119         }
120 
121         public static SystemDarkFeatures disableAll()
122         {
123             return new SystemDarkFeatures(Collections.<String>emptySet(), Collections.<String>emptySet(), true);
124         }
125 
126         public static SystemDarkFeatures darkFeatures(Set<String> enabled, Set<String> disabled)
127         {
128             return new SystemDarkFeatures(enabled, disabled, false);
129         }
130 
131         public Set<String> getEnabled()
132         {
133             return enabled;
134         }
135 
136         public Set<String> getDisabled()
137         {
138             return disabled;
139         }
140 
141         public boolean isDisableAll()
142         {
143             return disableAll;
144         }
145     }
146 }