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