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 }