KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > groovy > runtime > DefaultGroovyMethods


1 /*
2  * $Id: DefaultGroovyMethods.java,v 1.125 2005/01/04 01:52:28 spullara Exp $
3  *
4  * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5  *
6  * Redistribution and use of this software and associated documentation
7  * ("Software"), with or without modification, are permitted provided that the
8  * following conditions are met:
9  * 1. Redistributions of source code must retain copyright statements and
10  * notices. Redistributions must also contain a copy of this document.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. The name "groovy" must not be used to endorse or promote products
15  * derived from this Software without prior written permission of The Codehaus.
16  * For written permission, please contact info@codehaus.org.
17  * 4. Products derived from this Software may not be called "groovy" nor may
18  * "groovy" appear in their names without prior written permission of The
19  * Codehaus. "groovy" is a registered trademark of The Codehaus.
20  * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
23  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
26  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32  * DAMAGE.
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 JavaDoc;
44 import java.lang.reflect.Field JavaDoc;
45 import java.lang.reflect.Modifier JavaDoc;
46 import java.net.MalformedURLException JavaDoc;
47 import java.net.ServerSocket JavaDoc;
48 import java.net.Socket JavaDoc;
49 import java.net.URL JavaDoc;
50 import java.security.AccessController JavaDoc;
51 import java.security.PrivilegedAction JavaDoc;
52 import java.util.*;
53 import java.util.logging.Logger JavaDoc;
54 import java.util.regex.Matcher JavaDoc;
55 import java.util.regex.Pattern JavaDoc;
56
57 /**
58  * This class defines all the new groovy methods which appear on normal JDK
59  * classes inside the Groovy environment. Static methods are used with the
60  * first parameter the destination class.
61  *
62  * @author <a HREF="mailto:james@coredevelopers.net">James Strachan</a>
63  * @author Jeremy Rayner
64  * @author Sam Pullara
65  * @author Rod Cope
66  * @author Guillaume Laforge
67  * @author John Wilson
68  * @version $Revision: 1.125 $
69  */

70 public class DefaultGroovyMethods {
71
72     private static Logger JavaDoc log = Logger.getLogger(DefaultGroovyMethods.class.getName());
73
74     private static final Integer JavaDoc ONE = new Integer JavaDoc(1);
75     private static final char ZERO_CHAR = '\u0000';
76
77     /**
78      * Allows the subscript operator to be used to lookup dynamic property values.
79      * <code>bean[somePropertyNameExpression]</code>. The normal property notation
80      * of groovy is neater and more concise but only works with compile time known
81      * property names.
82      *
83      * @param self
84      * @return
85      */

86     public static Object JavaDoc getAt(Object JavaDoc self, String JavaDoc property) {
87         return InvokerHelper.getProperty(self, property);
88     }
89
90     /**
91      * Allows the subscript operator to be used to set dynamically named property values.
92      * <code>bean[somePropertyNameExpression] = foo</code>. The normal property notation
93      * of groovy is neater and more concise but only works with compile time known
94      * property names.
95      *
96      * @param self
97      */

98     public static void putAt(Object JavaDoc self, String JavaDoc property, Object JavaDoc newValue) {
99         InvokerHelper.setProperty(self, property, newValue);
100     }
101
102     /**
103      * Generates a detailed dump string of an object showing its class,
104      * hashCode and fields
105      */

106     public static String JavaDoc dump(Object JavaDoc self) {
107         if (self == null) {
108             return "null";
109         }
110         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("<");
111         Class JavaDoc klass = self.getClass();
112         buffer.append(klass.getName());
113         buffer.append("@");
114         buffer.append(Integer.toHexString(self.hashCode()));
115         boolean groovyObject = self instanceof GroovyObject;
116
117         /*jes this may be rewritten to use the new allProperties() stuff
118          * but the original pulls out private variables, whereas allProperties()
119          * does not. What's the real use of dump() here?
120          */

121         while (klass != null) {
122             Field JavaDoc[] fields = klass.getDeclaredFields();
123             for (int i = 0; i < fields.length; i++) {
124                 final Field JavaDoc field = fields[i];
125                 if ((field.getModifiers() & Modifier.STATIC) == 0) {
126                     if (groovyObject && field.getName().equals("metaClass")) {
127                         continue;
128                     }
129                     AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
130                         public Object JavaDoc run() {
131                             field.setAccessible(true);
132                             return null;
133                         }
134                     });
135                     buffer.append(" ");
136                     buffer.append(field.getName());
137                     buffer.append("=");
138                     try {
139                         buffer.append(InvokerHelper.toString(field.get(self)));
140                     } catch (Exception JavaDoc e) {
141                         buffer.append(e);
142                     }
143                 }
144             }
145
146             klass = klass.getSuperclass();
147         }
148
149         /* here is a different implementation that uses allProperties(). I have left
150          * it commented out because it returns a slightly different list of properties;
151          * ie it does not return privates. I don't know what dump() really should be doing,
152          * although IMO showing private fields is a no-no
153          */

