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.lang.reflect.Proxy;
47 import java.math.BigDecimal;
48 import java.math.BigInteger;
49 import java.net.MalformedURLException;
50 import java.net.ServerSocket;
51 import java.net.Socket;
52 import java.net.URI;
53 import java.net.URISyntaxException;
54 import java.net.URL;
55 import java.security.AccessController;
56 import java.security.PrivilegedAction;
57 import java.util.*;
58 import java.util.logging.Logger;
59 import java.util.regex.Matcher;
60 import java.util.regex.Pattern;
61
62 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
63 import org.codehaus.groovy.runtime.typehandling.NumberMath;
64 import org.codehaus.groovy.tools.RootLoader;
65 import org.w3c.dom.NodeList;
66
67 /***
68 * This class defines all the new groovy methods which appear on normal JDK
69 * classes inside the Groovy environment. Static methods are used with the
70 * first parameter the destination class.
71 *
72 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
73 * @author Jeremy Rayner
74 * @author Sam Pullara
75 * @author Rod Cope
76 * @author Guillaume Laforge
77 * @author John Wilson
78 * @author Hein Meling
79 * @author Dierk Koenig
80 * @author Pilho Kim
81 * @author Marc Guillemot
82 * @author Russel Winder
83 * @author bing ran
84 * @author Jochen Theodorou
85 * @version $Revision: 4598 $
86 */
87 public class DefaultGroovyMethods {
88
89 private static final Logger LOG = Logger.getLogger(DefaultGroovyMethods.class.getName());
90 private static final Integer ONE = new Integer(1);
91
92 /***
93 * Identity check. Since == is overridden in Groovy with the meaning of equality
94 * we need some fallback to check for object identity.
95 *
96 * @param self
97 * @param other
98 * @return true if self and other are identical, false otherwise
99 */
100 public static boolean is(Object self, Object other) {
101 return self == other;
102 }
103
104 /***
105 * Allows the closure to be called for the object reference self
106 *
107 * @param self the object to have a closure act upon
108 * @param closure the closure to call on the object
109 * @return result of calling the closure
110 */
111 public static Object identity(Object self, Closure closure) {
112 final Closure clonedClosure = (Closure) closure.clone();
113 clonedClosure.setDelegate(self);
114 return clonedClosure.call(self);
115 }
116
117 /***
118 * Allows the subscript operator to be used to lookup dynamic property values.
119 * <code>bean[somePropertyNameExpression]</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 the object to act upon
124 */
125 public static Object getAt(Object self, String property) {
126 return InvokerHelper.getProperty(self, property);
127 }
128
129 /***
130 * Allows the subscript operator to be used to set dynamically named property values.
131 * <code>bean[somePropertyNameExpression] = foo</code>. The normal property notation
132 * of groovy is neater and more concise but only works with property names which
133 * are known at compile time.
134 *
135 * @param self the object to act upon
136 * @param property the name of the property to set
137 * @param newValue the value to set
138 */
139 public static void putAt(Object self, String property, Object newValue) {
140 InvokerHelper.setProperty(self, property, newValue);
141 }
142
143 /***
144 * Generates a detailed dump string of an object showing its class,
145 * hashCode and fields
146 */
147 public static String dump(Object self) {
148 if (self == null) {
149 return "null";
150 }
151 StringBuffer buffer = new StringBuffer("<");
152 Class klass = self.getClass();
153 buffer.append(klass.getName());
154 buffer.append("@");
155 buffer.append(Integer.toHexString(self.hashCode()));
156 boolean groovyObject = self instanceof GroovyObject;
157
158
159
160
161
162 while (klass != null) {
163 Field[] fields = klass.getDeclaredFields();
164 for (int i = 0; i < fields.length; i++) {
165 final Field field = fields[i];
166 if ((field.getModifiers() & Modifier.STATIC) == 0) {
167 if (groovyObject && field.getName().equals("metaClass")) {
168 continue;
169 }
170 AccessController.doPrivileged(new PrivilegedAction() {
171 public Object run() {
172 field.setAccessible(true);
173 return null;
174 }
175 });
176 buffer.append(" ");
177 buffer.append(field.getName());
178 buffer.append("=");
179 try {
180 buffer.append(InvokerHelper.toString(field.get(self)));
181 } catch (Exception e) {
182 buffer.append(e);
183 }
184 }
185 }
186
187 klass = klass.getSuperclass();
188 }
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216 buffer.append(">");
217 return buffer.toString();
218 }
219
220 /***
221 * Retrieves the list of {@link MetaProperty} objects for 'self' and wraps it
222 * in a list of {@link PropertyValue} objects that additionally provide
223 * the value for each property of 'self'.
224 *
225 * @param self the receiver object
226 * @return list of {@link PropertyValue} objects
227 * @see groovy.util.Expando#getMetaPropertyValues()
228 */
229 public static List getMetaPropertyValues(Object self) {
230 MetaClass metaClass = InvokerHelper.getMetaClass(self);
231 List mps = metaClass.getProperties();
232 List props = new ArrayList(mps.size());
233 for (Iterator itr = mps.iterator(); itr.hasNext();) {
234 MetaProperty mp = (MetaProperty) itr.next();
235 PropertyValue pv = new PropertyValue(self, mp);
236 props.add(pv);
237 }
238 return props;
239 }
240
241 /***
242 * Convenience method that calls {@link #getMetaPropertyValues(Object)}(self)
243 * and provides the data in form of simple key/value pairs, i.e. without
244 * type() information.
245 *
246 * @param self the receiver object
247 * @return meta properties as Map of key/value pairs
248 */
249 public static Map getProperties(Object self) {
250 List metaProps = getMetaPropertyValues(self);
251 Map props = new HashMap(metaProps.size());
252
253 for (Iterator itr = metaProps.iterator(); itr.hasNext();) {
254 PropertyValue pv = (PropertyValue) itr.next();
255 try {
256 props.put(pv.getName(), pv.getValue());
257 } catch (Exception e) {
258 LOG.throwing(self.getClass().getName(), "getProperty(" + pv.getName() + ")", e);
259 }
260 }
261 return props;
262 }
263
264 /***
265 * Scoped use method
266 */
267 public static void use(Object self, Class categoryClass, Closure closure) {
268 GroovyCategorySupport.use(categoryClass, closure);
269 }
270
271 /***
272 * Scoped use method with list of categories
273 */
274 public static void use(Object self, List categoryClassList, Closure closure) {
275 GroovyCategorySupport.use(categoryClassList, closure);
276 }
277
278
279 /***
280 * use() a list of categories, specifying the list as varargs:<br>
281 * use(CategoryClass1, CategoryClass2) { ... }<br>
282 * This method prevents the error of forgetting to wrap the the category
283 * classes in a list.
284 *
285 * @param self
286 * @param array
287 */
288 public static void use(Object self, Object[] array) {
289 if (array.length < 2)
290 throw new IllegalArgumentException(
291 "Expecting at least 2 arguments, a category class and a Closure");
292 Closure closure;
293 try {
294 closure = (Closure) array[array.length - 1];
295 } catch (ClassCastException e) {
296 throw new IllegalArgumentException("Expecting a Closure to be the last argument");
297 }
298 List list = new ArrayList(array.length - 1);
299 for (int i = 0; i < array.length - 1; ++i)
300 list.add(array[i]);
301 GroovyCategorySupport.use(list, closure);
302 }
303
304 /***
305 * Print to a console in interactive format
306 */
307 public static void print(Object self, Object value) {
308 System.out.print(InvokerHelper.toString(value));
309 }
310
311 /***
312 * Print a linebreak to the standard out.
313 */
314 public static void println(Object self) {
315 System.out.println();
316 }
317
318 /***
319 * Print to a console in interactive format along with a newline
320 */
321 public static void println(Object self, Object value) {
322 System.out.println(InvokerHelper.toString(value));
323 }
324
325 /***
326 * Printf to a console. Only works with JDK1.5 or later.
327 */
328 public static void printf(Object self, String format, Object[] values) {
329 if (System.getProperty("java.version").charAt(2) == '5') {
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344 try {
345 System.out.getClass().getMethod("printf", new Class[]{String.class, Object[].class}).invoke(System.out, new Object[]{format, values});
346 } catch (NoSuchMethodException nsme) {
347 throw new RuntimeException("getMethod threw a NoSuchMethodException. This is impossible.");
348 } catch (IllegalAccessException iae) {
349 throw new RuntimeException("invoke threw a IllegalAccessException. This is impossible.");
350 } catch (java.lang.reflect.InvocationTargetException ite) {
351 throw new RuntimeException("invoke threw a InvocationTargetException. This is impossible.");
352 }
353 } else {
354 throw new RuntimeException("printf requires JDK1.5 or later.");
355 }
356 }
357
358 /***
359 * Returns a formatted string using the specified format string and
360 * arguments.
361 * <p/>
362 * <p/>
363 * For examples, <pre>
364 * printf ( "Hello, %s!\n" , [ "world" ] as String[] )
365 * printf ( "Hello, %s!\n" , [ "Groovy" ])
366 * printf ( "%d + %d = %d\n" , [ 1 , 2 , 1+2 ] as Integer[] )
367 * printf ( "%d + %d = %d\n" , [ 3 , 3 , 3+3 ])
368 * <p/>
369 * ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as Integer[] ) }
370 * ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as int[] ) }
371 * ( 0x41..0x45 ).each { printf ( "-- %c\n" , [ it ] as char[] ) }
372 * ( 07..011 ).each { printf ( "-- %d\n" , [ it ] as byte[] ) }
373 * ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as short[] ) }
374 * ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as long[] ) }
375 * ( 7..11 ).each { printf ( "-- %5.2f\n" , [ it ] as float[] ) }
376 * ( 7..11 ).each { printf ( "-- %5.2g\n" , [ it ] as double[] ) }
377 * </pre>
378 * <p/>
379 *
380 * @param format A format string
381 * @param arg Argument which is referenced by the format specifiers in the format
382 * string. The type of <code>arg</code> should be one of Object[], List,
383 * int[], short[], byte[], char[], boolean[], long[], float[], or double[].
384 * @since JDK 1.5
385 */
386 public static void printf(Object self, String format, Object arg) {
387 if (arg instanceof Object[]) {
388 printf(self, format, (Object[]) arg);
389 return;
390 } else if (arg instanceof List) {
391 printf(self, format, ((List) arg).toArray());
392 return;
393 } else if (!arg.getClass().isArray()) {
394 Object[] o = (Object[]) java.lang.reflect.Array.newInstance(arg.getClass(), 1);
395 o[0] = arg;
396 printf(self, format, o);
397 return;
398 }
399
400 Object[] ans = null;
401 String elemType = arg.getClass().getName();
402 if (elemType.equals("[I")) {
403 int[] ia = (int[]) arg;
404 ans = new Integer[ia.length];
405 for (int i = 0; i < ia.length; i++) {
406 ans[i] = new Integer(ia[i]);
407 }
408 } else if (elemType.equals("[C")) {
409 char[] ia = (char[]) arg;
410 ans = new Character[ia.length];
411 for (int i = 0; i < ia.length; i++) {
412 ans[i] = new Character(ia[i]);
413 }
414 } else if (elemType.equals("[Z")) {
415 boolean[] ia = (boolean[]) arg;
416 ans = new Boolean[ia.length];
417 for (int i = 0; i < ia.length; i++) {
418 ans[i] = new Boolean(ia[i]);
419 }
420 } else if (elemType.equals("[B")) {
421 byte[] ia = (byte[]) arg;
422 ans = new Byte[ia.length];
423 for (int i = 0; i < ia.length; i++) {
424 ans[i] = new Byte(ia[i]);
425 }
426 } else if (elemType.equals("[S")) {
427 short[] ia = (short[]) arg;
428 ans = new Short[ia.length];
429 for (int i = 0; i < ia.length; i++) {
430 ans[i] = new Short(ia[i]);
431 }
432 } else if (elemType.equals("[F")) {
433 float[] ia = (float[]) arg;
434 ans = new Float[ia.length];
435 for (int i = 0; i < ia.length; i++) {
436 ans[i] = new Float(ia[i]);
437 }
438 } else if (elemType.equals("[J")) {
439 long[] ia = (long[]) arg;
440 ans = new Long[ia.length];
441 for (int i = 0; i < ia.length; i++) {
442 ans[i] = new Long(ia[i]);
443 }
444 } else if (elemType.equals("[D")) {
445 double[] ia = (double[]) arg;
446 ans = new Double[ia.length];
447 for (int i = 0; i < ia.length; i++) {
448 ans[i] = new Double(ia[i]);
449 }
450 } else {
451 throw new RuntimeException("printf(String," + arg + ")");
452 }
453 printf(self, format, (Object[]) ans);
454 }
455
456
457 /***
458 * @return a String that matches what would be typed into a terminal to
459 * create this object. e.g. [1, 'hello'].inspect() -> [1, "hello"]
460 */
461 public static String inspect(Object self) {
462 return InvokerHelper.inspect(self);
463 }
464
465 /***
466 * Print to a console in interactive format
467 */
468 public static void print(Object self, PrintWriter out) {
469 if (out == null) {
470 out = new PrintWriter(System.out);
471 }
472 out.print(InvokerHelper.toString(self));
473 }
474
475 /***
476 * Print to a console in interactive format
477 *
478 * @param out the PrintWriter used for printing
479 */
480 public static void println(Object self, PrintWriter out) {
481 if (out == null) {
482 out = new PrintWriter(System.out);
483 }
484 InvokerHelper.invokeMethod(self, "print", out);
485 out.println();
486 }
487
488 /***
489 * Provide a dynamic method invocation method which can be overloaded in
490 * classes to implement dynamic proxies easily.
491 */
492 public static Object invokeMethod(Object object, String method, Object arguments) {
493 return InvokerHelper.invokeMethod(object, method, arguments);
494 }
495
496
497
498 public static boolean isCase(Object caseValue, Object switchValue) {
499 return caseValue.equals(switchValue);
500 }
501
502 public static boolean isCase(String caseValue, Object switchValue) {
503 if (switchValue == null) {
504 return caseValue == null;
505 }
506 return caseValue.equals(switchValue.toString());
507 }
508
509 public static boolean isCase(Class caseValue, Object switchValue) {
510 if (switchValue instanceof Class) {
511 Class val = (Class) switchValue;
512 return caseValue.isAssignableFrom(val);
513 }
514 return caseValue.isInstance(switchValue);
515 }
516
517 public static boolean isCase(Collection caseValue, Object switchValue) {
518 return caseValue.contains(switchValue);
519 }
520
521 public static boolean isCase(Pattern caseValue, Object switchValue) {
522 if (switchValue == null) {
523 return caseValue == null;
524 }
525 final Matcher matcher = caseValue.matcher(switchValue.toString());
526 if (matcher.matches()) {
527 RegexSupport.setLastMatcher(matcher);
528 return true;
529 } else {
530 return false;
531 }
532 }
533
534
535
536
537 public static Collection unique(Collection self) {
538 if (self instanceof Set)
539 return self;
540 List answer = new ArrayList();
541 NumberComparator comparator = new NumberComparator();
542 for (Iterator it = self.iterator(); it.hasNext();) {
543 Object o = it.next();
544 boolean duplicated = false;
545 for (Iterator it2 = answer.iterator(); it2.hasNext();) {
546 Object o2 = it2.next();
547 if (comparator.compare(o, o2) == 0) {
548 duplicated = true;
549 break;
550 }
551 }
552 if (!duplicated)
553 answer.add(o);
554 }
555 self.clear();
556 self.addAll(answer);
557 return self;
558 }
559
560 /***
561 * A convenience method for making a collection unique using a closure as a comparator
562 * (by Michael Baehr)
563 *
564 * @param self a Collection
565 * @param closure a Closure used as a comparator
566 * @return self without any duplicates
567 */
568 public static Collection unique(Collection self, Closure closure) {
569 if (self instanceof Set)
570 return self;
571
572 int params = closure.getMaximumNumberOfParameters();
573 if (params == 1) {
574 unique(self, new OrderBy(closure));
575 } else {
576 unique(self, new ClosureComparator(closure));
577 }
578 return self;
579 }
580
581 /***
582 * Remove all duplicates from a given Collection.
583 * Works on the receiver object and returns it.
584 * The order of members in the Collection are compared by the given Comparator.
585 * For each duplicate, the first member which is returned
586 * by the given Collection's iterator is retained, but all other ones are removed.
587 * The given Collection's original order is preserved.
588 * <p/>
589 * <code><pre>
590 * class Person {
591 * @Property fname, lname
592 * public String toString() {
593 * return fname + " " + lname
594 * }
595 * }
596 * <p/>
597 * class PersonComparator implements Comparator {
598 * public int compare(Object o1, Object o2) {
599 * Person p1 = (Person) o1
600 * Person p2 = (Person) o2
601 * if (p1.lname != p2.lname)
602 * return p1.lname.compareTo(p2.lname)
603 * else
604 * return p1.fname.compareTo(p2.fname)
605 * }
606 * <p/>
607 * public boolean equals(Object obj) {
608 * return this.equals(obj)
609 * }
610 * }
611 * <p/>
612 * Person a = new Person(fname:"John", lname:"Taylor")
613 * Person b = new Person(fname:"Clark", lname:"Taylor")
614 * Person c = new Person(fname:"Tom", lname:"Cruz")
615 * Person d = new Person(fname:"Clark", lname:"Taylor")
616 * <p/>
617 * def list = [a, b, c, d]
618 * List list2 = list.unique(new PersonComparator())
619 * assert( list2 == list && list == [a, b, c] )
620 * <p/>
621 * </pre></code>
622 *
623 * @param self a Collection
624 * @param comparator a Comparator.
625 * @return self without duplicates
626 */
627 public static Collection unique(Collection self, Comparator comparator) {
628 if (self instanceof Set)
629 return self;
630 List answer = new ArrayList();
631 for (Iterator it = self.iterator(); it.hasNext();) {
632 Object o = it.next();
633 boolean duplicated = false;
634 for (Iterator it2 = answer.iterator(); it2.hasNext();) {
635 Object o2 = it2.next();
636 if (comparator.compare(o, o2) == 0) {
637 duplicated = true;
638 break;
639 }
640 }
641 if (!duplicated)
642 answer.add(o);
643 }
644 self.clear();
645 self.addAll(answer);
646 return self;
647 }
648
649 /***
650 * Allows objects to be iterated through using a closure
651 *
652 * @param self the object over which we iterate
653 * @param closure the closure applied on each element found
654 */
655 public static void each(Object self, Closure closure) {
656 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
657 closure.call(iter.next());
658 }
659 }
660
661 /***
662 * Allows object to be iterated through a closure with a counter
663 *
664 * @param self an Object
665 * @param closure a Closure
666 */
667 public static void eachWithIndex(Object self, Closure closure) {
668 int counter = 0;
669 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
670 closure.call(new Object[]{iter.next(), new Integer(counter++)});
671 }
672 }
673
674 /***
675 * Allows objects to be iterated through using a closure
676 *
677 * @param self the collection over which we iterate
678 * @param closure the closure applied on each element of the collection
679 */
680 public static void each(Collection self, Closure closure) {
681 for (Iterator iter = self.iterator(); iter.hasNext();) {
682 closure.call(iter.next());
683 }
684 }
685
686 /***
687 * Allows a Map to be iterated through using a closure. If the
688 * closure takes one parameter then it will be passed the Map.Entry
689 * otherwise if the closure takes two parameters then it will be
690 * passed the key and the value.
691 *
692 * @param self the map over which we iterate
693 * @param closure the closure applied on each entry of the map
694 */
695 public static void each(Map self, Closure closure) {
696 for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
697 Map.Entry entry = (Map.Entry) iter.next();
698 callClosureForMapEntry(closure, entry);
699 }
700 }
701
702
703 /***
704 * Iterates over every element of a collection, and check whether a predicate is valid for all elements.
705 *
706 * @param self the object over which we iterate
707 * @param closure the closure predicate used for matching
708 * @return true if every item in the collection matches the closure
709 * predicate
710 */
711 public static boolean every(Object self, Closure closure) {
712 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
713 if (!DefaultTypeTransformation.castToBoolean(closure.call(iter.next()))) {
714 return false;
715 }
716 }
717 return true;
718 }
719
720 /***
721 * Iterates over every element of a collection, and check whether a predicate is valid for at least one element
722 *
723 * @param self the object over which we iterate
724 * @param closure the closure predicate used for matching
725 * @return true if any item in the collection matches the closure predicate
726 */
727 public static boolean any(Object self, Closure closure) {
728 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
729 if (DefaultTypeTransformation.castToBoolean(closure.call(iter.next()))) {
730 return true;
731 }
732 }
733 return false;
734 }
735
736 /***
737 * Iterates over every element of the collection and return each object that matches
738 * the given filter - calling the isCase() method used by switch statements.
739 * This method can be used with different kinds of filters like regular expresions, classes, ranges etc.
740 *
741 * @param self the object over which we iterate
742 * @param filter the filter to perform on the collection (using the isCase(object) method)
743 * @return a list of objects which match the filter
744 */
745 public static List grep(Object self, Object filter) {
746 List answer = new ArrayList();
747 MetaClass metaClass = InvokerHelper.getMetaClass(filter);
748 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
749 Object object = iter.next();
750 if (DefaultTypeTransformation.castToBoolean(metaClass.invokeMethod(filter, "isCase", object))) {
751 answer.add(object);
752 }
753 }
754 return answer;
755 }
756
757 /***
758 * Counts the number of occurencies of the given value inside this collection
759 *
760 * @param self the collection within which we count the number of occurencies
761 * @param value the value
762 * @return the number of occurrencies
763 */
764 public static int count(Collection self, Object value) {
765 int answer = 0;
766 for (Iterator iter = self.iterator(); iter.hasNext();) {
767 if (DefaultTypeTransformation.compareEqual(iter.next(), value)) {
768 ++answer;
769 }
770 }
771 return answer;
772 }
773
774 /***
775 * Convert a collection to a List.
776 *
777 * @param self a collection
778 * @return a List
779 */
780 public static List toList(Collection self) {
781 List answer = new ArrayList(self.size());
782 answer.addAll(self);
783 return answer;
784 }
785
786 /***
787 * Iterates through this object transforming each object into a new value using the closure
788 * as a transformer, returning a list of transformed values.
789 *
790 * @param self the values of the object to map
791 * @param closure the closure used to map each element of the collection
792 * @return a List of the mapped values
793 */
794 public static List collect(Object self, Closure closure) {
795 return (List) collect(self, new ArrayList(), closure);
796 }
797
798 /***
799 * Iterates through this object transforming each object into a new value using the closure
800 * as a transformer and adding it to the collection, returning the resulting collection.
801 *
802 * @param self the values of the object to map
803 * @param collection the Collection to which the mapped values are added
804 * @param closure the closure used to map each element of the collection
805 * @return the resultant collection
806 */
807 public static Collection collect(Object self, Collection collection, Closure closure) {
808 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
809 collection.add(closure.call(iter.next()));
810 }
811 return collection;
812 }
813
814 /***
815 * Iterates through this collection transforming each entry into a new value using the closure
816 * as a transformer, returning a list of transformed values.
817 *
818 * @param self a collection
819 * @param closure the closure used for mapping
820 * @return a List of the mapped values
821 */
822 public static List collect(Collection self, Closure closure) {
823 return (List) collect(self, new ArrayList(self.size()), closure);
824 }
825
826 /***
827 * Iterates through this collection transforming each entry into a new value using the closure
828 * as a transformer, returning a list of transformed values.
829 *
830 * @param self a collection
831 * @param collection the Collection to which the mapped values are added
832 * @param closure the closure used to map each element of the collection
833 * @return the resultant collection
834 */
835 public static Collection collect(Collection self, Collection collection, Closure closure) {
836 for (Iterator iter = self.iterator(); iter.hasNext();) {
837 collection.add(closure.call(iter.next()));
838 if (closure.getDirective() == Closure.DONE) {
839 break;
840 }
841 }
842 return collection;
843 }
844
845 /***
846 * Iterates through this Map transforming each entry into a new value using the closure
847 * as a transformer, returning a list of transformed values.
848 *
849 * @param self a Map
850 * @param collection the Collection to which the mapped values are added
851 * @param closure the closure used for mapping, which can be with one(Map.Entry) or two(key, value) parameters
852 * @return a List of the mapped values
853 */
854 public static Collection collect(Map self, Collection collection, Closure closure) {
855 boolean isTwoParams = (closure.getParameterTypes().length == 2);
856 for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
857 if (isTwoParams) {
858 Map.Entry entry = (Map.Entry) iter.next();
859 collection.add(closure.call(new Object[]{entry.getKey(), entry.getValue()}));
860 } else {
861 collection.add(closure.call(iter.next()));
862 }
863 }
864 return collection;
865 }
866
867 /***
868 * Iterates through this Map transforming each entry into a new value using the closure
869 * as a transformer, returning a list of transformed values.
870 *
871 * @param self a Map
872 * @param closure the closure used to map each element of the collection
873 * @return the resultant collection
874 */
875 public static List collect(Map self, Closure closure) {
876 return (List) collect(self, new ArrayList(self.size()), closure);
877 }
878
879 /***
880 * Finds the first value matching the closure condition
881 *
882 * @param self an Object with an iterator returning its values
883 * @param closure a closure condition
884 * @return the first Object found
885 */
886 public static Object find(Object self, Closure closure) {
887 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
888 Object value = iter.next();
889 if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
890 return value;
891 }
892 }
893 return null;
894 }
895
896 /***
897 * Finds the first value matching the closure condition
898 *
899 * @param self a Collection
900 * @param closure a closure condition
901 * @return the first Object found
902 */
903 public static Object find(Collection self, Closure closure) {
904 for (Iterator iter = self.iterator(); iter.hasNext();) {
905 Object value = iter.next();
906 if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
907 return value;
908 }
909 }
910 return null;
911 }
912
913 /***
914 * Finds the first value matching the closure condition
915 *
916 * @param self a Map
917 * @param closure a closure condition
918 * @return the first Object found
919 */
920 public static Object find(Map self, Closure closure) {
921 for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
922 Object value = iter.next();
923 if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
924 return value;
925 }
926 }
927 return null;
928 }
929
930 /***
931 * Finds all values matching the closure condition
932 *
933 * @param self an Object with an Iterator returning its values
934 * @param closure a closure condition
935 * @return a List of the values found
936 */
937 public static List findAll(Object self, Closure closure) {
938 List answer = new ArrayList();
939 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
940 Object value = iter.next();
941 if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
942 answer.add(value);
943 }
944 }
945 return answer;
946 }
947
948 /***
949 * Finds all values matching the closure condition
950 *
951 * @param self a Collection
952 * @param closure a closure condition
953 * @return a List of the values found
954 */
955 public static List findAll(Collection self, Closure closure) {
956 List answer = new ArrayList(self.size());
957 for (Iterator iter = self.iterator(); iter.hasNext();) {
958 Object value = iter.next();
959 if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
960 answer.add(value);
961 }
962 }
963 return answer;
964 }
965
966 /***
967 * Finds all entries matching the closure condition. If the
968 * closure takes one parameter then it will be passed the Map.Entry
969 * otherwise if the closure takes two parameters then it will be
970 * passed the key and the value.
971 *
972 * @param self a Map
973 * @param closure a closure condition applying on the entries
974 * @return a new subMap
975 */
976 public static Map findAll(Map self, Closure closure) {
977 Map answer = new HashMap(self.size());
978 for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
979 Map.Entry entry = (Map.Entry) iter.next();
980 if (DefaultTypeTransformation.castToBoolean(callClosureForMapEntry(closure, entry))) {
981 answer.put(entry.getKey(), entry.getValue());
982 }
983 }
984 return answer;
985 }
986
987 /***
988 * Groups all collection members into groups determined by the
989 * supplied mapping closure.
990 *
991 * @param self a collection to group (no map)
992 * @param closure a closure mapping entries on keys
993 * @return a new Map grouped by keys
994 */
995 public static Map groupBy(Collection self, Closure closure) {
996 Map answer = new HashMap();
997 for (Iterator iter = self.iterator(); iter.hasNext();) {
998 groupCurrentElement(closure, answer, iter);
999 }
1000 return answer;
1001 }
1002
1003 /***
1004 * Groups all map members into groups determined by the
1005 * supplied mapping closure.
1006 *
1007 * @param self a map to group
1008 * @param closure a closure mapping entries on keys
1009 * @return a new Map grouped by keys
1010 */
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021 /***
1022 * Groups the current element of the iterator as determined
1023 * by the mapping closure.
1024 *
1025 * @param closure a closure mapping the current entry on a key
1026 * @param answer the map containing the results
1027 * @param iter the iterator from which the current element stems
1028 */
1029 private static void groupCurrentElement(Closure closure, Map answer, Iterator iter) {
1030 Object element = iter.next();
1031 Object value = closure.call(element);
1032 if (answer.containsKey(value)) {
1033 ((List) answer.get(value)).add(element);
1034 } else {
1035 ArrayList groupedElements = new ArrayList();
1036 groupedElements.add(element);
1037 answer.put(value, groupedElements);
1038 }
1039 }
1040
1041
1042 protected static Object callClosureForMapEntry(Closure closure, Map.Entry entry) {
1043 if (closure.getMaximumNumberOfParameters() == 2) {
1044 return closure.call(new Object[]{entry.getKey(), entry.getValue()});
1045 }
1046 return closure.call(entry);
1047 }
1048
1049
1050 /***
1051 * Iterates through the given collection, passing in the initial value to
1052 * the closure along with the current iterated item then passing into the
1053 * next iteration the value of the previous closure.
1054 *
1055 * @param self a Collection
1056 * @param value a value
1057 * @param closure a closure
1058 * @return the last value of the last iteration
1059 */
1060 public static Object inject(Collection self, Object value, Closure closure) {
1061 Object[] params = new Object[2];
1062 for (Iterator iter = self.iterator(); iter.hasNext();) {
1063 Object item = iter.next();
1064 params[0] = value;
1065 params[1] = item;
1066 value = closure.call(params);
1067 }
1068 return value;
1069 }
1070
1071 /***
1072 * Iterates through the given array of objects, passing in the initial value to
1073 * the closure along with the current iterated item then passing into the
1074 * next iteration the value of the previous closure.
1075 *
1076 * @param self an Object[]
1077 * @param value a value
1078 * @param closure a closure
1079 * @return the last value of the last iteration
1080 */
1081 public static Object inject(Object[] self, Object value, Closure closure) {
1082 Object[] params = new Object[2];
1083 for (int i = 0; i < self.length; i++) {
1084 params[0] = value;
1085 params[1] = self[i];
1086 value = closure.call(params);
1087 }
1088 return value;
1089 }
1090
1091 /***
1092 * Sums a collection of numeric values. <code>coll.sum()</code> is equivalent to:
1093 * <code>coll.inject(0) {value, item -> value + item}</code>.
1094 *
1095 * @param self Collection of values to add together.
1096 * @return The sum of all of the list itmems.
1097 */
1098 public static Object sum(Collection self) {
1099 Object result = null;
1100
1101 if (self.size() == 0) return result;
1102
1103 boolean isNumber = true;
1104
1105 Class classref = null;
1106 try {
1107 classref = Class.forName("java.lang.Number");
1108 } catch (Exception ex) {
1109 }
1110
1111 for (Iterator iter = self.iterator(); iter.hasNext();) {
1112 if (!classref.isInstance(iter.next())) {
1113 isNumber = false;
1114 break;
1115 }
1116 }
1117
1118 if (isNumber) {
1119 result = new Integer(0);
1120 } else {
1121 result = new String();
1122 }
1123
1124 Object[] param = new Object[1];
1125 for (Iterator iter = self.iterator(); iter.hasNext();) {
1126 param[0] = iter.next();
1127 MetaClass metaClass = InvokerHelper.getMetaClass(result);
1128 result = metaClass.invokeMethod(result, "plus", param);
1129 }
1130 return result;
1131 }
1132
1133 /***
1134 * Sums the result of apply a closure to each item of a collection.
1135 * <code>coll.sum(closure)</code> is equivalent to:
1136 * <code>coll.collect(closure).sum()</code>.
1137 *
1138 * @param self a Collection
1139 * @param closure a single parameter closure that returns a numeric value.
1140 * @return The sum of the values returned by applying the closure to each
1141 * item of the list.
1142 */
1143 public static Object sum(Collection self, Closure closure) {
1144 Object result = new Integer(0);
1145 Object[] closureParam = new Object[1];
1146 Object[] plusParam = new Object[1];
1147 for (Iterator iter = self.iterator(); iter.hasNext();) {
1148 closureParam[0] = iter.next();
1149 plusParam[0] = closure.call(closureParam);
1150 MetaClass metaClass = InvokerHelper.getMetaClass(result);
1151 result = metaClass.invokeMethod(result, "plus", plusParam);
1152 }
1153 return result;
1154 }
1155
1156 /***
1157 * Concatenates all of the items of the collection together with the given String as a separator
1158 *
1159 * @param self a Collection of objects
1160 * @param separator a String separator
1161 * @return the joined String
1162 */
1163 public static String join(Collection self, String separator) {
1164 StringBuffer buffer = new StringBuffer();
1165 boolean first = true;
1166
1167 if (separator == null) separator = "";
1168
1169 for (Iterator iter = self.iterator(); iter.hasNext();) {
1170 Object value = iter.next();
1171 if (first) {
1172 first = false;
1173 } else {
1174 buffer.append(separator);
1175 }
1176 buffer.append(InvokerHelper.toString(value));
1177 }
1178 return buffer.toString();
1179 }
1180
1181 /***
1182 * Concatenates all of the elements of the array together with the given String as a separator
1183 *
1184 * @param self an array of Object
1185 * @param separator a String separator
1186 * @return the joined String
1187 */
1188 public static String join(Object[] self, String separator) {
1189 StringBuffer buffer = new StringBuffer();
1190 boolean first = true;
1191
1192 if (separator == null) separator = "";
1193
1194 for (int i = 0; i < self.length; i++) {
1195 String value = InvokerHelper.toString(self[i]);
1196 if (first) {
1197 first = false;
1198 } else {
1199 buffer.append(separator);
1200 }
1201 buffer.append(value);
1202 }
1203 return buffer.toString();
1204 }
1205
1206 /***
1207 * Selects the maximum value found in the collection
1208 *
1209 * @param self a Collection
1210 * @return the maximum value
1211 */
1212 public static Object max(Collection self) {
1213 Object answer = null;
1214 for (Iterator iter = self.iterator(); iter.hasNext();) {
1215 Object value = iter.next();
1216 if (value != null) {
1217 if (answer == null || ScriptBytecodeAdapter.compareGreaterThan(value, answer)) {
1218 answer = value;
1219 }
1220 }
1221 }
1222 return answer;
1223 }
1224
1225 /***
1226 * Selects the maximum value found in the collection using the given comparator
1227 *
1228 * @param self a Collection
1229 * @param comparator a Comparator
1230 * @return the maximum value
1231 */
1232 public static Object max(Collection self, Comparator comparator) {
1233 Object answer = null;
1234 for (Iterator iter = self.iterator(); iter.hasNext();) {
1235 Object value = iter.next();
1236 if (answer == null || comparator.compare(value, answer) > 0) {
1237 answer = value;
1238 }
1239 }
1240 return answer;
1241 }
1242
1243 /***
1244 * Selects the minimum value found in the collection
1245 *
1246 * @param self a Collection
1247 * @return the minimum value
1248 */
1249 public static Object min(Collection self) {
1250 Object answer = null;
1251 for (Iterator iter = self.iterator(); iter.hasNext();) {
1252 Object value = iter.next();
1253 if (value != null) {
1254 if (answer == null || ScriptBytecodeAdapter.compareLessThan(value, answer)) {
1255 answer = value;
1256 }
1257 }
1258 }
1259 return answer;
1260 }
1261
1262 /***
1263 * Selects the minimum value found in the collection using the given comparator
1264 *
1265 * @param self a Collection
1266 * @param comparator a Comparator
1267 * @return the minimum value
1268 */
1269 public static Object min(Collection self, Comparator comparator) {
1270 Object answer = null;
1271 for (Iterator iter = self.iterator(); iter.hasNext();) {
1272 Object value = iter.next();
1273 if (answer == null || comparator.compare(value, answer) < 0) {
1274 answer = value;
1275 }
1276 }
1277 return answer;
1278 }
1279
1280 /***
1281 * Selects the minimum value found in the collection using the given closure as a comparator
1282 *
1283 * @param self a Collection
1284 * @param closure a closure used as a comparator
1285 * @return the minimum value
1286 */
1287 public static Object min(Collection self, Closure closure) {
1288 int params = closure.getMaximumNumberOfParameters();
1289 if (params == 1) {
1290 Object answer = null;
1291 Object answer_value = null;
1292 for (Iterator iter = self.iterator(); iter.hasNext();) {
1293 Object item = iter.next();
1294 Object value = closure.call(item);
1295 if (answer == null || ScriptBytecodeAdapter.compareLessThan(value, answer_value)) {
1296 answer = item;
1297 answer_value = value;
1298 }
1299 }
1300 return answer;
1301 } else {
1302 return min(self, new ClosureComparator(closure));
1303 }
1304 }
1305
1306 /***
1307 * Selects the maximum value found in the collection using the given closure as a comparator
1308 *
1309 * @param self a Collection
1310 * @param closure a closure used as a comparator
1311 * @return the maximum value
1312 */
1313 public static Object max(Collection self, Closure closure) {
1314 int params = closure.getMaximumNumberOfParameters();
1315 if (params == 1) {
1316 Object answer = null;
1317 Object answer_value = null;
1318 for (Iterator iter = self.iterator(); iter.hasNext();) {
1319 Object item = iter.next();
1320 Object value = closure.call(item);
1321 if (answer == null || ScriptBytecodeAdapter.compareLessThan(answer_value, value)) {
1322 answer = item;
1323 answer_value = value;
1324 }
1325 }
1326 return answer;
1327 } else {
1328 return max(self, new ClosureComparator(closure));
1329 }
1330 }
1331
1332 /***
1333 * Makes a String look like a Collection by adding support for the size() method
1334 *
1335 * @param text a String
1336 * @return the length of the String
1337 */
1338 public static int size(String text) {
1339 return text.length();
1340 }
1341
1342 /***
1343 * Provide standard Groovy size() method for StringBuffers
1344 *
1345 * @param buffer a StringBuffer
1346 * @return the length of the StringBuffer
1347 */
1348 public static int size(StringBuffer buffer) {
1349 return buffer.length();
1350 }
1351
1352 /***
1353 * Provide the standard Groovy size method
1354 */
1355 public static long size(File file) {
1356 return file.length();
1357 }
1358
1359
1360 /***
1361 * Provide the standard Groovy size method
1362 */
1363 public static long size(Matcher matcher) {
1364 return getCount(matcher);
1365 }
1366
1367 /***
1368 * Makes an Array look like a Collection by adding support for the size() method
1369 *
1370 * @param self an Array of Object
1371 * @return the size of the Array
1372 */
1373 public static int size(Object[] self) {
1374 return self.length;
1375 }
1376
1377 /***
1378 * Support the subscript operator for String.
1379 *
1380 * @param text a String
1381 * @param index the index of the Character to get
1382 * @return the Character at the given index
1383 */
1384 public static CharSequence getAt(CharSequence text, int index) {
1385 index = normaliseIndex(index, text.length());
1386 return text.subSequence(index, index + 1);
1387 }
1388
1389 /***
1390 * Support the subscript operator for String
1391 *
1392 * @param text a String
1393 * @return the Character object at the given index
1394 */
1395 public static String getAt(String text, int index) {
1396 index = normaliseIndex(index, text.length());
1397 return text.substring(index, index + 1);
1398 }
1399
1400 /***
1401 * Support the range subscript operator for CharSequence
1402 *
1403 * @param text a CharSequence
1404 * @param range a Range
1405 * @return the subsequence CharSequence
1406 */
1407 public static CharSequence getAt(CharSequence text, Range range) {
1408 int from = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getFrom()), text.length());
1409 int to = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getTo()), text.length());
1410
1411
1412 if (from > to) {
1413 int tmp = from;
1414 from = to;
1415 to = tmp;
1416 }
1417
1418 return text.subSequence(from, to + 1);
1419 }
1420
1421 /***
1422 * Support the range subscript operator for CharSequence or StringBuffer with IntRange
1423 *
1424 * @param text a CharSequence
1425 * @param range an IntRange
1426 * @return the subsequence CharSequence
1427 */
1428 public static CharSequence getAt(CharSequence text, IntRange range) {
1429 return getAt(text, (Range) range);
1430 }
1431
1432 /***
1433 * Support the range subscript operator for String with IntRange
1434 *
1435 * @param text a String
1436 * @param range an IntRange
1437 * @return the resulting String
1438 */
1439 public static String getAt(String text, IntRange range) {
1440 return getAt(text, (Range) range);
1441 }
1442
1443 /***
1444 * Support the range subscript operator for String
1445 *
1446 * @param text a String
1447 * @param range a Range
1448 * @return a substring corresponding to the Range
1449 */
1450 public static String getAt(String text, Range range) {
1451 int from = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getFrom()), text.length());
1452 int to = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getTo()), text.length());
1453
1454
1455 boolean reverse = range.isReverse();
1456 if (from > to) {
1457 int tmp = to;
1458 to = from;
1459 from = tmp;
1460 reverse = !reverse;
1461 }
1462
1463 String answer = text.substring(from, to + 1);
1464 if (reverse) {
1465 answer = reverse(answer);
1466 }
1467 return answer;
1468 }
1469
1470 /***
1471 * Creates a new string which is the reverse (backwards) of this string
1472 *
1473 * @param self a String
1474 * @return a new string with all the characters reversed.
1475 */
1476 public static String reverse(String self) {
1477 int size = self.length();
1478 StringBuffer buffer = new StringBuffer(size);
1479 for (int i = size - 1; i >= 0; i--) {
1480 buffer.append(self.charAt(i));
1481 }
1482 return buffer.toString();
1483 }
1484
1485 /***
1486 * Transforms a String representing a URL into a URL object.
1487 *
1488 * @param self the String representing a URL
1489 * @return a URL
1490 * @throws MalformedURLException is thrown if the URL is not well formed.
1491 */
1492 public static URL toURL(String self) throws MalformedURLException {
1493 return new URL(self);
1494 }
1495
1496 /***
1497 * Transforms a String representing a URI into a URI object.
1498 *
1499 * @param self the String representing a URI
1500 * @return a URI
1501 * @throws URISyntaxException is thrown if the URI is not well formed.
1502 */
1503 public static URI toURI(String self) throws URISyntaxException {
1504 return new URI(self);
1505 }
1506
1507 /***
1508 * Turns a String into a regular expression pattern
1509 *
1510 * @param self a String to convert into a regular expression
1511 * @return the regular expression pattern
1512 */
1513 public static Pattern negate(String self) {
1514 return Pattern.compile(self);
1515 }
1516
1517 /***
1518 * Replaces all occurrencies of a captured group by the result of a closure on that text.
1519 * <p/>
1520 * <p> For examples,
1521 * <pre>
1522