View Javadoc
1   /*
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 1999 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id: RandomHelper.java 6785 2007-01-29 05:09:59Z ekuns $
34   */
35  package org.castor.xmlctf;
36  
37  import java.math.BigDecimal;
38  import java.util.ArrayList;
39  import java.util.Collection;
40  import java.util.HashSet;
41  import java.util.LinkedList;
42  import java.util.List;
43  import java.util.Random;
44  import java.util.Set;
45  import java.util.SortedSet;
46  import java.util.TreeSet;
47  import java.util.Vector;
48  
49  import org.exolab.castor.types.RecurringDuration;
50  import org.exolab.castor.types.TimeDuration;
51  
52  /**
53   * Assists in the generation of random instances of a given object model.
54   *
55   * @author <a href="mailto:gignoux@intalio.com">Sebastien Gignoux</a>
56   * @version $Revision: 6785 $ $Date: 2006-04-13 06:47:36 -0600 (Thu, 13 Apr 2006) $
57   */
58  public class RandomHelper {
59  
60    /**
61     * The seed which was used to initialize the pseudo-random number generator.
62     */
63    private static long _seed;
64  
65    /**
66     * The pseudo-random number generator.
67     */
68    private static Random _rand;
69  
70    static {
71      _seed = System.currentTimeMillis();
72      _rand = new Random(_seed);
73    }
74  
75    /**
76     * The maximum length of a string to be generated by rndString().
77     */
78    private static final int MAX_STRING_LENGTH = 50;
79  
80    /**
81     * The maximum length of a collection (like a Vector) generated by rndString().
82     */
83    private static final int MAX_COLLECTION_LENGTH = 50;
84  
85    /**
86     * List of the characters that can be used to compose a string.
87     */
88    private static final String PRINTABLE_CHAR =
89        " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_:.,=+~!@#$%^&*()[]{}\\|?";
90  
91    /**
92     * Returns a populated array of int of random length.
93     *
94     * @param array An unused parameter, used only for polymorphism.
95     * @param c An unused parameter that indicates we are making a random Object, not a random
96     *        primitive
97     * @return a populated array of int of random length.
98     */
99    public static int[] getRandom(int[] array, Class c) {
100     int size = _rand.nextInt(MAX_COLLECTION_LENGTH);
101 
102     int[] ret = new int[size];
103     for (int i = 0; i < size; ++i) {
104       ret[i] = _rand.nextInt();
105     }
106 
107     return ret;
108   }
109 
110   /**
111    * Returns a populated array of byte of random length.
112    *
113    * @param array An unused parameter, used only for polymorphism.
114    * @param c An unused parameter that indicates we are making a random Object, not a random
115    *        primitive
116    * @return a populated array of byte of random length.
117    */
118   public static byte[] getRandom(byte[] array, Class c) {
119     int size = _rand.nextInt(MAX_COLLECTION_LENGTH);
120 
121     byte[] ret = new byte[size];
122     _rand.nextBytes(ret);
123 
124     return ret;
125   }
126 
127   /**
128    * Returns a populated array of String of random length.
129    *
130    * @param array An unused parameter, used only for polymorphism.
131    * @param c An unused parameter that indicates we are making a random Object, not a random
132    *        primitive
133    * @return a populated array of String of random length.
134    */
135   public static String[] getRandom(String[] array, Class c) {
136     int size = _rand.nextInt(MAX_COLLECTION_LENGTH);
137 
138     String[] newArray = new String[size];
139     for (int i = 0; i < size; ++i) {
140       newArray[i] = getRandom(new String(), null);
141     }
142 
143     return newArray;
144   }
145 
146   /**
147    * Creates a populated array of type c of random length. If the class to put into the vector
148    * implements CastorTestable, randomizeFields() will be called on the objects.
149    *
150    * @param array An unused parameter, used only for polymorphism.
151    * @param c the type of object to put in the array
152    * @return a populated array of random length.
153    * @throws InstantiationException if the class cannot be instantiated.
154    * @throws IllegalAccessException if the class cannot be accessed.
155    */
156   public static Object[] getRandom(Object[] array, Class c)
157       throws InstantiationException, IllegalAccessException {
158 
159     int size = _rand.nextInt(MAX_COLLECTION_LENGTH);
160     Object[] newArray = new Object[size];
161 
162     for (int i = 0; i < size; ++i) {
163       newArray[i] = c.newInstance();
164       if (CastorTestable.class.isAssignableFrom(c)) {
165         ((CastorTestable) newArray[i]).randomizeFields();
166       }
167     }
168 
169     return newArray;
170   }
171 
172 
173   /**
174    * Returns a populated vector of random length. If the class to put into the vector implements
175    * CastorTestable, randomizeFields() will be called on the objects.
176    *
177    * @param vect the vector to populate, if null a new Vector will be created.
178    * @param c the type of object to put in the vector.
179    * @return a populated Vector of random length.
180    * @throws InstantiationException if the class cannot be instantiated.
181    * @throws IllegalAccessException if the class cannot be accessed.
182    */
183   public static Vector getRandom(Vector vect, Class c)
184       throws InstantiationException, IllegalAccessException {
185 
186     Vector vector = (vect != null) ? vect : new Vector();
187 
188     int size = _rand.nextInt(MAX_COLLECTION_LENGTH);
189     for (int i = 0; i < size; ++i) {
190       Object object = c.newInstance();
191       vector.add(object);
192       if (CastorTestable.class.isAssignableFrom(c)) {
193         ((CastorTestable) object).randomizeFields();
194       }
195     }
196 
197     return vector;
198   }
199 
200   /**
201    * Returns a populated ArrayList of random length. If the class of the object contained into the
202    * vector implements CastorTestable, randomizeFields() will be called on the objects.
203    *
204    * @param al the ArrayList to populate
205    * @param c the type of object to put in the vector
206    * @return a populated ArrayList of random length.
207    * @throws InstantiationException if the class cannot be instantiated
208    * @throws IllegalAccessException if the class cannot be accessed
209    */
210   public static ArrayList getRandom(ArrayList al, Class c)
211       throws InstantiationException, IllegalAccessException {
212     return new ArrayList(RandomHelper.getRandom(new Vector(al), c));
213   }
214 
215   /**
216    * Returns a populated Collection of random length. If the class of the object contained into the
217    * vector implements CastorTestable, randomizeFields() will be called on the objects.
218    *
219    * @param al the ArrayList to populate
220    * @param c the type of object to put in the vector
221    * @return a populated ArrayList of random length.
222    * @throws InstantiationException if the class cannot be instantiated
223    * @throws IllegalAccessException if the class cannot be accessed
224    */
225   public static Collection getRandom(Collection al, Class c)
226       throws InstantiationException, IllegalAccessException {
227     return new LinkedList(RandomHelper.getRandom(new Vector(al), c));
228   }
229 
230   /**
231    * Returns a populated List of random length. If the class of the object contained into the vector
232    * implements CastorTestable, randomizeFields() will be called on the objects.
233    *
234    * @param al the ArrayList to populate
235    * @param c the type of object to put in the vector
236    * @return a populated ArrayList of random length.
237    * @throws InstantiationException if the class cannot be instantiated
238    * @throws IllegalAccessException if the class cannot be accessed
239    */
240   public static List getRandom(List al, Class c)
241       throws InstantiationException, IllegalAccessException {
242     return new LinkedList(RandomHelper.getRandom(new Vector(al), c));
243   }
244 
245   /**
246    * Returns a populated Set of random length. If the class of the object contained into the vector
247    * implements CastorTestable, randomizeFields() will be called on the objects.
248    *
249    * @param al the Set to populate
250    * @param c the type of object to put in the vector
251    * @return a populated Set of random length.
252    * @throws InstantiationException if the class cannot be instantiated
253    * @throws IllegalAccessException if the class cannot be accessed
254    */
255   public static Set getRandom(Set al, Class c)
256       throws InstantiationException, IllegalAccessException {
257     return new HashSet(RandomHelper.getRandom(new Vector(al), c));
258   }
259 
260   /**
261    * Returns a populated SortedSet of random length. If the class of the object contained into the
262    * vector implements CastorTestable, randomizeFields() will be called on the objects.
263    *
264    * @param al the SortedSet to populate
265    * @param c the type of object to put in the vector
266    * @return a populated SortedSet of random length.
267    * @throws InstantiationException if the class cannot be instantiated
268    * @throws IllegalAccessException if the class cannot be accessed
269    */
270   public static SortedSet getRandom(SortedSet al, Class c)
271       throws InstantiationException, IllegalAccessException {
272     return new TreeSet(RandomHelper.getRandom(new Vector(al), c));
273   }
274 
275   /**
276    * Returns a random String that will not have leading or trailing whitespace and that will not
277    * have consecutive internal whitespace. To get a random string without these restrictions, use
278    * {@link #getRandom(String, Class, boolean)} with the boolean argument <code>false</code>.
279    *
280    * @param s An unused parameter, used only for polymorphism.
281    * @param c An unused parameter that indicates we are making a random Object, not a random
282    *        primitive
283    * @return a random string
284    */
285   public static String getRandom(String s, Class c) {
286     return getRandom(s, c, true);
287   }
288 
289   /**
290    * Returns a random String, optionally with leading and trailing whitespace removed and internal
291    * consecutive whitespace collapsed.
292    *
293    * @param s An unused parameter, used only for polymorphism.
294    * @param c An unused parameter that indicates we are making a random Object, not a random
295    *        primitive
296    * @param collapseWhitespace if true, removes leading and trailing whitespace and collapses
297    *        multiple consecutive spaces.
298    * @return a random string
299    * @see <a href="http://www.w3.org/TR/xmlschema-2/#rf-whiteSpace">the XML schema definition of
300    *      whitespace</a>
301    */
302   public static String getRandom(String s, Class c, boolean collapseWhitespace) {
303     int size = 1 + _rand.nextInt(MAX_STRING_LENGTH - 1);
304     char[] data = new char[size];
305     for (int i = 0; i < size; ++i) {
306       data[i] = rndPrintableChar();
307     }
308 
309     if (!collapseWhitespace) {
310       return new String(data);
311     }
312 
313     // Make sure the first character is not whitespace
314     while (Character.isWhitespace(data[0])) {
315       data[0] = rndPrintableChar();
316     }
317 
318     // Make sure the last character is not whitespace
319     while (Character.isWhitespace(data[size - 1])) {
320       data[size - 1] = rndPrintableChar();
321     }
322 
323     // Make sure there are no consecutive whitespace characters
324     for (int i = 0; i < size - 1; i++) {
325       while (Character.isWhitespace(data[i]) && Character.isWhitespace(data[i + 1])) {
326         data[i] = rndPrintableChar();
327       }
328     }
329 
330     return new String(data);
331   }
332 
333   /**
334    * Returns a random java.util.Date.
335    * 
336    * @param date An unused parameter, used only for polymorphism.
337    * @param c An unused parameter that indicates we are making a random Object, not a random
338    *        primitive
339    * @return a random java.util.Date.
340    */
341   public static java.util.Date getRandom(java.util.Date date, Class c) {
342     long milli = _rand.nextLong();
343     return new java.util.Date(milli);
344   }
345 
346   /**
347    * Returns a random Castor TimeDuration.
348    * 
349    * @param date An unused parameter, used only for polymorphism.
350    * @param c An unused parameter that indicates we are making a random Object, not a random
351    *        primitive
352    * @return a random Castor timeDuration.
353    */
354   public static TimeDuration getRandom(TimeDuration date, Class c) {
355     long randLong = _rand.nextInt();
356     randLong = (randLong > 0) ? randLong : -randLong;
357     return new TimeDuration(randLong);
358   }
359 
360   /**
361    * Returns a random Castor RecurringDuration.
362    *
363    * @param recurring An unused parameter, used only for polymorphism.
364    * @param c An unused parameter that indicates we are making a random Object, not a random
365    *        primitive
366    * @return a random Castor recurringDuration.
367    */
368   public static RecurringDuration getRandom(RecurringDuration recurring, Class c) {
369     short randShort;
370     long randLong = _rand.nextLong();
371     TimeDuration randDuration = new TimeDuration(randLong);
372     RecurringDuration result = new RecurringDuration(randDuration, randDuration);
373     short[] values = new short[10];
374     // only positive values are allowed
375     // century
376     randShort = (short) _rand.nextInt(99);
377     values[0] = (randShort > 0) ? randShort : (short) -randShort;
378     // year
379     randShort = (short) _rand.nextInt(99);
380     values[1] = (randShort > 0) ? randShort : (short) -randShort;
381     // month
382     randShort = (short) _rand.nextInt(12);
383     values[2] = (randShort > 0) ? randShort : (short) -randShort;
384     // day
385     randShort = (short) _rand.nextInt(30);
386     values[3] = (randShort > 0) ? randShort : (short) -randShort;
387     // hour
388     randShort = (short) _rand.nextInt(24);
389     values[4] = (randShort > 0) ? randShort : (short) -randShort;
390     // minute
391     randShort = (short) _rand.nextInt(60);
392     values[5] = (randShort > 0) ? randShort : (short) -randShort;
393     // second
394     randShort = (short) _rand.nextInt(60);
395     values[6] = (randShort > 0) ? randShort : (short) -randShort;
396     // millisecond
397     randShort = (short) _rand.nextInt(99);
398     values[7] = (randShort > 0) ? randShort : (short) -randShort;
399     // time zone hour
400     randShort = (short) _rand.nextInt(12);
401     values[8] = randShort;
402     // time zone minute
403     randShort = (short) _rand.nextInt(60);
404     values[9] = (randShort > 0) ? randShort : (short) -randShort;
405     result.setValues(values);
406 
407     values = null;
408     randDuration = null;
409 
410     return result;
411   }
412 
413   /**
414    * Returns a random Object of the type provided by class c.
415    *
416    * @param object An unused parameter, used only for polymorphism.
417    * @param c the type of object we will create a randomized instance of. This class must implement
418    *        CastorTestable.
419    * @return a random Object.
420    */
421   public static Object getRandom(Object object, Class c) {
422     try {
423       Object obj = c.newInstance();
424       if (obj.getClass().isAssignableFrom(CastorTestable.class)) {
425         ((CastorTestable) obj).randomizeFields();
426       }
427       return obj;
428     } catch (Exception e) {
429       // TODO: find a better way of handling this failure
430       e.printStackTrace();
431     }
432     return null;
433   }
434 
435   /**
436    * Returns a random BigDecimal.
437    *
438    * @param bg An unused parameter, used only for polymorphism.
439    * @param c An unused parameter that indicates we are making a random Object, not a random
440    *        primitive
441    * @return a random BigDecimal.
442    */
443   public static BigDecimal getRandom(BigDecimal bg, Class c) {
444     return new BigDecimal(_rand.nextDouble());
445   }
446 
447   /**
448    * Returns a random int.
449    * 
450    * @param i An unused parameter, used only for polymorphism.
451    * @return a random int.
452    */
453   public static int getRandom(int i) {
454     return _rand.nextInt();
455   }
456 
457   /**
458    * Returns a random float.
459    * 
460    * @param f An unused parameter, used only for polymorphism.
461    * @return a random float.
462    */
463   public static float getRandom(float f) {
464     return _rand.nextFloat();
465   }
466 
467 
468   /**
469    * Returns a random boolean.
470    * 
471    * @param b An unused parameter, used only for polymorphism.
472    * @return a random boolean.
473    */
474   public static boolean getRandom(boolean b) {
475     return _rand.nextBoolean();
476   }
477 
478   /**
479    * Returns a random long.
480    * 
481    * @param l An unused parameter, used only for polymorphism.
482    * @return a random long.
483    */
484   public static long getRandom(long l) {
485     return _rand.nextLong();
486   }
487 
488   /**
489    * Returns a random short.
490    * 
491    * @param l An unused parameter, used only for polymorphism.
492    * @return a random short.
493    */
494   public static short getRandom(short l) {
495     return Integer.valueOf(_rand.nextInt()).shortValue();
496   }
497 
498   /**
499    * Returns a random double.
500    * 
501    * @param d An unused parameter, used only for polymorphism.
502    * @return a random double.
503    */
504   public static double getRandom(double d) {
505     return _rand.nextDouble();
506   }
507 
508   /**
509    * Returns a random printable char.
510    * 
511    * @param c An unused parameter, used only for polymorphism.
512    * @return a random printable char.
513    */
514   public static char getRandom(char c) {
515     return rndPrintableChar();
516   }
517 
518   /**
519    * Returns a random byte.
520    * 
521    * @param b An unused parameter, used only for polymorphism.
522    * @return a random byte.
523    */
524   public static byte getRandom(byte b) {
525     byte[] tmp = new byte[1]; // TODO: Cache more...
526     _rand.nextBytes(tmp);
527     return tmp[0];
528   }
529 
530 
531   /**
532    * Returns true or false randomly with equal probability.
533    * 
534    * @return true or false randomly with equal probability.
535    */
536   public static boolean flip() {
537     return _rand.nextBoolean();
538   }
539 
540   /**
541    * Returns true randomly with the probability p.
542    *
543    * @param p A probability for returning true
544    * @return true p% of the time
545    */
546   public static boolean flip(double p) {
547     return (_rand.nextDouble() < p) ? true : false;
548   }
549 
550   /**
551    * Returns a random printable character from the {@link #PRINTABLE_CHAR} string.
552    *
553    * @return a random printable character from the PRINTABLE_CHAR string.
554    */
555   public static char rndPrintableChar() {
556     return PRINTABLE_CHAR.charAt(_rand.nextInt(PRINTABLE_CHAR.length()));
557   }
558 
559   /**
560    * Returns the seed which was used to initialize the pseudo-random number generator.
561    *
562    * @return the seed which was used to initialize the pseudo-random number generator
563    */
564   public static long getSeed() {
565     return _seed;
566   }
567 
568   /**
569    * Re-initializes the random number generator with the given seed.
570    *
571    * @param seed the new seed for the random number generator.
572    */
573   public static void setSeed(long seed) {
574     _seed = seed;
575     _rand = new Random(_seed);
576   }
577 
578 }