154         /*
155         List props = allProperties(self);
156 for(Iterator itr = props.iterator(); itr.hasNext(); ) {
157 PropertyValue pv = (PropertyValue) itr.next();
158
159             // the original skipped this, so I will too
160             if(pv.getName().equals("metaClass")) continue;
161             if(pv.getName().equals("class")) continue;
162
163             buffer.append(" ");
164             buffer.append(pv.getName());
165             buffer.append("=");
166             try {
167                 buffer.append(InvokerHelper.toString(pv.getValue()));
168             }
169             catch (Exception e) {
170                 buffer.append(e);
171             }
172 }
173         */

174
175         buffer.append(">");
176         return buffer.toString();
177     }
178
179     public static void eachPropertyName(Object JavaDoc self, Closure closure) {
180         List props = allProperties(self);
181         for (Iterator itr = props.iterator(); itr.hasNext();) {
182             PropertyValue pv = (PropertyValue) itr.next();
183             closure.call(pv.getName());
184         }
185     }
186
187     public static void eachProperty(Object JavaDoc self, Closure closure) {
188         List props = allProperties(self);
189         for (Iterator itr = props.iterator(); itr.hasNext();) {
190             PropertyValue pv = (PropertyValue) itr.next();
191             closure.call(pv);
192         }
193     }
194
195     public static List allProperties(Object JavaDoc self) {
196         List props = new ArrayList();
197         MetaClass metaClass = InvokerHelper.getMetaClass(self);
198
199         List mps;
200
201         if (self instanceof groovy.util.Expando) {
202             mps = ((groovy.util.Expando) self).getProperties();
203         } else {
204             // get the MetaProperty list from the MetaClass
205
mps = metaClass.getProperties();
206         }
207
208         for (Iterator itr = mps.iterator(); itr.hasNext();) {
209             MetaProperty mp = (MetaProperty) itr.next();
210             PropertyValue pv = new PropertyValue(self, mp);
211             props.add(pv);
212         }
213
214         return props;
215     }
216
217     /**
218      * Scoped use method
219      */

220     public static void use(Object JavaDoc self, Class JavaDoc categoryClass, Closure closure) {
221         GroovyCategorySupport.use(categoryClass, closure);
222     }
223
224     /**
225      * Scoped use method with list of categories
226      */

227     public static void use(Object JavaDoc self, List categoryClassList, Closure closure) {
228         GroovyCategorySupport.use(categoryClassList, closure);
229     }
230
231
232     /**
233      * Print to a console in interactive format
234      */

235     public static void print(Object JavaDoc self, Object JavaDoc value) {
236         System.out.print(InvokerHelper.toString(value));
237     }
238
239     /**
240      * Print a linebreak to the standard out.
241      */

242     public static void println(Object JavaDoc self) {
243         System.out.println();
244     }
245
246     /**
247      * Print to a console in interactive format along with a newline
248      */

249     public static void println(Object JavaDoc self, Object JavaDoc value) {
250         System.out.println(InvokerHelper.toString(value));
251     }
252
253     /**
254      * @return a String that matches what would be typed into a terminal to
255      * create this object. e.g. [1, 'hello'].inspect() -> [1, "hello"]
256      */

257     public static String JavaDoc inspect(Object JavaDoc self) {
258         return InvokerHelper.inspect(self);
259     }
260
261     /**
262      * Print to a console in interactive format
263      */

264     public static void print(Object JavaDoc self, PrintWriter out) {
265         if (out == null) {
266             out = new PrintWriter(System.out);
267         }
268         out.print(InvokerHelper.toString(self));
269     }
270
271     /**
272      * Print to a console in interactive format
273      *
274      * @param out the PrintWriter used for printing
275      */

