View Javadoc

1   package com.atlassian.sal.core.features;
2   
3   import com.atlassian.sal.api.features.DarkFeatureManager;
4   import com.atlassian.sal.api.features.EnabledDarkFeatures;
5   import com.atlassian.sal.api.features.EnabledDarkFeaturesBuilder;
6   import com.atlassian.sal.api.features.MissingPermissionException;
7   import com.atlassian.sal.api.features.SiteDarkFeaturesStorage;
8   import com.atlassian.sal.api.features.ValidFeatureKeyPredicate;
9   import com.atlassian.sal.api.user.UserKey;
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      private final UserManager userManager;
22      private final SiteDarkFeaturesStorage siteDarkFeaturesStorage;
23      private final SystemDarkFeatureInitializer.SystemDarkFeatures systemDarkFeatures;
24  
25      public DefaultDarkFeatureManager(final UserManager userManager, final SiteDarkFeaturesStorage siteDarkFeaturesStorage) {
26          this.userManager = userManager;
27          this.siteDarkFeaturesStorage = siteDarkFeaturesStorage;
28          this.systemDarkFeatures = SystemDarkFeatureInitializer.getSystemStartupDarkFeatures();
29      }
30  
31      @Override
32      public boolean isFeatureEnabledForAllUsers(final String featureKey) {
33          return ValidFeatureKeyPredicate.isValidFeatureKey(featureKey) && getFeaturesEnabledForAllUsers().isFeatureEnabled(featureKey);
34      }
35  
36      @Override
37      public boolean isFeatureEnabledForCurrentUser(final String featureKey) {
38          return isFeatureEnabledForAllUsers(featureKey);
39      }
40  
41      @Override
42      public boolean isFeatureEnabledForUser(@Nullable final UserKey userKey, final String featureKey) {
43          if (isUserAnonymous(userKey) || isUserExisting(userKey)) {
44              return isFeatureEnabledForAllUsers(featureKey);
45          } else {
46              throw new IllegalArgumentException("The user does not exist");
47          }
48      }
49  
50      @Override
51      public boolean canManageFeaturesForAllUsers() {
52          try {
53              final UserKey remoteUserKey = userManager.getRemoteUserKey();
54              return userManager.isSystemAdmin(remoteUserKey);
55          } catch (RuntimeException e) {
56              /**
57               * Applying the principle of least surprise here so the caller wouldn't have to deal with undeclared
58               * runtime exceptions. Determining that a user has the proper permissions is very unlikely to be successful
59               * when an exception is thrown.
60               */
61              return false;
62          }
63      }
64  
65      @Override
66      public void enableFeatureForAllUsers(final String featureKey) {
67          checkFeatureKey(featureKey);
68          checkCurrentUserCanManageFeaturesForAllUsers();
69          siteDarkFeaturesStorage.enable(featureKey);
70      }
71  
72      @Override
73      public void disableFeatureForAllUsers(final String featureKey) {
74          checkFeatureKey(featureKey);
75          checkCurrentUserCanManageFeaturesForAllUsers();
76          siteDarkFeaturesStorage.disable(featureKey);
77      }
78  
79      @Override
80      public void enableFeatureForCurrentUser(final String featureKey) {
81          throwUnsupportedPerUserOperationException();
82      }
83  
84      @Override
85      public void enableFeatureForUser(final UserKey userKey, final String featureKey) {
86          throwUnsupportedPerUserOperationException();
87      }
88  
89      @Override
90      public void disableFeatureForCurrentUser(final String featureKey) {
91          throwUnsupportedPerUserOperationException();
92      }
93  
94      @Override
95      public void disableFeatureForUser(final UserKey userKey, final String featureKey) {
96          throwUnsupportedPerUserOperationException();
97      }
98  
99      public EnabledDarkFeatures getFeaturesEnabledForAllUsers() {
100         if (systemDarkFeatures.isDisableAll()) {
101             return EnabledDarkFeatures.NONE;
102         } else {
103             return new EnabledDarkFeaturesBuilder()
104                     .unmodifiableFeaturesEnabledForAllUsers(systemDarkFeatures.getEnabled())
105                     .featuresEnabledForAllUsers(siteDarkFeaturesStorage.getEnabledDarkFeatures())
106                     .build();
107         }
108     }
109 
110     @Override
111     public EnabledDarkFeatures getFeaturesEnabledForCurrentUser() {
112         return getFeaturesEnabledForAllUsers();
113     }
114 
115     @Override
116     public EnabledDarkFeatures getFeaturesEnabledForUser(@Nullable final UserKey userKey) {
117         if (isUserAnonymous(userKey) || isUserExisting(userKey)) {
118             return getFeaturesEnabledForAllUsers();
119         } else {
120             throw new IllegalArgumentException("The user does not exist");
121         }
122     }
123 
124     private boolean isUserExisting(@Nullable final UserKey userKey) {
125         return (userKey != null) && userManager.getUserProfile(userKey) != null;
126     }
127 
128     private boolean isUserAnonymous(@Nullable final UserKey userKey) {
129         return userKey == null;
130     }
131 
132     private void checkCurrentUserCanManageFeaturesForAllUsers() {
133         if (!canManageFeaturesForAllUsers()) {
134             throw new MissingPermissionException("The current user is not allowed to change dark features affecting all users.");
135         }
136     }
137 
138     private void throwUnsupportedPerUserOperationException() {
139         throw new UnsupportedOperationException("The default implementation doesn't support per-user dark features.");
140     }
141 }