1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.util;
18 
19 import android.annotation.IntRange;
20 import android.annotation.NonNull;
21 import android.text.TextUtils;
22 
23 import java.util.Collection;
24 
25 /**
26  * Simple static methods to be called at the start of your own methods to verify
27  * correct arguments and state.
28  */
29 public class Preconditions {
30 
checkArgument(boolean expression)31     public static void checkArgument(boolean expression) {
32         if (!expression) {
33             throw new IllegalArgumentException();
34         }
35     }
36 
37     /**
38      * Ensures that an expression checking an argument is true.
39      *
40      * @param expression the expression to check
41      * @param errorMessage the exception message to use if the check fails; will
42      *     be converted to a string using {@link String#valueOf(Object)}
43      * @throws IllegalArgumentException if {@code expression} is false
44      */
checkArgument(boolean expression, final Object errorMessage)45     public static void checkArgument(boolean expression, final Object errorMessage) {
46         if (!expression) {
47             throw new IllegalArgumentException(String.valueOf(errorMessage));
48         }
49     }
50 
51     /**
52      * Ensures that an expression checking an argument is true.
53      *
54      * @param expression the expression to check
55      * @param messageTemplate a printf-style message template to use if the check fails; will
56      *     be converted to a string using {@link String#format(String, Object...)}
57      * @param messageArgs arguments for {@code messageTemplate}
58      * @throws IllegalArgumentException if {@code expression} is false
59      */
checkArgument(boolean expression, final String messageTemplate, final Object... messageArgs)60     public static void checkArgument(boolean expression,
61             final String messageTemplate,
62             final Object... messageArgs) {
63         if (!expression) {
64             throw new IllegalArgumentException(String.format(messageTemplate, messageArgs));
65         }
66     }
67 
68     /**
69      * Ensures that an string reference passed as a parameter to the calling
70      * method is not empty.
71      *
72      * @param string an string reference
73      * @return the string reference that was validated
74      * @throws IllegalArgumentException if {@code string} is empty
75      */
checkStringNotEmpty(final T string)76     public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string) {
77         if (TextUtils.isEmpty(string)) {
78             throw new IllegalArgumentException();
79         }
80         return string;
81     }
82 
83     /**
84      * Ensures that an string reference passed as a parameter to the calling
85      * method is not empty.
86      *
87      * @param string an string reference
88      * @param errorMessage the exception message to use if the check fails; will
89      *     be converted to a string using {@link String#valueOf(Object)}
90      * @return the string reference that was validated
91      * @throws IllegalArgumentException if {@code string} is empty
92      */
checkStringNotEmpty(final T string, final Object errorMessage)93     public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string,
94             final Object errorMessage) {
95         if (TextUtils.isEmpty(string)) {
96             throw new IllegalArgumentException(String.valueOf(errorMessage));
97         }
98         return string;
99     }
100 
101     /**
102      * Ensures that an object reference passed as a parameter to the calling
103      * method is not null.
104      *
105      * @param reference an object reference
106      * @return the non-null reference that was validated
107      * @throws NullPointerException if {@code reference} is null
108      */
checkNotNull(final T reference)109     public static @NonNull <T> T checkNotNull(final T reference) {
110         if (reference == null) {
111             throw new NullPointerException();
112         }
113         return reference;
114     }
115 
116     /**
117      * Ensures that an object reference passed as a parameter to the calling
118      * method is not null.
119      *
120      * @param reference an object reference
121      * @param errorMessage the exception message to use if the check fails; will
122      *     be converted to a string using {@link String#valueOf(Object)}
123      * @return the non-null reference that was validated
124      * @throws NullPointerException if {@code reference} is null
125      */
checkNotNull(final T reference, final Object errorMessage)126     public static @NonNull <T> T checkNotNull(final T reference, final Object errorMessage) {
127         if (reference == null) {
128             throw new NullPointerException(String.valueOf(errorMessage));
129         }
130         return reference;
131     }
132 
133     /**
134      * Ensures that an object reference passed as a parameter to the calling
135      * method is not null.
136      *
137      * @param reference an object reference
138      * @param messageTemplate a printf-style message template to use if the check fails; will
139      *     be converted to a string using {@link String#format(String, Object...)}
140      * @param messageArgs arguments for {@code messageTemplate}
141      * @return the non-null reference that was validated
142      * @throws NullPointerException if {@code reference} is null
143      */
checkNotNull(final T reference, final String messageTemplate, final Object... messageArgs)144     public static @NonNull <T> T checkNotNull(final T reference,
145             final String messageTemplate,
146             final Object... messageArgs) {
147         if (reference == null) {
148             throw new NullPointerException(String.format(messageTemplate, messageArgs));
149         }
150         return reference;
151     }
152 
153     /**
154      * Ensures the truth of an expression involving the state of the calling
155      * instance, but not involving any parameters to the calling method.
156      *
157      * @param expression a boolean expression
158      * @param message exception message
159      * @throws IllegalStateException if {@code expression} is false
160      */
checkState(final boolean expression, String message)161     public static void checkState(final boolean expression, String message) {
162         if (!expression) {
163             throw new IllegalStateException(message);
164         }
165     }
166 
167     /**
168      * Ensures the truth of an expression involving the state of the calling
169      * instance, but not involving any parameters to the calling method.
170      *
171      * @param expression a boolean expression
172      * @throws IllegalStateException if {@code expression} is false
173      */
checkState(final boolean expression)174     public static void checkState(final boolean expression) {
175         checkState(expression, null);
176     }
177 
178     /**
179      * Check the requested flags, throwing if any requested flags are outside
180      * the allowed set.
181      *
182      * @return the validated requested flags.
183      */
checkFlagsArgument(final int requestedFlags, final int allowedFlags)184     public static int checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
185         if ((requestedFlags & allowedFlags) != requestedFlags) {
186             throw new IllegalArgumentException("Requested flags 0x"
187                     + Integer.toHexString(requestedFlags) + ", but only 0x"
188                     + Integer.toHexString(allowedFlags) + " are allowed");
189         }
190 
191         return requestedFlags;
192     }
193 
194     /**
195      * Ensures that that the argument numeric value is non-negative.
196      *
197      * @param value a numeric int value
198      * @param errorMessage the exception message to use if the check fails
199      * @return the validated numeric value
200      * @throws IllegalArgumentException if {@code value} was negative
201      */
checkArgumentNonnegative(final int value, final String errorMessage)202     public static @IntRange(from = 0) int checkArgumentNonnegative(final int value,
203             final String errorMessage) {
204         if (value < 0) {
205             throw new IllegalArgumentException(errorMessage);
206         }
207 
208         return value;
209     }
210 
211     /**
212      * Ensures that that the argument numeric value is non-negative.
213      *
214      * @param value a numeric int value
215      *
216      * @return the validated numeric value
217      * @throws IllegalArgumentException if {@code value} was negative
218      */
checkArgumentNonnegative(final int value)219     public static @IntRange(from = 0) int checkArgumentNonnegative(final int value) {
220         if (value < 0) {
221             throw new IllegalArgumentException();
222         }
223 
224         return value;
225     }
226 
227     /**
228      * Ensures that that the argument numeric value is non-negative.
229      *
230      * @param value a numeric long value
231      * @return the validated numeric value
232      * @throws IllegalArgumentException if {@code value} was negative
233      */
checkArgumentNonnegative(final long value)234     public static long checkArgumentNonnegative(final long value) {
235         if (value < 0) {
236             throw new IllegalArgumentException();
237         }
238 
239         return value;
240     }
241 
242     /**
243      * Ensures that that the argument numeric value is non-negative.
244      *
245      * @param value a numeric long value
246      * @param errorMessage the exception message to use if the check fails
247      * @return the validated numeric value
248      * @throws IllegalArgumentException if {@code value} was negative
249      */
checkArgumentNonnegative(final long value, final String errorMessage)250     public static long checkArgumentNonnegative(final long value, final String errorMessage) {
251         if (value < 0) {
252             throw new IllegalArgumentException(errorMessage);
253         }
254 
255         return value;
256     }
257 
258     /**
259      * Ensures that that the argument numeric value is positive.
260      *
261      * @param value a numeric int value
262      * @param errorMessage the exception message to use if the check fails
263      * @return the validated numeric value
264      * @throws IllegalArgumentException if {@code value} was not positive
265      */
checkArgumentPositive(final int value, final String errorMessage)266     public static int checkArgumentPositive(final int value, final String errorMessage) {
267         if (value <= 0) {
268             throw new IllegalArgumentException(errorMessage);
269         }
270 
271         return value;
272     }
273 
274     /**
275      * Ensures that the argument floating point value is a finite number.
276      *
277      * <p>A finite number is defined to be both representable (that is, not NaN) and
278      * not infinite (that is neither positive or negative infinity).</p>
279      *
280      * @param value a floating point value
281      * @param valueName the name of the argument to use if the check fails
282      *
283      * @return the validated floating point value
284      *
285      * @throws IllegalArgumentException if {@code value} was not finite
286      */
checkArgumentFinite(final float value, final String valueName)287     public static float checkArgumentFinite(final float value, final String valueName) {
288         if (Float.isNaN(value)) {
289             throw new IllegalArgumentException(valueName + " must not be NaN");
290         } else if (Float.isInfinite(value)) {
291             throw new IllegalArgumentException(valueName + " must not be infinite");
292         }
293 
294         return value;
295     }
296 
297     /**
298      * Ensures that the argument floating point value is within the inclusive range.
299      *
300      * <p>While this can be used to range check against +/- infinity, note that all NaN numbers
301      * will always be out of range.</p>
302      *
303      * @param value a floating point value
304      * @param lower the lower endpoint of the inclusive range
305      * @param upper the upper endpoint of the inclusive range
306      * @param valueName the name of the argument to use if the check fails
307      *
308      * @return the validated floating point value
309      *
310      * @throws IllegalArgumentException if {@code value} was not within the range
311      */
checkArgumentInRange(float value, float lower, float upper, String valueName)312     public static float checkArgumentInRange(float value, float lower, float upper,
313             String valueName) {
314         if (Float.isNaN(value)) {
315             throw new IllegalArgumentException(valueName + " must not be NaN");
316         } else if (value < lower) {
317             throw new IllegalArgumentException(
318                     String.format(
319                             "%s is out of range of [%f, %f] (too low)", valueName, lower, upper));
320         } else if (value > upper) {
321             throw new IllegalArgumentException(
322                     String.format(
323                             "%s is out of range of [%f, %f] (too high)", valueName, lower, upper));
324         }
325 
326         return value;
327     }
328 
329     /**
330      * Ensures that the argument int value is within the inclusive range.
331      *
332      * @param value a int value
333      * @param lower the lower endpoint of the inclusive range
334      * @param upper the upper endpoint of the inclusive range
335      * @param valueName the name of the argument to use if the check fails
336      *
337      * @return the validated int value
338      *
339      * @throws IllegalArgumentException if {@code value} was not within the range
340      */
checkArgumentInRange(int value, int lower, int upper, String valueName)341     public static int checkArgumentInRange(int value, int lower, int upper,
342             String valueName) {
343         if (value < lower) {
344             throw new IllegalArgumentException(
345                     String.format(
346                             "%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
347         } else if (value > upper) {
348             throw new IllegalArgumentException(
349                     String.format(
350                             "%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
351         }
352 
353         return value;
354     }
355 
356     /**
357      * Ensures that the argument long value is within the inclusive range.
358      *
359      * @param value a long value
360      * @param lower the lower endpoint of the inclusive range
361      * @param upper the upper endpoint of the inclusive range
362      * @param valueName the name of the argument to use if the check fails
363      *
364      * @return the validated long value
365      *
366      * @throws IllegalArgumentException if {@code value} was not within the range
367      */
checkArgumentInRange(long value, long lower, long upper, String valueName)368     public static long checkArgumentInRange(long value, long lower, long upper,
369             String valueName) {
370         if (value < lower) {
371             throw new IllegalArgumentException(
372                     String.format(
373                             "%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
374         } else if (value > upper) {
375             throw new IllegalArgumentException(
376                     String.format(
377                             "%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
378         }
379 
380         return value;
381     }
382 
383     /**
384      * Ensures that the array is not {@code null}, and none of its elements are {@code null}.
385      *
386      * @param value an array of boxed objects
387      * @param valueName the name of the argument to use if the check fails
388      *
389      * @return the validated array
390      *
391      * @throws NullPointerException if the {@code value} or any of its elements were {@code null}
392      */
checkArrayElementsNotNull(final T[] value, final String valueName)393     public static <T> T[] checkArrayElementsNotNull(final T[] value, final String valueName) {
394         if (value == null) {
395             throw new NullPointerException(valueName + " must not be null");
396         }
397 
398         for (int i = 0; i < value.length; ++i) {
399             if (value[i] == null) {
400                 throw new NullPointerException(
401                         String.format("%s[%d] must not be null", valueName, i));
402             }
403         }
404 
405         return value;
406     }
407 
408     /**
409      * Ensures that the {@link Collection} is not {@code null}, and none of its elements are
410      * {@code null}.
411      *
412      * @param value a {@link Collection} of boxed objects
413      * @param valueName the name of the argument to use if the check fails
414      *
415      * @return the validated {@link Collection}
416      *
417      * @throws NullPointerException if the {@code value} or any of its elements were {@code null}
418      */
checkCollectionElementsNotNull( final C value, final String valueName)419     public static @NonNull <C extends Collection<T>, T> C checkCollectionElementsNotNull(
420             final C value, final String valueName) {
421         if (value == null) {
422             throw new NullPointerException(valueName + " must not be null");
423         }
424 
425         long ctr = 0;
426         for (T elem : value) {
427             if (elem == null) {
428                 throw new NullPointerException(
429                         String.format("%s[%d] must not be null", valueName, ctr));
430             }
431             ++ctr;
432         }
433 
434         return value;
435     }
436 
437     /**
438      * Ensures that the {@link Collection} is not {@code null}, and contains at least one element.
439      *
440      * @param value a {@link Collection} of boxed elements.
441      * @param valueName the name of the argument to use if the check fails.
442 
443      * @return the validated {@link Collection}
444      *
445      * @throws NullPointerException if the {@code value} was {@code null}
446      * @throws IllegalArgumentException if the {@code value} was empty
447      */
checkCollectionNotEmpty(final Collection<T> value, final String valueName)448     public static <T> Collection<T> checkCollectionNotEmpty(final Collection<T> value,
449             final String valueName) {
450         if (value == null) {
451             throw new NullPointerException(valueName + " must not be null");
452         }
453         if (value.isEmpty()) {
454             throw new IllegalArgumentException(valueName + " is empty");
455         }
456         return value;
457     }
458 
459     /**
460      * Ensures that all elements in the argument floating point array are within the inclusive range
461      *
462      * <p>While this can be used to range check against +/- infinity, note that all NaN numbers
463      * will always be out of range.</p>
464      *
465      * @param value a floating point array of values
466      * @param lower the lower endpoint of the inclusive range
467      * @param upper the upper endpoint of the inclusive range
468      * @param valueName the name of the argument to use if the check fails
469      *
470      * @return the validated floating point value
471      *
472      * @throws IllegalArgumentException if any of the elements in {@code value} were out of range
473      * @throws NullPointerException if the {@code value} was {@code null}
474      */
checkArrayElementsInRange(float[] value, float lower, float upper, String valueName)475     public static float[] checkArrayElementsInRange(float[] value, float lower, float upper,
476             String valueName) {
477         checkNotNull(value, valueName + " must not be null");
478 
479         for (int i = 0; i < value.length; ++i) {
480             float v = value[i];
481 
482             if (Float.isNaN(v)) {
483                 throw new IllegalArgumentException(valueName + "[" + i + "] must not be NaN");
484             } else if (v < lower) {
485                 throw new IllegalArgumentException(
486                         String.format("%s[%d] is out of range of [%f, %f] (too low)",
487                                 valueName, i, lower, upper));
488             } else if (v > upper) {
489                 throw new IllegalArgumentException(
490                         String.format("%s[%d] is out of range of [%f, %f] (too high)",
491                                 valueName, i, lower, upper));
492             }
493         }
494 
495         return value;
496     }
497 
498     /**
499      * Ensures that all elements in the argument integer array are within the inclusive range
500      *
501      * @param value an integer array of values
502      * @param lower the lower endpoint of the inclusive range
503      * @param upper the upper endpoint of the inclusive range
504      * @param valueName the name of the argument to use if the check fails
505      *
506      * @return the validated integer array
507      *
508      * @throws IllegalArgumentException if any of the elements in {@code value} were out of range
509      * @throws NullPointerException if the {@code value} was {@code null}
510      */
checkArrayElementsInRange(int[] value, int lower, int upper, String valueName)511     public static int[] checkArrayElementsInRange(int[] value, int lower, int upper,
512             String valueName) {
513         checkNotNull(value, valueName + " must not be null");
514 
515         for (int i = 0; i < value.length; ++i) {
516             int v = value[i];
517 
518             if (v < lower) {
519                 throw new IllegalArgumentException(
520                         String.format("%s[%d] is out of range of [%d, %d] (too low)",
521                                 valueName, i, lower, upper));
522             } else if (v > upper) {
523                 throw new IllegalArgumentException(
524                         String.format("%s[%d] is out of range of [%d, %d] (too high)",
525                                 valueName, i, lower, upper));
526             }
527         }
528 
529         return value;
530     }
531 }
532