276     public static void println(Object JavaDoc self, PrintWriter out) {
277         if (out == null) {
278             out = new PrintWriter(System.out);
279         }
280         InvokerHelper.invokeMethod(self, "print", out);
281         out.println();
282     }
283
284     /**
285      * Provide a dynamic method invocation method which can be overloaded in
286      * classes to implement dynamic proxies easily.
287      */

288     public static Object JavaDoc invokeMethod(Object JavaDoc object, String JavaDoc method, Object JavaDoc arguments) {
289         return InvokerHelper.invokeMethod(object, method, arguments);
290     }
291
292     // isCase methods
293
//-------------------------------------------------------------------------
294
public static boolean isCase(Object JavaDoc caseValue, Object JavaDoc switchValue) {
295         return caseValue.equals(switchValue);
296     }
297
298     public static boolean isCase(String JavaDoc caseValue, Object JavaDoc switchValue) {
299         if (switchValue == null) {
300             return caseValue == null;
301         }
302         return caseValue.equals(switchValue.toString());
303     }
304
305     public static boolean isCase(Class JavaDoc caseValue, Object JavaDoc switchValue) {
306         return caseValue.isInstance(switchValue);
307     }
308
309     public static boolean isCase(Collection caseValue, Object JavaDoc switchValue) {
310         return caseValue.contains(switchValue);
311     }
312
313     public static boolean isCase(Pattern JavaDoc caseValue, Object JavaDoc switchValue) {
314         Matcher JavaDoc matcher = caseValue.matcher(switchValue.toString());
315         if (matcher.matches()) {
316             RegexSupport.setLastMatcher(matcher);
317             return true;
318         } else {
319             return false;
320         }
321     }
322
323     // Collection based methods
324
//-------------------------------------------------------------------------
325

326     /**
327      * Allows objects to be iterated through using a closure
328      *
329      * @param self the object over which we iterate
330      * @param closure the closure applied on each element found
331      */

332     public static void each(Object JavaDoc self, Closure closure) {
333         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
334             closure.call(iter.next());
335         }
336     }
337
338     /**
339      * Allows object to be iterated through a closure with a counter
340      *
341      * @param self an Object
342      * @param closure a Closure
343      */

344     public static void eachWithIndex(Object JavaDoc self, Closure closure) {
345         int counter = 0;
346         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
347             closure.call(new Object JavaDoc[]{iter.next(), new Integer JavaDoc(counter++)});
348         }
349     }
350
351     /**
352      * Allows objects to be iterated through using a closure
353      *
354      * @param self the collection over which we iterate
355      * @param closure the closure applied on each element of the collection
356      */

357     public static void each(Collection self, Closure closure) {
358         for (Iterator iter = self.iterator(); iter.hasNext();) {
359             closure.call(iter.next());
360         }
361     }
362
363     /**
364      * Allows a Map to be iterated through using a closure. If the
365      * closure takes one parameter then it will be passed the Map.Entry
366      * otherwise if the closure takes two parameters then it will be
367      * passed the key and the value.
368      *
369      * @param self the map over which we iterate
370      * @param closure the closure applied on each entry of the map
371      */

372     public static void each(Map self, Closure closure) {
373         if (closure.getParameterTypes().length == 2) {
374             for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
375                 Map.Entry entry = (Map.Entry) iter.next();
376                 closure.call(new Object JavaDoc[]{entry.getKey(), entry.getValue()});
377             }
378         } else {
379             for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
380                 closure.call(iter.next());
381             }
382         }
383     }
384
385     /**
386      * Iterates over every element of a collection, and check whether a predicate is valid for all elements.
387      *
388      * @param self the object over which we iterate
389      * @param closure the closure predicate used for matching
390      * @return true if every item in the collection matches the closure
391      * predicate
392      */

393     public static boolean every(Object JavaDoc self, Closure closure) {
394         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
395             if (!InvokerHelper.asBool(closure.call(iter.next()))) {
396                 return false;
397             }
398         }
399         return true;
400     }
401
402     /**
403      * Iterates over every element of a collection, and check whether a predicate is valid for at least one element
404      *
405      * @param self the object over which we iterate
406      * @param closure the closure predicate used for matching
407      * @return true if any item in the collection matches the closure predicate
408      */

409     public static boolean any(Object JavaDoc self, Closure closure) {
410         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
411             if (InvokerHelper.asBool(closure.call(iter.next()))) {
412                 return true;
413             }
414         }
415         return false;
416     }
417
418     /**
419      * Iterates over every element of the collection and return each object that matches
420      * the given filter - calling the isCase() method used by switch statements.
421      * This method can be used with different kinds of filters like regular expresions, classes, ranges etc.
422      *
423      * @param self the object over which we iterate
424      * @param filter the filter to perform on the collection (using the isCase(object) method)
425      * @return a list of objects which match the filter
426      */

