blob: 14b1475a1b6d3c5c89a517d58479771d19265711 [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001/*
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
17package com.kenai.jbosh;
18
19import java.security.SecureRandom;
20import java.util.concurrent.atomic.AtomicLong;
21import java.util.concurrent.locks.Lock;
22import 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 */
28final 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 &lt;= 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}