Source Code Cross Referenced for DefaultGroovyMethods.java in  » Scripting » groovy-1.0 » org » codehaus » groovy » runtime » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » groovy 1.0 » org.codehaus.groovy.runtime 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Id: DefaultGroovyMethods.java 4598 2006-12-22 20:21:21Z blackdrag $
0003:         *
0004:         * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
0005:         *
0006:         * Redistribution and use of this software and associated documentation
0007:         * ("Software"), with or without modification, are permitted provided that the
0008:         * following conditions are met:
0009:         *  1. Redistributions of source code must retain copyright statements and
0010:         * notices. Redistributions must also contain a copy of this document.
0011:         *  2. Redistributions in binary form must reproduce the above copyright
0012:         * notice, this list of conditions and the following disclaimer in the
0013:         * documentation and/or other materials provided with the distribution.
0014:         *  3. The name "groovy" must not be used to endorse or promote products
0015:         * derived from this Software without prior written permission of The Codehaus.
0016:         * For written permission, please contact info@codehaus.org.
0017:         *  4. Products derived from this Software may not be called "groovy" nor may
0018:         * "groovy" appear in their names without prior written permission of The
0019:         * Codehaus. "groovy" is a registered trademark of The Codehaus.
0020:         *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
0021:         *
0022:         * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
0023:         * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0024:         * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0025:         * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
0026:         * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0027:         * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
0028:         * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
0029:         * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0030:         * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0031:         * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
0032:         * DAMAGE.
0033:         *
0034:         */
0035:        package org.codehaus.groovy.runtime;
0036:
0037:        import groovy.lang.*;
0038:        import groovy.util.CharsetToolkit;
0039:        import groovy.util.ClosureComparator;
0040:        import groovy.util.OrderBy;
0041:
0042:        import java.io.*;
0043:        import java.lang.reflect.Array;
0044:        import java.lang.reflect.Field;
0045:        import java.lang.reflect.Modifier;
0046:        import java.lang.reflect.Proxy;
0047:        import java.math.BigDecimal;
0048:        import java.math.BigInteger;
0049:        import java.net.MalformedURLException;
0050:        import java.net.ServerSocket;
0051:        import java.net.Socket;
0052:        import java.net.URI;
0053:        import java.net.URISyntaxException;
0054:        import java.net.URL;
0055:        import java.security.AccessController;
0056:        import java.security.PrivilegedAction;
0057:        import java.util.*;
0058:        import java.util.logging.Logger;
0059:        import java.util.regex.Matcher;
0060:        import java.util.regex.Pattern;
0061:
0062:        import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
0063:        import org.codehaus.groovy.runtime.typehandling.NumberMath;
0064:        import org.codehaus.groovy.tools.RootLoader;
0065:        import org.w3c.dom.NodeList;
0066:
0067:        /**
0068:         * This class defines all the new groovy methods which appear on normal JDK
0069:         * classes inside the Groovy environment. Static methods are used with the
0070:         * first parameter the destination class.
0071:         *
0072:         * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
0073:         * @author Jeremy Rayner
0074:         * @author Sam Pullara
0075:         * @author Rod Cope
0076:         * @author Guillaume Laforge
0077:         * @author John Wilson
0078:         * @author Hein Meling
0079:         * @author Dierk Koenig
0080:         * @author Pilho Kim
0081:         * @author Marc Guillemot
0082:         * @author Russel Winder
0083:         * @author bing ran
0084:         * @author Jochen Theodorou
0085:         * @version $Revision: 4598 $
0086:         */
0087:        public class DefaultGroovyMethods {
0088:
0089:            private static final Logger LOG = Logger
0090:                    .getLogger(DefaultGroovyMethods.class.getName());
0091:            private static final Integer ONE = new Integer(1);
0092:
0093:            /**
0094:             * Identity check. Since == is overridden in Groovy with the meaning of equality
0095:             * we need some fallback to check for object identity.
0096:             *
0097:             * @param self
0098:             * @param other
0099:             * @return true if self and other are identical, false otherwise
0100:             */
0101:            public static boolean is(Object self, Object other) {
0102:                return self == other;
0103:            }
0104:
0105:            /**
0106:             * Allows the closure to be called for the object reference self
0107:             *
0108:             * @param self    the object to have a closure act upon
0109:             * @param closure the closure to call on the object
0110:             * @return result of calling the closure
0111:             */
0112:            public static Object identity(Object self, Closure closure) {
0113:                final Closure clonedClosure = (Closure) closure.clone();
0114:                clonedClosure.setDelegate(self);
0115:                return clonedClosure.call(self);
0116:            }
0117:
0118:            /**
0119:             * Allows the subscript operator to be used to lookup dynamic property values.
0120:             * <code>bean[somePropertyNameExpression]</code>. The normal property notation
0121:             * of groovy is neater and more concise but only works with compile-time known
0122:             * property names.
0123:             *
0124:             * @param self the object to act upon
0125:             */
0126:            public static Object getAt(Object self, String property) {
0127:                return InvokerHelper.getProperty(self, property);
0128:            }
0129:
0130:            /**
0131:             * Allows the subscript operator to be used to set dynamically named property values.
0132:             * <code>bean[somePropertyNameExpression] = foo</code>. The normal property notation
0133:             * of groovy is neater and more concise but only works with property names which
0134:             * are known at compile time.
0135:             *
0136:             * @param self     the object to act upon
0137:             * @param property the name of the property to set
0138:             * @param newValue the value to set
0139:             */
0140:            public static void putAt(Object self, String property,
0141:                    Object newValue) {
0142:                InvokerHelper.setProperty(self, property, newValue);
0143:            }
0144:
0145:            /**
0146:             * Generates a detailed dump string of an object showing its class,
0147:             * hashCode and fields
0148:             */
0149:            public static String dump(Object self) {
0150:                if (self == null) {
0151:                    return "null";
0152:                }
0153:                StringBuffer buffer = new StringBuffer("<");
0154:                Class klass = self.getClass();
0155:                buffer.append(klass.getName());
0156:                buffer.append("@");
0157:                buffer.append(Integer.toHexString(self.hashCode()));
0158:                boolean groovyObject = self instanceof  GroovyObject;
0159:
0160:                /*jes this may be rewritten to use the new getProperties() stuff
0161:                 * but the original pulls out private variables, whereas getProperties()
0162:                 * does not. What's the real use of dump() here?
0163:                 */
0164:                while (klass != null) {
0165:                    Field[] fields = klass.getDeclaredFields();
0166:                    for (int i = 0; i < fields.length; i++) {
0167:                        final Field field = fields[i];
0168:                        if ((field.getModifiers() & Modifier.STATIC) == 0) {
0169:                            if (groovyObject
0170:                                    && field.getName().equals("metaClass")) {
0171:                                continue;
0172:                            }
0173:                            AccessController
0174:                                    .doPrivileged(new PrivilegedAction() {
0175:                                        public Object run() {
0176:                                            field.setAccessible(true);
0177:                                            return null;
0178:                                        }
0179:                                    });
0180:                            buffer.append(" ");
0181:                            buffer.append(field.getName());
0182:                            buffer.append("=");
0183:                            try {
0184:                                buffer.append(InvokerHelper.toString(field
0185:                                        .get(self)));
0186:                            } catch (Exception e) {
0187:                                buffer.append(e);
0188:                            }
0189:                        }
0190:                    }
0191:
0192:                    klass = klass.getSuperclass();
0193:                }
0194:
0195:                /* here is a different implementation that uses getProperties(). I have left
0196:                 * it commented out because it returns a slightly different list of properties;
0197:                 * ie it does not return privates. I don't know what dump() really should be doing,
0198:                 * although IMO showing private fields is a no-no
0199:                 */
0200:                /*
0201:                List props = getProperties(self);
0202:                    for(Iterator itr = props.keySet().iterator(); itr.hasNext(); ) {
0203:                    String propName = itr.next().toString();
0204:
0205:                    // the original skipped this, so I will too
0206:                    if(pv.getName().equals("metaClass")) continue;
0207:                    if(pv.getName().equals("class")) continue;
0208:
0209:                    buffer.append(" ");
0210:                    buffer.append(propName);
0211:                    buffer.append("=");
0212:                    try {
0213:                        buffer.append(InvokerHelper.toString(props.get(propName)));
0214:                    }
0215:                    catch (Exception e) {
0216:                        buffer.append(e);
0217:                    }
0218:                }
0219:                 */
0220:
0221:                buffer.append(">");
0222:                return buffer.toString();
0223:            }
0224:
0225:            /**
0226:             * Retrieves the list of {@link MetaProperty} objects for 'self' and wraps it
0227:             * in a list of {@link PropertyValue} objects that additionally provide
0228:             * the value for each property of 'self'.
0229:             *
0230:             * @param self the receiver object
0231:             * @return list of {@link PropertyValue} objects
0232:             * @see groovy.util.Expando#getMetaPropertyValues()
0233:             */
0234:            public static List getMetaPropertyValues(Object self) {
0235:                MetaClass metaClass = InvokerHelper.getMetaClass(self);
0236:                List mps = metaClass.getProperties();
0237:                List props = new ArrayList(mps.size());
0238:                for (Iterator itr = mps.iterator(); itr.hasNext();) {
0239:                    MetaProperty mp = (MetaProperty) itr.next();
0240:                    PropertyValue pv = new PropertyValue(self, mp);
0241:                    props.add(pv);
0242:                }
0243:                return props;
0244:            }
0245:
0246:            /**
0247:             * Convenience method that calls {@link #getMetaPropertyValues(Object)}(self)
0248:             * and provides the data in form of simple key/value pairs, i.e. without
0249:             * type() information.
0250:             *
0251:             * @param self the receiver object
0252:             * @return meta properties as Map of key/value pairs
0253:             */
0254:            public static Map getProperties(Object self) {
0255:                List metaProps = getMetaPropertyValues(self);
0256:                Map props = new HashMap(metaProps.size());
0257:
0258:                for (Iterator itr = metaProps.iterator(); itr.hasNext();) {
0259:                    PropertyValue pv = (PropertyValue) itr.next();
0260:                    try {
0261:                        props.put(pv.getName(), pv.getValue());
0262:                    } catch (Exception e) {
0263:                        LOG.throwing(self.getClass().getName(), "getProperty("
0264:                                + pv.getName() + ")", e);
0265:                    }
0266:                }
0267:                return props;
0268:            }
0269:
0270:            /**
0271:             * Scoped use method
0272:             */
0273:            public static void use(Object self, Class categoryClass,
0274:                    Closure closure) {
0275:                GroovyCategorySupport.use(categoryClass, closure);
0276:            }
0277:
0278:            /**
0279:             * Scoped use method with list of categories
0280:             */
0281:            public static void use(Object self, List categoryClassList,
0282:                    Closure closure) {
0283:                GroovyCategorySupport.use(categoryClassList, closure);
0284:            }
0285:
0286:            /**
0287:             * use() a list of categories, specifying the list as varargs:<br>
0288:             * use(CategoryClass1, CategoryClass2) { ... }<br>
0289:             * This method prevents the error of forgetting to wrap the the category
0290:             * classes in a list.
0291:             *
0292:             * @param self
0293:             * @param array
0294:             */
0295:            public static void use(Object self, Object[] array) {
0296:                if (array.length < 2)
0297:                    throw new IllegalArgumentException(
0298:                            "Expecting at least 2 arguments, a category class and a Closure");
0299:                Closure closure;
0300:                try {
0301:                    closure = (Closure) array[array.length - 1];
0302:                } catch (ClassCastException e) {
0303:                    throw new IllegalArgumentException(
0304:                            "Expecting a Closure to be the last argument");
0305:                }
0306:                List list = new ArrayList(array.length - 1);
0307:                for (int i = 0; i < array.length - 1; ++i)
0308:                    list.add(array[i]);
0309:                GroovyCategorySupport.use(list, closure);
0310:            }
0311:
0312:            /**
0313:             * Print to a console in interactive format
0314:             */
0315:            public static void print(Object self, Object value) {
0316:                System.out.print(InvokerHelper.toString(value));
0317:            }
0318:
0319:            /**
0320:             * Print a linebreak to the standard out.
0321:             */
0322:            public static void println(Object self) {
0323:                System.out.println();
0324:            }
0325:
0326:            /**
0327:             * Print to a console in interactive format along with a newline
0328:             */
0329:            public static void println(Object self, Object value) {
0330:                System.out.println(InvokerHelper.toString(value));
0331:            }
0332:
0333:            /**
0334:             * Printf to a console.  Only works with JDK1.5 or later.
0335:             */
0336:            public static void printf(Object self, String format,
0337:                    Object[] values) {
0338:                if (System.getProperty("java.version").charAt(2) == '5') {
0339:                    //
0340:                    //  Cannot just do:
0341:                    //
0342:                    //        System.out.printf(format, values) ;
0343:                    //
0344:                    //  because this fails to compile on JDK1.4.x and earlier.  So until the entire world is using
0345:                    //  JDK1.5 or later then we have to do things by reflection so as to hide the use of printf
0346:                    //  from the compiler.  In JDK1.5 you might try:
0347:                    //
0348:                    //        System.out.getClass().getMethod("printf", String.class, Object[].class).invoke(System.out, format, values) ;
0349:                    //
0350:                    //  but of course this doesn't work on JDK1.4 as it relies on varargs.  argh.  So we are
0351:                    //  forced into:
0352:                    //
0353:                    try {
0354:                        System.out.getClass().getMethod("printf",
0355:                                new Class[] { String.class, Object[].class })
0356:                                .invoke(System.out,
0357:                                        new Object[] { format, values });
0358:                    } catch (NoSuchMethodException nsme) {
0359:                        throw new RuntimeException(
0360:                                "getMethod threw a NoSuchMethodException.  This is impossible.");
0361:                    } catch (IllegalAccessException iae) {
0362:                        throw new RuntimeException(
0363:                                "invoke threw a IllegalAccessException.  This is impossible.");
0364:                    } catch (java.lang.reflect.InvocationTargetException ite) {
0365:                        throw new RuntimeException(
0366:                                "invoke threw a InvocationTargetException.  This is impossible.");
0367:                    }
0368:                } else {
0369:                    throw new RuntimeException(
0370:                            "printf requires JDK1.5 or later.");
0371:                }
0372:            }
0373:
0374:            /**
0375:             * Returns a formatted string using the specified format string and
0376:             * arguments.
0377:             * <p/>
0378:             * <p/>
0379:             * For examples, <pre>
0380:             *     printf ( "Hello, %s!\n" , [ "world" ] as String[] )
0381:             *     printf ( "Hello, %s!\n" , [ "Groovy" ])
0382:             *     printf ( "%d + %d = %d\n" , [ 1 , 2 , 1+2 ] as Integer[] )
0383:             *     printf ( "%d + %d = %d\n" , [ 3 , 3 , 3+3 ])
0384:             * <p/>
0385:             *     ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as Integer[] ) }
0386:             *     ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as int[] ) }
0387:             *     ( 0x41..0x45 ).each { printf ( "-- %c\n" , [ it ] as char[] ) }
0388:             *     ( 07..011 ).each { printf ( "-- %d\n" , [ it ] as byte[] ) }
0389:             *     ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as short[] ) }
0390:             *     ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as long[] ) }
0391:             *     ( 7..11 ).each { printf ( "-- %5.2f\n" , [ it ] as float[] ) }
0392:             *     ( 7..11 ).each { printf ( "-- %5.2g\n" , [ it ] as double[] ) }
0393:             * </pre>
0394:             * <p/>
0395:             *
0396:             * @param format A format string
0397:             * @param arg    Argument which is referenced by the format specifiers in the format
0398:             *               string.  The type of <code>arg</code> should be one of Object[], List,
0399:             *               int[], short[], byte[], char[], boolean[], long[], float[], or double[].
0400:             * @since JDK 1.5
0401:             */
0402:            public static void printf(Object self, String format, Object arg) {
0403:                if (arg instanceof  Object[]) {
0404:                    printf(self, format, (Object[]) arg);
0405:                    return;
0406:                } else if (arg instanceof  List) {
0407:                    printf(self, format, ((List) arg).toArray());
0408:                    return;
0409:                } else if (!arg.getClass().isArray()) {
0410:                    Object[] o = (Object[]) java.lang.reflect.Array
0411:                            .newInstance(arg.getClass(), 1);
0412:                    o[0] = arg;
0413:                    printf(self, format, o);
0414:                    return;
0415:                }
0416:
0417:                Object[] ans = null;
0418:                String elemType = arg.getClass().getName();
0419:                if (elemType.equals("[I")) {
0420:                    int[] ia = (int[]) arg;
0421:                    ans = new Integer[ia.length];
0422:                    for (int i = 0; i < ia.length; i++) {
0423:                        ans[i] = new Integer(ia[i]);
0424:                    }
0425:                } else if (elemType.equals("[C")) {
0426:                    char[] ia = (char[]) arg;
0427:                    ans = new Character[ia.length];
0428:                    for (int i = 0; i < ia.length; i++) {
0429:                        ans[i] = new Character(ia[i]);
0430:                    }
0431:                } else if (elemType.equals("[Z")) {
0432:                    boolean[] ia = (boolean[]) arg;
0433:                    ans = new Boolean[ia.length];
0434:                    for (int i = 0; i < ia.length; i++) {
0435:                        ans[i] = new Boolean(ia[i]);
0436:                    }
0437:                } else if (elemType.equals("[B")) {
0438:                    byte[] ia = (byte[]) arg;
0439:                    ans = new Byte[ia.length];
0440:                    for (int i = 0; i < ia.length; i++) {
0441:                        ans[i] = new Byte(ia[i]);
0442:                    }
0443:                } else if (elemType.equals("[S")) {
0444:                    short[] ia = (short[]) arg;
0445:                    ans = new Short[ia.length];
0446:                    for (int i = 0; i < ia.length; i++) {
0447:                        ans[i] = new Short(ia[i]);
0448:                    }
0449:                } else if (elemType.equals("[F")) {
0450:                    float[] ia = (float[]) arg;
0451:                    ans = new Float[ia.length];
0452:                    for (int i = 0; i < ia.length; i++) {
0453:                        ans[i] = new Float(ia[i]);
0454:                    }
0455:                } else if (elemType.equals("[J")) {
0456:                    long[] ia = (long[]) arg;
0457:                    ans = new Long[ia.length];
0458:                    for (int i = 0; i < ia.length; i++) {
0459:                        ans[i] = new Long(ia[i]);
0460:                    }
0461:                } else if (elemType.equals("[D")) {
0462:                    double[] ia = (double[]) arg;
0463:                    ans = new Double[ia.length];
0464:                    for (int i = 0; i < ia.length; i++) {
0465:                        ans[i] = new Double(ia[i]);
0466:                    }
0467:                } else {
0468:                    throw new RuntimeException("printf(String," + arg + ")");
0469:                }
0470:                printf(self, format, (Object[]) ans);
0471:            }
0472:
0473:            /**
0474:             * @return a String that matches what would be typed into a terminal to
0475:             *         create this object. e.g. [1, 'hello'].inspect() -> [1, "hello"]
0476:             */
0477:            public static String inspect(Object self) {
0478:                return InvokerHelper.inspect(self);
0479:            }
0480:
0481:            /**
0482:             * Print to a console in interactive format
0483:             */
0484:            public static void print(Object self, PrintWriter out) {
0485:                if (out == null) {
0486:                    out = new PrintWriter(System.out);
0487:                }
0488:                out.print(InvokerHelper.toString(self));
0489:            }
0490:
0491:            /**
0492:             * Print to a console in interactive format
0493:             *
0494:             * @param out the PrintWriter used for printing
0495:             */
0496:            public static void println(Object self, PrintWriter out) {
0497:                if (out == null) {
0498:                    out = new PrintWriter(System.out);
0499:                }
0500:                InvokerHelper.invokeMethod(self, "print", out);
0501:                out.println();
0502:            }
0503:
0504:            /**
0505:             * Provide a dynamic method invocation method which can be overloaded in
0506:             * classes to implement dynamic proxies easily.
0507:             */
0508:            public static Object invokeMethod(Object object, String method,
0509:                    Object arguments) {
0510:                return InvokerHelper.invokeMethod(object, method, arguments);
0511:            }
0512:
0513:            // isCase methods
0514:            //-------------------------------------------------------------------------
0515:            public static boolean isCase(Object caseValue, Object switchValue) {
0516:                return caseValue.equals(switchValue);
0517:            }
0518:
0519:            public static boolean isCase(String caseValue, Object switchValue) {
0520:                if (switchValue == null) {
0521:                    return caseValue == null;
0522:                }
0523:                return caseValue.equals(switchValue.toString());
0524:            }
0525:
0526:            public static boolean isCase(Class caseValue, Object switchValue) {
0527:                if (switchValue instanceof  Class) {
0528:                    Class val = (Class) switchValue;
0529:                    return caseValue.isAssignableFrom(val);
0530:                }
0531:                return caseValue.isInstance(switchValue);
0532:            }
0533:
0534:            public static boolean isCase(Collection caseValue,
0535:                    Object switchValue) {
0536:                return caseValue.contains(switchValue);
0537:            }
0538:
0539:            public static boolean isCase(Pattern caseValue, Object switchValue) {
0540:                if (switchValue == null) {
0541:                    return caseValue == null;
0542:                }
0543:                final Matcher matcher = caseValue.matcher(switchValue
0544:                        .toString());
0545:                if (matcher.matches()) {
0546:                    RegexSupport.setLastMatcher(matcher);
0547:                    return true;
0548:                } else {
0549:                    return false;
0550:                }
0551:            }
0552:
0553:            // Collection based methods
0554:            //-------------------------------------------------------------------------
0555:
0556:            public static Collection unique(Collection self) {
0557:                if (self instanceof  Set)
0558:                    return self;
0559:                List answer = new ArrayList();
0560:                NumberComparator comparator = new NumberComparator();
0561:                for (Iterator it = self.iterator(); it.hasNext();) {
0562:                    Object o = it.next();
0563:                    boolean duplicated = false;
0564:                    for (Iterator it2 = answer.iterator(); it2.hasNext();) {
0565:                        Object o2 = it2.next();
0566:                        if (comparator.compare(o, o2) == 0) {
0567:                            duplicated = true;
0568:                            break;
0569:                        }
0570:                    }
0571:                    if (!duplicated)
0572:                        answer.add(o);
0573:                }
0574:                self.clear();
0575:                self.addAll(answer);
0576:                return self;
0577:            }
0578:
0579:            /**
0580:             * A convenience method for making a collection unique using a closure as a comparator
0581:             * (by Michael Baehr)
0582:             *
0583:             * @param self    a Collection
0584:             * @param closure a Closure used as a comparator
0585:             * @return self   without any duplicates
0586:             */
0587:            public static Collection unique(Collection self, Closure closure) {
0588:                if (self instanceof  Set)
0589:                    return self;
0590:                // use a comparator of one item or two
0591:                int params = closure.getMaximumNumberOfParameters();
0592:                if (params == 1) {
0593:                    unique(self, new OrderBy(closure));
0594:                } else {
0595:                    unique(self, new ClosureComparator(closure));
0596:                }
0597:                return self;
0598:            }
0599:
0600:            /**
0601:             * Remove all duplicates from a given Collection.
0602:             * Works on the receiver object and returns it.
0603:             * The order of members in the Collection are compared by the given Comparator.
0604:             * For each duplicate, the first member which is returned
0605:             * by the given Collection's iterator is retained, but all other ones are removed.
0606:             * The given Collection's original order is preserved.
0607:             * <p/>
0608:             * <code><pre>
0609:             *     class Person {
0610:             *         @Property fname, lname
0611:             *         public String toString() {
0612:             *             return fname + " " + lname
0613:             *         }
0614:             *     }
0615:             * <p/>
0616:             *     class PersonComparator implements Comparator {
0617:             *         public int compare(Object o1, Object o2) {
0618:             *             Person p1 = (Person) o1
0619:             *             Person p2 = (Person) o2
0620:             *             if (p1.lname != p2.lname)
0621:             *                 return p1.lname.compareTo(p2.lname)
0622:             *             else
0623:             *                 return p1.fname.compareTo(p2.fname)
0624:             *         }
0625:             * <p/>
0626:             *         public boolean equals(Object obj) {
0627:             *             return this.equals(obj)
0628:             *         }
0629:             *     }
0630:             * <p/>
0631:             *     Person a = new Person(fname:"John", lname:"Taylor")
0632:             *     Person b = new Person(fname:"Clark", lname:"Taylor")
0633:             *     Person c = new Person(fname:"Tom", lname:"Cruz")
0634:             *     Person d = new Person(fname:"Clark", lname:"Taylor")
0635:             * <p/>
0636:             *     def list = [a, b, c, d]
0637:             *     List list2 = list.unique(new PersonComparator())
0638:             *     assert( list2 == list && list == [a, b, c] )
0639:             * <p/>
0640:             * </pre></code>
0641:             *
0642:             * @param self       a Collection
0643:             * @param comparator a Comparator.
0644:             * @return self       without duplicates
0645:             */
0646:            public static Collection unique(Collection self,
0647:                    Comparator comparator) {
0648:                if (self instanceof  Set)
0649:                    return self;
0650:                List answer = new ArrayList();
0651:                for (Iterator it = self.iterator(); it.hasNext();) {
0652:                    Object o = it.next();
0653:                    boolean duplicated = false;
0654:                    for (Iterator it2 = answer.iterator(); it2.hasNext();) {
0655:                        Object o2 = it2.next();
0656:                        if (comparator.compare(o, o2) == 0) {
0657:                            duplicated = true;
0658:                            break;
0659:                        }
0660:                    }
0661:                    if (!duplicated)
0662:                        answer.add(o);
0663:                }
0664:                self.clear();
0665:                self.addAll(answer);
0666:                return self;
0667:            }
0668:
0669:            /**
0670:             * Allows objects to be iterated through using a closure
0671:             *
0672:             * @param self    the object over which we iterate
0673:             * @param closure the closure applied on each element found
0674:             */
0675:            public static void each(Object self, Closure closure) {
0676:                for (Iterator iter = InvokerHelper.asIterator(self); iter
0677:                        .hasNext();) {
0678:                    closure.call(iter.next());
0679:                }
0680:            }
0681:
0682:            /**
0683:             * Allows object to be iterated through a closure with a counter
0684:             *
0685:             * @param self    an Object
0686:             * @param closure a Closure
0687:             */
0688:            public static void eachWithIndex(Object self, Closure closure) {
0689:                int counter = 0;
0690:                for (Iterator iter = InvokerHelper.asIterator(self); iter
0691:                        .hasNext();) {
0692:                    closure.call(new Object[] { iter.next(),
0693:                            new Integer(counter++) });
0694:                }
0695:            }
0696:
0697:            /**
0698:             * Allows objects to be iterated through using a closure
0699:             *
0700:             * @param self    the collection over which we iterate
0701:             * @param closure the closure applied on each element of the collection
0702:             */
0703:            public static void each(Collection self, Closure closure) {
0704:                for (Iterator iter = self.iterator(); iter.hasNext();) {
0705:                    closure.call(iter.next());
0706:                }
0707:            }
0708:
0709:            /**
0710:             * Allows a Map to be iterated through using a closure. If the
0711:             * closure takes one parameter then it will be passed the Map.Entry
0712:             * otherwise if the closure takes two parameters then it will be
0713:             * passed the key and the value.
0714:             *
0715:             * @param self    the map over which we iterate
0716:             * @param closure the closure applied on each entry of the map
0717:             */
0718:            public static void each(Map self, Closure closure) {
0719:                for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
0720:                    Map.Entry entry = (Map.Entry) iter.next();
0721:                    callClosureForMapEntry(closure, entry);
0722:                }
0723:            }
0724:
0725:            /**
0726:             * Iterates over every element of a collection, and check whether a predicate is valid for all elements.
0727:             *
0728:             * @param self    the object over which we iterate
0729:             * @param closure the closure predicate used for matching
0730:             * @return true if every item in the collection matches the closure
0731:             *         predicate
0732:             */
0733:            public static boolean every(Object self, Closure closure) {
0734:                for (Iterator iter = InvokerHelper.asIterator(self); iter
0735:                        .hasNext();) {
0736:                    if (!DefaultTypeTransformation.castToBoolean(closure
0737:                            .call(iter.next()))) {
0738:                        return false;
0739:                    }
0740:                }
0741:                return true;
0742:            }
0743:
0744:            /**
0745:             * Iterates over every element of a collection, and check whether a predicate is valid for at least one element
0746:             *
0747:             * @param self    the object over which we iterate
0748:             * @param closure the closure predicate used for matching
0749:             * @return true if any item in the collection matches the closure predicate
0750:             */
0751:            public static boolean any(Object self, Closure closure) {
0752:                for (Iterator iter = InvokerHelper.asIterator(self); iter
0753:                        .hasNext();) {
0754:                    if (DefaultTypeTransformation.castToBoolean(closure
0755:                            .call(iter.next()))) {
0756:                        return true;
0757:                    }
0758:                }
0759:                return false;
0760:            }
0761:
0762:            /**
0763:             * Iterates over every element of the collection and return each object that matches
0764:             * the given filter - calling the isCase() method used by switch statements.
0765:             * This method can be used with different kinds of filters like regular expresions, classes, ranges etc.
0766:             *
0767:             * @param self   the object over which we iterate
0768:             * @param filter the filter to perform on the collection (using the isCase(object) method)
0769:             * @return a list of objects which match the filter
0770:             */
0771:            public static List grep(Object self, Object filter) {
0772:                List answer = new ArrayList();
0773:                MetaClass metaClass = InvokerHelper.getMetaClass(filter);
0774:                for (Iterator iter = InvokerHelper.asIterator(self); iter
0775:                        .hasNext();) {
0776:                    Object object = iter.next();
0777:                    if (DefaultTypeTransformation.castToBoolean(metaClass
0778:                            .invokeMethod(filter, "isCase", object))) {
0779:                        answer.add(object);
0780:                    }
0781:                }
0782:                return answer;
0783:            }
0784:
0785:            /**
0786:             * Counts the number of occurencies of the given value inside this collection
0787:             *
0788:             * @param self  the collection within which we count the number of occurencies
0789:             * @param value the value
0790:             * @return the number of occurrencies
0791:             */
0792:            public static int count(Collection self, Object value) {
0793:                int answer = 0;
0794:                for (Iterator iter = self.iterator(); iter.hasNext();) {
0795:                    if (DefaultTypeTransformation.compareEqual(iter.next(),
0796:                            value)) {
0797:                        ++answer;
0798:                    }
0799:                }
0800:                return answer;
0801:            }
0802:
0803:            /**
0804:             * Convert a collection to a List.
0805:             *
0806:             * @param self a collection
0807:             * @return a List
0808:             */
0809:            public static List toList(Collection self) {
0810:                List answer = new ArrayList(self.size());
0811:                answer.addAll(self);
0812:                return answer;
0813:            }
0814:
0815:            /**
0816:             * Iterates through this object transforming each object into a new value using the closure
0817:             * as a transformer, returning a list of transformed values.
0818:             *
0819:             * @param self    the values of the object to map
0820:             * @param closure the closure used to map each element of the collection
0821:             * @return a List of the mapped values
0822:             */
0823:            public static List collect(Object self, Closure closure) {
0824:                return (List) collect(self, new ArrayList(), closure);
0825:            }
0826:
0827:            /**
0828:             * Iterates through this object transforming each object into a new value using the closure
0829:             * as a transformer and adding it to the collection, returning the resulting collection.
0830:             *
0831:             * @param self       the values of the object to map
0832:             * @param collection the Collection to which the mapped values are added
0833:             * @param closure    the closure used to map each element of the collection
0834:             * @return the resultant collection
0835:             */
0836:            public static Collection collect(Object self,
0837:                    Collection collection, Closure closure) {
0838:                for (Iterator iter = InvokerHelper.asIterator(self); iter
0839:                        .hasNext();) {
0840:                    collection.add(closure.call(iter.next()));
0841:                }
0842:                return collection;
0843:            }
0844:
0845:            /**
0846:             * Iterates through this collection transforming each entry into a new value using the closure
0847:             * as a transformer, returning a list of transformed values.
0848:             *
0849:             * @param self    a collection
0850:             * @param closure the closure used for mapping
0851:             * @return a List of the mapped values
0852:             */
0853:            public static List collect(Collection self, Closure closure) {
0854:                return (List) collect(self, new ArrayList(self.size()), closure);
0855:            }
0856:
0857:            /**
0858:             * Iterates through this collection transforming each entry into a new value using the closure
0859:             * as a transformer, returning a list of transformed values.
0860:             *
0861:             * @param self       a collection
0862:             * @param collection the Collection to which the mapped values are added
0863:             * @param closure    the closure used to map each element of the collection
0864:             * @return the resultant collection
0865:             */
0866:            public static Collection collect(Collection self,
0867:                    Collection collection, Closure closure) {
0868:                for (Iterator iter = self.iterator(); iter.hasNext();) {
0869:                    collection.add(closure.call(iter.next()));
0870:                    if (closure.getDirective() == Closure.DONE) {
0871:                        break;
0872:                    }
0873:                }
0874:                return collection;
0875:            }
0876:
0877:            /**
0878:             * Iterates through this Map transforming each entry into a new value using the closure
0879:             * as a transformer, returning a list of transformed values.
0880:             *
0881:             * @param self       a Map
0882:             * @param collection the Collection to which the mapped values are added
0883:             * @param closure    the closure used for mapping, which can be with one(Map.Entry) or two(key, value) parameters
0884:             * @return a List of the mapped values
0885:             */
0886:            public static Collection collect(Map self, Collection collection,
0887:                    Closure closure) {
0888:                boolean isTwoParams = (closure.getParameterTypes().length == 2);
0889:                for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
0890:                    if (isTwoParams) {
0891:                        Map.Entry entry = (Map.Entry) iter.next();
0892:                        collection.add(closure.call(new Object[] {
0893:                                entry.getKey(), entry.getValue() }));
0894:                    } else {
0895:                        collection.add(closure.call(iter.next()));
0896:                    }
0897:                }
0898:                return collection;
0899:            }
0900:
0901:            /**
0902:             * Iterates through this Map transforming each entry into a new value using the closure
0903:             * as a transformer, returning a list of transformed values.
0904:             *
0905:             * @param self    a Map
0906:             * @param closure the closure used to map each element of the collection
0907:             * @return the resultant collection
0908:             */
0909:            public static List collect(Map self, Closure closure) {
0910:                return (List) collect(self, new ArrayList(self.size()), closure);
0911:            }
0912:
0913:            /**
0914:             * Finds the first value matching the closure condition
0915:             *
0916:             * @param self    an Object with an iterator returning its values
0917:             * @param closure a closure condition
0918:             * @return the first Object found
0919:             */
0920:            public static Object find(Object self, Closure closure) {
0921:                for (Iterator iter = InvokerHelper.asIterator(self); iter
0922:                        .hasNext();) {
0923:                    Object value = iter.next();
0924:                    if (DefaultTypeTransformation.castToBoolean(closure
0925:                            .call(value))) {
0926:                        return value;
0927:                    }
0928:                }
0929:                return null;
0930:            }
0931:
0932:            /**
0933:             * Finds the first value matching the closure condition
0934:             *
0935:             * @param self    a Collection
0936:             * @param closure a closure condition
0937:             * @return the first Object found
0938:             */
0939:            public static Object find(Collection self, Closure closure) {
0940:                for (Iterator iter = self.iterator(); iter.hasNext();) {
0941:                    Object value = iter.next();
0942:                    if (DefaultTypeTransformation.castToBoolean(closure
0943:                            .call(value))) {
0944:                        return value;
0945:                    }
0946:                }
0947:                return null;
0948:            }
0949:
0950:            /**
0951:             * Finds the first value matching the closure condition
0952:             *
0953:             * @param self    a Map
0954:             * @param closure a closure condition
0955:             * @return the first Object found
0956:             */
0957:            public static Object find(Map self, Closure closure) {
0958:                for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
0959:                    Object value = iter.next();
0960:                    if (DefaultTypeTransformation.castToBoolean(closure
0961:                            .call(value))) {
0962:                        return value;
0963:                    }
0964:                }
0965:                return null;
0966:            }
0967:
0968:            /**
0969:             * Finds all values matching the closure condition
0970:             *
0971:             * @param self    an Object with an Iterator returning its values
0972:             * @param closure a closure condition
0973:             * @return a List of the values found
0974:             */
0975:            public static List findAll(Object self, Closure closure) {
0976:                List answer = new ArrayList();
0977:                for (Iterator iter = InvokerHelper.asIterator(self); iter
0978:                        .hasNext();) {
0979:                    Object value = iter.next();
0980:                    if (DefaultTypeTransformation.castToBoolean(closure
0981:                            .call(value))) {
0982:                        answer.add(value);
0983:                    }
0984:                }
0985:                return answer;
0986:            }
0987:
0988:            /**
0989:             * Finds all values matching the closure condition
0990:             *
0991:             * @param self    a Collection
0992:             * @param closure a closure condition
0993:             * @return a List of the values found
0994:             */
0995:            public static List findAll(Collection self, Closure closure) {
0996:                List answer = new ArrayList(self.size());
0997:                for (Iterator iter = self.iterator(); iter.hasNext();) {
0998:                    Object value = iter.next();
0999:                    if (DefaultTypeTransformation.castToBoolean(closure
1000:                            .call(value))) {
1001:                        answer.add(value);
1002:                    }
1003:                }
1004:                return answer;
1005:            }
1006:
1007:            /**
1008:             * Finds all entries matching the closure condition. If the
1009:             * closure takes one parameter then it will be passed the Map.Entry
1010:             * otherwise if the closure takes two parameters then it will be
1011:             * passed the key and the value.
1012:             *
1013:             * @param self    a Map
1014:             * @param closure a closure condition applying on the entries
1015:             * @return a new subMap
1016:             */
1017:            public static Map findAll(Map self, Closure closure) {
1018:                Map answer = new HashMap(self.size());
1019:                for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
1020:                    Map.Entry entry = (Map.Entry) iter.next();
1021:                    if (DefaultTypeTransformation
1022:                            .castToBoolean(callClosureForMapEntry(closure,
1023:                                    entry))) {
1024:                        answer.put(entry.getKey(), entry.getValue());
1025:                    }
1026:                }
1027:                return answer;
1028:            }
1029:
1030:            /**
1031:             * Groups all collection members into groups determined by the
1032:             * supplied mapping closure.
1033:             *
1034:             * @param self    a collection to group (no map)
1035:             * @param closure a closure mapping entries on keys
1036:             * @return a new Map grouped by keys
1037:             */
1038:            public static Map groupBy(Collection self, Closure closure) {
1039:                Map answer = new HashMap();
1040:                for (Iterator iter = self.iterator(); iter.hasNext();) {
1041:                    groupCurrentElement(closure, answer, iter);
1042:                }
1043:                return answer;
1044:            }
1045:
1046:            /**
1047:             * Groups all map members into groups determined by the
1048:             * supplied mapping closure.
1049:             * 
1050:             * @param self     a map to group
1051:             * @param closure  a closure mapping entries on keys
1052:             * @return         a new Map grouped by keys
1053:             */
1054:            /* Removed for 1.0, to be discussed for 1.1
1055:            public static Map groupBy(Map self, Closure closure) {
1056:                final Map answer = new HashMap();
1057:                for (final Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
1058:                    groupCurrentElement(closure, answer, iter);
1059:                }
1060:                return answer;
1061:            }
1062:             */
1063:
1064:            /**
1065:             * Groups the current element of the iterator as determined
1066:             * by the mapping closure.
1067:             * 
1068:             * @param closure  a closure mapping the current entry on a key
1069:             * @param answer   the map containing the results
1070:             * @param iter     the iterator from which the current element stems
1071:             */
1072:            private static void groupCurrentElement(Closure closure,
1073:                    Map answer, Iterator iter) {
1074:                Object element = iter.next();
1075:                Object value = closure.call(element);
1076:                if (answer.containsKey(value)) {
1077:                    ((List) answer.get(value)).add(element);
1078:                } else {
1079:                    ArrayList groupedElements = new ArrayList();
1080:                    groupedElements.add(element);
1081:                    answer.put(value, groupedElements);
1082:                }
1083:            }
1084:
1085:            // internal helper method
1086:            protected static Object callClosureForMapEntry(Closure closure,
1087:                    Map.Entry entry) {
1088:                if (closure.getMaximumNumberOfParameters() == 2) {
1089:                    return closure.call(new Object[] { entry.getKey(),
1090:                            entry.getValue() });
1091:                }
1092:                return closure.call(entry);
1093:            }
1094:
1095:            /**
1096:             * Iterates through the given collection, passing in the initial value to
1097:             * the closure along with the current iterated item then passing into the
1098:             * next iteration the value of the previous closure.
1099:             *
1100:             * @param self    a Collection
1101:             * @param value   a value
1102:             * @param closure a closure
1103:             * @return the last value of the last iteration
1104:             */
1105:            public static Object inject(Collection self, Object value,
1106:                    Closure closure) {
1107:                Object[] params = new Object[2];
1108:                for (Iterator iter = self.iterator(); iter.hasNext();) {
1109:                    Object item = iter.next();
1110:                    params[0] = value;
1111:                    params[1] = item;
1112:                    value = closure.call(params);
1113:                }
1114:                return value;
1115:            }
1116:
1117:            /**
1118:             * Iterates through the given array of objects, passing in the initial value to
1119:             * the closure along with the current iterated item then passing into the
1120:             * next iteration the value of the previous closure.
1121:             *
1122:             * @param self    an Object[]
1123:             * @param value   a value
1124:             * @param closure a closure
1125:             * @return the last value of the last iteration
1126:             */
1127:            public static Object inject(Object[] self, Object value,
1128:                    Closure closure) {
1129:                Object[] params = new Object[2];
1130:                for (int i = 0; i < self.length; i++) {
1131:                    params[0] = value;
1132:                    params[1] = self[i];
1133:                    value = closure.call(params);
1134:                }
1135:                return value;
1136:            }
1137:
1138:            /**
1139:             * Sums a collection of numeric values. <code>coll.sum()</code> is equivalent to:
1140:             * <code>coll.inject(0) {value, item -> value + item}</code>.
1141:             *
1142:             * @param self Collection of values to add together.
1143:             * @return The sum of all of the list itmems.
1144:             */
1145:            public static Object sum(Collection self) {
1146:                Object result = null;
1147:
1148:                if (self.size() == 0)
1149:                    return result;
1150:
1151:                boolean isNumber = true;
1152:
1153:                Class classref = null;
1154:                try {
1155:                    classref = Class.forName("java.lang.Number");
1156:                } catch (Exception ex) {
1157:                }
1158:
1159:                for (Iterator iter = self.iterator(); iter.hasNext();) {
1160:                    if (!classref.isInstance(iter.next())) {
1161:                        isNumber = false;
1162:                        break;
1163:                    }
1164:                }
1165:
1166:                if (isNumber) {
1167:                    result = new Integer(0);
1168:                } else {
1169:                    result = new String();
1170:                }
1171:
1172:                Object[] param = new Object[1];
1173:                for (Iterator iter = self.iterator(); iter.hasNext();) {
1174:                    param[0] = iter.next();
1175:                    MetaClass metaClass = InvokerHelper.getMetaClass(result);
1176:                    result = metaClass.invokeMethod(result, "plus", param);
1177:                }
1178:                return result;
1179:            }
1180:
1181:            /**
1182:             * Sums the result of apply a closure to each item of a collection.
1183:             * <code>coll.sum(closure)</code> is equivalent to:
1184:             * <code>coll.collect(closure).sum()</code>.
1185:             *
1186:             * @param self    a Collection
1187:             * @param closure a single parameter closure that returns a numeric value.
1188:             * @return The sum of the values returned by applying the closure to each
1189:             *         item of the list.
1190:             */
1191:            public static Object sum(Collection self, Closure closure) {
1192:                Object result = new Integer(0);
1193:                Object[] closureParam = new Object[1];
1194:                Object[] plusParam = new Object[1];
1195:                for (Iterator iter = self.iterator(); iter.hasNext();) {
1196:                    closureParam[0] = iter.next();
1197:                    plusParam[0] = closure.call(closureParam);
1198:                    MetaClass metaClass = InvokerHelper.getMetaClass(result);
1199:                    result = metaClass.invokeMethod(result, "plus", plusParam);
1200:                }
1201:                return result;
1202:            }
1203:
1204:            /**
1205:             * Concatenates all of the items of the collection together with the given String as a separator
1206:             *
1207:             * @param self      a Collection of objects
1208:             * @param separator a String separator
1209:             * @return the joined String
1210:             */
1211:            public static String join(Collection self, String separator) {
1212:                StringBuffer buffer = new StringBuffer();
1213:                boolean first = true;
1214:
1215:                if (separator == null)
1216:                    separator = "";
1217:
1218:                for (Iterator iter = self.iterator(); iter.hasNext();) {
1219:                    Object value = iter.next();
1220:                    if (first) {
1221:                        first = false;
1222:                    } else {
1223:                        buffer.append(separator);
1224:                    }
1225:                    buffer.append(InvokerHelper.toString(value));
1226:                }
1227:                return buffer.toString();
1228:            }
1229:
1230:            /**
1231:             * Concatenates all of the elements of the array together with the given String as a separator
1232:             *
1233:             * @param self      an array of Object
1234:             * @param separator a String separator
1235:             * @return the joined String
1236:             */
1237:            public static String join(Object[] self, String separator) {
1238:                StringBuffer buffer = new StringBuffer();
1239:                boolean first = true;
1240:
1241:                if (separator == null)
1242:                    separator = "";
1243:
1244:                for (int i = 0; i < self.length; i++) {
1245:                    String value = InvokerHelper.toString(self[i]);
1246:                    if (first) {
1247:                        first = false;
1248:                    } else {
1249:                        buffer.append(separator);
1250:                    }
1251:                    buffer.append(value);
1252:                }
1253:                return buffer.toString();
1254:            }
1255:
1256:            /**
1257:             * Selects the maximum value found in the collection
1258:             *
1259:             * @param self a Collection
1260:             * @return the maximum value
1261:             */
1262:            public static Object max(Collection self) {
1263:                Object answer = null;
1264:                for (Iterator iter = self.iterator(); iter.hasNext();) {
1265:                    Object value = iter.next();
1266:                    if (value != null) {
1267:                        if (answer == null
1268:                                || ScriptBytecodeAdapter.compareGreaterThan(
1269:                                        value, answer)) {
1270:                            answer = value;
1271:                        }
1272:                    }
1273:                }
1274:                return answer;
1275:            }
1276:
1277:            /**
1278:             * Selects the maximum value found in the collection using the given comparator
1279:             *
1280:             * @param self       a Collection
1281:             * @param comparator a Comparator
1282:             * @return the maximum value
1283:             */
1284:            public static Object max(Collection self, Comparator comparator) {
1285:                Object answer = null;
1286:                for (Iterator iter = self.iterator(); iter.hasNext();) {
1287:                    Object value = iter.next();
1288:                    if (answer == null || comparator.compare(value, answer) > 0) {
1289:                        answer = value;
1290:                    }
1291:                }
1292:                return answer;
1293:            }
1294:
1295:            /**
1296:             * Selects the minimum value found in the collection
1297:             *
1298:             * @param self a Collection
1299:             * @return the minimum value
1300:             */
1301:            public static Object min(Collection self) {
1302:                Object answer = null;
1303:                for (Iterator iter = self.iterator(); iter.hasNext();) {
1304:                    Object value = iter.next();
1305:                    if (value != null) {
1306:                        if (answer == null
1307:                                || ScriptBytecodeAdapter.compareLessThan(value,
1308:                                        answer)) {
1309:                            answer = value;
1310:                        }
1311:                    }
1312:                }
1313:                return answer;
1314:            }
1315:
1316:            /**
1317:             * Selects the minimum value found in the collection using the given comparator
1318:             *
1319:             * @param self       a Collection
1320:             * @param comparator a Comparator
1321:             * @return the minimum value
1322:             */
1323:            public static Object min(Collection self, Comparator comparator) {
1324:                Object answer = null;
1325:                for (Iterator iter = self.iterator(); iter.hasNext();) {
1326:                    Object value = iter.next();
1327:                    if (answer == null || comparator.compare(value, answer) < 0) {
1328:                        answer = value;
1329:                    }
1330:                }
1331:                return answer;
1332:            }
1333:
1334:            /**
1335:             * Selects the minimum value found in the collection using the given closure as a comparator
1336:             *
1337:             * @param self    a Collection
1338:             * @param closure a closure used as a comparator
1339:             * @return the minimum value
1340:             */
1341:            public static Object min(Collection self, Closure closure) {
1342:                int params = closure.getMaximumNumberOfParameters();
1343:                if (params == 1) {
1344:                    Object answer = null;
1345:                    Object answer_value = null;
1346:                    for (Iterator iter = self.iterator(); iter.hasNext();) {
1347:                        Object item = iter.next();
1348:                        Object value = closure.call(item);
1349:                        if (answer == null
1350:                                || ScriptBytecodeAdapter.compareLessThan(value,
1351:                                        answer_value)) {
1352:                            answer = item;
1353:                            answer_value = value;
1354:                        }
1355:                    }
1356:                    return answer;
1357:                } else {
1358:                    return min(self, new ClosureComparator(closure));
1359:                }
1360:            }
1361:
1362:            /**
1363:             * Selects the maximum value found in the collection using the given closure as a comparator
1364:             *
1365:             * @param self    a Collection
1366:             * @param closure a closure used as a comparator
1367:             * @return the maximum value
1368:             */
1369:            public static Object max(Collection self, Closure closure) {
1370:                int params = closure.getMaximumNumberOfParameters();
1371:                if (params == 1) {
1372:                    Object answer = null;
1373:                    Object answer_value = null;
1374:                    for (Iterator iter = self.iterator(); iter.hasNext();) {
1375:                        Object item = iter.next();
1376:                        Object value = closure.call(item);
1377:                        if (answer == null
1378:                                || ScriptBytecodeAdapter.compareLessThan(
1379:                                        answer_value, value)) {
1380:                            answer = item;
1381:                            answer_value = value;
1382:                        }
1383:                    }
1384:                    return answer;
1385:                } else {
1386:                    return max(self, new ClosureComparator(closure));
1387:                }
1388:            }
1389:
1390:            /**
1391:             * Makes a String look like a Collection by adding support for the size() method
1392:             *
1393:             * @param text a String
1394:             * @return the length of the String
1395:             */
1396:            public static int size(String text) {
1397:                return text.length();
1398:            }
1399:
1400:            /**
1401:             * Provide standard Groovy size() method for StringBuffers
1402:             *
1403:             * @param buffer a StringBuffer
1404:             * @return the length of the StringBuffer
1405:             */
1406:            public static int size(StringBuffer buffer) {
1407:                return buffer.length();
1408:            }
1409:
1410:            /**
1411:             * Provide the standard Groovy size method
1412:             */
1413:            public static long size(File file) {
1414:                return file.length();
1415:            }
1416:
1417:            /**
1418:             * Provide the standard Groovy size method
1419:             */
1420:            public static long size(Matcher matcher) {
1421:                return getCount(matcher);
1422:            }
1423:
1424:            /**
1425:             * Makes an Array look like a Collection by adding support for the size() method
1426:             *
1427:             * @param self an Array of Object
1428:             * @return the size of the Array
1429:             */
1430:            public static int size(Object[] self) {
1431:                return self.length;
1432:            }
1433:
1434:            /**
1435:             * Support the subscript operator for String.
1436:             *
1437:             * @param text  a String
1438:             * @param index the index of the Character to get
1439:             * @return the Character at the given index
1440:             */
1441:            public static CharSequence getAt(CharSequence text, int index) {
1442:                index = normaliseIndex(index, text.length());
1443:                return text.subSequence(index, index + 1);
1444:            }
1445:
1446:            /**
1447:             * Support the subscript operator for String
1448:             *
1449:             * @param text a String
1450:             * @return the Character object at the given index
1451:             */
1452:            public static String getAt(String text, int index) {
1453:                index = normaliseIndex(index, text.length());
1454:                return text.substring(index, index + 1);
1455:            }
1456:
1457:            /**
1458:             * Support the range subscript operator for CharSequence
1459:             *
1460:             * @param text  a CharSequence
1461:             * @param range a Range
1462:             * @return the subsequence CharSequence
1463:             */
1464:            public static CharSequence getAt(CharSequence text, Range range) {
1465:                int from = normaliseIndex(DefaultTypeTransformation
1466:                        .intUnbox(range.getFrom()), text.length());
1467:                int to = normaliseIndex(DefaultTypeTransformation
1468:                        .intUnbox(range.getTo()), text.length());
1469:
1470:                // If this is a backwards range, reverse the arguments to substring.
1471:                if (from > to) {
1472:                    int tmp = from;
1473:                    from = to;
1474:                    to = tmp;
1475:                }
1476:
1477:                return text.subSequence(from, to + 1);
1478:            }
1479:
1480:            /**
1481:             * Support the range subscript operator for CharSequence or StringBuffer with IntRange
1482:             *
1483:             * @param text  a CharSequence
1484:             * @param range an IntRange
1485:             * @return the subsequence CharSequence
1486:             */
1487:            public static CharSequence getAt(CharSequence text, IntRange range) {
1488:                return getAt(text, (Range) range);
1489:            }
1490:
1491:            /**
1492:             * Support the range subscript operator for String with IntRange
1493:             *
1494:             * @param text  a String
1495:             * @param range an IntRange
1496:             * @return the resulting String
1497:             */
1498:            public static String getAt(String text, IntRange range) {
1499:                return getAt(text, (Range) range);
1500:            }
1501:
1502:            /**
1503:             * Support the range subscript operator for String
1504:             *
1505:             * @param text  a String
1506:             * @param range a Range
1507:             * @return a substring corresponding to the Range
1508:             */
1509:            public static String getAt(String text, Range range) {
1510:                int from = normaliseIndex(DefaultTypeTransformation
1511:                        .intUnbox(range.getFrom()), text.length());
1512:                int to = normaliseIndex(DefaultTypeTransformation
1513:                        .intUnbox(range.getTo()), text.length());
1514:
1515:                // If this is a backwards range, reverse the arguments to substring.
1516:                boolean reverse = range.isReverse();
1517:                if (from > to) {
1518:                    int tmp = to;
1519:                    to = from;
1520:                    from = tmp;
1521:                    reverse = !reverse;
1522:                }
1523:
1524:                String answer = text.substring(from, to + 1);
1525:                if (reverse) {
1526:                    answer = reverse(answer);
1527:                }
1528:                return answer;
1529:            }
1530:
1531:            /**
1532:             * Creates a new string which is the reverse (backwards) of this string
1533:             *
1534:             * @param self a String
1535:             * @return a new string with all the characters reversed.
1536:             */
1537:            public static String reverse(String self) {
1538:                int size = self.length();
1539:                StringBuffer buffer = new StringBuffer(size);
1540:                for (int i = size - 1; i >= 0; i--) {
1541:                    buffer.append(self.charAt(i));
1542:                }
1543:                return buffer.toString();
1544:            }
1545:
1546:            /**
1547:             * Transforms a String representing a URL into a URL object.
1548:             *
1549:             * @param self the String representing a URL
1550:             * @return a URL
1551:             * @throws MalformedURLException is thrown if the URL is not well formed.
1552:             */
1553:            public static URL toURL(String self) throws MalformedURLException {
1554:                return new URL(self);
1555:            }
1556:
1557:            /**
1558:             * Transforms a String representing a URI into a URI object.
1559:             *
1560:             * @param self the String representing a URI
1561:             * @return a URI
1562:             * @throws URISyntaxException is thrown if the URI is not well formed.
1563:             */
1564:            public static URI toURI(String self) throws URISyntaxException {
1565:                return new URI(self);
1566:            }
1567:
1568:            /**
1569:             * Turns a String into a regular expression pattern
1570:             *
1571:             * @param self a String to convert into a regular expression
1572:             * @return the regular expression pattern
1573:             */
1574:            public static Pattern negate(String self) {
1575:                return Pattern.compile(self);
1576:            }
1577:
1578:            /**
1579:             * Replaces all occurrencies of a captured group by the result of a closure on that text.
1580:             * <p/>
1581:             * <p> For examples,
1582:             * <pre>
1583:             *     assert "FOOBAR-FOOBAR-" == "foobar-FooBar-".replaceAll("(([fF][oO]{2})[bB]ar)", { Object[] it -> it[0].toUpperCase() })
1584:             * <p/>
1585:             *     Here,
1586:             *          it[0] is the global string of the matched group
1587:             *          it[1] is the first string in the matched group
1588:             *          it[2] is the second string in the matched group
1589:             * <p/>
1590:             * <p/>
1591:             *     assert "FOO-FOO-" == "foobar-FooBar-".replaceAll("(([fF][oO]{2})[bB]ar)", { x, y, z -> z.toUpperCase() })
1592:             * <p/>
1593:             *     Here,
1594:             *          x is the global string of the matched group
1595:             *          y is the first string in the matched group
1596:             *          z is the second string in the matched group
1597:             * </pre>
1598:             *
1599:             * @param self    a String
1600:             * @param regex   the capturing regex
1601:             * @param closure the closure to apply on each captured group
1602:             * @return a String with replaced content
1603:             */
1604:            public static String replaceAll(String self, String regex,
1605:                    Closure closure) {
1606:                Matcher matcher = Pattern.compile(regex).matcher(self);
1607:                if (matcher.find()) {
1608:                    matcher.reset();
1609:                    StringBuffer sb = new StringBuffer();
1610:                    while (matcher.find()) {
1611:                        int count = matcher.groupCount();
1612:                        ArrayList groups = new ArrayList();
1613:                        for (int i = 0; i <= count; i++) {
1614:                            groups.add(matcher.group(i));
1615:                        }
1616:                        matcher.appendReplacement(sb, String.valueOf(closure
1617:                                .call((Object[]) groups.toArray())));
1618:                    }
1619:                    matcher.appendTail(sb);
1620:                    return sb.toString();
1621:                } else {
1622:                    return self;
1623:                }
1624:            }
1625:
1626:            private static String getPadding(String padding, int length) {
1627:                if (padding.length() < length) {
1628:                    return multiply(padding,
1629:                            new Integer(length / padding.length() + 1))
1630:                            .substring(0, length);
1631:                } else {
1632:                    return padding.substring(0, length);
1633:                }
1634:            }
1635:
1636:            /**
1637:             * Pad a String with the characters appended to the left
1638:             *
1639:             * @param numberOfChars the total number of characters
1640:             * @param padding       the charaters used for padding
1641:             * @return the String padded to the left
1642:             */
1643:            public static String padLeft(String self, Number numberOfChars,
1644:                    String padding) {
1645:                int numChars = numberOfChars.intValue();
1646:                if (numChars <= self.length()) {
1647:                    return self;
1648:                } else {
1649:                    return getPadding(padding, numChars - self.length()) + self;
1650:                }
1651:            }
1652:
1653:            /**
1654:             * Pad a String with the spaces appended to the left
1655:             *
1656:             * @param numberOfChars the total number of characters
1657:             * @return the String padded to the left
1658:             */
1659:
1660:            public static String padLeft(String self, Number numberOfChars) {
1661:                return padLeft(self, numberOfChars, " ");
1662:            }
1663:
1664:            /**
1665:             * Pad a String with the characters appended to the right
1666:             *
1667:             * @param numberOfChars the total number of characters
1668:             * @param padding       the charaters used for padding
1669:             * @return the String padded to the right
1670:             */
1671:
1672:            public static String padRight(String self, Number numberOfChars,
1673:                    String padding) {
1674:                int numChars = numberOfChars.intValue();
1675:                if (numChars <= self.length()) {
1676:                    return self;
1677:                } else {
1678:                    return self + getPadding(padding, numChars - self.length());
1679:                }
1680:            }
1681:
1682:            /**
1683:             * Pad a String with the spaces appended to the right
1684:             *
1685:             * @param numberOfChars the total number of characters
1686:             * @return the String padded to the right
1687:             */
1688:
1689:            public static String padRight(String self, Number numberOfChars) {
1690:                return padRight(self, numberOfChars, " ");
1691:            }
1692:
1693:            /**
1694:             * Center a String and padd it with the characters appended around it
1695:             *
1696:             * @param numberOfChars the total number of characters
1697:             * @param padding       the charaters used for padding
1698:             * @return the String centered with padded character around
1699:             */
1700:            public static String center(String self, Number numberOfChars,
1701:                    String padding) {
1702:                int numChars = numberOfChars.intValue();
1703:                if (numChars <= self.length()) {
1704:                    return self;
1705:                } else {
1706:                    int charsToAdd = numChars - self.length();
1707:                    String semiPad = charsToAdd % 2 == 1 ? getPadding(padding,
1708:                            charsToAdd / 2 + 1) : getPadding(padding,
1709:                            charsToAdd / 2);
1710:                    if (charsToAdd % 2 == 0)
1711:                        return semiPad + self + semiPad;
1712:                    else
1713:                        return semiPad.substring(0, charsToAdd / 2) + self
1714:                                + semiPad;
1715:                }
1716:            }
1717:
1718:            /**
1719:             * Center a String and padd it with spaces appended around it
1720:             *
1721:             * @param numberOfChars the total number of characters
1722:             * @return the String centered with padded character around
1723:             */
1724:            public static String center(String self, Number numberOfChars) {
1725:                return center(self, numberOfChars, " ");
1726:            }
1727:
1728:            /**
1729:             * Support the subscript operator, e.g. matcher[index], for a regex Matcher.
1730:             * <p/>
1731:             * For an example using no group match, <code><pre>
1732:             *    def p = /ab[d|f]/
1733:             *    def m = "abcabdabeabf" =~ p
1734:             *    for (i in 0..<m.count) {
1735:             *        println( "m.groupCount() = " + m.groupCount())
1736:             *        println( "  " + i + ": " + m[i] )   // m[i] is a String
1737:             *    }
1738:             * </pre></code>
1739:             * <p/>
1740:             * For an example using group matches, <code><pre>
1741:             *    def p = /(?:ab([c|d|e|f]))/
1742:             *    def m = "abcabdabeabf" =~ p
1743:             *    for (i in 0..<m.count) {
1744:             *        println( "m.groupCount() = " + m.groupCount())
1745:             *        println( "  " + i + ": " + m[i] )   // m[i] is a List
1746:             *    }
1747:             * </pre></code>
1748:             * <p/>
1749:             * For another example using group matches, <code><pre>
1750:             *    def m = "abcabdabeabfabxyzabx" =~ /(?:ab([d|x-z]+))/
1751:             *    m.count.times {
1752:             *        println( "m.groupCount() = " + m.groupCount())
1753:             *        println( "  " + it + ": " + m[it] )   // m[it] is a List
1754:             *    }
1755:             * </pre></code>
1756:             *
1757:             * @param matcher a Matcher
1758:             * @param idx     an index
1759:             * @return object a matched String if no groups matched, list of matched groups otherwise.
1760:             */
1761:            public static Object getAt(Matcher matcher, int idx) {
1762:                try {
1763:                    int count = getCount(matcher);
1764:                    if (idx < -count || idx >= count) {
1765:                        throw new IndexOutOfBoundsException(
1766:                                "index is out of range " + (-count) + ".."
1767:                                        + (count - 1) + " (index = " + idx
1768:                                        + ")");
1769:                    }
1770:                    idx = normaliseIndex(idx, count);
1771:                    matcher.reset();
1772:                    for (int i = 0; i <= idx; i++) {
1773:                        matcher.find();
1774:                    }
1775:
1776:                    if (hasGroup(matcher)) {
1777:                        // are we using groups?
1778:                        // yes, so return the specified group as list
1779:                        ArrayList list = new ArrayList(matcher.groupCount());
1780:                        for (int i = 0; i <= matcher.groupCount(); i++) {
1781:                            list.add(matcher.group(i));
1782:                        }
1783:                        return list;
1784:                    } else {
1785:                        // not using groups, so return the nth
1786:                        // occurrence of the pattern
1787:                        return matcher.group();
1788:                    }
1789:                } catch (IllegalStateException ex) {
1790:                    return null;
1791:                }
1792:            }
1793:
1794:            /**
1795:             * Set the position of the given Matcher to the given index.
1796:             *
1797:             * @param matcher a Matcher
1798:             * @param idx     the index number
1799:             */
1800:            public static void setIndex(Matcher matcher, int idx) {
1801:                int count = getCount(matcher);
1802:                if (idx < -count || idx >= count) {
1803:                    throw new IndexOutOfBoundsException(
1804:                            "index is out of range " + (-count) + ".."
1805:                                    + (count - 1) + " (index = " + idx + ")");
1806:                }
1807:                if (idx == 0) {
1808:                    matcher.reset();
1809:                } else if (idx > 0) {
1810:                    matcher.reset();
1811:                    for (int i = 0; i < idx; i++) {
1812:                        matcher.find();
1813:                    }
1814:                } else if (idx < 0) {
1815:                    matcher.reset();
1816:                    idx += getCount(matcher);
1817:                    for (int i = 0; i < idx; i++) {
1818:                        matcher.find();
1819:                    }
1820:                }
1821:            }
1822:
1823:            /**
1824:             * Find the number of Strings matched to the given Matcher.
1825:             *
1826:             * @param matcher a Matcher
1827:             * @return int  the number of Strings matched to the given matcher.
1828:             */
1829:            public static int getCount(Matcher matcher) {
1830:                int counter = 0;
1831:                matcher.reset();
1832:                while (matcher.find()) {
1833:                    counter++;
1834:                }
1835:                matcher.reset();
1836:                return counter;
1837:            }
1838:
1839:            /**
1840:             * Check whether a Matcher contains a group or not.
1841:             *
1842:             * @param matcher a Matcher
1843:             * @return boolean  <code>true</code> if matcher contains at least one group.
1844:             */
1845:            public static boolean hasGroup(Matcher matcher) {
1846:                return matcher.groupCount() > 0;
1847:            }
1848:
1849:            /**
1850:             * Support the range subscript operator for a List
1851:             *
1852:             * @param self  a List
1853:             * @param range a Range
1854:             * @return a sublist based on range borders or a new list if range is reversed
1855:             * @see java.util.List#subList(int,int)
1856:             */
1857:            public static List getAt(List self, IntRange range) {
1858:                RangeInfo info = subListBorders(self.size(), range);
1859:                List answer = self.subList(info.from, info.to); // sublist is always exclusive, but Ranges are not
1860:                if (info.reverse) {
1861:                    answer = reverse(answer);
1862:                }
1863:                return answer;
1864:            }
1865:
1866:            // helper method for getAt and putAt
1867:            protected static RangeInfo subListBorders(int size, IntRange range) {
1868:                int from = normaliseIndex(DefaultTypeTransformation
1869:                        .intUnbox(range.getFrom()), size);
1870:                int to = normaliseIndex(DefaultTypeTransformation
1871:                        .intUnbox(range.getTo()), size);
1872:                boolean reverse = range.isReverse();
1873:                if (from > to) { // support list[1..-1]
1874:                    int tmp = to;
1875:                    to = from;
1876:                    from = tmp;
1877:                    reverse = !reverse;
1878:                }
1879:                return new RangeInfo(from, to + 1, reverse);
1880:            }
1881:
1882:            // helper method for getAt and putAt
1883:            protected static RangeInfo subListBorders(int size, EmptyRange range) {
1884:                int from = normaliseIndex(DefaultTypeTransformation
1885:                        .intUnbox(range.getFrom()), size);
1886:                return new RangeInfo(from, from, false);
1887:            }
1888:
1889:            /**
1890:             * Allows a List to be used as the indices to be used on a List
1891:             *
1892:             * @param self    a List
1893:             * @param indices a Collection of indices
1894:             * @return a new list of the values at the given indices
1895:             */
1896:            public static List getAt(List self, Collection indices) {
1897:                List answer = new ArrayList(indices.size());
1898:                for (Iterator iter = indices.iterator(); iter.hasNext();) {
1899:                    Object value = iter.next();
1900:                    if (value instanceof  Range) {
1901:                        answer.addAll(getAt(self, (Range) value));
1902:                    } else if (value instanceof  List) {
1903:                        answer.addAll(getAt(self, (List) value));
1904:                    } else {
1905:                        int idx = DefaultTypeTransformation.intUnbox(value);
1906:                        answer.add(getAt(self, idx));
1907:                    }
1908:                }
1909:                return answer;
1910:            }
1911:
1912:            /**
1913:             * Allows a List to be used as the indices to be used on a List
1914:             *
1915:             * @param self    an Array of Objects
1916:             * @param indices a Collection of indices
1917:             * @return a new list of the values at the given indices
1918:             */
1919:            public static List getAt(Object[] self, Collection indices) {
1920:                List answer = new ArrayList(indices.size());
1921:                for (Iterator iter = indices.iterator(); iter.hasNext();) {
1922:                    Object value = iter.next();
1923:                    if (value instanceof  Range) {
1924:                        answer.addAll(getAt(self, (Range) value));
1925:                    } else if (value instanceof  Collection) {
1926:                        answer.addAll(getAt(self, (Collection) value));
1927:                    } else {
1928:                        int idx = DefaultTypeTransformation.intUnbox(value);
1929:                        answer.add(getAt(self, idx));
1930:                    }
1931:                }
1932:                return answer;
1933:            }
1934:
1935:            /**
1936:             * Allows a List to be used as the indices to be used on a CharSequence
1937:             *
1938:             * @param self    a CharSequence
1939:             * @param indices a Collection of indices
1940:             * @return a String of the values at the given indices
1941:             */
1942:            public static CharSequence getAt(CharSequence self,
1943:                    Collection indices) {
1944:                StringBuffer answer = new StringBuffer();
1945:                for (Iterator iter = indices.iterator(); iter.hasNext();) {
1946:                    Object value = iter.next();
1947:                    if (value instanceof  Range) {
1948:                        answer.append(getAt(self, (Range) value));
1949:                    } else if (value instanceof  Collection) {
1950:                        answer.append(getAt(self, (Collection) value));
1951:                    } else {
1952:                        int idx = DefaultTypeTransformation.intUnbox(value);
1953:                        answer.append(getAt(self, idx));
1954:                    }
1955:                }
1956:                return answer.toString();
1957:            }
1958:
1959:            /**
1960:             * Allows a List to be used as the indices to be used on a String
1961:             *
1962:             * @param self    a String
1963:             * @param indices a Collection of indices
1964:             * @return a String of the values at the given indices
1965:             */
1966:            public static String getAt(String self, Collection indices) {
1967:                return (String) getAt((CharSequence) self, indices);
1968:            }
1969:
1970:            /**
1971:             * Allows a List to be used as the indices to be used on a Matcher
1972:             *
1973:             * @param self    a Matcher
1974:             * @param indices a Collection of indices
1975:             * @return a String of the values at the given indices
1976:             */
1977:            public static String getAt(Matcher self, Collection indices) {
1978:                StringBuffer answer = new StringBuffer();
1979:                for (Iterator iter = indices.iterator(); iter.hasNext();) {
1980:                    Object value = iter.next();
1981:                    if (value instanceof  Range) {
1982:                        answer.append(getAt(self, (Range) value));
1983:                    } else if (value instanceof  Collection) {
1984:                        answer.append(getAt(self, (Collection) value));
1985:                    } else {
1986:                        int idx = DefaultTypeTransformation.intUnbox(value);
1987:                        answer.append(getAt(self, idx));
1988:                    }
1989:                }
1990:                return answer.toString();
1991:            }
1992:
1993:            /**
1994:             * Creates a sub-Map containing the given keys. This method is similar to
1995:             * List.subList() but uses keys rather than index ranges.
1996:             *
1997:             * @param map  a Map
1998:             * @param keys a Collection of keys
1999:             * @return a new Map containing the given keys
2000:             */
2001:            public static Map subMap(Map map, Collection keys) {
2002:                Map answer = new HashMap(keys.size());
2003:                for (Iterator iter = keys.iterator(); iter.hasNext();) {
2004:                    Object key = iter.next();
2005:                    answer.put(key, map.get(key));
2006:                }
2007:                return answer;
2008:            }
2009:
2010:            /**
2011:             * Looks up an item in a Map for the given key and returns the value - unless
2012:             * there is no entry for the given key in which case add the default value
2013:             * to the map and return that.
2014:             *
2015:             * @param map          a Map
2016:             * @param key          the key to lookup the value of
2017:             * @param defaultValue the value to return and add to the map for this key if
2018:             *                     there is no entry for the given key
2019:             * @return the value of the given key or the default value, added to the map if the
2020:             *         key did not exist
2021:             */
2022:            public static Object get(Map map, Object key, Object defaultValue) {
2023:                Object answer = map.get(key);
2024:                if (answer == null) {
2025:                    answer = defaultValue;
2026:                    map.put(key, answer);
2027:                }
2028:                return answer;
2029:            }
2030:
2031:            /**
2032:             * Support the range subscript operator for an Array
2033:             *
2034:             * @param array an Array of Objects
2035:             * @param range a Range
2036:             * @return a range of a list from the range's from index up to but not
2037:             *         including the ranges's to value
2038:             */
2039:            public static List getAt(Object[] array, Range range) {
2040:                List list = Arrays.asList(array);
2041:                return getAt(list, range);
2042:            }
2043:
2044:            public static List getAt(Object[] array, IntRange range) {
2045:                List list = Arrays.asList(array);
2046:                return getAt(list, range);
2047:            }
2048:
2049:            public static List getAt(Object[] array, ObjectRange range) {
2050:                List list = Arrays.asList(array);
2051:                return getAt(list, range);
2052:            }
2053:
2054:            /**
2055:             * Support the subscript operator for an Array
2056:             *
2057:             * @param array an Array of Objects
2058:             * @param idx   an index
2059:             * @return the value at the given index
2060:             */
2061:            public static Object getAt(Object[] array, int idx) {
2062:                return array[normaliseIndex(idx, array.length)];
2063:            }
2064:
2065:            /**
2066:             * Support the subscript operator for an Array
2067:             *
2068:             * @param array an Array of Objects
2069:             * @param idx   an index
2070:             * @param value an Object to put at the given index
2071:             */
2072:            public static void putAt(Object[] array, int idx, Object value) {
2073:                if (value instanceof  Number) {
2074:                    Class arrayComponentClass = array.getClass()
2075:                            .getComponentType();
2076:
2077:                    if (!arrayComponentClass.equals(value.getClass())) {
2078:                        Object newVal = DefaultTypeTransformation.castToType(
2079:                                value, arrayComponentClass);
2080:                        array[normaliseIndex(idx, array.length)] = newVal;
2081:                        return;
2082:                    }
2083:                }
2084:                array[normaliseIndex(idx, array.length)] = value;
2085:            }
2086:
2087:            /**
2088:             * Allows conversion of arrays into a mutable List
2089:             *
2090:             * @param array an Array of Objects
2091:             * @return the array as a List
2092:             */
2093:            public static List toList(Object[] array) {
2094:                int size = array.length;
2095:                List list = new ArrayList(size);
2096:                for (int i = 0; i < size; i++) {
2097:                    list.add(array[i]);
2098:                }
2099:                return list;
2100:            }
2101:
2102:            /**
2103:             * Support the subscript operator for a List
2104:             *
2105:             * @param self a List
2106:             * @param idx  an index
2107:             * @return the value at the given index
2108:             */
2109:            public static Object getAt(List self, int idx) {
2110:                int size = self.size();
2111:                int i = normaliseIndex(idx, size);
2112:                if (i < size) {
2113:                    return self.get(i);
2114:                } else {
2115:                    return null;
2116:                }
2117:            }
2118:
2119:            /**
2120:             * A helper method to allow lists to work with subscript operators
2121:             *
2122:             * @param self  a List
2123:             * @param idx   an index
2124:             * @param value the value to put at the given index
2125:             */
2126:            public static void putAt(List self, int idx, Object value) {
2127:                int size = self.size();
2128:                idx = normaliseIndex(idx, size);
2129:                if (idx < size) {
2130:                    self.set(idx, value);
2131:                } else {
2132:                    while (size < idx) {
2133:                        self.add(size++, null);
2134:                    }
2135:                    self.add(idx, value);
2136:                }
2137:            }
2138:
2139:            /**
2140:             * Support the range subscript operator for StringBuffer
2141:             *
2142:             * @param self  a StringBuffer
2143:             * @param range a Range
2144:             * @param value the object that's toString() will be inserted
2145:             */
2146:            public static void putAt(StringBuffer self, IntRange range,
2147:                    Object value) {
2148:                RangeInfo info = subListBorders(self.length(), range);
2149:                self.replace(info.from, info.to, value.toString());
2150:            }
2151:
2152:            /**
2153:             * Support the range subscript operator for StringBuffer
2154:             *
2155:             * @param self  a StringBuffer
2156:             * @param range a Range
2157:             * @param value the object that's toString() will be inserted
2158:             */
2159:            public static void putAt(StringBuffer self, EmptyRange range,
2160:                    Object value) {
2161:                RangeInfo info = subListBorders(self.length(), range);
2162:                self.replace(info.from, info.to, value.toString());
2163:            }
2164:
2165:            /**
2166:             * A helper method to allow lists to work with subscript operators
2167:             *
2168:             * @param self  a List
2169:             * @param range the subset of the list to set
2170:             * @param value the values to put at the given sublist or a Collection of values
2171:             */
2172:            public static void putAt(List self, EmptyRange range, Object value) {
2173:                RangeInfo info = subListBorders(self.size(), range);
2174:                List sublist = self.subList(info.from, info.to);
2175:                sublist.clear();
2176:                if (value instanceof  Collection) {
2177:                    Collection col = (Collection) value;
2178:                    if (col.size() == 0)
2179:                        return;
2180:                    sublist.addAll(col);
2181:                } else {
2182:                    sublist.add(value);
2183:                }
2184:            }
2185:
2186:            /**
2187:             * A helper method to allow lists to work with subscript operators
2188:             *
2189:             * @param self  a List
2190:             * @param range the subset of the list to set
2191:             * @param value the value to put at the given sublist or a Collection of values
2192:             */
2193:            public static void putAt(List self, IntRange range, Object value) {
2194:                RangeInfo info = subListBorders(self.size(), range);
2195:                List sublist = self.subList(info.from, info.to);
2196:                sublist.clear();
2197:                if (value instanceof  Collection) {
2198:                    Collection col = (Collection) value;
2199:                    if (col.size() == 0)
2200:                        return;
2201:                    sublist.addAll(col);
2202:                } else {
2203:                    sublist.add(value);
2204:                }
2205:            }
2206:
2207:            /**
2208:             * A helper method to allow lists to work with subscript operators
2209:             *
2210:             * @param self   a List
2211:             * @param splice the subset of the list to set
2212:             * @param values the value to put at the given sublist
2213:             * @deprecated replace with putAt(List self, Range range, List value)
2214:             */
2215:            public static void putAt(List self, List splice, List values) {
2216:                List sublist = getSubList(self, splice);
2217:                sublist.clear();
2218:                sublist.addAll(values);
2219:            }
2220:
2221:            /**
2222:             * A helper method to allow lists to work with subscript operators
2223:             *
2224:             * @param self   a List
2225:             * @param splice the subset of the list to set
2226:             * @param value  the value to put at the given sublist
2227:             * @deprecated replace with putAt(List self, Range range, Object value)
2228:             */
2229:            public static void putAt(List self, List splice, Object value) {
2230:                List sublist = getSubList(self, splice);
2231:                sublist.clear();
2232:                sublist.add(value);
2233:            }
2234:
2235:            // helper method for putAt(Splice)
2236:            // todo: remove after putAt(Splice) gets deleted
2237:            protected static List getSubList(List self, List splice) {
2238:                int left /* = 0 */;
2239:                int right = 0;
2240:                boolean emptyRange = false;
2241:                if (splice.size() == 2) {
2242:                    left = DefaultTypeTransformation.intUnbox(splice.get(0));
2243:                    right = DefaultTypeTransformation.intUnbox(splice.get(1));
2244:                } else if (splice instanceof  IntRange) {
2245:                    IntRange range = (IntRange) splice;
2246:                    left = range.getFromInt();
2247:                    right = range.getToInt();
2248:                } else if (splice instanceof  EmptyRange) {
2249:                    RangeInfo info = subListBorders(self.size(),
2250:                            (EmptyRange) splice);
2251:                    left = info.from;
2252:                    emptyRange = true;
2253:                } else {
2254:                    throw new IllegalArgumentException(
2255:                            "You must specify a list of 2 indexes to create a sub-list");
2256:                }
2257:                int size = self.size();
2258:                left = normaliseIndex(left, size);
2259:                right = normaliseIndex(right, size);
2260:                List sublist /* = null */;
2261:                if (!emptyRange) {
2262:                    sublist = self.subList(left, right + 1);
2263:                } else {
2264:                    sublist = self.subList(left, left);
2265:                }
2266:                return sublist;
2267:            }
2268:
2269:            /**
2270:             * Support the subscript operator for a List
2271:             *
2272:             * @param self a Map
2273:             * @param key  an Object as a key for the map
2274:             * @return the value corresponding to the given key
2275:             */
2276:            public static Object getAt(Map self, Object key) {
2277:                return self.get(key);
2278:            }
2279:
2280:            /**
2281:             * A helper method to allow lists to work with subscript operators
2282:             *
2283:             * @param self a Map
2284:             * @param key  an Object as a key for the map
2285:             * @return the value corresponding to the given key
2286:             */
2287:            public static Object putAt(Map self, Object key, Object value) {
2288:                return self.put(key, value);
2289:            }
2290:
2291:            /**
2292:             * This converts a possibly negative index to a real index into the array.
2293:             *
2294:             * @param i
2295:             * @param size
2296:             */
2297:            protected static int normaliseIndex(int i, int size) {
2298:                int temp = i;
2299:                if (i < 0) {
2300:                    i += size;
2301:                }
2302:                if (i < 0) {
2303:                    throw new ArrayIndexOutOfBoundsException(
2304:                            "Negative array index [" + temp
2305:                                    + "] too large for array size " + size);
2306:                }
2307:                return i;
2308:            }
2309:
2310:            /**
2311:             * Support the subscript operator for List
2312:             *
2313:             * @param coll     a Collection
2314:             * @param property a String
2315:             * @return a List
2316:             */
2317:            public static List getAt(Collection coll, String property) {
2318:                List answer = new ArrayList(coll.size());
2319:                for (Iterator iter = coll.iterator(); iter.hasNext();) {
2320:                    Object item = iter.next();
2321:                    Object value = InvokerHelper.getProperty(item, property);
2322:                    if (value instanceof  Collection) {
2323:                        answer.addAll((Collection) value);
2324:                    } else {
2325:                        answer.add(value);
2326:                    }
2327:                }
2328:                return answer;
2329:            }
2330:
2331:            /**
2332:             * A convenience method for creating an immutable map
2333:             *
2334:             * @param self a Map
2335:             * @return an immutable Map
2336:             */
2337:            public static Map asImmutable(Map self) {
2338:                return Collections.unmodifiableMap(self);
2339:            }
2340:
2341:            /**
2342:             * A convenience method for creating an immutable sorted map
2343:             *
2344:             * @param self a SortedMap
2345:             * @return an immutable SortedMap
2346:             */
2347:            public static SortedMap asImmutable(SortedMap self) {
2348:                return Collections.unmodifiableSortedMap(self);
2349:            }
2350:
2351:            /**
2352:             * A convenience method for creating an immutable list
2353:             *
2354:             * @param self a List
2355:             * @return an immutable List
2356:             */
2357:            public static List asImmutable(List self) {
2358:                return Collections.unmodifiableList(self);
2359:            }
2360:
2361:            /**
2362:             * A convenience method for creating an immutable list
2363:             *
2364:             * @param self a Set
2365:             * @return an immutable Set
2366:             */
2367:            public static Set asImmutable(Set self) {
2368:                return Collections.unmodifiableSet(self);
2369:            }
2370:
2371:            /**
2372:             * A convenience method for creating an immutable sorted set
2373:             *
2374:             * @param self a SortedSet
2375:             * @return an immutable SortedSet
2376:             */
2377:            public static SortedSet asImmutable(SortedSet self) {
2378:                return Collections.unmodifiableSortedSet(self);
2379:            }
2380:
2381:            /**
2382:             * A convenience method for creating an immutable Collection
2383:             *
2384:             * @param self a Collection
2385:             * @return an immutable Collection
2386:             */
2387:            public static Collection asImmutable(Collection self) {
2388:                return Collections.unmodifiableCollection(self);
2389:            }
2390:
2391:            /**
2392:             * A convenience method for creating a synchronized Map
2393:             *
2394:             * @param self a Map
2395:             * @return a synchronized Map
2396:             */
2397:            public static Map asSynchronized(Map self) {
2398:                return Collections.synchronizedMap(self);
2399:            }
2400:
2401:            /**
2402:             * A convenience method for creating a synchronized SortedMap
2403:             *
2404:             * @param self a SortedMap
2405:             * @return a synchronized SortedMap
2406:             */
2407:            public static SortedMap asSynchronized(SortedMap self) {
2408:                return Collections.synchronizedSortedMap(self);
2409:            }
2410:
2411:            /**
2412:             * A convenience method for creating a synchronized Collection
2413:             *
2414:             * @param self a Collection
2415:             * @return a synchronized Collection
2416:             */
2417:            public static Collection asSynchronized(Collection self) {
2418:                return Collections.synchronizedCollection(self);
2419:            }
2420:
2421:            /**
2422:             * A convenience method for creating a synchronized List
2423:             *
2424:             * @param self a List
2425:             * @return a synchronized List
2426:             */
2427:            public static List asSynchronized(List self) {
2428:                return Collections.synchronizedList(self);
2429:            }
2430:
2431:            /**
2432:             * A convenience method for creating a synchronized Set
2433:             *
2434:             * @param self a Set
2435:             * @return a synchronized Set
2436:             */
2437:            public static Set asSynchronized(Set self) {
2438:                return Collections.synchronizedSet(self);
2439:            }
2440:
2441:            /**
2442:             * A convenience method for creating a synchronized SortedSet
2443:             *
2444:             * @param self a SortedSet
2445:             * @return a synchronized SortedSet
2446:             */
2447:            public static SortedSet asSynchronized(SortedSet self) {
2448:                return Collections.synchronizedSortedSet(self);
2449:            }
2450:
2451:            public static SpreadMap spread(Map self) {
2452:                return toSpreadMap(self);
2453:            }
2454:
2455:            /**
2456:             * Returns the converted <code>SpreadLMap</code> of the given <code>self</code>.
2457:             * <p/>
2458:             * For examples, if there is defined a function like as
2459:             * <blockquote><pre>
2460:             *     def fn(a, b, c, d) { return a + b + c + d }
2461:             * </pre></blockquote>, then all of the following three have the same meaning.
2462:             * <blockquote><pre>
2463:             *     println fn(a:1, [b:2, c:3].toSpreadMap(), d:4)
2464:             *     println fn(a:1, *:[b:2, c:3], d:4)
2465:             *     println fn(a:1, b:2, c:3, d:4)
2466:             * </pre></blockquote>
2467:             * <p/>
2468:             *
2469:             * @param self a list to be converted into a spreadmap
2470:             * @return a newly created Spreadmap if this list is not null and its size is positive.
2471:             */
2472:            public static SpreadMap toSpreadMap(Map self) {
2473:                if (self == null)
2474:                    throw new GroovyRuntimeException(
2475:                            "Fail to convert Map to SpreadMap, because it is null.");
2476:                else
2477:                    return new SpreadMap(self);
2478:            }
2479:
2480:            public static SpreadMap toSpreadMap(Object[] self) {
2481:                if (self == null)
2482:                    throw new GroovyRuntimeException(
2483:                            "Fail to convert Object[] to SpreadMap, because it is null.");
2484:                else if (self.length % 2 != 0)
2485:                    throw new GroovyRuntimeException(
2486:                            "Fail to convert Object[] to SpreadMap, because it's size is not even.");
2487:                else
2488:                    return new SpreadMap(self);
2489:            }
2490:
2491:            /**
2492:             * Sorts the given collection into a sorted list.
2493:             *
2494:             * @param self the collection to be sorted
2495:             * @return the sorted collection as a List
2496:             */
2497:            public static List sort(Collection self) {
2498:                List answer = asList(self);
2499:                Collections.sort(answer, new NumberComparator());
2500:                return answer;
2501:            }
2502:
2503:            /**
2504:             * Avoids doing unnecessary work when sorting an already sorted set
2505:             *
2506:             * @param self
2507:             * @return the sorted set
2508:             */
2509:            public static SortedSet sort(SortedSet self) {
2510:                return self;
2511:            }
2512:
2513:            /**
2514:             * Removes the last item from the List. Using add() and pop()
2515:             * is similar to push and pop on a Stack.
2516:             *
2517:             * @param self a List
2518:             * @return the item removed from the List
2519:             * @throws NoSuchElementException if the list is empty and you try to pop() it.
2520:             */
2521:            public static Object pop(List self) {
2522:                if (self.isEmpty()) {
2523:                    throw new NoSuchElementException(
2524:                            "Cannot pop() an empty List");
2525:                }
2526:                return self.remove(self.size() - 1);
2527:            }
2528:
2529:            /**
2530:             * A convenience method for sorting a Collection with a specific comparator
2531:             *
2532:             * @param self       a collection to be sorted
2533:             * @param comparator a Comparator used for the comparison
2534:             * @return a newly created sorted List
2535:             */
2536:            public static List sort(Collection self, Comparator comparator) {
2537:                List list = asList(self);
2538:                Collections.sort(list, comparator);
2539:                return list;
2540:            }
2541:
2542:            /**
2543:             * A convenience method for sorting a Collection using a closure as a comparator
2544:             *
2545:             * @param self    a Collection to be sorted
2546:             * @param closure a Closure used as a comparator
2547:             * @return a newly created sorted List
2548:             */
2549:            public static List sort(Collection self, Closure closure) {
2550:                List list = asList(self);
2551:                // use a comparator of one item or two
2552:                int params = closure.getMaximumNumberOfParameters();
2553:                if (params == 1) {
2554:                    Collections.sort(list, new OrderBy(closure));
2555:                } else {
2556:                    Collections.sort(list, new ClosureComparator(closure));
2557:                }
2558:                return list;
2559:            }
2560:
2561:            /**
2562:             * Converts the given collection into a List
2563:             *
2564:             * @param self a collection to be converted into a List
2565:             * @return a newly created List if this collection is not already a List
2566:             */
2567:            public static List asList(Collection self) {
2568:                if (self instanceof  List) {
2569:                    return (List) self;
2570:                } else {
2571:                    return new ArrayList(self);
2572:                }
2573:            }
2574:
2575:            public static Object asType(Collection col, Class clazz) {
2576:                if (clazz == List.class) {
2577:                    return asList(col);
2578:                } else if (clazz == Set.class) {
2579:                    if (col instanceof  Set)
2580:                        return col;
2581:                    return new HashSet(col);
2582:                }
2583:                return asType((Object) col, clazz);
2584:            }
2585:
2586:            public static Object asType(Closure cl, Class clazz) {
2587:                if (clazz.isInterface() && !(clazz.isInstance(cl))) {
2588:                    return Proxy.newProxyInstance(clazz.getClassLoader(),
2589:                            new Class[] { clazz }, new ConvertedClosure(cl));
2590:                }
2591:                return asType((Object) cl, clazz);
2592:            }
2593:
2594:            public static Object asType(Map map, Class clazz) {
2595:                if (clazz.isInterface() && !(clazz.isInstance(map))) {
2596:                    return Proxy.newProxyInstance(clazz.getClassLoader(),
2597:                            new Class[] { clazz }, new ConvertedMap(map));
2598:                }
2599:                return asType((Object) map, clazz);
2600:            }
2601:
2602:            /**
2603:             * Reverses the list
2604:             *
2605:             * @param self a List
2606:             * @return a reversed List
2607:             */
2608:            public static List reverse(List self) {
2609:                int size = self.size();
2610:                List answer = new ArrayList(size);
2611:                ListIterator iter = self.listIterator(size);
2612:                while (iter.hasPrevious()) {
2613:                    answer.add(iter.previous());
2614:                }
2615:                return answer;
2616:            }
2617:
2618:            /**
2619:             * Create a List as a union of both Collections
2620:             *
2621:             * @param left  the left Collection
2622:             * @param right the right Collection
2623:             * @return a List
2624:             */
2625:            public static List plus(Collection left, Collection right) {
2626:                List answer = new ArrayList(left.size() + right.size());
2627:                answer.addAll(left);
2628:                answer.addAll(right);
2629:                return answer;
2630:            }
2631:
2632:            /**
2633:             * Create a List as a union of a Collection and an Object
2634:             *
2635:             * @param left  a Collection
2636:             * @param right an object to append
2637:             * @return a List
2638:             */
2639:            public static List plus(Collection left, Object right) {
2640:                List answer = new ArrayList(left.size() + 1);
2641:                answer.addAll(left);
2642:                answer.add(right);
2643:                return answer;
2644:            }
2645:
2646:            /**
2647:             * Create a List composed of the same elements repeated a certain number of times.
2648:             *
2649:             * @param self   a Collection
2650:             * @param factor the number of times to append
2651:             * @return a List
2652:             */
2653:            public static List multiply(Collection self, Number factor) {
2654:                int size = factor.intValue();
2655:                List answer = new ArrayList(self.size() * size);
2656:                for (int i = 0; i < size; i++) {
2657:                    answer.addAll(self);
2658:                }
2659:                return answer;
2660:            }
2661:
2662:            /**
2663:             * Create a List composed of the intersection of both collections
2664:             *
2665:             * @param left  a Collection
2666:             * @param right a Collection
2667:             * @return a List as an intersection of both collections
2668:             */
2669:            public static List intersect(Collection left, Collection right) {
2670:                if (left.size() == 0)
2671:                    return new ArrayList();
2672:
2673:                boolean nlgnSort = sameType(new Collection[] { left, right });
2674:
2675:                ArrayList result = new ArrayList();
2676:                //creates the collection to look for values.
2677:                Collection pickFrom = new TreeSet(new NumberComparator());
2678:                pickFrom.addAll(left);
2679:
2680:                for (Iterator iter = right.iterator(); iter.hasNext();) {
2681:                    final Object o = iter.next();
2682:                    if (pickFrom.contains(o))
2683:                        result.add(o);
2684:                }
2685:                return result;
2686:            }
2687:
2688:            /**
2689:             * Returns <code>true</code> if the intersection of two collenctions is empty.
2690:             *
2691:             * @param left  a Collection
2692:             * @param right a Collection
2693:             * @return boolean   <code>true</code> if the intersection of two collenctions is empty, <code>false</code> otherwise.
2694:             */
2695:            public static boolean disjoint(Collection left, Collection right) {
2696:
2697:                if (left.size() == 0 || right.size() == 0)
2698:                    return true;
2699:
2700:                boolean nlgnSort = sameType(new Collection[] { left, right });
2701:
2702:                Collection pickFrom = (Collection) new TreeSet(
2703:                        new NumberComparator());
2704:                ((TreeSet) pickFrom).addAll(right);
2705:
2706:                for (Iterator iter = left.iterator(); iter.hasNext();) {
2707:                    final Object o = iter.next();
2708:                    if (pickFrom.contains(o))
2709:                        return false;
2710:                }
2711:                return true;
2712:            }
2713:
2714:            // Default comparator for numbers of different types.
2715:            private static class NumberComparator implements  Comparator {
2716:                public int compare(Object o1, Object o2) {
2717:                    if (o1 instanceof  Number && o2 instanceof  Number) {
2718:                        BigDecimal x1 = new BigDecimal("" + o1);
2719:                        BigDecimal x2 = new BigDecimal("" + o2);
2720:                        return x1.compareTo(x2);
2721:                    } else if (o1.getClass() == o2.getClass()
2722:                            && o1 instanceof  Comparable) {
2723:                        return ((Comparable) o1).compareTo((Comparable) o2);
2724:                    } else {
2725:                        int x1 = o1.hashCode();
2726:                        int x2 = o2.hashCode();
2727:                        return (x1 - x2);
2728:                    }
2729:                }
2730:
2731:                public boolean equals(Object obj) {
2732:                    return this .equals(obj);
2733:                }
2734:            }
2735:
2736:            /**
2737:             * Compare two Lists.
2738:             * If numbers exits in the Lists, then they are compared as numbers,
2739:             * for example 2 == 2L.
2740:             *
2741:             * @param left  a List
2742:             * @param right a List
2743:             * @return boolean   <code>true</code> if two Lists equals, <code>false</code> otherwise.
2744:             */
2745:            public static boolean equals(List left, List right) {
2746:                if (left == null) {
2747:                    return right == null;
2748:                } else if (right == null) {
2749:                    return false;
2750:                } else if (left.size() != right.size()) {
2751:                    return false;
2752:                } else {
2753:                    final NumberComparator numberComparator = new NumberComparator();
2754:                    final Iterator it1 = left.iterator(), it2 = right
2755:                            .iterator();
2756:
2757:                    while (it1.hasNext()) {
2758:                        final Object o1 = it1.next();
2759:                        final Object o2 = it2.next();
2760:
2761:                        if (o1 == null) {
2762:                            if (o2 != null)
2763:                                return false;
2764:                        } else {
2765:                            if (o1 instanceof  Number) {
2766:                                if (!(o2 instanceof  Number && numberComparator
2767:                                        .compare(o1, o2) == 0)) {
2768:                                    return false;
2769:                                }
2770:                            } else {
2771:                                // Use this way of calling equals in case the elament is a List
2772:                                // or any other type which has an equals in DGM
2773:                                if (!((Boolean) InvokerHelper.invokeMethod(o1,
2774:                                        "equals", new Object[] { o2 }))
2775:                                        .booleanValue())
2776:                                    return false;
2777:                            }
2778:                        }
2779:                    }
2780:
2781:                    return true;
2782:                }
2783:            }
2784:
2785:            /**
2786:             * Create a List composed of the elements of the first list minus the elements of the collection
2787:             *
2788:             * @param self     a List
2789:             * @param removeMe a Collection of elements to remove
2790:             * @return a List with the common elements removed
2791:             */
2792:            public static List minus(List self, Collection removeMe) {
2793:
2794:                if (self.size() == 0)
2795:                    return new ArrayList();
2796:
2797:                boolean nlgnSort = sameType(new Collection[] { self, removeMe });
2798:
2799:                //we can't use the same tactic as for intersection
2800:                //since AbstractCollection only does a remove on the first
2801:                //element it encounter.
2802:
2803:                Comparator numberComparator = new NumberComparator();
2804:
2805:                if (nlgnSort && (self.get(0) instanceof  Comparable)) {
2806:                    //n*LOG(n) version
2807:                    Set answer /* = null */;
2808:                    if (Number.class.isInstance(self.get(0))) {
2809:                        answer = new TreeSet(numberComparator);
2810:                        answer.addAll(self);
2811:                        for (Iterator it = self.iterator(); it.hasNext();) {
2812:                            Object o = it.next();
2813:                            if (Number.class.isInstance(o)) {
2814:                                for (Iterator it2 = removeMe.iterator(); it2
2815:                                        .hasNext();) {
2816:                                    Object o2 = it2.next();
2817:                                    if (Number.class.isInstance(o2)) {
2818:                                        if (numberComparator.compare(o, o2) == 0)
2819:                                            answer.remove(o);
2820:                                    }
2821:                                }
2822:                            } else {
2823:                                if (removeMe.contains(o))
2824:                                    answer.remove(o);
2825:                            }
2826:                        }
2827:                    } else {
2828:                        answer = new TreeSet(numberComparator);
2829:                        answer.addAll(self);
2830:                        answer.removeAll(removeMe);
2831:                    }
2832:
2833:                    List ansList = new ArrayList();
2834:                    for (Iterator it = self.iterator(); it.hasNext();) {
2835:                        Object o = it.next();
2836:                        if (answer.contains(o))
2837:                            ansList.add(o);
2838:                    }
2839:                    return ansList;
2840:                } else {
2841:                    //n*n version
2842:                    List tmpAnswer = new LinkedList(self);
2843:                    for (Iterator iter = tmpAnswer.iterator(); iter.hasNext();) {
2844:                        Object element = iter.next();
2845:                        //boolean removeElement = false;
2846:                        for (Iterator iterator = removeMe.iterator(); iterator
2847:                                .hasNext();) {
2848:                            Object elt = iterator.next();
2849:                            if (elt != null
2850:                                    && numberComparator.compare(element, elt) == 0) {
2851:                                iter.remove();
2852:                            }
2853:                        }
2854:                    }
2855:
2856:                    //remove duplicates
2857:                    //can't use treeset since the base classes are different
2858:                    return new ArrayList(tmpAnswer);
2859:                }
2860:            }
2861:
2862:            public static List minus(List self, Object operand) {
2863:                Comparator numberComparator = new NumberComparator();
2864:                List ansList = new ArrayList();
2865:                for (Iterator it = self.iterator(); it.hasNext();) {
2866:                    Object o = it.next();
2867:                    if (numberComparator.compare(o, operand) != 0)
2868:                        ansList.add(o);
2869:                }
2870:                return ansList;
2871:            }
2872:
2873:            /**
2874:             * Flatten a list
2875:             *
2876:             * @param self a List
2877:             * @return a flattened List
2878:             */
2879:            public static List flatten(List self) {
2880:                return new ArrayList(flatten(self, new LinkedList()));
2881:            }
2882:
2883:            /**
2884:             * Iterate over each element of the list in the reverse order.
2885:             *
2886:             * @param self    a List
2887:             * @param closure a closure
2888:             */
2889:            public static void reverseEach(List self, Closure closure) {
2890:                List reversed = reverse(self);
2891:                for (Iterator iter = reversed.iterator(); iter.hasNext();) {
2892:                    closure.call(iter.next());
2893:                }
2894:            }
2895:
2896:            private static List flatten(Collection elements, List addTo) {
2897:                Iterator iter = elements.iterator();
2898:                while (iter.hasNext()) {
2899:                    Object element = iter.next();
2900:                    if (element instanceof  Collection) {
2901:                        flatten((Collection) element, addTo);
2902:                    } else if (element instanceof  Map) {
2903:                        flatten(((Map) element).values(), addTo);
2904:                    } else {
2905:                        addTo.add(element);
2906:                    }
2907:                }
2908:                return addTo;
2909:            }
2910:
2911:            /**
2912:             * Overloads the left shift operator to provide an easy way to append objects to a list
2913:             *
2914:             * @param self  a Collection
2915:             * @param value an Object to be added to the collection.
2916:             * @return a Collection with an Object added to it.
2917:             */
2918:            public static Collection leftShift(Collection self, Object value) {
2919:                self.add(value);
2920:                return self;
2921:            }
2922:
2923:            /**
2924:             * Overloads the left shift operator to provide an easy way to append multiple
2925:             * objects as string representations to a String
2926:             *
2927:             * @param self  a String
2928:             * @param value an Obect
2929:             * @return a StringBuffer
2930:             */
2931:            public static StringBuffer leftShift(String self, Object value) {
2932:                return new StringBuffer(self).append(value);
2933:            }
2934:
2935:            protected static StringWriter createStringWriter(String self) {
2936:                StringWriter answer = new StringWriter();
2937:                answer.write(self);
2938:                return answer;
2939:            }
2940:
2941:            protected static StringBufferWriter createStringBufferWriter(
2942:                    StringBuffer self) {
2943:                return new StringBufferWriter(self);
2944:            }
2945:
2946:            /**
2947:             * Overloads the left shift operator to provide an easy way to append multiple
2948:             * objects as string representations to a StringBuffer
2949:             *
2950:             * @param self  a StringBuffer
2951:             * @param value a value to append
2952:             * @return a StringBuffer
2953:             */
2954:            public static StringBuffer leftShift(StringBuffer self, Object value) {
2955:                self.append(value);
2956:                return self;
2957:            }
2958:
2959:            /**
2960:             * Overloads the left shift operator to provide an append mechanism to add things to a writer
2961:             *
2962:             * @param self  a Writer
2963:             * @param value a value to append
2964:             * @return a StringWriter
2965:             */
2966:            public static Writer leftShift(Writer self, Object value)
2967:                    throws IOException {
2968:                InvokerHelper.write(self, value);
2969:                return self;
2970:            }
2971:
2972:            /**
2973:             * Implementation of the left shift operator for integral types.  Non integral
2974:             * Number types throw UnsupportedOperationException.
2975:             */
2976:            public static Number leftShift(Number left, Number right) {
2977:                return NumberMath.leftShift(left, right);
2978:            }
2979:
2980:            /**
2981:             * Implementation of the right shift operator for integral types.  Non integral
2982:             * Number types throw UnsupportedOperationException.
2983:             */
2984:            public static Number rightShift(Number left, Number right) {
2985:                return NumberMath.rightShift(left, right);
2986:            }
2987:
2988:            /**
2989:             * Implementation of the right shift (unsigned) operator for integral types.  Non integral
2990:             * Number types throw UnsupportedOperationException.
2991:             */
2992:            public static Number rightShiftUnsigned(Number left, Number right) {
2993:                return NumberMath.rightShiftUnsigned(left, right);
2994:            }
2995:
2996:            /**
2997:             * A helper method so that dynamic dispatch of the writer.write(object) method
2998:             * will always use the more efficient Writable.writeTo(writer) mechanism if the
2999:             * object implements the Writable interface.
3000:             *
3001:             * @param self     a Writer
3002:             * @param writable an object implementing the Writable interface
3003:             */
3004:            public static void write(Writer self, Writable writable)
3005:                    throws IOException {
3006:                writable.writeTo(self);
3007:            }
3008:
3009:            /**
3010:             * Overloads the left shift operator to provide an append mechanism to add things to a stream
3011:             *
3012:             * @param self  an OutputStream
3013:             * @param value a value to append
3014:             * @return a Writer
3015:             */
3016:            public static Writer leftShift(OutputStream self, Object value)
3017:                    throws IOException {
3018:                OutputStreamWriter writer = new FlushingStreamWriter(self);
3019:                leftShift(writer, value);
3020:                return writer;
3021:            }
3022:
3023:            /**
3024:             * Pipe an inputstream into an outputstream for efficient stream copying.
3025:             *
3026:             * @param self stream on which to write
3027:             * @param in   stream to read from
3028:             * @return the outputstream itself
3029:             * @throws IOException
3030:             */
3031:            public static OutputStream leftShift(OutputStream self,
3032:                    InputStream in) throws IOException {
3033:                byte[] buf = new byte[1024];
3034:                while (true) {
3035:                    int count = in.read(buf, 0, buf.length);
3036:                    if (count == -1)
3037:                        break;
3038:                    if (count == 0) {
3039:                        Thread.yield();
3040:                        continue;
3041:                    }
3042:                    self.write(buf, 0, count);
3043:                }
3044:                self.flush();
3045:                return self;
3046:            }
3047:
3048:            /**
3049:             * Overloads the left shift operator to provide an append mechanism to add bytes to a stream
3050:             *
3051:             * @param self  an OutputStream
3052:             * @param value a value to append
3053:             * @return an OutputStream
3054:             */
3055:            public static OutputStream leftShift(OutputStream self, byte[] value)
3056:                    throws IOException {
3057:                self.write(value);
3058:                self.flush();
3059:                return self;
3060:            }
3061:
3062:            private static boolean sameType(Collection[] cols) {
3063:                List all = new LinkedList();
3064:                for (int i = 0; i < cols.length; i++) {
3065:                    all.addAll(cols[i]);
3066:                }
3067:                if (all.size() == 0)
3068:                    return true;
3069:
3070:                Object first = all.get(0);
3071:
3072:                //trying to determine the base class of the collections
3073:                //special case for Numbers
3074:                Class baseClass;
3075:                if (first instanceof  Number) {
3076:                    baseClass = Number.class;
3077:                } else {
3078:                    baseClass = first.getClass();
3079:                }
3080:
3081:                for (int i = 0; i < cols.length; i++) {
3082:                    for (Iterator iter = cols[i].iterator(); iter.hasNext();) {
3083:                        if (!baseClass.isInstance(iter.next())) {
3084:                            return false;
3085:                        }
3086:                    }
3087:                }
3088:                return true;
3089:            }
3090:
3091:            // Primitive type array methods
3092:            //-------------------------------------------------------------------------
3093:
3094:            public static Object getAt(byte[] array, int idx) {
3095:                return primitiveArrayGet(array, idx);
3096:            }
3097:
3098:            public static Object getAt(char[] array, int idx) {
3099:                return primitiveArrayGet(array, idx);
3100:            }
3101:
3102:            public static Object getAt(short[] array, int idx) {
3103:                return primitiveArrayGet(array, idx);
3104:            }
3105:
3106:            public static Object getAt(int[] array, int idx) {
3107:                return primitiveArrayGet(array, idx);
3108:            }
3109:
3110:            public static Object getAt(long[] array, int idx) {
3111:                return primitiveArrayGet(array, idx);
3112:            }
3113:
3114:            public static Object getAt(float[] array, int idx) {
3115:                return primitiveArrayGet(array, idx);
3116:            }
3117:
3118:            public static Object getAt(double[] array, int idx) {
3119:                return primitiveArrayGet(array, idx);
3120:            }
3121:
3122:            public static Object getAt(boolean[] array, int idx) {
3123:                return primitiveArrayGet(array, idx);
3124:            }
3125:
3126:            public static Object getAt(byte[] array, Range range) {
3127:                return primitiveArrayGet(array, range);
3128:            }
3129:
3130:            public static Object getAt(char[] array, Range range) {
3131:                return primitiveArrayGet(array, range);
3132:            }
3133:
3134:            public static Object getAt(short[] array, Range range) {
3135:                return primitiveArrayGet(array, range);
3136:            }
3137:
3138:            public static Object getAt(int[] array, Range range) {
3139:                return primitiveArrayGet(array, range);
3140:            }
3141:
3142:            public static Object getAt(long[] array, Range range) {
3143:                return primitiveArrayGet(array, range);
3144:            }
3145:
3146:            public static Object getAt(float[] array, Range range) {
3147:                return primitiveArrayGet(array, range);
3148:            }
3149:
3150:            public static Object getAt(double[] array, Range range) {
3151:                return primitiveArrayGet(array, range);
3152:            }
3153:
3154:            public static Object getAt(boolean[] array, Range range) {
3155:                return primitiveArrayGet(array, range);
3156:            }
3157:
3158:            public static Object getAt(byte[] array, IntRange range) {
3159:                return primitiveArrayGet(array, range);
3160:            }
3161:
3162:            public static Object getAt(char[] array, IntRange range) {
3163:                return primitiveArrayGet(array, range);
3164:            }
3165:
3166:            public static Object getAt(short[] array, IntRange range) {
3167:                return primitiveArrayGet(array, range);
3168:            }
3169:
3170:            public static Object getAt(int[] array, IntRange range) {
3171:                return primitiveArrayGet(array, range);
3172:            }
3173:
3174:            public static Object getAt(long[] array, IntRange range) {
3175:                return primitiveArrayGet(array, range);
3176:            }
3177:
3178:            public static Object getAt(float[] array, IntRange range) {
3179:                return primitiveArrayGet(array, range);
3180:            }
3181:
3182:            public static Object getAt(double[] array, IntRange range) {
3183:                return primitiveArrayGet(array, range);
3184:            }
3185:
3186:            public static Object getAt(boolean[] array, IntRange range) {
3187:                return primitiveArrayGet(array, range);
3188:            }
3189:
3190:            public static Object getAt(byte[] array, ObjectRange range) {
3191:                return primitiveArrayGet(array, range);
3192:            }
3193:
3194:            public static Object getAt(char[] array, ObjectRange range) {
3195:                return primitiveArrayGet(array, range);
3196:            }
3197:
3198:            public static Object getAt(short[] array, ObjectRange range) {
3199:                return primitiveArrayGet(array, range);
3200:            }
3201:
3202:            public static Object getAt(int[] array, ObjectRange range) {
3203:                return primitiveArrayGet(array, range);
3204:            }
3205:
3206:            public static Object getAt(long[] array, ObjectRange range) {
3207:                return primitiveArrayGet(array, range);
3208:            }
3209:
3210:            public static Object getAt(float[] array, ObjectRange range) {
3211:                return primitiveArrayGet(array, range);
3212:            }
3213:
3214:            public static Object getAt(double[] array, ObjectRange range) {
3215:                return primitiveArrayGet(array, range);
3216:            }
3217:
3218:            public static Object getAt(boolean[] array, ObjectRange range) {
3219:                return primitiveArrayGet(array, range);
3220:            }
3221:
3222:            public static Object getAt(byte[] array, Collection indices) {
3223:                return primitiveArrayGet(array, indices);
3224:            }
3225:
3226:            public static Object getAt(char[] array, Collection indices) {
3227:                return primitiveArrayGet(array, indices);
3228:            }
3229:
3230:            public static Object getAt(short[] array, Collection indices) {
3231:                return primitiveArrayGet(array, indices);
3232:            }
3233:
3234:            public static Object getAt(int[] array, Collection indices) {
3235:                return primitiveArrayGet(array, indices);
3236:            }
3237:
3238:            public static Object getAt(long[] array, Collection indices) {
3239:                return primitiveArrayGet(array, indices);
3240:            }
3241:
3242:            public static Object getAt(float[] array, Collection indices) {
3243:                return primitiveArrayGet(array, indices);
3244:            }
3245:
3246:            public static Object getAt(double[] array, Collection indices) {
3247:                return primitiveArrayGet(array, indices);
3248:            }
3249:
3250:            public static Object getAt(boolean[] array, Collection indices) {
3251:                return primitiveArrayGet(array, indices);
3252:            }
3253:
3254:            public static void putAt(boolean[] array, int idx, Boolean newValue) {
3255:                primitiveArrayPut(array, idx, newValue);
3256:            }
3257:
3258:            public static void putAt(byte[] array, int idx, Object newValue) {
3259:                if (!(newValue instanceof  Byte)) {
3260:                    Number n = (Number) newValue;
3261:                    newValue = new Byte(n.byteValue());
3262:                }
3263:                primitiveArrayPut(array, idx, newValue);
3264:            }
3265:
3266:            public static void putAt(char[] array, int idx, Object newValue) {
3267:                if (newValue instanceof  String) {
3268:                    String s = (String) newValue;
3269:                    if (s.length() != 1)
3270:                        throw new IllegalArgumentException(
3271:                                "String of length 1 expected but got a bigger one");
3272:                    char c = s.charAt(0);
3273:                    newValue = new Character(c);
3274:                }
3275:                primitiveArrayPut(array, idx, newValue);
3276:            }
3277:
3278:            public static void putAt(short[] array, int idx, Object newValue) {
3279:                if (!(newValue instanceof  Short)) {
3280:                    Number n = (Number) newValue;
3281:                    newValue = new Short(n.shortValue());
3282:                }
3283:                primitiveArrayPut(array, idx, newValue);
3284:            }
3285:
3286:            public static void putAt(int[] array, int idx, Object newValue) {
3287:                if (!(newValue instanceof  Integer)) {
3288:                    Number n = (Number) newValue;
3289:                    newValue = new Integer(n.intValue());
3290:                }
3291:                primitiveArrayPut(array, idx, newValue);
3292:            }
3293:
3294:            public static void putAt(long[] array, int idx, Object newValue) {
3295:                if (!(newValue instanceof  Long)) {
3296:                    Number n = (Number) newValue;
3297:                    newValue = new Long(n.longValue());
3298:                }
3299:                primitiveArrayPut(array, idx, newValue);
3300:            }
3301:
3302:            public static void putAt(float[] array, int idx, Object newValue) {
3303:                if (!(newValue instanceof  Float)) {
3304:                    Number n = (Number) newValue;
3305:                    newValue = new Float(n.floatValue());
3306:                }
3307:                primitiveArrayPut(array, idx, newValue);
3308:            }
3309:
3310:            public static void putAt(double[] array, int idx, Object newValue) {
3311:                if (!(newValue instanceof  Double)) {
3312:                    Number n = (Number) newValue;
3313:                    newValue = new Double(n.doubleValue());
3314:                }
3315:                primitiveArrayPut(array, idx, newValue);
3316:            }
3317:
3318:            public static int size(byte[] array) {
3319:                return Array.getLength(array);
3320:            }
3321:
3322:            public static int size(char[] array) {
3323:                return Array.getLength(array);
3324:            }
3325:
3326:            public static int size(short[] array) {
3327:                return Array.getLength(array);
3328:            }
3329:
3330:            public static int size(int[] array) {
3331:                return Array.getLength(array);
3332:            }
3333:
3334:            public static int size(long[] array) {
3335:                return Array.getLength(array);
3336:            }
3337:
3338:            public static int size(float[] array) {
3339:                return Array.getLength(array);
3340:            }
3341:
3342:            public static int size(double[] array) {
3343:                return Array.getLength(array);
3344:            }
3345:
3346:            public static List toList(byte[] array) {
3347:                return DefaultTypeTransformation.primitiveArrayToList(array);
3348:            }
3349:
3350:            public static List toList(char[] array) {
3351:                return DefaultTypeTransformation.primitiveArrayToList(array);
3352:            }
3353:
3354:            public static List toList(short[] array) {
3355:                return DefaultTypeTransformation.primitiveArrayToList(array);
3356:            }
3357:
3358:            public static List toList(int[] array) {
3359:                return DefaultTypeTransformation.primitiveArrayToList(array);
3360:            }
3361:
3362:            public static List toList(long[] array) {
3363:                return DefaultTypeTransformation.primitiveArrayToList(array);
3364:            }
3365:
3366:            public static List toList(float[] array) {
3367:                return DefaultTypeTransformation.primitiveArrayToList(array);
3368:            }
3369:
3370:            public static List toList(double[] array) {
3371:                return DefaultTypeTransformation.primitiveArrayToList(array);
3372:            }
3373:
3374:            private static final char[] tTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
3375:                    .toCharArray();
3376:
3377:            public static Writable encodeBase64(Byte[] data) {
3378:                return encodeBase64(DefaultTypeTransformation
3379:                        .convertToByteArray(data));
3380:            }
3381:
3382:            /**
3383:             * Produce a Writable object which writes the base64 encoding of the byte array
3384:             * Calling toString() on the result rerurns the encoding as a String
3385:             *
3386:             * @param data byte array to be encoded
3387:             * @return object which will write the base64 encoding of the byte array
3388:             */
3389:            public static Writable encodeBase64(final byte[] data) {
3390:                return new Writable() {
3391:                    public Writer writeTo(final Writer writer)
3392:                            throws IOException {
3393:                        int charCount = 0;
3394:                        final int dLimit = (data.length / 3) * 3;
3395:
3396:                        for (int dIndex = 0; dIndex != dLimit; dIndex += 3) {
3397:                            int d = ((data[dIndex] & 0XFF) << 16)
3398:                                    | ((data[dIndex + 1] & 0XFF) << 8)
3399:                                    | (data[dIndex + 2] & 0XFF);
3400:
3401:                            writer.write(tTable[d >> 18]);
3402:                            writer.write(tTable[(d >> 12) & 0X3F]);
3403:                            writer.write(tTable[(d >> 6) & 0X3F]);
3404:                            writer.write(tTable[d & 0X3F]);
3405:
3406:                            if (++charCount == 18) {
3407:                                writer.write('\n');
3408:                                charCount = 0;
3409:                            }
3410:                        }
3411:
3412:                        if (dLimit != data.length) {
3413:                            int d = (data[dLimit] & 0XFF) << 16;
3414:
3415:                            if (dLimit + 1 != data.length) {
3416:                                d |= (data[dLimit + 1] & 0XFF) << 8;
3417:                            }
3418:
3419:                            writer.write(tTable[d >> 18]);
3420:                            writer.write(tTable[(d >> 12) & 0X3F]);
3421:                            writer
3422:                                    .write((dLimit + 1 < data.length) ? tTable[(d >> 6) & 0X3F]
3423:                                            : '=');
3424:                            writer.write('=');
3425:                        }
3426:
3427:                        return writer;
3428:                    }
3429:
3430:                    public String toString() {
3431:                        StringWriter buffer = new StringWriter();
3432:
3433:                        try {
3434:                            writeTo(buffer);
3435:                        } catch (IOException e) {
3436:                            throw new StringWriterIOException(e);
3437:                        }
3438:
3439:                        return buffer.toString();
3440:                    }
3441:                };
3442:            }
3443:
3444:            private static final byte[] translateTable = (
3445:            //
3446:            "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
3447:            //                    \t    \n                \r
3448:                    + "\u0042\u0042\u0041\u0041\u0042\u0042\u0041\u0042"
3449:                    //
3450:                    + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
3451:                    //
3452:                    + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
3453:                    //        sp    !     "     #     $     %     &     '
3454:                    + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
3455:                    //         (    )     *     +     ,     -     .     /
3456:                    + "\u0042\u0042\u0042\u003E\u0042\u0042\u0042\u003F"
3457:                    //         0    1     2     3     4     5     6     7
3458:                    + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
3459:                    //         8    9     :     ;     <     =     >     ?
3460:                    + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
3461:                    //         @    A     B     C     D     E     F     G
3462:                    + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
3463:                    //         H    I   J K   L     M   N   O
3464:                    + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
3465:                    //         P    Q     R     S     T     U     V    W
3466:                    + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
3467:                    //         X    Y     Z     [     \     ]     ^    _
3468:                    + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u0042"
3469:                    //         '    a     b     c     d     e     f     g
3470:                    + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
3471:                    //        h   i   j     k     l     m     n     o    p
3472:                    + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
3473:                    //        p     q     r     s     t     u     v     w
3474:                    + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
3475:                    //        x     y     z
3476:                    + "\u0031\u0032\u0033").getBytes();
3477:
3478:            /**
3479:             * Decode the Sting from base64 into a byte array
3480:             *
3481:             * @param value the string to be decoded
3482:             * @return the decoded bytes as an array
3483:             */
3484:            public static byte[] decodeBase64(String value) {
3485:                int byteShift = 4;
3486:                int tmp = 0;
3487:                boolean done = false;
3488:                final StringBuffer buffer = new StringBuffer();
3489:
3490:                for (int i = 0; i != value.length(); i++) {
3491:                    final char c = value.charAt(i);
3492:                    final int sixBit = (c < 123) ? translateTable[c] : 66;
3493:
3494:                    if (sixBit < 64) {
3495:                        if (done)
3496:                            throw new RuntimeException(
3497:                                    "= character not at end of base64 value"); // TODO: change this exception type
3498:
3499:                        tmp = (tmp << 6) | sixBit;
3500:
3501:                        if (byteShift-- != 4) {
3502:                            buffer
3503:                                    .append((char) ((tmp >> (byteShift * 2)) & 0XFF));
3504:                        }
3505:
3506:                    } else if (sixBit == 64) {
3507:
3508:                        byteShift--;
3509:                        done = true;
3510:
3511:                    } else if (sixBit == 66) {
3512:                        // RFC 2045 says that I'm allowed to take the presence of
3513:                        // these characters as evedence of data corruption
3514:                        // So I will
3515:                        throw new RuntimeException(
3516:                                "bad character in base64 value"); // TODO: change this exception type
3517:                    }
3518:
3519:                    if (byteShift == 0)
3520:                        byteShift = 4;
3521:                }
3522:
3523:                try {
3524:                    return buffer.toString().getBytes("ISO-8859-1");
3525:                } catch (UnsupportedEncodingException e) {
3526:                    throw new RuntimeException(
3527:                            "Base 64 decode produced byte values > 255"); // TODO: change this exception type
3528:                }
3529:            }
3530:
3531:            /**
3532:             * Implements the getAt(int) method for primitve type arrays
3533:             */
3534:            protected static Object primitiveArrayGet(Object array, int idx) {
3535:                return Array.get(array, normaliseIndex(idx, Array
3536:                        .getLength(array)));
3537:            }
3538:
3539:            /**
3540:             * Implements the getAt(Range) method for primitve type arrays
3541:             */
3542:            protected static List primitiveArrayGet(Object array, Range range) {
3543:                List answer = new ArrayList();
3544:                for (Iterator iter = range.iterator(); iter.hasNext();) {
3545:                    int idx = DefaultTypeTransformation.intUnbox(iter.next());
3546:                    answer.add(primitiveArrayGet(array, idx));
3547:                }
3548:                return answer;
3549:            }
3550:
3551:            /**
3552:             * Implements the getAt(Collection) method for primitve type arrays
3553:             */
3554:            protected static List primitiveArrayGet(Object self,
3555:                    Collection indices) {
3556:                List answer = new ArrayList();
3557:                for (Iterator iter = indices.iterator(); iter.hasNext();) {
3558:                    Object value = iter.next();
3559:                    if (value instanceof  Range) {
3560:                        answer.addAll(primitiveArrayGet(self, (Range) value));
3561:                    } else if (value instanceof  List) {
3562:                        answer.addAll(primitiveArrayGet(self, (List) value));
3563:                    } else {
3564:                        int idx = DefaultTypeTransformation.intUnbox(value);
3565:                        answer.add(primitiveArrayGet(self, idx));
3566:                    }
3567:                }
3568:                return answer;
3569:            }
3570:
3571:            /**
3572:             * Implements the set(int idx) method for primitve type arrays
3573:             */
3574:            protected static void primitiveArrayPut(Object array, int idx,
3575:                    Object newValue) {
3576:                Array.set(array, normaliseIndex(idx, Array.getLength(array)),
3577:                        newValue);
3578:            }
3579:
3580:            // String methods
3581:            //-------------------------------------------------------------------------
3582:
3583:            /**
3584:             * Converts the given string into a Character object
3585:             * using the first character in the string
3586:             *
3587:             * @param self a String
3588:             * @return the first Character
3589:             */
3590:            public static Character toCharacter(String self) {
3591:                /** @todo use cache? */
3592:                return new Character(self.charAt(0));
3593:            }
3594:
3595:            /**
3596:             * Converts the given string into a Boolean object
3597:             * If the trimmed string is "true", "y" or "1" (ignoring case)
3598:             * then the result is true othewrwise it is false
3599:             *
3600:             * @param self a String
3601:             * @return The Boolean value
3602:             */
3603:            public static Boolean toBoolean(String self) {
3604:                final String trimmed = self.trim();
3605:
3606:                if ("true".equalsIgnoreCase(trimmed)
3607:                        || "y".equalsIgnoreCase(trimmed) || "1".equals(trimmed)) {
3608:                    return Boolean.TRUE;
3609:                } else {
3610:                    return Boolean.FALSE;
3611:                }
3612:            }
3613:
3614:            /**
3615:             * Tokenize a String
3616:             *
3617:             * @param self  a String
3618:             * @param token the delimiter
3619:             * @return a List of tokens
3620:             */
3621:            public static List tokenize(String self, String token) {
3622:                return InvokerHelper.asList(new StringTokenizer(self, token));
3623:            }
3624:
3625:            /**
3626:             * Tokenize a String (with a whitespace as delimiter)
3627:             *
3628:             * @param self a String
3629:             * @return a List of tokens
3630:             */
3631:            public static List tokenize(String self) {
3632:                return InvokerHelper.asList(new StringTokenizer(self));
3633:            }
3634:
3635:            /**
3636:             * Appends a String
3637:             *
3638:             * @param left  a String
3639:             * @param value any Object
3640:             * @return a String
3641:             */
3642:            public static String plus(String left, Object value) {
3643:                return left + toString(value);
3644:            }
3645:
3646:            /**
3647:             * Appends a String
3648:             *
3649:             * @param value a Number
3650:             * @param right a String
3651:             * @return a String
3652:             */
3653:            public static String plus(Number value, String right) {
3654:                return toString(value) + right;
3655:            }
3656:
3657:            /**
3658:             * Appends a String
3659:             *
3660:             * @param left  a StringBuffer
3661:             * @param value a String
3662:             * @return a String
3663:             */
3664:            public static String plus(StringBuffer left, String value) {
3665:                return left + value;
3666:            }
3667:
3668:            /**
3669:             * Remove a part of a String
3670:             *
3671:             * @param left  a String
3672:             * @param value a String part to remove
3673:             * @return a String minus the part to be removed
3674:             */
3675:            public static String minus(String left, Object value) {
3676:                String text = toString(value);
3677:                return left.replaceFirst(text, "");
3678:            }
3679:
3680:            /**
3681:             * Provide an implementation of contains() like Collection to make Strings more polymorphic
3682:             * This method is not required on JDK 1.5 onwards
3683:             *
3684:             * @param self a String
3685:             * @param text a String to look for
3686:             * @return true if this string contains the given text
3687:             */
3688:            public static boolean contains(String self, String text) {
3689:                int idx = self.indexOf(text);
3690:                return idx >= 0;
3691:            }
3692:
3693:            /**
3694:             * Count the number of occurencies of a substring
3695:             *
3696:             * @param self a String
3697:             * @param text a substring
3698:             * @return the number of occurrencies of the given string inside this String
3699:             */
3700:            public static int count(String self, String text) {
3701:                int answer = 0;
3702:                for (int idx = 0; true; idx++) {
3703:                    idx = self.indexOf(text, idx);
3704:                    if (idx >= 0) {
3705:                        ++answer;
3706:                    } else {
3707:                        break;
3708:                    }
3709:                }
3710:                return answer;
3711:            }
3712:
3713:            /**
3714:             * This method is called by the ++ operator for the class String.
3715:             * It increments the last character in the given string. If the
3716:             * character in the string is Character.MAX_VALUE a Character.MIN_VALUE
3717:             * will be appended. The empty string is incremented to a string
3718:             * consisting of the character Character.MIN_VALUE.
3719:             *
3720:             * @param self a String
3721:             * @return an incremented String
3722:             */
3723:            public static String next(String self) {
3724:                StringBuffer buffer = new StringBuffer(self);
3725:                if (buffer.length() == 0) {
3726:                    buffer.append(Character.MIN_VALUE);
3727:                } else {
3728:                    char last = buffer.charAt(buffer.length() - 1);
3729:                    if (last == Character.MAX_VALUE) {
3730:                        buffer.append(Character.MIN_VALUE);
3731:                    } else {
3732:                        char next = last;
3733:                        next++;
3734:                        buffer.setCharAt(buffer.length() - 1, next);
3735:                    }
3736:                }
3737:                return buffer.toString();
3738:            }
3739:
3740:            /**
3741:             * This method is called by the -- operator for the class String.
3742:             * It decrements the last character in the given string. If the
3743:             * character in the string is Character.MIN_VALUE it will be deleted.
3744:             * The empty string can't be decremented.
3745:             *
3746:             * @param self a String
3747:             * @return a String with a decremented digit at the end
3748:             */
3749:            public static String previous(String self) {
3750:                StringBuffer buffer = new StringBuffer(self);
3751:                if (buffer.length() == 0)
3752:                    throw new IllegalArgumentException("the string is empty");
3753:                char last = buffer.charAt(buffer.length() - 1);
3754:                if (last == Character.MIN_VALUE) {
3755:                    buffer.deleteCharAt(buffer.length() - 1);
3756:                } else {
3757:                    char next = last;
3758:                    next--;
3759:                    buffer.setCharAt(buffer.length() - 1, next);
3760:                }
3761:                return buffer.toString();
3762:            }
3763:
3764:            /**
3765:             * Executes the given string as a command line process. For more control
3766:             * over the process mechanism in JDK 1.5 you can use java.lang.ProcessBuilder.
3767:             *
3768:             * @param self a command line String
3769:             * @return the Process which has just started for this command line string
3770:             */
3771:            public static Process execute(String self) throws IOException {
3772:                return Runtime.getRuntime().exec(self);
3773:            }
3774:
3775:            /**
3776:             * Executes the command specified by the <code>String</code> array that is the parameter.
3777:             * The first item in the array is the command the others are the parameters. For more
3778:             * control over the process mechanism in JDK 1.5 you can use
3779:             * <code>java.lang.ProcessBuilder</code>.
3780:             *
3781:             * @param commandArray an array of <code>String<code> containing the command name and
3782:             *                     parameters as separate items in the array.
3783:             * @return the Process which has just started for this command line string.
3784:             */
3785:            public static Process execute(String[] commandArray)
3786:                    throws IOException {
3787:                return Runtime.getRuntime().exec(commandArray);
3788:            }
3789:
3790:            /**
3791:             * Executes the command specified by the <code>self</code> with environments <code>envp</code>
3792:             * under the working directory <code>dir</code>.
3793:             * For more control over the process mechanism in JDK 1.5 you can use <code>java.lang.ProcessBuilder</code>.
3794:             *
3795:             * @param self a command line String to be executed.
3796:             * @param envp an array of Strings, each element of which
3797:             *             has environment variable settings in the format
3798:             *             <i>name</i>=<i>value</i>, or
3799:             *             <tt>null</tt> if the subprocess should inherit
3800:             *             the environment of the current process.
3801:             * @param dir  the working directory of the subprocess, or
3802:             *             <tt>null</tt> if the subprocess should inherit
3803:             *             the working directory of the current process.
3804:             * @return the Process which has just started for this command line string.
3805:             */
3806:            public static Process execute(String self, final String[] envp,
3807:                    File dir) throws IOException {
3808:                return Runtime.getRuntime().exec(self, envp, dir);
3809:            }
3810:
3811:            /**
3812:             * Executes the command specified by the <code>String</code> list that is the parameter.
3813:             * The first item in the array is the command the others are the parameters. All entries
3814:             * must be <code>String</code>s.  For more control over the process mechanism in JDK 1.5 you
3815:             * can use <code>java.lang.ProcessBuilder</code>.
3816:             *
3817:             * @param commandList a list of <code>String<code> containing the command name and
3818:             *                    parameters as separate items in the list.
3819:             * @return the Process which has just started for this command line string.
3820:             */
3821:            public static Process execute(List commandList) throws IOException {
3822:                final String[] commandArray = new String[commandList.size()];
3823:                Iterator it = commandList.iterator();
3824:                for (int i = 0; it.hasNext(); ++i) {
3825:                    commandArray[i] = it.next().toString();
3826:                }
3827:                return execute(commandArray);
3828:            }
3829:
3830:            /**
3831:             * Executes the command specified by the <code>self</code> with environments <code>envp</code>
3832:             * under the working directory <code>dir</code>.
3833:             * For more control over the process mechanism in JDK 1.5 you can use <code>java.lang.ProcessBuilder</code>.
3834:             *
3835:             * @param self a command line String to be executed.
3836:             * @param envp a List of Strings, each member of which
3837:             *             has environment variable settings in the format
3838:             *             <i>name</i>=<i>value</i>, or
3839:             *             <tt>null</tt> if the subprocess should inherit
3840:             *             the environment of the current process.
3841:             * @param dir  the working directory of the subprocess, or
3842:             *             <tt>null</tt> if the subprocess should inherit
3843:             *             the working directory of the current process.
3844:             * @return the Process which has just started for this command line string.
3845:             */
3846:            public static Process execute(String self, List envp, File dir)
3847:                    throws IOException {
3848:                if (envp == null) {
3849:                    return execute(self, (String[]) null, dir);
3850:                }
3851:                String[] commandArray = new String[envp.size()];
3852:                if (envp != null) {
3853:                    Iterator it = envp.iterator();
3854:                    for (int i = 0; it.hasNext(); ++i) {
3855:                        commandArray[i] = it.next().toString();
3856:                    }
3857:                } else {
3858:                    commandArray = null;
3859:                }
3860:                return execute(self, commandArray, dir);
3861:            }
3862:
3863:            /**
3864:             * Repeat a String a certain number of times
3865:             *
3866:             * @param self   a String to be repeated
3867:             * @param factor the number of times the String should be repeated
3868:             * @return a String composed of a repeatition
3869:             * @throws IllegalArgumentException if the number of repeatition is &lt; 0
3870:             */
3871:            public static String multiply(String self, Number factor) {
3872:                int size = factor.intValue();
3873:                if (size == 0)
3874:                    return "";
3875:                else if (size < 0) {
3876:                    throw new IllegalArgumentException(
3877:                            "multiply() should be called with a number of 0 or greater not: "
3878:                                    + size);
3879:                }
3880:                StringBuffer answer = new StringBuffer(self);
3881:                for (int i = 1; i < size; i++) {
3882:                    answer.append(self);
3883:                }
3884:                return answer.toString();
3885:            }
3886:
3887:            /**
3888:             * Returns the string representation of the given map with bracket boundaries.
3889:             *
3890:             * @param self a Map
3891:             * @return the string representation
3892:             */
3893:            public static String toString(Map self) {
3894:                return toMapString(self);
3895:            }
3896:
3897:            /**
3898:             * Returns the string representation of the given map with bracket boundaries.
3899:             *
3900:             * @param self a Map
3901:             * @return the string representation
3902:             */
3903:            public static String toMapString(Map self) {
3904:                return (self == null) ? "null" : InvokerHelper
3905:                        .toMapString(self);
3906:            }
3907:
3908:            /**
3909:             * Returns the string representation of the given collection with the bracket boundaries.
3910:             *
3911:             * @param self a Collection
3912:             * @return the string representation
3913:             */
3914:            public static String toString(Collection self) {
3915:                return toListString(self);
3916:            }
3917:
3918:            /**
3919:             * Returns the string representation of the given collection with the bracket boundaries.
3920:             *
3921:             * @param self a Collection
3922:             * @return the string representation
3923:             */
3924:            public static String toListString(Collection self) {
3925:                return (self == null) ? "null" : InvokerHelper
3926:                        .toListString(self);
3927:            }
3928:
3929:            /**
3930:             * Returns the string representation of the given array with the brace boundaries.
3931:             *
3932:             * @param self an Object[]
3933:             * @return the string representation
3934:             */
3935:            public static String toString(Object[] self) {
3936:                return toArrayString(self);
3937:            }
3938:
3939:            /**
3940:             * Returns the string representation of the given array with the brace boundaries.
3941:             *
3942:             * @param self an Object[]
3943:             * @return the string representation
3944:             */
3945:            public static String toArrayString(Object[] self) {
3946:                return (self == null) ? "null" : InvokerHelper
3947:                        .toArrayString(self);
3948:            }
3949:
3950:            protected static String toString(Object value) {
3951:                if (value instanceof  Map)
3952:                    return toMapString((Map) value);
3953:                else if (value instanceof  Collection)
3954:                    return toListString((Collection) value);
3955:                else if (value instanceof  Object[])
3956:                    return toArrayString((Object[]) value);
3957:                return (value == null) ? "null" : value.toString();
3958:            }
3959:
3960:            // Number based methods
3961:            //-------------------------------------------------------------------------
3962:
3963:            /**
3964:             * Increment a Character by one
3965:             *
3966:             * @param self a Character
3967:             * @return an incremented Number
3968:             */
3969:            public static Number next(Character self) {
3970:                return plus(self, ONE);
3971:            }
3972:
3973:            /**
3974:             * Increment a Number by one
3975:             *
3976:             * @param self a Number
3977:             * @return an incremented Number
3978:             */
3979:            public static Number next(Number self) {
3980:                return plus(self, ONE);
3981:            }
3982:
3983:            /**
3984:             * Decrement a Character by one
3985:             *
3986:             * @param self a Character
3987:             * @return a decremented Number
3988:             */
3989:            public static Number previous(Character self) {
3990:                return minus(self, ONE);
3991:            }
3992:
3993:            /**
3994:             * Decrement a Number by one
3995:             *
3996:             * @param self a Number
3997:             * @return a decremented Number
3998:             */
3999:            public static Number previous(Number self) {
4000:                return minus(self, ONE);
4001:            }
4002:
4003:            /**
4004:             * Add a Character and a Number
4005:             *
4006:             * @param left  a Character
4007:             * @param right a Number
4008:             * @return the addition of the Character and the Number
4009:             */
4010:            public static Number plus(Character left, Number right) {
4011:                return plus(new Integer(left.charValue()), right);
4012:            }
4013:
4014:            /**
4015:             * Add a Number and a Character
4016:             *
4017:             * @param left  a Number
4018:             * @param right a Character
4019:             * @return the addition of the Character and the Number
4020:             */
4021:            public static Number plus(Number left, Character right) {
4022:                return plus(left, new Integer(right.charValue()));
4023:            }
4024:
4025:            /**
4026:             * Add two Characters
4027:             *
4028:             * @param left  a Character
4029:             * @param right a Character
4030:             * @return the addition of both Characters
4031:             */
4032:            public static Number plus(Character left, Character right) {
4033:                return plus(new Integer(left.charValue()), right);
4034:            }
4035:
4036:            /**
4037:             * Add two numbers and return the result.
4038:             *
4039:             * @param left  a Number
4040:             * @param right another Number to add
4041:             * @return the addition of both Numbers
4042:             */
4043:            public static Number plus(Number left, Number right) {
4044:                return NumberMath.add(left, right);
4045:            }
4046:
4047:            /**
4048:             * Compare a Character and a Number
4049:             *
4050:             * @param left  a Character
4051:             * @param right a Number
4052:             * @return the result of the comparison
4053:             */
4054:            public static int compareTo(Character left, Number right) {
4055:                return compareTo(new Integer(left.charValue()), right);
4056:            }
4057:
4058:            /**
4059:             * Compare a Number and a Character
4060:             *
4061:             * @param left  a Number
4062:             * @param right a Character
4063:             * @return the result of the comparison
4064:             */
4065:            public static int compareTo(Number left, Character right) {
4066:                return compareTo(left, new Integer(right.charValue()));
4067:            }
4068:
4069:            /**
4070:             * Compare two Characters
4071:             *
4072:             * @param left  a Character
4073:             * @param right a Character
4074:             * @return the result of the comparison
4075:             */
4076:            public static int compareTo(Character left, Character right) {
4077:                return compareTo(new Integer(left.charValue()), right);
4078:            }
4079:
4080:            /**
4081:             * Compare two Numbers
4082:             *
4083:             * @param left  a Number
4084:             * @param right another Number to compare to
4085:             * @return the comparision of both numbers
4086:             */
4087:            public static int compareTo(Number left, Number right) {
4088:                /** @todo maybe a double dispatch thing to handle new large numbers? */
4089:                return NumberMath.compareTo(left, right);
4090:            }
4091:
4092:            /**
4093:             * Subtract a Number from a Character
4094:             *
4095:             * @param left  a Character
4096:             * @param right a Number
4097:             * @return the addition of the Character and the Number
4098:             */
4099:            public static Number minus(Character left, Number right) {
4100:                return minus(new Integer(left.charValue()), right);
4101:            }
4102:
4103:            /**
4104:             * Subtract a Character from a Number
4105:             *
4106:             * @param left  a Number
4107:             * @param right a Character
4108:             * @return the addition of the Character and the Number
4109:             */
4110:            public static Number minus(Number left, Character right) {
4111:                return minus(left, new Integer(right.charValue()));
4112:            }
4113:
4114:            /**
4115:             * Subtraction two Characters
4116:             *
4117:             * @param left  a Character
4118:             * @param right a Character
4119:             * @return the addition of both Characters
4120:             */
4121:            public static Number minus(Character left, Character right) {
4122:                return minus(new Integer(left.charValue()), right);
4123:            }
4124:
4125:            /**
4126:             * Substraction of two Numbers
4127:             *
4128:             * @param left  a Number
4129:             * @param right another Number to substract to the first one
4130:             * @return the substraction
4131:             */
4132:            public static Number minus(Number left, Number right) {
4133:                return NumberMath.subtract(left, right);
4134:            }
4135:
4136:            /**
4137:             * Multiply a Character by a Number
4138:             *
4139:             * @param left  a Character
4140:             * @param right a Number
4141:             * @return the multiplication of both
4142:             */
4143:            public static Number multiply(Character left, Number right) {
4144:                return multiply(new Integer(left.charValue()), right);
4145:            }
4146:
4147:            /**
4148:             * Multiply a Number by a Character
4149:             *
4150:             * @param left  a Number
4151:             * @param right a Character
4152:             * @return the multiplication of both
4153:             */
4154:            public static Number multiply(Number left, Character right) {
4155:                return multiply(left, new Integer(right.charValue()));
4156:            }
4157:
4158:            /**
4159:             * Multiply two Characters
4160:             *
4161:             * @param left  a Character
4162:             * @param right another Character
4163:             * @return the multiplication of both
4164:             */
4165:            public static Number multiply(Character left, Character right) {
4166:                return multiply(new Integer(left.charValue()), right);
4167:            }
4168:
4169:            /**
4170:             * Multiply two Numbers
4171:             *
4172:             * @param left  a Number
4173:             * @param right another Number
4174:             * @return the multiplication of both
4175:             */
4176:            //Note:  This method is NOT called if left AND right are both BigIntegers or BigDecimals because
4177:            //those classes implement a method with a better exact match.
4178:            public static Number multiply(Number left, Number right) {
4179:                return NumberMath.multiply(left, right);
4180:            }
4181:
4182:            /**
4183:             * Multiply a BigDecimal and a Double.
4184:             * Note: This method was added to enforce the Groovy rule of
4185:             * BigDecimal*Double == Double. Without this method, the
4186:             * multiply(BigDecimal) method in BigDecimal would respond
4187:             * and return a BigDecimal instead. Since BigDecimal is prefered
4188:             * over Number, the Number*Number method is not choosen as in older
4189:             * versions of Groovy. 
4190:             *
4191:             * @param left  a BigDecimal
4192:             * @param right a Double
4193:             * @return the multiplication of both
4194:             */
4195:            public static Number multiply(BigDecimal left, Double right) {
4196:                return NumberMath.multiply(left, right);
4197:            }
4198:
4199:            /**
4200:             * Multiply a BigDecimal and a BigInteger.
4201:             * Note: This method was added to enforce the Groovy rule of
4202:             * BigDecimal*long == long. Without this method, the
4203:             * multiply(BigDecimal) method in BigDecimal would respond
4204:             * and return a BigDecimal instead. Since BigDecimal is prefered
4205:             * over Number, the Number*Number method is not choosen as in older
4206:             * versions of Groovy. Biginteger is the fallback for all integer
4207:             * types in Groovy
4208:             *
4209:             * @param left  a BigDecimal
4210:             * @param right a BigInteger
4211:             * @return the multiplication of both
4212:             */
4213:            public static Number multiply(BigDecimal left, BigInteger right) {
4214:                return NumberMath.multiply(left, right);
4215:            }
4216:
4217:            /**
4218:             * Power of a Number to a certain exponent
4219:             *
4220:             * @param self     a Number
4221:             * @param exponent a Number exponent
4222:             * @return a Number to the power of a certain exponent
4223:             */
4224:            public static Number power(Number self, Number exponent) {
4225:                double base, exp, answer;
4226:                base = self.doubleValue();
4227:                exp = exponent.doubleValue();
4228:
4229:                answer = Math.pow(base, exp);
4230:                if ((double) ((int) answer) == answer) {
4231:                    return new Integer((int) answer);
4232:                } else if ((double) ((long) answer) == answer) {
4233:                    return new Long((long) answer);
4234:                } else {
4235:                    return new Double(answer);
4236:                }
4237:            }
4238:
4239:            /**
4240:             * Divide a Character by a Number
4241:             *
4242:             * @param left  a Character
4243:             * @param right a Number
4244:             * @return the multiplication of both
4245:             */
4246:            public static Number div(Character left, Number right) {
4247:                return div(new Integer(left.charValue()), right);
4248:            }
4249:
4250:            /**
4251:             * Divide a Number by a Character
4252:             *
4253:             * @param left  a Number
4254:             * @param right a Character
4255:             * @return the multiplication of both
4256:             */
4257:            public static Number div(Number left, Character right) {
4258:                return div(left, new Integer(right.charValue()));
4259:            }
4260:
4261:            /**
4262:             * Divide two Characters
4263:             *
4264:             * @param left  a Character
4265:             * @param right another Character
4266:             * @return the multiplication of both
4267:             */
4268:            public static Number div(Character left, Character right) {
4269:                return div(new Integer(left.charValue()), right);
4270:            }
4271:
4272:            /**
4273:             * Divide two Numbers
4274:             *
4275:             * @param left  a Number
4276:             * @param right another Number
4277:             * @return a Number resulting of the divide operation
4278:             */
4279:            //Method name changed from 'divide' to avoid collision with BigInteger method that has
4280:            //different semantics.  We want a BigDecimal result rather than a BigInteger.
4281:            public static Number div(Number left, Number right) {
4282:                return NumberMath.divide(left, right);
4283:            }
4284:
4285:            /**
4286:             * Integer Divide a Character by a Number
4287:             *
4288:             * @param left  a Character
4289:             * @param right a Number
4290:             * @return the integer division of both
4291:             */
4292:            public static Number intdiv(Character left, Number right) {
4293:                return intdiv(new Integer(left.charValue()), right);
4294:            }
4295:
4296:            /**
4297:             * Integer Divide a Number by a Character
4298:             *
4299:             * @param left  a Number
4300:             * @param right a Character
4301:             * @return the integer division of both
4302:             */
4303:            public static Number intdiv(Number left, Character right) {
4304:                return intdiv(left, new Integer(right.charValue()));
4305:            }
4306:
4307:            /**
4308:             * Integer Divide two Characters
4309:             *
4310:             * @param left  a Character
4311:             * @param right another Character
4312:             * @return the integer division of both
4313:             */
4314:            public static Number intdiv(Character left, Character right) {
4315:                return intdiv(new Integer(left.charValue()), right);
4316:            }
4317:
4318:            /**
4319:             * Integer Divide two Numbers
4320:             *
4321:             * @param left  a Number
4322:             * @param right another Number
4323:             * @return a Number (an Integer) resulting of the integer division operation
4324:             */
4325:            public static Number intdiv(Number left, Number right) {
4326:                return NumberMath.intdiv(left, right);
4327:            }
4328:
4329:            /**
4330:             * Bitwise OR together two numbers
4331:             *
4332:             * @param left  a Number
4333:             * @param right another Number to bitwise OR
4334:             * @return the bitwise OR of both Numbers
4335:             */
4336:            public static Number or(Number left, Number right) {
4337:                return NumberMath.or(left, right);
4338:            }
4339:
4340:            /**
4341:             * Bitwise AND together two Numbers
4342:             *
4343:             * @param left  a Number
4344:             * @param right another Number to bitwse AND
4345:             * @return the bitwise AND of both Numbers
4346:             */
4347:            public static Number and(Number left, Number right) {
4348:                return NumberMath.and(left, right);
4349:            }
4350:
4351:            /**
4352:             * Bitwise XOR together two Numbers
4353:             *
4354:             * @param left  a Number
4355:             * @param right another Number to bitwse XOR
4356:             * @return the bitwise XOR of both Numbers
4357:             */
4358:            public static Number xor(Number left, Number right) {
4359:                return NumberMath.xor(left, right);
4360:            }
4361:
4362:            /**
4363:             * Performs a division modulus operation
4364:             *
4365:             * @param left  a Number
4366:             * @param right another Number to mod
4367:             * @return the modulus result
4368:             */
4369:            public static Number mod(Number left, Number right) {
4370:                return NumberMath.mod(left, right);
4371:            }
4372:
4373:            /**
4374:             * Negates the number
4375:             *
4376:             * @param left a Number
4377:             * @return the negation of the number
4378:             */
4379:            public static Number negate(Number left) {
4380:                return NumberMath.negate(left);
4381:            }
4382:
4383:            /**
4384:             * Iterates a number of times
4385:             *
4386:             * @param self    a Number
4387:             * @param closure the closure to call a number of times
4388:             */
4389:            public static void times(Number self, Closure closure) {
4390:                for (int i = 0, size = self.intValue(); i < size; i++) {
4391:                    closure.call(new Integer(i));
4392:                    if (closure.getDirective() == Closure.DONE) {
4393:                        break;
4394:                    }
4395:                }
4396:            }
4397:
4398:            /**
4399:             * Iterates from this number up to the given number
4400:             *
4401:             * @param self    a Number
4402:             * @param to      another Number to go up to
4403:             * @param closure the closure to call
4404:             */
4405:            public static void upto(Number self, Number to, Closure closure) {
4406:                int self1 = self.intValue();
4407:                int to1 = to.intValue();
4408:                if (self1 <= to1) {
4409:                    for (int i = self1; i <= to1; i++) {
4410:                        closure.call(new Integer(i));
4411:                    }
4412:                } else
4413:                    throw new GroovyRuntimeException("Infinite loop in " + self
4414:                            + ".upto(" + to + ")");
4415:            }
4416:
4417:            public static void upto(long self, Number to, Closure closure) {
4418:                long to1 = to.longValue();
4419:                if (self <= to1) {
4420:                    for (long i = self; i <= to1; i++) {
4421:                        closure.call(new Long(i));
4422:                    }
4423:                } else
4424:                    throw new GroovyRuntimeException("Infinite loop in " + self
4425:                            + ".upto(" + to + ")");
4426:            }
4427:
4428:            public static void upto(Long self, Number to, Closure closure) {
4429:                long self1 = self.longValue();
4430:                long to1 = to.longValue();
4431:                if (self1 <= to1) {
4432:                    for (long i = self1; i <= to1; i++) {
4433:                        closure.call(new Long(i));
4434:                    }
4435:                } else
4436:                    throw new GroovyRuntimeException("Infinite loop in " + self
4437:                            + ".upto(" + to + ")");
4438:            }
4439:
4440:            public static void upto(float self, Number to, Closure closure) {
4441:                float to1 = to.floatValue();
4442:                if (self <= to1) {
4443:                    for (float i = self; i <= to1; i++) {
4444:                        closure.call(new Float(i));
4445:                    }
4446:                } else
4447:                    throw new GroovyRuntimeException("Infinite loop in " + self
4448:                            + ".upto(" + to + ")");
4449:            }
4450:
4451:            public static void upto(Float self, Number to, Closure closure) {
4452:                float self1 = self.floatValue();
4453:                float to1 = to.floatValue();
4454:                if (self1 <= to1) {
4455:                    for (float i = self1; i <= to1; i++) {
4456:                        closure.call(new Float(i));
4457:                    }
4458:                } else
4459:                    throw new GroovyRuntimeException("Infinite loop in " + self
4460:                            + ".upto(" + to + ")");
4461:            }
4462:
4463:            public static void upto(Double self, Number to, Closure closure) {
4464:                double self1 = self.doubleValue();
4465:                double to1 = to.doubleValue();
4466:                if (self1 <= to1) {
4467:                    for (double i = self1; i <= to1; i++) {
4468:                        closure.call(new Double(i));
4469:                    }
4470:                } else
4471:                    throw new GroovyRuntimeException("Infinite loop in " + self
4472:                            + ".upto(" + to + ")");
4473:            }
4474:
4475:            public static void upto(BigInteger self, Number to, Closure closure) {
4476:                if (to instanceof  BigDecimal) {
4477:                    final BigDecimal one = new BigDecimal("1.0");
4478:                    BigDecimal self1 = new BigDecimal(self);
4479:                    BigDecimal to1 = (BigDecimal) to;
4480:                    if (self1.compareTo(to1) <= 0) {
4481:                        for (BigDecimal i = self1; i.compareTo(to1) <= 0; i = i
4482:                                .add(one)) {
4483:                            closure.call(i);
4484:                        }
4485:                    } else
4486:                        throw new GroovyRuntimeException("Infinite loop in "
4487:                                + self + ".upto(" + to + ")");
4488:                } else if (to instanceof  BigInteger) {
4489:                    final BigInteger one = new BigInteger("1");
4490:                    BigInteger to1 = (BigInteger) to;
4491:                    if (self.compareTo(to1) <= 0) {
4492:                        for (BigInteger i = self; i.compareTo(to1) <= 0; i = i
4493:                                .add(one)) {
4494:                            closure.call(i);
4495:                        }
4496:                    } else
4497:                        throw new GroovyRuntimeException("Infinite loop in "
4498:                                + self + ".upto(" + to + ")");
4499:                } else {
4500:                    final BigInteger one = new BigInteger("1");
4501:                    BigInteger to1 = new BigInteger("" + to);
4502:                    if (self.compareTo(to1) <= 0) {
4503:                        for (BigInteger i = self; i.compareTo(to1) <= 0; i = i
4504:                                .add(one)) {
4505:                            closure.call(i);
4506:                        }
4507:                    } else
4508:                        throw new GroovyRuntimeException("Infinite loop in "
4509:                                + self + ".upto(" + to + ")");
4510:                }
4511:            }
4512:
4513:            public static void upto(BigDecimal self, Number to, Closure closure) {
4514:                final BigDecimal one = new BigDecimal("1.0");
4515:                if (to instanceof  BigDecimal) {
4516:                    BigDecimal to1 = (BigDecimal) to;
4517:                    if (self.compareTo(to1) <= 0) {
4518:                        for (BigDecimal i = self; i.compareTo(to1) <= 0; i = i
4519:                                .add(one)) {
4520:                            closure.call(i);
4521:                        }
4522:                    } else
4523:                        throw new GroovyRuntimeException("Infinite loop in "
4524:                                + self + ".upto(" + to + ")");
4525:                } else if (to instanceof  BigInteger) {
4526:                    BigDecimal to1 = new BigDecimal((BigInteger) to);
4527:                    if (self.compareTo(to1) <= 0) {
4528:                        for (BigDecimal i = self; i.compareTo(to1) <= 0; i = i
4529:                                .add(one)) {
4530:                            closure.call(i);
4531:                        }
4532:                    } else
4533:                        throw new GroovyRuntimeException("Infinite loop in "
4534:                                + self + ".upto(" + to + ")");
4535:                } else {
4536:                    BigDecimal to1 = new BigDecimal("" + to);
4537:                    if (self.compareTo(to1) <= 0) {
4538:                        for (BigDecimal i = self; i.compareTo(to1) <= 0; i = i
4539:                                .add(one)) {
4540:                            closure.call(i);
4541:                        }
4542:                    } else
4543:                        throw new GroovyRuntimeException("Infinite loop in "
4544:                                + self + ".upto(" + to + ")");
4545:                }
4546:            }
4547:
4548:            /**
4549:             * Iterates from this number down to the given number
4550:             *
4551:             * @param self    a Number
4552:             * @param to      another Number to go down to
4553:             * @param closure the closure to call
4554:             */
4555:            public static void downto(Number self, Number to, Closure closure) {
4556:                int self1 = self.intValue();
4557:                int to1 = to.intValue();
4558:                if (self1 >= to1) {
4559:                    for (int i = self1; i >= to1; i--) {
4560:                        closure.call(new Integer(i));
4561:                    }
4562:                } else
4563:                    throw new GroovyRuntimeException("Infinite loop in " + self
4564:                            + ".downto(" + to + ")");
4565:            }
4566:
4567:            public static void downto(long self, Number to, Closure closure) {
4568:                long to1 = to.longValue();
4569:                if (self >= to1) {
4570:                    for (long i = self; i >= to1; i--) {
4571:                        closure.call(new Long(i));
4572:                    }
4573:                } else
4574:                    throw new GroovyRuntimeException("Infinite loop in " + self
4575:                            + ".downto(" + to + ")");
4576:            }
4577:
4578:            public static void downto(Long self, Number to, Closure closure) {
4579:                long self1 = self.longValue();
4580:                long to1 = to.longValue();
4581:                if (self1 >= to1) {
4582:                    for (long i = self1; i >= to1; i--) {
4583:                        closure.call(new Long(i));
4584:                    }
4585:                } else
4586:                    throw new GroovyRuntimeException("Infinite loop in " + self
4587:                            + ".downto(" + to + ")");
4588:            }
4589:
4590:            public static void downto(float self, Number to, Closure closure) {
4591:                float to1 = to.floatValue();
4592:                if (self >= to1) {
4593:                    for (float i = self; i >= to1; i--) {
4594:                        closure.call(new Float(i));
4595:                    }
4596:                } else
4597:                    throw new GroovyRuntimeException("Infinite loop in " + self
4598:                            + ".downto(" + to + ")");
4599:            }
4600:
4601:            public static void downto(Float self, Number to, Closure closure) {
4602:                float self1 = self.floatValue();
4603:                float to1 = to.floatValue();
4604:                if (self1 >= to1) {
4605:                    for (float i = self1; i >= to1; i--) {
4606:                        closure.call(new Float(i));
4607:                    }
4608:                } else
4609:                    throw new GroovyRuntimeException("Infinite loop in " + self
4610:                            + ".downto(" + to + ")");
4611:            }
4612:
4613:            public static void downto(double self, Number to, Closure closure) {
4614:                double to1 = to.doubleValue();
4615:                if (self >= to1) {
4616:                    for (double i = self; i >= to1; i--) {
4617:                        closure.call(new Double(i));
4618:                    }
4619:                } else
4620:                    throw new GroovyRuntimeException("Infinite loop in " + self
4621:                            + ".downto(" + to + ")");
4622:            }
4623:
4624:            public static void downto(Double self, Number to, Closure closure) {
4625:                double self1 = self.doubleValue();
4626:                double to1 = to.doubleValue();
4627:                if (self1 >= to1) {
4628:                    for (double i = self1; i >= to1; i--) {
4629:                        closure.call(new Double(i));
4630:                    }
4631:                } else
4632:                    throw new GroovyRuntimeException("Infinite loop in " + self
4633:                            + ".downto(" + to + ")");
4634:            }
4635:
4636:            public static void downto(BigInteger self, Number to,
4637:                    Closure closure) {
4638:                if (to instanceof  BigDecimal) {
4639:                    final BigDecimal one = new BigDecimal("1.0");
4640:                    final BigDecimal to1 = (BigDecimal) to;
4641:                    final BigDecimal selfD = new BigDecimal(self);
4642:                    if (selfD.compareTo(to1) >= 0) {
4643:                        for (BigDecimal i = selfD; i.compareTo(to1) >= 0; i = i
4644:                                .subtract(one)) {
4645:                            closure.call(i.toBigInteger());
4646:                        }
4647:                    } else
4648:                        throw new GroovyRuntimeException("Infinite loop in "
4649:                                + self + ".downto(" + to + ")");
4650:                } else if (to instanceof  BigInteger) {
4651:                    final BigInteger one = new BigInteger("1");
4652:                    final BigInteger to1 = (BigInteger) to;
4653:                    if (self.compareTo(to1) >= 0) {
4654:                        for (BigInteger i = self; i.compareTo(to1) >= 0; i = i
4655:                                .subtract(one)) {
4656:                            closure.call(i);
4657:                        }
4658:                    } else
4659:                        throw new GroovyRuntimeException("Infinite loop in "
4660:                                + self + ".downto(" + to + ")");
4661:                } else {
4662:                    final BigInteger one = new BigInteger("1");
4663:                    final BigInteger to1 = new BigInteger("" + to);
4664:                    if (self.compareTo(to1) >= 0) {
4665:                        for (BigInteger i = self; i.compareTo(to1) >= 0; i = i
4666:                                .subtract(one)) {
4667:                            closure.call(i);
4668:                        }
4669:                    } else
4670:                        throw new GroovyRuntimeException("Infinite loop in "
4671:                                + self + ".downto(" + to + ")");
4672:                }
4673:            }
4674:
4675:            public static void downto(BigDecimal self, Number to,
4676:                    Closure closure) {
4677:                final BigDecimal one = new BigDecimal("1.0");
4678:                if (to instanceof  BigDecimal) {
4679:                    BigDecimal to1 = (BigDecimal) to;
4680:                    if (self.compareTo(to1) >= 0) {
4681:                        for (BigDecimal i = self; i.compareTo(to1) >= 0; i = i
4682:                                .subtract(one)) {
4683:                            closure.call(i);
4684:                        }
4685:                    } else
4686:                        throw new GroovyRuntimeException("Infinite loop in "
4687:                                + self + ".downto(" + to + ")");
4688:                } else if (to instanceof  BigInteger) {
4689:                    BigDecimal to1 = new BigDecimal((BigInteger) to);
4690:                    if (self.compareTo(to1) >= 0) {
4691:                        for (BigDecimal i = self; i.compareTo(to1) >= 0; i = i
4692:                                .subtract(one)) {
4693:                            closure.call(i);
4694:                        }
4695:                    } else
4696:                        throw new GroovyRuntimeException("Infinite loop in "
4697:                                + self + ".downto(" + to + ")");
4698:                } else {
4699:                    BigDecimal to1 = new BigDecimal("" + to);
4700:                    if (self.compareTo(to1) >= 0) {
4701:                        for (BigDecimal i = self; i.compareTo(to1) >= 0; i = i
4702:                                .subtract(one)) {
4703:                            closure.call(i);
4704:                        }
4705:                    } else
4706:                        throw new GroovyRuntimeException("Infinite loop in "
4707:                                + self + ".downto(" + to + ")");
4708:                }
4709:            }
4710:
4711:            /**
4712:             * Iterates from this number up to the given number using a step increment
4713:             *
4714:             * @param self       a Number to start with
4715:             * @param to         a Number to go up to
4716:             * @param stepNumber a Number representing the step increment
4717:             * @param closure    the closure to call
4718:             */
4719:            public static void step(Number self, Number to, Number stepNumber,
4720:                    Closure closure) {
4721:                if (self instanceof  BigDecimal || to instanceof  BigDecimal
4722:                        || stepNumber instanceof  BigDecimal) {
4723:                    final BigDecimal zero = new BigDecimal("0.0");
4724:                    BigDecimal self1 = (self instanceof  BigDecimal) ? (BigDecimal) self
4725:                            : new BigDecimal("" + self);
4726:                    BigDecimal to1 = (to instanceof  BigDecimal) ? (BigDecimal) to
4727:                            : new BigDecimal("" + to);
4728:                    BigDecimal stepNumber1 = (stepNumber instanceof  BigDecimal) ? (BigDecimal) stepNumber
4729:                            : new BigDecimal("" + stepNumber);
4730:                    if (stepNumber1.compareTo(zero) > 0
4731:                            && to1.compareTo(self1) > 0) {
4732:                        for (BigDecimal i = self1; i.compareTo(to1) < 0; i = i
4733:                                .add(stepNumber1)) {
4734:                            closure.call(i);
4735:                        }
4736:                    } else if (stepNumber1.compareTo(zero) < 0
4737:                            && to1.compareTo(self1) < 0) {
4738:                        for (BigDecimal i = self1; i.compareTo(to1) > 0; i = i
4739:                                .add(stepNumber1)) {
4740:                            closure.call(i);
4741:                        }
4742:                    } else
4743:                        throw new GroovyRuntimeException("Infinite loop in "
4744:                                + self1 + ".step(" + to1 + ", " + stepNumber1
4745:                                + ")");
4746:                } else if (self instanceof  BigInteger
4747:                        || to instanceof  BigInteger
4748:                        || stepNumber instanceof  BigInteger) {
4749:                    final BigInteger zero = new BigInteger("0");
4750:                    BigInteger self1 = (self instanceof  BigInteger) ? (BigInteger) self
4751:                            : new BigInteger("" + self);
4752:                    BigInteger to1 = (to instanceof  BigInteger) ? (BigInteger) to
4753:                            : new BigInteger("" + to);
4754:                    BigInteger stepNumber1 = (stepNumber instanceof  BigInteger) ? (BigInteger) stepNumber
4755:                            : new BigInteger("" + stepNumber);
4756:                    if (stepNumber1.compareTo(zero) > 0
4757:                            && to1.compareTo(self1) > 0) {
4758:                        for (BigInteger i = self1; i.compareTo(to1) < 0; i = i
4759:                                .add(stepNumber1)) {
4760:                            closure.call(i);
4761:                        }
4762:                    } else if (stepNumber1.compareTo(zero) < 0
4763:                            && to1.compareTo(self1) < 0) {
4764:                        for (BigInteger i = self1; i.compareTo(to1) > 0; i = i
4765:                                .add(stepNumber1)) {
4766:                            closure.call(i);
4767:                        }
4768:                    } else
4769:                        throw new GroovyRuntimeException("Infinite loop in "
4770:                                + self1 + ".step(" + to1 + ", " + stepNumber1
4771:                                + ")");
4772:                } else {
4773:                    int self1 = self.intValue();
4774:                    int to1 = to.intValue();
4775:                    int stepNumber1 = stepNumber.intValue();
4776:                    if (stepNumber1 > 0 && to1 > self1) {
4777:                        for (int i = self1; i < to1; i += stepNumber1) {
4778:                            closure.call(new Integer(i));
4779:                        }
4780:                    } else if (stepNumber1 < 0 && to1 < self1) {
4781:                        for (int i = self1; i > to1; i += stepNumber1) {
4782:                            closure.call(new Integer(i));
4783:                        }
4784:                    } else
4785:                        throw new GroovyRuntimeException("Infinite loop in "
4786:                                + self1 + ".step(" + to1 + ", " + stepNumber1
4787:                                + ")");
4788:                }
4789:            }
4790:
4791:            /**
4792:             * Get the absolute value
4793:             *
4794:             * @param number a Number
4795:             * @return the absolute value of that Number
4796:             */
4797:            //Note:  This method is NOT called if number is a BigInteger or BigDecimal because
4798:            //those classes implement a method with a better exact match.
4799:            public static int abs(Number number) {
4800:                return Math.abs(number.intValue());
4801:            }
4802:
4803:            /**
4804:             * Get the absolute value
4805:             *
4806:             * @param number a Long
4807:             * @return the absolute value of that Long
4808:             */
4809:            public static long abs(Long number) {
4810:                return Math.abs(number.longValue());
4811:            }
4812:
4813:            /**
4814:             * Get the absolute value
4815:             *
4816:             * @param number a Float
4817:             * @return the absolute value of that Float
4818:             */
4819:            public static float abs(Float number) {
4820:                return Math.abs(number.floatValue());
4821:            }
4822:
4823:            /**
4824:             * Get the absolute value
4825:             *
4826:             * @param number a Double
4827:             * @return the absolute value of that Double
4828:             */
4829:            public static double abs(Double number) {
4830:                return Math.abs(number.doubleValue());
4831:            }
4832:
4833:            /**
4834:             * Get the absolute value
4835:             *
4836:             * @param number a Float
4837:             * @return the absolute value of that Float
4838:             */
4839:            public static int round(Float number) {
4840:                return Math.round(number.floatValue());
4841:            }
4842:
4843:            /**
4844:             * Round the value
4845:             *
4846:             * @param number a Double
4847:             * @return the absolute value of that Double
4848:             */
4849:            public static long round(Double number) {
4850:                return Math.round(number.doubleValue());
4851:            }
4852:
4853:            /**
4854:             * Parse a String into an Integer
4855:             *
4856:             * @param self a String
4857:             * @return an Integer
4858:             */
4859:            public static Integer toInteger(String self) {
4860:                return Integer.valueOf(self.trim());
4861:            }
4862:
4863:            /**
4864:             * Parse a String into a Long
4865:             *
4866:             * @param self a String
4867:             * @return a Long
4868:             */
4869:            public static Long toLong(String self) {
4870:                return Long.valueOf(self.trim());
4871:            }
4872:
4873:            /**
4874:             * Parse a String into a Float
4875:             *
4876:             * @param self a String
4877:             * @return a Float
4878:             */
4879:            public static Float toFloat(String self) {
4880:                return Float.valueOf(self.trim());
4881:            }
4882:
4883:            /**
4884:             * Parse a String into a Double
4885:             *
4886:             * @param self a String
4887:             * @return a Double
4888:             */
4889:            public static Double toDouble(String self) {
4890:                return Double.valueOf(self.trim());
4891:            }
4892:
4893:            /**
4894:             * Parse a String into a BigInteger
4895:             *
4896:             * @param self a String
4897:             * @return a BigInteger
4898:             */
4899:            public static BigInteger toBigInteger(String self) {
4900:                return new BigInteger(self.trim());
4901:            }
4902:
4903:            /**
4904:             * Parse a String into a BigDecimal
4905:             *
4906:             * @param self a String
4907:             * @return a BigDecimal
4908:             */
4909:            public static BigDecimal toBigDecimal(String self) {
4910:                return new BigDecimal(self.trim());
4911:            }
4912:
4913:            /**
4914:             * Transform a Number into an Integer
4915:             *
4916:             * @param self a Number
4917:             * @return an Integer
4918:             */
4919:            public static Integer toInteger(Number self) {
4920:                return new Integer(self.intValue());
4921:            }
4922:
4923:            /**
4924:             * Transform a Number into a Long
4925:             *
4926:             * @param self a Number
4927:             * @return an Long
4928:             */
4929:            public static Long toLong(Number self) {
4930:                return new Long(self.longValue());
4931:            }
4932:
4933:            /**
4934:             * Transform a Number into a Float
4935:             *
4936:             * @param self a Number
4937:             * @return an Float
4938:             */
4939:            public static Float toFloat(Number self) {
4940:                return new Float(self.floatValue());
4941:            }
4942:
4943:            /**
4944:             * Transform a Number into a Double
4945:             *
4946:             * @param self a Number
4947:             * @return an Double
4948:             */
4949:            public static Double toDouble(Number self) {
4950:                return new Double(self.doubleValue());
4951:            }
4952:
4953:            /**
4954:             * Transform a Number into a BigDecimal
4955:             *
4956:             * @param self a Number
4957:             * @return an BigDecimal
4958:             */
4959:            public static BigDecimal toBigDecimal(Number self) {
4960:                return new BigDecimal(self.doubleValue());
4961:            }
4962:
4963:            public static Object asType(Number self, Class c) {
4964:                if (c == BigDecimal.class) {
4965:                    return toBigDecimal(self);
4966:                } else if (c == BigInteger.class) {
4967:                    return toBigInteger(self);
4968:                } else if (c == Double.class) {
4969:                    return toDouble(self);
4970:                } else if (c == Float.class) {
4971:                    return toFloat(self);
4972:                }
4973:                return asType((Object) self, c);
4974:            }
4975:
4976:            /**
4977:             * Transform a Number into a BigInteger
4978:             *
4979:             * @param self a Number
4980:             * @return an BigInteger
4981:             */
4982:            public static BigInteger toBigInteger(Number self) {
4983:                return new BigInteger(Long.toString(self.longValue()));
4984:            }
4985:
4986:            // Date methods
4987:            //-------------------------------------------------------------------------
4988:
4989:            /**
4990:             * Increments a Date by a day
4991:             *
4992:             * @param self a Date
4993:             * @return the next days date
4994:             */
4995:            public static Date next(Date self) {
4996:                return plus(self, 1);
4997:            }
4998:
4999:            /**
5000:             * Increments a java.sql.Date by a day
5001:             *
5002:             * @param self a java.sql.Date
5003:             * @return the next days date
5004:             */
5005:            public static java.sql.Date next(java.sql.Date self) {
5006:                return new java.sql.Date(next((Date) self).getTime());
5007:            }
5008:
5009:            /**
5010:             * Decrement a Date by a day
5011:             *
5012:             * @param self a Date
5013:             * @return the previous days date
5014:             */
5015:            public static Date previous(Date self) {
5016:                return minus(self, 1);
5017:            }
5018:
5019:            /**
5020:             * Decrement a java.sql.Date by a day
5021:             *
5022:             * @param self a java.sql.Date
5023:             * @return the previous days date
5024:             */
5025:            public static java.sql.Date previous(java.sql.Date self) {
5026:                return new java.sql.Date(previous((Date) self).getTime());
5027:            }
5028:
5029:            /**
5030:             * Adds a number of days to this date and returns the new date
5031:             *
5032:             * @param self a Date
5033:             * @param days the number of days to increase
5034:             * @return the new date
5035:             */
5036:            public static Date plus(Date self, int days) {
5037:                Calendar calendar = (Calendar) Calendar.getInstance().clone();
5038:                calendar.setTime(self);
5039:                calendar.add(Calendar.DAY_OF_YEAR, days);
5040:                return calendar.getTime();
5041:            }
5042:
5043:            /**
5044:             * Adds a number of days to this date and returns the new date
5045:             *
5046:             * @param self a java.sql.Date
5047:             * @param days the number of days to increase
5048:             * @return the new date
5049:             */
5050:            public static java.sql.Date plus(java.sql.Date self, int days) {
5051:                return new java.sql.Date(plus((Date) self, days).getTime());
5052:            }
5053:
5054:            /**
5055:             * Subtracts a number of days from this date and returns the new date
5056:             *
5057:             * @param self a Date
5058:             * @return the new date
5059:             */
5060:            public static Date minus(Date self, int days) {
5061:                return plus(self, -days);
5062:            }
5063:
5064:            /**
5065:             * Subtracts a number of days from this date and returns the new date
5066:             *
5067:             * @param self a java.sql.Date
5068:             * @return the new date
5069:             */
5070:            public static java.sql.Date minus(java.sql.Date self, int days) {
5071:                return new java.sql.Date(minus((Date) self, days).getTime());
5072:            }
5073:
5074:            // Boolean based methods
5075:            //-------------------------------------------------------------------------
5076:
5077:            public static Boolean and(Boolean left, Boolean right) {
5078:                return Boolean.valueOf(left.booleanValue()
5079:                        & right.booleanValue());
5080:            }
5081:
5082:            public static Boolean or(Boolean left, Boolean right) {
5083:                return Boolean.valueOf(left.booleanValue()
5084:                        | right.booleanValue());
5085:            }
5086:
5087:            public static Boolean xor(Boolean left, Boolean right) {
5088:                return Boolean.valueOf(left.booleanValue()
5089:                        ^ right.booleanValue());
5090:            }
5091:
5092:            //    public static Boolean negate(Boolean left) {
5093:            //        return Boolean.valueOf(!left.booleanValue());
5094:            //    }
5095:
5096:            // File and stream based methods
5097:            //-------------------------------------------------------------------------
5098:
5099:            /**
5100:             * Helper method to create an object input stream from the given file.
5101:             *
5102:             * @param file a file
5103:             * @return an object input stream
5104:             * @throws FileNotFoundException
5105:             * @throws IOException
5106:             */
5107:            public static ObjectInputStream newObjectInputStream(File file)
5108:                    throws FileNotFoundException, IOException {
5109:                return new ObjectInputStream(new FileInputStream(file));
5110:            }
5111:
5112:            /**
5113:             * Iterates through the given file object by object
5114:             *
5115:             * @param self    a File
5116:             * @param closure a closure
5117:             * @throws IOException
5118:             * @throws ClassNotFoundException
5119:             */
5120:            public static void eachObject(File self, Closure closure)
5121:                    throws IOException, ClassNotFoundException {
5122:                eachObject(newObjectInputStream(self), closure);
5123:            }
5124:
5125:            /**
5126:             * Iterates through the given object stream object by object. The
5127:             * ObjectInputStream is closed afterwards.
5128:             *
5129:             * @param ois     an ObjectInputStream, closed after the operation
5130:             * @param closure a closure
5131:             * @throws IOException
5132:             * @throws ClassNotFoundException
5133:             */
5134:            public static void eachObject(ObjectInputStream ois, Closure closure)
5135:                    throws IOException, ClassNotFoundException {
5136:                try {
5137:                    while (true) {
5138:                        try {
5139:                            Object obj = ois.readObject();
5140:                            // we allow null objects in the object stream
5141:                            closure.call(obj);
5142:                        } catch (EOFException e) {
5143:                            break;
5144:                        }
5145:                    }
5146:                    InputStream temp = ois;
5147:                    ois = null;
5148:                    temp.close();
5149:                } finally {
5150:                    if (ois != null) {
5151:                        try {
5152:                            ois.close();
5153:                        } catch (Exception e) {
5154:                            // ignore this exception since there
5155:                            // has to be another already
5156:                            LOG
5157:                                    .warning("Caught exception closing ObjectInputStream: "
5158:                                            + e);
5159:                        }
5160:                    }
5161:                }
5162:            }
5163:
5164:            /**
5165:             * Iterates through the given file line by line
5166:             *
5167:             * @param self    a File
5168:             * @param closure a closure
5169:             * @throws IOException
5170:             */
5171:            public static void eachLine(File self, Closure closure)
5172:                    throws IOException {
5173:                eachLine(newReader(self), closure);
5174:            }
5175:
5176:            /**
5177:             * Iterates through the given reader line by line. The
5178:             * Reader is closed afterwards
5179:             *
5180:             * @param self    a Reader, closed after the method returns
5181:             * @param closure a closure
5182:             * @throws IOException
5183:             */
5184:            public static void eachLine(Reader self, Closure closure)
5185:                    throws IOException {
5186:                BufferedReader br /* = null */;
5187:
5188:                if (self instanceof  BufferedReader)
5189:                    br = (BufferedReader) self;
5190:                else
5191:                    br = new BufferedReader(self);
5192:
5193:                try {
5194:                    while (true) {
5195:                        String line = br.readLine();
5196:                        if (line == null) {
5197:                            break;
5198:                        } else {
5199:                            closure.call(line);
5200:                        }
5201:                    }
5202:                    Reader temp = self;
5203:                    self = null;
5204:                    temp.close();
5205:                } finally {
5206:                    if (self != null) {
5207:                        try {
5208:                            self.close();
5209:                        } catch (Exception e) {
5210:                            // ignore this exception since there
5211:                            // has to be another already
5212:                            LOG
5213:                                    .warning("Caught exception closing Reader: "
5214:                                            + e);
5215:                        }
5216:                    }
5217:                    if (br != null) {
5218:                        try {
5219:                            br.close();
5220:                        } catch (Exception e) {
5221:                            // ignore this exception since this
5222:                            // is only our internal problem
5223:                            LOG
5224:                                    .warning("Caught exception closing Reader: "
5225:                                            + e);
5226:                        }
5227:                    }
5228:                }
5229:            }
5230:
5231:            /**
5232:             * Iterates through the given file line by line, splitting on the seperator
5233:             *
5234:             * @param self    a File
5235:             * @param sep     a String separator
5236:             * @param closure a closure
5237:             * @throws IOException
5238:             */
5239:            public static void splitEachLine(File self, String sep,
5240:                    Closure closure) throws IOException {
5241:                splitEachLine(newReader(self), sep, closure);
5242:            }
5243:
5244:            /**
5245:             * Iterates through the given reader line by line, splitting on the separator.
5246:             * The Reader is closed afterwards.
5247:             *
5248:             * @param self    a Reader, closed after the method returns
5249:             * @param sep     a String separator
5250:             * @param closure a closure
5251:             * @throws IOException
5252:             */
5253:            public static void splitEachLine(Reader self, String sep,
5254:                    Closure closure) throws IOException {
5255:                BufferedReader br /* = null */;
5256:
5257:                if (self instanceof  BufferedReader)
5258:                    br = (BufferedReader) self;
5259:                else
5260:                    br = new BufferedReader(self);
5261:
5262:                try {
5263:                    while (true) {
5264:                        String line = br.readLine();
5265:                        if (line == null) {
5266:                            break;
5267:                        } else {
5268:                            List vals = Arrays.asList(line.split(sep));
5269:                            closure.call(vals);
5270:                        }
5271:                    }
5272:                    Reader temp = self;
5273:                    self = null;
5274:                    temp.close();
5275:                } finally {
5276:                    if (self != null) {
5277:                        try {
5278:                            self.close();
5279:                        } catch (Exception e) {
5280:                            // ignore this exception since there
5281:                            // has to be another already
5282:                            LOG
5283:                                    .warning("Caught exception closing Reader: "
5284:                                            + e);
5285:                        }
5286:                    }
5287:                    if (br != null) {
5288:                        try {
5289:                            br.close();
5290:                        } catch (Exception e) {
5291:                            // ignore this exception since this
5292:                            // is only our internal problem
5293:                            LOG
5294:                                    .warning("Caught exception closing Reader: "
5295:                                            + e);
5296:                        }
5297:                    }
5298:                }
5299:            }
5300:
5301:            /**
5302:             * Read a single, whole line from the given Reader
5303:             *
5304:             * @param self a Reader
5305:             * @return a line
5306:             * @throws IOException
5307:             */
5308:            public static String readLine(Reader self) throws IOException {
5309:                BufferedReader br /* = null */;
5310:
5311:                if (self instanceof  BufferedReader) {
5312:                    br = (BufferedReader) self;
5313:                } else {
5314:                    br = new BufferedReader(self); // todo dk: bug! will return null on second call
5315:                }
5316:                return br.readLine();
5317:            }
5318:
5319:            /**
5320:             * Read a single, whole line from the given InputStream
5321:             *
5322:             * @param stream an InputStream
5323:             * @return a line
5324:             * @throws IOException
5325:             */
5326:            public static String readLine(InputStream stream)
5327:                    throws IOException {
5328:                return readLine(new InputStreamReader(stream));
5329:            }
5330:
5331:            /**
5332:             * Reads the file into a list of Strings for each line
5333:             *
5334:             * @param file a File
5335:             * @return a List of lines
5336:             * @throws IOException
5337:             */
5338:            public static List readLines(File file) throws IOException {
5339:                IteratorClosureAdapter closure = new IteratorClosureAdapter(
5340:                        file);
5341:                eachLine(file, closure);
5342:                return closure.asList();
5343:            }
5344:
5345:            /**
5346:             * Reads the content of the File opened with the specified encoding and returns it as a String
5347:             *
5348:             * @param file    the file whose content we want to read
5349:             * @param charset the charset used to read the content of the file
5350:             * @return a String containing the content of the file
5351:             * @throws IOException
5352:             */
5353:            public static String getText(File file, String charset)
5354:                    throws IOException {
5355:                BufferedReader reader = newReader(file, charset);
5356:                return getText(reader);
5357:            }
5358:
5359:            /**
5360:             * Reads the content of the File and returns it as a String
5361:             *
5362:             * @param file the file whose content we want to read
5363:             * @return a String containing the content of the file
5364:             * @throws IOException
5365:             */
5366:            public static String getText(File file) throws IOException {
5367:                BufferedReader reader = newReader(file);
5368:                return getText(reader);
5369:            }
5370:
5371:            /**
5372:             * Reads the content of this URL and returns it as a String
5373:             *
5374:             * @param url URL to read content from
5375:             * @return the text from that URL
5376:             * @throws IOException
5377:             */
5378:            public static String getText(URL url) throws IOException {
5379:                return getText(url, CharsetToolkit.getDefaultSystemCharset()
5380:                        .toString());
5381:            }
5382:
5383:            /**
5384:             * Reads the content of this URL and returns it as a String
5385:             *
5386:             * @param url     URL to read content from
5387:             * @param charset opens the stream with a specified charset
5388:             * @return the text from that URL
5389:             * @throws IOException
5390:             */
5391:            public static String getText(URL url, String charset)
5392:                    throws IOException {
5393:                BufferedReader reader = new BufferedReader(
5394:                        new InputStreamReader(url.openConnection()
5395:                                .getInputStream(), charset));
5396:                return getText(reader);
5397:            }
5398:
5399:            /**
5400:             * Reads the content of this InputStream and returns it as a String
5401:             *
5402:             * @param is an input stream
5403:             * @return the text from that URL
5404:             * @throws IOException
5405:             */
5406:            public static String getText(InputStream is) throws IOException {
5407:                BufferedReader reader = new BufferedReader(
5408:                        new InputStreamReader(is));
5409:                return getText(reader);
5410:            }
5411:
5412:            /**
5413:             * Reads the content of this InputStream with a specified charset and returns it as a String
5414:             *
5415:             * @param is      an input stream
5416:             * @param charset opens the stream with a specified charset
5417:             * @return the text from that URL
5418:             * @throws IOException
5419:             */
5420:            public static String getText(InputStream is, String charset)
5421:                    throws IOException {
5422:                BufferedReader reader = new BufferedReader(
5423:                        new InputStreamReader(is, charset));
5424:                return getText(reader);
5425:            }
5426:
5427:            /**
5428:             * Reads the content of the Reader and returns it as a String
5429:             *
5430:             * @param reader a Reader whose content we want to read
5431:             * @return a String containing the content of the buffered reader
5432:             * @throws IOException
5433:             */
5434:            public static String getText(Reader reader) throws IOException {
5435:                BufferedReader bufferedReader = new BufferedReader(reader);
5436:                return getText(bufferedReader);
5437:            }
5438:
5439:            /**
5440:             * Reads the content of the BufferedReader and returns it as a String.
5441:             * The BufferedReader is closed afterwards.
5442:             *
5443:             * @param reader a BufferedReader whose content we want to read
5444:             * @return a String containing the content of the buffered reader
5445:             * @throws IOException
5446:             */
5447:            public static String getText(BufferedReader reader)
5448:                    throws IOException {
5449:                StringBuffer answer = new StringBuffer();
5450:                // reading the content of the file within a char buffer 
5451:                // allow to keep the correct line endings
5452:                char[] charBuffer = new char[4096];
5453:                int nbCharRead /* = 0*/;
5454:                try {
5455:                    while ((nbCharRead = reader.read(charBuffer)) != -1) {
5456:                        // appends buffer
5457:                        answer.append(charBuffer, 0, nbCharRead);
5458:                    }
5459:                    Reader temp = reader;
5460:                    reader = null;
5461:                    temp.close();
5462:                } finally {
5463:                    if (reader != null) {
5464:                        try {
5465:                            reader.close();
5466:                        } catch (Exception e) {
5467:                            // ignore since there has to be an exception already
5468:                            LOG
5469:                                    .warning("Caught exception closing Reader: "
5470:                                            + e);
5471:                        }
5472:                    }
5473:                }
5474:                return answer.toString();
5475:            }
5476:
5477:            /**
5478:             * Write the text and append a new line (depending on the platform
5479:             * line-ending)
5480:             *
5481:             * @param writer a BufferedWriter
5482:             * @param line   the line to write
5483:             * @throws IOException
5484:             */
5485:            public static void writeLine(BufferedWriter writer, String line)
5486:                    throws IOException {
5487:                writer.write(line);
5488:                writer.newLine();
5489:            }
5490:
5491:            /**
5492:             * Write the text to the File.
5493:             *
5494:             * @param file a File
5495:             * @param text the text to write to the File
5496:             * @throws IOException
5497:             */
5498:            public static void write(File file, String text) throws IOException {
5499:                BufferedWriter writer = null;
5500:                try {
5501:                    writer = newWriter(file);
5502:                    writer.write(text);
5503:                    writer.flush();
5504:
5505:                    Writer temp = writer;
5506:                    writer = null;
5507:                    temp.close();
5508:                } finally {
5509:                    if (writer != null) {
5510:                        try {
5511:                            writer.close();
5512:                        } catch (Exception e) {
5513:                            // ignore since there has to be an exception already
5514:                            LOG
5515:                                    .warning("Caught exception closing Writer: "
5516:                                            + e);
5517:                        }
5518:                    }
5519:                }
5520:            }
5521:
5522:            /**
5523:             * Write the text to the File.
5524:             *
5525:             * @param file a File
5526:             * @param text the text to write to the File
5527:             * @throws IOException
5528:             */
5529:            public static File leftShift(File file, Object text)
5530:                    throws IOException {
5531:                append(file, text);
5532:                return file;
5533:            }
5534:
5535:            /**
5536:             * Write the text to the File with a specified encoding.
5537:             *
5538:             * @param file    a File
5539:             * @param text    the text to write to the File
5540:             * @param charset the charset used
5541:             * @throws IOException
5542:             */
5543:            public static void write(File file, String text, String charset)
5544:                    throws IOException {
5545:                BufferedWriter writer = null;
5546:                try {
5547:                    writer = newWriter(file, charset);
5548:                    writer.write(text);
5549:                    writer.flush();
5550:
5551:                    Writer temp = writer;
5552:                    writer = null;
5553:                    temp.close();
5554:                } finally {
5555:                    if (writer != null) {
5556:                        try {
5557:                            writer.close();
5558:                        } catch (Exception e) {
5559:                            // ignore since there has to be an exception already
5560:                            LOG
5561:                                    .warning("Caught exception closing Writer: "
5562:                                            + e);
5563:                        }
5564:                    }
5565:                }
5566:            }
5567:
5568:            /**
5569:             * Append the text at the end of the File
5570:             *
5571:             * @param file a File
5572:             * @param text the text to append at the end of the File
5573:             * @throws IOException
5574:             */
5575:            public static void append(File file, Object text)
5576:                    throws IOException {
5577:                BufferedWriter writer = null;
5578:                try {
5579:                    writer = newWriter(file, true);
5580:                    InvokerHelper.write(writer, text);
5581:                    writer.flush();
5582:
5583:                    Writer temp = writer;
5584:                    writer = null;
5585:                    temp.close();
5586:                } finally {
5587:                    if (writer != null) {
5588:                        try {
5589:                            writer.close();
5590:                        } catch (Exception e) {
5591:                            // ignore since there has to be an exception already
5592:                            LOG
5593:                                    .warning("Caught exception closing Writer: "
5594:                                            + e);
5595:                        }
5596:                    }
5597:                }
5598:            }
5599:
5600:            /**
5601:             * Append the text at the end of the File with a specified encoding
5602:             *
5603:             * @param file    a File
5604:             * @param text    the text to append at the end of the File
5605:             * @param charset the charset used
5606:             * @throws IOException
5607:             */
5608:            public static void append(File file, Object text, String charset)
5609:                    throws IOException {
5610:                BufferedWriter writer = null;
5611:                try {
5612:                    writer = newWriter(file, charset, true);
5613:                    InvokerHelper.write(writer, text);
5614:                    writer.flush();
5615:
5616:                    Writer temp = writer;
5617:                    writer = null;
5618:                    temp.close();
5619:                } finally {
5620:                    if (writer != null) {
5621:                        try {
5622:                            writer.close();
5623:                        } catch (Exception e) {
5624:                            // ignore since there has to be an exception already
5625:                            LOG
5626:                                    .warning("Caught exception closing Writer: "
5627:                                            + e);
5628:                        }
5629:                    }
5630:                }
5631:            }
5632:
5633:            /**
5634:             * Reads the reader into a list of Strings for each line
5635:             *
5636:             * @param reader a Reader
5637:             * @return a List of lines
5638:             * @throws IOException
5639:             */
5640:            public static List readLines(Reader reader) throws IOException {
5641:                IteratorClosureAdapter closure = new IteratorClosureAdapter(
5642:                        reader);
5643:                eachLine(reader, closure);
5644:                return closure.asList();
5645:            }
5646:
5647:            /**
5648:             * This method is used to throw useful exceptions when the eachFile* and eachDir closure methods
5649:             * are used incorrectly.
5650:             *
5651:             * @param dir The directory to check
5652:             * @throws FileNotFoundException    Thrown if the given directory does not exist
5653:             * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
5654:             */
5655:            private static void checkDir(File dir)
5656:                    throws FileNotFoundException, IllegalArgumentException {
5657:                if (!dir.exists())
5658:                    throw new FileNotFoundException(dir.getAbsolutePath());
5659:                if (!dir.isDirectory())
5660:                    throw new IllegalArgumentException(
5661:                            "The provided File object is not a directory: "
5662:                                    + dir.getAbsolutePath());
5663:            }
5664:
5665:            /**
5666:             * Invokes the closure for each file in the given directory
5667:             *
5668:             * @param self    a File
5669:             * @param closure a closure
5670:             * @throws FileNotFoundException    Thrown if the given directory does not exist
5671:             * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
5672:             */
5673:            public static void eachFile(File self, Closure closure)
5674:                    throws FileNotFoundException, IllegalArgumentException {
5675:                checkDir(self);
5676:                File[] files = self.listFiles();
5677:                for (int i = 0; i < files.length; i++) {
5678:                    closure.call(files[i]);
5679:                }
5680:            }
5681:
5682:            /**
5683:             * Invokes the closure for each file in the given directory and recursively.
5684:             * It is a depth-first exploration, directories are included in the search.
5685:             *
5686:             * @param self    a File
5687:             * @param closure a closure
5688:             * @throws FileNotFoundException    Thrown if the given directory does not exist
5689:             * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
5690:             */
5691:            public static void eachFileRecurse(File self, Closure closure)
5692:                    throws FileNotFoundException, IllegalArgumentException {
5693:                checkDir(self);
5694:                File[] files = self.listFiles();
5695:                for (int i = 0; i < files.length; i++) {
5696:                    if (files[i].isDirectory()) {
5697:                        closure.call(files[i]);
5698:                        eachFileRecurse(files[i], closure);
5699:                    } else {
5700:                        closure.call(files[i]);
5701:                    }
5702:                }
5703:            }
5704:
5705:            /**
5706:             * Invokes the closure for each directory in the given directory,
5707:             * ignoring regular files.
5708:             *
5709:             * @param self    a directory
5710:             * @param closure a closure
5711:             * @throws FileNotFoundException    Thrown if the given directory does not exist
5712:             * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
5713:             */
5714:            public static void eachDir(File self, Closure closure)
5715:                    throws FileNotFoundException, IllegalArgumentException {
5716:                checkDir(self);
5717:                File[] files = self.listFiles();
5718:                for (int i = 0; i < files.length; i++) {
5719:                    if (files[i].isDirectory()) {
5720:                        closure.call(files[i]);
5721:                    }
5722:                }
5723:            }
5724:
5725:            /**
5726:             * Invokes the closure for each file matching the given filter in the given directory
5727:             * - calling the isCase() method used by switch statements.  This method can be used
5728:             * with different kinds of filters like regular expresions, classes, ranges etc.
5729:             *
5730:             * @param self    a file
5731:             * @param filter  the filter to perform on the directory (using the isCase(object) method)
5732:             * @param closure
5733:             * @throws FileNotFoundException    Thrown if the given directory does not exist
5734:             * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
5735:             */
5736:            public static void eachFileMatch(File self, Object filter,
5737:                    Closure closure) throws FileNotFoundException,
5738:                    IllegalArgumentException {
5739:                checkDir(self);
5740:                File[] files = self.listFiles();
5741:                MetaClass metaClass = InvokerHelper.getMetaClass(filter);
5742:                for (int i = 0; i < files.length; i++) {
5743:                    if (DefaultTypeTransformation
5744:                            .castToBoolean(metaClass.invokeMethod(filter,
5745:                                    "isCase", files[i].getName()))) {
5746:                        closure.call(files[i]);
5747:                    }
5748:                }
5749:            }
5750:
5751:            /**
5752:             * Allow simple syntax for using timers.
5753:             *
5754:             * @param timer   a timer object
5755:             * @param delay   the delay in milliseconds before running the closure code
5756:             * @param closure
5757:             */
5758:            public static void runAfter(Timer timer, int delay,
5759:                    final Closure closure) {
5760:                TimerTask timerTask = new TimerTask() {
5761:                    public void run() {
5762:                        closure.call();
5763:                    }
5764:                };
5765:                timer.schedule(timerTask, delay);
5766:            }
5767:
5768:            /**
5769:             * Helper method to create a buffered reader for a file
5770:             *
5771:             * @param file a File
5772:             * @return a BufferedReader
5773:             * @throws IOException
5774:             */
5775:            public static BufferedReader newReader(File file)
5776:                    throws IOException {
5777:                CharsetToolkit toolkit = new CharsetToolkit(file);
5778:                return toolkit.getReader();
5779:            }
5780:
5781:            /**
5782:             * Helper method to create a buffered reader for a file, with a specified charset
5783:             *
5784:             * @param file    a File
5785:             * @param charset the charset with which we want to write in the File
5786:             * @return a BufferedReader
5787:             * @throws FileNotFoundException        if the File was not found
5788:             * @throws UnsupportedEncodingException if the encoding specified is not supported
5789:             */
5790:            public static BufferedReader newReader(File file, String charset)
5791:                    throws FileNotFoundException, UnsupportedEncodingException {
5792:                return new BufferedReader(new InputStreamReader(
5793:                        new FileInputStream(file), charset));
5794:            }
5795:
5796:            /**
5797:             * Provides a reader for an arbitrary input stream
5798:             *
5799:             * @param self an input stream
5800:             * @return a reader
5801:             */
5802:            public static BufferedReader newReader(InputStream self) {
5803:                return new BufferedReader(new InputStreamReader(self));
5804:            }
5805:
5806:            /**
5807:             * Helper method to create a new BufferedReader for a file and then
5808:             * passes it into the closure and ensures its closed again afterwords
5809:             *
5810:             * @param file
5811:             * @throws FileNotFoundException
5812:             */
5813:            public static void withReader(File file, Closure closure)
5814:                    throws IOException {
5815:                withReader(newReader(file), closure);
5816:            }
5817:
5818:            /**
5819:             * Helper method to create a buffered output stream for a file
5820:             *
5821:             * @param file
5822:             * @throws FileNotFoundException
5823:             */
5824:            public static BufferedOutputStream newOutputStream(File file)
5825:                    throws IOException {
5826:                return new BufferedOutputStream(new FileOutputStream(file));
5827:            }
5828:
5829:            /**
5830:             * Helper method to create a new OutputStream for a file and then
5831:             * passes it into the closure and ensures its closed again afterwords
5832:             *
5833:             * @param file a File
5834:             * @throws FileNotFoundException
5835:             */
5836:            public static void withOutputStream(File file, Closure closure)
5837:                    throws IOException {
5838:                withStream(newOutputStream(file), closure);
5839:            }
5840:
5841:            /**
5842:             * Helper method to create a new InputStream for a file and then
5843:             * passes it into the closure and ensures its closed again afterwords
5844:             *
5845:             * @param file a File
5846:             * @throws FileNotFoundException
5847:             */
5848:            public static void withInputStream(File file, Closure closure)
5849:                    throws IOException {
5850:                withStream(newInputStream(file), closure);
5851:            }
5852:
5853:            /**
5854:             * Helper method to create a buffered writer for a file
5855:             *
5856:             * @param file a File
5857:             * @return a BufferedWriter
5858:             * @throws FileNotFoundException
5859:             */
5860:            public static BufferedWriter newWriter(File file)
5861:                    throws IOException {
5862:                return new BufferedWriter(new FileWriter(file));
5863:            }
5864:
5865:            /**
5866:             * Helper method to create a buffered writer for a file in append mode
5867:             *
5868:             * @param file   a File
5869:             * @param append true if in append mode
5870:             * @return a BufferedWriter
5871:             * @throws FileNotFoundException
5872:             */
5873:            public static BufferedWriter newWriter(File file, boolean append)
5874:                    throws IOException {
5875:                return new BufferedWriter(new FileWriter(file, append));
5876:            }
5877:
5878:            /**
5879:             * Helper method to create a buffered writer for a file
5880:             *
5881:             * @param file    a File
5882:             * @param charset the name of the encoding used to write in this file
5883:             * @param append  true if in append mode
5884:             * @return a BufferedWriter
5885:             * @throws FileNotFoundException
5886:             */
5887:            public static BufferedWriter newWriter(File file, String charset,
5888:                    boolean append) throws IOException {
5889:                if (append) {
5890:                    return new BufferedWriter(new OutputStreamWriter(
5891:                            new FileOutputStream(file, append), charset));
5892:                } else {
5893:                    // first write the Byte Order Mark for Unicode encodings
5894:                    FileOutputStream stream = new FileOutputStream(file);
5895:                    if ("UTF-16BE".equals(charset)) {
5896:                        writeUtf16Bom(stream, true);
5897:                    } else if ("UTF-16LE".equals(charset)) {
5898:                        writeUtf16Bom(stream, false);
5899:                    }
5900:                    return new BufferedWriter(new OutputStreamWriter(stream,
5901:                            charset));
5902:                }
5903:            }
5904:
5905:            /**
5906:             * Helper method to create a buffered writer for a file
5907:             *
5908:             * @param file    a File
5909:             * @param charset the name of the encoding used to write in this file
5910:             * @return a BufferedWriter
5911:             * @throws FileNotFoundException
5912:             */
5913:            public static BufferedWriter newWriter(File file, String charset)
5914:                    throws IOException {
5915:                return newWriter(file, charset, false);
5916:            }
5917:
5918:            /**
5919:             * Write a Byte Order Mark at the begining of the file
5920:             *
5921:             * @param stream    the FileOuputStream to write the BOM to
5922:             * @param bigEndian true if UTF 16 Big Endian or false if Low Endian
5923:             * @throws IOException
5924:             */
5925:            private static void writeUtf16Bom(FileOutputStream stream,
5926:                    boolean bigEndian) throws IOException {
5927:                if (bigEndian) {
5928:                    stream.write(-2);
5929:                    stream.write(-1);
5930:                } else {
5931:                    stream.write(-1);
5932:                    stream.write(-2);
5933:                }
5934:            }
5935:
5936:            /**
5937:             * Helper method to create a new BufferedWriter for a file and then
5938:             * passes it into the closure and ensures it is closed again afterwords
5939:             *
5940:             * @param file    a File
5941:             * @param closure a closure
5942:             * @throws FileNotFoundException
5943:             */
5944:            public static void withWriter(File file, Closure closure)
5945:                    throws IOException {
5946:                withWriter(newWriter(file), closure);
5947:            }
5948:
5949:            /**
5950:             * Helper method to create a new BufferedWriter for a file in a specified encoding
5951:             * and then passes it into the closure and ensures it is closed again afterwords
5952:             *
5953:             * @param file    a File
5954:             * @param charset the charset used
5955:             * @param closure a closure
5956:             * @throws FileNotFoundException
5957:             */
5958:            public static void withWriter(File file, String charset,
5959:                    Closure closure) throws IOException {
5960:                withWriter(newWriter(file, charset), closure);
5961:            }
5962:
5963:            /**
5964:             * Helper method to create a new BufferedWriter for a file in a specified encoding
5965:             * in append mode and then passes it into the closure and ensures it is closed again afterwords
5966:             *
5967:             * @param file    a File
5968:             * @param charset the charset used
5969:             * @param closure a closure
5970:             * @throws FileNotFoundException
5971:             */
5972:            public static void withWriterAppend(File file, String charset,
5973:                    Closure closure) throws IOException {
5974:                withWriter(newWriter(file, charset, true), closure);
5975:            }
5976:
5977:            /**
5978:             * Helper method to create a new PrintWriter for a file
5979:             *
5980:             * @param file a File
5981:             * @throws FileNotFoundException
5982:             */
5983:            public static PrintWriter newPrintWriter(File file)
5984:                    throws IOException {
5985:                return new PrintWriter(newWriter(file));
5986:            }
5987:
5988:            /**
5989:             * Helper method to create a new PrintWriter for a file with a specified charset
5990:             *
5991:             * @param file    a File
5992:             * @param charset the charset
5993:             * @return a PrintWriter
5994:             * @throws FileNotFoundException
5995:             */
5996:            public static PrintWriter newPrintWriter(File file, String charset)
5997:                    throws IOException {
5998:                return new PrintWriter(newWriter(file, charset));
5999:            }
6000:
6001:            /**
6002:             * Helper method to create a new PrintWriter for a file and then
6003:             * passes it into the closure and ensures its closed again afterwords
6004:             *
6005:             * @param file a File
6006:             * @throws FileNotFoundException
6007:             */
6008:            public static void withPrintWriter(File file, Closure closure)
6009:                    throws IOException {
6010:                withWriter(newPrintWriter(file), closure);
6011:            }
6012:
6013:            /**
6014:             * Allows a writer to be used, calling the closure with the writer
6015:             * and then ensuring that the writer is closed down again irrespective
6016:             * of whether exceptions occur or the
6017:             *
6018:             * @param writer  the writer which is used and then closed
6019:             * @param closure the closure that the writer is passed into
6020:             * @throws IOException
6021:             */
6022:            public static void withWriter(Writer writer, Closure closure)
6023:                    throws IOException {
6024:                try {
6025:                    closure.call(writer);
6026:                    writer.flush();
6027:
6028:                    Writer temp = writer;
6029:                    writer = null;
6030:                    temp.close();
6031:                } finally {
6032:                    if (writer != null) {
6033:                        try {
6034:                            writer.close();
6035:                        } catch (Exception e) {
6036:                            // ignore since there has to be an exception already
6037:                            LOG
6038:                                    .warning("Caught exception closing Writer: "
6039:                                            + e);
6040:                        }
6041:                    }
6042:                }
6043:            }
6044:
6045:            /**
6046:             * Allows a Reader to be used, calling the closure with the reader
6047:             * and then ensuring that the reader is closed down again irrespective
6048:             * of whether exceptions occur or the
6049:             *
6050:             * @param reader  the reader which is used and then closed
6051:             * @param closure the closure that the writer is passed into
6052:             * @throws IOException
6053:             */
6054:            public static void withReader(Reader reader, Closure closure)
6055:                    throws IOException {
6056:                try {
6057:                    closure.call(reader);
6058:
6059:                    Reader temp = reader;
6060:                    reader = null;
6061:                    temp.close();
6062:                } finally {
6063:                    if (reader != null) {
6064:                        try {
6065:                            reader.close();
6066:                        } catch (Exception e) {
6067:                            // ignore since there has to be an exception already
6068:                            LOG
6069:                                    .warning("Caught exception closing Reader: "
6070:                                            + e);
6071:                        }
6072:                    }
6073:                }
6074:            }
6075:
6076:            /**
6077:             * Allows a InputStream to be used, calling the closure with the stream
6078:             * and then ensuring that the stream is closed down again irrespective
6079:             * of whether exceptions occur or the
6080:             *
6081:             * @param stream  the stream which is used and then closed
6082:             * @param closure the closure that the stream is passed into
6083:             * @throws IOException
6084:             */
6085:            public static void withStream(InputStream stream, Closure closure)
6086:                    throws IOException {
6087:                try {
6088:                    closure.call(stream);
6089:
6090:                    InputStream temp = stream;
6091:                    stream = null;
6092:                    temp.close();
6093:                } finally {
6094:                    if (stream != null) {
6095:                        try {
6096:                            stream.close();
6097:                        } catch (Exception e) {
6098:                            // ignore since there has to be an exception already
6099:                            LOG
6100:                                    .warning("Caught exception closing InputStream: "
6101:                                            + e);
6102:                        }
6103:                    }
6104:                }
6105:            }
6106:
6107:            /**
6108:             * Reads the stream into a list of Strings for each line
6109:             *
6110:             * @param stream a stream
6111:             * @return a List of lines
6112:             * @throws IOException
6113:             */
6114:            public static List readLines(InputStream stream) throws IOException {
6115:                return readLines(new BufferedReader(new InputStreamReader(
6116:                        stream)));
6117:            }
6118:
6119:            /**
6120:             * Iterates through the given stream line by line
6121:             *
6122:             * @param stream  a stream
6123:             * @param closure a closure
6124:             * @throws IOException
6125:             */
6126:            public static void eachLine(InputStream stream, Closure closure)
6127:                    throws IOException {
6128:                eachLine(new InputStreamReader(stream), closure);
6129:            }
6130:
6131:            /**
6132:             * Iterates through the lines read from the URL's associated input stream
6133:             *
6134:             * @param url     a URL to open and read
6135:             * @param closure a closure to apply on each line
6136:             * @throws IOException
6137:             */
6138:            public static void eachLine(URL url, Closure closure)
6139:                    throws IOException {
6140:                eachLine(url.openConnection().getInputStream(), closure);
6141:            }
6142:
6143:            /**
6144:             * Helper method to create a new BufferedReader for a URL and then
6145:             * passes it into the closure and ensures its closed again afterwords
6146:             *
6147:             * @param url a URL
6148:             * @throws FileNotFoundException
6149:             */
6150:            public static void withReader(URL url, Closure closure)
6151:                    throws IOException {
6152:                withReader(url.openConnection().getInputStream(), closure);
6153:            }
6154:
6155:            /**
6156:             * Helper method to create a new BufferedReader for a stream and then
6157:             * passes it into the closure and ensures its closed again afterwords
6158:             *
6159:             * @param in a stream
6160:             * @throws FileNotFoundException
6161:             */
6162:            public static void withReader(InputStream in, Closure closure)
6163:                    throws IOException {
6164:                withReader(new InputStreamReader(in), closure);
6165:            }
6166:
6167:            /**
6168:             * Allows an output stream to be used, calling the closure with the output stream
6169:             * and then ensuring that the output stream is closed down again irrespective
6170:             * of whether exceptions occur
6171:             *
6172:             * @param stream  the stream which is used and then closed
6173:             * @param closure the closure that the writer is passed into
6174:             * @throws IOException
6175:             */
6176:            public static void withWriter(OutputStream stream, Closure closure)
6177:                    throws IOException {
6178:                withWriter(new OutputStreamWriter(stream), closure);
6179:            }
6180:
6181:            /**
6182:             * Allows an output stream to be used, calling the closure with the output stream
6183:             * and then ensuring that the output stream is closed down again irrespective
6184:             * of whether exceptions occur.
6185:             *
6186:             * @param stream  the stream which is used and then closed
6187:             * @param charset the charset used
6188:             * @param closure the closure that the writer is passed into
6189:             * @throws IOException
6190:             */
6191:            public static void withWriter(OutputStream stream, String charset,
6192:                    Closure closure) throws IOException {
6193:                withWriter(new OutputStreamWriter(stream, charset), closure);
6194:            }
6195:
6196:            /**
6197:             * Allows a OutputStream to be used, calling the closure with the stream
6198:             * and then ensuring that the stream is closed down again irrespective
6199:             * of whether exceptions occur.
6200:             *
6201:             * @param os      the stream which is used and then closed
6202:             * @param closure the closure that the stream is passed into
6203:             * @throws IOException
6204:             */
6205:            public static void withStream(OutputStream os, Closure closure)
6206:                    throws IOException {
6207:                try {
6208:                    closure.call(os);
6209:                    os.flush();
6210:
6211:                    OutputStream temp = os;
6212:                    os = null;
6213:                    temp.close();
6214:                } finally {
6215:                    if (os != null) {
6216:                        try {
6217:                            os.close();
6218:                        } catch (IOException e) {
6219:                            LOG
6220:                                    .warning("Caught exception closing OutputStream: "
6221:                                            + e);
6222:                        }
6223:                    }
6224:                }
6225:            }
6226:
6227:            /**
6228:             * Helper method to create a buffered input stream for a file
6229:             *
6230:             * @param file a File
6231:             * @return a BufferedInputStream of the file
6232:             * @throws FileNotFoundException
6233:             */
6234:            public static BufferedInputStream newInputStream(File file)
6235:                    throws FileNotFoundException {
6236:                return new BufferedInputStream(new FileInputStream(file));
6237:            }
6238:
6239:            /**
6240:             * Traverse through each byte of the specified File
6241:             *
6242:             * @param self    a File
6243:             * @param closure a closure
6244:             */
6245:            public static void eachByte(File self, Closure closure)
6246:                    throws IOException {
6247:                BufferedInputStream is = newInputStream(self);
6248:                eachByte(is, closure);
6249:            }
6250:
6251:            /**
6252:             * Traverse through each byte of the specified stream. The
6253:             * stream is closed afterwards.
6254:             *
6255:             * @param is      stream to iterate over, closed after the method call
6256:             * @param closure closure to apply to each byte
6257:             * @throws IOException
6258:             */
6259:            public static void eachByte(InputStream is, Closure closure)
6260:                    throws IOException {
6261:                try {
6262:                    while (true) {
6263:                        int b = is.read();
6264:                        if (b == -1) {
6265:                            break;
6266:                        } else {
6267:                            closure.call(new Byte((byte) b));
6268:                        }
6269:                    }
6270:
6271:                    InputStream temp = is;
6272:                    is = null;
6273:                    temp.close();
6274:                } finally {
6275:                    if (is != null) {
6276:                        try {
6277:                            is.close();
6278:                        } catch (IOException e) {
6279:                            LOG
6280:                                    .warning("Caught exception closing InputStream: "
6281:                                            + e);
6282:                        }
6283:                    }
6284:                }
6285:            }
6286:
6287:            /**
6288:             * Traverse through each byte of the specified URL
6289:             *
6290:             * @param url     url to iterate over
6291:             * @param closure closure to apply to each byte
6292:             * @throws IOException
6293:             */
6294:            public static void eachByte(URL url, Closure closure)
6295:                    throws IOException {
6296:                InputStream is = url.openConnection().getInputStream();
6297:                eachByte(is, closure);
6298:            }
6299:
6300:            /**
6301:             * Transforms the characters from a reader with a Closure and
6302:             * write them to a writer.
6303:             *
6304:             * @param reader
6305:             * @param writer
6306:             * @param closure
6307:             */
6308:            public static void transformChar(Reader reader, Writer writer,
6309:                    Closure closure) throws IOException {
6310:                int c;
6311:                try {
6312:                    char[] chars = new char[1];
6313:                    while ((c = reader.read()) != -1) {
6314:                        chars[0] = (char) c;
6315:                        writer.write((String) closure.call(new String(chars)));
6316:                    }
6317:                    writer.flush();
6318:
6319:                    Writer temp2 = writer;
6320:                    writer = null;
6321:                    temp2.close();
6322:                    Reader temp1 = reader;
6323:                    reader = null;
6324:                    temp1.close();
6325:                } finally {
6326:                    if (reader != null) {
6327:                        try {
6328:                            reader.close();
6329:                        } catch (IOException e) {
6330:                            LOG
6331:                                    .warning("Caught exception closing Reader: "
6332:                                            + e);
6333:                        }
6334:                    }
6335:                    if (writer != null) {
6336:                        try {
6337:                            writer.close();
6338:                        } catch (IOException e) {
6339:                            LOG
6340:                                    .warning("Caught exception closing Writer: "
6341:                                            + e);
6342:                        }
6343:                    }
6344:                }
6345:            }
6346:
6347:            /**
6348:             * Transforms the lines from a reader with a Closure and
6349:             * write them to a writer. Both Reader and Writer are
6350:             * closed after the operation
6351:             *
6352:             * @param reader  Lines of text to be transformed. Reader is closed afterwards.
6353:             * @param writer  Where transformed lines are written. Writer is closed afterwards.
6354:             * @param closure Single parameter closure that is called to transform each line of
6355:             *                text from the reader, before writing it to the writer.
6356:             */
6357:            public static void transformLine(Reader reader, Writer writer,
6358:                    Closure closure) throws IOException {
6359:                BufferedReader br = new BufferedReader(reader);
6360:                BufferedWriter bw = new BufferedWriter(writer);
6361:                String line;
6362:                try {
6363:                    while ((line = br.readLine()) != null) {
6364:                        Object o = closure.call(line);
6365:                        if (o != null) {
6366:                            bw.write(o.toString());
6367:                            bw.newLine();
6368:                        }
6369:                    }
6370:                    bw.flush();
6371:
6372:                    Writer temp2 = writer;
6373:                    writer = null;
6374:                    temp2.close();
6375:                    Reader temp1 = reader;
6376:                    reader = null;
6377:                    temp1.close();
6378:                } finally {
6379:                    if (br != null) {
6380:                        try {
6381:                            br.close();
6382:                        } catch (IOException e) {
6383:                            LOG
6384:                                    .warning("Caught exception closing Reader: "
6385:                                            + e);
6386:                        }
6387:                    }
6388:                    if (reader != null) {
6389:                        try {
6390:                            reader.close();
6391:                        } catch (IOException e) {
6392:                            LOG
6393:                                    .warning("Caught exception closing Reader: "
6394:                                            + e);
6395:                        }
6396:                    }
6397:                    if (bw != null) {
6398:                        try {
6399:                            bw.close();
6400:                        } catch (IOException e) {
6401:                            LOG
6402:                                    .warning("Caught exception closing Writer: "
6403:                                            + e);
6404:                        }
6405:                    }
6406:                    if (writer != null) {
6407:                        try {
6408:                            writer.close();
6409:                        } catch (IOException e) {
6410:                            LOG
6411:                                    .warning("Caught exception closing Writer: "
6412:                                            + e);
6413:                        }
6414:                    }
6415:                }
6416:            }
6417:
6418:            /**
6419:             * Filter the lines from a reader and write them on the writer,
6420:             * according to a closure which returns true or false.
6421:             * Both Reader and Writer are closed after the operation.
6422:             *
6423:             * @param reader  a reader, closed after the call
6424:             * @param writer  a writer, closed after the call
6425:             * @param closure the closure which returns booleans
6426:             * @throws IOException
6427:             */
6428:            public static void filterLine(Reader reader, Writer writer,
6429:                    Closure closure) throws IOException {
6430:                BufferedReader br = new BufferedReader(reader);
6431:                BufferedWriter bw = new BufferedWriter(writer);
6432:                String line;
6433:                try {
6434:                    while ((line = br.readLine()) != null) {
6435:                        if (DefaultTypeTransformation.castToBoolean(closure
6436:                                .call(line))) {
6437:                            bw.write(line);
6438:                            bw.newLine();
6439:                        }
6440:                    }
6441:                    bw.flush();
6442:
6443:                    Writer temp2 = writer;
6444:                    writer = null;
6445:                    temp2.close();
6446:                    Reader temp1 = reader;
6447:                    reader = null;
6448:                    temp1.close();
6449:                } finally {
6450:                    if (br != null) {
6451:                        try {
6452:                            br.close();
6453:                        } catch (IOException e) {
6454:                            LOG
6455:                                    .warning("Caught exception closing Reader: "
6456:                                            + e);
6457:                        }
6458:                    }
6459:                    if (reader != null) {
6460:                        try {
6461:                            reader.close();
6462:                        } catch (IOException e) {
6463:                            LOG
6464:                                    .warning("Caught exception closing Reader: "
6465:                                            + e);
6466:                        }
6467:                    }
6468:                    if (bw != null) {
6469:                        try {
6470:                            bw.close();
6471:                        } catch (IOException e) {
6472:                            LOG
6473:                                    .warning("Caught exception closing Writer: "
6474:                                            + e);
6475:                        }
6476:                    }
6477:                    if (writer != null) {
6478:                        try {
6479:                            writer.close();
6480:                        } catch (IOException e) {
6481:                            LOG
6482:                                    .warning("Caught exception closing Writer: "
6483:                                            + e);
6484:                        }
6485:                    }
6486:                }
6487:
6488:            }
6489:
6490:            /**
6491:             * Filters the lines of a File and creates a Writeable in return to
6492:             * stream the filtered lines
6493:             *
6494:             * @param self    a File
6495:             * @param closure a closure which returns a boolean indicating to filter
6496:             *                the line or not
6497:             * @return a Writable closure
6498:             * @throws IOException if <code>self</code> is not readable
6499:             */
6500:            public static Writable filterLine(File self, Closure closure)
6501:                    throws IOException {
6502:                return filterLine(newReader(self), closure);
6503:            }
6504:
6505:            /**
6506:             * Filter the lines from a File and write them on a writer, according to a closure
6507:             * which returns true or false
6508:             *
6509:             * @param self    a File
6510:             * @param writer  a writer
6511:             * @param closure a closure which returns a boolean value and takes a line as input
6512:             * @throws IOException if <code>self</code> is not readable
6513:             */
6514:            public static void filterLine(File self, Writer writer,
6515:                    Closure closure) throws IOException {
6516:                filterLine(newReader(self), writer, closure);
6517:            }
6518:
6519:            /**
6520:             * Filter the lines of a Reader and create a Writable in return to stream
6521:             * the filtered lines.
6522:             *
6523:             * @param reader  a reader
6524:             * @param closure a closure returning a boolean indicating to filter or not a line
6525:             * @return a Writable closure
6526:             */
6527:            public static Writable filterLine(Reader reader,
6528:                    final Closure closure) {
6529:                final BufferedReader br = new BufferedReader(reader);
6530:                return new Writable() {
6531:                    public Writer writeTo(Writer out) throws IOException {
6532:                        BufferedWriter bw = new BufferedWriter(out);
6533:                        String line;
6534:                        while ((line = br.readLine()) != null) {
6535:                            if (DefaultTypeTransformation.castToBoolean(closure
6536:                                    .call(line))) {
6537:                                bw.write(line);
6538:                                bw.newLine();
6539:                            }
6540:                        }
6541:                        bw.flush();
6542:                        return out;
6543:                    }
6544:
6545:                    public String toString() {
6546:                        StringWriter buffer = new StringWriter();
6547:                        try {
6548:                            writeTo(buffer);
6549:                        } catch (IOException e) {
6550:                            throw new StringWriterIOException(e);
6551:                        }
6552:                        return buffer.toString();
6553:                    }
6554:                };
6555:            }
6556:
6557:            /**
6558:             * Filter lines from an input stream using a closure predicate
6559:             *
6560:             * @param self      an input stream
6561:             * @param predicate a closure which returns boolean and takes a line
6562:             * @return a filtered writer
6563:             */
6564:            public static Writable filterLine(InputStream self,
6565:                    Closure predicate) {
6566:                return filterLine(newReader(self), predicate);
6567:            }
6568:
6569:            /**
6570:             * Filters lines from an input stream, writing to a writer, using a closure which
6571:             * returns boolean and takes a line.
6572:             *
6573:             * @param self      an InputStream
6574:             * @param writer    a writer to write output to
6575:             * @param predicate a closure which returns a boolean and takes a line as input
6576:             */
6577:            public static void filterLine(InputStream self, Writer writer,
6578:                    Closure predicate) throws IOException {
6579:                filterLine(newReader(self), writer, predicate);
6580:            }
6581:
6582:            /**
6583:             * Reads the content of the file into an array of byte
6584:             *
6585:             * @param file a File
6586:             * @return a List of Bytes
6587:             */
6588:            public static byte[] readBytes(File file) throws IOException {
6589:                byte[] bytes = new byte[(int) file.length()];
6590:                FileInputStream fileInputStream = new FileInputStream(file);
6591:                DataInputStream dis = new DataInputStream(fileInputStream);
6592:                try {
6593:                    dis.readFully(bytes);
6594:
6595:                    InputStream temp = dis;
6596:                    dis = null;
6597:                    temp.close();
6598:                } finally {
6599:                    if (dis != null) {
6600:                        try {
6601:                            dis.close();
6602:                        } catch (IOException e) {
6603:                            LOG
6604:                                    .warning("Caught exception closing DataInputStream: "
6605:                                            + e);
6606:                        }
6607:                    }
6608:                }
6609:                return bytes;
6610:            }
6611:
6612:            // ================================
6613:            // Socket and ServerSocket methods
6614:
6615:            /**
6616:             * Allows an InputStream and an OutputStream from a Socket to be used,
6617:             * calling the closure with the streams and then ensuring that the streams
6618:             * are closed down again irrespective of whether exceptions occur.
6619:             *
6620:             * @param socket  a Socket
6621:             * @param closure a Closure
6622:             * @throws IOException
6623:             */
6624:            public static void withStreams(Socket socket, Closure closure)
6625:                    throws IOException {
6626:                InputStream input = socket.getInputStream();
6627:                OutputStream output = socket.getOutputStream();
6628:                try {
6629:                    closure.call(new Object[] { input, output });
6630:
6631:                    InputStream temp1 = input;
6632:                    input = null;
6633:                    temp1.close();
6634:                    OutputStream temp2 = output;
6635:                    output = null;
6636:                    temp2.close();
6637:                } finally {
6638:                    if (input != null) {
6639:                        try {
6640:                            input.close();
6641:                        } catch (IOException e) {
6642:                            LOG
6643:                                    .warning("Caught exception closing InputStream: "
6644:                                            + e);
6645:                        }
6646:                    }
6647:                    if (output != null) {
6648:                        try {
6649:                            output.close();
6650:                        } catch (IOException e) {
6651:                            LOG
6652:                                    .warning("Caught exception closing OutputStream: "
6653:                                            + e);
6654:                        }
6655:                    }
6656:                }
6657:            }
6658:
6659:            /**
6660:             * Overloads the left shift operator to provide an append mechanism to
6661:             * add things to the output stream of a socket
6662:             *
6663:             * @param self  a Socket
6664:             * @param value a value to append
6665:             * @return a Writer
6666:             */
6667:            public static Writer leftShift(Socket self, Object value)
6668:                    throws IOException {
6669:                return leftShift(self.getOutputStream(), value);
6670:            }
6671:
6672:            /**
6673:             * Overloads the left shift operator to provide an append mechanism
6674:             * to add bytes to the output stream of a socket
6675:             *
6676:             * @param self  a Socket
6677:             * @param value a value to append
6678:             * @return an OutputStream
6679:             */
6680:            public static OutputStream leftShift(Socket self, byte[] value)
6681:                    throws IOException {
6682:                return leftShift(self.getOutputStream(), value);
6683:            }
6684:
6685:            /**
6686:             * Allow to pass a Closure to the accept methods of ServerSocket
6687:             *
6688:             * @param serverSocket a ServerSocket
6689:             * @param closure      a Closure
6690:             * @return a Socket
6691:             * @throws IOException
6692:             */
6693:            public static Socket accept(ServerSocket serverSocket,
6694:                    final Closure closure) throws IOException {
6695:                final Socket socket = serverSocket.accept();
6696:                new Thread(new Runnable() {
6697:                    public void run() {
6698:                        try {
6699:                            closure.call(socket);
6700:                        } finally {
6701:                            try {
6702:                                socket.close();
6703:                            } catch (IOException e) {
6704:                                LOG.warning("Caught exception closing socket: "
6705:                                        + e);
6706:                            }
6707:                        }
6708:                    }
6709:                }).start();
6710:                return socket;
6711:            }
6712:
6713:            /**
6714:             * @param file a File
6715:             * @return a File which wraps the input file and which implements Writable
6716:             */
6717:            public static File asWritable(File file) {
6718:                return new WritableFile(file);
6719:            }
6720:
6721:            public static Object asType(File f, Class c) {
6722:                if (c == Writable.class) {
6723:                    return asWritable(f);
6724:                }
6725:                return asType((Object) f, c);
6726:            }
6727:
6728:            /**
6729:             * @param file     a File
6730:             * @param encoding the encoding to be used when reading the file's contents
6731:             * @return File which wraps the input file and which implements Writable
6732:             */
6733:            public static File asWritable(File file, String encoding) {
6734:                return new WritableFile(file, encoding);
6735:            }
6736:
6737:            /**
6738:             * Converts the given String into a List of strings of one character
6739:             *
6740:             * @param self a String
6741:             * @return a List of characters (a 1-character String)
6742:             */
6743:            public static List toList(String self) {
6744:                int size = self.length();
6745:                List answer = new ArrayList(size);
6746:                for (int i = 0; i < size; i++) {
6747:                    answer.add(self.substring(i, i + 1));
6748:                }
6749:                return answer;
6750:            }
6751:
6752:            public static Object asType(String self, Class c) {
6753:                if (c == List.class) {
6754:                    return toList(self);
6755:                } else if (c == BigDecimal.class) {
6756:                    return toBigDecimal(self);
6757:                } else if (c == BigInteger.class) {
6758:                    return toBigInteger(self);
6759:                } else if (c == Character.class) {
6760:                    return toCharacter(self);
6761:                } else if (c == Double.class) {
6762:                    return toDouble(self);
6763:                } else if (c == Float.class) {
6764:                    return toFloat(self);
6765:                }
6766:                return asType((Object) self, c);
6767:            }
6768:
6769:            // Process methods
6770:            //-------------------------------------------------------------------------
6771:
6772:            /**
6773:             * An alias method so that a process appears similar to System.out, System.in, System.err;
6774:             * you can use process.in, process.out, process.err in a similar way
6775:             *
6776:             * @return an InputStream
6777:             */
6778:            public static InputStream getIn(Process self) {
6779:                return self.getInputStream();
6780:            }
6781:
6782:            /**
6783:             * Read the text of the output stream of the Process.
6784:             *
6785:             * @param self a Process
6786:             * @return the text of the output
6787:             * @throws IOException
6788:             */
6789:            public static String getText(Process self) throws IOException {
6790:                return getText(new BufferedReader(new InputStreamReader(self
6791:                        .getInputStream())));
6792:            }
6793:
6794:            /**
6795:             * An alias method so that a process appears similar to System.out, System.in, System.err;
6796:             * you can use process.in, process.out, process.err in a similar way
6797:             *
6798:             * @return an InputStream
6799:             */
6800:            public static InputStream getErr(Process self) {
6801:                return self.getErrorStream();
6802:            }
6803:
6804:            /**
6805:             * An alias method so that a process appears similar to System.out, System.in, System.err;
6806:             * you can use process.in, process.out, process.err in a similar way
6807:             *
6808:             * @return an OutputStream
6809:             */
6810:            public static OutputStream getOut(Process self) {
6811:                return self.getOutputStream();
6812:            }
6813:
6814:            /**
6815:             * Overloads the left shift operator to provide an append mechanism
6816:             * to pipe into a Process
6817:             *
6818:             * @param self  a Process
6819:             * @param value a value to append
6820:             * @return a Writer
6821:             */
6822:            public static Writer leftShift(Process self, Object value)
6823:                    throws IOException {
6824:                return leftShift(self.getOutputStream(), value);
6825:            }
6826:
6827:            /**
6828:             * Overloads the left shift operator to provide an append mechanism
6829:             * to pipe into a Process
6830:             *
6831:             * @param self  a Process
6832:             * @param value a value to append
6833:             * @return an OutputStream
6834:             */
6835:            public static OutputStream leftShift(Process self, byte[] value)
6836:                    throws IOException {
6837:                return leftShift(self.getOutputStream(), value);
6838:            }
6839:
6840:            /**
6841:             * Wait for the process to finish during a certain amount of time, otherwise stops the process.
6842:             *
6843:             * @param self           a Process
6844:             * @param numberOfMillis the number of milliseconds to wait before stopping the process
6845:             */
6846:            public static void waitForOrKill(Process self, long numberOfMillis) {
6847:                ProcessRunner runnable = new ProcessRunner(self);
6848:                Thread thread = new Thread(runnable);
6849:                thread.start();
6850:                runnable.waitForOrKill(numberOfMillis);
6851:            }
6852:
6853:            /**
6854:             * gets the input and error streams from a process and reads them
6855:             * to avoid the process to block due to a full ouput buffer. For this
6856:             * two Threads are started, so this method will return immediately
6857:             *
6858:             * @param self a Process
6859:             */
6860:            public static void consumeProcessOutput(Process self) {
6861:                Dumper d = new Dumper(self.getErrorStream());
6862:                Thread t = new Thread(d);
6863:                t.start();
6864:                d = new Dumper(self.getInputStream());
6865:                t = new Thread(d);
6866:                t.start();
6867:            }
6868:
6869:            /**
6870:             * Process each regex group matched substring of the given string. If the closure
6871:             * parameter takes one argument an array with all match groups is passed to it.
6872:             * If the closure takes as many arguments as there are match groups, then each
6873:             * parameter will be one match group.
6874:             *
6875:             * @param self    the source string
6876:             * @param regex   a Regex string
6877:             * @param closure a closure with one parameter or as much parameters as groups
6878:             */
6879:            public static void eachMatch(String self, String regex,
6880:                    Closure closure) {
6881:                Pattern p = Pattern.compile(regex);
6882:                Matcher m = p.matcher(self);
6883:                while (m.find()) {
6884:                    int count = m.groupCount();
6885:                    ArrayList groups = new ArrayList();
6886:                    for (int i = 0; i <= count; i++) {
6887:                        groups.add(m.group(i));
6888:                    }
6889:                    if (groups.size() == 1
6890:                            || closure.getMaximumNumberOfParameters() < groups
6891:                                    .size()) {
6892:                        // not enough parameters there to give each group part
6893:                        // it's own parameter, so try a closure with one parameter
6894:                        // and give it all groups as a array
6895:                        closure.call((Object) groups.toArray());
6896:                    } else {
6897:                        closure.call((Object[]) groups.toArray());
6898:                    }
6899:                }
6900:            }
6901:
6902:            /**
6903:             * Process each matched substring of the given group matcher. The object
6904:             * passed to the closure is an array of strings, matched per a successful match.
6905:             *
6906:             * @param self    the source matcher
6907:             * @param closure a closure
6908:             */
6909:            public static void each(Matcher self, Closure closure) {
6910:                Matcher m = self;
6911:                while (m.find()) {
6912:                    int count = m.groupCount();
6913:                    ArrayList groups = new ArrayList();
6914:                    for (int i = 0; i <= count; i++) {
6915:                        groups.add(m.group(i));
6916:                    }
6917:                    closure.call((Object[]) groups.toArray());
6918:                }
6919:            }
6920:
6921:            /**
6922:             * Iterates over every element of the collection and return the index of the first object
6923:             * that matches the condition specified in the closure
6924:             *
6925:             * @param self    the iteration object over which we iterate
6926:             * @param closure the filter to perform a match on the collection
6927:             * @return an integer that is the index of the first macthed object.
6928:             */
6929:            public static int findIndexOf(Object self, Closure closure) {
6930:                int i = 0;
6931:                for (Iterator iter = InvokerHelper.asIterator(self); iter
6932:                        .hasNext(); i++) {
6933:                    Object value = iter.next();
6934:                    if (DefaultTypeTransformation.castToBoolean(closure
6935:                            .call(value))) {
6936:                        break;
6937:                    }
6938:                }
6939:                return i;
6940:            }
6941:
6942:            /**
6943:             * Iterates through the class loader parents until it finds a loader with a class
6944:             * named equal to org.codehaus.groovy.tools.RootLoader. If there is no such class
6945:             * null will be returned. The name has to be used because a direct compare with
6946:             * == may fail as the class may be loaded through different classloaders.
6947:             *
6948:             * @see org.codehaus.groovy.tools.RootLoader
6949:             */
6950:            public static ClassLoader getRootLoader(ClassLoader cl) {
6951:                while (true) {
6952:                    if (cl == null)
6953:                        return null;
6954:                    if (cl.getClass().getName().equals(
6955:                            RootLoader.class.getName()))
6956:                        return cl;
6957:                    cl = cl.getParent();
6958:                }
6959:            }
6960:
6961:            /**
6962:             * Converts a given object to a type. This method is used through
6963:             * the "as" operator and is overloadable as any other operator.
6964:             *
6965:             * @param obj  the object to convert
6966:             * @param type the goal type
6967:             * @return the resulting object
6968:             */
6969:            public static Object asType(Object obj, Class type) {
6970:                return DefaultTypeTransformation.castToType(obj, type);
6971:            }
6972:
6973:            public static Object newInstance(Class c) {
6974:                return InvokerHelper.getInstance().invokeConstructorOf(c, null);
6975:            }
6976:
6977:            public static Object newInstance(Class c, Object[] args) {
6978:                if (args == null)
6979:                    args = new Object[] { null };
6980:                return InvokerHelper.getInstance().invokeConstructorOf(c, args);
6981:            }
6982:
6983:            /**
6984:             * A Runnable which waits for a process to complete together with a notification scheme
6985:             * allowing another thread to wait a maximum number of seconds for the process to complete
6986:             * before killing it.
6987:             */
6988:            protected static class ProcessRunner implements  Runnable {
6989:                Process process;
6990:                private boolean finished;
6991:
6992:                public ProcessRunner(Process process) {
6993:                    this .process = process;
6994:                }
6995:
6996:                public void run() {
6997:                    try {
6998:                        process.waitFor();
6999:                    } catch (InterruptedException e) {
7000:                    }
7001:                    synchronized (this ) {
7002:                        notifyAll();
7003:                        finished = true;
7004:                    }
7005:                }
7006:
7007:                public synchronized void waitForOrKill(long millis) {
7008:                    if (!finished) {
7009:                        try {
7010:                            wait(millis);
7011:                        } catch (InterruptedException e) {
7012:                        }
7013:                        if (!finished) {
7014:                            process.destroy();
7015:                        }
7016:                    }
7017:                }
7018:            }
7019:
7020:            protected static class RangeInfo {
7021:                protected int from, to;
7022:                protected boolean reverse;
7023:
7024:                public RangeInfo(int from, int to, boolean reverse) {
7025:                    this .from = from;
7026:                    this .to = to;
7027:                    this .reverse = reverse;
7028:                }
7029:            }
7030:
7031:            private static class Dumper implements  Runnable {
7032:                InputStream in;
7033:
7034:                public Dumper(InputStream in) {
7035:                    this .in = in;
7036:                }
7037:
7038:                public void run() {
7039:                    InputStreamReader isr = new InputStreamReader(in);
7040:                    BufferedReader br = new BufferedReader(isr);
7041:                    try {
7042:                        while (br.readLine() != null) {
7043:                        }
7044:                    } catch (IOException e) {
7045:                        throw new GroovyRuntimeException(
7046:                                "exception while reading process stream", e);
7047:                    }
7048:                }
7049:            }
7050:
7051:            public static Iterator iterator(Object o) {
7052:                return DefaultTypeTransformation.asCollection(o).iterator();
7053:            }
7054:
7055:            /**
7056:             * @return an Iterator for an Enumeration
7057:             */
7058:            public static Iterator iterator(final Enumeration enumeration) {
7059:                return new Iterator() {
7060:                    private Object last;
7061:
7062:                    public boolean hasNext() {
7063:                        return enumeration.hasMoreElements();
7064:                    }
7065:
7066:                    public Object next() {
7067:                        last = enumeration.nextElement();
7068:                        return last;
7069:                    }
7070:
7071:                    public void remove() {
7072:                        throw new UnsupportedOperationException(
7073:                                "Cannot remove() from an Enumeration");
7074:                    }
7075:                };
7076:            }
7077:
7078:            // TODO move into DOMCategory once we can make use of optional categories transparent
7079:
7080:            /**
7081:             * @return an Iterator for a NodeList
7082:             */
7083:            public static Iterator iterator(final NodeList nodeList) {
7084:                return new Iterator() {
7085:                    private int current /* = 0 */;
7086:
7087:                    public boolean hasNext() {
7088:                        return current < nodeList.getLength();
7089:                    }
7090:
7091:                    public Object next() {
7092:                        return nodeList.item(current++);
7093:                    }
7094:
7095:                    public void remove() {
7096:                        throw new UnsupportedOperationException(
7097:                                "Cannot remove() from a NodeList iterator");
7098:                    }
7099:                };
7100:            }
7101:
7102:            /**
7103:             * @return an Iterator for a Matcher
7104:             */
7105:            public static Iterator iterator(final Matcher matcher) {
7106:                return new Iterator() {
7107:                    private boolean found /* = false */;
7108:                    private boolean done /* = false */;
7109:
7110:                    public boolean hasNext() {
7111:                        if (done) {
7112:                            return false;
7113:                        }
7114:                        if (!found) {
7115:                            found = matcher.find();
7116:                            if (!found) {
7117:                                done = true;
7118:                            }
7119:                        }
7120:                        return found;
7121:                    }
7122:
7123:                    public Object next() {
7124:                        if (!found) {
7125:                            if (!hasNext()) {
7126:                                throw new NoSuchElementException();
7127:                            }
7128:                        }
7129:                        found = false;
7130:                        return matcher.group();
7131:                    }
7132:
7133:                    public void remove() {
7134:                        throw new UnsupportedOperationException();
7135:                    }
7136:                };
7137:            }
7138:
7139:            /**
7140:             * @return an Iterator for a Reader
7141:             */
7142:            public static Iterator iterator(Reader value) {
7143:                final BufferedReader bufferedReader;
7144:                if (value instanceof  BufferedReader)
7145:                    bufferedReader = (BufferedReader) value;
7146:                else
7147:                    bufferedReader = new BufferedReader(value);
7148:                return new Iterator() {
7149:                    String nextVal /* = null */;
7150:                    boolean nextMustRead = true;
7151:                    boolean hasNext = true;
7152:
7153:                    public boolean hasNext() {
7154:                        if (nextMustRead && hasNext) {
7155:                            try {
7156:                                nextVal = readNext();
7157:                                nextMustRead = false;
7158:                            } catch (IOException e) {
7159:                                hasNext = false;
7160:                            }
7161:                        }
7162:                        return hasNext;
7163:                    }
7164:
7165:                    public Object next() {
7166:                        String retval = null;
7167:                        if (nextMustRead) {
7168:                            try {
7169:                                retval = readNext();
7170:                            } catch (IOException e) {
7171:                                hasNext = false;
7172:                            }
7173:                        } else
7174:                            retval = nextVal;
7175:                        nextMustRead = true;
7176:                        return retval;
7177:                    }
7178:
7179:                    private String readNext() throws IOException {
7180:                        String nv = bufferedReader.readLine();
7181:                        if (nv == null)
7182:                            hasNext = false;
7183:                        return nv;
7184:                    }
7185:
7186:                    public void remove() {
7187:                        throw new UnsupportedOperationException(
7188:                                "Cannot remove() from a Reader Iterator");
7189:                    }
7190:                };
7191:            }
7192:
7193:            /**
7194:             * Standard iterator for a input stream which iterates through the stream content in a byte-based fashion.
7195:             *
7196:             * @param is
7197:             * @return
7198:             */
7199:            public static Iterator iterator(InputStream is) {
7200:                return iterator(new DataInputStream(is));
7201:            }
7202:
7203:            /**
7204:             * Standard iterator for a data input stream which iterates through the stream content in a byte-based fashion.
7205:             *
7206:             * @param dis
7207:             * @return
7208:             */
7209:            public static Iterator iterator(final DataInputStream dis) {
7210:                return new Iterator() {
7211:                    Byte nextVal;
7212:                    boolean nextMustRead = true;
7213:                    boolean hasNext = true;
7214:
7215:                    public boolean hasNext() {
7216:                        if (nextMustRead && hasNext) {
7217:                            try {
7218:                                byte bPrimitive = dis.readByte();
7219:                                nextVal = new Byte(bPrimitive);
7220:                                nextMustRead = false;
7221:                            } catch (IOException e) {
7222:                                hasNext = false;
7223:                            }
7224:                        }
7225:                        return hasNext;
7226:                    }
7227:
7228:                    public Object next() {
7229:                        Byte retval = null;
7230:                        if (nextMustRead) {
7231:                            try {
7232:                                byte b = dis.readByte();
7233:                                retval = new Byte(b);
7234:                            } catch (IOException e) {
7235:                                hasNext = false;
7236:                            }
7237:                        } else
7238:                            retval = nextVal;
7239:                        nextMustRead = true;
7240:                        return retval;
7241:                    }
7242:
7243:                    public void remove() {
7244:                        throw new UnsupportedOperationException(
7245:                                "Cannot remove() from an InputStream Iterator");
7246:                    }
7247:                };
7248:            }
7249:
7250:            /**
7251:             * Standard iterator for a file which iterates through the file content in a line-based fashion.
7252:             *
7253:             * @param f
7254:             * @return
7255:             * @throws IOException
7256:             */
7257:            public static Iterator iterator(File f) throws IOException {
7258:                return iterator(newReader(f));
7259:            }
7260:
7261:            public static Iterator iterator(Iterator it) {
7262:                return it;
7263:            }
7264:
7265:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.