diff -r effb66aab08b -r da026c172c1e src/java.base/share/classes/java/util/random/RandomGeneratorFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/java/util/random/RandomGeneratorFactory.java Thu Nov 14 12:50:08 2019 -0400 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util.random; + +import java.util.function.Function; +import java.util.Map; +import java.util.Objects; +import java.util.ServiceLoader; +import java.util.ServiceLoader.Provider; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * This is a factory class for generating random number generators of a specific + * catagory and algorithm. + */ +public class RandomGeneratorFactory { + /** + * Instance provider class of random number algorithm. + */ + private final Provider provider; + + /** + * Map of provider classes. + */ + private static Map> providerMap; + + /** + * Private constructor. + * + * @param provider Provider class to wrap. + */ + private RandomGeneratorFactory(Provider provider) { + this.provider = provider; + } + + /** + * Returns the provider map, lazily constructing map on first call. + * + * @return Map of provider classes. + */ + private static Map> getProviderMap() { + if (providerMap == null) { + synchronized (RandomGeneratorFactory.class) { + if (providerMap == null) { + providerMap = + ServiceLoader + .load(RandomGenerator.class) + .stream() + .filter(p -> !p.type().isInterface()) + .collect(Collectors.toMap(p -> p.type().getSimpleName().toUpperCase(), + Function.identity())); + } + } + } + return providerMap; + } + + private static Provider findProvider(String name, Class category) + throws IllegalArgumentException { + Map> pm = getProviderMap(); + Provider provider = pm.get(name.toUpperCase()); + if (provider == null || provider.type().isAssignableFrom(category)) { + throw new IllegalArgumentException(name + " is an unknown random number generator"); + } + return provider; + } + + /** + * Returns a {@link RandomGenerator} that utilizes the {@code name} algorithm. + * + * @param name Name of random number algorithm to use + * @param category Sub-interface of {@link RandomGenerator} to type check + * @param Sub-interface of {@link RandomGenerator} to produce + * @return An instance of {@link RandomGenerator} + * @throws IllegalArgumentException when either the name or category is null + */ + static T of(String name, Class category) + throws IllegalArgumentException { + @SuppressWarnings("unchecked") + T uncheckedRandomGenerator = (T)findProvider(name, category).get(); + return uncheckedRandomGenerator; + } + + /** + * Returns a {@link RandomGeneratorFactory} that will produce instances + * of {@link RandomGenerator} that utilizes the {@code name} algorithm. + * + * @param name Name of random number algorithm to use + * @param category Sub-interface of {@link RandomGenerator} to type check + * @param Sub-interface of {@link RandomGenerator} to produce + * @return Factory of {@link RandomGenerator} + * @throws IllegalArgumentException when either the name or category is null + */ + static RandomGeneratorFactory factoryOf(String name, Class category) + throws IllegalArgumentException { + @SuppressWarnings("unchecked") + Provider uncheckedProvider = (Provider)findProvider(name, category); + return new RandomGeneratorFactory(uncheckedProvider); + } + + /** + * Create an instance of {@link RandomGenerator}. + * + * @return Instance of {@link RandomGenerator}. + */ + public T create() { + return provider.get(); + } +} + +