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.rng.simple; 018 019import java.io.IOException; 020import java.io.ObjectOutputStream; 021import java.io.ObjectInputStream; 022import java.util.Random; 023import org.apache.commons.rng.RestorableUniformRandomProvider; 024import org.apache.commons.rng.core.RandomProviderDefaultState; 025 026/** 027 * Subclass of {@link Random} that {@link #next(int) delegates} to a 028 * {@link RestorableUniformRandomProvider} instance but will otherwise rely 029 * on the base class for generating all the random types. 030 * 031 * <p> 032 * Legacy applications coded against the JDK's API could use this subclass 033 * of {@link Random} in order to replace its linear congruential generator 034 * by any {@link RandomSource}. 035 * </p> 036 * 037 * Caveat: Use of this class is <em>not</em> recommended for new applications. 038 * In particular, there is no guarantee that the serialized form of this class 039 * will be compatible across (even <em>minor</em>) releases of the library. 040 * 041 * @since 1.0 042 */ 043public final class JDKRandomBridge extends Random { 044 /** Serializable version identifier. */ 045 private static final long serialVersionUID = 20161107L; 046 /** Source. */ 047 private final RandomSource source; 048 /** Delegate. */ 049 private transient RestorableUniformRandomProvider delegate; 050 /** Workaround JDK's "Random" bug: https://bugs.openjdk.java.net/browse/JDK-8154225. */ 051 private final transient boolean isInitialized; 052 053 /** 054 * Creates a new instance. 055 * 056 * @param source Source of randomness. 057 * @param seed Seed. Can be {@code null}. 058 */ 059 public JDKRandomBridge(RandomSource source, 060 Object seed) { 061 this.source = source; 062 delegate = source.create(seed); 063 isInitialized = true; 064 } 065 066 /** {@inheritDoc} */ 067 @Override 068 public synchronized void setSeed(long seed) { 069 if (isInitialized) { 070 delegate = source.create(seed); 071 072 // Force the clearing of the "haveNextNextGaussian" flag 073 // (cf. Javadoc of the base class); the value passed here 074 // is irrelevant (since it will not be used). 075 super.setSeed(0L); 076 } 077 } 078 079 /** 080 * Delegates the generation of 32 random bits to the 081 * {@code RandomSource} argument provided at 082 * {@link #JDKRandomBridge(RandomSource,Object) construction}. 083 * The returned value is such that if the source of randomness is 084 * {@link RandomSource#JDK}, all the generated values will be identical 085 * to those produced by the same sequence of calls on a {@link Random} 086 * instance initialized with the same seed. 087 * 088 * @param n Number of random bits which the requested value must contain. 089 * @return the value represented by the {@code n} high-order bits of a 090 * pseudo-random 32-bits integer. 091 */ 092 @Override 093 protected int next(int n) { 094 synchronized (this) { 095 return delegate.nextInt() >>> (32 - n); 096 } 097 } 098 099 /** 100 * @param output Output stream. 101 * @throws IOException if an error occurs. 102 */ 103 private void writeObject(ObjectOutputStream output) 104 throws IOException { 105 synchronized (this) { 106 // Write non-transient fields. 107 output.defaultWriteObject(); 108 109 // Save current state and size. 110 // Avoid the use of ObjectOutputStream.writeObject(Object) to save the state. 111 // This allows deserialization to avoid security issues in using readObject(). 112 final byte[] state = ((RandomProviderDefaultState) delegate.saveState()).getState(); 113 final int size = state.length; 114 output.writeInt(size); 115 output.write(state); 116 } 117 } 118 119 /** 120 * @param input Input stream. 121 * @throws IOException if an error occurs. 122 * @throws ClassNotFoundException if an error occurs. 123 */ 124 private void readObject(ObjectInputStream input) 125 throws IOException, 126 ClassNotFoundException { 127 // Read non-transient fields. 128 input.defaultReadObject(); 129 130 // Recreate the "delegate" from serialized info. 131 delegate = source.create(); 132 // And restore its state. 133 // Avoid the use of input.readObject() to deserialize by manually reading the byte[]. 134 // Note: ObjectInputStream.readObject() will execute the readObject() method of the named 135 // class in the stream which may contain potentially malicious code. 136 final int size = input.readInt(); 137 final byte[] state = new byte[size]; 138 input.readFully(state); 139 delegate.restoreState(new RandomProviderDefaultState(state)); 140 } 141}