1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.rng.simple; 18 19 import java.io.IOException; 20 import java.io.ObjectOutputStream; 21 import java.io.ObjectInputStream; 22 import java.util.Random; 23 import org.apache.commons.rng.RestorableUniformRandomProvider; 24 import org.apache.commons.rng.core.RandomProviderDefaultState; 25 26 /** 27 * Subclass of {@link Random} that {@link #next(int) delegates} to a 28 * {@link RestorableUniformRandomProvider} instance but will otherwise rely 29 * on the base class for generating all the random types. 30 * 31 * <p> 32 * Legacy applications coded against the JDK's API could use this subclass 33 * of {@link Random} in order to replace its linear congruential generator 34 * by any {@link RandomSource}. 35 * </p> 36 * 37 * Caveat: Use of this class is <em>not</em> recommended for new applications. 38 * In particular, there is no guarantee that the serialized form of this class 39 * will be compatible across (even <em>minor</em>) releases of the library. 40 * 41 * @since 1.0 42 */ 43 public final class JDKRandomBridge extends Random { 44 /** Serializable version identifier. */ 45 private static final long serialVersionUID = 20161107L; 46 /** Source. */ 47 private final RandomSource source; 48 /** Delegate. */ 49 private transient RestorableUniformRandomProvider delegate; 50 /** Workaround JDK's "Random" bug: https://bugs.openjdk.java.net/browse/JDK-8154225 */ 51 private final transient boolean isInitialized; 52 53 /** 54 * Creates a new instance. 55 * 56 * @param source Source of randomness. 57 * @param seed Seed. Can be {@code null}. 58 */ 59 public JDKRandomBridge(RandomSource source, 60 Object seed) { 61 this.source = source; 62 delegate = RandomSource.create(source, seed); 63 isInitialized = true; 64 } 65 66 /** {@inheritDoc} */ 67 @Override 68 public synchronized void setSeed(long seed) { 69 if (isInitialized) { 70 delegate = RandomSource.create(source, seed); 71 72 // Force the clearing of the "haveNextNextGaussian" flag 73 // (cf. Javadoc of the base class); the value passed here 74 // is irrelevant (since it will not be used). 75 super.setSeed(0L); 76 } 77 } 78 79 /** 80 * Delegates the generation of 32 random bits to the 81 * {@code RandomSource} argument provided at 82 * {@link #JDKRandomBridge(RandomSource,Object) construction}. 83 * The returned value is such that if the source of randomness is 84 * {@link RandomSource#JDK}, all the generated values will be identical 85 * to those produced by the same sequence of calls on a {@link Random} 86 * instance initialized with the same seed. 87 * 88 * @param n Number of random bits which the requested value must contain. 89 * @return the value represented by the {@code n} high-order bits of a 90 * pseudo-random 32-bits integer. 91 */ 92 @Override 93 protected synchronized int next(int n) { 94 return delegate.nextInt() >>> (32 - n); 95 } 96 97 /** 98 * @param out Output stream. 99 * @throws IOException if an error occurs. 100 */ 101 private synchronized void writeObject(ObjectOutputStream out) 102 throws IOException { 103 // Write non-transient fields. 104 out.defaultWriteObject(); 105 106 // Save current state. 107 out.writeObject(((RandomProviderDefaultState) delegate.saveState()).getState()); 108 } 109 110 /** 111 * @param in Input stream. 112 * @throws IOException if an error occurs. 113 * @throws ClassNotFoundException if an error occurs. 114 */ 115 private void readObject(ObjectInputStream in) 116 throws IOException, 117 ClassNotFoundException { 118 // Read non-transient fields. 119 in.defaultReadObject(); 120 121 // Recreate the "delegate" from serialized info. 122 delegate = RandomSource.create(source); 123 // And restore its state. 124 delegate.restoreState(new RandomProviderDefaultState((byte[]) in.readObject())); 125 } 126 }