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 }