1 package org.random.api; 2 3 import com.google.gson.JsonArray; 4 import com.google.gson.JsonObject; 5 import com.google.gson.JsonParser; 6 import java.io.BufferedReader; 7 import java.io.DataOutputStream; 8 import java.io.IOException; 9 import java.io.InputStreamReader; 10 import java.net.MalformedURLException; 11 import java.net.URL; 12 import java.util.Calendar; 13 import java.util.GregorianCalendar; 14 import java.util.HashMap; 15 import java.util.HashSet; 16 import java.util.LinkedList; 17 import java.util.UUID; 18 import java.util.logging.Level; 19 import java.util.logging.Logger; 20 import javax.net.ssl.HttpsURLConnection; 21 import org.random.api.exception.RandomOrgBadHTTPResponseException; 22 import org.random.api.exception.RandomOrgInsufficientBitsError; 23 import org.random.api.exception.RandomOrgInsufficientRequestsError; 24 import org.random.api.exception.RandomOrgJSONRPCError; 25 import org.random.api.exception.RandomOrgKeyNotRunningError; 26 import org.random.api.exception.RandomOrgRANDOMORGError; 27 import org.random.api.exception.RandomOrgSendTimeoutException; 28 29 /** 30 * RandomOrgClient main class through which API functions are accessed. * * This 31 * class provides either serialized or unserialized (determined on class 32 * creation) * access to both the signed and unsigned methods of the RANDOM.ORG 33 * API. These are * threadsafe and implemented as blocking remote procedure 34 * calls. * * If requests are to be issued serially a background Thread will 35 * maintain a Queue of * requests to process in sequence. * * The class also 36 * provides access to creation of a convenience class, RandomOrgCache, * for 37 * precaching API responses when the request is known in advance. * * This class 38 * will only allow the creation of one instance per API key. If an instance * of 39 * this class already exists for a given key, that instance will be returned 40 * instead * of a new instance. * * This class obeys most of the guidelines set 41 * forth in https://api.random.org/guidelines * All requests respect the 42 * server's advisoryDelay returned in any responses, or use * DEFAULT_DELAY if 43 * no advisoryDelay is returned. If the supplied API key is paused, i.e., * has 44 * exceeded its daily bit/request allowance, this implementation will back off 45 * until * midnight UTC. * * @see https://api.random.org/ 46 * 47 ** @see http://code.google.com/p/google-gson/ 48 ** @author Anders Haahr 49 * 50 */ 51 public class RandomOrgClient { 52 53 // Basic RANDOM.ORG API functions https://api.random.org/json-rpc/1/ 54 private static final String INTEGER_METHOD = "generateIntegers"; 55 private static final String DECIMAL_FRACTION_METHOD = "generateDecimalFractions"; 56 private static final String GAUSSIAN_METHOD = "generateGaussians"; 57 private static final String STRING_METHOD = "generateStrings"; 58 private static final String UUID_METHOD = "generateUUIDs"; 59 private static final String BLOB_METHOD = "generateBlobs"; 60 private static final String GET_USAGE_METHOD = "getUsage"; 61 62 // Signed RANDOM.ORG API functions https://api.random.org/json-rpc/1/signing 63 private static final String SIGNED_INTEGER_METHOD = "generateSignedIntegers"; 64 private static final String SIGNED_DECIMAL_FRACTION_METHOD = "generateSignedDecimalFractions"; 65 private static final String SIGNED_GAUSSIAN_METHOD = "generateSignedGaussians"; 66 private static final String SIGNED_STRING_METHOD = "generateSignedStrings"; 67 private static final String SIGNED_UUID_METHOD = "generateSignedUUIDs"; 68 private static final String SIGNED_BLOB_METHOD = "generateSignedBlobs"; 69 private static final String VERIFY_SIGNATURE_METHOD = "verifySignature"; 70 71 // Blob format literals 72 public static final String BLOB_FORMAT_BASE64 = "base64"; 73 public static final String BLOB_FORMAT_HEX = "hex"; 74 75 // Default back-off to use if no advisoryDelay back-off supplied by server (1 second) 76 private static final int DEFAULT_DELAY = 1 * 1000; 77 78 // On request fetch fresh allowance state if current state data is older than this value (1 hour) 79 private static final int ALLOWANCE_STATE_REFRESH_SECONDS = 3600 * 1000; 80 81 // default data sizes in bits 82 private static final int UUID_SIZE = 122; 83 84 // Maintain a dictionary of API keys and their instances. 85 private static HashMap<String, RandomOrgClient> keyIndexedInstances = new HashMap<String, RandomOrgClient>(); 86 87 private static HashSet<Integer> randomOrgErrors = new HashSet<Integer>(); 88 89 private static final Logger LOGGER = Logger.getLogger(RandomOrgClient.class.getPackage().getName()); 90 91 static { 92 int[] ints = {100, 101, 200, 201, 202, 203, 204, 300, 301, 302, 303, 304, 400, 401, 402, 403, 500, 32000}; 93 for (int i : ints) { 94 RandomOrgClient.randomOrgErrors.add(i); 95 } 96 } 97 98 /** 99 * Ensure only one instance of RandomOrgClient exists per API key. Create a 100 * new instance if the * supplied key isn't already known, otherwise return 101 * the previously instantiated one. * New instance will have a 102 * blockingTimeout of 24*60*60*1000 milliseconds, i.e., 1 day, a httpTimeout 103 * of * 120*1000 milliseconds, and will issue serialized requests. 104 * 105 * * 106 * @param apiKey of instance to create/find, obtained from RANDOM.ORG, see: 107 * https://api.random.org/api-keys * * @return new instance if instance 108 * doesn't already exist for this key, else existing instance. 109 * 110 */ getRandomOrgClient(String apiKey)111 public static RandomOrgClient getRandomOrgClient(String apiKey) { 112 return RandomOrgClient.getRandomOrgClient(apiKey, 24 * 60 * 60 * 1000, 120 * 1000, true); 113 } 114 115 /** 116 * Ensure only one instance of RandomOrgClient exists per API key. Create a 117 * new instance if the * supplied key isn't already known, otherwise return 118 * the previously instantiated one. * * @param apiKey of instance to 119 * create/find, obtained from RANDOM.ORG, see: 120 * https://api.random.org/api-keys 121 * 122 ** @param blockingTimeout maximum time in milliseconds to wait before 123 * being allowed to send a request. * Note this is a hint not a guarantee. 124 * Be advised advisory delay from server must always be obeyed. * Supply a 125 * value of -1 to allow blocking forever. (default 24*60*60*1000, i.e., 1 126 * day). 127 ** @param httpTimeout maximum time in milliseconds to wait for the server 128 * response to a request. (default 120*1000). 129 ** @param serialized determines whether or not requests from this instance 130 * will be added to a Queue and * issued serially or sent when received, 131 * obeying any advisory delay (default true). * * @return new instance if 132 * instance doesn't already exist for this key, else existing instance. 133 * 134 */ getRandomOrgClient(String apiKey, long blockingTimeout, int httpTimeout, boolean serialized)135 public static RandomOrgClient getRandomOrgClient(String apiKey, long blockingTimeout, int httpTimeout, boolean serialized) { 136 RandomOrgClient instance = RandomOrgClient.keyIndexedInstances.get(apiKey); 137 138 if (instance == null) { 139 instance = new RandomOrgClient(apiKey, blockingTimeout, httpTimeout, serialized); 140 RandomOrgClient.keyIndexedInstances.put(apiKey, instance); 141 } 142 143 return instance; 144 } 145 146 private String apiKey; 147 private long blockingTimeout; 148 private int httpTimeout; 149 private boolean serialized; 150 151 // maintain info to obey server advisory delay 152 private Object advisoryDelayLock = new Object(); 153 private int advisoryDelay = 0; 154 private long lastResponseReceivedTime = 0; 155 156 // maintain usage statistics from server 157 private int requestsLeft = -1; 158 private int bitsLeft = -1; 159 160 // Back-off info for when API key is detected as not running - probably because key 161 // has exceeded its daily usage limit. Back-off runs until midnight UTC. 162 private long backoff = -1; 163 private String backoffError; 164 165 private LinkedList<HashMap<String, Object>> serializedQueue; 166 167 /** 168 * Constructor. Initialize class and start serialized request sending Thread 169 * running as a daemon if applicable. * * @param apiKey of instance to 170 * create/find, obtained from RANDOM.ORG, see: 171 * https://api.random.org/api-keys 172 * 173 ** @param blockingTimeout maximum time in milliseconds to wait before 174 * being allowed to send a request. * Note this is a hint not a guarantee. 175 * Be advised advisory delay from server must always be obeyed. * Supply a 176 * value of -1 to allow blocking forever. (default 24*60*60*1000, i.e., 1 177 * day). 178 ** @param httpTimeout maximum time in milliseconds to wait for the server 179 * response to a request. (default 120*1000). 180 ** @param serialized determines whether or not requests from this instance 181 * will be added to a Queue and * issued serially or sent when received, 182 * obeying any advisory delay (default true). 183 * 184 */ RandomOrgClient(String apiKey, long blockingTimeout, int httpTimeout, boolean serialized)185 private RandomOrgClient(String apiKey, long blockingTimeout, int httpTimeout, boolean serialized) { 186 187 if (serialized) { 188 // set up the serialized request Queue and Thread 189 this.serializedQueue = new LinkedList<HashMap<String, Object>>(); 190 191 Thread t = new Thread(new Runnable() { 192 @Override 193 public void run() { 194 RandomOrgClient.this.threadedRequestSending(); 195 } 196 }); 197 t.setDaemon(true); 198 t.start(); 199 } 200 201 this.serialized = serialized; 202 203 this.apiKey = apiKey; 204 this.blockingTimeout = blockingTimeout; 205 this.httpTimeout = httpTimeout; 206 } 207 208 // Basic methods for generating randomness, see: https://api.random.org/json-rpc/1/basic 209 /** 210 * Request and return an array of true random integers within a user-defined 211 * range from the server. * See: 212 * https://api.random.org/json-rpc/1/basic#generateIntegers * * @param n how 213 * many random integers you need. Must be within the [1,1e4] range. 214 * 215 ** @param min the lower boundary for the range from which the random 216 * numbers will be picked. Must be within the [-1e9,1e9] range. 217 ** @param max the upper boundary for the range from which the random 218 * numbers will be picked. Must be within the [-1e9,1e9] range. * * @return 219 * array of random integers. * * @throws RandomOrgSendTimeoutException 220 * blocking timeout is exceeded before the request can be sent. 221 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 222 ** @throws RandomOrgInsufficientRequestsError API key's server requests 223 * allowance has been exceeded. 224 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 225 * has been exceeded. 226 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 227 * received. 228 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 229 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 230 ** @throws MalformedURLException in the unlikely event something goes 231 * wrong with URL creation. @see java.net.MalformedURLException 232 ** @throws IOException @see java.io.IOException 233 * 234 */ generateIntegers(int n, int min, int max)235 public int[] generateIntegers(int n, int min, int max) throws RandomOrgSendTimeoutException, 236 RandomOrgKeyNotRunningError, 237 RandomOrgInsufficientRequestsError, 238 RandomOrgInsufficientBitsError, 239 RandomOrgBadHTTPResponseException, 240 RandomOrgRANDOMORGError, 241 RandomOrgJSONRPCError, 242 MalformedURLException, 243 IOException { 244 return generateIntegers(n, min, max, true); 245 } 246 247 /** 248 * Request and return an array of true random integers within a user-defined 249 * range from the server. * See: 250 * https://api.random.org/json-rpc/1/basic#generateIntegers * * @param n how 251 * many random integers you need. Must be within the [1,1e4] range. 252 * 253 ** @param min the lower boundary for the range from which the random 254 * numbers will be picked. Must be within the [-1e9,1e9] range. 255 ** @param max the upper boundary for the range from which the random 256 * numbers will be picked. Must be within the [-1e9,1e9] range. 257 ** @param replacement specifies whether the random numbers should be 258 * picked with replacement. * If True the resulting numbers may contain 259 * duplicate values, otherwise the numbers will all be unique (default 260 * True). * * @return array of random integers. * * @throws 261 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 262 * request can be sent. 263 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 264 ** @throws RandomOrgInsufficientRequestsError API key's server requests 265 * allowance has been exceeded. 266 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 267 * has been exceeded. 268 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 269 * received. 270 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 271 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 272 ** @throws MalformedURLException in the unlikely event something goes 273 * wrong with URL creation. @see java.net.MalformedURLException 274 ** @throws IOException @see java.io.IOException 275 * 276 */ generateIntegers(int n, int min, int max, boolean replacement)277 public int[] generateIntegers(int n, int min, int max, boolean replacement) throws RandomOrgSendTimeoutException, 278 RandomOrgKeyNotRunningError, 279 RandomOrgInsufficientRequestsError, 280 RandomOrgInsufficientBitsError, 281 RandomOrgBadHTTPResponseException, 282 RandomOrgRANDOMORGError, 283 RandomOrgJSONRPCError, 284 MalformedURLException, 285 IOException { 286 287 JsonObject request = new JsonObject(); 288 289 request.addProperty("n", n); 290 request.addProperty("min", min); 291 request.addProperty("max", max); 292 request.addProperty("replacement", replacement); 293 294 request = this.generateKeyedRequest(request, INTEGER_METHOD); 295 296 JsonObject response = this.sendRequest(request); 297 298 return this.extractInts(response); 299 } 300 301 /** 302 * Request and return a list (size n) of true random decimal fractions, from 303 * a uniform distribution across * the [0,1] interval with a user-defined 304 * number of decimal places from the server. * See: 305 * https://api.random.org/json-rpc/1/basic#generateDecimalFractions 306 * 307 * * 308 * @param n how many random decimal fractions you need. Must be within the 309 * [1,1e4] range. 310 ** @param decimalPlaces the number of decimal places to use. Must be 311 * within the [1,20] range. * * @return array of random doubles. * * @throws 312 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 313 * request can be sent. 314 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 315 ** @throws RandomOrgInsufficientRequestsError API key's server requests 316 * allowance has been exceeded. 317 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 318 * has been exceeded. 319 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 320 * received. 321 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 322 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 323 ** @throws MalformedURLException in the unlikely event something goes 324 * wrong with URL creation. @see java.net.MalformedURLException 325 ** @throws IOException @see java.io.IOException 326 * 327 */ generateDecimalFractions(int n, int decimalPlaces)328 public double[] generateDecimalFractions(int n, int decimalPlaces) throws RandomOrgSendTimeoutException, 329 RandomOrgKeyNotRunningError, 330 RandomOrgInsufficientRequestsError, 331 RandomOrgInsufficientBitsError, 332 RandomOrgBadHTTPResponseException, 333 RandomOrgRANDOMORGError, 334 RandomOrgJSONRPCError, 335 MalformedURLException, 336 IOException { 337 return this.generateDecimalFractions(n, decimalPlaces, true); 338 } 339 340 /** 341 * Request and return a list (size n) of true random decimal fractions, from 342 * a uniform distribution across * the [0,1] interval with a user-defined 343 * number of decimal places from the server. * See: 344 * https://api.random.org/json-rpc/1/basic#generateDecimalFractions 345 * 346 * * 347 * @param n how many random decimal fractions you need. Must be within the 348 * [1,1e4] range. 349 ** @param decimalPlaces the number of decimal places to use. Must be 350 * within the [1,20] range. 351 ** @param replacement specifies whether the random numbers should be 352 * picked with replacement. * If True the resulting numbers may contain 353 * duplicate values, otherwise the numbers will all be unique (default 354 * True). * * @return array of random doubles. * * @throws 355 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 356 * request can be sent. 357 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 358 ** @throws RandomOrgInsufficientRequestsError API key's server requests 359 * allowance has been exceeded. 360 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 361 * has been exceeded. 362 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 363 * received. 364 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 365 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 366 ** @throws MalformedURLException in the unlikely event something goes 367 * wrong with URL creation. @see java.net.MalformedURLException 368 ** @throws IOException @see java.io.IOException 369 * 370 */ generateDecimalFractions(int n, int decimalPlaces, boolean replacement)371 public double[] generateDecimalFractions(int n, int decimalPlaces, boolean replacement) throws RandomOrgSendTimeoutException, 372 RandomOrgKeyNotRunningError, 373 RandomOrgInsufficientRequestsError, 374 RandomOrgInsufficientBitsError, 375 RandomOrgBadHTTPResponseException, 376 RandomOrgRANDOMORGError, 377 RandomOrgJSONRPCError, 378 MalformedURLException, 379 IOException { 380 381 JsonObject request = new JsonObject(); 382 383 request.addProperty("n", n); 384 request.addProperty("decimalPlaces", decimalPlaces); 385 request.addProperty("replacement", replacement); 386 387 request = this.generateKeyedRequest(request, DECIMAL_FRACTION_METHOD); 388 389 JsonObject response = this.sendRequest(request); 390 391 return this.extractDoubles(response); 392 } 393 394 /** 395 * Request and return a list (size n) of true random numbers from a Gaussian 396 * distribution (also known as a * normal distribution). The form uses a 397 * Box-Muller Transform to generate the Gaussian distribution from * 398 * uniformly distributed numbers. See: 399 * https://api.random.org/json-rpc/1/basic#generateGaussians * * @param n 400 * how many random numbers you need. Must be within the [1,1e4] range. 401 * 402 ** @param mean the distribution's mean. Must be within the [-1e6,1e6] 403 * range. 404 ** @param standardDeviation the distribution's standard deviation. Must be 405 * within the [-1e6,1e6] range. 406 ** @param significantDigits the number of significant digits to use. Must 407 * be within the [2,20] range. * * @return array of true random doubles from 408 * a Gaussian distribution. * * @throws RandomOrgSendTimeoutException 409 * blocking timeout is exceeded before the request can be sent. 410 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 411 ** @throws RandomOrgInsufficientRequestsError API key's server requests 412 * allowance has been exceeded. 413 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 414 * has been exceeded. 415 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 416 * received. 417 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 418 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 419 ** @throws MalformedURLException in the unlikely event something goes 420 * wrong with URL creation. @see java.net.MalformedURLException 421 ** @throws IOException @see java.io.IOException 422 * 423 */ generateGaussians(int n, double mean, double standardDeviation, int significantDigits)424 public double[] generateGaussians(int n, double mean, double standardDeviation, int significantDigits) throws RandomOrgSendTimeoutException, 425 RandomOrgKeyNotRunningError, 426 RandomOrgInsufficientRequestsError, 427 RandomOrgInsufficientBitsError, 428 RandomOrgBadHTTPResponseException, 429 RandomOrgRANDOMORGError, 430 RandomOrgJSONRPCError, 431 MalformedURLException, 432 IOException { 433 434 JsonObject request = new JsonObject(); 435 436 request.addProperty("n", n); 437 request.addProperty("mean", mean); 438 request.addProperty("standardDeviation", standardDeviation); 439 request.addProperty("significantDigits", significantDigits); 440 441 request = this.generateKeyedRequest(request, GAUSSIAN_METHOD); 442 443 JsonObject response = this.sendRequest(request); 444 445 return this.extractDoubles(response); 446 } 447 448 /** 449 * Request and return a list (size n) of true random unicode strings from 450 * the server. * See: 451 * https://api.random.org/json-rpc/1/basic#generateStrings * * @param n how 452 * many random strings you need. Must be within the [1,1e4] range. 453 * 454 ** @param length the length of each string. Must be within the [1,20] 455 * range. All strings will be of the same length. 456 ** @param characters a string that contains the set of characters that are 457 * allowed to occur in the random strings. * The maximum number of 458 * characters is 80. * * @return array of random Strings. * * @throws 459 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 460 * request can be sent. 461 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 462 ** @throws RandomOrgInsufficientRequestsError API key's server requests 463 * allowance has been exceeded. 464 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 465 * has been exceeded. 466 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 467 * received. 468 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 469 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 470 ** @throws MalformedURLException in the unlikely event something goes 471 * wrong with URL creation. @see java.net.MalformedURLException 472 ** @throws IOException @see java.io.IOException 473 * 474 */ generateStrings(int n, int length, String characters)475 public String[] generateStrings(int n, int length, String characters) throws RandomOrgSendTimeoutException, 476 RandomOrgKeyNotRunningError, 477 RandomOrgInsufficientRequestsError, 478 RandomOrgInsufficientBitsError, 479 RandomOrgBadHTTPResponseException, 480 RandomOrgRANDOMORGError, 481 RandomOrgJSONRPCError, 482 MalformedURLException, 483 IOException { 484 return this.generateStrings(n, length, characters, true); 485 } 486 487 /** 488 * Request and return a list (size n) of true random unicode strings from 489 * the server. * See: 490 * https://api.random.org/json-rpc/1/basic#generateStrings * * @param n how 491 * many random strings you need. Must be within the [1,1e4] range. 492 * 493 ** @param length the length of each string. Must be within the [1,20] 494 * range. All strings will be of the same length. 495 ** @param characters a string that contains the set of characters that are 496 * allowed to occur in the random strings. * The maximum number of 497 * characters is 80. 498 ** @param replacement specifies whether the random strings should be 499 * picked with replacement. If True the resulting * list of strings may 500 * contain duplicates, otherwise the strings will all be unique (default 501 * True). * * @return array of random Strings. * * @throws 502 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 503 * request can be sent. 504 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 505 ** @throws RandomOrgInsufficientRequestsError API key's server requests 506 * allowance has been exceeded. 507 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 508 * has been exceeded. 509 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 510 * received. 511 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 512 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 513 ** @throws MalformedURLException in the unlikely event something goes 514 * wrong with URL creation. @see java.net.MalformedURLException 515 ** @throws IOException @see java.io.IOException 516 * 517 */ generateStrings(int n, int length, String characters, boolean replacement)518 public String[] generateStrings(int n, int length, String characters, boolean replacement) throws RandomOrgSendTimeoutException, 519 RandomOrgKeyNotRunningError, 520 RandomOrgInsufficientRequestsError, 521 RandomOrgInsufficientBitsError, 522 RandomOrgBadHTTPResponseException, 523 RandomOrgRANDOMORGError, 524 RandomOrgJSONRPCError, 525 MalformedURLException, 526 IOException { 527 528 JsonObject request = new JsonObject(); 529 530 request.addProperty("n", n); 531 request.addProperty("length", length); 532 request.addProperty("characters", characters); 533 request.addProperty("replacement", replacement); 534 535 request = this.generateKeyedRequest(request, STRING_METHOD); 536 537 JsonObject response = this.sendRequest(request); 538 539 return this.extractStrings(response); 540 } 541 542 /** 543 * Request and return a list (size n) of version 4 true random Universally 544 * Unique IDentifiers (UUIDs) in accordance * with section 4.4 of RFC 4122, 545 * from the server. See: 546 * https://api.random.org/json-rpc/1/basic#generateUUIDs * * @param n how 547 * many random UUIDs you need. Must be within the [1,1e3] range. * * @return 548 * array of random UUIDs. * * @throws RandomOrgSendTimeoutException blocking 549 * timeout is exceeded before the request can be sent. 550 * 551 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 552 ** @throws RandomOrgInsufficientRequestsError API key's server requests 553 * allowance has been exceeded. 554 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 555 * has been exceeded. 556 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 557 * received. 558 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 559 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 560 ** @throws MalformedURLException in the unlikely event something goes 561 * wrong with URL creation. @see java.net.MalformedURLException 562 ** @throws IOException @see java.io.IOException 563 * 564 */ generateUUIDs(int n)565 public UUID[] generateUUIDs(int n) throws RandomOrgSendTimeoutException, 566 RandomOrgKeyNotRunningError, 567 RandomOrgInsufficientRequestsError, 568 RandomOrgInsufficientBitsError, 569 RandomOrgBadHTTPResponseException, 570 RandomOrgRANDOMORGError, 571 RandomOrgJSONRPCError, 572 MalformedURLException, 573 IOException { 574 575 JsonObject request = new JsonObject(); 576 577 request.addProperty("n", n); 578 579 request = this.generateKeyedRequest(request, UUID_METHOD); 580 581 JsonObject response = this.sendRequest(request); 582 583 return this.extractUUIDs(response); 584 } 585 586 /** 587 * Request and return a list (size n) of Binary Large OBjects (BLOBs) as 588 * unicode strings * containing true random data from the server. See: 589 * https://api.random.org/json-rpc/1/basic#generateBlobs * * @param n how 590 * many random blobs you need. Must be within the [1,100] range. 591 * 592 ** @param size the size of each blob, measured in bits. Must be within the 593 * [1,1048576] range and must be divisible by 8. * * @return array of random 594 * blobs as Strings. * * @throws RandomOrgSendTimeoutException blocking 595 * timeout is exceeded before the request can be sent. 596 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 597 ** @throws RandomOrgInsufficientRequestsError API key's server requests 598 * allowance has been exceeded. 599 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 600 * has been exceeded. 601 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 602 * received. 603 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 604 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 605 ** @throws MalformedURLException in the unlikely event something goes 606 * wrong with URL creation. @see java.net.MalformedURLException 607 ** @throws IOException @see java.io.IOException 608 * 609 */ generateBlobs(int n, int size)610 public String[] generateBlobs(int n, int size) throws RandomOrgSendTimeoutException, 611 RandomOrgKeyNotRunningError, 612 RandomOrgInsufficientRequestsError, 613 RandomOrgInsufficientBitsError, 614 RandomOrgBadHTTPResponseException, 615 RandomOrgRANDOMORGError, 616 RandomOrgJSONRPCError, 617 MalformedURLException, 618 IOException { 619 620 return this.generateBlobs(n, size, RandomOrgClient.BLOB_FORMAT_BASE64); 621 } 622 623 /** 624 * Request and return a list (size n) of Binary Large OBjects (BLOBs) as 625 * unicode strings * containing true random data from the server. See: 626 * https://api.random.org/json-rpc/1/basic#generateBlobs * * @param n how 627 * many random blobs you need. Must be within the [1,100] range. 628 * 629 ** @param size the size of each blob, measured in bits. Must be within the 630 * [1,1048576] range and must be divisible by 8. 631 ** @param format specifies the format in which the blobs will be returned. 632 * Values allowed are * BLOB_FORMAT_BASE64 and BLOB_FORMAT_HEX (default 633 * BLOB_FORMAT_BASE64). * * @return array of random blobs as Strings. 634 * 635 * @throws RandomOrgSendTimeoutException blocking timeout is exceeded before 636 * the request can be sent. 637 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 638 ** @throws RandomOrgInsufficientRequestsError API key's server requests 639 * allowance has been exceeded. 640 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 641 * has been exceeded. 642 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 643 * received. 644 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 645 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 646 ** @throws MalformedURLException in the unlikely event something goes 647 * wrong with URL creation. @see java.net.MalformedURLException 648 ** @throws IOException @see java.io.IOException 649 * 650 */ generateBlobs(int n, int size, String format)651 public String[] generateBlobs(int n, int size, String format) throws RandomOrgSendTimeoutException, 652 RandomOrgKeyNotRunningError, 653 RandomOrgInsufficientRequestsError, 654 RandomOrgInsufficientBitsError, 655 RandomOrgBadHTTPResponseException, 656 RandomOrgRANDOMORGError, 657 RandomOrgJSONRPCError, 658 MalformedURLException, 659 IOException { 660 661 JsonObject request = new JsonObject(); 662 663 request.addProperty("n", n); 664 request.addProperty("size", size); 665 request.addProperty("format", format); 666 667 request = this.generateKeyedRequest(request, BLOB_METHOD); 668 669 JsonObject response = this.sendRequest(request); 670 671 return this.extractStrings(response); 672 } 673 674 // Signed methods for generating randomness, see: https://api.random.org/json-rpc/1/signing 675 /** 676 * Request a list (size n) of true random integers within a user-defined 677 * range from the server. Returns a * dictionary object with the parsed 678 * integer list mapped to 'data', the original response mapped to 'random', 679 * * and the response's signature mapped to 'signature'. See: 680 * https://api.random.org/json-rpc/1/signing#generateSignedIntegers 681 * 682 * * 683 * @param n how many random integers you need. Must be within the [1,1e4] 684 * range. 685 ** @param min the lower boundary for the range from which the random 686 * numbers will be picked. Must be within the [-1e9,1e9] range. 687 ** @param max the upper boundary for the range from which the random 688 * numbers will be picked. Must be within the [-1e9,1e9] range. * * @return 689 * HashMap with "random": random JsonObject, "signature": signature String, 690 * "data": random int[] * * @throws RandomOrgSendTimeoutException blocking 691 * timeout is exceeded before the request can be sent. 692 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 693 ** @throws RandomOrgInsufficientRequestsError API key's server requests 694 * allowance has been exceeded. 695 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 696 * has been exceeded. 697 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 698 * received. 699 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 700 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 701 ** @throws MalformedURLException in the unlikely event something goes 702 * wrong with URL creation. @see java.net.MalformedURLException 703 ** @throws IOException @see java.io.IOException 704 * 705 */ generateSignedIntegers(int n, int min, int max)706 public HashMap<String, Object> generateSignedIntegers(int n, int min, int max) throws RandomOrgSendTimeoutException, 707 RandomOrgKeyNotRunningError, 708 RandomOrgInsufficientRequestsError, 709 RandomOrgInsufficientBitsError, 710 RandomOrgBadHTTPResponseException, 711 RandomOrgRANDOMORGError, 712 RandomOrgJSONRPCError, 713 MalformedURLException, 714 IOException { 715 return generateSignedIntegers(n, min, max, true); 716 } 717 718 /** 719 * Request a list (size n) of true random integers within a user-defined 720 * range from the server. Returns a * dictionary object with the parsed 721 * integer list mapped to 'data', the original response mapped to 'random', 722 * * and the response's signature mapped to 'signature'. See: 723 * https://api.random.org/json-rpc/1/signing#generateSignedIntegers 724 * 725 * * 726 * @param n how many random integers you need. Must be within the [1,1e4] 727 * range. 728 ** @param min the lower boundary for the range from which the random 729 * numbers will be picked. Must be within the [-1e9,1e9] range. 730 ** @param max the upper boundary for the range from which the random 731 * numbers will be picked. Must be within the [-1e9,1e9] range. 732 ** @param replacement specifies whether the random numbers should be 733 * picked with replacement. * If True the resulting numbers may contain 734 * duplicate values, otherwise the numbers will all be unique (default 735 * True). * * @return HashMap with "random": random JsonObject, "signature": 736 * signature String, "data": random int[] * * @throws 737 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 738 * request can be sent. 739 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 740 ** @throws RandomOrgInsufficientRequestsError API key's server requests 741 * allowance has been exceeded. 742 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 743 * has been exceeded. 744 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 745 * received. 746 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 747 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 748 ** @throws MalformedURLException in the unlikely event something goes 749 * wrong with URL creation. @see java.net.MalformedURLException 750 ** @throws IOException @see java.io.IOException 751 * 752 */ generateSignedIntegers(int n, int min, int max, boolean replacement)753 public HashMap<String, Object> generateSignedIntegers(int n, int min, int max, boolean replacement) throws RandomOrgSendTimeoutException, 754 RandomOrgKeyNotRunningError, 755 RandomOrgInsufficientRequestsError, 756 RandomOrgInsufficientBitsError, 757 RandomOrgBadHTTPResponseException, 758 RandomOrgRANDOMORGError, 759 RandomOrgJSONRPCError, 760 MalformedURLException, 761 IOException { 762 763 JsonObject request = new JsonObject(); 764 765 request.addProperty("n", n); 766 request.addProperty("min", min); 767 request.addProperty("max", max); 768 request.addProperty("replacement", replacement); 769 770 request = this.generateKeyedRequest(request, SIGNED_INTEGER_METHOD); 771 772 JsonObject response = this.sendRequest(request); 773 774 HashMap<String, Object> result = new HashMap<String, Object>(); 775 result.put("data", this.extractInts(response)); 776 777 return this.extractSignedResponse(response, result); 778 } 779 780 /** 781 * Request a list (size n) of true random decimal fractions, from a uniform 782 * distribution across the [0,1] interval * with a user-defined number of 783 * decimal places from the server. Returns a dictionary object with the 784 * parsed decimal * fraction list mapped to 'data', the original response 785 * mapped to 'random', and the response's signature mapped to * 'signature'. 786 * See: 787 * https://api.random.org/json-rpc/1/signing#generateSignedDecimalFractions 788 * 789 * * * @param n how many random decimal fractions you need. Must be within 790 * the [1,1e4] range. 791 ** @param decimalPlaces the number of decimal places to use. Must be 792 * within the [1,20] range. * * @return HashMap with "random": random 793 * JsonObject, "signature": signature String, "data": random double[] 794 * 795 * @throws RandomOrgSendTimeoutException blocking timeout is exceeded before 796 * the request can be sent. 797 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 798 ** @throws RandomOrgInsufficientRequestsError API key's server requests 799 * allowance has been exceeded. 800 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 801 * has been exceeded. 802 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 803 * received. 804 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 805 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 806 ** @throws MalformedURLException in the unlikely event something goes 807 * wrong with URL creation. @see java.net.MalformedURLException 808 ** @throws IOException @see java.io.IOException 809 * 810 */ generateSignedDecimalFractions(int n, int decimalPlaces)811 public HashMap<String, Object> generateSignedDecimalFractions(int n, int decimalPlaces) throws RandomOrgSendTimeoutException, 812 RandomOrgKeyNotRunningError, 813 RandomOrgInsufficientRequestsError, 814 RandomOrgInsufficientBitsError, 815 RandomOrgBadHTTPResponseException, 816 RandomOrgRANDOMORGError, 817 RandomOrgJSONRPCError, 818 MalformedURLException, 819 IOException { 820 821 return this.generateSignedDecimalFractions(n, decimalPlaces, true); 822 } 823 824 /** 825 * Request a list (size n) of true random decimal fractions, from a uniform 826 * distribution across the [0,1] interval * with a user-defined number of 827 * decimal places from the server. Returns a dictionary object with the 828 * parsed decimal * fraction list mapped to 'data', the original response 829 * mapped to 'random', and the response's signature mapped to * 'signature'. 830 * See: 831 * https://api.random.org/json-rpc/1/signing#generateSignedDecimalFractions 832 * 833 * * * @param n how many random decimal fractions you need. Must be within 834 * the [1,1e4] range. 835 ** @param decimalPlaces the number of decimal places to use. Must be 836 * within the [1,20] range. 837 ** @param replacement specifies whether the random numbers should be 838 * picked with replacement. * If True the resulting numbers may contain 839 * duplicate values, otherwise the numbers will all be unique (default 840 * True). * * @return HashMap with "random": random JsonObject, "signature": 841 * signature String, "data": random double[] * * @throws 842 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 843 * request can be sent. 844 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 845 ** @throws RandomOrgInsufficientRequestsError API key's server requests 846 * allowance has been exceeded. 847 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 848 * has been exceeded. 849 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 850 * received. 851 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 852 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 853 ** @throws MalformedURLException in the unlikely event something goes 854 * wrong with URL creation. @see java.net.MalformedURLException 855 ** @throws IOException @see java.io.IOException 856 * 857 */ generateSignedDecimalFractions(int n, int decimalPlaces, boolean replacement)858 public HashMap<String, Object> generateSignedDecimalFractions(int n, int decimalPlaces, boolean replacement) throws RandomOrgSendTimeoutException, 859 RandomOrgKeyNotRunningError, 860 RandomOrgInsufficientRequestsError, 861 RandomOrgInsufficientBitsError, 862 RandomOrgBadHTTPResponseException, 863 RandomOrgRANDOMORGError, 864 RandomOrgJSONRPCError, 865 MalformedURLException, 866 IOException { 867 868 JsonObject request = new JsonObject(); 869 870 request.addProperty("n", n); 871 request.addProperty("decimalPlaces", decimalPlaces); 872 request.addProperty("replacement", replacement); 873 874 request = this.generateKeyedRequest(request, SIGNED_DECIMAL_FRACTION_METHOD); 875 876 JsonObject response = this.sendRequest(request); 877 878 HashMap<String, Object> result = new HashMap<String, Object>(); 879 result.put("data", this.extractDoubles(response)); 880 881 return this.extractSignedResponse(response, result); 882 } 883 884 /** 885 * Request a list (size n) of true random numbers from a Gaussian 886 * distribution (also known as a normal distribution). * The form uses a 887 * Box-Muller Transform to generate the Gaussian distribution from uniformly 888 * distributed numbers. * Returns a dictionary object with the parsed random 889 * number list mapped to 'data', the original response mapped to 'random', * 890 * and the response's signature mapped to 'signature'. See: 891 * https://api.random.org/json-rpc/1/signing#generateSignedGaussians 892 * 893 * * 894 * @param n how many random numbers you need. Must be within the [1,1e4] 895 * range. 896 ** @param mean the distribution's mean. Must be within the [-1e6,1e6] 897 * range. 898 ** @param standardDeviation the distribution's standard deviation. Must be 899 * within the [-1e6,1e6] range. 900 ** @param significantDigits the number of significant digits to use. Must 901 * be within the [2,20] range. * * @return HashMap with "random": random 902 * JsonObject, "signature": signature String, "data": random double[] 903 * 904 * @throws RandomOrgSendTimeoutException blocking timeout is exceeded before 905 * the request can be sent. 906 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 907 ** @throws RandomOrgInsufficientRequestsError API key's server requests 908 * allowance has been exceeded. 909 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 910 * has been exceeded. 911 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 912 * received. 913 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 914 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 915 ** @throws MalformedURLException in the unlikely event something goes 916 * wrong with URL creation. @see java.net.MalformedURLException 917 ** @throws IOException @see java.io.IOException 918 * 919 */ generateSignedGaussians(int n, double mean, double standardDeviation, int significantDigits)920 public HashMap<String, Object> generateSignedGaussians(int n, double mean, double standardDeviation, int significantDigits) throws RandomOrgSendTimeoutException, 921 RandomOrgKeyNotRunningError, 922 RandomOrgInsufficientRequestsError, 923 RandomOrgInsufficientBitsError, 924 RandomOrgBadHTTPResponseException, 925 RandomOrgRANDOMORGError, 926 RandomOrgJSONRPCError, 927 MalformedURLException, 928 IOException { 929 930 JsonObject request = new JsonObject(); 931 932 request.addProperty("n", n); 933 request.addProperty("mean", mean); 934 request.addProperty("standardDeviation", standardDeviation); 935 request.addProperty("significantDigits", significantDigits); 936 937 request = this.generateKeyedRequest(request, SIGNED_GAUSSIAN_METHOD); 938 939 JsonObject response = this.sendRequest(request); 940 941 HashMap<String, Object> result = new HashMap<String, Object>(); 942 result.put("data", this.extractDoubles(response)); 943 944 return this.extractSignedResponse(response, result); 945 } 946 947 /** 948 * Request a list (size n) of true random strings from the server. Returns a 949 * dictionary object with the parsed random * string list mapped to 'data', 950 * the original response mapped to 'random', and the response's signature 951 * mapped to 'signature'. * See: 952 * https://api.random.org/json-rpc/1/signing#generateSignedStrings 953 * 954 * * 955 * @param n how many random strings you need. Must be within the [1,1e4] 956 * range. 957 ** @param length the length of each string. Must be within the [1,20] 958 * range. All strings will be of the same length. 959 ** @param characters a string that contains the set of characters that are 960 * allowed to occur in the random strings. * The maximum number of 961 * characters is 80. * * @return HashMap with "random": random JsonObject, 962 * "signature": signature String, "data": random String[] * * @throws 963 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 964 * request can be sent. 965 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 966 ** @throws RandomOrgInsufficientRequestsError API key's server requests 967 * allowance has been exceeded. 968 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 969 * has been exceeded. 970 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 971 * received. 972 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 973 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 974 ** @throws MalformedURLException in the unlikely event something goes 975 * wrong with URL creation. @see java.net.MalformedURLException 976 ** @throws IOException @see java.io.IOException 977 * 978 */ generateSignedStrings(int n, int length, String characters)979 public HashMap<String, Object> generateSignedStrings(int n, int length, String characters) throws RandomOrgSendTimeoutException, 980 RandomOrgKeyNotRunningError, 981 RandomOrgInsufficientRequestsError, 982 RandomOrgInsufficientBitsError, 983 RandomOrgBadHTTPResponseException, 984 RandomOrgRANDOMORGError, 985 RandomOrgJSONRPCError, 986 MalformedURLException, 987 IOException { 988 return this.generateSignedStrings(n, length, characters, true); 989 } 990 991 /** 992 * Request a list (size n) of true random strings from the server. Returns a 993 * dictionary object with the parsed random * string list mapped to 'data', 994 * the original response mapped to 'random', and the response's signature 995 * mapped to 'signature'. * See: 996 * https://api.random.org/json-rpc/1/signing#generateSignedStrings 997 * 998 * * 999 * @param n how many random strings you need. Must be within the [1,1e4] 1000 * range. 1001 ** @param length the length of each string. Must be within the [1,20] 1002 * range. All strings will be of the same length. 1003 ** @param characters a string that contains the set of characters that are 1004 * allowed to occur in the random strings. * The maximum number of 1005 * characters is 80. 1006 ** @param replacement specifies whether the random strings should be 1007 * picked with replacement. If True the resulting * list of strings may 1008 * contain duplicates, otherwise the strings will all be unique (default 1009 * True). * * @return HashMap with "random": random JsonObject, "signature": 1010 * signature String, "data": random String[] * * @throws 1011 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 1012 * request can be sent. 1013 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 1014 ** @throws RandomOrgInsufficientRequestsError API key's server requests 1015 * allowance has been exceeded. 1016 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 1017 * has been exceeded. 1018 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 1019 * received. 1020 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 1021 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 1022 ** @throws MalformedURLException in the unlikely event something goes 1023 * wrong with URL creation. @see java.net.MalformedURLException 1024 ** @throws IOException @see java.io.IOException 1025 * 1026 */ generateSignedStrings(int n, int length, String characters, boolean replacement)1027 public HashMap<String, Object> generateSignedStrings(int n, int length, String characters, boolean replacement) throws RandomOrgSendTimeoutException, 1028 RandomOrgKeyNotRunningError, 1029 RandomOrgInsufficientRequestsError, 1030 RandomOrgInsufficientBitsError, 1031 RandomOrgBadHTTPResponseException, 1032 RandomOrgRANDOMORGError, 1033 RandomOrgJSONRPCError, 1034 MalformedURLException, 1035 IOException { 1036 1037 JsonObject request = new JsonObject(); 1038 1039 request.addProperty("n", n); 1040 request.addProperty("length", length); 1041 request.addProperty("characters", characters); 1042 request.addProperty("replacement", replacement); 1043 1044 request = this.generateKeyedRequest(request, SIGNED_STRING_METHOD); 1045 1046 JsonObject response = this.sendRequest(request); 1047 1048 HashMap<String, Object> result = new HashMap<String, Object>(); 1049 result.put("data", this.extractStrings(response)); 1050 1051 return this.extractSignedResponse(response, result); 1052 } 1053 1054 /** 1055 * Request a list (size n) of version 4 true random Universally Unique 1056 * IDentifiers (UUIDs) in accordance with * section 4.4 of RFC 4122, from 1057 * the server. Returns a dictionary object with the parsed random UUID list 1058 * mapped * to 'data', the original response mapped to 'random', and the 1059 * response's signature mapped to 'signature'. * See: 1060 * https://api.random.org/json-rpc/1/signing#generateSignedUUIDs * * @param 1061 * n how many random UUIDs you need. Must be within the [1,1e3] range. 1062 * 1063 * * 1064 * @return HashMap with "random": random JsonObject, "signature": signature 1065 * String, "data": random UUID[] * * @throws RandomOrgSendTimeoutException 1066 * blocking timeout is exceeded before the request can be sent. 1067 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 1068 ** @throws RandomOrgInsufficientRequestsError API key's server requests 1069 * allowance has been exceeded. 1070 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 1071 * has been exceeded. 1072 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 1073 * received. 1074 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 1075 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 1076 ** @throws MalformedURLException in the unlikely event something goes 1077 * wrong with URL creation. @see java.net.MalformedURLException 1078 ** @throws IOException @see java.io.IOException 1079 * 1080 */ generateSignedUUIDs(int n)1081 public HashMap<String, Object> generateSignedUUIDs(int n) throws RandomOrgSendTimeoutException, 1082 RandomOrgKeyNotRunningError, 1083 RandomOrgInsufficientRequestsError, 1084 RandomOrgInsufficientBitsError, 1085 RandomOrgBadHTTPResponseException, 1086 RandomOrgRANDOMORGError, 1087 RandomOrgJSONRPCError, 1088 MalformedURLException, 1089 IOException { 1090 1091 JsonObject request = new JsonObject(); 1092 1093 request.addProperty("n", n); 1094 1095 request = this.generateKeyedRequest(request, SIGNED_UUID_METHOD); 1096 1097 JsonObject response = this.sendRequest(request); 1098 1099 HashMap<String, Object> result = new HashMap<String, Object>(); 1100 result.put("data", this.extractUUIDs(response)); 1101 1102 return this.extractSignedResponse(response, result); 1103 } 1104 1105 /** 1106 * Request a list (size n) of Binary Large OBjects (BLOBs) containing true 1107 * random data from the server. Returns a * dictionary object with the 1108 * parsed random BLOB list mapped to 'data', the original response mapped to 1109 * 'random', * and the response's signature mapped to 'signature'. See: 1110 * https://api.random.org/json-rpc/1/signing#generateSignedBlobs * * @param 1111 * n how many random blobs you need. Must be within the [1,100] range. 1112 * 1113 ** @param size the size of each blob, measured in bits. Must be within the 1114 * [1,1048576] range and must be divisible by 8. * * @return HashMap with 1115 * "random": random JsonObject, "signature": signature String, "data": 1116 * random String[] * * @throws RandomOrgSendTimeoutException blocking 1117 * timeout is exceeded before the request can be sent. 1118 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 1119 ** @throws RandomOrgInsufficientRequestsError API key's server requests 1120 * allowance has been exceeded. 1121 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 1122 * has been exceeded. 1123 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 1124 * received. 1125 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 1126 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 1127 ** @throws MalformedURLException in the unlikely event something goes 1128 * wrong with URL creation. @see java.net.MalformedURLException 1129 ** @throws IOException @see java.io.IOException 1130 * 1131 */ generateSignedBlobs(int n, int size)1132 public HashMap<String, Object> generateSignedBlobs(int n, int size) throws RandomOrgSendTimeoutException, 1133 RandomOrgKeyNotRunningError, 1134 RandomOrgInsufficientRequestsError, 1135 RandomOrgInsufficientBitsError, 1136 RandomOrgBadHTTPResponseException, 1137 RandomOrgRANDOMORGError, 1138 RandomOrgJSONRPCError, 1139 MalformedURLException, 1140 IOException { 1141 1142 return this.generateSignedBlobs(n, size, RandomOrgClient.BLOB_FORMAT_BASE64); 1143 } 1144 1145 /** 1146 * Request a list (size n) of Binary Large OBjects (BLOBs) containing true 1147 * random data from the server. Returns a * dictionary object with the 1148 * parsed random BLOB list mapped to 'data', the original response mapped to 1149 * 'random', * and the response's signature mapped to 'signature'. See: 1150 * https://api.random.org/json-rpc/1/signing#generateSignedBlobs * * @param 1151 * n how many random blobs you need. Must be within the [1,100] range. 1152 * 1153 ** @param size the size of each blob, measured in bits. Must be within the 1154 * [1,1048576] range and must be divisible by 8. 1155 ** @param format specifies the format in which the blobs will be returned. 1156 * Values allowed are * BLOB_FORMAT_BASE64 and BLOB_FORMAT_HEX (default 1157 * BLOB_FORMAT_BASE64). * * @return HashMap with "random": random 1158 * JsonObject, "signature": signature String, "data": random String[] 1159 * 1160 * @throws RandomOrgSendTimeoutException blocking timeout is exceeded before 1161 * the request can be sent. 1162 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 1163 ** @throws RandomOrgInsufficientRequestsError API key's server requests 1164 * allowance has been exceeded. 1165 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 1166 * has been exceeded. 1167 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 1168 * received. 1169 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 1170 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 1171 ** @throws MalformedURLException in the unlikely event something goes 1172 * wrong with URL creation. @see java.net.MalformedURLException 1173 ** @throws IOException @see java.io.IOException 1174 * 1175 */ generateSignedBlobs(int n, int size, String format)1176 public HashMap<String, Object> generateSignedBlobs(int n, int size, String format) throws RandomOrgSendTimeoutException, 1177 RandomOrgKeyNotRunningError, 1178 RandomOrgInsufficientRequestsError, 1179 RandomOrgInsufficientBitsError, 1180 RandomOrgBadHTTPResponseException, 1181 RandomOrgRANDOMORGError, 1182 RandomOrgJSONRPCError, 1183 MalformedURLException, 1184 IOException { 1185 1186 JsonObject request = new JsonObject(); 1187 1188 request.addProperty("n", n); 1189 request.addProperty("size", size); 1190 request.addProperty("format", format); 1191 1192 request = this.generateKeyedRequest(request, SIGNED_BLOB_METHOD); 1193 1194 JsonObject response = this.sendRequest(request); 1195 1196 HashMap<String, Object> result = new HashMap<String, Object>(); 1197 result.put("data", this.extractStrings(response)); 1198 1199 return this.extractSignedResponse(response, result); 1200 } 1201 1202 // Signature verification for signed methods, see: https://api.random.org/json-rpc/1/signing 1203 /** 1204 * Verify the signature of a response previously received from one of the 1205 * methods in the Signed API with the * server. This is used to examine the 1206 * authenticity of numbers. Return True on verification success. * See: 1207 * https://api.random.org/json-rpc/1/signing#verifySignature * * @param 1208 * random the random field from a response returned by RANDOM.ORG through 1209 * one of the Signed API methods. 1210 * 1211 ** @param signature the signature field from the same response that the 1212 * random field originates from. * * @return verification success. * @throws 1213 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 1214 * request can be sent. 1215 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 1216 ** @throws RandomOrgInsufficientRequestsError API key's server requests 1217 * allowance has been exceeded. 1218 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 1219 * has been exceeded. 1220 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 1221 * received. 1222 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 1223 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 1224 ** @throws MalformedURLException in the unlikely event something goes 1225 * wrong with URL creation. @see java.net.MalformedURLException 1226 ** @throws IOException @see java.io.IOException 1227 * 1228 */ verifySignature(JsonObject random, String signature)1229 public boolean verifySignature(JsonObject random, String signature) throws RandomOrgSendTimeoutException, 1230 RandomOrgKeyNotRunningError, 1231 RandomOrgInsufficientRequestsError, 1232 RandomOrgInsufficientBitsError, 1233 RandomOrgBadHTTPResponseException, 1234 RandomOrgRANDOMORGError, 1235 RandomOrgJSONRPCError, 1236 MalformedURLException, 1237 IOException { 1238 1239 JsonObject request = new JsonObject(); 1240 1241 request.add("random", random); 1242 request.addProperty("signature", signature); 1243 1244 request = this.generateRequest(request, VERIFY_SIGNATURE_METHOD); 1245 1246 JsonObject response = this.sendRequest(request); 1247 1248 return this.extractVerificationResponse(response); 1249 } 1250 1251 // Methods used to create a cache for any given randomness request. 1252 /** 1253 * Get a RandomOrgCache to obtain random integers. The RandomOrgCache can be 1254 * polled for new results conforming to * the output format of the input 1255 * request. RandomOrgCache type is same as expected return value. * * @param 1256 * n how many random integers you need. Must be within the [1,1e4] range. 1257 * 1258 ** @param min the lower boundary for the range from which the random 1259 * numbers will be picked. Must be within the [-1e9,1e9] range. 1260 ** @param max the upper boundary for the range from which the random 1261 * numbers will be picked. Must be within the [-1e9,1e9] range. * * @return 1262 * RandomOrgCache<int[]> 1263 * 1264 */ createIntegerCache(int n, int min, int max)1265 public RandomOrgCache<int[]> createIntegerCache(int n, int min, int max) { 1266 return this.createIntegerCache(n, min, max, true, 20); 1267 } 1268 1269 /** 1270 * Get a RandomOrgCache to obtain random integers. The RandomOrgCache can be 1271 * polled for new results conforming to * the output format of the input 1272 * request. RandomOrgCache type is same as expected return value. * * @param 1273 * n how many random integers you need. Must be within the [1,1e4] range. 1274 * 1275 ** @param min the lower boundary for the range from which the random 1276 * numbers will be picked. Must be within the [-1e9,1e9] range. 1277 ** @param max the upper boundary for the range from which the random 1278 * numbers will be picked. Must be within the [-1e9,1e9] range. 1279 ** @param replacement specifies whether the random numbers should be 1280 * picked with replacement. * If True the resulting numbers may contain 1281 * duplicate values, otherwise the numbers will all be unique (default 1282 * True). 1283 ** @param cacheSize number of result-sets for the cache to try to maintain 1284 * at any given time (default 20, minimum 2). * * @return 1285 * RandomOrgCache<int[]> 1286 * 1287 */ createIntegerCache(int n, int min, int max, boolean replacement, int cacheSize)1288 public RandomOrgCache<int[]> createIntegerCache(int n, int min, int max, boolean replacement, int cacheSize) { 1289 if (cacheSize < 2) { 1290 cacheSize = 2; 1291 } 1292 1293 JsonObject request = new JsonObject(); 1294 1295 request.addProperty("min", min); 1296 request.addProperty("max", max); 1297 request.addProperty("replacement", replacement); 1298 1299 int bulkN = 0; 1300 1301 // If possible, make requests more efficient by bulk-ordering from the server. 1302 // initially set at cache_size/2, but cache will auto-shrink bulk request size if requests can't be fulfilled. 1303 if (replacement) { 1304 bulkN = cacheSize / 2; 1305 request.addProperty("n", bulkN * n); 1306 1307 // not possible to make the request more efficient 1308 } else { 1309 request.addProperty("n", n); 1310 } 1311 1312 // get the request object for use in all requests from this cache 1313 request = this.generateKeyedRequest(request, INTEGER_METHOD); 1314 1315 // max single request size, in bits, for adjusting bulk requests later 1316 int maxRequestSize = (int) Math.ceil(Math.log(max - min + 1) / Math.log(2) * n); 1317 1318 return new RandomOrgCache<int[]>( 1319 new JsonObjectInputCallable<JsonObject>() { 1320 @Override 1321 public JsonObject call() throws RandomOrgSendTimeoutException, RandomOrgKeyNotRunningError, RandomOrgInsufficientRequestsError, RandomOrgInsufficientBitsError, RandomOrgBadHTTPResponseException, RandomOrgRANDOMORGError, RandomOrgJSONRPCError, MalformedURLException, IOException { 1322 return RandomOrgClient.this.sendRequest(this.input); 1323 } 1324 }, new JsonObjectInputCallable<int[]>() { 1325 @Override 1326 public int[] call() { 1327 return RandomOrgClient.this.extractInts(this.input); 1328 } 1329 }, 1330 request, cacheSize, bulkN, n, maxRequestSize); 1331 } 1332 1333 /** 1334 * Get a RandomOrgCache to obtain random decimal fractions. The 1335 * RandomOrgCache can be polled for new results * conforming to the output 1336 * format of the input request. RandomOrgCache type is same as expected 1337 * return value. * * @param n how many random decimal fractions you need. 1338 * Must be within the [1,1e4] range. 1339 * 1340 ** @param decimalPlaces the number of decimal places to use. Must be 1341 * within the [1,20] range. * * @return RandomOrgCache<double[]> 1342 * 1343 */ 1344 public RandomOrgCache<double[]> createDecimalFractionCache(int n, int decimalPlaces) { 1345 return this.createDecimalFractionCache(n, decimalPlaces, true, 20); 1346 } 1347 1348 /** 1349 * Get a RandomOrgCache to obtain random decimal fractions. The 1350 * RandomOrgCache can be polled for new results * conforming to the output 1351 * format of the input request. RandomOrgCache type is same as expected 1352 * return value. * * @param n how many random decimal fractions you need. 1353 * Must be within the [1,1e4] range. 1354 * 1355 ** @param decimalPlaces the number of decimal places to use. Must be 1356 * within the [1,20] range. 1357 ** @param replacement specifies whether the random numbers should be 1358 * picked with replacement. * If True the resulting numbers may contain 1359 * duplicate values, otherwise the numbers will all be unique (default 1360 * True). 1361 ** @param cacheSize number of result-sets for the cache to try to maintain 1362 * at any given time (default 20, minimum 2). * * @return 1363 * RandomOrgCache<double[]> 1364 * 1365 */ 1366 public RandomOrgCache<double[]> createDecimalFractionCache(int n, int decimalPlaces, boolean replacement, int cacheSize) { 1367 if (cacheSize < 2) { 1368 cacheSize = 2; 1369 } 1370 1371 JsonObject request = new JsonObject(); 1372 1373 request.addProperty("decimalPlaces", decimalPlaces); 1374 request.addProperty("replacement", replacement); 1375 1376 int bulkN = 0; 1377 1378 // If possible, make requests more efficient by bulk-ordering from the server. 1379 // initially set at cache_size/2, but cache will auto-shrink bulk request size if requests can't be fulfilled. 1380 if (replacement) { 1381 bulkN = cacheSize / 2; 1382 request.addProperty("n", bulkN * n); 1383 1384 // not possible to make the request more efficient 1385 } else { 1386 request.addProperty("n", n); 1387 } 1388 1389 // get the request object for use in all requests from this cache 1390 request = this.generateKeyedRequest(request, DECIMAL_FRACTION_METHOD); 1391 1392 // max single request size, in bits, for adjusting bulk requests later 1393 int maxRequestSize = (int) Math.ceil(Math.log(10) / Math.log(2) * decimalPlaces * n); 1394 1395 return new RandomOrgCache<double[]>( 1396 new JsonObjectInputCallable<JsonObject>() { 1397 @Override 1398 public JsonObject call() throws RandomOrgSendTimeoutException, RandomOrgKeyNotRunningError, RandomOrgInsufficientRequestsError, RandomOrgInsufficientBitsError, RandomOrgBadHTTPResponseException, RandomOrgRANDOMORGError, RandomOrgJSONRPCError, MalformedURLException, IOException { 1399 return RandomOrgClient.this.sendRequest(this.input); 1400 } 1401 }, new JsonObjectInputCallable<double[]>() { 1402 @Override 1403 public double[] call() { 1404 return RandomOrgClient.this.extractDoubles(this.input); 1405 } 1406 }, 1407 request, cacheSize, bulkN, n, maxRequestSize); 1408 } 1409 1410 /** 1411 * Get a RandomOrgCache to obtain random numbers. The RandomOrgCache can be 1412 * polled for new results * conforming to the output format of the input 1413 * request. RandomOrgCache type is same as expected return value. * * @param 1414 * n how many random numbers you need. Must be within the [1,1e4] range. 1415 * 1416 ** @param mean the distribution's mean. Must be within the [-1e6,1e6] 1417 * range. 1418 ** @param standardDeviation the distribution's standard deviation. Must be 1419 * within the [-1e6,1e6] range. 1420 ** @param significantDigits the number of significant digits to use. Must 1421 * be within the [2,20] range. * * @return RandomOrgCache<double[]> 1422 * 1423 */ 1424 public RandomOrgCache<double[]> createGaussianCache(int n, double mean, double standardDeviation, int significantDigits) { 1425 return this.createGaussianCache(n, mean, standardDeviation, significantDigits, 20); 1426 } 1427 1428 /** 1429 * Get a RandomOrgCache to obtain random numbers. The RandomOrgCache can be 1430 * polled for new results * conforming to the output format of the input 1431 * request. RandomOrgCache type is same as expected return value. * * @param 1432 * n how many random numbers you need. Must be within the [1,1e4] range. 1433 * 1434 ** @param mean the distribution's mean. Must be within the [-1e6,1e6] 1435 * range. 1436 ** @param standardDeviation the distribution's standard deviation. Must be 1437 * within the [-1e6,1e6] range. 1438 ** @param significantDigits the number of significant digits to use. Must 1439 * be within the [2,20] range. 1440 ** @param cacheSize number of result-sets for the cache to try to maintain 1441 * at any given time (default 20, minimum 2). * * @return 1442 * RandomOrgCache<double[]> 1443 * 1444 */ 1445 public RandomOrgCache<double[]> createGaussianCache(int n, double mean, double standardDeviation, int significantDigits, int cacheSize) { 1446 if (cacheSize < 2) { 1447 cacheSize = 2; 1448 } 1449 1450 JsonObject request = new JsonObject(); 1451 1452 request.addProperty("mean", mean); 1453 request.addProperty("standardDeviation", standardDeviation); 1454 request.addProperty("significantDigits", significantDigits); 1455 1456 int bulkN = 0; 1457 1458 // make requests more efficient by bulk-ordering from the server. 1459 // initially set at cache_size/2, but cache will auto-shrink bulk request size if requests can't be fulfilled. 1460 bulkN = cacheSize / 2; 1461 request.addProperty("n", bulkN * n); 1462 1463 // get the request object for use in all requests from this cache 1464 request = this.generateKeyedRequest(request, GAUSSIAN_METHOD); 1465 1466 // max single request size, in bits, for adjusting bulk requests later 1467 int maxRequestSize = (int) Math.ceil(Math.log(Math.pow(10, significantDigits)) / Math.log(2) * n); 1468 1469 return new RandomOrgCache<double[]>( 1470 new JsonObjectInputCallable<JsonObject>() { 1471 @Override 1472 public JsonObject call() throws RandomOrgSendTimeoutException, RandomOrgKeyNotRunningError, RandomOrgInsufficientRequestsError, RandomOrgInsufficientBitsError, RandomOrgBadHTTPResponseException, RandomOrgRANDOMORGError, RandomOrgJSONRPCError, MalformedURLException, IOException { 1473 return RandomOrgClient.this.sendRequest(this.input); 1474 } 1475 }, new JsonObjectInputCallable<double[]>() { 1476 @Override 1477 public double[] call() { 1478 return RandomOrgClient.this.extractDoubles(this.input); 1479 } 1480 }, 1481 request, cacheSize, bulkN, n, maxRequestSize); 1482 } 1483 1484 /** 1485 * Get a RandomOrgCache to obtain random strings. The RandomOrgCache can be 1486 * polled for new results * conforming to the output format of the input 1487 * request. RandomOrgCache type is same as expected return value. * * @param 1488 * n how many random strings you need. Must be within the [1,1e4] range. 1489 * 1490 ** @param length the length of each string. Must be within the [1,20] 1491 * range. All strings will be of the same length. 1492 ** @param characters a string that contains the set of characters that are 1493 * allowed to occur in the random strings. * The maximum number of 1494 * characters is 80. * * @return RandomOrgCache<String[]> 1495 * 1496 */ 1497 public RandomOrgCache<String[]> createStringCache(int n, int length, String characters) { 1498 return this.createStringCache(n, length, characters, true, 20); 1499 } 1500 1501 /** 1502 * Get a RandomOrgCache to obtain random strings. The RandomOrgCache can be 1503 * polled for new results * conforming to the output format of the input 1504 * request. RandomOrgCache type is same as expected return value. * * @param 1505 * n how many random strings you need. Must be within the [1,1e4] range. 1506 * 1507 ** @param length the length of each string. Must be within the [1,20] 1508 * range. All strings will be of the same length. 1509 ** @param characters a string that contains the set of characters that are 1510 * allowed to occur in the random strings. * The maximum number of 1511 * characters is 80. 1512 ** @param replacement specifies whether the random strings should be 1513 * picked with replacement. If True the resulting * list of strings may 1514 * contain duplicates, otherwise the strings will all be unique (default 1515 * True). 1516 ** @param cacheSize number of result-sets for the cache to try to maintain 1517 * at any given time (default 20, minimum 2). * * @return 1518 * RandomOrgCache<String[]> 1519 * 1520 */ 1521 public RandomOrgCache<String[]> createStringCache(int n, int length, String characters, boolean replacement, int cacheSize) { 1522 if (cacheSize < 2) { 1523 cacheSize = 2; 1524 } 1525 1526 JsonObject request = new JsonObject(); 1527 1528 request.addProperty("length", length); 1529 request.addProperty("characters", characters); 1530 request.addProperty("replacement", replacement); 1531 1532 int bulkN = 0; 1533 1534 // If possible, make requests more efficient by bulk-ordering from the server. 1535 // initially set at cache_size/2, but cache will auto-shrink bulk request size if requests can't be fulfilled. 1536 if (replacement) { 1537 bulkN = cacheSize / 2; 1538 request.addProperty("n", bulkN * n); 1539 1540 // not possible to make the request more efficient 1541 } else { 1542 request.addProperty("n", n); 1543 } 1544 1545 // get the request object for use in all requests from this cache 1546 request = this.generateKeyedRequest(request, STRING_METHOD); 1547 1548 // max single request size, in bits, for adjusting bulk requests later 1549 int maxRequestSize = (int) Math.ceil(Math.log(characters.length()) / Math.log(2) * length * n); 1550 1551 return new RandomOrgCache<String[]>( 1552 new JsonObjectInputCallable<JsonObject>() { 1553 @Override 1554 public JsonObject call() throws RandomOrgSendTimeoutException, RandomOrgKeyNotRunningError, RandomOrgInsufficientRequestsError, RandomOrgInsufficientBitsError, RandomOrgBadHTTPResponseException, RandomOrgRANDOMORGError, RandomOrgJSONRPCError, MalformedURLException, IOException { 1555 return RandomOrgClient.this.sendRequest(this.input); 1556 } 1557 }, new JsonObjectInputCallable<String[]>() { 1558 @Override 1559 public String[] call() { 1560 return RandomOrgClient.this.extractStrings(this.input); 1561 } 1562 }, 1563 request, cacheSize, bulkN, n, maxRequestSize); 1564 } 1565 1566 /** 1567 * Get a RandomOrgCache to obtain UUIDs. The RandomOrgCache can be polled 1568 * for new results conforming to the * output format of the input request. 1569 * RandomOrgCache type is same as expected return value. * * @param n how 1570 * many random UUIDs you need. Must be within the [1,1e3] range. * * @return 1571 * RandomOrgCache<UUID[]> 1572 * 1573 */ 1574 public RandomOrgCache<UUID[]> createUUIDCache(int n) { 1575 return this.createUUIDCache(n, 10); 1576 } 1577 1578 /** 1579 * Get a RandomOrgCache to obtain UUIDs. The RandomOrgCache can be polled 1580 * for new results conforming to the * output format of the input request. 1581 * RandomOrgCache type is same as expected return value. * * @param n how 1582 * many random UUIDs you need. Must be within the [1,1e3] range. 1583 * 1584 ** @param cacheSize number of result-sets for the cache to try to maintain 1585 * at any given time (default 10, minimum 2). * * @return 1586 * RandomOrgCache<UUID[]> 1587 * 1588 */ 1589 public RandomOrgCache<UUID[]> createUUIDCache(int n, int cacheSize) { 1590 if (cacheSize < 2) { 1591 cacheSize = 2; 1592 } 1593 1594 JsonObject request = new JsonObject(); 1595 1596 int bulkN = 0; 1597 1598 // make requests more efficient by bulk-ordering from the server. 1599 // initially set at cache_size/2, but cache will auto-shrink bulk request size if requests can't be fulfilled. 1600 bulkN = cacheSize / 2; 1601 request.addProperty("n", bulkN * n); 1602 1603 // get the request object for use in all requests from this cache 1604 request = this.generateKeyedRequest(request, UUID_METHOD); 1605 1606 // max single request size, in bits, for adjusting bulk requests later 1607 int maxRequestSize = n * UUID_SIZE; 1608 1609 return new RandomOrgCache<UUID[]>( 1610 new JsonObjectInputCallable<JsonObject>() { 1611 @Override 1612 public JsonObject call() throws RandomOrgSendTimeoutException, RandomOrgKeyNotRunningError, RandomOrgInsufficientRequestsError, RandomOrgInsufficientBitsError, RandomOrgBadHTTPResponseException, RandomOrgRANDOMORGError, RandomOrgJSONRPCError, MalformedURLException, IOException { 1613 return RandomOrgClient.this.sendRequest(this.input); 1614 } 1615 }, new JsonObjectInputCallable<UUID[]>() { 1616 @Override 1617 public UUID[] call() { 1618 return RandomOrgClient.this.extractUUIDs(this.input); 1619 } 1620 }, 1621 request, cacheSize, bulkN, n, maxRequestSize); 1622 } 1623 1624 /** 1625 * Get a RandomOrgCache to obtain random blobs. The RandomOrgCache can be 1626 * polled for new results conforming * to the output format of the input 1627 * request. RandomOrgCache type is same as expected return value. * * @param 1628 * n how many random blobs you need. Must be within the [1,100] range. 1629 * 1630 ** @param size the size of each blob, measured in bits. Must be within the 1631 * [1,1048576] range and must be divisible by 8. * * @return 1632 * RandomOrgCache<String[]> 1633 * 1634 */ 1635 public RandomOrgCache<String[]> createBlobCache(int n, int size) { 1636 return this.createBlobCache(n, size, RandomOrgClient.BLOB_FORMAT_BASE64, 10); 1637 } 1638 1639 /** 1640 * Get a RandomOrgCache to obtain random blobs. The RandomOrgCache can be 1641 * polled for new results conforming * to the output format of the input 1642 * request. RandomOrgCache type is same as expected return value. * * @param 1643 * n how many random blobs you need. Must be within the [1,100] range. 1644 * 1645 ** @param size the size of each blob, measured in bits. Must be within the 1646 * [1,1048576] range and must be divisible by 8. 1647 ** @param format specifies the format in which the blobs will be returned. 1648 * Values allowed are * BLOB_FORMAT_BASE64 and BLOB_FORMAT_HEX (default 1649 * BLOB_FORMAT_BASE64). 1650 ** @param cacheSize number of result-sets for the cache to try to maintain 1651 * at any given time (default 10, minimum 2). * * @return 1652 * RandomOrgCache<String[]> 1653 * 1654 */ 1655 public RandomOrgCache<String[]> createBlobCache(int n, int size, String format, int cacheSize) { 1656 if (cacheSize < 2) { 1657 cacheSize = 2; 1658 } 1659 1660 JsonObject request = new JsonObject(); 1661 1662 request.addProperty("size", size); 1663 request.addProperty("format", format); 1664 1665 int bulkN = 0; 1666 1667 // make requests more efficient by bulk-ordering from the server. 1668 // initially set at cache_size/2, but cache will auto-shrink bulk request size if requests can't be fulfilled. 1669 bulkN = cacheSize / 2; 1670 request.addProperty("n", bulkN * n); 1671 1672 // get the request object for use in all requests from this cache 1673 request = this.generateKeyedRequest(request, BLOB_METHOD); 1674 1675 // max single request size, in bits, for adjusting bulk requests later 1676 int maxRequestSize = n * size; 1677 1678 return new RandomOrgCache<String[]>( 1679 new JsonObjectInputCallable<JsonObject>() { 1680 @Override 1681 public JsonObject call() throws RandomOrgSendTimeoutException, RandomOrgKeyNotRunningError, RandomOrgInsufficientRequestsError, RandomOrgInsufficientBitsError, RandomOrgBadHTTPResponseException, RandomOrgRANDOMORGError, RandomOrgJSONRPCError, MalformedURLException, IOException { 1682 return RandomOrgClient.this.sendRequest(this.input); 1683 } 1684 }, new JsonObjectInputCallable<String[]>() { 1685 @Override 1686 public String[] call() { 1687 return RandomOrgClient.this.extractStrings(this.input); 1688 } 1689 }, 1690 request, cacheSize, bulkN, n, maxRequestSize); 1691 } 1692 1693 // Methods for accessing server usage statistics. 1694 /** 1695 * Return the (estimated) number of remaining API requests available to the 1696 * client. If cached * usage info is older than 1697 * ALLOWANCE_STATE_REFRESH_SECONDS fresh info is obtained from server. * If 1698 * fresh info has to be obtained the following exceptions can be raised. 1699 * 1700 * * 1701 * @return number of requests remaining. * * @throws 1702 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 1703 * request can be sent. 1704 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 1705 ** @throws RandomOrgInsufficientRequestsError API key's server requests 1706 * allowance has been exceeded. 1707 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 1708 * has been exceeded. 1709 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 1710 * received. 1711 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 1712 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 1713 ** @throws MalformedURLException in the unlikely event something goes 1714 * wrong with URL creation. @see java.net.MalformedURLException 1715 ** @throws IOException @see java.io.IOException 1716 * 1717 */ 1718 public int getRequestsLeft() throws RandomOrgSendTimeoutException, 1719 RandomOrgKeyNotRunningError, 1720 RandomOrgInsufficientRequestsError, 1721 RandomOrgInsufficientBitsError, 1722 RandomOrgBadHTTPResponseException, 1723 RandomOrgRANDOMORGError, 1724 RandomOrgJSONRPCError, 1725 MalformedURLException, 1726 IOException { 1727 if (this.requestsLeft < 0 || System.currentTimeMillis() > (this.lastResponseReceivedTime + RandomOrgClient.ALLOWANCE_STATE_REFRESH_SECONDS)) { 1728 this.getUsage(); 1729 } 1730 return this.requestsLeft; 1731 } 1732 1733 /** 1734 * Return the (estimated) number of remaining true random bits available to 1735 * the client. If cached * usage info is older than 1736 * ALLOWANCE_STATE_REFRESH_SECONDS fresh info is obtained from server. * If 1737 * fresh info has to be obtained the following exceptions can be raised. 1738 * 1739 * * 1740 * @return number of bits remaining. * * @throws 1741 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 1742 * request can be sent. 1743 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 1744 ** @throws RandomOrgInsufficientRequestsError API key's server requests 1745 * allowance has been exceeded. 1746 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 1747 * has been exceeded. 1748 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 1749 * received. 1750 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 1751 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 1752 ** @throws MalformedURLException in the unlikely event something goes 1753 * wrong with URL creation. @see java.net.MalformedURLException 1754 ** @throws IOException @see java.io.IOException 1755 * 1756 */ 1757 public int getBitsLeft() throws RandomOrgSendTimeoutException, 1758 RandomOrgKeyNotRunningError, 1759 RandomOrgInsufficientRequestsError, 1760 RandomOrgInsufficientBitsError, 1761 RandomOrgBadHTTPResponseException, 1762 RandomOrgRANDOMORGError, 1763 RandomOrgJSONRPCError, 1764 MalformedURLException, 1765 IOException { 1766 if (this.bitsLeft < 0 || System.currentTimeMillis() > (this.lastResponseReceivedTime + RandomOrgClient.ALLOWANCE_STATE_REFRESH_SECONDS)) { 1767 this.getUsage(); 1768 } 1769 return this.bitsLeft; 1770 } 1771 1772 // Server communications & helper functions. 1773 /** 1774 * Issue a getUsage request to update bits and requests left. * * @throws 1775 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 1776 * request can be sent. 1777 * 1778 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 1779 ** @throws RandomOrgInsufficientRequestsError API key's server requests 1780 * allowance has been exceeded. 1781 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 1782 * has been exceeded. 1783 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 1784 * received. 1785 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 1786 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 1787 ** @throws MalformedURLException in the unlikely event something goes 1788 * wrong with URL creation. @see java.net.MalformedURLException 1789 ** @throws IOException @see java.io.IOException 1790 * 1791 */ 1792 private void getUsage() throws RandomOrgSendTimeoutException, 1793 RandomOrgKeyNotRunningError, 1794 RandomOrgInsufficientRequestsError, 1795 RandomOrgInsufficientBitsError, 1796 RandomOrgBadHTTPResponseException, 1797 RandomOrgRANDOMORGError, 1798 RandomOrgJSONRPCError, 1799 MalformedURLException, 1800 IOException { 1801 1802 JsonObject request = new JsonObject(); 1803 1804 request = this.generateKeyedRequest(request, GET_USAGE_METHOD); 1805 1806 this.sendRequest(request); 1807 } 1808 1809 /** 1810 * Add generic request parameters and API key to custom request. * * @param 1811 * params custom parameters to generate request around. 1812 * 1813 ** @param method to send request to. * * @return fleshed out JSON request. 1814 * 1815 */ 1816 private JsonObject generateKeyedRequest(JsonObject params, String method) { 1817 1818 params.addProperty("apiKey", this.apiKey); 1819 1820 JsonObject request = new JsonObject(); 1821 1822 request.addProperty("jsonrpc", "2.0"); 1823 request.addProperty("method", method); 1824 request.add("params", params); 1825 request.addProperty("id", UUID.randomUUID().toString()); 1826 1827 return request; 1828 } 1829 1830 /** 1831 * Add generic request parameters to custom request. * * @param params 1832 * custom parameters to generate request around. 1833 * 1834 ** @param method to send request to. * * @return fleshed out JSON request. 1835 * 1836 */ 1837 private JsonObject generateRequest(JsonObject params, String method) { 1838 1839 JsonObject request = new JsonObject(); 1840 1841 request.addProperty("jsonrpc", "2.0"); 1842 request.addProperty("method", method); 1843 request.add("params", params); 1844 request.addProperty("id", UUID.randomUUID().toString()); 1845 1846 return request; 1847 } 1848 1849 /** 1850 * Extracts int[] from JSON response. * * @param response JSON from which to 1851 * extract data. * * @return extracted int[]. 1852 * 1853 */ 1854 protected int[] extractInts(JsonObject response) { 1855 1856 JsonArray data = this.extractResponse(response); 1857 int[] randoms = new int[data.size()]; 1858 1859 for (int i = 0; i < randoms.length; i++) { 1860 randoms[i] = data.get(i).getAsInt(); 1861 } 1862 1863 return randoms; 1864 } 1865 1866 /** 1867 * Extracts double[] from JSON response. * * @param response JSON from which 1868 * to extract data. * * @return extracted double[]. 1869 * 1870 */ 1871 protected double[] extractDoubles(JsonObject response) { 1872 1873 JsonArray data = this.extractResponse(response); 1874 double[] randoms = new double[data.size()]; 1875 1876 for (int i = 0; i < randoms.length; i++) { 1877 randoms[i] = data.get(i).getAsDouble(); 1878 } 1879 1880 return randoms; 1881 } 1882 1883 /** 1884 * Extracts String[] from JSON response. * * @param response JSON from which 1885 * to extract data. * * @return extracted String[]. 1886 * 1887 */ 1888 protected String[] extractStrings(JsonObject response) { 1889 1890 JsonArray data = this.extractResponse(response); 1891 String[] randoms = new String[data.size()]; 1892 1893 for (int i = 0; i < randoms.length; i++) { 1894 randoms[i] = data.get(i).getAsString(); 1895 } 1896 1897 return randoms; 1898 } 1899 1900 /** 1901 * Extracts UUID[] from JSON response. * * @param response JSON from which 1902 * to extract data. * * @return extracted UUID[]. 1903 * 1904 */ 1905 protected UUID[] extractUUIDs(JsonObject response) { 1906 1907 JsonArray data = this.extractResponse(response); 1908 UUID[] randoms = new UUID[data.size()]; 1909 1910 for (int i = 0; i < randoms.length; i++) { 1911 randoms[i] = UUID.fromString(data.get(i).getAsString()); 1912 } 1913 1914 return randoms; 1915 } 1916 1917 /** 1918 * Gets random data as separate from response JSON. * * @param response JSON 1919 * from which to extract data. * * @return JsonArray of random data. 1920 * 1921 */ 1922 private JsonArray extractResponse(JsonObject response) { 1923 return response.get("result").getAsJsonObject().get("random").getAsJsonObject().get("data").getAsJsonArray(); 1924 } 1925 1926 /** 1927 * Gets signing data from response JSON and add to result HashMap. 1928 * 1929 * * 1930 * @param response JSON from which to extract data. 1931 ** @param result to add signing data to. * * @return the passed in result 1932 * HasMap. 1933 * 1934 */ 1935 private HashMap<String, Object> extractSignedResponse(JsonObject response, HashMap<String, Object> result) { 1936 result.put("random", response.get("result").getAsJsonObject().get("random").getAsJsonObject()); 1937 result.put("signature", response.get("result").getAsJsonObject().get("signature").getAsString()); 1938 1939 return result; 1940 } 1941 1942 /** 1943 * Gets verification response as separate from response JSON. * * @param 1944 * response JSON from which to extract verification response. * * @return 1945 * verification success. 1946 * 1947 */ 1948 private boolean extractVerificationResponse(JsonObject response) { 1949 1950 return response.get("result").getAsJsonObject().get("authenticity").getAsBoolean(); 1951 } 1952 1953 /** 1954 * Send request as determined by serialized boolean. * * @param request JSON 1955 * to send. * * @return JsonObject response. * * @throws 1956 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 1957 * request can be sent. 1958 * 1959 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 1960 ** @throws RandomOrgInsufficientRequestsError API key's server requests 1961 * allowance has been exceeded. 1962 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 1963 * has been exceeded. 1964 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 1965 * received. 1966 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 1967 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 1968 ** @throws MalformedURLException in the unlikely event something goes 1969 * wrong with URL creation. @see java.net.MalformedURLException 1970 ** @throws IOException @see java.io.IOException 1971 * 1972 */ 1973 protected JsonObject sendRequest(JsonObject request) throws RandomOrgSendTimeoutException, 1974 RandomOrgKeyNotRunningError, 1975 RandomOrgInsufficientRequestsError, 1976 RandomOrgInsufficientBitsError, 1977 RandomOrgBadHTTPResponseException, 1978 RandomOrgRANDOMORGError, 1979 RandomOrgJSONRPCError, 1980 MalformedURLException, 1981 IOException { 1982 1983 return this.serialized ? this.sendSerializedRequest(request) : this.sendUnserializedRequest(request); 1984 } 1985 1986 /** 1987 * Immediate call to server. Networking is run on a separate thread as 1988 * Android platform disallows networking on the main thread. * * @param 1989 * request JSON to send. * * @return JsonObject response. * * @throws 1990 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 1991 * request can be sent. 1992 * 1993 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 1994 ** @throws RandomOrgInsufficientRequestsError API key's server requests 1995 * allowance has been exceeded. 1996 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 1997 * has been exceeded. 1998 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 1999 * received. 2000 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 2001 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 2002 ** @throws MalformedURLException in the unlikely event something goes 2003 * wrong with URL creation. @see java.net.MalformedURLException 2004 ** @throws IOException @see java.io.IOException 2005 * 2006 */ 2007 private JsonObject sendUnserializedRequest(JsonObject request) throws RandomOrgSendTimeoutException, 2008 RandomOrgKeyNotRunningError, 2009 RandomOrgInsufficientRequestsError, 2010 RandomOrgInsufficientBitsError, 2011 RandomOrgBadHTTPResponseException, 2012 RandomOrgRANDOMORGError, 2013 RandomOrgJSONRPCError, 2014 MalformedURLException, 2015 IOException { 2016 2017 // Send request immediately. 2018 UnserializedRunnable r = new UnserializedRunnable(request); 2019 new Thread(r).start(); 2020 2021 // Wait for response to arrive. 2022 while (r.getData() == null) { 2023 try { 2024 Thread.sleep(50); 2025 } catch (InterruptedException e) { 2026 LOGGER.log(Level.INFO, "Client interrupted while waiting for server to return a response."); 2027 } 2028 } 2029 2030 // Raise any thrown exceptions. 2031 if (r.getData().containsKey("exception")) { 2032 this.throwException((Exception) r.getData().get("exception")); 2033 } 2034 2035 // Return response. 2036 return (JsonObject) r.getData().get("response"); 2037 } 2038 2039 /** 2040 * Add request to queue to be executed by networking thread one-by-one. * 2041 * Method blocks until this request receives a response or times out. 2042 * 2043 * * 2044 * @param request JSON to send. * * @return JsonObject response. * * @throws 2045 * RandomOrgSendTimeoutException blocking timeout is exceeded before the 2046 * request can be sent. 2047 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 2048 ** @throws RandomOrgInsufficientRequestsError API key's server requests 2049 * allowance has been exceeded. 2050 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 2051 * has been exceeded. 2052 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 2053 * received. 2054 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 2055 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 2056 ** @throws MalformedURLException in the unlikely event something goes 2057 * wrong with URL creation. @see java.net.MalformedURLException 2058 ** @throws IOException @see java.io.IOException 2059 * 2060 */ 2061 private JsonObject sendSerializedRequest(JsonObject request) throws RandomOrgSendTimeoutException, 2062 RandomOrgKeyNotRunningError, 2063 RandomOrgInsufficientRequestsError, 2064 RandomOrgInsufficientBitsError, 2065 RandomOrgBadHTTPResponseException, 2066 RandomOrgRANDOMORGError, 2067 RandomOrgJSONRPCError, 2068 MalformedURLException, 2069 IOException { 2070 2071 // Add request to the queue with it's own lock. 2072 Object requestLock = new Object(); 2073 2074 HashMap<String, Object> data = new HashMap<String, Object>(); 2075 data.put("lock", requestLock); 2076 data.put("request", request); 2077 data.put("response", null); 2078 data.put("exception", null); 2079 2080 synchronized (this.serializedQueue) { 2081 this.serializedQueue.offer(data); 2082 this.serializedQueue.notify(); 2083 } 2084 2085 // Wait on the lock for the specified blocking timeout. 2086 synchronized (requestLock) { 2087 try { 2088 if (this.blockingTimeout == -1) { 2089 requestLock.wait(); 2090 } else { 2091 requestLock.wait(this.blockingTimeout); 2092 } 2093 } catch (InterruptedException e) { 2094 LOGGER.log(Level.INFO, "Client interrupted while waiting for request to be sent."); 2095 } 2096 2097 // Lock has now either been notified or timed out. Examine data to determine which and react accordingly. 2098 // Request wasn't sent in time, cancel and raise exception. 2099 if (data.get("response") == null && data.get("exception") == null) { 2100 data.put("request", null); 2101 throw new RandomOrgSendTimeoutException("The maximum allowed blocking time of " + this.blockingTimeout 2102 + "millis has been exceeded while waiting for a synchronous request to send."); 2103 } 2104 2105 // Exception on sending request. 2106 if (data.get("exception") != null) { 2107 this.throwException((Exception) data.get("exception")); 2108 } 2109 2110 // Request was successful. 2111 return (JsonObject) data.get("response"); 2112 } 2113 } 2114 2115 /** 2116 * Thread to synchronously send requests in queue. 2117 */ 2118 protected void threadedRequestSending() { 2119 2120 // Thread to execute queued requests. 2121 while (true) { 2122 2123 HashMap<String, Object> request; 2124 2125 synchronized (this.serializedQueue) { 2126 // Block and wait for a request. 2127 if (this.serializedQueue.isEmpty()) { 2128 try { 2129 this.serializedQueue.wait(); 2130 } catch (InterruptedException e) { 2131 LOGGER.log(Level.INFO, "Client thread interrupted while waiting for a request to send."); 2132 } 2133 } 2134 2135 request = this.serializedQueue.pop(); 2136 } 2137 2138 // Get the request's lock to indicate request in progress. 2139 synchronized (request.get("lock")) { 2140 2141 // If request still exists it hasn't been cancelled. 2142 if (request.get("request") != null) { 2143 2144 // Send request. 2145 HashMap<String, Object> data = this.sendRequestCore((JsonObject) request.get("request")); 2146 2147 // Set result. 2148 if (data.containsKey("exception")) { 2149 request.put("exception", data.get("exception")); 2150 } else { 2151 request.put("response", data.get("response")); 2152 } 2153 } 2154 2155 // Notify completion and return 2156 request.get("lock").notify(); 2157 } 2158 } 2159 } 2160 2161 /** 2162 * Throw specific Exception types. * * @param e exception to throw. 2163 * 2164 * * 2165 * @throws RandomOrgSendTimeoutException blocking timeout is exceeded before 2166 * the request can be sent. 2167 ** @throws RandomOrgKeyNotRunningError API key has been stopped. 2168 ** @throws RandomOrgInsufficientRequestsError API key's server requests 2169 * allowance has been exceeded. 2170 ** @throws RandomOrgInsufficientBitsError API key's server bits allowance 2171 * has been exceeded. 2172 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 2173 * received. 2174 ** @throws RandomOrgRANDOMORGError server returns a RANDOM.ORG Error. 2175 ** @throws RandomOrgJSONRPCError server returns a JSON-RPC Error. 2176 ** @throws MalformedURLException in the unlikely event something goes 2177 * wrong with URL creation. @see java.net.MalformedURLException 2178 ** @throws IOException @see java.io.IOException 2179 * 2180 */ 2181 private void throwException(Exception e) throws RandomOrgSendTimeoutException, 2182 RandomOrgKeyNotRunningError, 2183 RandomOrgInsufficientRequestsError, 2184 RandomOrgInsufficientBitsError, 2185 RandomOrgBadHTTPResponseException, 2186 RandomOrgRANDOMORGError, 2187 RandomOrgJSONRPCError, 2188 MalformedURLException, 2189 IOException { 2190 2191 if (e.getClass() == RandomOrgSendTimeoutException.class) { 2192 throw (RandomOrgSendTimeoutException) e; 2193 } else if (e.getClass() == RandomOrgKeyNotRunningError.class) { 2194 throw (RandomOrgKeyNotRunningError) e; 2195 } else if (e.getClass() == RandomOrgInsufficientRequestsError.class) { 2196 throw (RandomOrgInsufficientRequestsError) e; 2197 } else if (e.getClass() == RandomOrgInsufficientBitsError.class) { 2198 throw (RandomOrgInsufficientBitsError) e; 2199 } else if (e.getClass() == RandomOrgBadHTTPResponseException.class) { 2200 throw (RandomOrgBadHTTPResponseException) e; 2201 } else if (e.getClass() == RandomOrgRANDOMORGError.class) { 2202 throw (RandomOrgRANDOMORGError) e; 2203 } else if (e.getClass() == RandomOrgJSONRPCError.class) { 2204 throw (RandomOrgJSONRPCError) e; 2205 } else if (e.getClass() == MalformedURLException.class) { 2206 throw (MalformedURLException) e; 2207 } else if (e.getClass() == IOException.class) { 2208 throw (IOException) e; 2209 } 2210 } 2211 2212 /** 2213 * Core send request function. * * @param request JSON to send. * * @return 2214 * info on request success/response in a HashMap with one or other of the 2215 * following entries: * "exception" : Exception - exception thrown, possible 2216 * exception types: * RandomOrgSendTimeoutException * 2217 * RandomOrgKeyNotRunningError * RandomOrgInsufficientRequestsError * 2218 * RandomOrgInsufficientBitsError * RandomOrgBadHTTPResponseException * 2219 * RandomOrgRANDOMORGError * RandomOrgJSONRPCError * MalformedURLException * 2220 * IOException * "response" : JsonObject - response 2221 * 2222 */ 2223 protected HashMap<String, Object> sendRequestCore(JsonObject request) { 2224 2225 HashMap<String, Object> ret = new HashMap<String, Object>(); 2226 2227 // If a back-off is set, no more requests can be issued until the required back-off time is up. 2228 if (this.backoff != -1) { 2229 2230 // Time not yet up, throw exception. 2231 if (System.currentTimeMillis() < this.backoff) { 2232 ret.put("exception", new RandomOrgInsufficientRequestsError(this.backoffError)); 2233 return ret; 2234 // Time is up, clear back-off. 2235 } else { 2236 this.backoff = -1; 2237 this.backoffError = null; 2238 } 2239 } 2240 2241 long wait = 0; 2242 2243 // Check server advisory delay. 2244 synchronized (this.advisoryDelayLock) { 2245 wait = this.advisoryDelay - (System.currentTimeMillis() - this.lastResponseReceivedTime); 2246 } 2247 2248 // Wait the specified delay if necessary and if wait time is not longer than the set blocking timeout. 2249 if (wait > 0) { 2250 if (this.blockingTimeout != -1 && wait > this.blockingTimeout) { 2251 ret.put("exception", new RandomOrgSendTimeoutException("The server advisory delay of " + wait 2252 + "millis is greater than the defined maximum allowed blocking time of " + this.blockingTimeout + "millis.")); 2253 return ret; 2254 } 2255 try { 2256 Thread.sleep(wait); 2257 } catch (InterruptedException e) { 2258 LOGGER.log(Level.INFO, "Client interrupted while waiting for server mandated blocking time."); 2259 } 2260 } 2261 2262 JsonObject response; 2263 2264 // Send the request 2265 try { 2266 response = this.post(request); 2267 } catch (MalformedURLException e) { 2268 ret.put("exception", e); 2269 return ret; 2270 } catch (RandomOrgBadHTTPResponseException e) { 2271 ret.put("exception", e); 2272 return ret; 2273 } catch (IOException e) { 2274 ret.put("exception", e); 2275 return ret; 2276 } 2277 2278 // Parse the response. 2279 // Has error? 2280 if (response.has("error")) { 2281 JsonObject error = response.get("error").getAsJsonObject(); 2282 2283 int code = error.get("code").getAsInt(); 2284 String message = error.get("message").getAsString(); 2285 2286 // RandomOrgAllowanceExceededError, API key not running, backoff until midnight UTC, 2287 // from RANDOM.ORG Errors: https://api.random.org/json-rpc/1/error-codes 2288 if (code == 402) { 2289 2290 Calendar date = new GregorianCalendar(); 2291 date.set(Calendar.HOUR_OF_DAY, 0); 2292 date.set(Calendar.MINUTE, 0); 2293 date.set(Calendar.SECOND, 0); 2294 date.set(Calendar.MILLISECOND, 0); 2295 date.add(Calendar.DAY_OF_MONTH, 1); 2296 2297 this.backoff = date.getTimeInMillis(); 2298 this.backoffError = "Error " + code + ": " + message; 2299 ret.put("exception", new RandomOrgInsufficientRequestsError(this.backoffError)); 2300 return ret; 2301 } else if (code == 401) { 2302 ret.put("exception", new RandomOrgKeyNotRunningError("Error " + code + ": " + message)); 2303 return ret; 2304 2305 } else if (code == 403) { 2306 ret.put("exception", new RandomOrgInsufficientBitsError("Error " + code + ": " + message, this.bitsLeft)); 2307 return ret; 2308 2309 // RandomOrgRANDOMORGError from RANDOM.ORG Errors: https://api.random.org/json-rpc/1/error-codes 2310 } else if (RandomOrgClient.randomOrgErrors.contains(code)) { 2311 ret.put("exception", new RandomOrgRANDOMORGError("Error " + code + ": " + message)); 2312 return ret; 2313 2314 // RandomOrgJSONRPCError from JSON-RPC Errors: https://api.random.org/json-rpc/1/error-codes 2315 } else { 2316 ret.put("exception", new RandomOrgJSONRPCError("Error " + code + ": " + message)); 2317 return ret; 2318 } 2319 } 2320 2321 JsonObject result = response.get("result").getAsJsonObject(); 2322 2323 // Update usage statistics 2324 if (result.has("requestsLeft")) { 2325 this.requestsLeft = result.get("requestsLeft").getAsInt(); 2326 this.bitsLeft = result.get("bitsLeft").getAsInt(); 2327 } 2328 2329 // Set new server advisory delay 2330 synchronized (this.advisoryDelayLock) { 2331 if (result.has("advisoryDelay")) { 2332 this.advisoryDelay = result.get("advisoryDelay").getAsInt(); 2333 } else { 2334 // Use default if none from server. 2335 this.advisoryDelay = RandomOrgClient.DEFAULT_DELAY; 2336 } 2337 2338 this.lastResponseReceivedTime = System.currentTimeMillis(); 2339 } 2340 2341 ret.put("response", response); 2342 return ret; 2343 } 2344 2345 /** 2346 * POST JSON to server and return JSON response. * * @param json request to 2347 * post. * * @return JSON response. * * @throws IOException @see 2348 * java.io.IOException 2349 * 2350 ** @throws MalformedURLException in the unlikely event something goes 2351 * wrong with URL creation. @see java.net.MalformedURLException 2352 ** @throws RandomOrgBadHTTPResponseException if a HTTP 200 OK response not 2353 * received. 2354 * 2355 */ 2356 private JsonObject post(JsonObject json) throws IOException, MalformedURLException, RandomOrgBadHTTPResponseException { 2357 2358 HttpsURLConnection con = (HttpsURLConnection) new URL("https://api.random.org/json-rpc/1/invoke").openConnection(); 2359 con.setConnectTimeout(this.httpTimeout); 2360 2361 // headers 2362 con.setRequestMethod("POST"); 2363 con.setRequestProperty("Content-Type", "application/json"); 2364 2365 // send JSON 2366 con.setDoOutput(true); 2367 DataOutputStream dos = new DataOutputStream(con.getOutputStream()); 2368 dos.writeBytes(json.toString()); 2369 dos.flush(); 2370 dos.close(); 2371 2372 // check response 2373 int responseCode = con.getResponseCode(); 2374 2375 // return JSON... 2376 if (responseCode == HttpsURLConnection.HTTP_OK) { 2377 BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); 2378 String inputLine; 2379 StringBuilder response = new StringBuilder(); 2380 2381 while ((inputLine = in.readLine()) != null) { 2382 response.append(inputLine); 2383 } 2384 in.close(); 2385 2386 return new JsonParser().parse(response.toString()).getAsJsonObject(); 2387 2388 // ...or throw error 2389 } else { 2390 throw new RandomOrgBadHTTPResponseException("Error " + responseCode + ": " + con.getResponseMessage()); 2391 } 2392 } 2393 2394 /** 2395 * Runnable for unserialized network calls. * 2396 */ 2397 private class UnserializedRunnable implements Runnable { 2398 2399 private JsonObject request; 2400 private HashMap<String, Object> data; 2401 2402 /** 2403 * @param request object to send to server. 2404 */ 2405 UnserializedRunnable(JsonObject request) { 2406 super(); 2407 this.request = request; 2408 } 2409 2410 /* @see java.lang.Runnable#run() */ 2411 @Override 2412 public void run() { 2413 this.data = RandomOrgClient.this.sendRequestCore(this.request); 2414 } 2415 2416 /** 2417 * @return data returned by network request - or null if not yet 2418 * arrived. 2419 */ 2420 public HashMap<String, Object> getData() { 2421 return this.data; 2422 } 2423 } 2424 } 2425