1 46 package groovy.lang; 47 48 import org.codehaus.groovy.runtime.InvokerHelper; 49 import org.codehaus.groovy.runtime.InvokerInvocationException; 50 51 import java.util.*; 52 import java.io.IOException ; 53 import java.io.StringWriter ; 54 import java.io.Writer ; 55 import java.lang.reflect.InvocationTargetException ; 56 import java.lang.reflect.Method ; 57 import java.security.AccessController ; 58 import java.security.PrivilegedAction ; 59 60 67 public abstract class Closure extends GroovyObjectSupport implements Cloneable , Runnable { 68 69 private static final Object noParameters[] = new Object []{null}; 70 private static final Object emptyArray[] = new Object [0]; 71 private static final Object emptyArrayParameter[] = new Object []{emptyArray}; 72 73 private Object delegate; 74 private final Object owner; 75 private final Method doCallMethod; 76 private final HashMap callsMap; 77 private final boolean supportsVarargs; 78 private final Class [] parameterTypes; 79 private final int numberOfParameters; 80 private Object curriedParams[] = emptyArray; 81 82 83 private int directive = 0; 84 public static int DONE = 1; 85 public static int SKIP = 2; 86 87 public Closure(Object delegate) { 88 this.delegate = delegate; 89 this.owner = delegate; 90 91 Class closureClass = this.getClass(); 92 callsMap = new HashMap(); 93 int paramLenTemp = -1; 94 Method doCallTemp = null; 95 96 while (true) { 97 final Method methods[] = closureClass.getDeclaredMethods(); 98 99 int i = 0; 100 101 for (int j = 0; j < methods.length; j++) { 102 if ("doCall".equals(methods[j].getName())) { 103 callsMap.put(new Integer (methods[j].getParameterTypes().length), methods[j]); 104 if (methods[j].getParameterTypes().length > paramLenTemp) { 105 doCallTemp = methods[j]; 106 paramLenTemp = methods[j].getParameterTypes().length; 107 } 108 } 109 } 110 111 if (!callsMap.isEmpty()) { 112 break; 113 } 114 115 closureClass = closureClass.getSuperclass(); 116 } 117 118 this.doCallMethod = doCallTemp; 119 120 AccessController.doPrivileged(new PrivilegedAction () { 121 public Object run() { 122 for (Iterator iter = callsMap.values().iterator(); iter.hasNext(); ) { 123 ((Method ) iter.next()).setAccessible(true); 124 } 125 return null; 126 } 127 }); 128 129 this.parameterTypes = this.doCallMethod.getParameterTypes(); 130 this.numberOfParameters = this.parameterTypes.length; 131 132 if (this.numberOfParameters > 0) { 133 this.supportsVarargs = this.parameterTypes[this.numberOfParameters - 1].equals(Object [].class); 134 } else { 135 this.supportsVarargs = false; 136 } 137 } 138 139 public Object invokeMethod(String method, Object arguments) { 140 if ("doCall".equals(method) || "call".equals(method)) { 141 if (arguments instanceof Object []) { 142 Object [] objs = (Object []) arguments; 143 if ((objs != null) && (objs.length > 1) && (objs[0] instanceof Object [])) { 144 boolean allNull = true; 145 for (int j = 1; j < objs.length; j++) { 146 if (objs[j] != null) { 147 allNull = false; 148 break; 149 } 150 } 151 if (allNull) 152 return callViaReflection((Object []) (objs[0])); 153 } 154 } 155 return callSpecial(arguments); 156 } else if ("curry".equals(method)) { 157 return curry((Object []) arguments); 158 } else { 159 try { 160 return getMetaClass().invokeMethod(this, method, arguments); 161 } catch (MissingMethodException e) { 162 if (owner != this) { 163 try { 164 return InvokerHelper.invokeMethod(this.owner, method, arguments); 166 } catch (InvokerInvocationException iie) { 167 throw iie; 168 } catch (GroovyRuntimeException e1) { 169 if (this.delegate != null && this.delegate != this && this.delegate != this.owner) { 170 try { 172 return InvokerHelper.invokeMethod(this.delegate, method, arguments); 173 } catch (MissingMethodException mme) { 174 throw new InvokerInvocationException(mme); 175 } catch (GroovyRuntimeException gre) { 176 throw new InvokerInvocationException(gre.getCause()); 177 } 178 } 179 } 180 } 181 throw e; 182 } 183 } 184 185 } 186 187 public Object getProperty(String property) { 188 if ("delegate".equals(property)) { 189 return getDelegate(); 190 } else if ("owner".equals(property)) { 191 return getOwner(); 192 } else if ("method".equals(property)) { 193 return getMethod(); 194 } else if ("parameterTypes".equals(property)) { 195 return getParameterTypes(); 196 } else if ("metaClass".equals(property)) { 197 return getMetaClass(); 198 } else if ("class".equals(property)) { 199 return getClass(); 200 } else { 201 try { 202 return InvokerHelper.getProperty(this.owner, property); 204 } catch (GroovyRuntimeException e1) { 205 if (this.delegate != null && this.delegate != this && this.delegate != this.owner) { 206 try { 207 return InvokerHelper.getProperty(this.delegate, property); 209 } catch (GroovyRuntimeException e2) { 210 } 212 } 213 214 throw e1; 215 } 216 } 217 } 218 219 public void setProperty(String property, Object newValue) { 220 if ("delegate".equals(property)) { 221 setDelegate(newValue); 222 } else if ("metaClass".equals(property)) { 223 setMetaClass((MetaClass) newValue); 224 } else { 225 try { 226 InvokerHelper.setProperty(this.owner, property, newValue); 228 return; 229 } catch (GroovyRuntimeException e1) { 230 if (this.delegate != null && this.delegate != this && this.delegate != this.owner) { 231 try { 232 InvokerHelper.setProperty(this.delegate, property, newValue); 234 return; 235 } catch (GroovyRuntimeException e2) { 236 } 238 } 239 240 throw e1; 241 } 242 } 243 } 244 245 public boolean isCase(Object candidate){ 246 return InvokerHelper.asBool(call(candidate)); 247 } 248 249 254 public Object call() { 255 return call(emptyArray); 256 } 257 258 264 public Object call(final Object arguments) { 265 final Object params[]; 266 267 if (this.curriedParams.length != 0) { 268 final Object args[]; 269 270 if (arguments instanceof Object []) { 271 args = (Object []) arguments; 272 } else { 273 args = new Object []{arguments}; 274 } 275 276 params = new Object [this.curriedParams.length + args.length]; 277 278 System.arraycopy(this.curriedParams, 0, params, 0, this.curriedParams.length); 279 System.arraycopy(args, 0, params, this.curriedParams.length, args.length); 280 } else { 281 if (arguments instanceof Object []) { 282 params = (Object []) arguments; 283 } else { 284 return doCall(arguments); 285 } 286 } 287 288 final int lastParam = this.numberOfParameters - 1; 289 290 if (this.supportsVarargs && !(this.numberOfParameters == params.length && (params[lastParam] == null || params[lastParam].getClass() == Object [].class))) { 291 final Object actualParameters[] = new Object [this.numberOfParameters]; 292 293 if (params.length < lastParam) { 298 throw new IncorrectClosureArgumentsException(this, params, this.parameterTypes); 305 } else { 306 final Object rest[] = new Object [params.length - lastParam]; 308 System.arraycopy(params, 0, actualParameters, 0, lastParam); 310 311 System.arraycopy(params, lastParam, rest, 0, rest.length); 313 314 actualParameters[lastParam] = rest; 316 317 return callViaReflection(actualParameters); 318 } 319 } 320 321 if (params.length == 0) { 322 return doCall(); 323 } else if (params.length == 1) { 324 return doCall(params[0]); 325 } else if (params.length == 2) { 326 return doCall(params[0], params[1]); 327 } else { 328 return callViaReflection(params); 329 } 330 } 331 332 public Object callSpecial(final Object arguments) { 333 final Object params[]; 334 335 if (this.curriedParams.length > 0) { 336 final Object args[]; 337 338 if (arguments instanceof Object []) { 339 args = (Object []) arguments; 340 } else { 341 args = new Object []{arguments}; 342 } 343 344 params = new Object [this.curriedParams.length + args.length]; 345 346 System.arraycopy(this.curriedParams, 0, params, 0, this.curriedParams.length); 347 System.arraycopy(args, 0, params, this.curriedParams.length, args.length); 348 } else { 349 Object [] tmpParams = null; 350 if (arguments instanceof Object []) { 351 tmpParams = (Object []) arguments; 352 353 if ((tmpParams != null) && (tmpParams.length > 1)) { 354 boolean allNull = true; 355 for (int j = 1; j < tmpParams.length; j++) { 356 if (tmpParams[j] != null) { 357 allNull = false; 358 break; 359 } 360 } 361 if (allNull) { 362 if (tmpParams[0] instanceof Object []) 363 tmpParams = (Object []) (tmpParams[0]); 364 else 365 throw new IncorrectClosureArgumentsException(this, new Object [] { tmpParams[0] }, this.parameterTypes); 366 } 367 } 368 params = tmpParams; 369 370 } else { 371 return doCall(arguments); 372 } 373 } 374 375 final int lastParam = this.numberOfParameters - 1; 376 377 if (this.supportsVarargs && !(this.numberOfParameters == params.length && (params.length > lastParam) && (params[lastParam] == null || params[lastParam].getClass() == Object [].class))) { 378 final Object actualParameters[] = new Object [this.numberOfParameters]; 379 380 if (params.length < lastParam) { 385 throw new IncorrectClosureArgumentsException(this, params, this.parameterTypes); 392 } else { 393 final Object rest[] = new Object [params.length - lastParam]; 395 System.arraycopy(params, 0, actualParameters, 0, lastParam); 397 398 System.arraycopy(params, lastParam, rest, 0, rest.length); 400 401 actualParameters[lastParam] = rest; 403 404 return callViaReflection(actualParameters); 405 } 406 } 407 408 if (params.length == 0) { 409 return doCall(); 410 } else if (params.length == 1) { 411 return doCall(params[0]); 412 } else if (params.length == 2) { 413 return doCall(params[0], params[1]); 414 } else { 415 return callViaReflection(params); 416 } 417 } 418 419 protected static Object throwRuntimeException(Throwable throwable) { 420 if (throwable instanceof RuntimeException ) { 421 throw (RuntimeException ) throwable; 422 } else { 423 throw new GroovyRuntimeException(throwable.getMessage(), throwable); 424 } 425 } 426 427 436 protected Object doCall(final Object p1) { 437 return callViaReflection(new Object []{p1}); 438 } 439 440 447 protected Object doCall() { 448 return doCall((Object )null); 449 } 450 451 452 461 protected Object doCall(final Object p1, final Object p2) { 462 return callViaReflection(new Object []{p1, p2}); 463 } 464 465 private Object callViaReflection(final Object params[]) { 466 try { 467 return ((Method ) callsMap.get(new Integer (params.length))).invoke(this, params); 469 } catch (final IllegalArgumentException e) { 470 throw new IncorrectClosureArgumentsException(this, params, this.parameterTypes); 471 } catch (final IllegalAccessException e) { 472 final Throwable cause = e.getCause(); 473 474 return throwRuntimeException((cause == null) ? e : cause); 475 } catch (final InvocationTargetException e) { 476 final Throwable cause = e.getCause(); 477 478 return throwRuntimeException((cause == null) ? e : cause); 479 } 480 } 481 482 487 public String getMethod() { 488 return ""; 489 } 490 491 495 public Object getOwner() { 496 return this.owner; 497 } 498 499 503 public Object getDelegate() { 504 return this.delegate; 505 } 506 507 512 public void setDelegate(Object delegate) { 513 this.delegate = delegate; 514 } 515 516 519 public Class [] getParameterTypes() { 520 return this.parameterTypes; 521 } 522 523 526 public Closure asWritable() { 527 return new WritableClosure(); 528 } 529 530 533 public void run() { 534 call(); 535 } 536 537 542 public Closure curry(final Object arguments[]) { 543 final Closure curriedClosure = (Closure) this.clone(); 544 final Object newCurriedParams[] = new Object [curriedClosure.curriedParams.length + arguments.length]; 545 546 System.arraycopy(curriedClosure.curriedParams, 0, newCurriedParams, 0, curriedClosure.curriedParams.length); 547 System.arraycopy(arguments, 0, newCurriedParams, curriedClosure.curriedParams.length, arguments.length); 548 549 curriedClosure.curriedParams = newCurriedParams; 550 551 return curriedClosure; 552 } 553 554 557 public Object clone() { 558 try { 559 return super.clone(); 560 } catch (final CloneNotSupportedException e) { 561 return null; 562 } 563 } 564 565 private class WritableClosure extends Closure implements Writable { 566 public WritableClosure() { 567 super(null); 568 } 569 570 573 public Writer writeTo(Writer out) throws IOException { 574 Closure.this.call(out); 575 576 return out; 577 } 578 579 582 public Object invokeMethod(String method, Object arguments) { 583 if ("clone".equals(method)) { 584 return clone(); 585 } else if ("curry".equals(method)) { 586 return curry((Object []) arguments); 587 } else if ("asWritable".equals(method)) { 588 return asWritable(); 589 } else { 590 return Closure.this.invokeMethod(method, arguments); 591 } 592 } 593 594 597 public Object getProperty(String property) { 598 return Closure.this.getProperty(property); 599 } 600 601 604 public void setProperty(String property, Object newValue) { 605 Closure.this.setProperty(property, newValue); 606 } 607 608 611 public Object call() { 612 return Closure.this.call(); 613 } 614 615 618 public Object call(Object arguments) { 619 return Closure.this.call(arguments); 620 } 621 622 625 protected Object doCall(Object p1) { 626 return Closure.this.doCall(p1); 627 } 628 629 632 protected Object doCall(Object p1, Object p2) { 633 return Closure.this.doCall(p1, p2); 634 } 635 636 639 public Object getDelegate() { 640 return Closure.this.getDelegate(); 641 } 642 643 646 public void setDelegate(Object delegate) { 647 Closure.this.setDelegate(delegate); 648 } 649 650 653 public Class [] getParameterTypes() { 654 return Closure.this.getParameterTypes(); 655 } 656 657 660 public Closure asWritable() { 661 return this; 662 } 663 664 667 public void run() { 668 Closure.this.run(); 669 } 670 671 674 public Closure curry(Object [] arguments) { 675 return Closure.this.curry(arguments).asWritable(); 676 } 677 678 681 public Object clone() { 682 return ((Closure) Closure.this.clone()).asWritable(); 683 } 684 685 688 public int hashCode() { 689 return Closure.this.hashCode(); 690 } 691 692 695 public boolean equals(Object arg0) { 696 return Closure.this.equals(arg0); 697 } 698 699 702 public String toString() { 703 final StringWriter writer = new StringWriter (); 704 705 try { 706 writeTo(writer); 707 } catch (IOException e) { 708 return null; 709 } 710 711 return writer.toString(); 712 } 713 } 714 715 718 public int getDirective() { 719 return directive; 720 } 721 722 725 public void setDirective(int directive) { 726 this.directive = directive; 727 } 728 } 729 | Popular Tags |