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