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