1 /* 2 * Copyright 2009 Mike Cumings 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.kenai.jbosh; 18 19 import java.security.SecureRandom; 20 import java.util.concurrent.atomic.AtomicLong; 21 import java.util.concurrent.locks.Lock; 22 import java.util.concurrent.locks.ReentrantLock; 23 24 /** 25 * Request ID sequence generator. This generator generates a random first 26 * RID and then manages the sequence from there on out. 27 */ 28 final class RequestIDSequence { 29 30 /** 31 * Maximum number of bits available for representing request IDs, according 32 * to the XEP-0124 spec.s 33 */ 34 private static final int MAX_BITS = 53; 35 36 /** 37 * Bits devoted to incremented values. 38 */ 39 private static final int INCREMENT_BITS = 32; 40 41 /** 42 * Minimum number of times the initial RID can be incremented before 43 * exceeding the maximum. 44 */ 45 private static final long MIN_INCREMENTS = 1L << INCREMENT_BITS; 46 47 /** 48 * Max initial value. 49 */ 50 private static final long MAX_INITIAL = (1L << MAX_BITS) - MIN_INCREMENTS; 51 52 /** 53 * Max bits mask. 54 */ 55 private static final long MASK = ~(Long.MAX_VALUE << MAX_BITS); 56 57 /** 58 * Random number generator. 59 */ 60 private static final SecureRandom RAND = new SecureRandom(); 61 62 /** 63 * Internal lock. 64 */ 65 private static final Lock LOCK = new ReentrantLock(); 66 67 /** 68 * The last reqest ID used, or <= 0 if a new request ID needs to be 69 * generated. 70 */ 71 private AtomicLong nextRequestID = new AtomicLong(); 72 73 /////////////////////////////////////////////////////////////////////////// 74 // Constructors: 75 76 /** 77 * Prevent direct construction. 78 */ 79 RequestIDSequence() { 80 nextRequestID = new AtomicLong(generateInitialValue()); 81 } 82 83 /////////////////////////////////////////////////////////////////////////// 84 // Public methods: 85 86 /** 87 * Calculates the next request ID value to use. This number must be 88 * initialized such that it is unlikely to ever exceed 2 ^ 53, according 89 * to XEP-0124. 90 * 91 * @return next request ID value 92 */ 93 public long getNextRID() { 94 return nextRequestID.getAndIncrement(); 95 } 96 97 /////////////////////////////////////////////////////////////////////////// 98 // Private methods: 99 100 /** 101 * Generates an initial RID value by generating numbers until a number is 102 * found which is smaller than the maximum allowed value and greater 103 * than zero. 104 * 105 * @return random initial value 106 */ 107 private long generateInitialValue() { 108 long result; 109 LOCK.lock(); 110 try { 111 do { 112 result = RAND.nextLong() & MASK; 113 } while (result > MAX_INITIAL); 114 } finally { 115 LOCK.unlock(); 116 } 117 return result; 118 } 119 120 } 121