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