| /* |
| * Copyright 2009 Mike Cumings |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.kenai.jbosh; |
| |
| import java.security.SecureRandom; |
| import java.util.concurrent.atomic.AtomicLong; |
| import java.util.concurrent.locks.Lock; |
| import java.util.concurrent.locks.ReentrantLock; |
| |
| /** |
| * Request ID sequence generator. This generator generates a random first |
| * RID and then manages the sequence from there on out. |
| */ |
| final class RequestIDSequence { |
| |
| /** |
| * Maximum number of bits available for representing request IDs, according |
| * to the XEP-0124 spec.s |
| */ |
| private static final int MAX_BITS = 53; |
| |
| /** |
| * Bits devoted to incremented values. |
| */ |
| private static final int INCREMENT_BITS = 32; |
| |
| /** |
| * Minimum number of times the initial RID can be incremented before |
| * exceeding the maximum. |
| */ |
| private static final long MIN_INCREMENTS = 1L << INCREMENT_BITS; |
| |
| /** |
| * Max initial value. |
| */ |
| private static final long MAX_INITIAL = (1L << MAX_BITS) - MIN_INCREMENTS; |
| |
| /** |
| * Max bits mask. |
| */ |
| private static final long MASK = ~(Long.MAX_VALUE << MAX_BITS); |
| |
| /** |
| * Random number generator. |
| */ |
| private static final SecureRandom RAND = new SecureRandom(); |
| |
| /** |
| * Internal lock. |
| */ |
| private static final Lock LOCK = new ReentrantLock(); |
| |
| /** |
| * The last reqest ID used, or <= 0 if a new request ID needs to be |
| * generated. |
| */ |
| private AtomicLong nextRequestID = new AtomicLong(); |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // Constructors: |
| |
| /** |
| * Prevent direct construction. |
| */ |
| RequestIDSequence() { |
| nextRequestID = new AtomicLong(generateInitialValue()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // Public methods: |
| |
| /** |
| * Calculates the next request ID value to use. This number must be |
| * initialized such that it is unlikely to ever exceed 2 ^ 53, according |
| * to XEP-0124. |
| * |
| * @return next request ID value |
| */ |
| public long getNextRID() { |
| return nextRequestID.getAndIncrement(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // Private methods: |
| |
| /** |
| * Generates an initial RID value by generating numbers until a number is |
| * found which is smaller than the maximum allowed value and greater |
| * than zero. |
| * |
| * @return random initial value |
| */ |
| private long generateInitialValue() { |
| long result; |
| LOCK.lock(); |
| try { |
| do { |
| result = RAND.nextLong() & MASK; |
| } while (result > MAX_INITIAL); |
| } finally { |
| LOCK.unlock(); |
| } |
| return result; |
| } |
| |
| } |