001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3;
018
019import java.security.NoSuchAlgorithmException;
020import java.security.SecureRandom;
021import java.security.Security;
022import java.util.Random;
023import java.util.concurrent.ThreadLocalRandom;
024import java.util.function.Supplier;
025
026import org.apache.commons.lang3.exception.UncheckedException;
027
028/**
029 * Supplements the standard {@link Random} class.
030 * <p>
031 * Use {@link #secure()} to get the singleton instance based on {@link SecureRandom#getInstanceStrong()} which uses an
032 * algorithms/providers specified in the {@code securerandom.strongAlgorithms} {@link Security} property.
033 * </p>
034 * <p>
035 * Use {@link #insecure()} to get the singleton instance based on {@link ThreadLocalRandom#current()}; <b>which is not
036 * cryptographically secure</b>.
037 * </p>
038 * <p>
039 * Starting in version 3.15.0, this class uses {@link SecureRandom#getInstanceStrong()} for static methods.
040 * </p>
041 * <p>
042 * Starting in version 3.16.0, this class uses {@link #secure()} for static methods and adds {@link #insecure()}.
043 * </p>
044 * <p>
045 * Before version 3.15.0, this class used {@link ThreadLocalRandom#current()} for static methods, which is not
046 * cryptographically secure.
047 * </p>
048 * <p>
049 * Please note that the Apache Commons project provides a component dedicated to pseudo-random number generation, namely
050 * <a href="https://commons.apache.org/proper/commons-rng/">Commons RNG</a>, that may be a better choice for
051 * applications with more stringent requirements (performance and/or correctness).
052 * </p>
053 *
054 * @see RandomStringUtils
055 * @since 3.3
056 */
057public class RandomUtils {
058
059    private static RandomUtils INSECURE = new RandomUtils(ThreadLocalRandom::current);
060
061    private static final Supplier<Random> SECURE_SUPPLIER = () -> RandomUtils.SECURE_RANDOM.get();
062
063    private static RandomUtils SECURE = new RandomUtils(SECURE_SUPPLIER);
064
065    private static final ThreadLocal<SecureRandom> SECURE_RANDOM = ThreadLocal.withInitial(() -> {
066        try {
067            return SecureRandom.getInstanceStrong();
068        } catch (final NoSuchAlgorithmException e) {
069            throw new UncheckedException(e);
070        }
071    });
072
073    /**
074     * Gets the singleton instance based on {@link ThreadLocalRandom#current()}; <b>which is not cryptographically
075     * secure</b>; use {@link #secure()} to use an algorithms/providers specified in the
076     * {@code securerandom.strongAlgorithms} {@link Security} property.
077     * </p>
078     * <p>
079     * The method {@link ThreadLocalRandom#current()} is called on-demand.
080     * </p>
081     *
082     * @return the singleton instance based on {@link ThreadLocalRandom#current()}.
083     * @see ThreadLocalRandom#current()
084     * @see #secure()
085     * @since 3.16.0
086     */
087    static RandomUtils insecure() {
088        return INSECURE;
089    }
090
091    /**
092     * Generates a random boolean value.
093     *
094     * @return the random boolean
095     * @since 3.5
096     */
097    public static boolean nextBoolean() {
098        return secure().randomBoolean();
099    }
100
101    /**
102     * Generates an array of random bytes.
103     *
104     * @param count the size of the returned array
105     * @return the random byte array
106     * @throws IllegalArgumentException if {@code count} is negative
107     */
108    public static byte[] nextBytes(final int count) {
109        return secure().randomBytes(count);
110    }
111
112    /**
113     * Generates a random double between 0 (inclusive) and Double.MAX_VALUE (exclusive).
114     *
115     * @return the random double
116     * @see #nextDouble(double, double)
117     * @since 3.5
118     */
119    public static double nextDouble() {
120        return secure().randomDouble();
121    }
122
123    /**
124     * Generates a random double within the specified range.
125     *
126     * @param startInclusive the smallest value that can be returned, must be non-negative
127     * @param endExclusive   the upper bound (not included)
128     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
129     *                                  negative
130     * @return the random double
131     */
132    public static double nextDouble(final double startInclusive, final double endExclusive) {
133        return secure().randomDouble(startInclusive, endExclusive);
134    }
135
136    /**
137     * Generates a random float between 0 (inclusive) and Float.MAX_VALUE (exclusive).
138     *
139     * @return the random float
140     * @see #nextFloat(float, float)
141     * @since 3.5
142     */
143    public static float nextFloat() {
144        return secure().randomFloat();
145    }
146
147    /**
148     * Generates a random float within the specified range.
149     *
150     * @param startInclusive the smallest value that can be returned, must be non-negative
151     * @param endExclusive   the upper bound (not included)
152     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
153     *                                  negative
154     * @return the random float
155     */
156    public static float nextFloat(final float startInclusive, final float endExclusive) {
157        return secure().randomFloat(startInclusive, endExclusive);
158    }
159
160    /**
161     * Generates a random int between 0 (inclusive) and Integer.MAX_VALUE (exclusive).
162     *
163     * @return the random integer
164     * @see #nextInt(int, int)
165     * @since 3.5
166     */
167    public static int nextInt() {
168        return secure().randomInt();
169    }
170
171    /**
172     * Generates a random integer within the specified range.
173     *
174     * @param startInclusive the smallest value that can be returned, must be non-negative
175     * @param endExclusive   the upper bound (not included)
176     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
177     *                                  negative
178     * @return the random integer
179     */
180    public static int nextInt(final int startInclusive, final int endExclusive) {
181        return secure().randomInt(startInclusive, endExclusive);
182    }
183
184    /**
185     * Generates a random long between 0 (inclusive) and Long.MAX_VALUE (exclusive).
186     *
187     * @return the random long
188     * @see #nextLong(long, long)
189     * @since 3.5
190     */
191    public static long nextLong() {
192        return secure().randomLong();
193    }
194
195    /**
196     * Generates a {@code long} value between 0 (inclusive) and the specified value (exclusive).
197     *
198     * @param n Bound on the random number to be returned. Must be positive.
199     * @return a random {@code long} value between 0 (inclusive) and {@code n} (exclusive).
200     */
201    private static long nextLong(final long n) {
202        return secure().randomLong(n);
203    }
204
205    /**
206     * Generates a random long within the specified range.
207     *
208     * @param startInclusive the smallest value that can be returned, must be non-negative
209     * @param endExclusive   the upper bound (not included)
210     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
211     *                                  negative
212     * @return the random long
213     */
214    public static long nextLong(final long startInclusive, final long endExclusive) {
215        return secure().randomLong(startInclusive, endExclusive);
216    }
217
218    /**
219     * Gets the singleton instance based on {@link SecureRandom#getInstanceStrong()} which uses an algorithms/providers
220     * specified in the {@code securerandom.strongAlgorithms} {@link Security} property.
221     * <p>
222     * The method {@link SecureRandom#getInstanceStrong()} is called on-demand.
223     * </p>
224     *
225     * @return the singleton instance based on {@link SecureRandom#getInstanceStrong()}.
226     * @see SecureRandom#getInstanceStrong()
227     * @since 3.16.0
228     */
229    public static RandomUtils secure() {
230        return SECURE;
231    }
232
233    static SecureRandom secureRandom() {
234        return SECURE_RANDOM.get();
235    }
236
237    private final Supplier<Random> random;
238
239    /**
240     * {@link RandomUtils} instances should NOT be constructed in standard programming. Instead, the class should be
241     * used as {@code RandomUtils.nextBytes(5);}.
242     * <p>
243     * This constructor is public to permit tools that require a JavaBean instance to operate.
244     * </p>
245     *
246     * @deprecated TODO Make private in 4.0.
247     */
248    @Deprecated
249    public RandomUtils() {
250        this(SECURE_SUPPLIER);
251    }
252
253    private RandomUtils(final Supplier<Random> random) {
254        this.random = random;
255    }
256
257    Random random() {
258        return random.get();
259    }
260
261    /**
262     * Generates a random boolean value.
263     *
264     * @return the random boolean
265     * @since 3.16.0
266     */
267    public boolean randomBoolean() {
268        return random().nextBoolean();
269    }
270
271    /**
272     * Generates an array of random bytes.
273     *
274     * @param count the size of the returned array
275     * @return the random byte array
276     * @throws IllegalArgumentException if {@code count} is negative
277     * @since 3.16.0
278     */
279    public byte[] randomBytes(final int count) {
280        Validate.isTrue(count >= 0, "Count cannot be negative.");
281        final byte[] result = new byte[count];
282        random().nextBytes(result);
283        return result;
284    }
285
286    /**
287     * Generates a random double between 0 (inclusive) and Double.MAX_VALUE (exclusive).
288     *
289     * @return the random double
290     * @see #nextDouble(double, double)
291     * @since 3.16.0
292     */
293    public double randomDouble() {
294        return nextDouble(0, Double.MAX_VALUE);
295    }
296
297    /**
298     * Generates a random double within the specified range.
299     *
300     * @param startInclusive the smallest value that can be returned, must be non-negative
301     * @param endExclusive   the upper bound (not included)
302     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
303     *                                  negative
304     * @return the random double
305     * @since 3.16.0
306     */
307    public double randomDouble(final double startInclusive, final double endExclusive) {
308        Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
309        Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
310        if (startInclusive == endExclusive) {
311            return startInclusive;
312        }
313        return startInclusive + (endExclusive - startInclusive) * random().nextDouble();
314    }
315
316    /**
317     * Generates a random float between 0 (inclusive) and Float.MAX_VALUE (exclusive).
318     *
319     * @return the random float
320     * @see #nextFloat(float, float)
321     * @since 3.16.0
322     */
323    public float randomFloat() {
324        return nextFloat(0, Float.MAX_VALUE);
325    }
326
327    /**
328     * Generates a random float within the specified range.
329     *
330     * @param startInclusive the smallest value that can be returned, must be non-negative
331     * @param endExclusive   the upper bound (not included)
332     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
333     *                                  negative
334     * @return the random float
335     */
336    public float randomFloat(final float startInclusive, final float endExclusive) {
337        Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
338        Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
339        if (startInclusive == endExclusive) {
340            return startInclusive;
341        }
342        return startInclusive + (endExclusive - startInclusive) * random().nextFloat();
343    }
344
345    /**
346     * Generates a random int between 0 (inclusive) and Integer.MAX_VALUE (exclusive).
347     *
348     * @return the random integer
349     * @see #nextInt(int, int)
350     * @since 3.16.0
351     */
352    public int randomInt() {
353        return nextInt(0, Integer.MAX_VALUE);
354    }
355
356    /**
357     * Generates a random integer within the specified range.
358     *
359     * @param startInclusive the smallest value that can be returned, must be non-negative
360     * @param endExclusive   the upper bound (not included)
361     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
362     *                                  negative
363     * @return the random integer
364     * @since 3.16.0
365     */
366    public int randomInt(final int startInclusive, final int endExclusive) {
367        Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
368        Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
369        if (startInclusive == endExclusive) {
370            return startInclusive;
371        }
372        return startInclusive + random().nextInt(endExclusive - startInclusive);
373    }
374
375    /**
376     * Generates a random long between 0 (inclusive) and Long.MAX_VALUE (exclusive).
377     *
378     * @return the random long
379     * @see #nextLong(long, long)
380     * @since 3.16.0
381     */
382    public long randomLong() {
383        return nextLong(Long.MAX_VALUE);
384    }
385
386    /**
387     * Generates a {@code long} value between 0 (inclusive) and the specified value (exclusive).
388     *
389     * @param n Bound on the random number to be returned. Must be positive.
390     * @return a random {@code long} value between 0 (inclusive) and {@code n} (exclusive).
391     */
392    private long randomLong(final long n) {
393        // Extracted from o.a.c.rng.core.BaseProvider.nextLong(long)
394        long bits;
395        long val;
396        do {
397            bits = random().nextLong() >>> 1;
398            val = bits % n;
399        } while (bits - val + n - 1 < 0);
400        return val;
401    }
402
403    /**
404     * Generates a random long within the specified range.
405     *
406     * @param startInclusive the smallest value that can be returned, must be non-negative
407     * @param endExclusive   the upper bound (not included)
408     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
409     *                                  negative
410     * @return the random long
411     * @since 3.16.0
412     */
413    public long randomLong(final long startInclusive, final long endExclusive) {
414        Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
415        Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
416        if (startInclusive == endExclusive) {
417            return startInclusive;
418        }
419        return startInclusive + nextLong(endExclusive - startInclusive);
420    }
421
422    @Override
423    public String toString() {
424        return "RandomUtils [random=" + random() + "]";
425    }
426
427}