1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 package org.codehaus.groovy.runtime;
36
37 import groovy.lang.*;
38 import groovy.util.CharsetToolkit;
39 import groovy.util.ClosureComparator;
40 import groovy.util.OrderBy;
41
42 import java.io.*;
43 import java.lang.reflect.Array;
44 import java.lang.reflect.Field;
45 import java.lang.reflect.Modifier;
46 import java.math.BigDecimal;
47 import java.math.BigInteger;
48 import java.net.MalformedURLException;
49 import java.net.ServerSocket;
50 import java.net.Socket;
51 import java.net.URI;
52 import java.net.URISyntaxException;
53 import java.net.URL;
54 import java.security.AccessController;
55 import java.security.PrivilegedAction;
56 import java.util.*;
57 import java.util.logging.Logger;
58 import java.util.regex.Matcher;
59 import java.util.regex.Pattern;
60
61 import org.codehaus.groovy.tools.RootLoader;
62
63 /***
64 * This class defines all the new groovy methods which appear on normal JDK
65 * classes inside the Groovy environment. Static methods are used with the
66 * first parameter the destination class.
67 *
68 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
69 * @author Jeremy Rayner
70 * @author Sam Pullara
71 * @author Rod Cope
72 * @author Guillaume Laforge
73 * @author John Wilson
74 * @author Hein Meling
75 * @author Dierk Koenig
76 * @author Pilho Kim
77 * @author Marc Guillemot
78 * @version $Revision: 1.207 $
79 */
80 public class DefaultGroovyMethods {
81
82 private static Logger log = Logger.getLogger(DefaultGroovyMethods.class.getName());
83
84 private static final Integer ONE = new Integer(1);
85 private static final char ZERO_CHAR = '\u0000';
86
87 /***
88 * Identity check. Since == is overridden in Groovy with the meaning of equality
89 * we need some fallback to check for object identity.
90 * @param self
91 * @param other
92 * @return true if self and other are identical, false otherwise
93 */
94 public static boolean is(Object self, Object other){
95 return self == other;
96 }
97
98 /***
99 * Allows the closure to be called for the object reference self
100 *
101 * @param self the object to have a closure act upon
102 * @param closure the closure to call on the object
103 * @return result of calling the closure
104 */
105 public static Object identity(Object self, Closure closure) {
106 closure.setDelegate(self);
107 return closure.call(self);
108 }
109
110 /***
111 * Allows the subscript operator to be used to lookup dynamic property values.
112 * <code>bean[somePropertyNameExpression]</code>. The normal property notation
113 * of groovy is neater and more concise but only works with compile time known
114 * property names.
115 *
116 * @param self
117 */
118 public static Object getAt(Object self, String property) {
119 return InvokerHelper.getProperty(self, property);
120 }
121
122 /***
123 * Allows the subscript operator to be used to set dynamically named property values.
124 * <code>bean[somePropertyNameExpression] = foo</code>. The normal property notation
125 * of groovy is neater and more concise but only works with compile time known
126 * property names.
127 *
128 * @param self
129 */
130 public static void putAt(Object self, String property, Object newValue) {
131 InvokerHelper.setProperty(self, property, newValue);
132 }
133
134 /***
135 * Generates a detailed dump string of an object showing its class,
136 * hashCode and fields
137 */
138 public static String dump(Object self) {
139 if (self == null) {
140 return "null";
141 }
142 StringBuffer buffer = new StringBuffer("<");
143 Class klass = self.getClass();
144 buffer.append(klass.getName());
145 buffer.append("@");
146 buffer.append(Integer.toHexString(self.hashCode()));
147 boolean groovyObject = self instanceof GroovyObject;
148
149
150
151
152
153 while (klass != null) {
154 Field[] fields = klass.getDeclaredFields();
155 for (int i = 0; i < fields.length; i++) {
156 final Field field = fields[i];
157 if ((field.getModifiers() & Modifier.STATIC) == 0) {
158 if (groovyObject && field.getName().equals("metaClass")) {
159 continue;
160 }
161 AccessController.doPrivileged(new PrivilegedAction() {
162 public Object run() {
163 field.setAccessible(true);
164 return null;
165 }
166 });
167 buffer.append(" ");
168 buffer.append(field.getName());
169 buffer.append("=");
170 try {
171 buffer.append(InvokerHelper.toString(field.get(self)));
172 } catch (Exception e) {
173 buffer.append(e);
174 }
175 }
176 }
177
178 klass = klass.getSuperclass();
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207 buffer.append(">");
208 return buffer.toString();
209 }
210
211 /***
212 * Retrieves the list of {@link MetaProperty} objects for 'self' and wraps it
213 * in a list of {@link PropertyValue} objects that additionally provide
214 * the value for each property of 'self'.
215 * @param self the receiver object
216 * @return list of {@link PropertyValue} objects
217 * @see groovy.util.Expando#getMetaPropertyValues()
218 */
219 public static List getMetaPropertyValues(Object self) {
220 MetaClass metaClass = InvokerHelper.getMetaClass(self);
221 List mps = metaClass.getProperties();
222 List props = new ArrayList(mps.size());
223 for (Iterator itr = mps.iterator(); itr.hasNext();) {
224 MetaProperty mp = (MetaProperty) itr.next();
225 PropertyValue pv = new PropertyValue(self, mp);
226 props.add(pv);
227 }
228 return props;
229 }
230
231 /***
232 * Convenience method that calls {@link #getMetaPropertyValues(Object)}(self)
233 * and provides the data in form of simple key/value pairs, i.e. without
234 * type() information.
235 * @param self the receiver object
236 * @return meta properties as Map of key/value pairs
237 */
238 public static Map getProperties(Object self) {
239 List metaProps = getMetaPropertyValues(self);
240 Map props = new HashMap(metaProps.size());
241
242 for (Iterator itr = metaProps.iterator(); itr.hasNext();) {
243 PropertyValue pv = (PropertyValue) itr.next();
244 try {
245 props.put(pv.getName(), pv.getValue());
246 } catch (Exception e) {
247 log.throwing(self.getClass().getName(), "getProperty("+pv.getName()+")", e );
248 }
249 }
250 return props;
251 }
252
253 /***
254 * Scoped use method
255 */
256 public static void use(Object self, Class categoryClass, Closure closure) {
257 GroovyCategorySupport.use(categoryClass, closure);
258 }
259
260 /***
261 * Scoped use method with list of categories
262 */
263 public static void use(Object self, List categoryClassList, Closure closure) {
264 GroovyCategorySupport.use(categoryClassList, closure);
265 }
266
267
268 /***
269 * Print to a console in interactive format
270 */
271 public static void print(Object self, Object value) {
272 System.out.print(InvokerHelper.toString(value));
273 }
274
275 /***
276 * Print a linebreak to the standard out.
277 */
278 public static void println(Object self) {
279 System.out.println();
280 }
281
282 /***
283 * Print to a console in interactive format along with a newline
284 */
285 public static void println(Object self, Object value) {
286 System.out.println(InvokerHelper.toString(value));
287 }
288
289 /***
290 * Printf to a console. Only works with JDK1.5 or later.
291 *
292 * @author Russel Winder
293 * @version 2005.02.01.15.53
294 */
295 public static void printf(final Object self, final String format, final Object[] values) {
296 if ( System.getProperty("java.version").charAt(2) == '5' ) {
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311 try {
312 System.out.getClass().getMethod("printf", new Class[] {String.class, Object[].class}).invoke(System.out, new Object[] {format, values}) ;
313 } catch ( NoSuchMethodException nsme ) {
314 throw new RuntimeException ("getMethod threw a NoSuchMethodException. This is impossible.") ;
315 } catch ( IllegalAccessException iae ) {
316 throw new RuntimeException ("invoke threw a IllegalAccessException. This is impossible.") ;
317 } catch ( java.lang.reflect.InvocationTargetException ite ) {
318 throw new RuntimeException ("invoke threw a InvocationTargetException. This is impossible.") ;
319 }
320 } else {
321 throw new RuntimeException ("printf requires JDK1.5 or later.") ;
322 }
323 }
324
325 /***
326 * Returns a formatted string using the specified format string and
327 * arguments.
328 *
329 * <p>
330 * For examples, <pre>
331 * printf ( "Hello, %s!\n" , [ "world" ] as String[] )
332 * printf ( "Hello, %s!\n" , [ "Groovy" ])
333 * printf ( "%d + %d = %d\n" , [ 1 , 2 , 1+2 ] as Integer[] )
334 * printf ( "%d + %d = %d\n" , [ 3 , 3 , 3+3 ])
335 *
336 * ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as Integer[] ) }
337 * ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as int[] ) }
338 * ( 0x41..0x45 ).each { printf ( "-- %c\n" , [ it ] as char[] ) }
339 * ( 07..011 ).each { printf ( "-- %d\n" , [ it ] as byte[] ) }
340 * ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as short[] ) }
341 * ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as long[] ) }
342 * ( 7..11 ).each { printf ( "-- %5.2f\n" , [ it ] as float[] ) }
343 * ( 7..11 ).each { printf ( "-- %5.2g\n" , [ it ] as double[] ) }
344 * </pre>
345 * <p>
346 *
347 * @param format
348 * A format string
349 *
350 * @param arg
351 * Argument which is referenced by the format specifiers in the format
352 * string. The type of <code>arg</code> should be one of Object[], List,
353 * int[], short[], byte[], char[], boolean[], long[], float[], or double[].
354 *
355 * @since JDK 1.5
356 *
357 * @author Pilho Kim
358 * @version 2005.07.25.02.31
359 */
360 public static void printf(final Object self, final String format, Object arg) {
361 if (arg instanceof Object[]) {
362 printf(self, format, (Object[]) arg);
363 return;
364 } else if (arg instanceof List) {
365 printf(self, format, ((List) arg).toArray());
366 return;
367 } else if (!arg.getClass().isArray()) {
368 Object[] o = (Object[]) java.lang.reflect.Array.newInstance(arg.getClass(), 1);
369 o[0]=arg;
370 printf(self, format, o);
371 return;
372 }
373
374 Object[] ans = null;
375 String elemType = arg.getClass().getName();
376 if (elemType.equals("[I")) {
377 int[] ia = (int[]) arg;
378 ans = new Integer[ia.length];
379 for (int i = 0; i < ia.length; i++) {
380 ans[i] = new Integer(ia[i]);
381 }
382 }
383 else if (elemType.equals("[C")) {
384 char[] ia = (char[]) arg;
385 ans = new Character[ia.length];
386 for (int i = 0; i < ia.length; i++) {
387 ans[i] = new Character(ia[i]);
388 }
389 }
390 else if (elemType.equals("[Z")) {
391 boolean[] ia = (boolean[]) arg;
392 ans = new Boolean[ia.length];
393 for (int i = 0; i < ia.length; i++) {
394 ans[i] = new Boolean(ia[i]);
395 }
396 }
397 else if (elemType.equals("[B")) {
398 byte[] ia = (byte[]) arg;
399 ans = new Byte[ia.length];
400 for (int i = 0; i < ia.length; i++) {
401 ans[i] = new Byte(ia[i]);
402 }
403 }
404 else if (elemType.equals("[S")) {
405 short[] ia = (short[]) arg;
406 ans = new Short[ia.length];
407 for (int i = 0; i < ia.length; i++) {
408 ans[i] = new Short(ia[i]);
409 }
410 }
411 else if (elemType.equals("[F")) {
412 float[] ia = (float[]) arg;
413 ans = new Float[ia.length];
414 for (int i = 0; i < ia.length; i++) {
415 ans[i] = new Float(ia[i]);
416 }
417 }
418 else if (elemType.equals("[J")) {
419 long[] ia = (long[]) arg;
420 ans = new Long[ia.length];
421 for (int i = 0; i < ia.length; i++) {
422 ans[i] = new Long(ia[i]);
423 }
424 }
425 else if (elemType.equals("[D")) {
426 double[] ia = (double[]) arg;
427 ans = new Double[ia.length];
428 for (int i = 0; i < ia.length; i++) {
429 ans[i] = new Double(ia[i]);
430 }
431 }
432 else {
433 throw new RuntimeException("printf(String," + arg + ")");
434 }
435 printf(self, format, (Object[]) ans);
436 }
437
438
439 /***
440 * @return a String that matches what would be typed into a terminal to
441 * create this object. e.g. [1, 'hello'].inspect() -> [1, "hello"]
442 */
443 public static String inspect(Object self) {
444 return InvokerHelper.inspect(self);
445 }
446
447 /***
448 * Print to a console in interactive format
449 */
450 public static void print(Object self, PrintWriter out) {
451 if (out == null) {
452 out = new PrintWriter(System.out);
453 }
454 out.print(InvokerHelper.toString(self));
455 }
456
457 /***
458 * Print to a console in interactive format
459 *
460 * @param out the PrintWriter used for printing
461 */
462 public static void println(Object self, PrintWriter out) {
463 if (out == null) {
464 out = new PrintWriter(System.out);
465 }
466 InvokerHelper.invokeMethod(self, "print", out);
467 out.println();
468 }
469
470 /***
471 * Provide a dynamic method invocation method which can be overloaded in
472 * classes to implement dynamic proxies easily.
473 */
474 public static Object invokeMethod(Object object, String method, Object arguments) {
475 return InvokerHelper.invokeMethod(object, method, arguments);
476 }
477
478
479
480 public static boolean isCase(Object caseValue, Object switchValue) {
481 return caseValue.equals(switchValue);
482 }
483
484 public static boolean isCase(String caseValue, Object switchValue) {
485 if (switchValue == null) {
486 return caseValue == null;
487 }
488 return caseValue.equals(switchValue.toString());
489 }
490
491 public static boolean isCase(Class caseValue, Object switchValue) {
492 if (switchValue instanceof Class) {
493 Class val = (Class) switchValue;
494 return caseValue.isAssignableFrom(val);
495 }
496 return caseValue.isInstance(switchValue);
497 }
498
499 public static boolean isCase(Collection caseValue, Object switchValue) {
500 return caseValue.contains(switchValue);
501 }
502
503 public static boolean isCase(Pattern caseValue, Object switchValue) {
504 if (switchValue == null) {
505 return caseValue == null;
506 }
507 final Matcher matcher = caseValue.matcher(switchValue.toString());
508 if (matcher.matches()) {
509 RegexSupport.setLastMatcher(matcher);
510 return true;
511 } else {
512 return false;
513 }
514 }
515
516 private static Object packArray(Object object) {
517 if (object instanceof Object[])
518 return new Object[] {object};
519 else
520 return object;
521 }
522
523
524
525
526 /***
527 * Remove all duplicates from a given Collection.
528 * Works on the receiver object and returns it.
529 * For each duplicate, only the first member which is returned
530 * by the given Collection's iterator is retained, but all other ones are removed.
531 * The given Collection's original order is retained.
532 * If there exists numbers in the Collection, then they are compared
533 * as numbers, that is, 2, 2.0, 3L, (short)4 are comparable.
534 *
535 * <code><pre>
536 * def x = [2, 2.0, 3L, 1.0, (short)4, 1]
537 * def y = x.unique()
538 * assert( y == x && x == [2, 3L, 1.0, (short)4] )
539 * </pre></code>
540 *
541 * @param self
542 * @return self without duplicates
543 */
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560 public static Collection unique(Collection self) {
561 if (self instanceof Set)
562 return self;
563 List answer = new ArrayList();
564 NumberComparator comparator = new NumberComparator();
565 for (Iterator it = self.iterator(); it.hasNext();) {
566 Object o = it.next();
567 boolean duplicated = false;
568 for (Iterator it2 = answer.iterator(); it2.hasNext();) {
569 Object o2 = it2.next();
570 if (comparator.compare(o, o2) == 0) {
571 duplicated = true;
572 break;
573 }
574 }
575 if (!duplicated)
576 answer.add(o);
577 }
578 self.clear();
579 self.addAll(answer);
580 return self;
581 }
582
583 /***
584 * Remove all duplicates from a given Collection.
585 * Works on the receiver object and returns it.
586 * The order of members in the Collection are compared by the given Comparator.
587 * For eachy duplicate, the first member which is returned
588 * by the given Collection's iterator is retained, but all other ones are removed.
589 * The given Collection's original order is retained.
590 *
591 * <code><pre>
592 * class Person {
593 * @Property fname, lname
594 * public String toString() {
595 * return fname + " " + lname
596 * }
597 * }
598 *
599 * class PersonComparator implements Comparator {
600 * public int compare(Object o1, Object o2) {
601 * Person p1 = (Person) o1
602 * Person p2 = (Person) o2
603 * if (p1.lname != p2.lname)
604 * return p1.lname.compareTo(p2.lname)
605 * else
606 * return p1.fname.compareTo(p2.fname)
607 * }
608 *
609 * public boolean equals(Object obj) {
610 * return this.equals(obj)
611 * }
612 * }
613 *
614 * Person a = new Person(fname:"John", lname:"Taylor")
615 * Person b = new Person(fname:"Clark", lname:"Taylor")
616 * Person c = new Person(fname:"Tom", lname:"Cruz")
617 * Person d = new Person(fname:"Clark", lname:"Taylor")
618 *
619 * def list = [a, b, c, d]
620 * List list2 = list.unique(new PersonComparator())
621 * assert( list2 == list && list == [a, b, c] )
622 *
623 * </pre></code>
624 *
625 * @param self a Collection
626 * @param comparator a Comparator.
627 * @return self without duplicates
628 */
629 public static Collection unique(Collection self, Comparator comparator) {
630 if (self instanceof Set)
631 return self;
632 List answer = new ArrayList();
633 for (Iterator it = self.iterator(); it.hasNext();) {
634 Object o = it.next();
635 boolean duplicated = false;
636 for (Iterator it2 = answer.iterator(); it2.hasNext();) {
637 Object o2 = it2.next();
638 if (comparator.compare(o, o2) == 0) {
639 duplicated = true;
640 break;
641 }
642 }
643 if (!duplicated)
644 answer.add(o);
645 }
646 self.clear();
647 self.addAll(answer);
648 return self;
649 }
650
651 /***
652 * Allows objects to be iterated through using a closure
653 *
654 * @param self the object over which we iterate
655 * @param closure the closure applied on each element found
656 */
657 public static void each(Object self, Closure closure) {
658 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
659 closure.call(iter.next());
660 }
661 }
662
663 /***
664 * Allows object to be iterated through a closure with a counter
665 *
666 * @param self an Object
667 * @param closure a Closure
668 */
669 public static void eachWithIndex(Object self, Closure closure) {
670 int counter = 0;
671 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
672 closure.call(new Object[]{iter.next(), new Integer(counter++)});
673 }
674 }
675
676 /***
677 * Allows objects to be iterated through using a closure
678 *
679 * @param self the collection over which we iterate
680 * @param closure the closure applied on each element of the collection
681 */
682 public static void each(Collection self, Closure closure) {
683 for (Iterator iter = self.iterator(); iter.hasNext();) {
684 closure.call(iter.next());
685 }
686 }
687
688 /***
689 * Allows a Map to be iterated through using a closure. If the
690 * closure takes one parameter then it will be passed the Map.Entry
691 * otherwise if the closure takes two parameters then it will be
692 * passed the key and the value.
693 *
694 * @param self the map over which we iterate
695 * @param closure the closure applied on each entry of the map
696 */
697 public static void each(Map self, Closure closure) {
698 for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
699 Map.Entry entry = (Map.Entry) iter.next();
700 callClosureForMapEntry(closure, entry);
701 }
702 }
703
704
705 /***
706 * Iterates over every element of a collection, and check whether a predicate is valid for all elements.
707 *
708 * @param self the object over which we iterate
709 * @param closure the closure predicate used for matching
710 * @return true if every item in the collection matches the closure
711 * predicate
712 */
713 public static boolean every(Object self, Closure closure) {
714 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
715 if (!InvokerHelper.asBool(closure.call(iter.next()))) {
716 return false;
717 }
718 }
719 return true;
720 }
721
722 /***
723 * Iterates over every element of a collection, and check whether a predicate is valid for at least one element
724 *
725 * @param self the object over which we iterate
726 * @param closure the closure predicate used for matching
727 * @return true if any item in the collection matches the closure predicate
728 */
729 public static boolean any(Object self, Closure closure) {
730 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
731 if (InvokerHelper.asBool(closure.call(iter.next()))) {
732 return true;
733 }
734 }
735 return false;
736 }
737
738 /***
739 * Iterates over every element of the collection and return each object that matches
740 * the given filter - calling the isCase() method used by switch statements.
741 * This method can be used with different kinds of filters like regular expresions, classes, ranges etc.
742 *
743 * @param self the object over which we iterate
744 * @param filter the filter to perform on the collection (using the isCase(object) method)
745 * @return a list of objects which match the filter
746 */
747 public static List grep(Object self, Object filter) {
748 List answer = new ArrayList();
749 MetaClass metaClass = InvokerHelper.getMetaClass(filter);
750 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
751 Object object = iter.next();
752 if (InvokerHelper.asBool(metaClass.invokeMethod(filter, "isCase", object))) {
753 answer.add(object);
754 }
755 }
756 return answer;
757 }
758
759 /***
760 * Counts the number of occurencies of the given value inside this collection
761 *
762 * @param self the collection within which we count the number of occurencies
763 * @param value the value
764 * @return the number of occurrencies
765 */
766 public static int count(Collection self, Object value) {
767 int answer = 0;
768 for (Iterator iter = self.iterator(); iter.hasNext();) {
769 if (InvokerHelper.compareEqual(iter.next(), value)) {
770 ++answer;
771 }
772 }
773 return answer;
774 }
775
776 /***
777 * Convert a collection to a List.
778 *
779 * @param self a collection
780 * @return a List
781 */
782 public static List toList(Collection self) {
783 List answer = new ArrayList(self.size());
784 answer.addAll(self);
785 return answer;
786 }
787
788 /***
789 * Iterates through this object transforming each object into a new value using the closure
790 * as a transformer, returning a list of transformed values.
791 *
792 * @param self the values of the object to map
793 * @param closure the closure used to map each element of the collection
794 * @return a List of the mapped values
795 */
796 public static List collect(Object self, Closure closure) {
797 return (List) collect(self, new ArrayList(), closure);
798 }
799
800 /***
801 * Iterates through this object transforming each object into a new value using the closure
802 * as a transformer and adding it to the collection, returning the resulting collection.
803 *
804 * @param self the values of the object to map
805 * @param collection the Collection to which the mapped values are added
806 * @param closure the closure used to map each element of the collection
807 * @return the resultant collection
808 */
809 public static Collection collect(Object self, Collection collection, Closure closure) {
810 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
811 collection.add(closure.call(iter.next()));
812 }
813 return collection;
814 }
815
816 /***
817 * Iterates through this collection transforming each entry into a new value using the closure
818 * as a transformer, returning a list of transformed values.
819 *
820 * @param self a collection
821 * @param closure the closure used for mapping
822 * @return a List of the mapped values
823 */
824 public static List collect(Collection self, Closure closure) {
825 return (List) collect(self, new ArrayList(self.size()), closure);
826 }
827
828 /***
829 * Iterates through this collection transforming each entry into a new value using the closure
830 * as a transformer, returning a list of transformed values.
831 *
832 * @param self a collection
833 * @param collection the Collection to which the mapped values are added
834 * @param closure the closure used to map each element of the collection
835 * @return the resultant collection
836 */
837 public static Collection collect(Collection self, Collection collection, Closure closure) {
838 for (Iterator iter = self.iterator(); iter.hasNext();) {
839 collection.add(closure.call(iter.next()));
840 if (closure.getDirective() == Closure.DONE) {
841 break;
842 }
843 }
844 return collection;
845 }
846
847 /***
848 * Iterates through this Map transforming each entry into a new value using the closure
849 * as a transformer, returning a list of transformed values.
850 *
851 * @param self a Map
852 * @param closure the closure used for mapping, which can be with one(Map.Entry) or two(key, value) parameters
853 * @return a List of the mapped values
854 */
855 public static Collection collect(Map self, Collection collection, Closure closure) {
856 boolean isTwoParams = (closure.getParameterTypes().length == 2);
857 for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
858 if (isTwoParams) {
859 Map.Entry entry = (Map.Entry) iter.next();
860 collection.add(closure.call(new Object[]{entry.getKey(), entry.getValue()}));
861 } else {
862 collection.add(closure.call(iter.next()));
863 }
864 }
865 return collection;
866 }
867
868 /***
869 * Iterates through this Map transforming each entry into a new value using the closure
870 * as a transformer, returning a list of transformed values.
871 *
872 * @param self a Map
873 * @param closure the closure used to map each element of the collection
874 * @return the resultant collection
875 */
876 public static List collect(Map self, Closure closure) {
877 return (List) collect(self, new ArrayList(self.size()), closure);
878 }
879
880 /***
881 * Finds the first value matching the closure condition
882 *
883 * @param self an Object with an iterator returning its values
884 * @param closure a closure condition
885 * @return the first Object found
886 */
887 public static Object find(Object self, Closure closure) {
888 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
889 Object value = iter.next();
890 if (InvokerHelper.asBool(closure.call(value))) {
891 return value;
892 }
893 }
894 return null;
895 }
896
897 /***
898 * Finds the first value matching the closure condition
899 *
900 * @param self a Collection
901 * @param closure a closure condition
902 * @return the first Object found
903 */
904 public static Object find(Collection self, Closure closure) {
905 for (Iterator iter = self.iterator(); iter.hasNext();) {
906 Object value = iter.next();
907 if (InvokerHelper.asBool(closure.call(value))) {
908 return value;
909 }
910 }
911 return null;
912 }
913
914 /***
915 * Finds the first value matching the closure condition
916 *
917 * @param self a Map
918 * @param closure a closure condition
919 * @return the first Object found
920 */
921 public static Object find(Map self, Closure closure) {
922 for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
923 Object value = iter.next();
924 if (InvokerHelper.asBool(closure.call(value))) {
925 return value;
926 }
927 }
928 return null;
929 }
930
931 /***
932 * Finds all values matching the closure condition
933 *
934 * @param self an Object with an Iterator returning its values
935 * @param closure a closure condition
936 * @return a List of the values found
937 */
938 public static List findAll(Object self, Closure closure) {
939 List answer = new ArrayList();
940 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
941 Object value = iter.next();
942 if (InvokerHelper.asBool(closure.call(value))) {
943 answer.add(value);
944 }
945 }
946 return answer;
947 }
948
949 /***
950 * Finds all values matching the closure condition
951 *
952 * @param self a Collection
953 * @param closure a closure condition
954 * @return a List of the values found
955 */
956 public static List findAll(Collection self, Closure closure) {
957 List answer = new ArrayList(self.size());
958 for (Iterator iter = self.iterator(); iter.hasNext();) {
959 Object value = iter.next();
960 if (InvokerHelper.asBool(closure.call(value))) {
961 answer.add(value);
962 }
963 }
964 return answer;
965 }
966
967 /***
968 * Finds all entries matching the closure condition. If the
969 * closure takes one parameter then it will be passed the Map.Entry
970 * otherwise if the closure takes two parameters then it will be
971 * passed the key and the value.
972 *
973 * @param self a Map
974 * @param closure a closure condition applying on the entries
975 * @return a new subMap
976 */
977 public static Map findAll(Map self, Closure closure) {
978 Map answer = new HashMap(self.size());
979 for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
980 Map.Entry entry = (Map.Entry) iter.next();
981 if (InvokerHelper.asBool(callClosureForMapEntry(closure, entry))) {
982 answer.put(entry.getKey(),entry.getValue());
983 }
984 }
985 return answer;
986 }
987
988
989 protected static Object callClosureForMapEntry(Closure closure, Map.Entry entry) {
990 if (closure.getMaximumNumberOfParameters() == 2) {
991 return closure.call(new Object[]{entry.getKey(), entry.getValue()});
992 }
993 return closure.call(entry);
994 }
995
996
997 /***
998 * Iterates through the given collection, passing in the initial value to
999 * the closure along with the current iterated item then passing into the
1000 * next iteration the value of the previous closure.
1001 *
1002 * @param self a Collection
1003 * @param value a value
1004 * @param closure a closure
1005 * @return the last value of the last iteration
1006 */
1007 public static Object inject(Collection self, Object value, Closure closure) {
1008 Object[] params = new Object[2];
1009 for (Iterator iter = self.iterator(); iter.hasNext();) {
1010 Object item = iter.next();
1011 params[0] = value;
1012 params[1] = item;
1013 value = closure.call(params);
1014 }
1015 return value;
1016 }
1017
1018 /***
1019 * Iterates through the given array of objects, passing in the initial value to
1020 * the closure along with the current iterated item then passing into the
1021 * next iteration the value of the previous closure.
1022 *
1023 * @param self an Object[]
1024 * @param value a value
1025 * @param closure a closure
1026 * @return the last value of the last iteration
1027 */
1028 public static Object inject(Object[] self, Object value, Closure closure) {
1029 Object[] params = new Object[2];
1030 for (int i = 0; i < self.length; i++) {
1031 params[0] = value;
1032 params[1] = self[i];
1033 value = closure.call(params);
1034 }
1035 return value;
1036 }
1037
1038 /***
1039 * Sums a collection of numeric values. <code>coll.sum()</code> is equivalent to:
1040 * <code>coll.inject(0) {value, item -> value + item}</code>.
1041 *
1042 * @param self Collection of values to add together.
1043 * @return The sum of all of the list itmems.
1044 */
1045 public static Object sum(Collection self) {
1046 Object result = null;
1047
1048 if (self.size() == 0) return result;
1049
1050 boolean isNumber = true;
1051
1052 Class classref = null;
1053 try {
1054 classref = Class.forName("java.lang.Number");
1055 } catch (Exception ex) {
1056 }
1057
1058 for (Iterator iter = self.iterator(); iter.hasNext(); ) {
1059 if (!classref.isInstance(iter.next())) {
1060 isNumber = false;
1061 break;
1062 }
1063 }
1064
1065 if (isNumber) {
1066 result = new Integer(0);
1067 } else {
1068 result = new String();
1069 }
1070
1071 Object[] param = new Object[1];
1072 for (Iterator iter = self.iterator(); iter.hasNext();) {
1073 Object operand = iter.next();
1074 param[0] = operand;
1075 MetaClass metaClass = InvokerHelper.getMetaClass(result);
1076 result = metaClass.invokeMethod(result, "plus", param);
1077 }
1078 return result;
1079 }
1080
1081 /***
1082 * Sums the result of apply a closure to each item of a collection.
1083 * <code>coll.sum(closure)</code> is equivalent to:
1084 * <code>coll.collect(closure).sum()</code>.
1085 *
1086 * @param self a Collection
1087 * @param closure a single parameter closure that returns a numeric value.
1088 * @return The sum of the values returned by applying the closure to each
1089 * item of the list.
1090 */
1091 public static Object sum(Collection self, Closure closure) {
1092 Object result = new Integer(0);
1093 Object[] closureParam = new Object[1];
1094 Object[] plusParam = new Object[1];
1095 for (Iterator iter = self.iterator(); iter.hasNext();) {
1096 Object item = iter.next();
1097 closureParam[0] = item;
1098 plusParam[0] = closure.call(closureParam);
1099 MetaClass metaClass = InvokerHelper.getMetaClass(result);
1100 result = metaClass.invokeMethod(result, "plus", plusParam);
1101 }
1102 return result;
1103 }
1104
1105 /***
1106 * Concatenates all of the items of the collection together with the given String as a separator
1107 *
1108 * @param self a Collection of objects
1109 * @param separator a String separator
1110 * @return the joined String
1111 */
1112 public static String join(Collection self, String separator) {
1113 StringBuffer buffer = new StringBuffer();
1114 boolean first = true;
1115
1116 if (separator == null) separator = "";
1117
1118 for (Iterator iter = self.iterator(); iter.hasNext();) {
1119 Object value = iter.next();
1120 if (first) {
1121 first = false;
1122 } else {
1123 buffer.append(separator);
1124 }
1125 buffer.append(InvokerHelper.toString(value));
1126 }
1127 return buffer.toString();
1128 }
1129
1130 /***
1131 * Concatenates all of the elements of the array together with the given String as a separator
1132 *
1133 * @param self an array of Object
1134 * @param separator a String separator
1135 * @return the joined String
1136 */
1137 public static String join(Object[] self, String separator) {
1138 StringBuffer buffer = new StringBuffer();
1139 boolean first = true;
1140
1141 if (separator == null) separator = "";
1142
1143 for (int i = 0; i < self.length; i++) {
1144 String value = InvokerHelper.toString(self[i]);
1145 if (first) {
1146 first = false;
1147 } else {
1148 buffer.append(separator);
1149 }
1150 buffer.append(value);
1151 }
1152 return buffer.toString();
1153 }
1154
1155 /***
1156 * Selects the maximum value found in the collection
1157 *
1158 * @param self a Collection
1159 * @return the maximum value
1160 */
1161 public static Object max(Collection self) {
1162 Object answer = null;
1163 for (Iterator iter = self.iterator(); iter.hasNext();) {
1164 Object value = iter.next();
1165 if (value != null) {
1166 if (answer == null || InvokerHelper.compareGreaterThan(value, answer)) {
1167 answer = value;
1168 }
1169 }
1170 }
1171 return answer;
1172 }
1173
1174 /***
1175 * Selects the maximum value found in the collection using the given comparator
1176 *
1177 * @param self a Collection
1178 * @param comparator a Comparator
1179 * @return the maximum value
1180 */
1181 public static Object max(Collection self, Comparator comparator) {
1182 Object answer = null;
1183 for (Iterator iter = self.iterator(); iter.hasNext();) {
1184 Object value = iter.next();
1185 if (answer == null || comparator.compare(value, answer) > 0) {
1186 answer = value;
1187 }
1188 }
1189 return answer;
1190 }
1191
1192 /***
1193 * Selects the minimum value found in the collection
1194 *
1195 * @param self a Collection
1196 * @return the minimum value
1197 */
1198 public static Object min(Collection self) {
1199 Object answer = null;
1200 for (Iterator iter = self.iterator(); iter.hasNext();) {
1201 Object value = iter.next();
1202 if (value != null) {
1203 if (answer == null || InvokerHelper.compareLessThan(value, answer)) {
1204 answer = value;
1205 }
1206 }
1207 }
1208 return answer;
1209 }
1210
1211 /***
1212 * Selects the minimum value found in the collection using the given comparator
1213 *
1214 * @param self a Collection
1215 * @param comparator a Comparator
1216 * @return the minimum value
1217 */
1218 public static Object min(Collection self, Comparator comparator) {
1219 Object answer = null;
1220 for (Iterator iter = self.iterator(); iter.hasNext();) {
1221 Object value = iter.next();
1222 if (answer == null || comparator.compare(value, answer) < 0) {
1223 answer = value;
1224 }
1225 }
1226 return answer;
1227 }
1228
1229 /***
1230 * Selects the minimum value found in the collection using the given closure as a comparator
1231 *
1232 * @param self a Collection
1233 * @param closure a closure used as a comparator
1234 * @return the minimum value
1235 */
1236 public static Object min(Collection self, Closure closure) {
1237 int params = closure.getMaximumNumberOfParameters();
1238 if (params == 1) {
1239 Object answer = null;
1240 Object answer_value = null;
1241 for (Iterator iter = self.iterator(); iter.hasNext();) {
1242 Object item = iter.next();
1243 Object value = closure.call(item);
1244 if (answer == null || InvokerHelper.compareLessThan(value, answer_value)) {
1245 answer = item;
1246 answer_value = value;
1247 }
1248 }
1249 return answer;
1250 } else {
1251 return min(self, new ClosureComparator(closure));
1252 }
1253 }
1254
1255 /***
1256 * Selects the maximum value found in the collection using the given closure as a comparator
1257 *
1258 * @param self a Collection
1259 * @param closure a closure used as a comparator
1260 * @return the maximum value
1261 */
1262 public static Object max(Collection self, Closure closure) {
1263 int params = closure.getMaximumNumberOfParameters();
1264 if (params == 1) {
1265 Object answer = null;
1266 Object answer_value = null;
1267 for (Iterator iter = self.iterator(); iter.hasNext();) {
1268 Object item = iter.next();
1269 Object value = closure.call(item);
1270 if (answer == null || InvokerHelper.compareLessThan(answer_value, value)) {
1271 answer = item;
1272 answer_value = value;
1273 }
1274 }
1275 return answer;
1276 } else {
1277 return max(self, new ClosureComparator(closure));
1278 }
1279 }
1280
1281 /***
1282 * Makes a String look like a Collection by adding support for the size() method
1283 *
1284 * @param text a String
1285 * @return the length of the String
1286 */
1287 public static int size(String text) {
1288 return text.length();
1289 }
1290
1291 /***
1292 * Provide standard Groovy size() method for StringBuffers
1293 *
1294 * @param buffer a StringBuffer
1295 * @return the length of the StringBuffer
1296 */
1297 public static int size(StringBuffer buffer) {
1298 return buffer.length();
1299 }
1300
1301 /***
1302 * Provide the standard Groovy size method
1303 */
1304 public static long size(File file){
1305 return file.length();
1306 }
1307
1308
1309 /***
1310 * Provide the standard Groovy size method
1311 */
1312 public static long size(Matcher matcher){
1313 return getCount(matcher);
1314 }
1315
1316 /***
1317 * Makes an Array look like a Collection by adding support for the size() method
1318 *
1319 * @param self an Array of Object
1320 * @return the size of the Array
1321 */
1322 public static int size(Object[] self) {
1323 return self.length;
1324 }
1325
1326 /***
1327 * Support the subscript operator for String.
1328 *
1329 * @param text a String
1330 * @param index the index of the Character to get
1331 * @return the Character at the given index
1332 */
1333 public static CharSequence getAt(CharSequence text, int index) {
1334 index = normaliseIndex(index, text.length());
1335 return text.subSequence(index, index + 1);
1336 }
1337
1338 /***
1339 * Support the subscript operator for String
1340 *
1341 * @param text a String
1342 * @return the Character object at the given index
1343 */
1344 public static String getAt(String text, int index) {
1345 index = normaliseIndex(index, text.length());
1346 return text.substring(index, index + 1);
1347 }
1348
1349 /***
1350 * Support the range subscript operator for CharSequence
1351 *
1352 * @param text a CharSequence
1353 * @param range a Range
1354 * @return the subsequence CharSequence
1355 */
1356 public static CharSequence getAt(CharSequence text, Range range) {
1357 int from = normaliseIndex(InvokerHelper.asInt(range.getFrom()), text.length());
1358 int to = normaliseIndex(InvokerHelper.asInt(range.getTo()), text.length());
1359
1360
1361 if (from > to) {
1362 int tmp = from;
1363 from = to;
1364 to = tmp;
1365 }
1366
1367 return text.subSequence(from, to + 1);
1368 }
1369
1370 /***
1371 * Support the range subscript operator for CharSequence or StringBuffer with IntRange
1372 *
1373 * @param text a CharSequence
1374 * @param range an IntRange
1375 * @return the subsequence CharSequence
1376 */
1377 public static CharSequence getAt(CharSequence text, IntRange range) {
1378 return getAt(text, (Range) range);
1379 }
1380
1381 /***
1382 * Support the range subscript operator for String with IntRange
1383 *
1384 * @param text a String
1385 * @param range an IntRange
1386 * @return the resulting String
1387 */
1388 public static String getAt(String text, IntRange range) {
1389 return getAt(text,(Range)range);
1390 }
1391
1392 /***
1393 * Support the range subscript operator for String
1394 *
1395 * @param text a String
1396 * @param range a Range
1397 * @return a substring corresponding to the Range
1398 */
1399 public static String getAt(String text, Range range) {
1400 int from = normaliseIndex(InvokerHelper.asInt(range.getFrom()), text.length());
1401 int to = normaliseIndex(InvokerHelper.asInt(range.getTo()), text.length());
1402
1403
1404 boolean reverse = range.isReverse();
1405 if (from > to) {
1406 int tmp = to;
1407 to = from;
1408 from = tmp;
1409 reverse = !reverse;
1410 }
1411
1412 String answer = text.substring(from, to + 1);
1413 if (reverse) {
1414 answer = reverse(answer);
1415 }
1416 return answer;
1417 }
1418
1419 /***
1420 * Creates a new string which is the reverse (backwards) of this string
1421 *
1422 * @param self a String
1423 * @return a new string with all the characters reversed.
1424 */
1425 public static String reverse(String self) {
1426 int size = self.length();
1427 StringBuffer buffer = new StringBuffer(size);
1428 for (int i = size - 1; i >= 0; i--) {
1429 buffer.append(self.charAt(i));
1430 }
1431 return buffer.toString();
1432 }
1433
1434 /***
1435 * Transforms a String representing a URL into a URL object.
1436 *
1437 * @param self the String representing a URL
1438 * @return a URL
1439 * @throws MalformedURLException is thrown if the URL is not well formed.
1440 */
1441 public static URL toURL(String self) throws MalformedURLException {
1442 return new URL(self);
1443 }
1444
1445 /***
1446 * Transforms a String representing a URI into a URI object.
1447 *
1448 * @param self the String representing a URI
1449 * @return a URI
1450 * @throws URISyntaxException
1451 * @throws URISyntaxException is thrown if the URI is not well formed.
1452 */
1453 public static URI toURI(String self) throws URISyntaxException {
1454 return new URI(self);
1455 }
1456
1457 /***
1458 * Turns a String into a regular expression pattern
1459 *
1460 * @param self a String to convert into a regular expression
1461 * @return the regular expression pattern
1462 */
1463 public static Pattern negate(String self) {
1464 return InvokerHelper.regexPattern(self);
1465 }
1466
1467 /***
1468 * Replaces all occurrencies of a captured group by the result of a closure on that text.
1469 *
1470 * <p> For examples,
1471 * <pre>
1472 * assert "FOOBAR-FOOBAR-" == "foobar-FooBar-".replaceAll("(([fF][oO]{2})[bB]ar)", { Object[] it -> it[0].toUpperCase() })
1473 *
1474 * Here,
1475 * it[0] is the global string of the matched group
1476 * it[1] is the first string in the matched group
1477 * it[2] is the second string in the matched group
1478 *
1479 *
1480 * assert "FOO-FOO-" == "foobar-FooBar-".replaceAll("(([fF][oO]{2})[bB]ar)", { x, y, z -> z.toUpperCase() })
1481 *
1482 * Here,
1483 * x is the global string of the matched group
1484 * y is the first string in the matched group
1485 * z is the second string in the matched group
1486 * </pre>
1487 *
1488 * @param self a String
1489 * @param regex the capturing regex
1490 * @param closure the closure to apply on each captured group
1491 * @return a String with replaced content
1492 */
1493 public static String replaceAll(String self, String regex, Closure closure) {
1494 Matcher matcher = Pattern.compile(regex).matcher(self);
1495 if (matcher.find()) {
1496 matcher.reset();
1497 StringBuffer sb = new StringBuffer();
1498 while (matcher.find()) {
1499 int count = matcher.groupCount();
1500 ArrayList groups = new ArrayList();
1501 for (int i = 0; i <= count; i++) {
1502 groups.add(matcher.group(i));
1503 }
1504 matcher.appendReplacement(sb, String.valueOf(closure.call((Object[]) groups.toArray() )));
1505 }
1506 matcher.appendTail(sb);
1507 return sb.toString();
1508 } else {
1509 return self;
1510 }
1511 }
1512
1513 private static String getPadding(String padding, int length) {
1514 if (padding.length() < length) {
1515 return multiply(padding, new Integer(length / padding.length() + 1)).substring(0, length);
1516 } else {
1517 return padding.substring(0, length);
1518 }
1519 }
1520
1521 /***
1522 * Pad a String with the characters appended to the left
1523 *
1524 * @param numberOfChars the total number of characters
1525 * @param padding the charaters used for padding
1526 * @return the String padded to the left
1527 */
1528 public static String padLeft(String self, Number numberOfChars, String padding) {
1529 int numChars = numberOfChars.intValue();
1530 if (numChars <= self.length()) {
1531 return self;
1532 } else {
1533 return getPadding(padding, numChars - self.length()) + self;
1534 }
1535 }
1536
1537 /***
1538 * Pad a String with the spaces appended to the left
1539 *
1540 * @param numberOfChars the total number of characters
1541 * @return the String padded to the left
1542 */
1543
1544 public static String padLeft(String self, Number numberOfChars) {
1545 return padLeft(self, numberOfChars, " ");
1546 }
1547
1548 /***
1549 * Pad a String with the characters appended to the right
1550 *
1551 * @param numberOfChars the total number of characters
1552 * @param padding the charaters used for padding
1553 * @return the String padded to the right
1554 */
1555
1556 public static String padRight(String self, Number numberOfChars, String padding) {
1557 int numChars = numberOfChars.intValue();
1558 if (numChars <= self.length()) {
1559 return self;
1560 } else {
1561 return self + getPadding(padding, numChars - self.length());
1562 }
1563 }
1564
1565 /***
1566 * Pad a String with the spaces appended to the right
1567 *
1568 * @param numberOfChars the total number of characters
1569 * @return the String padded to the right
1570 */
1571
1572 public static String padRight(String self, Number numberOfChars) {
1573 return padRight(self, numberOfChars, " ");
1574 }
1575
1576 /***
1577 * Center a String and padd it with the characters appended around it
1578 *
1579 * @param numberOfChars the total number of characters
1580 * @param padding the charaters used for padding
1581 * @return the String centered with padded character around
1582 */
1583 public static String center(String self, Number numberOfChars, String padding) {
1584 int numChars = numberOfChars.intValue();
1585 if (numChars <= self.length()) {
1586 return self;
1587 } else {
1588 int charsToAdd = numChars - self.length();
1589 String semiPad = charsToAdd % 2 == 1 ?
1590 getPadding(padding, charsToAdd / 2 + 1) :
1591 getPadding(padding, charsToAdd / 2);
1592 if (charsToAdd % 2 == 0)
1593 return semiPad + self + semiPad;
1594 else
1595 return semiPad.substring(0, charsToAdd / 2) + self + semiPad;
1596 }
1597 }
1598
1599 /***
1600 * Center a String and padd it with spaces appended around it
1601 *
1602 * @param numberOfChars the total number of characters
1603 * @return the String centered with padded character around
1604 */
1605 public static String center(String self, Number numberOfChars) {
1606 return center(self, numberOfChars, " ");
1607 }
1608
1609 /***
1610 * Support the subscript operator, e.g. matcher[index], for a regex Matcher.
1611 *
1612 * For an example using no group match, <code><pre>
1613 * def p = /ab[d|f]/
1614 * def m = "abcabdabeabf" =~ p
1615 * for (i in 0..<m.count) {
1616 * println( "m.groupCount() = " + m.groupCount())
1617 * println( " " + i + ": " + m[i] ) // m[i] is a String
1618 * }
1619 * </pre></code>
1620 *
1621 * For an example using group matches, <code><pre>
1622 * def p = /(?:ab([c|d|e|f]))/
1623 * def m = "abcabdabeabf" =~ p
1624 * for (i in 0..<m.count) {
1625 * println( "m.groupCount() = " + m.groupCount())
1626 * println( " " + i + ": " + m[i] ) // m[i] is a List
1627 * }
1628 * </pre></code>
1629 *
1630 * For another example using group matches, <code><pre>
1631 * def m = "abcabdabeabfabxyzabx" =~ /(?:ab([d|x-z]+))/
1632 * m.count.times {
1633 * println( "m.groupCount() = " + m.groupCount())
1634 * println( " " + it + ": " + m[it] ) // m[it] is a List
1635 * }
1636 * </pre></code>
1637 *
1638 * @param matcher a Matcher
1639 * @param idx an index
1640 * @return object a matched String if no groups matched, list of matched groups otherwise.
1641 */
1642 public static Object getAt(Matcher matcher, int idx) {
1643 try {
1644 int count = getCount(matcher);
1645 if (idx < -count || idx >= count) {
1646 throw new IndexOutOfBoundsException("index is out of range " + (-count) + ".." + (count - 1) + " (index = " + idx + ")");
1647 }
1648 idx = normaliseIndex(idx, count);
1649 matcher.reset();
1650 for (int i = 0; i <= idx; i++) {
1651 matcher.find();
1652 }
1653
1654 if (hasGroup(matcher)) {
1655
1656
1657 ArrayList list = new ArrayList(matcher.groupCount());
1658 for (int i = 0; i <= matcher.groupCount(); i++) {
1659 list.add(matcher.group(i));
1660 }
1661 return list;
1662 } else {
1663
1664
1665 return matcher.group();
1666 }
1667 }
1668 catch (IllegalStateException ex) {
1669 return null;
1670 }
1671 }
1672
1673 /***
1674 * Set the position of the given Matcher to the given index.
1675 *
1676 * @param matcher a Matcher
1677 * @param idx the index number
1678 */
1679 public static void setIndex(Matcher matcher, int idx) {
1680 int count = getCount(matcher);
1681 if (idx < -count || idx >= count) {
1682 throw new IndexOutOfBoundsException("index is out of range " + (-count) + ".." + (count - 1) + " (index = " + idx + ")");
1683 }
1684 if (idx == 0) {
1685 matcher.reset();
1686 }
1687 else if (idx > 0) {
1688 matcher.reset();
1689 for (int i = 0; i < idx; i++) {
1690 matcher.find();
1691 }
1692 }
1693 else if (idx < 0) {
1694 matcher.reset();
1695 idx += getCount(matcher);
1696 for (int i = 0; i < idx; i++) {
1697 matcher.find();
1698 }
1699 }
1700 }
1701
1702 /***
1703 * Find the number of Strings matched to the given Matcher.
1704 *
1705 * @param matcher a Matcher
1706 * @return int the number of Strings matched to the given matcher.
1707 */
1708 public static int getCount(Matcher matcher) {
1709 int counter = 0;
1710 matcher.reset();
1711 while (matcher.find()) {
1712 counter++;
1713 }
1714 matcher.reset();
1715 return counter;
1716 }
1717
1718 /***
1719 * Check whether a Matcher contains a group or not.
1720 *
1721 * @param matcher a Matcher
1722 * @return boolean <code>true</code> if matcher contains at least one group.
1723 */
1724 public static boolean hasGroup(Matcher matcher) {
1725 return matcher.groupCount() > 0;
1726 }
1727
1728 /***
1729 * Support the range subscript operator for a List
1730 *
1731 * @param self a List
1732 * @param range a Range
1733 * @return a sublist based on range borders or a new list if range is reversed
1734 * @see java.util.List#subList(int, int)
1735 */
1736 public static List getAt(List self, IntRange range) {
1737 RangeInfo info = subListBorders(self.size(), range);
1738 List answer = self.subList(info.from, info.to);
1739 if (info.reverse) {
1740 answer = reverse(answer);
1741 }
1742 return answer;
1743 }
1744
1745
1746 protected static RangeInfo subListBorders(int size, IntRange range){
1747 int from = normaliseIndex(InvokerHelper.asInt(range.getFrom()), size);
1748 int to = normaliseIndex(InvokerHelper.asInt(range.getTo()), size);
1749 boolean reverse = range.isReverse();
1750 if (from > to) {
1751 int tmp = to;
1752 to = from;
1753 from = tmp;
1754 reverse = !reverse;
1755 }
1756 return new RangeInfo(from, to+1, reverse);
1757 }
1758
1759
1760 protected static RangeInfo subListBorders(int size, EmptyRange range){
1761 int from = normaliseIndex(InvokerHelper.asInt(range.getFrom()), size);
1762 return new RangeInfo(from, from, false);
1763 }
1764
1765 /***
1766 * Allows a List to be used as the indices to be used on a List
1767 *
1768 * @param self a List
1769 * @param indices a Collection of indices
1770 * @return a new list of the values at the given indices
1771 */
1772 public static List getAt(List self, Collection indices) {
1773 List answer = new ArrayList(indices.size());
1774 for (Iterator iter = indices.iterator(); iter.hasNext();) {
1775 Object value = iter.next();
1776 if (value instanceof Range) {
1777 answer.addAll(getAt(self, (Range) value));
1778 } else if (value instanceof List) {
1779 answer.addAll(getAt(self, (List) value));
1780 } else {
1781 int idx = InvokerHelper.asInt(value);
1782 answer.add(getAt(self, idx));
1783 }
1784 }
1785 return answer;
1786 }
1787
1788 /***
1789 * Allows a List to be used as the indices to be used on a List
1790 *
1791 * @param self an Array of Objects
1792 * @param indices a Collection of indices
1793 * @return a new list of the values at the given indices
1794 */
1795 public static List getAt(Object[] self, Collection indices) {
1796 List answer = new ArrayList(indices.size());
1797 for (Iterator iter = indices.iterator(); iter.hasNext();) {
1798 Object value = iter.next();
1799 if (value instanceof Range) {
1800 answer.addAll(getAt(self, (Range) value));
1801 } else if (value instanceof Collection) {
1802 answer.addAll(getAt(self, (Collection) value));
1803 } else {
1804 int idx = InvokerHelper.asInt(value);
1805 answer.add(getAt(self, idx));
1806 }
1807 }
1808 return answer;
1809 }
1810
1811 /***
1812 * Allows a List to be used as the indices to be used on a CharSequence
1813 *
1814 * @param self a CharSequence
1815 * @param indices a Collection of indices
1816 * @return a String of the values at the given indices
1817 */
1818 public static CharSequence getAt(CharSequence self, Collection indices) {
1819 StringBuffer answer = new StringBuffer();
1820 for (Iterator iter = indices.iterator(); iter.hasNext();) {
1821 Object value = iter.next();
1822 if (value instanceof Range) {
1823 answer.append(getAt(self, (Range) value));
1824 } else if (value instanceof Collection) {
1825 answer.append(getAt(self, (Collection) value));
1826 } else {
1827 int idx = InvokerHelper.asInt(value);
1828 answer.append(getAt(self, idx));
1829 }
1830 }
1831 return answer.toString();
1832 }
1833
1834 /***
1835 * Allows a List to be used as the indices to be used on a String
1836 *
1837 * @param self a String
1838 * @param indices a Collection of indices
1839 * @return a String of the values at the given indices
1840 */
1841 public static String getAt(String self, Collection indices) {
1842 return (String) getAt((CharSequence) self, indices);
1843 }
1844
1845 /***
1846 * Allows a List to be used as the indices to be used on a Matcher
1847 *
1848 * @param self a Matcher
1849 * @param indices a Collection of indices
1850 * @return a String of the values at the given indices
1851 */
1852 public static String getAt(Matcher self, Collection indices) {
1853 StringBuffer answer = new StringBuffer();
1854 for (Iterator iter = indices.iterator(); iter.hasNext();) {
1855 Object value = iter.next();
1856 if (value instanceof Range) {
1857 answer.append(getAt(self, (Range) value));
1858 } else if (value instanceof Collection) {
1859 answer.append(getAt(self, (Collection) value));
1860 } else {
1861 int idx = InvokerHelper.asInt(value);
1862 answer.append(getAt(self, idx));
1863 }
1864 }
1865 return answer.toString();
1866 }
1867
1868 /***
1869 * Creates a sub-Map containing the given keys. This method is similar to
1870 * List.subList() but uses keys rather than index ranges.
1871 *
1872 * @param map a Map
1873 * @param keys a Collection of keys
1874 * @return a new Map containing the given keys
1875 */
1876 public static Map subMap(Map map, Collection keys) {
1877 Map answer = new HashMap(keys.size());
1878 for (Iterator iter = keys.iterator(); iter.hasNext();) {
1879 Object key = iter.next();
1880 answer.put(key, map.get(key));
1881 }
1882 return answer;
1883 }
1884
1885 /***
1886 * Looks up an item in a Map for the given key and returns the value - unless
1887 * there is no entry for the given key in which case add the default value
1888 * to the map and return that.
1889 *
1890 * @param map a Map
1891 * @param key the key to lookup the value of
1892 * @param defaultValue the value to return and add to the map for this key if
1893 * there is no entry for the given key
1894 * @return the value of the given key or the default value, added to the map if the
1895 * key did not exist
1896 */
1897 public static Object get(Map map, Object key, Object defaultValue) {
1898 Object answer = map.get(key);
1899 if (answer == null) {
1900 answer = defaultValue;
1901 map.put(key, answer);
1902 }
1903 return answer;
1904 }
1905
1906 /***
1907 * Support the range subscript operator for an Array
1908 *
1909 * @param array an Array of Objects
1910 * @param range a Range
1911 * @return a range of a list from the range's from index up to but not
1912 * including the ranges's to value
1913 */
1914 public static List getAt(Object[] array, Range range) {
1915 List list = Arrays.asList(array);
1916 return getAt(list, range);
1917 }
1918
1919 public static List getAt(Object[] array, IntRange range) {
1920 List list = Arrays.asList(array);
1921 return getAt(list, range);
1922 }
1923
1924 public static List getAt(Object[] array, ObjectRange range) {
1925 List list = Arrays.asList(array);
1926 return getAt(list, range);
1927 }
1928
1929 /***
1930 * Support the subscript operator for an Array
1931 *
1932 * @param array an Array of Objects
1933 * @param idx an index
1934 * @return the value at the given index
1935 */
1936 public static Object getAt(Object[] array, int idx) {
1937 return array[normaliseIndex(idx, array.length)];
1938 }
1939
1940 /***
1941 * Support the subscript operator for an Array
1942 *
1943 * @param array an Array of Objects
1944 * @param idx an index
1945 * @param value an Object to put at the given index
1946 */
1947 public static void putAt(Object[] array, int idx, Object value) {
1948 if (value instanceof Number) {
1949 Class arrayComponentClass = array.getClass().getComponentType();
1950
1951 if (!arrayComponentClass.equals(value.getClass())) {
1952 Object newVal = InvokerHelper.asType(value, arrayComponentClass);
1953 array[normaliseIndex(idx, array.length)] = newVal;
1954 return;
1955 }
1956 }
1957 array[normaliseIndex(idx, array.length)] = value;
1958 }
1959
1960 /***
1961 * Allows conversion of arrays into a mutable List
1962 *
1963 * @param array an Array of Objects
1964 * @return the array as a List
1965 */
1966 public static List toList(Object[] array) {
1967 int size = array.length;
1968 List list = new ArrayList(size);
1969 for (int i = 0; i < size; i++) {
1970 list.add(array[i]);
1971 }
1972 return list;
1973 }
1974
1975 /***
1976 * Support the subscript operator for a List
1977 *
1978 * @param self a List
1979 * @param idx an index
1980 * @return the value at the given index
1981 */
1982 public static Object getAt(List self, int idx) {
1983 int size = self.size();
1984 int i = normaliseIndex(idx, size);
1985 if (i < size) {
1986 return self.get(i);
1987 } else {
1988 return null;
1989 }
1990 }
1991
1992 /***
1993 * A helper method to allow lists to work with subscript operators
1994 *
1995 * @param self a List
1996 * @param idx an index
1997 * @param value the value to put at the given index
1998 */
1999 public static void putAt(List self, int idx, Object value) {
2000 int size = self.size();
2001 idx = normaliseIndex(idx, size);
2002 if (idx < size) {
2003 self.set(idx, value);
2004 } else {
2005 while (size < idx) {
2006 self.add(size++, null);
2007 }
2008 self.add(idx, value);
2009 }
2010 }
2011
2012
2013 /***
2014 * Support the range subscript operator for StringBuffer
2015 *
2016 * @param self a StringBuffer
2017 * @param range a Range
2018 * @param value the object that's toString() will be inserted
2019 */
2020 public static void putAt(StringBuffer self, IntRange range, Object value) {
2021 RangeInfo info = subListBorders(self.length(), range);
2022 self.replace(info.from, info.to, value.toString());
2023 }
2024 /***
2025 * Support the range subscript operator for StringBuffer
2026 *
2027 * @param self a StringBuffer
2028 * @param range a Range
2029 * @param value the object that's toString() will be inserted
2030 */
2031 public static void putAt(StringBuffer self, EmptyRange range, Object value) {
2032 RangeInfo info = subListBorders(self.length(), range);
2033 self.replace(info.from, info.to, value.toString());
2034 }
2035
2036 /***
2037 * A helper method to allow lists to work with subscript operators
2038 *
2039 * @param self a List
2040 * @param range the subset of the list to set
2041 * @param value the values to put at the given sublist or a Collection of values
2042 */
2043 public static void putAt(List self, EmptyRange range, Object value) {
2044 RangeInfo info = subListBorders(self.size(), range);
2045 List sublist = self.subList(info.from, info.to);
2046 sublist.clear();
2047 if (value instanceof Collection){
2048 Collection col = (Collection) value;
2049 if (col.size() == 0) return;
2050 sublist.addAll(col);
2051 } else {
2052 sublist.add(value);
2053 }
2054 }
2055
2056 /***
2057 * A helper method to allow lists to work with subscript operators
2058 *
2059 * @param self a List
2060 * @param range the subset of the list to set
2061 * @param value the value to put at the given sublist or a Collection of values
2062 */
2063 public static void putAt(List self, IntRange range, Object value) {
2064 RangeInfo info = subListBorders(self.size(), range);
2065 List sublist = self.subList(info.from, info.to);
2066 sublist.clear();
2067 if (value instanceof Collection){
2068 Collection col = (Collection) value;
2069 if (col.size() == 0) return;
2070 sublist.addAll(col);
2071 } else {
2072 sublist.add(value);
2073 }
2074 }
2075
2076 /***
2077 * A helper method to allow lists to work with subscript operators
2078 *
2079 * @param self a List
2080 * @param splice the subset of the list to set
2081 * @param values the value to put at the given sublist
2082 * @deprecated replace with putAt(List self, Range range, List value)
2083 */
2084 public static void putAt(List self, List splice, List values) {
2085 List sublist = getSubList(self, splice);
2086 sublist.clear();
2087 sublist.addAll(values);
2088 }
2089
2090 /***
2091 * A helper method to allow lists to work with subscript operators
2092 *
2093 * @param self a List
2094 * @param splice the subset of the list to set
2095 * @param value the value to put at the given sublist
2096 * @deprecated replace with putAt(List self, Range range, Object value)
2097 */
2098 public static void putAt(List self, List splice, Object value) {
2099 List sublist = getSubList(self, splice);
2100 sublist.clear();
2101 sublist.add(value);
2102 }
2103
2104
2105
2106 protected static List getSubList(List self, List splice) {
2107 int left = 0;
2108 int right = 0;
2109 boolean emptyRange = false;
2110 if (splice.size() == 2) {
2111 left = InvokerHelper.asInt(splice.get(0));
2112 right = InvokerHelper.asInt(splice.get(1));
2113 } else if (splice instanceof IntRange) {
2114 IntRange range = (IntRange) splice;
2115 left = range.getFromInt();
2116 right = range.getToInt();
2117 } else if (splice instanceof EmptyRange) {
2118 RangeInfo info = subListBorders(self.size(), (EmptyRange) splice);
2119 left = info.from;
2120 emptyRange = true;
2121 } else {
2122 throw new IllegalArgumentException("You must specify a list of 2 indexes to create a sub-list");
2123 }
2124 int size = self.size();
2125 left = normaliseIndex(left, size);
2126 right = normaliseIndex(right, size);
2127 List sublist = null;
2128 if (!emptyRange) {
2129 sublist = self.subList(left, right + 1);
2130 } else {
2131 sublist = self.subList(left, left);
2132 }
2133 return sublist;
2134 }
2135
2136 /***
2137 * Support the subscript operator for a List
2138 *
2139 * @param self a Map
2140 * @param key an Object as a key for the map
2141 * @return the value corresponding to the given key
2142 */
2143 public static Object getAt(Map self, Object key) {
2144 return self.get(key);
2145 }
2146
2147 /***
2148 * A helper method to allow lists to work with subscript operators
2149 *
2150 * @param self a Map
2151 * @param key an Object as a key for the map
2152 * @return the value corresponding to the given key
2153 */
2154 public static Object putAt(Map self, Object key, Object value) {
2155 return self.put(key, value);
2156 }
2157
2158 /***
2159 * This converts a possibly negative index to a real index into the array.
2160 *
2161 * @param i
2162 * @param size
2163 */
2164 protected static int normaliseIndex(int i, int size) {
2165 int temp = i;
2166 if (i < 0) {
2167 i += size;
2168 }
2169 if (i < 0) {
2170 throw new ArrayIndexOutOfBoundsException("Negative array index [" + temp + "] too large for array size " + size);
2171 }
2172 return i;
2173 }
2174
2175 /***
2176 * Support the subscript operator for List
2177 *
2178 * @param coll a Collection
2179 * @param property a String
2180 * @return a List
2181 */
2182 public static List getAt(Collection coll, String property) {
2183 List answer = new ArrayList(coll.size());
2184 for (Iterator iter = coll.iterator(); iter.hasNext();) {
2185 Object item = iter.next();
2186 Object value = InvokerHelper.getProperty(item, property);
2187 if (value instanceof Collection) {
2188 answer.addAll((Collection) value);
2189 } else {
2190 answer.add(value);
2191 }
2192 }
2193 return answer;
2194 }
2195
2196 /***
2197 * A convenience method for creating an immutable map
2198 *
2199 * @param self a Map
2200 * @return an immutable Map
2201 */
2202 public static Map asImmutable(Map self) {
2203 return Collections.unmodifiableMap(self);
2204 }
2205
2206 /***
2207 * A convenience method for creating an immutable sorted map
2208 *
2209 * @param self a SortedMap
2210 * @return an immutable SortedMap
2211 */
2212 public static SortedMap asImmutable(SortedMap self) {
2213 return Collections.unmodifiableSortedMap(self);
2214 }
2215
2216 /***
2217 * A convenience method for creating an immutable list
2218 *
2219 * @param self a List
2220 * @return an immutable List
2221 */
2222 public static List asImmutable(List self) {
2223 return Collections.unmodifiableList(self);
2224 }
2225
2226 /***
2227 * A convenience method for creating an immutable list
2228 *
2229 * @param self a Set
2230 * @return an immutable Set
2231 */
2232 public static Set asImmutable(Set self) {
2233 return Collections.unmodifiableSet(self);
2234 }
2235
2236 /***
2237 * A convenience method for creating an immutable sorted set
2238 *
2239 * @param self a SortedSet
2240 * @return an immutable SortedSet
2241 */
2242 public static SortedSet asImmutable(SortedSet self) {
2243 return Collections.unmodifiableSortedSet(self);
2244 }
2245
2246 /***
2247 * A convenience method for creating an immutable Collection
2248 *
2249 * @param self a Collection
2250 * @return an immutable Collection
2251 */
2252 public static Collection asImmutable(Collection self) {
2253 return Collections.unmodifiableCollection(self);
2254 }
2255
2256 /***
2257 * A convenience method for creating a synchronized Map
2258 *
2259 * @param self a Map
2260 * @return a synchronized Map
2261 */
2262 public static Map asSynchronized(Map self) {
2263 return Collections.synchronizedMap(self);
2264 }
2265
2266 /***
2267 * A convenience method for creating a synchronized SortedMap
2268 *
2269 * @param self a SortedMap
2270 * @return a synchronized SortedMap
2271 */
2272 public static SortedMap asSynchronized(SortedMap self) {
2273 return Collections.synchronizedSortedMap(self);
2274 }
2275
2276 /***
2277 * A convenience method for creating a synchronized Collection
2278 *
2279 * @param self a Collection
2280 * @return a synchronized Collection
2281 */
2282 public static Collection asSynchronized(Collection self) {
2283 return Collections.synchronizedCollection(self);
2284 }
2285
2286 /***
2287 * A convenience method for creating a synchronized List
2288 *
2289 * @param self a List
2290 * @return a synchronized List
2291 */
2292 public static List asSynchronized(List self) {
2293 return Collections.synchronizedList(self);
2294 }
2295
2296 /***
2297 * A convenience method for creating a synchronized Set
2298 *
2299 * @param self a Set
2300 * @return a synchronized Set
2301 */
2302 public static Set asSynchronized(Set self) {
2303 return Collections.synchronizedSet(self);
2304 }
2305
2306 /***
2307 * A convenience method for creating a synchronized SortedSet
2308 *
2309 * @param self a SortedSet
2310 * @return a synchronized SortedSet
2311 */
2312 public static SortedSet asSynchronized(SortedSet self) {
2313 return Collections.synchronizedSortedSet(self);
2314 }
2315
2316 /***
2317 * Returns the converted <code>SpreadList</code> of the given <code>self</code>.
2318 * <p>
2319 * This is the same method to <code>toSpreadList(List self)</code>.
2320 * <p>
2321 * For examples, if there is defined a function like as
2322 * <blockquote><pre>
2323 * def fn(a, b, c, d) { return a + b + c + d }
2324 * </pre></blockquote>, then all of the following three have the same meaning.
2325 * <blockquote><pre>
2326 * println fn(1, [2, 3].spread(), 4)
2327 * println fn(1, *[2, 3], 4)
2328 * println fn(1, 2, 3, 4)
2329 * </pre></blockquote>
2330 * <p>
2331 * </pre><br>
2332 *
2333 * @param self a list to be converted into a spreadlist
2334 * @return a newly created SpreadList if this list is not null and its size is positive.
2335 */
2336 public static SpreadList spread(List self) {
2337 return toSpreadList(self);
2338 }
2339
2340 /***
2341 * Returns the converted <code>SpreadList</code> of the given <code>self</code>.
2342 * <p>
2343 * This is the same method to <code>toSpreadList(Object[] self)</code>.
2344 * <p>
2345 * For examples, if there is defined a function like as
2346 * <blockquote><pre>
2347 * def fn(a, b, c, d) { return a + b + c + d }
2348 * </pre></blockquote>, then all of the following three have the same meaning.
2349 * <blockquote><pre>
2350 * println fn(([1, 2, 3] as Object[]).spread(), 4)
2351 * println fn(*[1, 2, 3], 4)
2352 * println fn(1, 2, 3, 4)
2353 * </pre></blockquote>
2354 * <p>
2355 * @param self an array of objects to be converted into a spreadlist
2356 * @return a newly created SpreadList if this array is not null and its size is positive.
2357 */
2358 public static SpreadList spread(Object[] self) {
2359 return toSpreadList(self);
2360 }
2361
2362 /***
2363 * Returns the converted <code>SpreadList</code> of the given <code>self</code>.
2364 * <p>
2365 * For examples, if there is defined a function like as
2366 * <blockquote><pre>
2367 * def fn(a, b, c, d) { return a + b + c + d }
2368 * </pre></blockquote>, then all of the following three have the same meaning.
2369 * <blockquote><pre>
2370 * println fn(1, [2, 3].toSpreadList(), 4)
2371 * println fn(1, *[2, 3], 4)
2372 * println fn(1, 2, 3, 4)
2373 * </pre></blockquote>
2374 * <p>
2375 * @param self a list to be converted into a spreadlist
2376 * @return a newly created SpreadList if this list is not null and its size is positive.
2377 */
2378 public static SpreadList toSpreadList(List self) {
2379 if (self == null)
2380 throw new GroovyRuntimeException("Fail to convert Object[] to SpreadList, because it is null.");
2381 else
2382 return toSpreadList(self.toArray());
2383 }
2384
2385 /***
2386 * Returns the converted <code>SpreadList</code> of the given <code>self</code>.
2387 * <p>
2388 * For examples, if there is defined a function like as
2389 * <blockquote><pre>
2390 * def fn(a, b, c, d) { return a + b + c + d }
2391 * </pre></blockquote>, then all of the following three have the same meaning.
2392 * <blockquote><pre>
2393 * println fn(([1, 2, 3] as Object[]).toSpreadList(), 4)
2394 * println fn(*[1, 2, 3], 4)
2395 * println fn(1, 2, 3, 4)
2396 * </pre></blockquote>
2397 * <p>
2398 * @param self an array of objects to be converted into a spreadlist
2399 * @return a newly created SpreadList if this array is not null and its size is positive.
2400 */
2401 public static SpreadList toSpreadList(Object[] self) {
2402 if (self == null)
2403 throw new GroovyRuntimeException("Fail to convert Object[] to SpreadList, because it is null.");
2404 else if (self.length == 0)
2405 throw new GroovyRuntimeException("Fail to convert Object[] to SpreadList, because its length is 0.");
2406 else
2407 return new SpreadList(self);
2408 }
2409
2410 public static SpreadMap spread(Map self) {
2411 return toSpreadMap(self);
2412 }
2413
2414 /***
2415 * Returns the converted <code>SpreadList</code> of the given <code>self</code>.
2416 * <p>
2417 * For examples, if there is defined a function like as
2418 * <blockquote><pre>
2419 * def fn(a, b, c, d) { return a + b + c + d }
2420 * </pre></blockquote>, then all of the following three have the same meaning.
2421 * <blockquote><pre>
2422 * println fn(a:1, [b:2, c:3].toSpreadMap(), d:4)
2423 * println fn(a:1, *:[b:2, c:3], d:4)
2424 * println fn(a:1, b:2, c:3, d:4)
2425 * </pre></blockquote>
2426 * <p>
2427 * @param self a list to be converted into a spreadlist
2428 * @return a newly created SpreadList if this list is not null and its size is positive.
2429 */
2430 public static SpreadMap toSpreadMap(Map self) {
2431 if (self == null)
2432 throw new GroovyRuntimeException("Fail to convert Map to SpreadMap, because it is null.");
2433 else
2434 return new SpreadMap(self);
2435 }
2436
2437 public static SpreadMap toSpreadMap(Object[] self) {
2438 if (self == null)
2439 throw new GroovyRuntimeException("Fail to convert Object[] to SpreadMap, because it is null.");
2440 else if (self.length % 2 != 0)
2441 throw new GroovyRuntimeException("Fail to convert Object[] to SpreadMap, because it's size is not even.");
2442 else
2443 return new SpreadMap(self);
2444 }
2445
2446 /***
2447 * Sorts the given collection into a sorted list.
2448 *
2449 * @param self the collection to be sorted
2450 * @return the sorted collection as a List
2451 */
2452 public static List sort(Collection self) {
2453 List answer = asList(self);
2454 Collections.sort(answer, new NumberComparator());
2455 return answer;
2456 }
2457
2458 /***
2459 * Avoids doing unnecessary work when sorting an already sorted set
2460 *
2461 * @param self
2462 * @return the sorted set
2463 */
2464 public static SortedSet sort(SortedSet self) {
2465 return self;
2466 }
2467
2468 /***
2469 * A convenience method for sorting a List
2470 *
2471 * @param self a List to be sorted
2472 * @return the sorted List
2473 */
2474 public static List sort(List self) {
2475 Collections.sort(self);
2476 return self;
2477 }
2478
2479 /***
2480 * Removes the last item from the List. Using add() and pop()
2481 * is similar to push and pop on a Stack.
2482 *
2483 * @param self a List
2484 * @return the item removed from the List
2485 * @throws NoSuchElementException if the list is empty and you try to pop() it.
2486 */
2487 public static Object pop(List self) {
2488 if (self.isEmpty()) {
2489 throw new NoSuchElementException("Cannot pop() an empty List");
2490 }
2491 return self.remove(self.size() - 1);
2492 }
2493
2494 /***
2495 * A convenience method for sorting a List with a specific comparator
2496 *
2497 * @param self a List
2498 * @param comparator a Comparator used for the comparison
2499 * @return a sorted List
2500 */
2501 public static List sort(List self, Comparator comparator) {
2502 Collections.sort(self, comparator);
2503 return self;
2504 }
2505
2506 /***
2507 * A convenience method for sorting a Collection with a specific comparator
2508 *
2509 * @param self a collection to be sorted
2510 * @param comparator a Comparator used for the comparison
2511 * @return a newly created sorted List
2512 */
2513 public static List sort(Collection self, Comparator comparator) {
2514 return sort(asList(self), comparator);
2515 }
2516
2517 /***
2518 * A convenience method for sorting a List using a closure as a comparator
2519 *
2520 * @param self a List
2521 * @param closure a Closure used as a comparator
2522 * @return a sorted List
2523 */
2524 public static List sort(List self, Closure closure) {
2525
2526 int params = closure.getMaximumNumberOfParameters();
2527 if (params == 1) {
2528 Collections.sort(self, new OrderBy(closure));
2529 } else {
2530 Collections.sort(self, new ClosureComparator(closure));
2531 }
2532 return self;
2533 }
2534
2535 /***
2536 * A convenience method for sorting a Collection using a closure as a comparator
2537 *
2538 * @param self a Collection to be sorted
2539 * @param closure a Closure used as a comparator
2540 * @return a newly created sorted List
2541 */
2542 public static List sort(Collection self, Closure closure) {
2543 return sort(asList(self), closure);
2544 }
2545
2546 /***
2547 * Converts the given collection into a List
2548 *
2549 * @param self a collection to be converted into a List
2550 * @return a newly created List if this collection is not already a List
2551 */
2552 public static List asList(Collection self) {
2553 if (self instanceof List) {
2554 return (List) self;
2555 } else {
2556 return new ArrayList(self);
2557 }
2558 }
2559
2560 /***
2561 * Reverses the list
2562 *
2563 * @param self a List
2564 * @return a reversed List
2565 */
2566 public static List reverse(List self) {
2567 int size = self.size();
2568 List answer = new ArrayList(size);
2569 ListIterator iter = self.listIterator(size);
2570 while (iter.hasPrevious()) {
2571 answer.add(iter.previous());
2572 }
2573 return answer;
2574 }
2575
2576 /***
2577 * Create a List as a union of both Collections
2578 *
2579 * @param left the left Collection
2580 * @param right the right Collection
2581 * @return a List
2582 */
2583 public static List plus(Collection left, Collection right) {
2584 List answer = new ArrayList(left.size() + right.size());
2585 answer.addAll(left);
2586 answer.addAll(right);
2587 return answer;
2588 }
2589
2590 /***
2591 * Create a List as a union of a Collection and an Object
2592 *
2593 * @param left a Collection
2594 * @param right an object to append
2595 * @return a List
2596 */
2597 public static List plus(Collection left, Object right) {
2598 List answer = new ArrayList(left.size() + 1);
2599 answer.addAll(left);
2600 answer.add(right);
2601 return answer;
2602 }
2603
2604 /***
2605 * Create a List composed of the same elements repeated a certain number of times.
2606 *
2607 * @param self a Collection
2608 * @param factor the number of times to append
2609 * @return a List
2610 */
2611 public static List multiply(Collection self, Number factor) {
2612 int size = factor.intValue();
2613 List answer = new ArrayList(self.size() * size);
2614 for (int i = 0; i < size; i++) {
2615 answer.addAll(self);
2616 }
2617 return answer;
2618 }
2619
2620 /***
2621 * Create a List composed of the intersection of both collections
2622 *
2623 * @param left a List
2624 * @param right a Collection
2625 * @return a List as an intersection of both collections
2626 */
2627 public static List intersect(List left, Collection right) {
2628
2629 if (left.size() == 0)
2630 return new ArrayList();
2631
2632 boolean nlgnSort = sameType(new Collection[]{left, right});
2633
2634 ArrayList result = new ArrayList();
2635
2636 Collection pickFrom = (Collection) new TreeSet(new NumberComparator());
2637 ((TreeSet) pickFrom).addAll(left);
2638
2639 for (Iterator iter = right.iterator(); iter.hasNext();) {
2640 final Object o = iter.next();
2641 if (pickFrom.contains(o))
2642 result.add(o);
2643 }
2644 return result;
2645 }
2646
2647 /***
2648 * Returns <code>true</code> if the intersection of two collenctions is empty.
2649 *
2650 * @param left a Collection
2651 * @param right a Collection
2652 * @return boolean <code>true</code> if the intersection of two collenctions is empty, <code>false</code> otherwise.
2653 */
2654 public static boolean disjoint(Collection left, Collection right) {
2655
2656 if (left.size() == 0 || right.size() == 0)
2657 return true;
2658
2659 boolean nlgnSort = sameType(new Collection[]{left, right});
2660
2661 Collection pickFrom = (Collection) new TreeSet(new NumberComparator());
2662 ((TreeSet) pickFrom).addAll(right);
2663
2664 for (Iterator iter = left.iterator(); iter.hasNext();) {
2665 final Object o = iter.next();
2666 if (pickFrom.contains(o))
2667 return false;
2668 }
2669 return true;
2670 }
2671
2672
2673 private static class NumberComparator implements Comparator {
2674 public int compare(Object o1, Object o2) {
2675 if (o1 instanceof Number && o2 instanceof Number) {
2676 BigDecimal x1 = new BigDecimal("" + o1);
2677 BigDecimal x2 = new BigDecimal("" + o2);
2678 return x1.compareTo(x2);
2679 }
2680 else if (o1.getClass() == o2.getClass() && o1 instanceof Comparable) {
2681 return ((Comparable) o1).compareTo((Comparable) o2);
2682 }
2683 else {
2684 int x1 = o1.hashCode();
2685 int x2 = o2.hashCode();
2686 return (x1 - x2);
2687 }
2688 }
2689
2690 public boolean equals(Object obj) {
2691 return this.equals(obj);
2692 }
2693 }
2694
2695 /***
2696 * Compare two Lists.
2697 * If numbers exits in the Lists, then they are compared as numbers,
2698 * for example 2 == 2L.
2699 *
2700 * @param left a List
2701 * @param right a List
2702 * @return boolean <code>true</code> if two Lists equals, <code>false</code> otherwise.
2703 */
2704 public static boolean equals(final List left, final List right) {
2705 if (left == null) {
2706 return right == null;
2707 } else if (right == null) {
2708 return false;
2709 } else if (left.size() != right.size()) {
2710 return false;
2711 } else {
2712 final NumberComparator numberComparator = new NumberComparator();
2713 final Iterator it1 = left.iterator(), it2 = right.iterator();
2714
2715 while (it1.hasNext()) {
2716 final Object o1 = it1.next();
2717 final Object o2 = it2.next();
2718
2719 if (o1 == null) {
2720 if (o2 != null) return false;
2721 } else {
2722 if (o1 instanceof Number) {
2723 if (!(o2 instanceof Number && numberComparator.compare(o1, o2) == 0)) {
2724 return false;
2725 }
2726 } else {
2727
2728
2729 if (!((Boolean)InvokerHelper.invokeMethod(o1, "equals", new Object[]{o2})).booleanValue()) return false;
2730 }
2731 }
2732 }
2733
2734 return true;
2735 }
2736 }
2737
2738 /***
2739 * Create a List composed of the elements of the first list minus the elements of the collection
2740 *
2741 * @param self a List
2742 * @param removeMe a Collection of elements to remove
2743 * @return a List with the common elements removed
2744 */
2745 public static List minus(List self, Collection removeMe) {
2746
2747 if (self.size() == 0)
2748 return new ArrayList();
2749
2750 boolean nlgnSort = sameType(new Collection[]{self, removeMe});
2751
2752
2753
2754
2755
2756 Comparator numberComparator = new NumberComparator();
2757
2758 if (nlgnSort && (self.get(0) instanceof Comparable)) {
2759
2760 Set answer = null;
2761 if (Number.class.isInstance(self.get(0))) {
2762 BigDecimal zero = new BigDecimal("0.0");
2763 answer = new TreeSet(numberComparator);
2764 answer.addAll(self);
2765 for (Iterator it = self.iterator(); it.hasNext(); ) {
2766 Object o = it.next();
2767 if (Number.class.isInstance(o)) {
2768 for (Iterator it2 = removeMe.iterator(); it2.hasNext(); ) {
2769 Object o2 = it2.next();
2770 if (Number.class.isInstance(o2)) {
2771 if (numberComparator.compare(o, o2) == 0)
2772 answer.remove(o);
2773 }
2774 }
2775 }
2776 else {
2777 if (removeMe.contains(o))
2778 answer.remove(o);
2779 }
2780 }
2781 }
2782 else {
2783 answer = new TreeSet(numberComparator);
2784 answer.addAll(self);
2785 answer.removeAll(removeMe);
2786 }
2787
2788 List ansList = new ArrayList();
2789 for (Iterator it = self.iterator(); it.hasNext(); ) {
2790 Object o = it.next();
2791 if (answer.contains(o))
2792 ansList.add(o);
2793 }
2794 return ansList;
2795 } else {
2796
2797 List tmpAnswer = new LinkedList(self);
2798 for (Iterator iter = tmpAnswer.iterator(); iter.hasNext();) {
2799 Object element = iter.next();
2800
2801 for (Iterator iterator = removeMe.iterator(); iterator.hasNext();) {
2802 Object elt = iterator.next();
2803 if (elt != null && numberComparator.compare(element, elt) == 0) {
2804 iter.remove();
2805 }
2806 }
2807 }
2808
2809
2810
2811 return new ArrayList(tmpAnswer);
2812 }
2813 }
2814
2815 /***
2816 * Flatten a list
2817 *
2818 * @param self a List
2819 * @return a flattened List
2820 */
2821 public static List flatten(List self) {
2822 return new ArrayList(flatten(self, new LinkedList()));
2823 }
2824
2825 /***
2826 * Iterate over each element of the list in the reverse order.
2827 *
2828 * @param self a List
2829 * @param closure a closure
2830 */
2831 public static void reverseEach(List self, Closure closure) {
2832 List reversed = reverse(self);
2833 for (Iterator iter = reversed.iterator(); iter.hasNext();) {
2834 closure.call(iter.next());
2835 }
2836 }
2837
2838 private static List flatten(Collection elements, List addTo) {
2839 Iterator iter = elements.iterator();
2840 while (iter.hasNext()) {
2841 Object element = iter.next();
2842 if (element instanceof Collection) {
2843 flatten((Collection) element, addTo);
2844 } else if (element instanceof Map) {
2845 flatten(((Map) element).values(), addTo);
2846 } else {
2847 addTo.add(element);
2848 }
2849 }
2850 return addTo;
2851 }
2852
2853 /***
2854 * Overloads the left shift operator to provide an easy way to append objects to a list
2855 *
2856 * @param self a Collection
2857 * @param value an Object to be added to the collection.
2858 * @return a Collection with an Object added to it.
2859 */
2860 public static Collection leftShift(Collection self, Object value) {
2861 self.add(value);
2862 return self;
2863 }
2864
2865 /***
2866 * Overloads the left shift operator to provide an easy way to append multiple
2867 * objects as string representations to a String
2868 *
2869 * @param self a String
2870 * @param value an Obect
2871 * @return a StringBuffer
2872 */
2873 public static StringBuffer leftShift(String self, Object value) {
2874 return new StringBuffer(self).append(value);
2875 }
2876
2877 protected static StringWriter createStringWriter(String self) {
2878 StringWriter answer = new StringWriter();
2879 answer.write(self);
2880 return answer;
2881 }
2882
2883 protected static StringBufferWriter createStringBufferWriter(StringBuffer self) {
2884 return new StringBufferWriter(self);
2885 }
2886
2887 /***
2888 * Overloads the left shift operator to provide an easy way to append multiple
2889 * objects as string representations to a StringBuffer
2890 *
2891 * @param self a StringBuffer
2892 * @param value a value to append
2893 * @return a StringBuffer
2894 */
2895 public static StringBuffer leftShift(StringBuffer self, Object value) {
2896 self.append(value);
2897 return self;
2898 }
2899
2900 /***
2901 * Overloads the left shift operator to provide an append mechanism to add things to a writer
2902 *
2903 * @param self a Writer
2904 * @param value a value to append
2905 * @return a StringWriter
2906 */
2907 public static Writer leftShift(Writer self, Object value) throws IOException {
2908 InvokerHelper.write(self, value);
2909 return self;
2910 }
2911
2912 /***
2913 * Implementation of the left shift operator for integral types. Non integral
2914 * Number types throw UnsupportedOperationException.
2915 */
2916 public static Number leftShift(Number left, Number right) {
2917 return NumberMath.leftShift(left, right);
2918 }
2919
2920 /***
2921 * Implementation of the right shift operator for integral types. Non integral
2922 * Number types throw UnsupportedOperationException.
2923 */
2924 public static Number rightShift(Number left, Number right) {
2925 return NumberMath.rightShift(left, right);
2926 }
2927
2928 /***
2929 * Implementation of the right shift (unsigned) operator for integral types. Non integral
2930 * Number types throw UnsupportedOperationException.
2931 */
2932 public static Number rightShiftUnsigned(Number left, Number right) {
2933 return NumberMath.rightShiftUnsigned(left, right);
2934 }
2935
2936 /***
2937 * A helper method so that dynamic dispatch of the writer.write(object) method
2938 * will always use the more efficient Writable.writeTo(writer) mechanism if the
2939 * object implements the Writable interface.
2940 *
2941 * @param self a Writer
2942 * @param writable an object implementing the Writable interface
2943 */
2944 public static void write(Writer self, Writable writable) throws IOException {
2945 writable.writeTo(self);
2946 }
2947
2948 /***
2949 * Overloads the left shift operator to provide an append mechanism to add things to a stream
2950 *
2951 * @param self an OutputStream
2952 * @param value a value to append
2953 * @return a Writer
2954 */
2955 public static Writer leftShift(OutputStream self, Object value) throws IOException {
2956 OutputStreamWriter writer = new FlushingStreamWriter(self);
2957 leftShift(writer, value);
2958 return writer;
2959 }
2960
2961 /***
2962 * Pipe an inputstream into an outputstream for efficient stream copying.
2963 *
2964 * @param self stream on which to write
2965 * @param in stream to read from
2966 * @return the outputstream itself
2967 * @throws IOException
2968 */
2969 public static OutputStream leftShift(OutputStream self, InputStream in) throws IOException {
2970 byte[] buf = new byte[1024];
2971 while (true) {
2972 int count = in.read(buf,0,buf.length);
2973 if (count == -1) break;
2974 if (count == 0) {
2975 Thread.yield();
2976 continue;
2977 }
2978 self.write(buf, 0, count);
2979 }
2980 self.flush();
2981 return self;
2982 }
2983
2984 /***
2985 * Overloads the left shift operator to provide an append mechanism to add bytes to a stream
2986 *
2987 * @param self an OutputStream
2988 * @param value a value to append
2989 * @return an OutputStream
2990 */
2991 public static OutputStream leftShift(OutputStream self, byte[] value) throws IOException {
2992 self.write(value);
2993 self.flush();
2994 return self;
2995 }
2996
2997 private static boolean sameType(Collection[] cols) {
2998 List all = new LinkedList();
2999 for (int i = 0; i < cols.length; i++) {
3000 all.addAll(cols[i]);
3001 }
3002 if (all.size() == 0)
3003 return true;
3004
3005 Object first = all.get(0);
3006
3007
3008
3009 Class baseClass;
3010 if (first instanceof Number) {
3011 baseClass = Number.class;
3012 } else {
3013 baseClass = first.getClass();
3014 }
3015
3016 for (int i = 0; i < cols.length; i++) {
3017 for (Iterator iter = cols[i].iterator(); iter.hasNext();) {
3018 if (!baseClass.isInstance(iter.next())) {
3019 return false;
3020 }
3021 }
3022 }
3023 return true;
3024 }
3025
3026
3027
3028
3029 public static Object getAt(byte[] array, int idx) {
3030 return primitiveArrayGet(array, idx);
3031 }
3032
3033 public static Object getAt(char[] array, int idx) {
3034 return primitiveArrayGet(array, idx);
3035 }
3036
3037 public static Object getAt(short[] array, int idx) {
3038 return primitiveArrayGet(array, idx);
3039 }
3040
3041 public static Object getAt(int[] array, int idx) {
3042 return primitiveArrayGet(array, idx);
3043 }
3044
3045 public static Object getAt(long[] array, int idx) {
3046 return primitiveArrayGet(array, idx);
3047 }
3048
3049 public static Object getAt(float[] array, int idx) {
3050 return primitiveArrayGet(array, idx);
3051 }
3052
3053 public static Object getAt(double[] array, int idx) {
3054 return primitiveArrayGet(array, idx);
3055 }
3056
3057 public static Object getAt(boolean[] array, int idx) {
3058 return primitiveArrayGet(array, idx);
3059 }
3060
3061 public static Object getAt(byte[] array, Range range) {
3062 return primitiveArrayGet(array, range);
3063 }
3064
3065 public static Object getAt(char[] array, Range range) {
3066 return primitiveArrayGet(array, range);
3067 }
3068
3069 public static Object getAt(short[] array, Range range) {
3070 return primitiveArrayGet(array, range);
3071 }
3072
3073 public static Object getAt(int[] array, Range range) {
3074 return primitiveArrayGet(array, range);
3075 }
3076
3077 public static Object getAt(long[] array, Range range) {
3078 return primitiveArrayGet(array, range);
3079 }
3080
3081 public static Object getAt(float[] array, Range range) {
3082 return primitiveArrayGet(array, range);
3083 }
3084
3085 public static Object getAt(double[] array, Range range) {
3086 return primitiveArrayGet(array, range);
3087 }
3088
3089 public static Object getAt(boolean[] array, Range range) {
3090 return primitiveArrayGet(array, range);
3091 }
3092
3093 public static Object getAt(byte[] array, IntRange range) {
3094 return primitiveArrayGet(array, range);
3095 }
3096
3097 public static Object getAt(char[] array, IntRange range) {
3098 return primitiveArrayGet(array, range);
3099 }
3100
3101 public static Object getAt(short[] array, IntRange range) {
3102 return primitiveArrayGet(array, range);
3103 }
3104
3105 public static Object getAt(int[] array, IntRange range) {
3106 return primitiveArrayGet(array, range);
3107 }
3108
3109 public static Object getAt(long[] array, IntRange range) {
3110 return primitiveArrayGet(array, range);
3111 }
3112
3113 public static Object getAt(float[] array, IntRange range) {
3114 return primitiveArrayGet(array, range);
3115 }
3116
3117 public static Object getAt(double[] array, IntRange range) {
3118 return primitiveArrayGet(array, range);
3119 }
3120
3121 public static Object getAt(boolean[] array, IntRange range) {
3122 return primitiveArrayGet(array, range);
3123 }
3124
3125 public static Object getAt(byte[] array, ObjectRange range) {
3126 return primitiveArrayGet(array, range);
3127 }
3128
3129 public static Object getAt(char[] array, ObjectRange range) {
3130 return primitiveArrayGet(array, range);
3131 }
3132
3133 public static Object getAt(short[] array, ObjectRange range) {
3134 return primitiveArrayGet(array, range);
3135 }
3136
3137 public static Object getAt(int[] array, ObjectRange range) {
3138 return primitiveArrayGet(array, range);
3139 }
3140
3141 public static Object getAt(long[] array, ObjectRange range) {
3142 return primitiveArrayGet(array, range);
3143 }
3144
3145 public static Object getAt(float[] array, ObjectRange range) {
3146 return primitiveArrayGet(array, range);
3147 }
3148
3149 public static Object getAt(double[] array, ObjectRange range) {
3150 return primitiveArrayGet(array, range);
3151 }
3152
3153 public static Object getAt(boolean[] array, ObjectRange range) {
3154 return primitiveArrayGet(array, range);
3155 }
3156
3157 public static Object getAt(byte[] array, Collection indices) {
3158 return primitiveArrayGet(array, indices);
3159 }
3160
3161 public static Object getAt(char[] array, Collection indices) {
3162 return primitiveArrayGet(array, indices);
3163 }
3164
3165 public static Object getAt(short[] array, Collection indices) {
3166 return primitiveArrayGet(array, indices);
3167 }
3168
3169 public static Object getAt(int[] array, Collection indices) {
3170 return primitiveArrayGet(array, indices);
3171 }
3172
3173 public static Object getAt(long[] array, Collection indices) {
3174 return primitiveArrayGet(array, indices);
3175 }
3176
3177 public static Object getAt(float[] array, Collection indices) {
3178 return primitiveArrayGet(array, indices);
3179 }
3180
3181 public static Object getAt(double[] array, Collection indices) {
3182 return primitiveArrayGet(array, indices);
3183 }
3184
3185 public static Object getAt(boolean[] array, Collection indices) {
3186 return primitiveArrayGet(array, indices);
3187 }
3188
3189 public static void putAt(boolean[] array, int idx, Boolean newValue) {
3190 primitiveArrayPut(array, idx, newValue);
3191 }
3192
3193 public static void putAt(byte[] array, int idx, Object newValue) {
3194 if (!(newValue instanceof Byte)) {
3195 Number n = (Number) newValue;
3196 newValue = new Byte(n.byteValue());
3197 }
3198 primitiveArrayPut(array, idx, newValue);
3199 }
3200
3201 public static void putAt(char[] array, int idx, Object newValue) {
3202 if (newValue instanceof String) {
3203 String s = (String) newValue;
3204 if (s.length()!=1) throw new IllegalArgumentException("String of length 1 expected but got a bigger one");
3205 char c = s.charAt(0);
3206 newValue = new Character(c);
3207 }
3208 primitiveArrayPut(array, idx, newValue);
3209 }
3210
3211 public static void putAt(short[] array, int idx, Object newValue) {
3212 if (!(newValue instanceof Short)) {
3213 Number n = (Number) newValue;
3214 newValue = new Short(n.shortValue());
3215 }
3216 primitiveArrayPut(array, idx, newValue);
3217 }
3218
3219 public static void putAt(int[] array, int idx, Object newValue) {
3220 if (!(newValue instanceof Integer)) {
3221 Number n = (Number) newValue;
3222 newValue = new Integer(n.intValue());
3223 }
3224 primitiveArrayPut(array, idx, newValue);
3225 }
3226
3227 public static void putAt(long[] array, int idx, Object newValue) {
3228 if (!(newValue instanceof Long)) {
3229 Number n = (Number) newValue;
3230 newValue = new Long(n.longValue());
3231 }
3232 primitiveArrayPut(array, idx, newValue);
3233 }
3234
3235 public static void putAt(float[] array, int idx, Object newValue) {
3236 if (!(newValue instanceof Float)) {
3237 Number n = (Number) newValue;
3238 newValue = new Float(n.floatValue());
3239 }
3240 primitiveArrayPut(array, idx, newValue);
3241 }
3242
3243 public static void putAt(double[] array, int idx, Object newValue) {
3244 if (!(newValue instanceof Double)) {
3245 Number n = (Number) newValue;
3246 newValue = new Double(n.doubleValue());
3247 }
3248 primitiveArrayPut(array, idx, newValue);
3249 }
3250
3251 public static int size(byte[] array) {
3252 return Array.getLength(array);
3253 }
3254
3255 public static int size(char[] array) {
3256 return Array.getLength(array);
3257 }
3258
3259 public static int size(short[] array) {
3260 return Array.getLength(array);
3261 }
3262
3263 public static int size(int[] array) {
3264 return Array.getLength(array);
3265 }
3266
3267 public static int size(long[] array) {
3268 return Array.getLength(array);
3269 }
3270
3271 public static int size(float[] array) {
3272 return Array.getLength(array);
3273 }
3274
3275 public static int size(double[] array) {
3276 return Array.getLength(array);
3277 }
3278
3279 public static List toList(byte[] array) {
3280 return InvokerHelper.primitiveArrayToList(array);
3281 }
3282
3283 public static List toList(char[] array) {
3284 return InvokerHelper.primitiveArrayToList(array);
3285 }
3286
3287 public static List toList(short[] array) {
3288 return InvokerHelper.primitiveArrayToList(array);
3289 }
3290
3291 public static List toList(int[] array) {
3292 return InvokerHelper.primitiveArrayToList(array);
3293 }
3294
3295 public static List toList(long[] array) {
3296 return InvokerHelper.primitiveArrayToList(array);
3297 }
3298
3299 public static List toList(float[] array) {
3300 return InvokerHelper.primitiveArrayToList(array);
3301 }
3302
3303 public static List toList(double[] array) {
3304 return InvokerHelper.primitiveArrayToList(array);
3305 }
3306
3307 private static final char[] tTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
3308
3309 public static Writable encodeBase64(final Byte[] data) {
3310 return encodeBase64(InvokerHelper.convertToByteArray(data));
3311 }
3312
3313 /***
3314 * Produce a Writable object which writes the base64 encoding of the byte array
3315 * Calling toString() on the result rerurns the encoding as a String
3316 *
3317 * @param data byte array to be encoded
3318 * @return object which will write the base64 encoding of the byte array
3319 */
3320 public static Writable encodeBase64(final byte[] data) {
3321 return new Writable() {
3322 public Writer writeTo(final Writer writer) throws IOException {
3323 int charCount = 0;
3324 final int dLimit = (data.length / 3) * 3;
3325
3326 for (int dIndex = 0; dIndex != dLimit; dIndex += 3) {
3327 int d = ((data[dIndex] & 0XFF) << 16) | ((data[dIndex + 1] & 0XFF) << 8) | (data[dIndex + 2] & 0XFF);
3328
3329 writer.write(tTable[d >> 18]);
3330 writer.write(tTable[(d >> 12) & 0X3F]);
3331 writer.write(tTable[(d >> 6) & 0X3F]);
3332 writer.write(tTable[d & 0X3F]);
3333
3334 if (++charCount == 18) {
3335 writer.write('\n');
3336 charCount = 0;
3337 }
3338 }
3339
3340 if (dLimit != data.length) {
3341 int d = (data[dLimit] & 0XFF) << 16;
3342
3343 if (dLimit + 1 != data.length) {
3344 d |= (data[dLimit + 1] & 0XFF) << 8;
3345 }
3346
3347 writer.write(tTable[d >> 18]);
3348 writer.write(tTable[(d >> 12) & 0X3F]);
3349 writer.write((dLimit + 1 < data.length) ? tTable[(d >> 6) & 0X3F] : '=');
3350 writer.write('=');
3351 }
3352
3353 return writer;
3354 }
3355
3356 public String toString() {
3357 StringWriter buffer = new StringWriter();
3358
3359 try {
3360 writeTo(buffer);
3361 } catch (IOException e) {
3362 throw new RuntimeException(e);
3363 }
3364
3365 return buffer.toString();
3366 }
3367 };
3368 }
3369
3370 private static final byte[] translateTable = (
3371
3372 "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
3373
3374 + "\u0042\u0042\u0041\u0041\u0042\u0042\u0041\u0042"
3375
3376 + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
3377
3378 + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
3379
3380 + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
3381
3382 + "\u0042\u0042\u0042\u003E\u0042\u0042\u0042\u003F"
3383
3384 + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
3385
3386 + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
3387
3388 + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
3389
3390 + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
3391
3392 + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
3393
3394 + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u0042"
3395
3396 + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
3397
3398 + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
3399
3400 + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
3401
3402 + "\u0031\u0032\u0033").getBytes();
3403
3404 /***
3405 * Decode the Sting from base64 into a byte array
3406 *
3407 * @param value the string to be decoded
3408 * @return the decoded bytes as an array
3409 */
3410 public static byte[] decodeBase64(final String value) {
3411 int byteShift = 4;
3412 int tmp = 0;
3413 boolean done = false;
3414 final StringBuffer buffer = new StringBuffer();
3415
3416 for (int i = 0; i != value.length(); i++) {
3417 final char c = value.charAt(i);
3418 final int sixBit = (c < 123) ? translateTable[c] : 66;
3419
3420 if (sixBit < 64) {
3421 if (done) throw new RuntimeException("= character not at end of base64 value");
3422
3423 tmp = (tmp << 6) | sixBit;
3424
3425 if (byteShift-- != 4) {
3426 buffer.append((char) ((tmp >> (byteShift * 2)) & 0XFF));
3427 }
3428
3429 } else if (sixBit == 64) {
3430
3431 byteShift--;
3432 done = true;
3433
3434 } else if (sixBit == 66) {
3435
3436
3437
3438 throw new RuntimeException("bad character in base64 value");
3439 }
3440
3441 if (byteShift == 0) byteShift = 4;
3442 }
3443
3444 try {
3445 return buffer.toString().getBytes("ISO-8859-1");
3446 } catch (UnsupportedEncodingException e) {
3447 throw new RuntimeException("Base 64 decode produced byte values > 255");
3448 }
3449 }
3450
3451 /***
3452 * Implements the getAt(int) method for primitve type arrays
3453 */
3454 protected static Object primitiveArrayGet(Object array, int idx) {
3455 return Array.get(array, normaliseIndex(idx, Array.getLength(array)));
3456 }
3457
3458 /***
3459 * Implements the getAt(Range) method for primitve type arrays
3460 */
3461 protected static List primitiveArrayGet(Object array, Range range) {
3462 List answer = new ArrayList();
3463 for (Iterator iter = range.iterator(); iter.hasNext();) {
3464 int idx = InvokerHelper.asInt(iter.next());
3465 answer.add(primitiveArrayGet(array, idx));
3466 }
3467 return answer;
3468 }
3469
3470 /***
3471 * Implements the getAt(Collection) method for primitve type arrays
3472 */
3473 protected static List primitiveArrayGet(Object self, Collection indices) {
3474 List answer = new ArrayList();
3475 for (Iterator iter = indices.iterator(); iter.hasNext();) {
3476 Object value = iter.next();
3477 if (value instanceof Range) {
3478 answer.addAll(primitiveArrayGet(self, (Range) value));
3479 } else if (value instanceof List) {
3480 answer.addAll(primitiveArrayGet(self, (List) value));
3481 } else {
3482 int idx = InvokerHelper.asInt(value);
3483 answer.add(primitiveArrayGet(self, idx));
3484 }
3485 }
3486 return answer;
3487 }
3488
3489 /***
3490 * Implements the set(int idx) method for primitve type arrays
3491 */
3492 protected static void primitiveArrayPut(Object array, int idx, Object newValue) {
3493 Array.set(array, normaliseIndex(idx, Array.getLength(array)), newValue);
3494 }
3495
3496
3497
3498
3499 /***
3500 * Converts the given string into a Character object
3501 * using the first character in the string
3502 *
3503 * @param self a String
3504 * @return the first Character
3505 */
3506 public static Character toCharacter(String self) {
3507 /*** @todo use cache? */
3508 return new Character(self.charAt(0));
3509 }
3510
3511 /***
3512 * Converts the given string into a Boolean object
3513 * If the trimmed string is "true", "y" or "1" (ignoring case)
3514 * then the result is true othewrwise it is false
3515 *
3516 * @param self a String
3517 * @return The Boolean value
3518 */
3519 public static Boolean toBoolean(String self) {
3520 final String trimmed = self.trim();
3521
3522 if ("true".equalsIgnoreCase(trimmed) || "y".equalsIgnoreCase(trimmed) || "1".equals(trimmed)) {
3523 return Boolean.TRUE;
3524 } else {
3525 return Boolean.FALSE;
3526 }
3527 }
3528
3529 /***
3530 * Tokenize a String
3531 *
3532 * @param self a String
3533 * @param token the delimiter
3534 * @return a List of tokens
3535 */
3536 public static List tokenize(String self, String token) {
3537 return InvokerHelper.asList(new StringTokenizer(self, token));
3538 }
3539
3540 /***
3541 * Tokenize a String (with a whitespace as delimiter)
3542 *
3543 * @param self a String
3544 * @return a List of tokens
3545 */
3546 public static List tokenize(String self) {
3547 return InvokerHelper.asList(new StringTokenizer(self));
3548 }
3549
3550 /***
3551 * Appends a String
3552 *
3553 * @param left a String
3554 * @param value a String
3555 * @return a String
3556 */
3557 public static String plus(String left, Object value) {
3558
3559 return left + toString(value);
3560 }
3561
3562 /***
3563 * Appends a String
3564 *
3565 * @param value a Number
3566 * @param right a String
3567 * @return a String
3568 */
3569 public static String plus(Number value, String right) {
3570 return toString(value) + right;
3571 }
3572
3573 /***
3574 * Appends a String
3575 *
3576 * @param left a StringBuffer
3577 * @param value a String
3578 * @return a String
3579 */
3580 public static String plus(StringBuffer left, String value) {
3581 return left + value;
3582 }
3583
3584
3585 /***
3586 * Remove a part of a String
3587 *
3588 * @param left a String
3589 * @param value a String part to remove
3590 * @return a String minus the part to be removed
3591 */
3592 public static String minus(String left, Object value) {
3593 String text = toString(value);
3594 return left.replaceFirst(text, "");
3595 }
3596
3597 /***
3598 * Provide an implementation of contains() like Collection to make Strings more polymorphic
3599 * This method is not required on JDK 1.5 onwards
3600 *
3601 * @param self a String
3602 * @param text a String to look for
3603 * @return true if this string contains the given text
3604 */
3605 public static boolean contains(String self, String text) {
3606 int idx = self.indexOf(text);
3607 return idx >= 0;
3608 }
3609
3610 /***
3611 * Count the number of occurencies of a substring
3612 *
3613 * @param self a String
3614 * @param text a substring
3615 * @return the number of occurrencies of the given string inside this String
3616 */
3617 public static int count(String self, String text) {
3618 int answer = 0;
3619 for (int idx = 0; true; idx++) {
3620 idx = self.indexOf(text, idx);
3621 if (idx >= 0) {
3622 ++answer;
3623 } else {
3624 break;
3625 }
3626 }
3627 return answer;
3628 }
3629
3630 /***
3631 * This method is called by the ++ operator for the class String.
3632 * It increments the last character in the given string. If the
3633 * character in the string is Character.MAX_VALUE a Character.MIN_VALUE
3634 * will be appended. The empty string is incremented to a string
3635 * consisting of the character Character.MIN_VALUE.
3636 *
3637 * @param self a String
3638 * @return an incremented String
3639 */
3640 public static String next(String self) {
3641 StringBuffer buffer = new StringBuffer(self);
3642 if (buffer.length()==0) {
3643 buffer.append(Character.MIN_VALUE);
3644 } else {
3645 char last = buffer.charAt(buffer.length()-1);
3646 if (last==Character.MAX_VALUE) {
3647 buffer.append(Character.MIN_VALUE);
3648 } else {
3649 char next = last;
3650 next++;
3651 buffer.setCharAt(buffer.length()-1,next);
3652 }
3653 }
3654 return buffer.toString();
3655 }
3656
3657 /***
3658 * This method is called by the -- operator for the class String.
3659 * It decrements the last character in the given string. If the
3660 * character in the string is Character.MIN_VALUE it will be deleted.
3661 * The empty string can't be decremented.
3662 *
3663 * @param self a String
3664 * @return a String with a decremented digit at the end
3665 */
3666 public static String previous(String self) {
3667 StringBuffer buffer = new StringBuffer(self);
3668 if (buffer.length()==0) throw new IllegalArgumentException("the string is empty");
3669 char last = buffer.charAt(buffer.length()-1);
3670 if (last==Character.MIN_VALUE) {
3671 buffer.deleteCharAt(buffer.length()-1);
3672 } else {
3673 char next = last;
3674 next--;
3675 buffer.setCharAt(buffer.length()-1,next);
3676 }
3677 return buffer.toString();
3678 }
3679
3680 /***
3681 * Executes the given string as a command line process. For more control
3682 * over the process mechanism in JDK 1.5 you can use java.lang.ProcessBuilder.
3683 *
3684 * @param self a command line String
3685 * @return the Process which has just started for this command line string
3686 */
3687 public static Process execute(String self) throws IOException {
3688 return Runtime.getRuntime().exec(self);
3689 }
3690
3691 /***
3692 * Executes the command specified by the <code>String</code> array that is the parameter.
3693 * The first item in the array is the command the others are the parameters. For more
3694 * control over the process mechanism in JDK 1.5 you can use
3695 * <code>java.lang.ProcessBuilder</code>.
3696 *
3697 * @param commandArray an array of <code>String<code> containing the command name and
3698 * parameters as separate items in the array.
3699 * @return the Process which has just started for this command line string.
3700 */
3701 public static Process execute(final String[] commandArray) throws IOException {
3702 return Runtime.getRuntime().exec(commandArray) ;
3703 }
3704
3705 /***
3706 * Executes the command specified by the <code>self</code> with environments <code>envp</code>
3707 * under the working directory <code>dir</code>.
3708 * For more control over the process mechanism in JDK 1.5 you can use <code>java.lang.ProcessBuilder</code>.
3709 *
3710 * @param self a command line String to be executed.
3711 * @param envp an array of Strings, each element of which
3712 * has environment variable settings in the format
3713 * <i>name</i>=<i>value</i>, or
3714 * <tt>null</tt> if the subprocess should inherit
3715 * the environment of the current process.
3716 * @param dir the working directory of the subprocess, or
3717 * <tt>null</tt> if the subprocess should inherit
3718 * the working directory of the current process.
3719 * @return the Process which has just started for this command line string.
3720 *
3721 */
3722 public static Process execute(String self, final String[] envp, File dir) throws IOException {
3723 return Runtime.getRuntime().exec(self, envp, dir) ;
3724 }
3725
3726 /***
3727 * Executes the command specified by the <code>String</code> list that is the parameter.
3728 * The first item in the array is the command the others are the parameters. All entries
3729 * must be <code>String</code>s. For more control over the process mechanism in JDK 1.5 you
3730 * can use <code>java.lang.ProcessBuilder</code>.
3731 *
3732 * @param commandList a list of <code>String<code> containing the command name and
3733 * parameters as separate items in the list.
3734 * @return the Process which has just started for this command line string.
3735 */
3736 public static Process execute(final List commandList) throws IOException {
3737 final String[] commandArray = new String[commandList.size()] ;
3738 Iterator it = commandList.iterator();
3739 for (int i = 0; it.hasNext(); ++i) {
3740 commandArray[i] = it.next().toString();
3741 }
3742 return execute(commandArray) ;
3743 }
3744
3745 /***
3746 * Executes the command specified by the <code>self</code> with environments <code>envp</code>
3747 * under the working directory <code>dir</code>.
3748 * For more control over the process mechanism in JDK 1.5 you can use <code>java.lang.ProcessBuilder</code>.
3749 *
3750 * @param self a command line String to be executed.
3751 * @param envp a List of Strings, each member of which
3752 * has environment variable settings in the format
3753 * <i>name</i>=<i>value</i>, or
3754 * <tt>null</tt> if the subprocess should inherit
3755 * the environment of the current process.
3756 * @param dir the working directory of the subprocess, or
3757 * <tt>null</tt> if the subprocess should inherit
3758 * the working directory of the current process.
3759 * @return the Process which has just started for this command line string.
3760 *
3761 */
3762 public static Process execute(String self, final List envp, File dir) throws IOException {
3763 final String[] commandArray = new String[envp.size()] ;
3764 Iterator it = envp.iterator();
3765 for (int i = 0; it.hasNext(); ++i) {
3766 commandArray[i] = it.next().toString();
3767 }
3768 return execute(self, commandArray, dir);
3769 }
3770
3771 /***
3772 * Repeat a String a certain number of times
3773 *
3774 * @param self a String to be repeated
3775 * @param factor the number of times the String should be repeated
3776 * @return a String composed of a repeatition
3777 * @throws IllegalArgumentException if the number of repeatition is < 0
3778 */
3779 public static String multiply(String self, Number factor) {
3780 int size = factor.intValue();
3781 if (size == 0)
3782 return "";
3783 else if (size < 0) {
3784 throw new IllegalArgumentException("multiply() should be called with a number of 0 or greater not: " + size);
3785 }
3786 StringBuffer answer = new StringBuffer(self);
3787 for (int i = 1; i < size; i++) {
3788 answer.append(self);
3789 }
3790 return answer.toString();
3791 }
3792
3793 /***
3794 * Returns the string representation of the given map with bracket boundaries.
3795 *
3796 * @param self a Map
3797 * @return the string representation
3798 */
3799 public static String toString(Map self) {
3800 return toMapString(self);
3801 }
3802
3803 /***
3804 * Returns the string representation of the given map with bracket boundaries.
3805 *
3806 * @param self a Map
3807 * @return the string representation
3808 */
3809 public static String toMapString(Map self) {
3810 return (self == null) ? "null" : InvokerHelper.toMapString(self);
3811 }
3812
3813 /***
3814 * Returns the string representation of the given collection with the bracket boundaries.
3815 *
3816 * @param self a Collection
3817 * @return the string representation
3818 */
3819 public static String toString(Collection self) {
3820 return toListString(self);
3821 }
3822
3823 /***
3824 * Returns the string representation of the given collection with the bracket boundaries.
3825 *
3826 * @param self a Collection
3827 * @return the string representation
3828 */
3829 public static String toListString(Collection self) {
3830 return (self == null) ? "null" : InvokerHelper.toListString(self);
3831 }
3832
3833 /***
3834 * Returns the string representation of the given array with the brace boundaries.
3835 *
3836 * @param self an Object[]
3837 * @return the string representation
3838 */
3839 public static String toString(Object[] self) {
3840 return toArrayString(self);
3841 }
3842
3843 /***
3844 * Returns the string representation of the given array with the brace boundaries.
3845 *
3846 * @param self an Object[]
3847 * @return the string representation
3848 */
3849 public static String toArrayString(Object[] self) {
3850 return (self == null) ? "null" : InvokerHelper.toArrayString(self);
3851 }
3852
3853
3854 protected static String toString(Object value) {
3855 if (value instanceof Map)
3856 return toMapString((Map)value);
3857 else if (value instanceof Collection)
3858 return toListString((Collection)value);
3859 else if (value instanceof Object[])
3860 return toArrayString((Object[])value);
3861 return (value == null) ? "null" : value.toString();
3862 }
3863
3864
3865
3866
3867 /***
3868 * Increment a Character by one
3869 *
3870 * @param self a Character
3871 * @return an incremented Number
3872 */
3873 public static Number next(Character self) {
3874 return plus(self, ONE);
3875 }
3876
3877 /***
3878 * Increment a Number by one
3879 *
3880 * @param self a Number
3881 * @return an incremented Number
3882 */
3883 public static Number next(Number self) {
3884 return plus(self, ONE);
3885 }
3886
3887 /***
3888 * Decrement a Character by one
3889 *
3890 * @param self a Character
3891 * @return a decremented Number
3892 */
3893 public static Number previous(Character self) {
3894 return minus(self, ONE);
3895 }
3896
3897 /***
3898 * Decrement a Number by one
3899 *
3900 * @param self a Number
3901 * @return a decremented Number
3902 */
3903 public static Number previous(Number self) {
3904 return minus(self, ONE);
3905 }
3906
3907 /***
3908 * Add a Character and a Number
3909 *
3910 * @param left a Character
3911 * @param right a Number
3912 * @return the addition of the Character and the Number
3913 */
3914 public static Number plus(Character left, Number right) {
3915 return plus(new Integer(left.charValue()), right);
3916 }
3917
3918 /***
3919 * Add a Number and a Character
3920 *
3921 * @param left a Number
3922 * @param right a Character
3923 * @return the addition of the Character and the Number
3924 */
3925 public static Number plus(Number left, Character right) {
3926 return plus(left, new Integer(right.charValue()));
3927 }
3928
3929 /***
3930 * Add two Characters
3931 *
3932 * @param left a Character
3933 * @param right a Character
3934 * @return the addition of both Characters
3935 */
3936 public static Number plus(Character left, Character right) {
3937 return plus(new Integer(left.charValue()), right);
3938 }
3939
3940 /***
3941 * Add two numbers and return the result.
3942 *
3943 * @param left a Number
3944 * @param right another Number to add
3945 * @return the addition of both Numbers
3946 */
3947 public static Number plus(Number left, Number right) {
3948 return NumberMath.add(left, right);
3949 }
3950
3951 /***
3952 * Compare a Character and a Number
3953 *
3954 * @param left a Character
3955 * @param right a Number
3956 * @return the result of the comparison
3957 */
3958 public static int compareTo(Character left, Number right) {
3959 return compareTo(new Integer(left.charValue()), right);
3960 }
3961
3962 /***
3963 * Compare a Number and a Character
3964 *
3965 * @param left a Number
3966 * @param right a Character
3967 * @return the result of the comparison
3968 */
3969 public static int compareTo(Number left, Character right) {
3970 return compareTo(left, new Integer(right.charValue()));
3971 }
3972
3973 /***
3974 * Compare two Characters
3975 *
3976 * @param left a Character
3977 * @param right a Character
3978 * @return the result of the comparison
3979 */
3980 public static int compareTo(Character left, Character right) {
3981 return compareTo(new Integer(left.charValue()), right);
3982 }
3983
3984 /***
3985 * Compare two Numbers
3986 *
3987 * @param left a Number
3988 * @param right another Number to compare to
3989 * @return the comparision of both numbers
3990 */
3991 public static int compareTo(Number left, Number right) {
3992 /*** @todo maybe a double dispatch thing to handle new large numbers? */
3993 return NumberMath.compareTo(left, right);
3994 }
3995
3996 /***
3997 * Subtract a Number from a Character
3998 *
3999 * @param left a Character
4000 * @param right a Number
4001 * @return the addition of the Character and the Number
4002 */
4003 public static Number minus(Character left, Number right) {
4004 return minus(new Integer(left.charValue()), right);
4005 }
4006
4007 /***
4008 * Subtract a Character from a Number
4009 *
4010 * @param left a Number
4011 * @param right a Character
4012 * @return the addition of the Character and the Number
4013 */
4014 public static Number minus(Number left, Character right) {
4015 return minus(left, new Integer(right.charValue()));
4016 }
4017
4018 /***
4019 * Subtraction two Characters
4020 *
4021 * @param left a Character
4022 * @param right a Character
4023 * @return the addition of both Characters
4024 */
4025 public static Number minus(Character left, Character right) {
4026 return minus(new Integer(left.charValue()), right);
4027 }
4028
4029 /***
4030 * Substraction of two Numbers
4031 *
4032 * @param left a Number
4033 * @param right another Number to substract to the first one
4034 * @return the substraction
4035 */
4036 public static Number minus(Number left, Number right) {
4037 return NumberMath.subtract(left, right);
4038 }
4039
4040 /***
4041 * Multiply a Character by a Number
4042 *
4043 * @param left a Character
4044 * @param right a Number
4045 * @return the multiplication of both
4046 */
4047 public static Number multiply(Character left, Number right) {
4048 return multiply(new Integer(left.charValue()), right);
4049 }
4050
4051 /***
4052 * Multiply a Number by a Character
4053 *
4054 * @param left a Number
4055 * @param right a Character
4056 * @return the multiplication of both
4057 */
4058 public static Number multiply(Number left, Character right) {
4059 return multiply(left, new Integer(right.charValue()));
4060 }
4061
4062 /***
4063 * Multiply two Characters
4064 *
4065 * @param left a Character
4066 * @param right another Character
4067 * @return the multiplication of both
4068 */
4069 public static Number multiply(Character left, Character right) {
4070 return multiply(new Integer(left.charValue()), right);
4071 }
4072
4073 /***
4074 * Multiply two Numbers
4075 *
4076 * @param left a Number
4077 * @param right another Number
4078 * @return the multiplication of both
4079 */
4080
4081
4082 public static Number multiply(Number left, Number right) {
4083 return NumberMath.multiply(left, right);
4084 }
4085
4086 /***
4087 * Power of a Number to a certain exponent
4088 *
4089 * @param self a Number
4090 * @param exponent a Number exponent
4091 * @return a Number to the power of a certain exponent
4092 */
4093 public static Number power(Number self, Number exponent) {
4094 double base, exp, answer;
4095 base = self.doubleValue();
4096 exp = exponent.doubleValue();
4097
4098 answer = Math.pow(base, exp);
4099 if ((double)((int)answer) == answer) {
4100 return new Integer((int)answer);
4101 }
4102 else if ((double)((long)answer) == answer) {
4103 return new Long((long)answer);
4104 }
4105 else {
4106 return new Double(answer);
4107 }
4108 }
4109
4110 /***
4111 * Divide a Character by a Number
4112 *
4113 * @param left a Character
4114 * @param right a Number
4115 * @return the multiplication of both
4116 */
4117 public static Number div(Character left, Number right) {
4118 return div(new Integer(left.charValue()), right);
4119 }
4120
4121 /***
4122 * Divide a Number by a Character
4123 *
4124 * @param left a Number
4125 * @param right a Character
4126 * @return the multiplication of both
4127 */
4128 public static Number div(Number left, Character right) {
4129 return div(left, new Integer(right.charValue()));
4130 }
4131
4132 /***
4133 * Divide two Characters
4134 *
4135 * @param left a Character
4136 * @param right another Character
4137 * @return the multiplication of both
4138 */
4139 public static Number div(Character left, Character right) {
4140 return div(new Integer(left.charValue()), right);
4141 }
4142
4143 /***
4144 * Divide two Numbers
4145 *
4146 * @param left a Number
4147 * @param right another Number
4148 * @return a Number resulting of the divide operation
4149 */
4150
4151
4152 public static Number div(Number left, Number right) {
4153 return NumberMath.divide(left, right);
4154 }
4155
4156 /***
4157 * Integer Divide a Character by a Number
4158 *
4159 * @param left a Character
4160 * @param right a Number
4161 * @return the integer division of both
4162 */
4163 public static Number intdiv(Character left, Number right) {
4164 return intdiv(new Integer(left.charValue()), right);
4165 }
4166
4167 /***
4168 * Integer Divide a Number by a Character
4169 *
4170 * @param left a Number
4171 * @param right a Character
4172 * @return the integer division of both
4173 */
4174 public static Number intdiv(Number left, Character right) {
4175 return intdiv(left, new Integer(right.charValue()));
4176 }
4177
4178 /***
4179 * Integer Divide two Characters
4180 *
4181 * @param left a Character
4182 * @param right another Character
4183 * @return the integer division of both
4184 */
4185 public static Number intdiv(Character left, Character right) {
4186 return intdiv(new Integer(left.charValue()), right);
4187 }
4188
4189 /***
4190 * Integer Divide two Numbers
4191 *
4192 * @param left a Number
4193 * @param right another Number
4194 * @return a Number (an Integer) resulting of the integer division operation
4195 */
4196 public static Number intdiv(Number left, Number right) {
4197 return NumberMath.intdiv(left, right);
4198 }
4199
4200 /***
4201 * Bitwise OR together two numbers
4202 *
4203 * @param left a Number
4204 * @param right another Number to bitwise OR
4205 * @return the bitwise OR of both Numbers
4206 */
4207 public static Number or(Number left, Number right) {
4208 return NumberMath.or(left, right);
4209 }
4210
4211 /***
4212 * Bitwise AND together two Numbers
4213 *
4214 * @param left a Number
4215 * @param right another Number to bitwse AND
4216 * @return the bitwise AND of both Numbers
4217 */
4218 public static Number and(Number left, Number right) {
4219 return NumberMath.and(left, right);
4220 }
4221
4222 /***
4223 * Bitwise XOR together two Numbers
4224 *
4225 * @param left a Number
4226 * @param right another Number to bitwse XOR
4227 * @return the bitwise XOR of both Numbers
4228 */
4229 public static Number xor(Number left, Number right) {
4230 return NumberMath.xor(left, right);
4231 }
4232
4233 /***
4234 * Performs a division modulus operation
4235 *
4236 * @param left a Number
4237 * @param right another Number to mod
4238 * @return the modulus result
4239 */
4240 public static Number mod(Number left, Number right) {
4241 return NumberMath.mod(left, right);
4242 }
4243
4244 /***
4245 * Negates the number
4246 *
4247 * @param left a Number
4248 * @return the negation of the number
4249 */
4250 public static Number negate(Number left) {
4251 return NumberMath.negate(left);
4252 }
4253
4254
4255 /***
4256 * Iterates a number of times
4257 *
4258 * @param self a Number
4259 * @param closure the closure to call a number of times
4260 */
4261 public static void times(Number self, Closure closure) {
4262 for (int i = 0, size = self.intValue(); i < size; i++) {
4263 closure.call(new Integer(i));
4264 if (closure.getDirective() == Closure.DONE) {
4265 break;
4266 }
4267 }
4268 }
4269
4270 /***
4271 * Iterates from this number up to the given number
4272 *
4273 * @param self a Number
4274 * @param to another Number to go up to
4275 * @param closure the closure to call
4276 */
4277 public static void upto(Number self, Number to, Closure closure) {
4278 int self1 = self.intValue();
4279 int to1 = to.intValue();
4280 if (self1 <= to1) {
4281 for (int i = self1; i <= to1; i++) {
4282 closure.call(new Integer(i));
4283 }
4284 }
4285 else
4286 throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to +")");
4287 }
4288
4289 public static void upto(long self, Number to, Closure closure) {
4290 long to1 = to.longValue();
4291 if (self <= to1) {
4292 for (long i = self; i <= to1; i++) {
4293 closure.call(new Long(i));
4294 }
4295 }
4296 else
4297 throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to +")");
4298 }
4299
4300 public static void upto(Long self, Number to, Closure closure) {
4301 long self1 = self.longValue();
4302 long to1 = to.longValue();
4303 if (self1 <= to1) {
4304 for (long i = self1; i <= to1; i++) {
4305 closure.call(new Long(i));
4306 }
4307 }
4308 else
4309 throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to +")");
4310 }
4311
4312 public static void upto(float self, Number to, Closure closure) {
4313 float to1 = to.floatValue();
4314 if (self <= to1) {
4315 for (float i = self; i <= to1; i++) {
4316 closure.call(new Float(i));
4317 }
4318 }
4319 else
4320 throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to +")");
4321 }
4322
4323 public static void upto(Float self, Number to, Closure closure) {
4324 float self1 = self.floatValue();
4325 float to1 = to.floatValue();
4326 if (self1 <= to1) {
4327 for (float i = self1; i <= to1; i++) {
4328 closure.call(new Float(i));
4329 }
4330 }
4331 else
4332 throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to +")");
4333 }
4334
4335 public static void upto(Double self, Number to, Closure closure) {
4336 double self1 = self.doubleValue();
4337 double to1 = to.doubleValue();
4338 if (self1 <= to1) {
4339 for (double i = self1; i <= to1; i++) {
4340 closure.call(new Double(i));
4341 }
4342 }
4343 else
4344 throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to +")");
4345 }
4346
4347 public static void upto(BigInteger self, Number to, Closure closure) {
4348 if (to instanceof BigDecimal) {
4349 final BigDecimal one = new BigDecimal("1.0");
4350 BigDecimal self1 = new BigDecimal(self);
4351 BigDecimal to1 = (BigDecimal) to;
4352 if (self1.compareTo(to1) <= 0) {
4353 for (BigDecimal i = self1; i.compareTo(to1) <= 0; i = i.add(one)) {
4354 closure.call(i);
4355 }
4356 }
4357 else
4358 throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to +")");
4359 }
4360 else if (to instanceof BigInteger) {
4361 final BigInteger one = new BigInteger("1");
4362 BigInteger to1 = (BigInteger) to;
4363 if (self.compareTo(to1) <= 0) {
4364 for (BigInteger i = self; i.compareTo(to1) <= 0; i = i.add(one)) {
4365 closure.call(i);
4366 }
4367 }
4368 else
4369 throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to +")");
4370 }
4371 else {
4372 final BigInteger one = new BigInteger("1");
4373 BigInteger to1 = new BigInteger("" + to);
4374 if (self.compareTo(to1) <= 0) {
4375 for (BigInteger i = self; i.compareTo(to1) <= 0; i = i.add(one)) {
4376 closure.call(i);
4377 }
4378 }
4379 else
4380 throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to +")");
4381 }
4382 }
4383
4384 public static void upto(BigDecimal self, Number to, Closure closure) {
4385 final BigDecimal one = new BigDecimal("1.0");
4386 if (to instanceof BigDecimal) {
4387 BigDecimal to1 = (BigDecimal) to;
4388 if (self.compareTo(to1) <= 0) {
4389 for (BigDecimal i = self; i.compareTo(to1) <= 0; i = i.add(one)) {
4390 closure.call(i);
4391 }
4392 }
4393 else
4394 throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to +")");
4395 }
4396 else if (to instanceof BigInteger) {
4397 BigDecimal to1 = new BigDecimal((BigInteger) to);
4398 if (self.compareTo(to1) <= 0) {
4399 for (BigDecimal i = self; i.compareTo(to1) <= 0; i = i.add(one)) {
4400 closure.call(i);
4401 }
4402 }
4403 else
4404 throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to +")");
4405 }
4406 else {
4407 BigDecimal to1 = new BigDecimal(""+to);
4408 if (self.compareTo(to1) <= 0) {
4409 for (BigDecimal i = self; i.compareTo(to1) <= 0; i = i.add(one)) {
4410 closure.call(i);
4411 }
4412 }
4413 else
4414 throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to +")");
4415 }
4416 }
4417
4418 /***
4419 * Iterates from this number down to the given number
4420 *
4421 * @param self a Number
4422 * @param to another Number to go down to
4423 * @param closure the closure to call
4424 */
4425 public static void downto(Number self, Number to, Closure closure) {
4426 int self1 = self.intValue();
4427 int to1 = to.intValue();
4428 if (self1 >= to1) {
4429 for (int i = self1; i >= to1; i--) {
4430 closure.call(new Integer(i));
4431 }
4432 }
4433 else
4434 throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to +")");
4435 }
4436
4437 public static void downto(long self, Number to, Closure closure) {
4438 long to1 = to.longValue();
4439 if (self >= to1) {
4440 for (long i = self; i >= to1; i--) {
4441 closure.call(new Long(i));
4442 }
4443 }
4444 else
4445 throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to +")");
4446 }
4447
4448 public static void downto(Long self, Number to, Closure closure) {
4449 long self1 = self.longValue();
4450 long to1 = to.longValue();
4451 if (self1 >= to1) {
4452 for (long i = self1; i >= to1; i--) {
4453 closure.call(new Long(i));
4454 }
4455 }
4456 else
4457 throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to +")");
4458 }
4459
4460 public static void downto(float self, Number to, Closure closure) {
4461 float to1 = to.floatValue();
4462 if (self >= to1) {
4463 for (float i = self; i >= to1; i--) {
4464 closure.call(new Float(i));
4465 }
4466 }
4467 else
4468 throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to +")");
4469 }
4470
4471 public static void downto(Float self, Number to, Closure closure) {
4472 float self1 = self.floatValue();
4473 float to1 = to.floatValue();
4474 if (self1 >= to1) {
4475 for (float i = self1; i >= to1; i--) {
4476 closure.call(new Float(i));
4477 }
4478 }
4479 else
4480 throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to +")");
4481 }
4482
4483 public static void downto(double self, Number to, Closure closure) {
4484 double to1 = to.doubleValue();
4485 if (self >= to1) {
4486 for (double i = self; i >= to1; i--) {
4487 closure.call(new Double(i));
4488 }
4489 }
4490 else
4491 throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to +")");
4492 }
4493
4494 public static void downto(Double self, Number to, Closure closure) {
4495 double self1 = self.doubleValue();
4496 double to1 = to.doubleValue();
4497 if (self1 >= to1) {
4498 for (double i = self1; i >= to1; i--) {
4499 closure.call(new Double(i));
4500 }
4501 }
4502 else
4503 throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to +")");
4504 }
4505
4506 public static void downto(final BigInteger self, final Number to, final Closure closure) {
4507 if (to instanceof BigDecimal) {
4508 final BigDecimal one = new BigDecimal("1.0");
4509 final BigDecimal to1 = (BigDecimal) to;
4510 final BigDecimal selfD = new BigDecimal(self);
4511 if (selfD.compareTo(to1) >= 0) {
4512 for (BigDecimal i = selfD; i.compareTo(to1) >= 0; i = i.subtract(one)) {
4513 closure.call(i.toBigInteger());
4514 }
4515 }
4516 else
4517 throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to +")");
4518 }
4519 else if (to instanceof BigInteger) {
4520 final BigInteger one = new BigInteger("1");
4521 final BigInteger to1 = (BigInteger) to;
4522 if (self.compareTo(to1) >= 0) {
4523 for (BigInteger i = self; i.compareTo(to1) >= 0; i = i.subtract(one)) {
4524 closure.call(i);
4525 }
4526 }
4527 else
4528 throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to +")");
4529 }
4530 else {
4531 final BigInteger one = new BigInteger("1");
4532 final BigInteger to1 = new BigInteger("" + to);
4533 if (self.compareTo(to1) >= 0) {
4534 for (BigInteger i = self; i.compareTo(to1) >= 0; i = i.subtract(one)) {
4535 closure.call(i);
4536 }
4537 }
4538 else
4539 throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to +")");
4540 }
4541 }
4542
4543 public static void downto(BigDecimal self, Number to, Closure closure) {
4544 final BigDecimal one = new BigDecimal("1.0");
4545 if (to instanceof BigDecimal) {
4546 BigDecimal to1 = (BigDecimal) to;
4547 if (self.compareTo(to1) >= 0) {
4548 for (BigDecimal i = self; i.compareTo(to1) >= 0; i = i.subtract(one)) {
4549 closure.call(i);
4550 }
4551 }
4552 else
4553 throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to +")");
4554 }
4555 else if (to instanceof BigInteger) {
4556 BigDecimal to1 = new BigDecimal((BigInteger) to);
4557 if (self.compareTo(to1) >= 0) {
4558 for (BigDecimal i = self; i.compareTo(to1) >= 0; i = i.subtract(one)) {
4559 closure.call(i);
4560 }
4561 }
4562 else
4563 throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to +")");
4564 }
4565 else {
4566 BigDecimal to1 = new BigDecimal(""+to);
4567 if (self.compareTo(to1) >= 0) {
4568 for (BigDecimal i = self; i.compareTo(to1) >= 0; i = i.subtract(one)) {
4569 closure.call(i);
4570 }
4571 }
4572 else
4573 throw new GroovyRuntimeException("Infinite loop in " + self +".downto(" + to +")");
4574 }
4575 }
4576
4577 /***
4578 * Iterates from this number up to the given number using a step increment
4579 *
4580 * @param self a Number to start with
4581 * @param to a Number to go up to
4582 * @param stepNumber a Number representing the step increment
4583 * @param closure the closure to call
4584 */
4585 public static void step(Number self, Number to, Number stepNumber, Closure closure) {
4586 if (self instanceof BigDecimal || to instanceof BigDecimal || stepNumber instanceof BigDecimal) {
4587 final BigDecimal zero = new BigDecimal("0.0");
4588 BigDecimal self1 = (self instanceof BigDecimal) ? (BigDecimal) self : new BigDecimal("" + self);
4589 BigDecimal to1 = (to instanceof BigDecimal) ? (BigDecimal) to : new BigDecimal("" + to);
4590 BigDecimal stepNumber1 = (stepNumber instanceof BigDecimal) ? (BigDecimal) stepNumber : new BigDecimal("" + stepNumber);
4591 if (stepNumber1.compareTo(zero) > 0 && to1.compareTo(self1) > 0) {
4592 for (BigDecimal i = self1; i.compareTo(to1) < 0; i = i.add(stepNumber1)) {
4593 closure.call(i);
4594 }
4595 }
4596 else if (stepNumber1.compareTo(zero) < 0 && to1.compareTo(self1) < 0) {
4597 for (BigDecimal i = self1; i.compareTo(to1) > 0; i = i.add(stepNumber1)) {
4598 closure.call(i);
4599 }
4600 }
4601 else
4602 throw new GroovyRuntimeException("Infinite loop in " + self1 + ".step(" + to1 + ", " + stepNumber1 + ")");
4603 }
4604 else if (self instanceof BigInteger || to instanceof BigInteger || stepNumber instanceof BigInteger) {
4605 final BigInteger zero = new BigInteger("0");
4606 BigInteger self1 = (self instanceof BigInteger) ? (BigInteger) self : new BigInteger("" + self);
4607 BigInteger to1 = (to instanceof BigInteger) ? (BigInteger) to : new BigInteger("" + to);
4608 BigInteger stepNumber1 = (stepNumber instanceof BigInteger) ? (BigInteger) stepNumber : new BigInteger("" + stepNumber);
4609 if (stepNumber1.compareTo(zero) > 0 && to1.compareTo(self1) > 0) {
4610 for (BigInteger i = self1; i.compareTo(to1) < 0; i = i.add(stepNumber1)) {
4611 closure.call(i);
4612 }
4613 }
4614 else if (stepNumber1.compareTo(zero) < 0 && to1.compareTo(self1) < 0) {
4615 for (BigInteger i = self1; i.compareTo(to1) > 0; i = i.add(stepNumber1)) {
4616 closure.call(i);
4617 }
4618 }
4619 else
4620 throw new GroovyRuntimeException("Infinite loop in " + self1 + ".step(" + to1 + ", " + stepNumber1 + ")");
4621 }
4622 else {
4623 int self1 = self.intValue();
4624 int to1 = to.intValue();
4625 int stepNumber1 = stepNumber.intValue();
4626 if (stepNumber1 > 0 && to1 > self1) {
4627 for (int i = self1; i < to1; i += stepNumber1) {
4628 closure.call(new Integer(i));
4629 }
4630 }
4631 else if (stepNumber1 < 0 && to1 < self1) {
4632 for (int i = self1; i > to1; i += stepNumber1) {
4633 closure.call(new Integer(i));
4634 }
4635 }
4636 else
4637 throw new GroovyRuntimeException("Infinite loop in " + self1 + ".step(" + to1 + ", " + stepNumber1 + ")");
4638 }
4639 }
4640
4641 /***
4642 * Get the absolute value
4643 *
4644 * @param number a Number
4645 * @return the absolute value of that Number
4646 */
4647
4648
4649 public static int abs(Number number) {
4650 return Math.abs(number.intValue());
4651 }
4652
4653 /***
4654 * Get the absolute value
4655 *
4656 * @param number a Long
4657 * @return the absolute value of that Long
4658 */
4659 public static long abs(Long number) {
4660 return Math.abs(number.longValue());
4661 }
4662
4663 /***
4664 * Get the absolute value
4665 *
4666 * @param number a Float
4667 * @return the absolute value of that Float
4668 */
4669 public static float abs(Float number) {
4670 return Math.abs(number.floatValue());
4671 }
4672
4673 /***
4674 * Get the absolute value
4675 *
4676 * @param number a Double
4677 * @return the absolute value of that Double
4678 */
4679 public static double abs(Double number) {
4680 return Math.abs(number.doubleValue());
4681 }
4682
4683 /***
4684 * Get the absolute value
4685 *
4686 * @param number a Float
4687 * @return the absolute value of that Float
4688 */
4689 public static int round(Float number) {
4690 return Math.round(number.floatValue());
4691 }
4692
4693 /***
4694 * Round the value
4695 *
4696 * @param number a Double
4697 * @return the absolute value of that Double
4698 */
4699 public static long round(Double number) {
4700 return Math.round(number.doubleValue());
4701 }
4702
4703 /***
4704 * Parse a String into an Integer
4705 *
4706 * @param self a String
4707 * @return an Integer
4708 */
4709 public static Integer toInteger(String self) {
4710 return Integer.valueOf(self.trim());
4711 }
4712
4713 /***
4714 * Parse a String into a Long
4715 *
4716 * @param self a String
4717 * @return a Long
4718 */
4719 public static Long toLong(String self) {
4720 return Long.valueOf(self.trim());
4721 }
4722
4723 /***
4724 * Parse a String into a Float
4725 *
4726 * @param self a String
4727 * @return a Float
4728 */
4729 public static Float toFloat(String self) {
4730 return Float.valueOf(self.trim());
4731 }
4732
4733 /***
4734 * Parse a String into a Double
4735 *
4736 * @param self a String
4737 * @return a Double
4738 */
4739 public static Double toDouble(String self) {
4740 return Double.valueOf(self.trim());
4741 }
4742
4743 /***
4744 * Parse a String into a BigInteger
4745 *
4746 * @param self a String
4747 * @return a BigInteger
4748 */
4749 public static BigInteger toBigInteger(String self) {
4750 return new BigInteger(self.trim());
4751 }
4752
4753 /***
4754 * Parse a String into a BigDecimal
4755 *
4756 * @param self a String
4757 * @return a BigDecimal
4758 */
4759 public static BigDecimal toBigDecimal(String self) {
4760 return new BigDecimal(self.trim());
4761 }
4762
4763 /***
4764 * Transform a Number into an Integer
4765 *
4766 * @param self a Number
4767 * @return an Integer
4768 */
4769 public static Integer toInteger(Number self) {
4770 return new Integer(self.intValue());
4771 }
4772
4773 /***
4774 * Transform a Number into a Long
4775 *
4776 * @param self a Number
4777 * @return an Long
4778 */
4779 public static Long toLong(Number self) {
4780 return new Long(self.longValue());
4781 }
4782
4783 /***
4784 * Transform a Number into a Float
4785 *
4786 * @param self a Number
4787 * @return an Float
4788 */
4789 public static Float toFloat(Number self) {
4790 return new Float(self.floatValue());
4791 }
4792
4793 /***
4794 * Transform a Number into a Double
4795 *
4796 * @param self a Number
4797 * @return an Double
4798 */
4799 public static Double toDouble(Number self) {
4800 return new Double(self.doubleValue());
4801 }
4802
4803 /***
4804 * Transform a Number into a BigDecimal
4805 *
4806 * @param self a Number
4807 * @return an BigDecimal
4808 */
4809 public static BigDecimal toBigDecimal(Number self) {
4810 return new BigDecimal(self.doubleValue());
4811 }
4812
4813 /***
4814 * Transform a Number into a BigInteger
4815 *
4816 * @param self a Number
4817 * @return an BigInteger
4818 */
4819 public static BigInteger toBigInteger(Number self) {
4820 return new BigInteger(Long.toString(self.longValue()));
4821 }
4822
4823
4824
4825
4826 /***
4827 * Increments a Date by a day
4828 *
4829 * @param self a Date
4830 * @return the next days date
4831 */
4832 public static Date next(Date self) {
4833 return plus(self, 1);
4834 }
4835
4836 /***
4837 * Increments a java.sql.Date by a day
4838 *
4839 * @param self a java.sql.Date
4840 * @return the next days date
4841 */
4842 public static java.sql.Date next(java.sql.Date self) {
4843 return new java.sql.Date(next((Date)self).getTime());
4844 }
4845
4846 /***
4847 * Decrement a Date by a day
4848 *
4849 * @param self a Date
4850 * @return the previous days date
4851 */
4852 public static Date previous(Date self) {
4853 return minus(self, 1);
4854 }
4855
4856 /***
4857 * Decrement a java.sql.Date by a day
4858 *
4859 * @param self a java.sql.Date
4860 * @return the previous days date
4861 */
4862 public static java.sql.Date previous(java.sql.Date self) {
4863 return new java.sql.Date(previous((Date)self).getTime());
4864 }
4865
4866 /***
4867 * Adds a number of days to this date and returns the new date
4868 *
4869 * @param self a Date
4870 * @param days the number of days to increase
4871 * @return the new date
4872 */
4873 public static Date plus(Date self, int days) {
4874 Calendar calendar = (Calendar) Calendar.getInstance().clone();
4875 calendar.setTime(self);
4876 calendar.add(Calendar.DAY_OF_YEAR, days);
4877 return calendar.getTime();
4878 }
4879
4880 /***
4881 * Adds a number of days to this date and returns the new date
4882 *
4883 * @param self a java.sql.Date
4884 * @param days the number of days to increase
4885 * @return the new date
4886 */
4887 public static java.sql.Date plus(java.sql.Date self, int days) {
4888 return new java.sql.Date(plus((Date)self, days).getTime());
4889 }
4890
4891 /***
4892 * Subtracts a number of days from this date and returns the new date
4893 *
4894 * @param self a Date
4895 * @return the new date
4896 */
4897 public static Date minus(Date self, int days) {
4898 return plus(self, -days);
4899 }
4900
4901 /***
4902 * Subtracts a number of days from this date and returns the new date
4903 *
4904 * @param self a java.sql.Date
4905 * @return the new date
4906 */
4907 public static java.sql.Date minus(java.sql.Date self, int days) {
4908 return new java.sql.Date(minus((Date)self, days).getTime());
4909 }
4910
4911
4912
4913
4914 public static Boolean and(Boolean left, Boolean right) {
4915 return Boolean.valueOf(left.booleanValue() & right.booleanValue());
4916 }
4917
4918 public static Boolean or(Boolean left, Boolean right) {
4919 return Boolean.valueOf(left.booleanValue() | right.booleanValue());
4920 }
4921
4922 public static Boolean xor(Boolean left, Boolean right) {
4923 return Boolean.valueOf(left.booleanValue() ^ right.booleanValue());
4924 }
4925
4926
4927
4928
4929
4930
4931
4932
4933 /***
4934 * Helper method to create an object input stream from the given file.
4935 *
4936 * @param file a file
4937 * @return an object input stream
4938 * @throws FileNotFoundException
4939 * @throws IOException
4940 */
4941 public static ObjectInputStream newObjectInputStream(File file) throws FileNotFoundException, IOException {
4942 return new ObjectInputStream(new FileInputStream(file));
4943 }
4944
4945 /***
4946 * Iterates through the given file object by object
4947 *
4948 * @param self a File
4949 * @param closure a closure
4950 * @throws IOException
4951 * @throws ClassNotFoundException
4952 */
4953 public static void eachObject(File self, Closure closure) throws IOException, ClassNotFoundException {
4954 eachObject(newObjectInputStream(self), closure);
4955 }
4956
4957 /***
4958 * Iterates through the given object stream object by object
4959 *
4960 * @param ois an ObjectInputStream
4961 * @param closure a closure
4962 * @throws IOException
4963 * @throws ClassNotFoundException
4964 */
4965 public static void eachObject(ObjectInputStream ois, Closure closure) throws IOException, ClassNotFoundException {
4966 try {
4967 while (true) {
4968 try {
4969 Object obj = ois.readObject();
4970
4971 closure.call(obj);
4972 } catch (EOFException e) {
4973 break;
4974 }
4975 }
4976 ois.close();
4977 } catch (ClassNotFoundException e) {
4978 try {
4979 ois.close();
4980 } catch (Exception e2) {
4981
4982 }
4983 throw e;
4984 } catch (IOException e) {
4985 try {
4986 ois.close();
4987 } catch (Exception e2) {
4988
4989 }
4990 throw e;
4991 }
4992 }
4993
4994 /***
4995 * Iterates through the given file line by line
4996 *
4997 * @param self a File
4998 * @param closure a closure
4999 * @throws IOException
5000 */
5001 public static void eachLine(File self, Closure closure) throws IOException {
5002 eachLine(newReader(self), closure);
5003 }
5004
5005 /***
5006 * Iterates through the given reader line by line
5007 *
5008 * @param self a Reader
5009 * @param closure a closure
5010 * @throws IOException
5011 */
5012 public static void eachLine(Reader self, Closure closure) throws IOException {
5013 BufferedReader br = null;
5014
5015 if (self instanceof BufferedReader)
5016 br = (BufferedReader) self;
5017 else
5018 br = new BufferedReader(self);
5019
5020 try {
5021 while (true) {
5022 String line = br.readLine();
5023 if (line == null) {
5024 break;
5025 } else {
5026 closure.call(line);
5027 }
5028 }
5029 br.close();
5030 } catch (IOException e) {
5031 if (self != null) {
5032 try {
5033 br.close();
5034 } catch (Exception e2) {
5035
5036 }
5037 throw e;
5038 }
5039 }
5040 }
5041
5042 /***
5043 * Iterates through the given file line by line, splitting on the seperator
5044 *
5045 * @param self a File
5046 * @param sep a String separator
5047 * @param closure a closure
5048 * @throws IOException
5049 */
5050 public static void splitEachLine(File self, String sep, Closure closure) throws IOException {
5051 splitEachLine(newReader(self), sep, closure);
5052 }
5053
5054 /***
5055 * Iterates through the given reader line by line, splitting on the seperator
5056 *
5057 * @param self a Reader
5058 * @param sep a String separator
5059 * @param closure a closure
5060 * @throws IOException
5061 */
5062 public static void splitEachLine(Reader self, String sep, Closure closure) throws IOException {
5063 BufferedReader br = null;
5064
5065 if (self instanceof BufferedReader)
5066 br = (BufferedReader) self;
5067 else
5068 br = new BufferedReader(self);
5069
5070 try {
5071 while (true) {
5072 String line = br.readLine();
5073 if (line == null) {
5074 break;
5075 } else {
5076 List vals = Arrays.asList(line.split(sep));
5077 closure.call(vals);
5078 }
5079 }
5080 br.close();
5081 } catch (IOException e) {
5082 if (self != null) {
5083 try {
5084 br.close();
5085 } catch (Exception e2) {
5086
5087 }
5088 throw e;
5089 }
5090 }
5091 }
5092
5093 /***
5094 * Read a single, whole line from the given Reader
5095 *
5096 * @param self a Reader
5097 * @return a line
5098 * @throws IOException
5099 */
5100 public static String readLine(Reader self) throws IOException {
5101 BufferedReader br = null;
5102
5103 if (self instanceof BufferedReader) {
5104 br = (BufferedReader) self;
5105 } else {
5106 br = new BufferedReader(self);
5107 }
5108 return br.readLine();
5109 }
5110
5111 /***
5112 * Read a single, whole line from the given InputStream
5113 *
5114 * @param stream an InputStream
5115 * @return a line
5116 * @throws IOException
5117 */
5118 public static String readLine(InputStream stream) throws IOException {
5119 return readLine(new InputStreamReader(stream));
5120 }
5121
5122 /***
5123 * Reads the file into a list of Strings for each line
5124 *
5125 * @param file a File
5126 * @return a List of lines
5127 * @throws IOException
5128 */
5129 public static List readLines(File file) throws IOException {
5130 IteratorClosureAdapter closure = new IteratorClosureAdapter(file);
5131 eachLine(file, closure);
5132 return closure.asList();
5133 }
5134
5135 /***
5136 * Reads the content of the File opened with the specified encoding and returns it as a String
5137 *
5138 * @param file the file whose content we want to read
5139 * @param charset the charset used to read the content of the file
5140 * @return a String containing the content of the file
5141 * @throws IOException
5142 */
5143 public static String getText(File file, String charset) throws IOException {
5144 BufferedReader reader = newReader(file, charset);
5145 return getText(reader);
5146 }
5147
5148 /***
5149 * Reads the content of the File and returns it as a String
5150 *
5151 * @param file the file whose content we want to read
5152 * @return a String containing the content of the file
5153 * @throws IOException
5154 */
5155 public static String getText(File file) throws IOException {
5156 BufferedReader reader = newReader(file);
5157 return getText(reader);
5158 }
5159
5160 /***
5161 * Reads the content of this URL and returns it as a String
5162 *
5163 * @param url URL to read content from
5164 * @return the text from that URL
5165 * @throws IOException
5166 */
5167 public static String getText(URL url) throws IOException {
5168 return getText(url, CharsetToolkit.getDefaultSystemCharset().toString());
5169 }
5170
5171 /***
5172 * Reads the content of this URL and returns it as a String
5173 *
5174 * @param url URL to read content from
5175 * @param charset opens the stream with a specified charset
5176 * @return the text from that URL
5177 * @throws IOException
5178 */
5179 public static String getText(URL url, String charset) throws IOException {
5180 BufferedReader reader = new BufferedReader(new InputStreamReader(url.openConnection().getInputStream(), charset));
5181 return getText(reader);
5182 }
5183
5184 /***
5185 * Reads the content of this InputStream and returns it as a String
5186 *
5187 * @param is an input stream
5188 * @return the text from that URL
5189 * @throws IOException
5190 */
5191 public static String getText(InputStream is) throws IOException {
5192 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
5193 return getText(reader);
5194 }
5195
5196 /***
5197 * Reads the content of this InputStream with a specified charset and returns it as a String
5198 *
5199 * @param is an input stream
5200 * @param charset opens the stream with a specified charset
5201 * @return the text from that URL
5202 * @throws IOException
5203 */
5204 public static String getText(InputStream is, String charset) throws IOException {
5205 BufferedReader reader = new BufferedReader(new InputStreamReader(is, charset));
5206 return getText(reader);
5207 }
5208
5209 /***
5210 * Reads the content of the Reader and returns it as a String
5211 *
5212 * @param reader a Reader whose content we want to read
5213 * @return a String containing the content of the buffered reader
5214 * @throws IOException
5215 */
5216 public static String getText(Reader reader) throws IOException {
5217 BufferedReader bufferedReader = new BufferedReader(reader);
5218 return getText(bufferedReader);
5219 }
5220
5221 /***
5222 * Reads the content of the BufferedReader and returns it as a String
5223 *
5224 * @param reader a BufferedReader whose content we want to read
5225 * @return a String containing the content of the buffered reader
5226 * @throws IOException
5227 */
5228 public static String getText(BufferedReader reader) throws IOException {
5229 StringBuffer answer = new StringBuffer();
5230
5231 char[] charBuffer = new char[4096];
5232 int nbCharRead = 0;
5233 while ((nbCharRead = reader.read(charBuffer)) != -1) {
5234
5235 answer.append(charBuffer, 0, nbCharRead);
5236 }
5237 reader.close();
5238 return answer.toString();
5239 }
5240
5241 /***
5242 * Write the text and append a new line (depending on the platform line-ending)
5243 *
5244 * @param writer a BufferedWriter
5245 * @param line the line to write
5246 * @throws IOException
5247 */
5248 public static void writeLine(BufferedWriter writer, String line) throws IOException {
5249 writer.write(line);
5250 writer.newLine();
5251 }
5252
5253 /***
5254 * Write the text to the File.
5255 *
5256 * @param file a File
5257 * @param text the text to write to the File
5258 * @throws IOException
5259 */
5260 public static void write(File file, String text) throws IOException {
5261 BufferedWriter writer = newWriter(file);
5262 writer.write(text);
5263 writer.close();
5264 }
5265
5266 /***
5267 * Write the text to the File.
5268 *
5269 * @param file a File
5270 * @param text the text to write to the File
5271 * @throws IOException
5272 */
5273 public static File leftShift(File file, Object text) throws IOException {
5274 append(file, text);
5275 return file;
5276 }
5277
5278 /***
5279 * Write the text to the File with a specified encoding.
5280 *
5281 * @param file a File
5282 * @param text the text to write to the File
5283 * @param charset the charset used
5284 * @throws IOException
5285 */
5286 public static void write(File file, String text, String charset) throws IOException {
5287 BufferedWriter writer = newWriter(file, charset);
5288 writer.write(text);
5289 writer.close();
5290 }
5291
5292 /***
5293 * Append the text at the end of the File
5294 *
5295 * @param file a File
5296 * @param text the text to append at the end of the File
5297 * @throws IOException
5298 */
5299 public static void append(File file, Object text) throws IOException {
5300 BufferedWriter writer = null;
5301 try {
5302 writer = newWriter(file, true);
5303 InvokerHelper.write(writer, text);
5304 } finally {
5305 if(writer != null)
5306 try {
5307 writer.close();
5308 }
5309 catch(Exception e){
5310
5311 }
5312 }
5313 }
5314 /***
5315 * Append the text at the end of the File with a specified encoding
5316 *
5317 * @param file a File
5318 * @param text the text to append at the end of the File
5319 * @param charset the charset used
5320 * @throws IOException
5321 */
5322 public static void append(File file, Object text, String charset) throws IOException {
5323 BufferedWriter writer = null;
5324 try {
5325 writer = newWriter(file, charset, true);
5326 InvokerHelper.write(writer, text);
5327 } finally {
5328 if(writer != null)
5329 try {
5330 writer.close();
5331 }
5332 catch(Exception e){
5333
5334 }
5335 }
5336 }
5337
5338 /***
5339 * Reads the reader into a list of Strings for each line
5340 *
5341 * @param reader a Reader
5342 * @return a List of lines
5343 * @throws IOException
5344 */
5345 public static List readLines(Reader reader) throws IOException {
5346 IteratorClosureAdapter closure = new IteratorClosureAdapter(reader);
5347 eachLine(reader, closure);
5348 return closure.asList();
5349 }
5350
5351 /***
5352 * This method is used to throw useful exceptions when the eachFile* and eachDir closure methods
5353 * are used incorrectly.
5354 *
5355 * @param dir The directory to check
5356 * @throws FileNotFoundException Thrown if the given directory does not exist
5357 * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
5358 */
5359 private static void checkDir(File dir) throws FileNotFoundException, IllegalArgumentException {
5360 if (!dir.exists())
5361 throw new FileNotFoundException(dir.getAbsolutePath());
5362 if (!dir.isDirectory())
5363 throw new IllegalArgumentException("The provided File object is not a directory: " + dir.getAbsolutePath());
5364 }
5365
5366 /***
5367 * Invokes the closure for each file in the given directory
5368 *
5369 * @param self a File
5370 * @param closure a closure
5371 * @throws FileNotFoundException Thrown if the given directory does not exist
5372 * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
5373 */
5374 public static void eachFile(File self, Closure closure) throws FileNotFoundException, IllegalArgumentException {
5375 checkDir(self);
5376 File[] files = self.listFiles();
5377 for (int i = 0; i < files.length; i++) {
5378 closure.call(files[i]);
5379 }
5380 }
5381
5382 /***
5383 * Invokes the closure for each file in the given directory and recursively.
5384 * It is a depth-first exploration, directories are included in the search.
5385 *
5386 * @param self a File
5387 * @param closure a closure
5388 * @throws FileNotFoundException Thrown if the given directory does not exist
5389 * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
5390 */
5391 public static void eachFileRecurse(File self, Closure closure) throws FileNotFoundException, IllegalArgumentException {
5392 checkDir(self);
5393 File[] files = self.listFiles();
5394 for (int i = 0; i < files.length; i++) {
5395 if (files[i].isDirectory()) {
5396 closure.call(files[i]);
5397 eachFileRecurse(files[i], closure);
5398 } else {
5399 closure.call(files[i]);
5400 }
5401 }
5402 }
5403
5404 /***
5405 * Invokes the closure for each directory in the given directory,
5406 * ignoring regular files.
5407 *
5408 * @param self a directory
5409 * @param closure a closure
5410 * @throws FileNotFoundException Thrown if the given directory does not exist
5411 * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
5412 */
5413 public static void eachDir(File self, Closure closure) throws FileNotFoundException, IllegalArgumentException {
5414 checkDir(self);
5415 File[] files = self.listFiles();
5416 for (int i = 0; i < files.length; i++) {
5417 if (files[i].isDirectory()) {
5418 closure.call(files[i]);
5419 }
5420 }
5421 }
5422
5423 /***
5424 * Invokes the closure for each file matching the given filter in the given directory
5425 * - calling the isCase() method used by switch statements. This method can be used
5426 * with different kinds of filters like regular expresions, classes, ranges etc.
5427 *
5428 * @param self a file
5429 * @param filter the filter to perform on the directory (using the isCase(object) method)
5430 * @param closure
5431 * @throws FileNotFoundException Thrown if the given directory does not exist
5432 * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
5433 */
5434 public static void eachFileMatch(File self, Object filter, Closure closure) throws FileNotFoundException, IllegalArgumentException {
5435 checkDir(self);
5436 File[] files = self.listFiles();
5437 MetaClass metaClass = InvokerHelper.getMetaClass(filter);
5438 for (int i = 0; i < files.length; i++) {
5439 if (InvokerHelper.asBool(metaClass.invokeMethod(filter, "isCase", files[i].getName()))) {
5440 closure.call(files[i]);
5441 }
5442 }
5443 }
5444
5445 /***
5446 * Allow simple syntax for using timers.
5447 *
5448 * @param timer a timer object
5449 * @param delay the delay in milliseconds before running the closure code
5450 * @param closure
5451 */
5452 public static void runAfter(Timer timer, int delay, final Closure closure) {
5453 TimerTask timerTask = new TimerTask() {
5454 public void run() {
5455 closure.call();
5456 }
5457 };
5458 timer.schedule(timerTask, delay);
5459 }
5460
5461 /***
5462 * Helper method to create a buffered reader for a file
5463 *
5464 * @param file a File
5465 * @return a BufferedReader
5466 * @throws IOException
5467 */
5468 public static BufferedReader newReader(File file) throws IOException {
5469 CharsetToolkit toolkit = new CharsetToolkit(file);
5470 return toolkit.getReader();
5471 }
5472
5473 /***
5474 * Helper method to create a buffered reader for a file, with a specified charset
5475 *
5476 * @param file a File
5477 * @param charset the charset with which we want to write in the File
5478 * @return a BufferedReader
5479 * @throws FileNotFoundException if the File was not found
5480 * @throws UnsupportedEncodingException if the encoding specified is not supported
5481 */
5482 public static BufferedReader newReader(File file, String charset)
5483 throws FileNotFoundException, UnsupportedEncodingException {
5484 return new BufferedReader(new InputStreamReader(new FileInputStream(file), charset));
5485 }
5486
5487 /***
5488 * Provides a reader for an arbitrary input stream
5489 *
5490 * @param self an input stream
5491 * @return a reader
5492 */
5493 public static BufferedReader newReader(final InputStream self) {
5494 return new BufferedReader(new InputStreamReader(self));
5495 }
5496
5497 /***
5498 * Helper method to create a new BufferedReader for a file and then
5499 * passes it into the closure and ensures its closed again afterwords
5500 *
5501 * @param file
5502 * @throws FileNotFoundException
5503 */
5504 public static void withReader(File file, Closure closure) throws IOException {
5505 withReader(newReader(file), closure);
5506 }
5507
5508 /***
5509 * Helper method to create a buffered output stream for a file
5510 *
5511 * @param file
5512 * @throws FileNotFoundException
5513 */
5514 public static BufferedOutputStream newOutputStream(File file) throws IOException {
5515 return new BufferedOutputStream(new FileOutputStream(file));
5516 }
5517
5518 /***
5519 * Helper method to create a new OutputStream for a file and then
5520 * passes it into the closure and ensures its closed again afterwords
5521 *
5522 * @param file a File
5523 * @throws FileNotFoundException
5524 */
5525 public static void withOutputStream(File file, Closure closure) throws IOException {
5526 withStream(newOutputStream(file), closure);
5527 }
5528
5529 /***
5530 * Helper method to create a new InputStream for a file and then
5531 * passes it into the closure and ensures its closed again afterwords
5532 *
5533 * @param file a File
5534 * @throws FileNotFoundException
5535 */
5536 public static void withInputStream(File file, Closure closure) throws IOException {
5537 withStream(newInputStream(file), closure);
5538 }
5539
5540 /***
5541 * Helper method to create a buffered writer for a file
5542 *
5543 * @param file a File
5544 * @return a BufferedWriter
5545 * @throws FileNotFoundException
5546 */
5547 public static BufferedWriter newWriter(File file) throws IOException {
5548 return new BufferedWriter(new FileWriter(file));
5549 }
5550
5551 /***
5552 * Helper method to create a buffered writer for a file in append mode
5553 *
5554 * @param file a File
5555 * @param append true if in append mode
5556 * @return a BufferedWriter
5557 * @throws FileNotFoundException
5558 */
5559 public static BufferedWriter newWriter(File file, boolean append) throws IOException {
5560 return new BufferedWriter(new FileWriter(file, append));
5561 }
5562
5563 /***
5564 * Helper method to create a buffered writer for a file
5565 *
5566 * @param file a File
5567 * @param charset the name of the encoding used to write in this file
5568 * @param append true if in append mode
5569 * @return a BufferedWriter
5570 * @throws FileNotFoundException
5571 */
5572 public static BufferedWriter newWriter(File file, String charset, boolean append) throws IOException {
5573 if (append) {
5574 return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, append), charset));
5575 } else {
5576
5577 FileOutputStream stream = new FileOutputStream(file);
5578 if ("UTF-16BE".equals(charset)) {
5579 writeUtf16Bom(stream, true);
5580 } else if ("UTF-16LE".equals(charset)) {
5581 writeUtf16Bom(stream, false);
5582 }
5583 return new BufferedWriter(new OutputStreamWriter(stream, charset));
5584 }
5585 }
5586
5587 /***
5588 * Helper method to create a buffered writer for a file
5589 *
5590 * @param file a File
5591 * @param charset the name of the encoding used to write in this file
5592 * @return a BufferedWriter
5593 * @throws FileNotFoundException
5594 */
5595 public static BufferedWriter newWriter(File file, String charset) throws IOException {
5596 return newWriter(file, charset, false);
5597 }
5598
5599 /***
5600 * Write a Byte Order Mark at the begining of the file
5601 *
5602 * @param stream the FileOuputStream to write the BOM to
5603 * @param bigEndian true if UTF 16 Big Endian or false if Low Endian
5604 * @throws IOException
5605 */
5606 private static void writeUtf16Bom(FileOutputStream stream, boolean bigEndian) throws IOException {
5607 if (bigEndian) {
5608 stream.write(-2);
5609 stream.write(-1);
5610 } else {
5611 stream.write(-1);
5612 stream.write(-2);
5613 }
5614 }
5615
5616 /***
5617 * Helper method to create a new BufferedWriter for a file and then
5618 * passes it into the closure and ensures it is closed again afterwords
5619 *
5620 * @param file a File
5621 * @param closure a closure
5622 * @throws FileNotFoundException
5623 */
5624 public static void withWriter(File file, Closure closure) throws IOException {
5625 withWriter(newWriter(file), closure);
5626 }
5627
5628 /***
5629 * Helper method to create a new BufferedWriter for a file in a specified encoding
5630 * and then passes it into the closure and ensures it is closed again afterwords
5631 *
5632 * @param file a File
5633 * @param charset the charset used
5634 * @param closure a closure
5635 * @throws FileNotFoundException
5636 */
5637 public static void withWriter(File file, String charset, Closure closure) throws IOException {
5638 withWriter(newWriter(file, charset), closure);
5639 }
5640
5641 /***
5642 * Helper method to create a new BufferedWriter for a file in a specified encoding
5643 * in append mode and then passes it into the closure and ensures it is closed again afterwords
5644 *
5645 * @param file a File
5646 * @param charset the charset used
5647 * @param closure a closure
5648 * @throws FileNotFoundException
5649 */
5650 public static void withWriterAppend(File file, String charset, Closure closure) throws IOException {
5651 withWriter(newWriter(file, charset, true), closure);
5652 }
5653
5654 /***
5655 * Helper method to create a new PrintWriter for a file
5656 *
5657 * @param file a File
5658 * @throws FileNotFoundException
5659 */
5660 public static PrintWriter newPrintWriter(File file) throws IOException {
5661 return new PrintWriter(newWriter(file));
5662 }
5663
5664 /***
5665 * Helper method to create a new PrintWriter for a file with a specified charset
5666 *
5667 * @param file a File
5668 * @param charset the charset
5669 * @return a PrintWriter
5670 * @throws FileNotFoundException
5671 */
5672 public static PrintWriter newPrintWriter(File file, String charset) throws IOException {
5673 return new PrintWriter(newWriter(file, charset));
5674 }
5675
5676 /***
5677 * Helper method to create a new PrintWriter for a file and then
5678 * passes it into the closure and ensures its closed again afterwords
5679 *
5680 * @param file a File
5681 * @throws FileNotFoundException
5682 */
5683 public static void withPrintWriter(File file, Closure closure) throws IOException {
5684 withWriter(newPrintWriter(file), closure);
5685 }
5686
5687 /***
5688 * Allows a writer to be used, calling the closure with the writer
5689 * and then ensuring that the writer is closed down again irrespective
5690 * of whether exceptions occur or the
5691 *
5692 * @param writer the writer which is used and then closed
5693 * @param closure the closure that the writer is passed into
5694 * @throws IOException
5695 */
5696 public static void withWriter(Writer writer, Closure closure) throws IOException {
5697 try {
5698 closure.call(writer);
5699
5700
5701
5702 Writer temp = writer;
5703 writer = null;
5704 temp.close();
5705 } finally {
5706 if (writer != null) {
5707 try {
5708 writer.close();
5709 } catch (IOException e) {
5710 log.warning("Caught exception closing writer: " + e);
5711 }
5712 }
5713 }
5714 }
5715
5716 /***
5717 * Allows a Reader to be used, calling the closure with the writer
5718 * and then ensuring that the writer is closed down again irrespective
5719 * of whether exceptions occur or the
5720 *
5721 * @param writer the writer which is used and then closed
5722 * @param closure the closure that the writer is passed into
5723 * @throws IOException
5724 */
5725 public static void withReader(Reader writer, Closure closure) throws IOException {
5726 try {
5727 closure.call(writer);
5728
5729
5730
5731 Reader temp = writer;
5732 writer = null;
5733 temp.close();
5734 } finally {
5735 if (writer != null) {
5736 try {
5737 writer.close();
5738 } catch (IOException e) {
5739 log.warning("Caught exception closing writer: " + e);
5740 }
5741 }
5742 }
5743 }
5744
5745 /***
5746 * Allows a InputStream to be used, calling the closure with the stream
5747 * and then ensuring that the stream is closed down again irrespective
5748 * of whether exceptions occur or the
5749 *
5750 * @param stream the stream which is used and then closed
5751 * @param closure the closure that the stream is passed into
5752 * @throws IOException
5753 */
5754 public static void withStream(InputStream stream, Closure closure) throws IOException {
5755 try {
5756 closure.call(stream);
5757
5758
5759
5760 InputStream temp = stream;
5761 stream = null;
5762 temp.close();
5763 } finally {
5764 if (stream != null) {
5765 try {
5766 stream.close();
5767 } catch (IOException e) {
5768 log.warning("Caught exception closing stream: " + e);
5769 }
5770 }
5771 }
5772 }
5773
5774 /***
5775 * Reads the stream into a list of Strings for each line
5776 *
5777 * @param stream a stream
5778 * @return a List of lines
5779 * @throws IOException
5780 */
5781 public static List readLines(InputStream stream) throws IOException {
5782 return readLines(new BufferedReader(new InputStreamReader(stream)));
5783 }
5784
5785 /***
5786 * Iterates through the given stream line by line
5787 *
5788 * @param stream a stream
5789 * @param closure a closure
5790 * @throws IOException
5791 */
5792 public static void eachLine(InputStream stream, Closure closure) throws IOException {
5793 eachLine(new InputStreamReader(stream), closure);
5794 }
5795
5796 /***
5797 * Iterates through the lines read from the URL's associated input stream
5798 *
5799 * @param url a URL to open and read
5800 * @param closure a closure to apply on each line
5801 * @throws IOException
5802 */
5803 public static void eachLine(URL url, Closure closure) throws IOException {
5804 eachLine(url.openConnection().getInputStream(), closure);
5805 }
5806
5807 /***
5808 * Helper method to create a new BufferedReader for a URL and then
5809 * passes it into the closure and ensures its closed again afterwords
5810 *
5811 * @param url a URL
5812 * @throws FileNotFoundException
5813 */
5814 public static void withReader(URL url, Closure closure) throws IOException {
5815 withReader(url.openConnection().getInputStream(), closure);
5816 }
5817
5818 /***
5819 * Helper method to create a new BufferedReader for a stream and then
5820 * passes it into the closure and ensures its closed again afterwords
5821 *
5822 * @param in a stream
5823 * @throws FileNotFoundException
5824 */
5825 public static void withReader(InputStream in, Closure closure) throws IOException {
5826 withReader(new InputStreamReader(in), closure);
5827 }
5828
5829 /***
5830 * Allows an output stream to be used, calling the closure with the output stream
5831 * and then ensuring that the output stream is closed down again irrespective
5832 * of whether exceptions occur
5833 *
5834 * @param stream the stream which is used and then closed
5835 * @param closure the closure that the writer is passed into
5836 * @throws IOException
5837 */
5838 public static void withWriter(OutputStream stream, Closure closure) throws IOException {
5839 withWriter(new OutputStreamWriter(stream), closure);
5840 }
5841
5842 /***
5843 * Allows an output stream to be used, calling the closure with the output stream
5844 * and then ensuring that the output stream is closed down again irrespective
5845 * of whether exceptions occur.
5846 *
5847 * @param stream the stream which is used and then closed
5848 * @param charset the charset used
5849 * @param closure the closure that the writer is passed into
5850 * @throws IOException
5851 */
5852 public static void withWriter(OutputStream stream, String charset, Closure closure) throws IOException {
5853 withWriter(new OutputStreamWriter(stream, charset), closure);
5854 }
5855
5856 /***
5857 * Allows a OutputStream to be used, calling the closure with the stream
5858 * and then ensuring that the stream is closed down again irrespective
5859 * of whether exceptions occur.
5860 *
5861 * @param stream the stream which is used and then closed
5862 * @param closure the closure that the stream is passed into
5863 * @throws IOException
5864 */
5865 public static void withStream(OutputStream stream, Closure closure) throws IOException {
5866 try {
5867 closure.call(stream);
5868
5869
5870
5871 OutputStream temp = stream;
5872 stream = null;
5873 temp.close();
5874 } finally {
5875 if (stream != null) {
5876 try {
5877 stream.close();
5878 } catch (IOException e) {
5879 log.warning("Caught exception closing stream: " + e);
5880 }
5881 }
5882 }
5883 }
5884
5885 /***
5886 * Helper method to create a buffered input stream for a file
5887 *
5888 * @param file a File
5889 * @return a BufferedInputStream of the file
5890 * @throws FileNotFoundException
5891 */
5892 public static BufferedInputStream newInputStream(File file) throws FileNotFoundException {
5893 return new BufferedInputStream(new FileInputStream(file));
5894 }
5895
5896 /***
5897 * Traverse through each byte of the specified File
5898 *
5899 * @param self a File
5900 * @param closure a closure
5901 */
5902 public static void eachByte(File self, Closure closure) throws IOException {
5903 BufferedInputStream is = newInputStream(self);
5904 eachByte(is, closure);
5905 }
5906
5907 /***
5908 * Traverse through each byte of the specified stream
5909 *
5910 * @param is stream to iterate over
5911 * @param closure closure to apply to each byte
5912 * @throws IOException
5913 */
5914 public static void eachByte(InputStream is, Closure closure) throws IOException {
5915 try {
5916 while (true) {
5917 int b = is.read();
5918 if (b == -1) {
5919 break;
5920 } else {
5921 closure.call(new Byte((byte) b));
5922 }
5923 }
5924 is.close();
5925 } catch (IOException e) {
5926 if (is != null) {
5927 try {
5928 is.close();
5929 } catch (Exception e2) {
5930
5931 }
5932 throw e;
5933 }
5934 }
5935 }
5936
5937 /***
5938 * Traverse through each byte of the specified URL
5939 *
5940 * @param url url to iterate over
5941 * @param closure closure to apply to each byte
5942 * @throws IOException
5943 */
5944 public static void eachByte(URL url, Closure closure) throws IOException {
5945 InputStream is = url.openConnection().getInputStream();
5946 eachByte(is, closure);
5947 }
5948
5949 /***
5950 * Transforms the characters from a reader with a Closure and write them to a writer
5951 *
5952 * @param reader
5953 * @param writer
5954 * @param closure
5955 */
5956 public static void transformChar(Reader reader, Writer writer, Closure closure) {
5957 int c;
5958 try {
5959 char[] chars = new char[1];
5960 while ((c = reader.read()) != -1) {
5961 chars[0] = (char) c;
5962 writer.write((String) closure.call(new String(chars)));
5963 }
5964 } catch (IOException e) {
5965 }
5966 }
5967
5968 /***
5969 * Transforms the lines from a reader with a Closure and write them to a writer
5970 *
5971 * @param reader Lines of text to be transformed.
5972 * @param writer Where transformed lines are written.
5973 * @param closure Single parameter closure that is called to transform each line of
5974 * text from the reader, before writing it to the writer.
5975 */
5976 public static void transformLine(Reader reader, Writer writer, Closure closure) throws IOException {
5977 BufferedReader br = new BufferedReader(reader);
5978 BufferedWriter bw = new BufferedWriter(writer);
5979 String line;
5980 while ((line = br.readLine()) != null) {
5981 Object o = closure.call(line);
5982 if (o != null) {
5983 bw.write(o.toString());
5984 bw.newLine();
5985 }
5986 }
5987 bw.flush();
5988 }
5989
5990 /***
5991 * Filter the lines from a reader and write them on the writer, according to a closure
5992 * which returns true or false.
5993 *
5994 * @param reader a reader
5995 * @param writer a writer
5996 * @param closure the closure which returns booleans
5997 * @throws IOException
5998 */
5999 public static void filterLine(Reader reader, Writer writer, Closure closure) throws IOException {
6000 BufferedReader br = new BufferedReader(reader);
6001 BufferedWriter bw = new BufferedWriter(writer);
6002 String line;
6003 while ((line = br.readLine()) != null) {
6004 if (InvokerHelper.asBool(closure.call(line))) {
6005 bw.write(line);
6006 bw.newLine();
6007 }
6008 }
6009 bw.flush();
6010 }
6011
6012 /***
6013 * Filters the lines of a File and creates a Writeable in return to stream the filtered lines
6014 *
6015 * @param self a File
6016 * @param closure a closure which returns a boolean indicating to filter the line or not
6017 * @return a Writable closure
6018 * @throws IOException if <code>self</code> is not readable
6019 */
6020 public static Writable filterLine(final File self, final Closure closure) throws IOException {
6021 return filterLine(newReader(self), closure);
6022 }
6023
6024 /***
6025 * Filter the lines from a File and write them on a writer, according to a closure
6026 * which returns true or false
6027 *
6028 * @param self a File
6029 * @param writer a writer
6030 * @param closure a closure which returns a boolean value and takes a line as input
6031 * @throws IOException if <code>self</code> is not readable
6032 */
6033 public static void filterLine(final File self, final Writer writer, final Closure closure) throws IOException {
6034 filterLine(newReader(self), writer, closure);
6035 }
6036
6037 /***
6038 * Filter the lines of a Reader and create a Writable in return to stream the filtered lines
6039 *
6040 * @param reader a reader
6041 * @param closure a closure returning a boolean indicating to filter or not a line
6042 * @return a Writable closure
6043 */
6044 public static Writable filterLine(Reader reader, final Closure closure) {
6045 final BufferedReader br = new BufferedReader(reader);
6046 return new Writable() {
6047 public Writer writeTo(Writer out) throws IOException {
6048 BufferedWriter bw = new BufferedWriter(out);
6049 String line;
6050 while ((line = br.readLine()) != null) {
6051 if (InvokerHelper.asBool(closure.call(line))) {
6052 bw.write(line);
6053 bw.newLine();
6054 }
6055 }
6056 bw.flush();
6057 return out;
6058 }
6059
6060 public String toString() {
6061 StringWriter buffer = new StringWriter();
6062 try {
6063 writeTo(buffer);
6064 } catch (IOException e) {
6065 throw new RuntimeException(e);
6066 }
6067 return buffer.toString();
6068 }
6069 };
6070 }
6071
6072 /***
6073 * Filter lines from an input stream using a closure predicate
6074 *
6075 * @param self an input stream
6076 * @param predicate a closure which returns boolean and takes a line
6077 * @return a filtered writer
6078 */
6079 public static Writable filterLine(final InputStream self, final Closure predicate) {
6080 return filterLine(newReader(self), predicate);
6081 }
6082
6083 /***
6084 * Filters lines from an input stream, writing to a writer, using a closure which
6085 * returns boolean and takes a line.
6086 *
6087 * @param self an InputStream
6088 * @param writer a writer to write output to
6089 * @param predicate a closure which returns a boolean and takes a line as input
6090 */
6091 public static void filterLine(final InputStream self, final Writer writer, final Closure predicate)
6092 throws IOException {
6093 filterLine(newReader(self), writer, predicate);
6094 }
6095
6096 /***
6097 * Reads the content of the file into an array of byte
6098 *
6099 * @param file a File
6100 * @return a List of Bytes
6101 */
6102 public static byte[] readBytes(File file) throws IOException {
6103 byte[] bytes = new byte[(int) file.length()];
6104 FileInputStream fileInputStream = new FileInputStream(file);
6105 DataInputStream dis = new DataInputStream(fileInputStream);
6106 dis.readFully(bytes);
6107 dis.close();
6108 return bytes;
6109 }
6110
6111
6112
6113
6114
6115
6116 /***
6117 * Allows an InputStream and an OutputStream from a Socket to be used,
6118 * calling the closure with the streams and then ensuring that the streams are closed down again
6119 * irrespective of whether exceptions occur.
6120 *
6121 * @param socket a Socket
6122 * @param closure a Closure
6123 * @throws IOException
6124 */
6125 public static void withStreams(Socket socket, Closure closure) throws IOException {
6126 InputStream input = socket.getInputStream();
6127 OutputStream output = socket.getOutputStream();
6128 try {
6129 closure.call(new Object[]{input, output});
6130 } finally {
6131 try {
6132 input.close();
6133 } catch (IOException e) {
6134
6135 }
6136 try {
6137 output.close();
6138 } catch (IOException e) {
6139
6140 }
6141 }
6142 }
6143
6144 /***
6145 * Overloads the left shift operator to provide an append mechanism
6146 * to add things to the output stream of a socket
6147 *
6148 * @param self a Socket
6149 * @param value a value to append
6150 * @return a Writer
6151 */
6152 public static Writer leftShift(Socket self, Object value) throws IOException {
6153 return leftShift(self.getOutputStream(), value);
6154 }
6155
6156 /***
6157 * Overloads the left shift operator to provide an append mechanism
6158 * to add bytes to the output stream of a socket
6159 *
6160 * @param self a Socket
6161 * @param value a value to append
6162 * @return an OutputStream
6163 */
6164 public static OutputStream leftShift(Socket self, byte[] value) throws IOException {
6165 return leftShift(self.getOutputStream(), value);
6166 }
6167
6168 /***
6169 * Allow to pass a Closure to the accept methods of ServerSocket
6170 *
6171 * @param serverSocket a ServerSocket
6172 * @param closure a Closure
6173 * @return a Socket
6174 * @throws IOException
6175 */
6176 public static Socket accept(ServerSocket serverSocket, final Closure closure) throws IOException {
6177 final Socket socket = serverSocket.accept();
6178 new Thread(new Runnable() {
6179 public void run() {
6180 try {
6181 closure.call(socket);
6182 } finally {
6183 try {
6184 socket.close();
6185 } catch (IOException e) {
6186
6187 }
6188 }
6189 }
6190 }).start();
6191 return socket;
6192 }
6193
6194
6195 /***
6196 * @param file a File
6197 * @return a File which wraps the input file and which implements Writable
6198 */
6199 public static File asWritable(File file) {
6200 return new WritableFile(file);
6201 }
6202
6203 /***
6204 * @param file a File
6205 * @param encoding the encoding to be used when reading the file's contents
6206 * @return File which wraps the input file and which implements Writable
6207 */
6208 public static File asWritable(File file, String encoding) {
6209 return new WritableFile(file, encoding);
6210 }
6211
6212 /***
6213 * Converts the given String into a List of strings of one character
6214 *
6215 * @param self a String
6216 * @return a List of characters (a 1-character String)
6217 */
6218 public static List toList(String self) {
6219 int size = self.length();
6220 List answer = new ArrayList(size);
6221 for (int i = 0; i < size; i++) {
6222 answer.add(self.substring(i, i + 1));
6223 }
6224 return answer;
6225 }
6226
6227
6228
6229
6230 /***
6231 * An alias method so that a process appears similar to System.out, System.in, System.err;
6232 * you can use process.in, process.out, process.err in a similar way
6233 *
6234 * @return an InputStream
6235 */
6236 public static InputStream getIn(Process self) {
6237 return self.getInputStream();
6238 }
6239
6240 /***
6241 * Read the text of the output stream of the Process.
6242 *
6243 * @param self a Process
6244 * @return the text of the output
6245 * @throws IOException
6246 */
6247 public static String getText(Process self) throws IOException {
6248 return getText(new BufferedReader(new InputStreamReader(self.getInputStream())));
6249 }
6250
6251 /***
6252 * An alias method so that a process appears similar to System.out, System.in, System.err;
6253 * you can use process.in, process.out, process.err in a similar way
6254 *
6255 * @return an InputStream
6256 */
6257 public static InputStream getErr(Process self) {
6258 return self.getErrorStream();
6259 }
6260
6261 /***
6262 * An alias method so that a process appears similar to System.out, System.in, System.err;
6263 * you can use process.in, process.out, process.err in a similar way
6264 *
6265 * @return an OutputStream
6266 */
6267 public static OutputStream getOut(Process self) {
6268 return self.getOutputStream();
6269 }
6270
6271 /***
6272 * Overloads the left shift operator to provide an append mechanism
6273 * to pipe into a Process
6274 *
6275 * @param self a Process
6276 * @param value a value to append
6277 * @return a Writer
6278 */
6279 public static Writer leftShift(Process self, Object value) throws IOException {
6280 return leftShift(self.getOutputStream(), value);
6281 }
6282
6283 /***
6284 * Overloads the left shift operator to provide an append mechanism
6285 * to pipe into a Process
6286 *
6287 * @param self a Process
6288 * @param value a value to append
6289 * @return an OutputStream
6290 */
6291 public static OutputStream leftShift(Process self, byte[] value) throws IOException {
6292 return leftShift(self.getOutputStream(), value);
6293 }
6294
6295 /***
6296 * Wait for the process to finish during a certain amount of time, otherwise stops the process.
6297 *
6298 * @param self a Process
6299 * @param numberOfMillis the number of milliseconds to wait before stopping the process
6300 */
6301 public static void waitForOrKill(Process self, long numberOfMillis) {
6302 ProcessRunner runnable = new ProcessRunner(self);
6303 Thread thread = new Thread(runnable);
6304 thread.start();
6305 runnable.waitForOrKill(numberOfMillis);
6306 }
6307
6308 /***
6309 * gets the input and error streams from a process and reads them
6310 * to avoid the process to block due to a full ouput buffer. For this
6311 * two Threads are started, so this method will return immediately
6312 *
6313 * @param self a Process
6314 */
6315 public static void consumeProcessOutput(Process self) {
6316 Dumper d = new Dumper(self.getErrorStream());
6317 Thread t = new Thread(d);
6318 t.start();
6319 d = new Dumper(self.getInputStream());
6320 t = new Thread(d);
6321 t.start();
6322 }
6323
6324 /***
6325 * Process each regex group matched substring of the given string. If the closure
6326 * parameter takes one argument an array with all match groups is passed to it.
6327 * If the closure takes as many arguments as there are match groups, then each
6328 * parameter will be one match group.
6329 *
6330 * @param self the source string
6331 * @param regex a Regex string
6332 * @param closure a closure with one parameter or as much parameters as groups
6333 * @author bing ran
6334 * @author Pilho Kim
6335 * @author Jochen Theodorou
6336 */
6337 public static void eachMatch(String self, String regex, Closure closure) {
6338 Pattern p = Pattern.compile(regex);
6339 Matcher m = p.matcher(self);
6340 while (m.find()) {
6341 int count = m.groupCount();
6342 ArrayList groups = new ArrayList();
6343 for (int i = 0; i <= count; i++) {
6344 groups.add(m.group(i));
6345 }
6346 if (groups.size()==1 || closure.getMaximumNumberOfParameters()<groups.size()) {
6347
6348
6349
6350 closure.call((Object)groups.toArray());
6351 } else {
6352 closure.call((Object[])groups.toArray());
6353 }
6354 }
6355 }
6356
6357 /***
6358 * Process each matched substring of the given group matcher. The object
6359 * passed to the closure is an array of strings, matched per a successful match.
6360 *
6361 * @param self the source matcher
6362 * @param closure a closure
6363 * @author bing ran
6364 * @author Pilho Kim
6365 */
6366 public static void each(Matcher self, Closure closure) {
6367 Matcher m = self;
6368 while (m.find()) {
6369 int count = m.groupCount();
6370 ArrayList groups = new ArrayList();
6371 for (int i = 0; i <= count; i++) {
6372 groups.add(m.group(i));
6373 }
6374 closure.call((Object[])groups.toArray());
6375 }
6376 }
6377
6378 /***
6379 * Iterates over every element of the collection and return the index of the first object
6380 * that matches the condition specified in the closure
6381 *
6382 * @param self the iteration object over which we iterate
6383 * @param closure the filter to perform a match on the collection
6384 * @return an integer that is the index of the first macthed object.
6385 */
6386 public static int findIndexOf(Object self, Closure closure) {
6387 int i = 0;
6388 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext(); i++) {
6389 Object value = iter.next();
6390 if (InvokerHelper.asBool(closure.call(value))) {
6391 break;
6392 }
6393 }
6394 return i;
6395 }
6396
6397 /***
6398 * use() a list of categories, specifying the list as varargs:<br>
6399 * use(CategoryClass1, CategoryClass2) { ... }<br>
6400 * This method prevents the error of forgetting to wrap the the category
6401 * classes in a list.
6402 * @param self
6403 * @param array
6404 */
6405 public static void use(Object self, Object[] array) {
6406 if (array.length < 2)
6407 throw new IllegalArgumentException(
6408 "Expecting at least 2 arguments, a category class and a Closure");
6409 Closure closure;
6410 try {
6411 closure = (Closure)array[array.length - 1];
6412 } catch (ClassCastException e) {
6413 throw new IllegalArgumentException("Expecting a Closure to be the last argument");
6414 }
6415 List list = new ArrayList(array.length - 1);
6416 for (int i = 0; i < array.length - 1; ++i)
6417 list.add(array[i]);
6418 GroovyCategorySupport.use(list, closure);
6419 }
6420
6421 /***
6422 * Iterates through the class loader parents until it finds a loader with a class
6423 * named equal to org.codehaus.groovy.tools.RootLoader. If there is no such class
6424 * null will be returned. The name has to be used because a direct compare with
6425 * == may fail as the class may be loaded through different classloaders.
6426 * @see org.codehaus.groovy.tools.RootLoader
6427 */
6428 public static ClassLoader getRootLoader(ClassLoader cl) {
6429 while (true) {
6430 if (cl==null) return null;
6431 if (cl.getClass().getName().equals(RootLoader.class.getName())) return cl;
6432 cl = cl.getParent();
6433 }
6434 }
6435
6436 /***
6437 * A Runnable which waits for a process to complete together with a notification scheme
6438 * allowing another thread to wait a maximum number of seconds for the process to complete
6439 * before killing it.
6440 */
6441 protected static class ProcessRunner implements Runnable {
6442 Process process;
6443 private boolean finished;
6444
6445 public ProcessRunner(Process process) {
6446 this.process = process;
6447 }
6448
6449 public void run() {
6450 try {
6451 process.waitFor();
6452 } catch (InterruptedException e) {
6453 }
6454 synchronized (this) {
6455 notifyAll();
6456 finished = true;
6457 }
6458 }
6459
6460 public synchronized void waitForOrKill(long millis) {
6461 if (!finished) {
6462 try {
6463 wait(millis);
6464 } catch (InterruptedException e) {
6465 }
6466 if (!finished) {
6467 process.destroy();
6468 }
6469 }
6470 }
6471 }
6472
6473 protected static class RangeInfo {
6474 protected int from, to;
6475 protected boolean reverse;
6476
6477 public RangeInfo(int from, int to, boolean reverse) {
6478 this.from = from;
6479 this.to = to;
6480 this.reverse = reverse;
6481 }
6482 }
6483
6484 private static class Dumper implements Runnable{
6485 InputStream in;
6486
6487 public Dumper(InputStream in) {
6488 this.in = in;
6489 }
6490
6491 public void run() {
6492 InputStreamReader isr = new InputStreamReader(in);
6493 BufferedReader br = new BufferedReader(isr);
6494 try {
6495 while (br.readLine()!=null) {}
6496 } catch (IOException e) {
6497 throw new GroovyRuntimeException("exception while reading process stream",e);
6498 }
6499 }
6500 }
6501 }