Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6f2e1a2

Browse files
committed
Adds a Random implementation
1 parent 0d0853c commit 6f2e1a2

File tree

1 file changed

+316
-0
lines changed

1 file changed

+316
-0
lines changed
Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
package org.random.util;
2+
3+
import java.io.IOException;
4+
import java.util.NoSuchElementException;
5+
import java.util.Random;
6+
7+
import org.random.api.RandomOrgCache;
8+
import org.random.api.RandomOrgClient;
9+
10+
/**
11+
* An implementation of {@link Random} with a true RNG.
12+
* <p>
13+
* This implements a true random number generator based on the random.org service.
14+
* For more information about that see <code>https://random.org/</code>.
15+
* <p>
16+
* This class offers cached number retrieving from the random.org server over the official API.
17+
* This cached numbers can be instantly access bit wise by the typical public methods of the random class.
18+
* If more bits are requested as cached the methods will block till they get retrieved from the server.
19+
* <p>
20+
* To use this class a official API key from <code>https://api.random.org/api-keys</code> is required.
21+
* <p>
22+
* To optimize that cache for your needs you can setup the cache size on creation of an instance. By default
23+
* it will cache 16 16-bit values sums up to 256 bits.
24+
*
25+
* @see https://random.org/
26+
* @see https://api.random.org/
27+
*
28+
* @author Adam Wagenhäuser
29+
*
30+
*/
31+
public class RandomOrgRandom extends Random {
32+
33+
/**
34+
*
35+
*/
36+
private static final long serialVersionUID = 4785372106424073371L;
37+
38+
/**
39+
* Default cache size of 16 values.
40+
*/
41+
protected static final int DEFAULT_CACHE_SIZE = 16;
42+
43+
/**
44+
* Count of 16-bit values to cache.
45+
* <p>
46+
* So the cache size is <code>16 * cacheSize</code> bits.
47+
* <p>
48+
* Must be at least 2, default is 16.
49+
*/
50+
protected int cacheSize;
51+
52+
/**
53+
* The local 16-bit value random.org cache.
54+
* <p>
55+
* It stores up to {@link #cacheSize} values.
56+
*/
57+
protected RandomOrgCache<int[]> cache;
58+
59+
/**
60+
* The random.org client used for the cache.
61+
*
62+
* @see #cache
63+
*/
64+
protected RandomOrgClient client;
65+
66+
/**
67+
* Left to right bit buffer for getting single bits.
68+
*
69+
* @see #bitBufferLength
70+
*/
71+
protected int bitBuffer = 0;
72+
73+
/**
74+
* Count of currently stored bits in the <code>bitBuffer</code>.
75+
*
76+
* @see #bitBuffer
77+
*/
78+
protected int bitBufferLength = 0;
79+
80+
/**
81+
* Create a new Random instance for the given api key.
82+
* <p>
83+
* This Random needs an official API key for the random.org API. See
84+
* https://api.random.org/api-keys for more details.
85+
* <p>
86+
* The random.org library guarantees that not multiple clients are running
87+
* at once. So it's save to create multiple <code>RandomOrgRandom</code>s
88+
* with the same key, if needed.
89+
*
90+
* @param apiKey an API key to use
91+
*/
92+
public RandomOrgRandom(String apiKey) {
93+
this(apiKey, DEFAULT_CACHE_SIZE);
94+
}
95+
96+
/**
97+
* Create a new Random instance for the given api key and given cache size.
98+
* <p>
99+
* This Random needs an official API key for the random.org API. See
100+
* https://api.random.org/api-keys for more details.
101+
* <p>
102+
* The <code>cacheSize</code> specifies the count of 16-bit values maintained by a background thread.
103+
* If you set the value to high such a creation of a random will consume a lot of the allowance.
104+
* It it is to low your application will block frequently. The default value is 16 values.
105+
* <p>
106+
* The random.org library guarantees that not multiple clients are running
107+
* at once. So it's save to create multiple <code>RandomOrgRandom</code>s
108+
* with the same key, if needed.
109+
*
110+
* @param apiKey an API key to use
111+
* @param cacheSize the size of the cache to use
112+
*/
113+
public RandomOrgRandom(String apiKey, int cacheSize) {
114+
115+
this.cacheSize = cacheSize;
116+
117+
/*
118+
* Defining the random.org client with the given app key.
119+
*/
120+
client = RandomOrgClient.getRandomOrgClient(apiKey);
121+
122+
/*
123+
* Getting always 16-bit numbers at once.
124+
*/
125+
cache = client.createIntegerCache(1, 0, 0xFFFF, true, cacheSize);
126+
127+
}
128+
129+
/**
130+
* Create a new Random instance using the given client.
131+
* <p>
132+
* This Random needs a random.org client instance for the random.org API.
133+
* <p>
134+
* The random.org library guarantees that not multiple clients are running
135+
* at once. So it's save to create multiple <code>RandomOrgRandom</code>s
136+
* with the same key, if needed.
137+
*
138+
* @param client a random.org client to use
139+
*/
140+
public RandomOrgRandom(RandomOrgClient client) {
141+
this(client, DEFAULT_CACHE_SIZE);
142+
}
143+
144+
/**
145+
* Create a new Random instance using the given client and given cache size.
146+
* <p>
147+
* This Random needs a random.org client instance for the random.org API.
148+
* <p>
149+
* The <code>cacheSize</code> specifies the count of 16-bit values maintained by a background thread.
150+
* If you set the value to high such a creation of a random will consume a lot of the allowance.
151+
* It it is to low your application will block frequently. The default value is 16 values.
152+
* <p>
153+
* The random.org library guarantees that not multiple clients are running
154+
* at once. So it's save to create multiple <code>RandomOrgRandom</code>s
155+
* with the same key, if needed.
156+
*
157+
* @param client a random.org client to use
158+
* @param cacheSize the size of the cache to use
159+
*/
160+
public RandomOrgRandom(RandomOrgClient client, int cacheSize) {
161+
this.client = client;
162+
this.cacheSize = cacheSize;
163+
164+
/*
165+
* Getting always 16-bit numbers at once.
166+
*/
167+
cache = client.createIntegerCache(1, 0, 0xFFFF, true, cacheSize);
168+
}
169+
170+
/**
171+
* Gets the given count of random bits.
172+
* <p>
173+
* Note: for usual bits retrieving the <code>next(int)</code> method should be used.
174+
* <p>
175+
* The <code>numBits</code> must in range from <code>0</code> to <code>16</code>, both included.
176+
* <p>
177+
* This method will return the count of bits as a 16 bit short value. If
178+
* less than 16 bits are requested the random bits are stored in the less
179+
* significant bits and the more significant bits are filled with zeros.
180+
* So all random number are in range from <code>0</code> to <code>2^numBits - 1</code>, both included.
181+
* <pre>
182+
* Example getting 12 bits:
183+
*
184+
* int ranBits = getSubBits(12) & 0x0FFF
185+
* </pre>
186+
*
187+
* @param numBits the count of bits to get
188+
* @return a short containing the given count of random bits
189+
* @see #next(int)
190+
* @throws NoSuchElementException if the number couldn't be retrieved
191+
*/
192+
protected synchronized short getSubBits(int numBits) {
193+
194+
int mask = ((int) (Math.pow(2, numBits)) - 1);
195+
196+
if (numBits < 0 || 16 < numBits) {
197+
throw new IllegalArgumentException("Only 0 up to 16 bits can be get");
198+
}
199+
200+
if (bitBufferLength < numBits) {
201+
bitBuffer |= (nextShort() & 0xFFFF) << bitBufferLength;
202+
bitBufferLength += 16;
203+
}
204+
205+
short value = (short) (bitBuffer & mask);
206+
207+
bitBuffer >>= numBits;
208+
209+
bitBufferLength -= numBits;
210+
211+
return value;
212+
}
213+
214+
/**
215+
* Gets the remaining quota for the used key.
216+
* <p>
217+
* This method gets the count of bit which can be still retrieved from the
218+
* server. If this value is negative no more bit can be retrieved.
219+
* <p>
220+
* Note that this method will access a buffered value if not too old,
221+
* so the return can be different from the actual value.
222+
* <p>
223+
* Note that this value do not contain local cached bit. So the current
224+
* local available bits count can be bigger that the return of this method.
225+
*
226+
* @return the remaining quota
227+
* @throws IOException @see {@link RandomOrgClient#getBitsLeft()}
228+
*/
229+
public long getRemainingQuota() throws IOException {
230+
231+
return client.getBitsLeft();
232+
233+
}
234+
235+
/**
236+
* Gets the next fully 16 bit random number.
237+
*
238+
* @return a 16 bit random number
239+
* @throws NoSuchElementException if the number couldn't be retrieved
240+
*/
241+
public short nextShort() {
242+
Short s;
243+
244+
try {
245+
while (true) {
246+
s = null;
247+
248+
try {
249+
s = (short) cache.get()[0];
250+
} catch (NoSuchElementException e) {
251+
try {
252+
if (getRemainingQuota() <= 0) {
253+
throw e;
254+
}
255+
} catch (IOException ioe) {
256+
// TODO add logger
257+
throw e;
258+
}
259+
}
260+
261+
if (s == null) {
262+
// TODO block till new bits are available
263+
Thread.sleep(100);
264+
} else {
265+
return s;
266+
}
267+
}
268+
} catch (InterruptedException e) {
269+
e.printStackTrace();
270+
271+
throw new NoSuchElementException("Interrupt was triggered.");
272+
}
273+
}
274+
275+
@Override
276+
protected int next(int numBits) {
277+
int numShorts = (numBits+15)/16;
278+
short b[] = new short[numShorts];
279+
int next = 0;
280+
281+
/*
282+
* Get full shorts.
283+
*/
284+
285+
for (int i = 1; i < b.length; i++)
286+
b[i] = nextShort();
287+
288+
/*
289+
* Get last partial short.
290+
*/
291+
292+
int sigleBits = 16 - numShorts*16 + numBits;
293+
294+
b[0] = getSubBits(sigleBits);
295+
296+
/*
297+
* Merge together.
298+
*/
299+
300+
for (int i = 0; i < numShorts; i++)
301+
next = (next << 16) + (b[i] & 0xFFFF);
302+
303+
return next ;//>>> (numShorts*16 - numBits);
304+
}
305+
306+
/**
307+
* Returns the size of the cache locally used.
308+
* <p>
309+
* This size can be specified in the constructor.
310+
*
311+
* @return the size of the cache
312+
*/
313+
public int getCachSize() {
314+
return cacheSize;
315+
}
316+
}

0 commit comments

Comments
 (0)