1 46 package org.codehaus.groovy.runtime; 47 48 import groovy.lang.*; 49 import org.apache.xml.serialize.OutputFormat; 50 import org.apache.xml.serialize.XMLSerializer; 51 import org.w3c.dom.Element ; 52 import org.w3c.dom.Node ; 53 import org.w3c.dom.NodeList ; 54 55 import java.io.File ; 56 import java.io.IOException ; 57 import java.io.StringWriter ; 58 import java.lang.reflect.Method ; 59 import java.security.AccessController ; 60 import java.security.PrivilegedAction ; 61 import java.util.*; 62 import java.util.regex.Matcher ; 63 import java.util.regex.Pattern ; 64 65 71 public class Invoker { 72 73 protected static final Object [] EMPTY_ARGUMENTS = { 74 }; 75 protected static final Class [] EMPTY_TYPES = { 76 }; 77 78 public MetaClassRegistry getMetaRegistry() { 79 return metaRegistry; 80 } 81 82 private MetaClassRegistry metaRegistry = new MetaClassRegistry(); 83 84 public MetaClass getMetaClass(Object object) { 85 return metaRegistry.getMetaClass(object.getClass()); 86 } 87 88 96 public Object invokeMethod(Object object, String methodName, Object arguments) { 97 108 109 if (object == null) { 110 throw new NullPointerException ("Cannot invoke method: " + methodName + " on null object"); 111 } 112 113 if (object instanceof Class ) { 115 Class theClass = (Class ) object; 116 MetaClass metaClass = metaRegistry.getMetaClass(theClass); 117 return metaClass.invokeStaticMethod(object, methodName, asArray(arguments)); 118 } 119 else { 121 if (!(object instanceof GroovyObject)) { 123 Class theClass = object.getClass(); 124 MetaClass metaClass = metaRegistry.getMetaClass(theClass); 125 return metaClass.invokeMethod(object, methodName, asArray(arguments)); 126 } 127 else 129 { 130 if (object instanceof Closure) { 132 Closure closure = (Closure) object; 133 return closure.invokeMethod(methodName, arguments); 134 } 135 else 138 { 139 GroovyObject groovy = (GroovyObject) object; 140 try 141 { 142 return groovy.getMetaClass().invokeMethod(object, methodName, arguments); 144 } 145 catch (MissingMethodException e) 146 { 147 if (e.getMethod().equals(methodName) && object.getClass() == e.getType()) { 148 return groovy.invokeMethod(methodName, arguments); 150 } else { 151 throw e; 152 } 153 } 154 } 155 } 156 } 157 } 158 159 public Object invokeSuperMethod(Object object, String methodName, Object arguments) { 160 if (object == null) { 161 throw new NullPointerException ("Cannot invoke method: " + methodName + " on null object"); 162 } 163 164 Class theClass = object.getClass(); 165 166 MetaClass metaClass = metaRegistry.getMetaClass(theClass.getSuperclass()); 167 return metaClass.invokeMethod(object, methodName, asArray(arguments)); 168 } 169 170 public Object invokeStaticMethod(String type, String method, Object arguments) { 171 MetaClass metaClass = metaRegistry.getMetaClass(loadClass(type)); 172 List argumentList = asList(arguments); 173 return metaClass.invokeStaticMethod(null, method, asArray(arguments)); 174 } 175 176 public Object invokeConstructor(String type, Object arguments) { 177 return invokeConstructorOf(loadClass(type), arguments); 179 } 180 181 public Object invokeConstructorOf(Class type, Object arguments) { 182 MetaClass metaClass = metaRegistry.getMetaClass(type); 183 return metaClass.invokeConstructor(asArray(arguments)); 184 } 185 186 190 public Object [] asArray(Object arguments) { 191 if (arguments == null) { 192 return EMPTY_ARGUMENTS; 193 } 194 if (arguments instanceof Tuple) { 195 Tuple tuple = (Tuple) arguments; 196 return tuple.toArray(); 197 } 198 if (arguments instanceof Object []) { 199 return (Object []) arguments; 200 } else { 201 return new Object []{arguments}; 202 } 203 } 204 205 public List asList(Object value) { 206 if (value == null) { 207 return Collections.EMPTY_LIST; 208 } else if (value instanceof List ) { 209 return (List ) value; 210 } else if (value.getClass().isArray()) { 211 return Arrays.asList((Object []) value); 212 } else if (value instanceof Enumeration) { 213 List answer = new ArrayList(); 214 for (Enumeration e = (Enumeration) value; e.hasMoreElements();) { 215 answer.add(e.nextElement()); 216 } 217 return answer; 218 } else { 219 return Collections.singletonList(value); 221 } 222 } 223 224 228 public Collection asCollection(Object value) { 229 if (value == null) { 230 return Collections.EMPTY_LIST; 231 } else if (value instanceof Collection) { 232 return (Collection) value; 233 } else if (value instanceof Map) { 234 Map map = (Map) value; 235 return map.entrySet(); 236 } else if (value.getClass().isArray()) { 237 if (value.getClass().getComponentType().isPrimitive()) { 238 return InvokerHelper.primitiveArrayToList(value); 239 } 240 return Arrays.asList((Object []) value); 241 } else if (value instanceof MethodClosure) { 242 MethodClosure method = (MethodClosure) value; 243 IteratorClosureAdapter adapter = new IteratorClosureAdapter(method.getDelegate()); 244 method.call(adapter); 245 return adapter.asList(); 246 } else if (value instanceof String ) { 247 return DefaultGroovyMethods.toList((String ) value); 248 } else if (value instanceof File ) { 249 try { 250 return DefaultGroovyMethods.readLines((File ) value); 251 } catch (IOException e) { 252 throw new GroovyRuntimeException("Error reading file: " + value, e); 253 } 254 } else { 255 return Collections.singletonList(value); 257 } 258 } 259 260 public Iterator asIterator(Object value) { 261 if (value == null) { 262 return Collections.EMPTY_LIST.iterator(); 263 } 264 if (value instanceof Iterator) { 265 return (Iterator) value; 266 } 267 if (value instanceof NodeList ) { 268 final NodeList nodeList = (NodeList ) value; 269 return new Iterator() { 270 private int current = 0; 271 272 public boolean hasNext() { 273 return current < nodeList.getLength(); 274 } 275 276 public Object next() { 277 Node node = nodeList.item(current++); 278 return node; 279 } 280 281 public void remove() { 282 throw new UnsupportedOperationException ("Cannot remove() from an Enumeration"); 283 } 284 }; 285 } else if (value instanceof Enumeration) { 286 final Enumeration enumeration = (Enumeration) value; 287 return new Iterator() { 288 private Object last; 289 290 public boolean hasNext() { 291 return enumeration.hasMoreElements(); 292 } 293 294 public Object next() { 295 last = enumeration.nextElement(); 296 return last; 297 } 298 299 public void remove() { 300 throw new UnsupportedOperationException ("Cannot remove() from an Enumeration"); 301 } 302 }; 303 } else if (value instanceof Matcher ) { 304 final Matcher matcher = (Matcher ) value; 305 return new Iterator() { 306 private boolean found = false; 307 private boolean done = false; 308 309 public boolean hasNext() { 310 if (done) 311 return false; 312 if (!found) { 313 found = matcher.find(); 314 if (!found) 315 done = true; 316 } 317 return found; 318 } 319 320 public Object next() { 321 if (!found) { 322 if (!hasNext()) { 323 throw new NoSuchElementException(); 324 } 325 } 326 found = false; 327 return matcher.group(); 328 } 329 330 public void remove() { 331 throw new UnsupportedOperationException (); 332 } 333 }; 334 } else { 335 try { 336 final Method method = value.getClass().getMethod("iterator", EMPTY_TYPES); 338 339 if (method != null) { 340 AccessController.doPrivileged(new PrivilegedAction () { 341 public Object run() { 342 method.setAccessible(true); 343 return null; 344 } 345 }); 346 347 return (Iterator) method.invoke(value, EMPTY_ARGUMENTS); 348 } 349 } catch (Exception e) { 350 } 352 } 353 return asCollection(value).iterator(); 354 } 355 356 359 public boolean objectsEqual(Object left, Object right) { 360 if (left == right) { 361 return true; 362 } 363 if (left != null) { 364 if (right == null) { 365 return false; 366 } 367 if (left instanceof Comparable ) { 368 return compareTo(left, right) == 0; 369 } else { 370 return left.equals(right); 371 } 372 } 373 return false; 374 } 375 376 public String inspect(Object self) { 377 return format(self, true); 378 } 379 380 383 public int compareTo(Object left, Object right) { 384 if (left == right) { 386 return 0; 387 } 388 if (left == null) { 389 return -1; 390 } else if (right == null) { 391 return 1; 392 } 393 if (left instanceof Comparable ) { 394 if (left instanceof Number ) { 395 if (isValidCharacterString(right)) { 396 return asCharacter((Number ) left).compareTo(asCharacter((String ) right)); 397 } 398 return DefaultGroovyMethods.compareTo((Number ) left, asNumber(right)); 399 } else if (left instanceof Character ) { 400 if (isValidCharacterString(right)) { 401 return ((Character ) left).compareTo(asCharacter((String ) right)); 402 } else if (right instanceof Number ) { 403 return ((Character ) left).compareTo(asCharacter((Number ) right)); 404 } 405 } else if (right instanceof Number ) { 406 if (isValidCharacterString(left)) { 407 return asCharacter((String ) left).compareTo(asCharacter((Number ) right)); 408 } 409 return DefaultGroovyMethods.compareTo(asNumber(left), (Number ) right); 410 } else if (left instanceof String && right instanceof Character ) { 411 return ((String ) left).compareTo(right.toString()); 412 } 413 Comparable comparable = (Comparable ) left; 414 return comparable.compareTo(right); 415 } 416 if (left.getClass().isArray()) { 417 Collection leftList = asCollection(left); 418 if (right.getClass().isArray()) { 419 right = asCollection(right); 420 } 421 return ((Comparable ) leftList).compareTo(right); 422 } 423 424 throw new GroovyRuntimeException("Cannot compare values: " + left + " and " + right); 425 } 426 427 431 public String toString(Object arguments) { 432 return format(arguments, false); 433 } 434 435 438 public String toTypeString(Object [] arguments) { 439 if (arguments == null) { 440 return "null"; 441 } 442 StringBuffer argBuf = new StringBuffer (); 443 for (int i = 0; i < arguments.length; i++) { 444 if (i > 0) 445 argBuf.append(", "); 446 argBuf.append(arguments[i] != null ? arguments[i].getClass().getName() : "null"); 447 } 448 return argBuf.toString(); 449 } 450 451 protected String format(Object arguments, boolean verbose) { 452 if (arguments == null) { 453 return "null"; 454 } else if (arguments.getClass().isArray()) { 455 return format(asCollection(arguments), verbose); 456 } else if (arguments instanceof Range) { 457 Range range = (Range) arguments; 458 if (verbose) { 459 return range.inspect(); 460 } else { 461 return range.toString(); 462 } 463 } else if (arguments instanceof List ) { 464 List list = (List ) arguments; 465 StringBuffer buffer = new StringBuffer ("["); 466 boolean first = true; 467 for (Iterator iter = list.iterator(); iter.hasNext();) { 468 if (first) { 469 first = false; 470 } else { 471 buffer.append(", "); 472 } 473 buffer.append(format(iter.next(), verbose)); 474 } 475 buffer.append("]"); 476 return buffer.toString(); 477 } else if (arguments instanceof Map) { 478 Map map = (Map) arguments; 479 if (map.isEmpty()) { 480 return "[:]"; 481 } 482 StringBuffer buffer = new StringBuffer ("["); 483 boolean first = true; 484 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) { 485 if (first) { 486 first = false; 487 } else { 488 buffer.append(", "); 489 } 490 Map.Entry entry = (Map.Entry) iter.next(); 491 buffer.append(format(entry.getKey(), verbose)); 492 buffer.append(":"); 493 buffer.append(format(entry.getValue(), verbose)); 494 } 495 buffer.append("]"); 496 return buffer.toString(); 497 } else if (arguments instanceof Element ) { 498 Element node = (Element ) arguments; 499 OutputFormat format = new OutputFormat(node.getOwnerDocument()); 500 format.setOmitXMLDeclaration(true); 501 format.setIndenting(true); 502 format.setLineWidth(0); 503 format.setPreserveSpace(true); 504 StringWriter sw = new StringWriter (); 505 XMLSerializer serializer = new XMLSerializer(sw, format); 506 try { 507 serializer.asDOMSerializer(); 508 serializer.serialize(node); 509 } catch (IOException e) { 510 } 511 return sw.toString(); 512 } else if (arguments instanceof String ) { 513 if (verbose) { 514 return "\"" + arguments + "\""; 515 } else { 516 return (String ) arguments; 517 } 518 } else { 519 return arguments.toString(); 520 } 521 } 522 523 531 public void setProperty(Object object, String property, Object newValue) { 532 if (object == null) { 533 throw new GroovyRuntimeException("Cannot set property on null object"); 534 } else if (object instanceof GroovyObject) { 535 GroovyObject pogo = (GroovyObject) object; 536 pogo.setProperty(property, newValue); 537 } else if (object instanceof Map) { 538 Map map = (Map) object; 539 map.put(property, newValue); 540 } else { 541 metaRegistry.getMetaClass(object.getClass()).setProperty(object, property, newValue); 542 } 543 } 544 545 552 public Object getProperty(Object object, String property) { 553 if (object == null) { 554 throw new NullPointerException ("Cannot get property: " + property + " on null object"); 555 } else if (object instanceof GroovyObject) { 556 GroovyObject pogo = (GroovyObject) object; 557 return pogo.getProperty(property); 558 } else if (object instanceof Map) { 559 Map map = (Map) object; 560 return map.get(property); 561 } else { 562 return metaRegistry.getMetaClass(object.getClass()).getProperty(object, property); 563 } 564 } 565 566 public int asInt(Object value) { 567 if (value instanceof Number ) { 568 Number n = (Number ) value; 569 return n.intValue(); 570 } 571 throw new GroovyRuntimeException("Could not convert object: " + value + " into an int"); 572 } 573 574 public Number asNumber(Object value) { 575 if (value instanceof Number ) { 576 return (Number ) value; 577 } else if (value instanceof String ) { 578 String s = (String ) value; 579 580 if (s.length() == 1) 581 return new Integer (s.charAt(0)); 582 else 583 return Double.valueOf(s); 584 } else if (value instanceof Character ) { 585 return new Integer (((Character ) value).charValue()); 586 } else { 587 throw new GroovyRuntimeException("Could not convert object: " + value + " into a Number"); 588 } 589 } 590 591 595 protected Class loadClass(String type) { 596 try { 597 return getClass().getClassLoader().loadClass(type); 598 } catch (ClassNotFoundException e) { 599 try { 600 return Thread.currentThread().getContextClassLoader().loadClass(type); 601 } catch (ClassNotFoundException e2) { 602 try { 603 return Class.forName(type); 604 } catch (ClassNotFoundException e3) { 605 } 606 } 607 throw new GroovyRuntimeException("Could not load type: " + type, e); 608 } 609 } 610 611 618 public Matcher objectFindRegex(Object left, Object right) { 619 String stringToCompare; 620 if (left instanceof String ) { 621 stringToCompare = (String ) left; 622 } else { 623 stringToCompare = toString(left); 624 } 625 String regexToCompareTo; 626 if (right instanceof String ) { 627 regexToCompareTo = (String ) right; 628 } else if (right instanceof Pattern ) { 629 Pattern pattern = (Pattern ) right; 630 return pattern.matcher(stringToCompare); 631 } else { 632 regexToCompareTo = toString(right); 633 } 634 Matcher matcher = Pattern.compile(regexToCompareTo).matcher(stringToCompare); 635 return matcher; 636 } 637 638 645 public boolean objectMatchRegex(Object left, Object right) { 646 Pattern pattern; 647 if (right instanceof Pattern ) { 648 pattern = (Pattern ) right; 649 } else { 650 pattern = Pattern.compile(toString(right)); 651 } 652 String stringToCompare = toString(left); 653 Matcher matcher = pattern.matcher(stringToCompare); 654 RegexSupport.setLastMatcher(matcher); 655 return matcher.matches(); 656 } 657 658 664 public Pattern regexPattern(Object regex) { 665 return Pattern.compile(regex.toString()); 666 } 667 668 public Object asType(Object object, Class type) { 669 if (object == null) { 670 return null; 671 } 672 if (type.isInstance(object)) { 673 return object; 674 } 675 if (type.equals(String .class)) { 676 return object.toString(); 677 } 678 if (type.equals(Character .class)) { 679 if (object instanceof Number ) { 680 return asCharacter((Number ) object); 681 } else { 682 String text = object.toString(); 683 if (text.length() == 1) { 684 return new Character (text.charAt(0)); 685 } else { 686 throw new ClassCastException ("Cannot cast: " + text + " to a Character"); 687 } 688 } 689 } 690 if (Number .class.isAssignableFrom(type)) { 691 if (object instanceof Character ) { 692 return new Integer (((Character ) object).charValue()); 693 } else if (object instanceof String ) { 694 String c = (String ) object; 695 if (c.length() == 1) { 696 return new Integer (c.charAt(0)); 697 } else { 698 throw new ClassCastException ("Cannot cast: '" + c + "' to an Integer"); 699 } 700 } 701 } 702 if (object instanceof Number ) { 703 Number n = (Number ) object; 704 if (type.isPrimitive()) { 705 if (type == byte.class) { 706 return new Byte (n.byteValue()); 707 } 708 if (type == char.class) { 709 return new Character ((char) n.intValue()); 710 } 711 if (type == short.class) { 712 return new Short (n.shortValue()); 713 } 714 if (type == int.class) { 715 return new Integer (n.intValue()); 716 } 717 if (type == long.class) { 718 return new Long (n.longValue()); 719 } 720 if (type == float.class) { 721 return new Float (n.floatValue()); 722 } 723 if (type == double.class) { 724 Double answer = new Double (n.doubleValue()); 725 if (!(n instanceof Double ) && (answer.doubleValue() == Double.NEGATIVE_INFINITY 727 || answer.doubleValue() == Double.POSITIVE_INFINITY)) { 728 throw new GroovyRuntimeException("Automatic coercion of " + n.getClass().getName() 729 + " value " + n + " to double failed. Value is out of range."); 730 } 731 return answer; 732 } 733 } else { 734 if (Number .class.isAssignableFrom(type)) { 735 if (type == Byte .class) { 736 return new Byte (n.byteValue()); 737 } 738 if (type == Character .class) { 739 return new Character ((char) n.intValue()); 740 } 741 if (type == Short .class) { 742 return new Short (n.shortValue()); 743 } 744 if (type == Integer .class) { 745 return new Integer (n.intValue()); 746 } 747 if (type == Long .class) { 748 return new Long (n.longValue()); 749 } 750 if (type == Float .class) { 751 return new Float (n.floatValue()); 752 } 753 if (type == Double .class) { 754 Double answer = new Double (n.doubleValue()); 755 if (!(n instanceof Double ) && (answer.doubleValue() == Double.NEGATIVE_INFINITY 757 || answer.doubleValue() == Double.POSITIVE_INFINITY)) { 758 throw new GroovyRuntimeException("Automatic coercion of " + n.getClass().getName() 759 + " value " + n + " to double failed. Value is out of range."); 760 } 761 return answer; 762 } 763 764 } 765 } 766 } 767 if (type == Boolean .class) { 768 return asBool(object) ? Boolean.TRUE : Boolean.FALSE; 769 } 770 return object; 771 } 772 773 public boolean asBool(Object object) { 774 if (object instanceof Boolean ) { 775 Boolean booleanValue = (Boolean ) object; 776 return booleanValue.booleanValue(); 777 } else if (object instanceof Matcher ) { 778 Matcher matcher = (Matcher ) object; 779 RegexSupport.setLastMatcher(matcher); 780 return matcher.find(); 781 } else if (object instanceof Collection) { 782 Collection collection = (Collection) object; 783 return !collection.isEmpty(); 784 } else if (object instanceof Number ) { 785 Number n = (Number ) object; 786 return n.doubleValue() != 0; 787 } else { 788 return object != null; 789 } 790 } 791 792 protected Character asCharacter(Number value) { 793 return new Character ((char) value.intValue()); 794 } 795 796 protected Character asCharacter(String text) { 797 return new Character (text.charAt(0)); 798 } 799 800 803 protected boolean isValidCharacterString(Object value) { 804 if (value instanceof String ) { 805 String s = (String ) value; 806 if (s.length() == 1) { 807 return true; 808 } 809 } 810 return false; 811 } 812 813 public void removeMetaClass(Class clazz) { 814 getMetaRegistry().removeMetaClass(clazz); 815 } 816 } 817 | Popular Tags |