427     public static List grep(Object JavaDoc self, Object JavaDoc filter) {
428         List answer = new ArrayList();
429         MetaClass metaClass = InvokerHelper.getMetaClass(filter);
430         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
431             Object JavaDoc object = iter.next();
432             if (InvokerHelper.asBool(metaClass.invokeMethod(filter, "isCase", object))) {
433                 answer.add(object);
434             }
435         }
436         return answer;
437     }
438
439     /**
440      * Counts the number of occurencies of the given value inside this collection
441      *
442      * @param self the collection within which we count the number of occurencies
443      * @param value the value
444      * @return the number of occurrencies
445      */

446     public static int count(Collection self, Object JavaDoc value) {
447         int answer = 0;
448         for (Iterator iter = self.iterator(); iter.hasNext();) {
449             if (InvokerHelper.compareEqual(iter.next(), value)) {
450                 ++answer;
451             }
452         }
453         return answer;
454     }
455
456     /**
457      * Convert a collection to a List.
458      *
459      * @param self a collection
460      * @return a List
461      */

462     public static List toList(Collection self) {
463         List answer = new ArrayList(self.size());
464         answer.addAll(self);
465         return answer;
466     }
467
468     /**
469      * Iterates through this object transforming each object into a new value using the closure
470      * as a transformer, returning a list of transformed values.
471      *
472      * @param self the values of the object to map
473      * @param closure the closure used to map each element of the collection
474      * @return a List of the mapped values
475      */

476     public static List collect(Object JavaDoc self, Closure closure) {
477         return (List) collect(self, new ArrayList(), closure);
478     }
479
480     /**
481      * Iterates through this object transforming each object into a new value using the closure
482      * as a transformer and adding it to the collection, returning the resulting collection.
483      *
484      * @param self the values of the object to map
485      * @param collection the Collection to which the mapped values are added
486      * @param closure the closure used to map each element of the collection
487      * @return the resultant collection
488      */

489     public static Collection collect(Object JavaDoc self, Collection collection, Closure closure) {
490         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
491             collection.add(closure.call(iter.next()));
492         }
493         return collection;
494     }
495
496     /**
497      * Iterates through this collection transforming each entry into a new value using the closure
498      * as a transformer, returning a list of transformed values.
499      *
500      * @param self a collection
501      * @param closure the closure used for mapping
502      * @return a List of the mapped values
503      */

504     public static List collect(Collection self, Closure closure) {
505         return (List) collect(self, new ArrayList(self.size()), closure);
506     }
507
508     /**
509      * Iterates through this collection transforming each entry into a new value using the closure
510      * as a transformer, returning a list of transformed values.
511      *
512      * @param self a collection
513      * @param collection the Collection to which the mapped values are added
514      * @param closure the closure used to map each element of the collection
515      * @return the resultant collection
516      */

517     public static Collection collect(Collection self, Collection collection, Closure closure) {
518         for (Iterator iter = self.iterator(); iter.hasNext();) {
519             collection.add(closure.call(iter.next()));
520             if (closure.getDirective() == Closure.DONE) {
521                 break;
522             }
523         }
524         return collection;
525     }
526
527     /**
528      * Iterates through this Map transforming each entry into a new value using the closure
529      * as a transformer, returning a list of transformed values.
530      *
531      * @param self a Map
532      * @param closure the closure used for mapping
533      * @return a List of the mapped values
534      */

535     public static Collection collect(Map self, Collection collection, Closure closure) {
536         for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
537             collection.add(closure.call(iter.next()));
538         }
539         return collection;
540     }
541
542     /**
543      * Iterates through this Map transforming each entry into a new value using the closure
544      * as a transformer, returning a list of transformed values.
545      *
546      * @param self a Map
547      * @param collection the Collection to which the mapped values are added
548      * @param closure the closure used to map each element of the collection
549      * @return the resultant collection
550      */

551     public static List collect(Map self, Closure closure) {
552         return (List) collect(self, new ArrayList(self.size()), closure);
553     }
554
555     /**
556      * Finds the first value matching the closure condition
557      *
558      * @param self an Object with an iterator returning its values
559      * @param closure a closure condition
560      * @return the first Object found
561      */

