/*
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Intalio, Inc. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Intalio, Inc. Exolab is a registered
* trademark of Intalio, Inc.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999 (C) Intalio, Inc. All Rights Reserved.
*
* $Id: RandomHelper.java 6785 2007-01-29 05:09:59Z ekuns $
*/
package org.castor.xmlctf;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Vector;
import org.exolab.castor.types.RecurringDuration;
import org.exolab.castor.types.TimeDuration;
/**
* Assists in the generation of random instances of a given object model.
*
* @author <a href="mailto:gignoux@intalio.com">Sebastien Gignoux</a>
* @version $Revision: 6785 $ $Date: 2006-04-13 06:47:36 -0600 (Thu, 13 Apr 2006) $
*/
public class RandomHelper {
/**
* The seed which was used to initialize the pseudo-random number generator.
*/
private static long _seed;
/**
* The pseudo-random number generator.
*/
private static Random _rand;
static {
_seed = System.currentTimeMillis();
_rand = new Random(_seed);
}
/**
* The maximum length of a string to be generated by rndString().
*/
private static final int MAX_STRING_LENGTH = 50;
/**
* The maximum length of a collection (like a Vector) generated by rndString().
*/
private static final int MAX_COLLECTION_LENGTH = 50;
/**
* List of the characters that can be used to compose a string.
*/
private static final String PRINTABLE_CHAR = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_:.,=+~!@#$%^&*()[]{}\\|?";
/**
* Returns a populated array of int of random length.
*
* @param array An unused parameter, used only for polymorphism.
* @param c An unused parameter that indicates we are making a random
* Object, not a random primitive
* @return a populated array of int of random length.
*/
public static int[] getRandom(int[] array, Class c) {
int size = _rand.nextInt(MAX_COLLECTION_LENGTH);
int[] ret = new int[size];
for (int i=0; i<size; ++i) {
ret[i] = _rand.nextInt();
}
return ret;
}
/**
* Returns a populated array of byte of random length.
*
* @param array An unused parameter, used only for polymorphism.
* @param c An unused parameter that indicates we are making a random
* Object, not a random primitive
* @return a populated array of byte of random length.
*/
public static byte[] getRandom(byte[] array, Class c) {
int size = _rand.nextInt(MAX_COLLECTION_LENGTH);
byte[] ret = new byte[size];
_rand.nextBytes(ret);
return ret;
}
/**
* Returns a populated array of String of random length.
*
* @param array An unused parameter, used only for polymorphism.
* @param c An unused parameter that indicates we are making a random
* Object, not a random primitive
* @return a populated array of String of random length.
*/
public static String[] getRandom(String[] array, Class c) {
int size = _rand.nextInt(MAX_COLLECTION_LENGTH);
String[] newArray = new String[size];
for (int i=0; i<size; ++i) {
newArray[i] = getRandom(new String(), null);
}
return newArray;
}
/**
* Creates a populated array of type c of random length. If the class to put
* into the vector implements CastorTestable, randomizeFields() will be
* called on the objects.
*
* @param array An unused parameter, used only for polymorphism.
* @param c the type of object to put in the array
* @return a populated array of random length.
* @throws InstantiationException if the class cannot be instantiated.
* @throws IllegalAccessException if the class cannot be accessed.
*/
public static Object[] getRandom(Object[] array, Class c)
throws InstantiationException, IllegalAccessException {
int size = _rand.nextInt(MAX_COLLECTION_LENGTH);
Object[] newArray = new Object[size];
for (int i=0; i<size; ++i) {
newArray[i] = c.newInstance();
if (CastorTestable.class.isAssignableFrom(c)) {
((CastorTestable)newArray[i]).randomizeFields();
}
}
return newArray;
}
/**
* Returns a populated vector of random length. If the class to put into the
* vector implements CastorTestable, randomizeFields() will be called on the
* objects.
*
* @param vect the vector to populate, if null a new Vector will be created.
* @param c the type of object to put in the vector.
* @return a populated Vector of random length.
* @throws InstantiationException if the class cannot be instantiated.
* @throws IllegalAccessException if the class cannot be accessed.
*/
public static Vector getRandom(Vector vect, Class c)
throws InstantiationException, IllegalAccessException {
Vector vector = (vect != null) ? vect : new Vector();
int size = _rand.nextInt(MAX_COLLECTION_LENGTH);
for (int i=0; i<size; ++i) {
Object object = c.newInstance();
vector.add(object);
if (CastorTestable.class.isAssignableFrom(c)) {
((CastorTestable)object).randomizeFields();
}
}
return vector;
}
/**
* Returns a populated ArrayList of random length. If the class of the
* object contained into the vector implements CastorTestable,
* randomizeFields() will be called on the objects.
*
* @param al the ArrayList to populate
* @param c the type of object to put in the vector
* @return a populated ArrayList of random length.
* @throws InstantiationException if the class cannot be instantiated
* @throws IllegalAccessException if the class cannot be accessed
*/
public static ArrayList getRandom(ArrayList al, Class c)
throws InstantiationException, IllegalAccessException {
return new ArrayList(RandomHelper.getRandom(new Vector(al), c));
}
/**
* Returns a populated Collection of random length. If the class of the
* object contained into the vector implements CastorTestable,
* randomizeFields() will be called on the objects.
*
* @param al the ArrayList to populate
* @param c the type of object to put in the vector
* @return a populated ArrayList of random length.
* @throws InstantiationException if the class cannot be instantiated
* @throws IllegalAccessException if the class cannot be accessed
*/
public static Collection getRandom(Collection al, Class c)
throws InstantiationException, IllegalAccessException {
return new LinkedList(RandomHelper.getRandom(new Vector(al), c));
}
/**
* Returns a populated List of random length. If the class of the object
* contained into the vector implements CastorTestable, randomizeFields()
* will be called on the objects.
*
* @param al the ArrayList to populate
* @param c the type of object to put in the vector
* @return a populated ArrayList of random length.
* @throws InstantiationException if the class cannot be instantiated
* @throws IllegalAccessException if the class cannot be accessed
*/
public static List getRandom(List al, Class c)
throws InstantiationException, IllegalAccessException {
return new LinkedList(RandomHelper.getRandom(new Vector(al), c));
}
/**
* Returns a populated Set of random length. If the class of the object
* contained into the vector implements CastorTestable, randomizeFields()
* will be called on the objects.
*
* @param al the Set to populate
* @param c the type of object to put in the vector
* @return a populated Set of random length.
* @throws InstantiationException if the class cannot be instantiated
* @throws IllegalAccessException if the class cannot be accessed
*/
public static Set getRandom(Set al, Class c)
throws InstantiationException, IllegalAccessException {
return new HashSet(RandomHelper.getRandom(new Vector(al), c));
}
/**
* Returns a populated SortedSet of random length. If the class of the
* object contained into the vector implements CastorTestable,
* randomizeFields() will be called on the objects.
*
* @param al the SortedSet to populate
* @param c the type of object to put in the vector
* @return a populated SortedSet of random length.
* @throws InstantiationException if the class cannot be instantiated
* @throws IllegalAccessException if the class cannot be accessed
*/
public static SortedSet getRandom(SortedSet al, Class c)
throws InstantiationException, IllegalAccessException {
return new TreeSet(RandomHelper.getRandom(new Vector(al), c));
}
/**
* Returns a random String that will not have leading or trailing whitespace
* and that will not have consecutive internal whitespace. To get a random
* string without these restrictions, use
* {@link #getRandom(String, Class, boolean)} with the boolean argument
* <code>false</code>.
*
* @param s An unused parameter, used only for polymorphism.
* @param c An unused parameter that indicates we are making a random
* Object, not a random primitive
* @return a random string
*/
public static String getRandom(String s, Class c) {
return getRandom(s, c, true);
}
/**
* Returns a random String, optionally with leading and trailing whitespace
* removed and internal consecutive whitespace collapsed.
*
* @param s An unused parameter, used only for polymorphism.
* @param c An unused parameter that indicates we are making a random
* Object, not a random primitive
* @param collapseWhitespace if true, removes leading and trailing
* whitespace and collapses multiple consecutive spaces.
* @return a random string
* @see <a href="http://www.w3.org/TR/xmlschema-2/#rf-whiteSpace">the XML
* schema definition of whitespace</a>
*/
public static String getRandom(String s, Class c, boolean collapseWhitespace) {
int size = 1 + _rand.nextInt(MAX_STRING_LENGTH - 1);
char[] data = new char[size];
for (int i=0; i < size; ++i) {
data[i] = rndPrintableChar();
}
if (! collapseWhitespace) {
return new String(data);
}
// Make sure the first character is not whitespace
while (Character.isWhitespace(data[0])) {
data[0] = rndPrintableChar();
}
// Make sure the last character is not whitespace
while (Character.isWhitespace(data[size-1])) {
data[size-1] = rndPrintableChar();
}
// Make sure there are no consecutive whitespace characters
for (int i = 0; i < size - 1; i++) {
while (Character.isWhitespace(data[i]) && Character.isWhitespace(data[i+1])) {
data[i] = rndPrintableChar();
}
}
return new String(data);
}
/**
* Returns a random java.util.Date.
* @param date An unused parameter, used only for polymorphism.
* @param c An unused parameter that indicates we are making a random
* Object, not a random primitive
* @return a random java.util.Date.
*/
public static java.util.Date getRandom(java.util.Date date, Class c) {
long milli = _rand.nextLong();
return new java.util.Date(milli);
}
/**
* Returns a random Castor TimeDuration.
* @param date An unused parameter, used only for polymorphism.
* @param c An unused parameter that indicates we are making a random
* Object, not a random primitive
* @return a random Castor timeDuration.
*/
public static TimeDuration getRandom(TimeDuration date, Class c) {
long randLong = _rand.nextInt();
randLong = (randLong > 0) ? randLong : -randLong;
return new TimeDuration(randLong);
}
/**
* Returns a random Castor RecurringDuration.
*
* @param recurring An unused parameter, used only for polymorphism.
* @param c An unused parameter that indicates we are making a random
* Object, not a random primitive
* @return a random Castor recurringDuration.
*/
public static RecurringDuration getRandom(RecurringDuration recurring, Class c) {
short randShort;
long randLong = _rand.nextLong();
TimeDuration randDuration = new TimeDuration(randLong);
RecurringDuration result = new RecurringDuration(randDuration, randDuration);
short[] values = new short[10];
//only positive values are allowed
//century
randShort = (short) _rand.nextInt(99);
values[0] = (randShort > 0)? randShort:(short)-randShort;
//year
randShort = (short)_rand.nextInt(99);
values[1] = (randShort > 0)? randShort:(short)-randShort;
//month
randShort = (short)_rand.nextInt(12);
values[2] = (randShort > 0)? randShort:(short)-randShort;
//day
randShort = (short)_rand.nextInt(30);
values[3] = (randShort > 0)? randShort:(short)-randShort;
//hour
randShort = (short)_rand.nextInt(24);
values[4] = (randShort > 0)? randShort:(short)-randShort;
//minute
randShort = (short)_rand.nextInt(60);
values[5] = (randShort > 0)? randShort:(short)-randShort;
//second
randShort = (short)_rand.nextInt(60);
values[6] = (randShort > 0)? randShort:(short)-randShort;
//millisecond
randShort = (short)_rand.nextInt(99);
values[7] = (randShort > 0)? randShort:(short)-randShort;
//time zone hour
randShort = (short)_rand.nextInt(12);
values[8] = randShort;
//time zone minute
randShort = (short)_rand.nextInt(60);
values[9] = (randShort > 0)? randShort:(short)-randShort;
result.setValues(values);
values = null;
randDuration = null;
return result;
}
/**
* Returns a random Object of the type provided by class c.
*
* @param object An unused parameter, used only for polymorphism.
* @param c the type of object we will create a randomized instance of. This
* class must implement CastorTestable.
* @return a random Object.
*/
public static Object getRandom(Object object, Class c) {
try {
Object obj = c.newInstance();
if (obj.getClass().isAssignableFrom(CastorTestable.class)) {
((CastorTestable)obj).randomizeFields();
}
return obj;
} catch (Exception e) {
// TODO: find a better way of handling this failure
e.printStackTrace();
}
return null;
}
/**
* Returns a random BigDecimal.
*
* @param bg An unused parameter, used only for polymorphism.
* @param c An unused parameter that indicates we are making a random
* Object, not a random primitive
* @return a random BigDecimal.
*/
public static BigDecimal getRandom(BigDecimal bg, Class c) {
return new BigDecimal(_rand.nextDouble());
}
/**
* Returns a random int.
* @param i An unused parameter, used only for polymorphism.
* @return a random int.
*/
public static int getRandom(int i) {
return _rand.nextInt();
}
/**
* Returns a random float.
* @param f An unused parameter, used only for polymorphism.
* @return a random float.
*/
public static float getRandom(float f) {
return _rand.nextFloat();
}
/**
* Returns a random boolean.
* @param b An unused parameter, used only for polymorphism.
* @return a random boolean.
*/
public static boolean getRandom(boolean b) {
return _rand.nextBoolean();
}
/**
* Returns a random long.
* @param l An unused parameter, used only for polymorphism.
* @return a random long.
*/
public static long getRandom(long l) {
return _rand.nextLong();
}
/**
* Returns a random short.
* @param l An unused parameter, used only for polymorphism.
* @return a random short.
*/
public static short getRandom(short l) {
return new Integer(_rand.nextInt()).shortValue();
}
/**
* Returns a random double.
* @param d An unused parameter, used only for polymorphism.
* @return a random double.
*/
public static double getRandom(double d) {
return _rand.nextDouble();
}
/**
* Returns a random printable char.
* @param c An unused parameter, used only for polymorphism.
* @return a random printable char.
*/
public static char getRandom(char c) {
return rndPrintableChar();
}
/**
* Returns a random byte.
* @param b An unused parameter, used only for polymorphism.
* @return a random byte.
*/
public static byte getRandom(byte b) {
byte[] tmp = new byte[1]; // TODO: Cache more...
_rand.nextBytes(tmp);
return tmp[0];
}
/**
* Returns true or false randomly with equal probability.
* @return true or false randomly with equal probability.
*/
public static boolean flip() {
return _rand.nextBoolean();
}
/**
* Returns true randomly with the probability p.
*
* @param p A probability for returning true
* @return true p% of the time
*/
public static boolean flip(double p) {
return (_rand.nextDouble() < p)? true : false;
}
/**
* Returns a random printable character from the {@link #PRINTABLE_CHAR}
* string.
*
* @return a random printable character from the PRINTABLE_CHAR string.
*/
public static char rndPrintableChar() {
return PRINTABLE_CHAR.charAt(_rand.nextInt(PRINTABLE_CHAR.length()));
}
/**
* Returns the seed which was used to initialize the pseudo-random number
* generator.
*
* @return the seed which was used to initialize the pseudo-random number
* generator
*/
public static long getSeed() {
return _seed;
}
/**
* Re-initializes the random number generator with the given seed.
*
* @param seed the new seed for the random number generator.
*/
public static void setSeed(long seed) {
_seed = seed;
_rand = new Random(_seed);
}
}