10
10
import java .util .Optional ;
11
11
import java .util .Set ;
12
12
13
+ import us .kbase .auth2 .lib .exceptions .IllegalParameterException ;
14
+
13
15
/** A specification for how a user search should be conducted.
14
16
*
15
17
* If a search prefix or regex is supplied and neither withSearchOnUserName() nor
@@ -24,7 +26,8 @@ public class UserSearchSpec {
24
26
25
27
//TODO ZLATER CODE don't expose regex externally. Not sure how best to do this without duplicating a lot of the class. For now setting regex is default access (package only).
26
28
27
- private final List <String > prefixes ;
29
+ private final List <String > userNamePrefixes ;
30
+ private final List <String > displayPrefixes ;
28
31
private final String regex ;
29
32
private final boolean searchUser ;
30
33
private final boolean searchDisplayName ;
@@ -34,15 +37,19 @@ public class UserSearchSpec {
34
37
private final boolean includeDisabled ;
35
38
36
39
private UserSearchSpec (
37
- final List <String > prefixes ,
40
+ final List <String > userNamePrefixes ,
41
+ final List <String > displayPrefixes ,
38
42
final String regex ,
39
43
final boolean searchUser ,
40
44
final boolean searchDisplayName ,
41
45
final Set <Role > searchRoles ,
42
46
final Set <String > searchCustomRoles ,
43
47
final boolean includeRoot ,
44
48
final boolean includeDisabled ) {
45
- this .prefixes = prefixes == null ? null : Collections .unmodifiableList (prefixes );
49
+ this .userNamePrefixes = userNamePrefixes == null ? null :
50
+ Collections .unmodifiableList (userNamePrefixes );
51
+ this .displayPrefixes = displayPrefixes == null ? null :
52
+ Collections .unmodifiableList (displayPrefixes );
46
53
this .regex = regex ;
47
54
this .searchUser = searchUser ;
48
55
this .searchDisplayName = searchDisplayName ;
@@ -52,13 +59,21 @@ private UserSearchSpec(
52
59
this .includeDisabled = includeDisabled ;
53
60
}
54
61
55
- /** Returns the user and/or display name prefixes for the search, if any.
56
- * The prefixes match the start of the username or the start of any part of the whitespace
62
+ /** Returns the user name prefixes for the search, if any.
63
+ * The prefixes match the start of the user name.
64
+ * @return the search prefix.
65
+ */
66
+ public List <String > getSearchUserNamePrefixes () {
67
+ return userNamePrefixes == null ? Collections .emptyList () : userNamePrefixes ;
68
+ }
69
+
70
+ /** Returns the display name prefixes for the search, if any.
71
+ * The prefixes match the start of any part of the whitespace
57
72
* tokenized display name.
58
73
* @return the search prefix.
59
74
*/
60
- public List <String > getSearchPrefixes () {
61
- return prefixes == null ? Collections .emptyList () : prefixes ;
75
+ public List <String > getSearchDisplayPrefixes () {
76
+ return displayPrefixes == null ? Collections .emptyList () : displayPrefixes ;
62
77
}
63
78
64
79
/** Returns the user and/or display name regex for the search, if any.
@@ -80,35 +95,33 @@ public boolean hasSearchRegex() {
80
95
* @return true if the search prefixes are set.
81
96
*/
82
97
public boolean hasSearchPrefixes () {
83
- return prefixes != null ;
98
+ return displayPrefixes != null ;
84
99
}
85
100
86
- private boolean hasSearchString () {
87
- return prefixes != null || regex != null ;
88
- }
89
-
90
101
/** Returns true if a search should occur on the user's user name.
91
102
*
92
- * True when a) a prefix or regex is provided and b) withSearchOnUserName() was called with a
93
- * true argument or neither withSearchOnUserName() nor withSearchOnDisplayName() were called
94
- * with a true argument.
103
+ * True when
104
+ * a) a prefix with a valid format for a username or regex is provided and
105
+ * b) withSearchOnUserName() was called with a true argument or neither or both of
106
+ * withSearchOnUserName() and withSearchOnDisplayName() were called with a true argument.
95
107
* @return whether the search should occur on the user's user name with the provided prefix or
96
108
* regex.
97
109
*/
98
110
public boolean isUserNameSearch () {
99
- return searchUser || ( hasSearchString ( ) && !searchDisplayName );
111
+ return ( regex != null || userNamePrefixes != null ) && ( searchUser || !searchDisplayName );
100
112
}
101
113
102
114
/** Returns true if a search should occur on the user's tokenized display name.
103
115
*
104
- * True when a) a prefix or regex is provided and b) withSearchOnDisplayName() was called with
105
- * a true argument or neither withSearchOnUserName() nor withSearchOnDisplayName() were
106
- * called with a true argument.
116
+ * True when
117
+ * a) a prefix or regex is provided and
118
+ * b) withSearchOnDisplayName() was called with a true argument or neither or both of
119
+ * withSearchOnUserName() and withSearchOnDisplayName() were called with a true argument.
107
120
* @return whether the search should occur on the users's display name with the provided
108
121
* prefix or regex.
109
122
*/
110
123
public boolean isDisplayNameSearch () {
111
- return searchDisplayName || ( hasSearchString ( ) && !searchUser );
124
+ return ( regex != null || displayPrefixes != null ) && ( searchDisplayName || !searchUser );
112
125
}
113
126
114
127
/** Returns true if a search should occur on the user's roles.
@@ -202,8 +215,8 @@ public static Builder getBuilder() {
202
215
203
216
@ Override
204
217
public int hashCode () {
205
- return Objects .hash (includeDisabled , includeRoot , prefixes , regex ,
206
- searchCustomRoles , searchDisplayName , searchRoles , searchUser );
218
+ return Objects .hash (displayPrefixes , includeDisabled , includeRoot , regex ,
219
+ searchCustomRoles , searchDisplayName , searchRoles , searchUser , userNamePrefixes );
207
220
}
208
221
209
222
@ Override
@@ -218,14 +231,15 @@ public boolean equals(Object obj) {
218
231
return false ;
219
232
}
220
233
UserSearchSpec other = (UserSearchSpec ) obj ;
221
- return includeDisabled == other .includeDisabled
234
+ return Objects .equals (displayPrefixes , other .displayPrefixes )
235
+ && includeDisabled == other .includeDisabled
222
236
&& includeRoot == other .includeRoot
223
- && Objects .equals (prefixes , other .prefixes )
224
237
&& Objects .equals (regex , other .regex )
225
238
&& Objects .equals (searchCustomRoles , other .searchCustomRoles )
226
239
&& searchDisplayName == other .searchDisplayName
227
240
&& Objects .equals (searchRoles , other .searchRoles )
228
- && searchUser == other .searchUser ;
241
+ && searchUser == other .searchUser
242
+ && Objects .equals (userNamePrefixes , other .userNamePrefixes );
229
243
}
230
244
231
245
/** A builder for a UserSearchSpec.
@@ -234,7 +248,7 @@ public boolean equals(Object obj) {
234
248
*/
235
249
public static class Builder {
236
250
237
- private List < String > prefixes = null ;
251
+ private String prefix ;
238
252
private String regex = null ;
239
253
private boolean searchUser = false ;
240
254
private boolean searchDisplayName = false ;
@@ -249,15 +263,16 @@ private Builder() {}
249
263
* The prefix will replace the search regex, if any.
250
264
* The prefix matches the start of the username or the start of any part of the whitespace
251
265
* and hyphen tokenized display name.
252
- * The prefix is always split by whitespace and hyphens, punctuation removed, and
253
- * converted to lower case.
266
+ * The user name prefix is split by whitespace and all illegal characters removed.
267
+ * The display name prefix is split by whitespace and hyphens, punctuation removed,
268
+ * and converted to lower case.
254
269
* Once the prefix or search regex is set in this builder it cannot be removed.
255
270
* @param prefix the prefix.
256
271
* @return this builder.
257
272
*/
258
273
public Builder withSearchPrefix (final String prefix ) {
259
274
checkStringNoCheckedException (prefix , "prefix" );
260
- this .prefixes = DisplayName . getCanonicalDisplayName ( prefix ) ;
275
+ this .prefix = prefix ;
261
276
this .regex = null ;
262
277
return this ;
263
278
}
@@ -273,12 +288,14 @@ public Builder withSearchPrefix(final String prefix) {
273
288
*/
274
289
Builder withSearchRegex (final String regex ) {
275
290
this .regex = checkStringNoCheckedException (regex , "regex" );
276
- this .prefixes = null ;
291
+ this .prefix = null ;
277
292
return this ;
278
293
}
279
294
280
295
/** Specify whether a search on a users's user name should occur.
281
296
* A prefix must be set prior to calling this method.
297
+ * If neither a user nor a display search is set (the default) and a prefix is set, then
298
+ * the search occurs on both fields.
282
299
* @param search whether the search should occur on the user's user name.
283
300
* @return this builder.
284
301
*/
@@ -290,6 +307,8 @@ public Builder withSearchOnUserName(final boolean search) {
290
307
291
308
/** Specify whether a search on a users's display name should occur.
292
309
* A prefix must be set prior to calling this method.
310
+ * If neither a user nor a display search is set (the default) and a prefix is set, then
311
+ * the search occurs on both fields.
293
312
* @param search whether the search should occur on the user's display name.
294
313
* @return this builder.
295
314
*/
@@ -300,7 +319,7 @@ public Builder withSearchOnDisplayName(final boolean search) {
300
319
}
301
320
302
321
private void checkSearchPrefix (final boolean search ) {
303
- if (search && prefixes == null && regex == null ) {
322
+ if (search && prefix == null && regex == null ) {
304
323
throw new IllegalStateException (
305
324
"Must provide a prefix or regex if a name search is to occur" );
306
325
}
@@ -353,10 +372,50 @@ public Builder withIncludeDisabled(final boolean include) {
353
372
354
373
/** Build a UserSearchSpec instance.
355
374
* @return a UserSearchSpec.
375
+ * @throws IllegalParameterException if a prefix is set that, after normalizing, contains
376
+ * no characters for the requested search(es).
356
377
*/
357
- public UserSearchSpec build () {
358
- return new UserSearchSpec (prefixes , regex , searchUser , searchDisplayName , searchRoles ,
359
- searchCustomRoles , includeRoot , includeDisabled );
378
+ public UserSearchSpec build () throws IllegalParameterException {
379
+ List <String > userNamePrefixes = null ;
380
+ List <String > displayPrefixes = null ;
381
+ if (this .prefix != null ) {
382
+ /* UsrSrch DisSrch UsrOK DisOK Throw exception?
383
+ * T T Y implies Y
384
+ * T T No Y No, just go with display search
385
+ * T T No No Display or user exception
386
+ *
387
+ * T F Y implies Y
388
+ * T F No Y User exception
389
+ * T F No No User exception
390
+ *
391
+ * F T Y implies Y
392
+ * F T No Y
393
+ * F T No No Display exception
394
+ *
395
+ * Note that:
396
+ * * If the user search is ok (UsrOK) the display search must be ok since the
397
+ * user search has at least one a-z char.
398
+ * * The first block where UsrSrch and DisSrch are all true is equivalent
399
+ * to a block where they're all false, and so that block is omitted.
400
+ */
401
+ userNamePrefixes = UserName .getCanonicalNames (prefix );
402
+ userNamePrefixes = userNamePrefixes .isEmpty () ? null : userNamePrefixes ;
403
+ displayPrefixes = DisplayName .getCanonicalDisplayName (prefix );
404
+ displayPrefixes = displayPrefixes .isEmpty () ? null : displayPrefixes ;
405
+ if (searchUser && !searchDisplayName && userNamePrefixes == null ) {
406
+ throw new IllegalParameterException (String .format (
407
+ "The search prefix %s contains no valid username prefix "
408
+ + "and a user name search was requested" , this .prefix ));
409
+ }
410
+ if (displayPrefixes == null ) {
411
+ throw new IllegalParameterException (String .format (
412
+ "The search prefix %s contains only punctuation and a "
413
+ + "display name search was requested" , this .prefix ));
414
+ }
415
+ }
416
+ return new UserSearchSpec (userNamePrefixes , displayPrefixes , regex , searchUser ,
417
+ searchDisplayName , searchRoles , searchCustomRoles ,
418
+ includeRoot , includeDisabled );
360
419
}
361
420
}
362
421
}
0 commit comments