View Javadoc
1   package com.atlassian.sal.api.features;
2   
3   import com.atlassian.sal.api.user.UserKey;
4   
5   import javax.annotation.Nonnull;
6   import javax.annotation.Nullable;
7   import java.util.Optional;
8   
9   /**
10   * <p>Provides a cross-product method for determining whether a dark feature is enabled.</p>
11   *
12   * <p>Implementing products can back these checks with their own internal dark feature management system, but must
13   * follow the enable and disable dark features on startup based on system properties and the contents of an optional
14   * properties file. To avoid clashes with other system properties all features specified as system property must be
15   * prefixed with {@link DarkFeatureManager#ATLASSIAN_DARKFEATURE_PREFIX}. The prefix is removed from the feature key
16   * when it is processed later. Values must be either true or false. The location of the dark features property file can
17   * be overridden with the {@link DarkFeatureManager#DARKFEATURES_PROPERTIES_FILE_PROPERTY} system property.</p>
18   *
19   * <p>See SystemDarkFeatureInitializer in sal-core for an implementation.</p>
20   *
21   * @since 2.10
22   */
23  public interface DarkFeatureManager {
24      /**
25       * Prefix for all dark feature specified as system property.
26       */
27      String ATLASSIAN_DARKFEATURE_PREFIX = "atlassian.darkfeature.";
28  
29      /**
30       * System property for disabling all dark features.
31       */
32      String DISABLE_ALL_DARKFEATURES_PROPERTY = "atlassian.darkfeature.disabled";
33  
34      /**
35       * System property for overriding location of dark features property file.
36       */
37      String DARKFEATURES_PROPERTIES_FILE_PROPERTY = "darkfeatures.properties.file";
38  
39      /**
40       * Default properties file name.
41       */
42      String DARKFEATURES_PROPERTIES_FILE_PROPERTY_DEFAULT = "atlassian-darkfeatures.properties";
43  
44      /**
45       * Checks whether the product contains the given feature for all users, regardless whether the feature can be
46       * changed during runtime or not.
47       *
48       * @param featureKey key of the feature to be checked
49       * @return Optional boolean, <code>true</code> if the feature key is valid and enabled, false otherwise;
50       * Optional.empty() when the featureKey is not know or is invalid as per
51       * {@link ValidFeatureKeyPredicate#isValidFeatureKey(String)}
52       * @see ValidFeatureKeyPredicate
53       */
54      @Nonnull
55      Optional<Boolean> isEnabledForAllUsers(@Nonnull String featureKey);
56  
57      /**
58       * Checks whether the product contains the given feature for all users or for the current user only
59       * (must be called within the context of a request). If the user couldn't be resolved or is anonymous,
60       * only features enabled for all users are considered.
61       *
62       * @param featureKey key of the feature to be checked
63       * @return Optional boolean, <code>true</code> if the feature is valid and enabled, either for all users or the
64       * current user only; <code>false</code> otherwise. Optional.empty() when the featureKey is not know or is invalid
65       * as per {@link ValidFeatureKeyPredicate#isValidFeatureKey(String)}
66       * @see ValidFeatureKeyPredicate
67       */
68      @Nonnull
69      Optional<Boolean> isEnabledForCurrentUser(@Nonnull String featureKey);
70  
71      /**
72       * Checks whether the product contains the given feature for all users or just for the given user. In case the user
73       * is anonymous, only features enabled for all users are considered.
74       *
75       * @param userKey    the key of the user being queried; <code>null</code> represents the anonymous user
76       * @param featureKey key of the feature to be checked
77       * @return Optional boolean, <code>true</code> if the feature key is valid and enabled, either for all users or the
78       * current user only; <code>false</code> otherwise; Optional.empty() when the featureKey is not know or is invalid
79       * as per {@link ValidFeatureKeyPredicate#isValidFeatureKey(String)}
80       * @throws IllegalArgumentException if the user doesn't exist
81       * @see ValidFeatureKeyPredicate
82       */
83      @Nonnull
84      Optional<Boolean> isEnabledForUser(@Nullable UserKey userKey, @Nonnull String featureKey);
85  
86      /**
87       * Checks if a dark feature is enabled for all users, regardless whether the feature can be changed during runtime
88       * or not.
89       *
90       * @param featureKey key of the feature to be checked
91       * @return <code>true</code> if the feature key is valid and enabled, false otherwise
92       * @see ValidFeatureKeyPredicate
93       *
94       * @deprecated use {@link #isEnabledForAllUsers(String)} instead
95       */
96      @Deprecated
97      boolean isFeatureEnabledForAllUsers(String featureKey);
98  
99      /**
100      * Checks if a dark feature is enabled for all users or for the current user only (must be called within the context
101      * of a request). If the user couldn't be resolved or is anonymous, only features enabled for all users are
102      * considered.
103      *
104      * @param featureKey key of the feature to be checked
105      * @return <code>true</code> if the feature is valid and enabled, either for all users or the current user only;
106      * <code>false</code> otherwise.
107      * @see ValidFeatureKeyPredicate
108      *
109      * @deprecated use {@link #isEnabledForCurrentUser(String)} instead
110      */
111     @Deprecated
112     boolean isFeatureEnabledForCurrentUser(String featureKey);
113 
114     /**
115      * Checks if a dark feature is enabled for all users or just for the given user. In case the user is anonymous,
116      * only features enabled for all users are considered.
117      *
118      * @param userKey    the key of the user being queried; <code>null</code> represents the anonymous user
119      * @param featureKey key of the feature to be checked
120      * @return <code>true</code> if the feature key is valid and enabled, either for all users or the current user only;
121      * <code>false</code> otherwise.
122      * @throws IllegalArgumentException if the user doesn't exist
123      * @see ValidFeatureKeyPredicate
124      *
125      * @deprecated use {@link #isEnabledForUser(UserKey, String)} instead
126      */
127     @Deprecated
128     boolean isFeatureEnabledForUser(@Nullable UserKey userKey, String featureKey);
129 
130     /**
131      * Returns true if the current acting user has permission to change dark features for all users. This is a nothrow
132      * method and should return a value instead of throw an exception.
133      *
134      * @return <code>true</code> iff the current acting user has permission to change dark features for all users,
135      * <code>false</code> otherwise
136      */
137     boolean canManageFeaturesForAllUsers();
138 
139     /**
140      * Enable the given dark feature all users. The acting user must have permission to change dark features for all
141      * users.
142      *
143      * @param featureKey key of the feature to be enabled
144      * @throws InvalidFeatureKeyException if the feature key is not valid
145      * @throws MissingPermissionException if the user has not the required permission
146      * @throws IllegalStateException      if the update failed
147      * @see ValidFeatureKeyPredicate
148      * @see #canManageFeaturesForAllUsers()
149      */
150     void enableFeatureForAllUsers(String featureKey);
151 
152     /**
153      * Disable the given dark feature for all users. The acting user must have permission to change dark features for
154      * all users.
155      *
156      * @param featureKey key of the feature to be disabled
157      * @throws InvalidFeatureKeyException if the feature key is not valid
158      * @throws MissingPermissionException if the user has not the required permission
159      * @throws IllegalStateException      if the update failed
160      * @see ValidFeatureKeyPredicate
161      * @see #canManageFeaturesForAllUsers()
162      */
163     void disableFeatureForAllUsers(String featureKey);
164 
165     /**
166      * Enable a dark feature for the current user only. Anonymous users are not supported. <strong>If the feature is
167      * already enabled for all users, the user will still be able to use it.</strong>
168      *
169      * @param featureKey key of the feature to enable
170      * @throws InvalidFeatureKeyException if the feature key is not valid
171      * @throws IllegalStateException      if the current user could not be resolved, is anonymous or the update failed due to
172      *                                    any other reason
173      * @see ValidFeatureKeyPredicate
174      */
175     void enableFeatureForCurrentUser(String featureKey);
176 
177     /**
178      * Enable a dark feature for the given user only. Anonymous users are not supported. <strong>If the feature is
179      * already enabled for all users, the user will still be able to use it.</strong>
180      *
181      * @param userKey    key of the user to enable the feature for; not <code>null</code>
182      * @param featureKey key of the feature to be enabled
183      * @throws IllegalArgumentException   if the user does not exist or is anonymous
184      * @throws InvalidFeatureKeyException if the feature key is not valid
185      * @throws IllegalStateException      if the update failed
186      * @see ValidFeatureKeyPredicate
187      */
188     void enableFeatureForUser(UserKey userKey, String featureKey);
189 
190     /**
191      * Disable a dark feature for the current user only. Anonymous users are not supported. <strong>If the feature is
192      * enabled for all users, the current user will still be able to use it.</strong>
193      *
194      * @param featureKey key of the feature to be disabled
195      * @throws InvalidFeatureKeyException if the feature key is not valid
196      * @throws IllegalStateException      if the current user could not be resolved, is anonymous or the update failed due to
197      *                                    any other reason
198      * @see ValidFeatureKeyPredicate
199      */
200     void disableFeatureForCurrentUser(String featureKey);
201 
202     /**
203      * Disable a dark feature for the given user only. Anonymous users are not supported. <strong>If the feature is
204      * enabled for all users, the user will still be able to use it.</strong>
205      *
206      * @param userKey    key of the user to disable the feature for; not <code>null</code>
207      * @param featureKey key of the feature to be disabled
208      * @throws IllegalArgumentException   if the user does not exist or is anonymous
209      * @throws InvalidFeatureKeyException if the feature key is not valid
210      * @throws IllegalStateException      if the update failed
211      * @see ValidFeatureKeyPredicate
212      */
213     void disableFeatureForUser(UserKey userKey, String featureKey);
214 
215     /**
216      * @return all dark features enabled for all users.
217      */
218     EnabledDarkFeatures getFeaturesEnabledForAllUsers();
219 
220     /**
221      * Return features enabled for the current user (must be called within the context of a request). In case the
222      * current user could not be resolved or is anonymous, all dark features enabled for all users are returned instead.
223      *
224      * @return all dark features applicable for the current user.
225      */
226     EnabledDarkFeatures getFeaturesEnabledForCurrentUser();
227 
228     /**
229      * Return enabled features for a given user. In case the current user is anonymous, all global enabled features are
230      * returned.
231      *
232      * @param userKey key of the user being queried; <code>null</code> represents the anonymous user
233      * @return all dark features applicable for the given user
234      * @throws IllegalArgumentException if the user doesn't exist
235      */
236     EnabledDarkFeatures getFeaturesEnabledForUser(@Nullable UserKey userKey);
237 
238 }