562     public static Object JavaDoc find(Object JavaDoc self, Closure closure) {
563         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
564             Object JavaDoc value = iter.next();
565             if (InvokerHelper.asBool(closure.call(value))) {
566                 return value;
567             }
568         }
569         return null;
570     }
571
572     /**
573      * Finds the first value matching the closure condition
574      *
575      * @param self a Collection
576      * @param closure a closure condition
577      * @return the first Object found
578      */

579     public static Object JavaDoc find(Collection self, Closure closure) {
580         for (Iterator iter = self.iterator(); iter.hasNext();) {
581             Object JavaDoc value = iter.next();
582             if (InvokerHelper.asBool(closure.call(value))) {
583                 return value;
584             }
585         }
586         return null;
587     }
588
589     /**
590      * Finds the first value matching the closure condition
591      *
592      * @param self a Map
593      * @param closure a closure condition
594      * @return the first Object found
595      */

596     public static Object JavaDoc find(Map self, Closure closure) {
597         for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
598             Object JavaDoc value = iter.next();
599             if (InvokerHelper.asBool(closure.call(value))) {
600                 return value;
601             }
602         }
603         return null;
604     }
605
606     /**
607      * Finds all values matching the closure condition
608      *
609      * @param self an Object with an Iterator returning its values
610      * @param closure a closure condition
611      * @return a List of the values found
612      */

613     public static List findAll(Object JavaDoc self, Closure closure) {
614         List answer = new ArrayList();
615         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
616             Object JavaDoc value = iter.next();
617             if (InvokerHelper.asBool(closure.call(value))) {
618                 answer.add(value);
619             }
620         }
621         return answer;
622     }
623
624     /**
625      * Finds all values matching the closure condition
626      *
627      * @param self a Collection
628      * @param closure a closure condition
629      * @return a List of the values found
630      */

631     public static List findAll(Collection self, Closure closure) {
632         List answer = new ArrayList(self.size());
633         for (Iterator iter = self.iterator(); iter.hasNext();) {
634             Object JavaDoc value = iter.next();
635             if (InvokerHelper.asBool(closure.call(value))) {
636                 answer.add(value);
637             }
638         }
639         return answer;
640     }
641
642     /**
643      * Finds all values matching the closure condition
644      *
645      * @param self a Map
646      * @param closure a closure condition applying on the keys
647      * @return a List of keys
648      */

649     public static List findAll(Map self, Closure closure) {
650         List answer = new ArrayList(self.size());
651         for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
652             Object JavaDoc value = iter.next();
653             if (InvokerHelper.asBool(closure.call(value))) {
654                 answer.add(value);
655             }
656         }
657         return answer;
658     }
659
660     /**
661      * Iterates through the given collection, passing in the initial value to
662      * the closure along with the current iterated item then passing into the
663      * next iteration the value of the previous closure.
664      *
665      * @param self a Collection
666      * @param value a value
667      * @param closure a closure
668      * @return the last value of the last iteration
669      */

670     public static Object JavaDoc inject(Collection self, Object JavaDoc value, Closure closure) {
671         Object JavaDoc[] params = new Object JavaDoc[2];
672         for (Iterator iter = self.iterator(); iter.hasNext();) {
673             Object JavaDoc item = iter.next();
674             params[0] = value;
675             params[1] = item;
676             value = closure.call(params);
677         }
678         return value;
679     }
680
681     /**
682      * Concatenates all of the items of the collection together with the given String as a separator
683      *
684      * @param self a Collection of objects
685      * @param separator a String separator
686      * @return the joined String
687      */

688     public static String JavaDoc join(Collection self, String JavaDoc separator) {
689         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
690         boolean first = true;
691         for (Iterator iter = self.iterator(); iter.hasNext();) {
692             Object JavaDoc value = iter.next();
693             if (first) {
694                 first = false;
695             } else {
696                 buffer.append(separator);
697             }
698             buffer.append(InvokerHelper.toString(value));
699         }
700         return buffer.toString();
701     }
702
703     /**
704      * Concatenates all of the elements of the array together with the given String as a separator
705      *
706      * @param self an array of Object
707      * @param separator a String separator
708      * @return the joined String
709      */

