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