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 = RandomSource.create(source, seed); 063 isInitialized = true; 064 } 065 066 /** {@inheritDoc} */ 067 @Override 068 public synchronized void setSeed(long seed) { 069 if (isInitialized) { 070 delegate = RandomSource.create(source, 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 synchronized int next(int n) { 094 return delegate.nextInt() >>> (32 - n); 095 } 096 097 /** 098 * @param out Output stream. 099 * @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}