1 /*
2  * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package java.util.random;
27 
28 import java.lang.reflect.Constructor;
29 import java.math.BigInteger;
30 import java.security.AccessController;
31 import java.security.PrivilegedActionException;
32 import java.security.PrivilegedExceptionAction;
33 import java.util.Objects;
34 import java.util.function.Function;
35 import java.util.Map;
36 import java.util.function.Supplier;
37 import java.util.random.RandomGenerator.ArbitrarilyJumpableGenerator;
38 import java.util.random.RandomGenerator.JumpableGenerator;
39 import java.util.random.RandomGenerator.LeapableGenerator;
40 import java.util.random.RandomGenerator.SplittableGenerator;
41 import java.util.random.RandomGenerator.StreamableGenerator;
42 import java.util.ServiceLoader;
43 import java.util.ServiceLoader.Provider;
44 import java.util.stream.Collectors;
45 import java.util.stream.Stream;
46 import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
47 import jdk.random.L128X1024MixRandom;
48 import jdk.random.L128X128MixRandom;
49 import jdk.random.L128X256MixRandom;
50 import jdk.random.L32X64MixRandom;
51 import jdk.random.L64X1024MixRandom;
52 import jdk.random.L64X128MixRandom;
53 import jdk.random.L64X128StarStarRandom;
54 import jdk.random.L64X256MixRandom;
55 import jdk.random.Xoroshiro128PlusPlus;
56 import jdk.random.Xoshiro256PlusPlus;
57 
58 /**
59  * This is a factory class for generating multiple random number generators
60  * of a specific <a href="package-summary.html#algorithms">algorithm</a>.
61  * {@link RandomGeneratorFactory} also provides
62  * methods for selecting random number generator algorithms.
63  *
64  * A specific {@link RandomGeneratorFactory} can be located by using the
65  * {@link RandomGeneratorFactory#of(String)} method, where the argument string
66  * is the name of the <a href="package-summary.html#algorithms">algorithm</a>
67  * required. The method
68  * {@link RandomGeneratorFactory#all()} produces a non-empty {@link Stream} of all available
69  * {@link RandomGeneratorFactory RandomGeneratorFactorys} that can be searched
70  * to locate a {@link RandomGeneratorFactory} suitable to the task.
71  *
72  * There are three methods for constructing a RandomGenerator instance,
73  * depending on the type of initial seed required.
74  * {@link RandomGeneratorFactory#create(long)} is used for long
75  * seed construction,
76  * {@link RandomGeneratorFactory#create(byte[])} is used for byte[]
77  * seed construction, and
78  * {@link RandomGeneratorFactory#create()} is used for random seed
79  * construction. Example;
80  *
81  * <pre>{@code
82  *    RandomGeneratorFactory<RandomGenerator> factory = RandomGeneratorFactory.of("Random");
83  *
84  *     for (int i = 0; i < 10; i++) {
85  *         new Thread(() -> {
86  *             RandomGenerator random = factory.create(100L);
87  *             System.out.println(random.nextDouble());
88  *         }).start();
89  *     }
90  * }</pre>
91  *
92  * RandomGeneratorFactory also provides methods describing the attributes (or properties)
93  * of a generator and can be used to select random number generator
94  * <a href="package-summary.html#algorithms">algorithms</a>.
95  * These methods are typically used in
96  * conjunction with {@link RandomGeneratorFactory#all()}. In this example, the code
97  * locates the {@link RandomGeneratorFactory} that produces
98  * {@link RandomGenerator RandomGenerators}
99  * with the highest number of state bits.
100  *
101  * <pre>{@code
102  *     RandomGeneratorFactory<RandomGenerator> best = RandomGeneratorFactory.all()
103  *         .sorted(Comparator.comparingInt(RandomGenerator::stateBits).reversed())
104  *         .findFirst()
105  *         .orElse(RandomGeneratorFactory.of("Random"));
106  *     System.out.println(best.name() + " in " + best.group() + " was selected");
107  *
108  *     RandomGenerator rng = best.create();
109  *     System.out.println(rng.nextLong());
110  * }</pre>
111  *
112  * @since 17
113  *
114  * @see java.util.random
115  *
116  */
117 public final class RandomGeneratorFactory<T extends RandomGenerator> {
118     /**
119      * Instance provider class of random number algorithm.
120      */
121     private final Provider<? extends RandomGenerator> provider;
122 
123     /**
124      * Provider RandomGeneratorProperties annotation.
125      */
126     private volatile RandomGeneratorProperties properties;
127 
128     /**
129      * Default provider constructor.
130      */
131     private volatile Constructor<T> ctor;
132 
133     /**
134      * Provider constructor with long seed.
135      */
136     private Constructor<T> ctorLong;
137 
138     /**
139      * Provider constructor with byte[] seed.
140      */
141     private Constructor<T> ctorBytes;
142 
143 
144     private static class FactoryMapHolder {
145         static final Map<String, Provider<? extends RandomGenerator>> FACTORY_MAP = createFactoryMap();
146 
147         /**
148          * Returns the factory map, lazily constructing map on first use.
149          *
150          * @return Map of RandomGeneratorFactory classes.
151          */
createFactoryMap()152         private static Map<String, Provider<? extends RandomGenerator>> createFactoryMap() {
153             // Android-changed: don't use SPI, list all available algorithms.
154             /*
155             return ServiceLoader
156                 .load(RandomGenerator.class)
157                 .stream()
158                 .filter(p -> !p.type().isInterface())
159                 .collect(Collectors.toMap(p -> p.type().getSimpleName(), Function.identity()));
160             */
161             return Map.ofEntries(
162                     entryFor(L32X64MixRandom.class, L32X64MixRandom::new),
163                     entryFor(L64X128MixRandom.class, L64X128MixRandom::new),
164                     entryFor(L64X128StarStarRandom.class, L64X128StarStarRandom::new),
165                     entryFor(L64X256MixRandom.class, L64X256MixRandom::new),
166                     entryFor(L64X1024MixRandom.class, L64X1024MixRandom::new),
167                     entryFor(L128X128MixRandom.class, L128X128MixRandom::new),
168                     entryFor(L128X256MixRandom.class, L128X256MixRandom::new),
169                     entryFor(L128X1024MixRandom.class, L128X1024MixRandom::new),
170                     entryFor(Xoroshiro128PlusPlus.class, Xoroshiro128PlusPlus::new),
171                     entryFor(Xoshiro256PlusPlus.class, Xoshiro256PlusPlus::new));
172         }
173 
174         // BEGIN Android-added: method to create Map.Entry<String, Provider> for a RandomGenerator.
entryFor( Class<T> clazz, Supplier<T> supplier)175         private static <T extends RandomGenerator> Map.Entry<String, Provider<T>> entryFor(
176                 Class<T> clazz, Supplier<T> supplier) {
177             return Map.entry(clazz.getSimpleName(), new Provider<>() {
178                 @Override
179                 public Class<? extends T> type() {
180                     return clazz;
181                 }
182 
183                 @Override
184                 public T get() {
185                     return supplier.get();
186                 }
187             });
188         }
189         // END Android-added: method to create Map.Entry<String, Provider> for a RandomGenerator.
190     }
191 
192     /**
193      * Private constructor.
194      *
195      * @param provider  Provider class to wrap.
196      */
197     private RandomGeneratorFactory(Provider<? extends RandomGenerator> provider) {
198         this.provider = provider;
199     }
200 
201     /**
202      * Returns the factory map, lazily constructing map on first call.
203      *
204      * @return Map of RandomGeneratorFactory classes.
205      */
206     private static Map<String, Provider<? extends RandomGenerator>> getFactoryMap() {
207         return FactoryMapHolder.FACTORY_MAP;
208     }
209 
210     /**
211      * Return the annotation for the specified provider.
212      *
213      * @return RandomGeneratorProperties annotation for the specified provider.
214      */
215      private RandomGeneratorProperties getProperties() {
216         if (properties == null) {
217             synchronized (provider) {
218                 if (properties == null) {
219                     properties = provider.type().getDeclaredAnnotation(RandomGeneratorProperties.class);
220                     Objects.requireNonNull(properties, provider.type() + " missing annotation");
221                 }
222             }
223         }
224 
225         return properties;
226     }
227 
228     /**
229      * Return true if the provider is a subclass of the category.
230      *
231      * @param category Interface category, sub-interface of {@link RandomGenerator}.
232      *
233      * @return true if the provider is a subclass of the category.
234      */
235     private boolean isSubclass(Class<? extends RandomGenerator> category) {
236         return isSubclass(category, provider);
237     }
238 
239     /**
240      * Return true if the provider is a subclass of the category.
241      *
242      * @param category Interface category, sub-interface of {@link RandomGenerator}.
243      * @param provider Provider that is being filtered.
244      *
245      * @return true if the provider is a subclass of the category.
246      */
247     private static boolean isSubclass(Class<? extends RandomGenerator> category,
248                                       Provider<? extends RandomGenerator> provider) {
249         return provider != null && category.isAssignableFrom(provider.type());
250     }
251 
252     /**
253      * Returns the provider matching name and category.
254      *
255      * @param name      Name of RandomGenerator
256      * @param category  Interface category, sub-interface of {@link RandomGenerator}.
257      *
258      * @return A provider matching name and category.
259      *
260      * @throws IllegalArgumentException if provider is not a subclass of category.
261      */
262     private static Provider<? extends RandomGenerator> findProvider(String name,
263                                                                     Class<? extends RandomGenerator> category)
264             throws IllegalArgumentException {
265         Map<String, Provider<? extends RandomGenerator>> fm = getFactoryMap();
266         Provider<? extends RandomGenerator> provider = fm.get(name);
267         if (provider == null) {
268             throw new IllegalArgumentException("No implementation of the random number generator algorithm \"" +
269                                                 name +
270                                                 "\" is available");
271         } else if (!isSubclass(category, provider)) {
272             throw new IllegalArgumentException("The random number generator algorithm \"" +
273                                                 name +
274                                                 "\" is not implemented with the interface \"" +
275                                                 category.getSimpleName() +
276                                                 "\"");
277         }
278         return provider;
279     }
280 
281     /**
282      * Returns a {@link RandomGenerator} that utilizes the {@code name}
283      * <a href="package-summary.html#algorithms">algorithm</a>.
284      *
285      * @param name      Name of random number algorithm to use
286      * @param category  Sub-interface of {@link RandomGenerator} to type check
287      * @param <T>       Sub-interface of {@link RandomGenerator} to produce
288      *
289      * @return An instance of {@link RandomGenerator}
290      *
291      * @throws IllegalArgumentException when either the name or category is null
292      */
293     static <T extends RandomGenerator> T of(String name, Class<T> category)
294             throws IllegalArgumentException {
295         @SuppressWarnings("unchecked")
296         T uncheckedRandomGenerator = (T)findProvider(name, category).get();
297         return uncheckedRandomGenerator;
298     }
299 
300     /**
301      * Returns a {@link RandomGeneratorFactory} that will produce instances
302      * of {@link RandomGenerator} that utilizes the named algorithm.
303      *
304      * @param name  Name of random number algorithm to use
305      * @param category Sub-interface of {@link RandomGenerator} to type check
306      * @param <T> Sub-interface of {@link RandomGenerator} to produce
307      *
308      * @return Factory of {@link RandomGenerator}
309      *
310      * @throws IllegalArgumentException when either the name or category is null
311      */
312     static <T extends RandomGenerator> RandomGeneratorFactory<T> factoryOf(String name, Class<T> category)
313             throws IllegalArgumentException {
314         Provider<? extends RandomGenerator> uncheckedProvider = findProvider(name, category);
315         return new RandomGeneratorFactory<>(uncheckedProvider);
316     }
317 
318     /**
319      * Fetch the required constructors for class of random number algorithm.
320      *
321      * @param randomGeneratorClass class of random number algorithm (provider)
322      */
323     private void getConstructors(Class<? extends RandomGenerator> randomGeneratorClass) {
324         if (ctor == null) {
325             synchronized (provider) {
326                 if (ctor == null) {
327                     PrivilegedExceptionAction<Constructor<?>[]> ctorAction = randomGeneratorClass::getConstructors;
328                     try {
329                         @SuppressWarnings("removal")
330                         Constructor<?>[] ctors = AccessController.doPrivileged(ctorAction);
331 
332                         Constructor<T> tmpCtor = null;
333                         Constructor<T> tmpCtorLong = null;
334                         Constructor<T> tmpCtorBytes = null;
335 
336 
337                         for (Constructor<?> ctorGeneric : ctors) {
338                             @SuppressWarnings("unchecked")
339                             Constructor<T> ctorSpecific = (Constructor<T>) ctorGeneric;
340                             final Class<?>[] parameterTypes = ctorSpecific.getParameterTypes();
341 
342                             if (parameterTypes.length == 0) {
343                                 tmpCtor = ctorSpecific;
344                             } else if (parameterTypes.length == 1) {
345                                 Class<?> argType = parameterTypes[0];
346 
347                                 if (argType == long.class) {
348                                     tmpCtorLong = ctorSpecific;
349                                 } else if (argType == byte[].class) {
350                                     tmpCtorBytes = ctorSpecific;
351                                 }
352                             }
353                         }
354 
355                         if (tmpCtor == null) {
356                             throw new IllegalStateException("Random algorithm " + name() + " is missing a default constructor");
357                         }
358 
359                         // Store specialized constructors first, guarded by ctor
360                         ctorBytes = tmpCtorBytes;
361                         ctorLong = tmpCtorLong;
362                         ctor = tmpCtor;
363                     } catch (PrivilegedActionException ex) {
364                         // Do nothing
365                     }
366                 }
367             }
368         }
369     }
370 
371     /**
372      * Ensure all the required constructors are fetched.
373      */
374     private void ensureConstructors() {
375         getConstructors(provider.type());
376     }
377 
378     /**
379      * Returns a {@link RandomGeneratorFactory} that can produce instances of
380      * {@link RandomGenerator} that utilize the {@code name}
381      * <a href="package-summary.html#algorithms">algorithm</a>.
382      *
383      * @implSpec Availability is determined by RandomGeneratorFactory using the
384      * service provider API to locate implementations of the RandomGenerator interface.
385      *
386      * @param name  Name of random number generator
387      * <a href="package-summary.html#algorithms">algorithm</a>
388      * @param <T> Sub-interface of {@link RandomGenerator} to produce
389      *
390      * @return {@link RandomGeneratorFactory} of {@link RandomGenerator}
391      *
392      * @throws NullPointerException if name is null
393      * @throws IllegalArgumentException if the named algorithm is not found
394      */
395     public static <T extends RandomGenerator> RandomGeneratorFactory<T> of(String name) {
396         Objects.requireNonNull(name);
397         @SuppressWarnings("unchecked")
398         RandomGeneratorFactory<T> factory =
399                 (RandomGeneratorFactory<T>)factoryOf(name, RandomGenerator.class);
400         return factory;
401     }
402 
403     /**
404      * Returns a {@link RandomGeneratorFactory} meeting the minimal requirement
405      * of having an algorithm whose state bits are greater than or equal 64.
406      *
407      * @implSpec  Since algorithms will improve over time, there is no
408      * guarantee that this method will return the same algorithm over time.
409      *
410      * @return a {@link RandomGeneratorFactory}
411      */
412     public static RandomGeneratorFactory<RandomGenerator> getDefault() {
413         return factoryOf("L32X64MixRandom", RandomGenerator.class);
414     }
415 
416     /**
417      * Returns a non-empty stream of available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}.
418      *
419      * RandomGenerators that are marked as deprecated are not included in the result.
420      *
421      * @implSpec Availability is determined by RandomGeneratorFactory using the service provider API
422      * to locate implementations of the RandomGenerator interface.
423      *
424      * @return a non-empty stream of all available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}.
425      */
426     public static Stream<RandomGeneratorFactory<RandomGenerator>> all() {
427         Map<String, Provider<? extends RandomGenerator>> fm = getFactoryMap();
428         return fm.values()
429                  .stream()
430                  .filter(p -> !p.type().isAnnotationPresent(Deprecated.class) &&
431                               p.type().isAnnotationPresent(RandomGeneratorProperties.class))
432                  .map(RandomGeneratorFactory::new);
433     }
434 
435     /**
436      * Return the name of the <a href="package-summary.html#algorithms">algorithm</a>
437      * used by the random number generator.
438      *
439      * @return Name of the <a href="package-summary.html#algorithms">algorithm</a>.
440      */
441     public String name() {
442         return provider.type().getSimpleName();
443     }
444 
445     /**
446      * Return the group name of the <a href="package-summary.html#algorithms">algorithm</a>
447      * used by the random number generator.
448      *
449      * @return Group name of the <a href="package-summary.html#algorithms">algorithm</a>.
450      */
451     public String group() {
452         return getProperties().group();
453     }
454 
455     /**
456      * Returns number of bits used by the <a href="package-summary.html#algorithms">algorithm</a>
457      * to maintain state of seed.
458      *
459      * @return number of bits used by the <a href="package-summary.html#algorithms">algorithm</a>
460      *         to maintain state of seed.
461      */
462     public int stateBits() {
463         RandomGeneratorProperties properties = getProperties();
464         int i = properties.i();
465         int k = properties.k();
466 
467         return i == 0 && k == 0 ? Integer.MAX_VALUE : i + k;
468     }
469 
470     /**
471      * Returns the equidistribution of the <a href="package-summary.html#algorithms">algorithm</a>.
472      *
473      * @return the equidistribution of the <a href="package-summary.html#algorithms">algorithm</a>.
474      */
475     public int equidistribution() {
476         return getProperties().equidistribution();
477     }
478 
479     /**
480      * Return the period of the <a href="package-summary.html#algorithms">algorithm</a>
481      * used by the random number generator.
482      * Returns BigInteger.ZERO if period is not determinable.
483      *
484      * @return BigInteger period.
485      */
486     public BigInteger period() {
487         RandomGeneratorProperties properties = getProperties();
488         int i = properties.i();
489         int j = properties.j();
490         int k = properties.k();
491 
492         if (i == 0 && j == 0 && k == 0) {
493             return BigInteger.ZERO;
494         } else {
495             return BigInteger.ONE.shiftLeft(i).subtract(BigInteger.valueOf(j)).shiftLeft(k);
496         }
497     }
498 
499     /**
500      * Return true if random generator is computed using an arithmetic
501      * <a href="package-summary.html#algorithms">algorithm</a>
502      * and is statistically deterministic.
503      *
504      * @return true if random generator is statistical.
505      */
506     public boolean isStatistical() {
507         return !getProperties().isStochastic();
508     }
509 
510     /**
511      * Return true if random generator is computed using external or entropic
512      * sources as inputs.
513      *
514      * @return true if random generator is stochastic.
515      */
516     public boolean isStochastic() {
517         return getProperties().isStochastic();
518     }
519 
520     /**
521      * Return true if random generator uses a hardware device (HRNG) to produce
522      * entropic input.
523      *
524      * @return true if random generator is generated by hardware.
525      */
526     public boolean isHardware() {
527         return getProperties().isHardware();
528     }
529 
530     /**
531      * Return true if random generator can jump an arbitrarily specified distant
532      * point in the state cycle.
533      *
534      * @return true if random generator is arbitrarily jumpable.
535      */
536     public boolean isArbitrarilyJumpable() {
537         return isSubclass(ArbitrarilyJumpableGenerator.class);
538     }
539 
540     /**
541      * Return true if random generator can jump a specified distant point in
542      * the state cycle.
543      *
544      * @return true if random generator is jumpable.
545      */
546     public boolean isJumpable() {
547         return isSubclass(JumpableGenerator.class);
548     }
549 
550     /**
551      * Return true if random generator is jumpable and can leap to a very distant
552      * point in the state cycle.
553      *
554      * @return true if random generator is leapable.
555      */
556     public boolean isLeapable() {
557         return isSubclass(LeapableGenerator.class);
558     }
559 
560     /**
561      * Return true if random generator can be cloned into a separate object with
562      * the same properties but positioned further in the state cycle.
563      *
564      * @return true if random generator is splittable.
565      */
566     public boolean isSplittable() {
567         return isSubclass(SplittableGenerator.class);
568     }
569 
570     /**
571      * Return true if random generator can be used to create
572      * {@link java.util.stream.Stream Streams} of random numbers.
573      *
574      * @return true if random generator is streamable.
575      */
576     public boolean isStreamable() {
577         return isSubclass(StreamableGenerator.class);
578     }
579 
580     /**
581      * Return true if the implementation of RandomGenerator (algorithm) has been
582      * marked for deprecation.
583      *
584      * @implNote Random number generator algorithms evolve over time; new
585      *           algorithms will be introduced and old algorithms will
586      *           lose standing. If an older algorithm is deemed unsuitable
587      *           for continued use, it will be marked as deprecated to indicate
588      *           that it may be removed at some point in the future.
589      *
590      * @return true if the implementation of RandomGenerator (algorithm) has been
591      *         marked for deprecation
592      */
593      public boolean isDeprecated() {
594         return provider.type().isAnnotationPresent(Deprecated.class);
595      }
596 
597     /**
598      * Create an instance of {@link RandomGenerator} based on
599      * <a href="package-summary.html#algorithms">algorithm</a> chosen.
600      *
601      * @return new in instance of {@link RandomGenerator}.
602      *
603      */
604     public T create() {
605         try {
606             ensureConstructors();
607             return ctor.newInstance();
608         } catch (Exception ex) {
609             // Should never happen.
610             throw new IllegalStateException("Random algorithm " + name() + " is missing a default constructor", ex);
611         }
612     }
613 
614     /**
615      * Create an instance of {@link RandomGenerator} based on
616      * <a href="package-summary.html#algorithms">algorithm</a> chosen
617      * providing a starting long seed. If long seed is not supported by an
618      * algorithm then the no argument form of create is used.
619      *
620      * @param seed long random seed value.
621      *
622      * @return new in instance of {@link RandomGenerator}.
623      */
624     public T create(long seed) {
625         try {
626             ensureConstructors();
627             return ctorLong.newInstance(seed);
628         } catch (Exception ex) {
629             return create();
630         }
631     }
632 
633     /**
634      * Create an instance of {@link RandomGenerator} based on
635      * <a href="package-summary.html#algorithms">algorithm</a> chosen
636      * providing a starting byte[] seed. If byte[] seed is not supported by an
637      * <a href="package-summary.html#algorithms">algorithm</a> then the no
638      * argument form of create is used.
639      *
640      * @param seed byte array random seed value.
641      *
642      * @return new in instance of {@link RandomGenerator}.
643      *
644      * @throws NullPointerException if seed is null.
645      */
646     public T create(byte[] seed) {
647         Objects.requireNonNull(seed, "seed must not be null");
648         try {
649             ensureConstructors();
650             return ctorBytes.newInstance(seed);
651         } catch (Exception ex) {
652             return create();
653         }
654     }
655 
656 }
657 
658 
659