710     public static String JavaDoc join(Object JavaDoc[] self, String JavaDoc separator) {
711         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
712         boolean first = true;
713         for (int i = 0; i < self.length; i++) {
714             String JavaDoc value = InvokerHelper.toString(self[i]);
715             if (first) {
716                 first = false;
717             } else {
718                 buffer.append(separator);
719             }
720             buffer.append(value);
721         }
722         return buffer.toString();
723     }
724
725     /**
726      * Selects the maximum value found in the collection
727      *
728      * @param self a Collection
729      * @return the maximum value
730      */

731     public static Object JavaDoc max(Collection self) {
732         Object JavaDoc answer = null;
733         for (Iterator iter = self.iterator(); iter.hasNext();) {
734             Object JavaDoc value = iter.next();
735             if (value != null) {
736                 if (answer == null || InvokerHelper.compareGreaterThan(value, answer)) {
737                     answer = value;
738                 }
739             }
740         }
741         return answer;
742     }
743
744     /**
745      * Selects the maximum value found in the collection using the given comparator
746      *
747      * @param self a Collection
748      * @param comparator a Comparator
749      * @return the maximum value
750      */

751     public static Object JavaDoc max(Collection self, Comparator comparator) {
752         Object JavaDoc answer = null;
753         for (Iterator iter = self.iterator(); iter.hasNext();) {
754             Object JavaDoc value = iter.next();
755             if (answer == null || comparator.compare(value, answer) > 0) {
756                 answer = value;
757             }
758         }
759         return answer;
760     }
761
762     /**
763      * Selects the minimum value found in the collection
764      *
765      * @param self a Collection
766      * @return the minimum value
767      */

768     public static Object JavaDoc min(Collection self) {
769         Object JavaDoc answer = null;
770         for (Iterator iter = self.iterator(); iter.hasNext();) {
771             Object JavaDoc value = iter.next();
772             if (value != null) {
773                 if (answer == null || InvokerHelper.compareLessThan(value, answer)) {
774                     answer = value;
775                 }
776             }
777         }
778         return answer;
779     }
780
781     /**
782      * Selects the minimum value found in the collection using the given comparator
783      *
784      * @param self a Collection
785      * @param comparator a Comparator
786      * @return the minimum value
787      */

788     public static Object JavaDoc min(Collection self, Comparator comparator) {
789         Object JavaDoc answer = null;
790         for (Iterator iter = self.iterator(); iter.hasNext();) {
791             Object JavaDoc value = iter.next();
792             if (answer == null || comparator.compare(value, answer) < 0) {
793                 answer = value;
794
795             }
796         }
797         return answer;
798     }
799
800     /**
801      * Selects the minimum value found in the collection using the given closure as a comparator
802      *
803      * @param self a Collection
804      * @param closure a closure used as a comparator
805      * @return the minimum value
806      */

807     public static Object JavaDoc min(Collection self, Closure closure) {
808         return min(self, new ClosureComparator(closure));
809     }
810
811     /**
812      * Selects the maximum value found in the collection using the given closure as a comparator
813      *
814      * @param self a Collection
815      * @param closure a closure used as a comparator
816      * @return the maximum value
817      */

818     public static Object JavaDoc max(Collection self, Closure closure) {
819         return max(self, new ClosureComparator(closure));
820     }
821
822     /**
823      * Makes a String look like a Collection by adding support for the size() method
824      *
825      * @param text a String
826      * @return the length of the String
827      */

828     public static int size(String JavaDoc text) {
829         return text.length();
830     }
831
832     /**
833      * Makes an Array look like a Collection by adding support for the size() method
834      *
835      * @param self an Array of Object
836      * @return the size of the Array
837      */

838     public static int size(Object JavaDoc[] self) {
839         return self.length;
840     }
841
842     /**
843      * Support the subscript operator for String.
844      *
845      * @param text a String
846      * @param index the index of the Character to get
847      * @return the Character at the given index
848      */

849     public static CharSequence JavaDoc getAt(CharSequence JavaDoc text, int index) {
850         index = normaliseIndex(index, text.length());
851         return text.subSequence(index, index + 1);
852     }
853
854     /**
855      * Support the subscript operator for String
856      *
857      * @param text a String
858      * @return the Character object at the given index
859      */

860     public static String JavaDoc getAt(String JavaDoc text, int index) {
861         index = normaliseIndex(index, text.length());
862         return text.substring(index, index + 1);
863     }
864
865     /**
866      * Support the range subscript operator for CharSequence
867      *
868      * @param text a CharSequence
869      * @param range a Range
870      * @return the subsequence CharSequence
871      */

872     public static Char