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