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 }