/*
* Atricore IDBus
*
* Copyright (c) 2009, Atricore Inc.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.atricore.idbus.kernel.main.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
/**
* This is an implementation of an id generator based on Jakarta Tomcat 5.0
* Assertion id generation.
* This implementation is thread safe.
*
* @author <a href="mailto:gbrigand@josso.org">Gianluca Brigandi</a>
* @version $Id: AbstractIdGenerator.java 1183 2009-05-05 20:48:01Z sgonzalez $
*/
public abstract class AbstractIdGenerator implements IdGenerator {
private static final Log logger = LogFactory.getLog(AbstractIdGenerator.class);
/**
* The default message digest algorithm to use if we cannot use
* the requested one.
*/
protected static final String DEFAULT_ALGORITHM = "MD5";
/**
* The message digest algorithm to be used when generating Assertion
* identifiers. This must be an algorithm supported by the
* <code>java.security.MessageDigest</code> class on your platform.
*/
private String _algorithm = DEFAULT_ALGORITHM;
private int _assertionIdLength = 16;
private String _entropy;
private Random _random;
/**
* The Java class name of the random number generator class to be used
* when generating assertion identifiers.
*/
protected String _randomClass = "java.security.SecureRandom";
/**
* Return the random number generator instance we should use for
* generating assertion identifiers. If there is no such generator
* currently defined, construct and seed a new one.
*/
public synchronized Random getRandom() {
if (_random == null) {
synchronized (this) {
if (_random == null) {
// Calculate the new random number generator seed
long seed = System.currentTimeMillis();
long t1 = seed;
char entropy[] = getEntropy().toCharArray();
for (int i = 0; i < entropy.length; i++) {
long update = ((byte) entropy[i]) << ((i % 8) * 8);
seed ^= update;
}
try {
// Construct and seed a new random number generator
Class clazz = Class.forName(_randomClass);
_random = (Random) clazz.newInstance();
_random.setSeed(seed);
} catch (Exception e) {
// Can't instantiate random class, fall back to the simple case
logger.error("Can't use random class : " + _randomClass + ", fall back to the simple case.", e);
_random = new java.util.Random();
_random.setSeed(seed);
}
// Log a debug msg if this is taking too long ...
long t2 = System.currentTimeMillis();
if ((t2 - t1) > 100)
logger.debug("Delay getting Random with class : " + _randomClass + " [getRandom()] " + (t2 - t1) + " ms.");
}
}
}
return (_random);
}
/**
* Return the MessageDigest object to be used for calculating
* assertion identifiers. If none has been created yet, initialize
* one the first time this method is called.
*/
public synchronized MessageDigest getDigest() {
MessageDigest digest = null;
if (_algorithm != null) {
try {
digest = MessageDigest.getInstance(_algorithm);
logger.debug("Using hash algorithm/encoding : " + _algorithm);
} catch (NoSuchAlgorithmException e) {
logger.error("Algorithm not supported : " + _algorithm, e);
try {
digest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
} catch (NoSuchAlgorithmException f) {
logger.error("Algorithm not supported : " + DEFAULT_ALGORITHM, e);
digest = null;
}
}
}
return digest;
}
/**
* Generate a byte array containing a assertion identifier
*/
protected void getRandomBytes(byte[] bytes) {
// Performance may be improved by using O.S. Specific devices like /dev/urandom (see tomcat 5.0)
Random random = getRandom();
random.nextBytes(bytes);
}
/**
* Return the entropy increaser value, or compute a semi-useful value
* if this String has not yet been set.
*/
public String getEntropy() {
// Calculate a semi-useful value if this has not been set
if (_entropy == null)
setEntropy(this.toString());
return (_entropy);
}
/**
* Set the entropy increaser value.
*
* @param entropy The new entropy increaser value
*/
public void setEntropy(String entropy) {
// String oldEntropy = entropy;
_entropy = entropy;
}
/**
* Return the digest algorithm for the id generator.
*
* @return String the algorithm name (i.e. MD5).
*/
public String getAlgorithm() {
return _algorithm;
}
/**
* Set the message digest algorithm for the id generator.
*
* @param algorithm The new message digest algorithm
*/
public void setAlgorithm(String algorithm) {
_algorithm = algorithm;
}
/**
* Gets the assertion id length (in bytes) for Assertions created by this
* Generator
*/
public int getAssertionIdLength() {
return _assertionIdLength;
}
/**
* Sets the assertion id length (in bytes) for Assertions created by this
* Generator
*
* @param idLength The assertion id length
*/
public void setAssertionIdLength(int idLength) {
_assertionIdLength = idLength;
}
/**
* Gets the random number generator class name.
*/
public String getRandomClass() {
return _randomClass;
}
/**
* Sets the random number generator class name.
*/
public void setRandomClass(String randomClass) {
_randomClass = randomClass;
_random = null;
}
}