View Javadoc

1   package com.atlassian.sal.core.features;
2   
3   import com.atlassian.fugue.Option;
4   import com.atlassian.sal.api.features.DarkFeatureManager;
5   import com.atlassian.sal.api.features.EnabledDarkFeatures;
6   import com.atlassian.sal.api.features.EnabledDarkFeaturesBuilder;
7   import com.atlassian.sal.api.features.ValidFeatureKeyPredicate;
8   import com.atlassian.sal.api.features.MissingPermissionException;
9   import com.atlassian.sal.api.features.SiteDarkFeaturesStorage;
10  import com.atlassian.sal.api.user.UserManager;
11  
12  import javax.annotation.Nullable;
13  
14  import static com.atlassian.sal.api.features.ValidFeatureKeyPredicate.checkFeatureKey;
15  
16  /**
17   * Default implementation of DarkFeatureManager - sufficient for any product which does not already have its own dark
18   * feature framework. Does not implement per-user enabling.
19   */
20  public class DefaultDarkFeatureManager implements DarkFeatureManager
21  {
22      private final UserManager userManager;
23      private final SiteDarkFeaturesStorage siteDarkFeaturesStorage;
24      private final SystemDarkFeatureInitializer.SystemDarkFeatures systemDarkFeatures;
25  
26      public DefaultDarkFeatureManager(final UserManager userManager, final SiteDarkFeaturesStorage siteDarkFeaturesStorage)
27      {
28          this.userManager = userManager;
29          this.siteDarkFeaturesStorage = siteDarkFeaturesStorage;
30          this.systemDarkFeatures = SystemDarkFeatureInitializer.getSystemStartupDarkFeatures();
31      }
32  
33      @Override
34      public boolean isFeatureEnabledForAllUsers(final String featureKey)
35      {
36          return ValidFeatureKeyPredicate.isValidFeatureKey(featureKey) && getFeaturesEnabledForAllUsers().isFeatureEnabled(featureKey);
37      }
38  
39      @Override
40      public boolean isFeatureEnabledForCurrentUser(final String featureKey)
41      {
42          return isFeatureEnabledForAllUsers(featureKey);
43      }
44  
45      @Override
46      public Option<Boolean> isFeatureEnabledForUser(@Nullable final String username, final String featureKey)
47      {
48          return isUserAnonymous(username) || isUserExisting(username) ? Option.some(isFeatureEnabledForAllUsers(featureKey)) : Option.<Boolean>none();
49      }
50  
51      @Override
52      public boolean canManageFeaturesForAllUsers()
53      {
54          try
55          {
56              final String remoteUsername = userManager.getRemoteUsername();
57              return userManager.isSystemAdmin(remoteUsername);
58          }
59          catch (RuntimeException e)
60          {
61              /**
62               * Applying the principle of least surprise here so the caller wouldn't have to deal with undeclared
63               * runtime exceptions. Determining that a user has the proper permissions is very unlikely to be successful
64               * when an exception is thrown.
65               */
66              return false;
67          }
68      }
69  
70      @Override
71      public void enableFeatureForAllUsers(final String featureKey)
72      {
73          checkFeatureKey(featureKey);
74          checkCurrentUserCanManageFeaturesForAllUsers();
75          siteDarkFeaturesStorage.enable(featureKey);
76      }
77  
78      @Override
79      public void disableFeatureForAllUsers(final String featureKey)
80      {
81          checkFeatureKey(featureKey);
82          checkCurrentUserCanManageFeaturesForAllUsers();
83          siteDarkFeaturesStorage.disable(featureKey);
84      }
85  
86      @Override
87      public void enableFeatureForCurrentUser(final String featureKey)
88      {
89          throwUnsupportedPerUserOperationException();
90      }
91  
92      @Override
93      public void enableFeatureForUser(final String username, final String featureKey)
94      {
95          throwUnsupportedPerUserOperationException();
96      }
97  
98      @Override
99      public void disableFeatureForCurrentUser(final String featureKey)
100     {
101         throwUnsupportedPerUserOperationException();
102     }
103 
104     @Override
105     public void disableFeatureForUser(final String username, final String featureKey)
106     {
107         throwUnsupportedPerUserOperationException();
108     }
109 
110     public EnabledDarkFeatures getFeaturesEnabledForAllUsers()
111     {
112         if (systemDarkFeatures.isDisableAll())
113         {
114             return EnabledDarkFeatures.NONE;
115         }
116         else
117         {
118             return new EnabledDarkFeaturesBuilder()
119                     .unmodifiableFeaturesEnabledForAllUsers(systemDarkFeatures.getEnabled())
120                     .featuresEnabledForAllUsers(siteDarkFeaturesStorage.getEnabledDarkFeatures())
121                     .build();
122         }
123     }
124 
125     @Override
126     public EnabledDarkFeatures getFeaturesEnabledForCurrentUser()
127     {
128         return getFeaturesEnabledForAllUsers();
129     }
130 
131     @Override
132     public Option<EnabledDarkFeatures> getFeaturesEnabledForUser(@Nullable final String username)
133     {
134         return isUserAnonymous(username) || isUserExisting(username) ? Option.some(getFeaturesEnabledForAllUsers()) : Option.<EnabledDarkFeatures>none();
135     }
136 
137     private boolean isUserExisting(@Nullable final String username)
138     {
139         return userManager.resolve(username) != null;
140     }
141 
142     private boolean isUserAnonymous(@Nullable final String username)
143     {
144         return username == null;
145     }
146 
147     private void checkCurrentUserCanManageFeaturesForAllUsers()
148     {
149         if (!canManageFeaturesForAllUsers())
150         {
151             throw new MissingPermissionException("The current user is not allowed to change dark features affecting all users.");
152         }
153     }
154 
155     private void throwUnsupportedPerUserOperationException()
156     {
157         throw new UnsupportedOperationException("The default implementation doesn't support per-user dark features.");
158     }
159 }