/* * 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; } }