View Javadoc

1   /*
2    $Id: Invoker.java,v 1.76 2005/06/08 20:06:19 glaforge Exp $
3   
4    Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5   
6    Redistribution and use of this software and associated documentation
7    ("Software"), with or without modification, are permitted provided
8    that the following conditions are met:
9   
10   1. Redistributions of source code must retain copyright
11      statements and notices.  Redistributions must also contain a
12      copy of this document.
13  
14   2. Redistributions in binary form must reproduce the
15      above copyright notice, this list of conditions and the
16      following disclaimer in the documentation and/or other
17      materials provided with the distribution.
18  
19   3. The name "groovy" must not be used to endorse or promote
20      products derived from this Software without prior written
21      permission of The Codehaus.  For written permission,
22      please contact info@codehaus.org.
23  
24   4. Products derived from this Software may not be called "groovy"
25      nor may "groovy" appear in their names without prior written
26      permission of The Codehaus. "groovy" is a registered
27      trademark of The Codehaus.
28  
29   5. Due credit should be given to The Codehaus -
30      http://groovy.codehaus.org/
31  
32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43   OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45   */
46  package org.codehaus.groovy.runtime;
47  
48  import org.codehaus.groovy.classgen.AsmClassGenerator;
49  import groovy.lang.Closure;
50  import groovy.lang.GroovyObject;
51  import groovy.lang.GroovyRuntimeException;
52  import groovy.lang.MetaClass;
53  import groovy.lang.MetaClassRegistry;
54  import groovy.lang.MissingMethodException;
55  import groovy.lang.Range;
56  import groovy.lang.SpreadList;
57  import groovy.lang.Tuple;
58  import groovy.lang.GroovyInterceptable;
59  import org.apache.xml.serialize.OutputFormat;
60  import org.apache.xml.serialize.XMLSerializer;
61  import org.w3c.dom.Element;
62  import org.w3c.dom.Node;
63  import org.w3c.dom.NodeList;
64  
65  import java.io.File;
66  import java.io.IOException;
67  import java.io.StringWriter;
68  import java.lang.reflect.Array;
69  import java.lang.reflect.Method;
70  import java.math.BigDecimal;
71  import java.security.AccessController;
72  import java.security.PrivilegedAction;
73  import java.util.ArrayList;
74  import java.util.Arrays;
75  import java.util.Collection;
76  import java.util.Collections;
77  import java.util.Enumeration;
78  import java.util.Iterator;
79  import java.util.List;
80  import java.util.Map;
81  import java.util.NoSuchElementException;
82  import java.util.regex.Matcher;
83  import java.util.regex.Pattern;
84  
85  /***
86   * A helper class to invoke methods or extract properties on arbitrary Java objects dynamically
87   *
88   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
89   * @version $Revision: 1.76 $
90   */
91  public class Invoker {
92  
93      protected static final Object[] EMPTY_ARGUMENTS = {
94      };
95      protected static final Class[] EMPTY_TYPES = {
96      };
97  
98      public MetaClassRegistry getMetaRegistry() {
99          return metaRegistry;
100     }
101 
102     private MetaClassRegistry metaRegistry = new MetaClassRegistry();
103 
104     public MetaClass getMetaClass(Object object) {
105         return metaRegistry.getMetaClass(object.getClass());
106     }
107 
108     /***
109      * Invokes the given method on the object.
110      *
111      * @param object
112      * @param methodName
113      * @param arguments
114      * @return
115      */
116     public Object invokeMethod(Object object, String methodName, Object arguments) {
117         /*
118         System
119             .out
120             .println(
121                 "Invoker - Invoking method on object: "
122                     + object
123                     + " method: "
124                     + methodName
125                     + " arguments: "
126                     + InvokerHelper.toString(arguments));
127                     */
128 
129         if (object == null) {
130             throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
131         }
132 
133         // if the object is a Class, call a static method from that class
134         if (object instanceof Class) {
135             Class theClass = (Class) object;
136             MetaClass metaClass = metaRegistry.getMetaClass(theClass);
137             return metaClass.invokeStaticMethod(object, methodName, asArray(arguments));
138         }
139         else // it's an instance
140         {
141             // if it's not an object implementing GroovyObject (thus not builder, nor a closure)
142             if (!(object instanceof GroovyObject)) {
143                 Class theClass = object.getClass();
144                 MetaClass metaClass = metaRegistry.getMetaClass(theClass);
145                 return metaClass.invokeMethod(object, methodName, asArray(arguments));
146             }
147             // it's an object implementing GroovyObject
148             else {
149                 // if it's a closure, use the closure's invokeMethod()
150                 if (object instanceof Closure) {
151                     Closure closure = (Closure) object;
152                     return closure.invokeMethod(methodName, asArray(arguments));
153                 }
154                 // it's some kind of wacky object that overrides invokeMethod() to do some groovy stuff
155                 // (like a proxy, a builder, some custom funny object which controls the invokation mechanism)
156                 else {
157                     GroovyObject groovy = (GroovyObject) object;
158                     try {
159                         // if it's a pure interceptable object (even intercepting toString(), clone(), ...)
160                         if (groovy instanceof GroovyInterceptable) {
161                             return groovy.invokeMethod(methodName, asArray(arguments));
162                         }
163                         // else if there's a statically typed method or a GDK method
164                         else {
165                             return groovy.getMetaClass().invokeMethod(object, methodName, asArray(arguments));
166                         }
167                     }
168                     catch (MissingMethodException e) {
169                         if (e.getMethod().equals(methodName) && object.getClass() == e.getType()) {
170                             // in case there's nothing else, invoke the object's own invokeMethod()
171                             return groovy.invokeMethod(methodName, asArray(arguments));
172                         }
173                         else {
174                             throw e;
175                         }
176                     }
177                 }
178             }
179         }
180     }
181 
182     public Object invokeSuperMethod(Object object, String methodName, Object arguments) {
183         if (object == null) {
184             throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
185         }
186 
187         Class theClass = object.getClass();
188 
189         MetaClass metaClass = metaRegistry.getMetaClass(theClass.getSuperclass());
190         return metaClass.invokeMethod(object, methodName, asArray(arguments));
191     }
192 
193     public Object invokeStaticMethod(String type, String method, Object arguments) {
194         MetaClass metaClass = metaRegistry.getMetaClass(loadClass(type));
195         List argumentList = asList(arguments);
196         return metaClass.invokeStaticMethod(null, method, asArray(arguments));
197     }
198 
199     public Object invokeConstructor(String type, Object arguments) {
200         return invokeConstructorOf(loadClass(type), arguments);
201     }
202 
203     public Object invokeConstructorOf(Class type, Object arguments) {
204         MetaClass metaClass = metaRegistry.getMetaClass(type);
205         return metaClass.invokeConstructor(asArray(arguments));
206     }
207 
208     /***
209      * Converts the given object into an array; if its an array then just
210      * cast otherwise wrap it in an array
211      */
212     public Object[] asArray(Object arguments) {
213         if (arguments == null) {
214             return EMPTY_ARGUMENTS;
215         }
216         else if ((arguments instanceof Object[]) && ((Object[]) arguments).length == 0) {
217             return (Object[]) arguments;
218         }
219         else if (arguments instanceof Tuple) {
220             Tuple tuple = (Tuple) arguments;
221             Object[] objects = tuple.toArray();
222             ArrayList array = new ArrayList();
223             for (int i = 0; i < objects.length; i++) {
224                 if (objects[i] instanceof SpreadList) {
225                     SpreadList slist = (SpreadList) objects[i];
226                     for (int j = 0; j < slist.size(); j++) {
227                         array.add(slist.get(j));
228                     }
229                 }
230                 else {
231                     array.add(objects[i]);
232                 }
233             }
234             return array.toArray();
235         }
236         else if (arguments instanceof Object[]) {
237             Object[] objects = (Object[]) arguments;
238             ArrayList array = new ArrayList();
239             for (int i = 0; i < objects.length; i++) {
240                 if (objects[i] instanceof SpreadList) {
241                     SpreadList slist = (SpreadList) objects[i];
242                     for (int j = 0; j < slist.size(); j++) {
243                         array.add(slist.get(j));
244                     }
245                 }
246                 else {
247                     array.add(objects[i]);
248                 }
249             }
250             return array.toArray();
251         }
252         else if (arguments instanceof SpreadList) {
253             ArrayList array = new ArrayList();
254             SpreadList slist = (SpreadList) arguments;
255             for (int j = 0; j < slist.size(); j++) {
256                 array.add(slist.get(j));
257             }
258             return array.toArray();
259         }
260         else {
261             return new Object[]{arguments};
262         }
263     }
264 
265     public List asList(Object value) {
266         if (value == null) {
267             return Collections.EMPTY_LIST;
268         }
269         else if (value instanceof List) {
270             return (List) value;
271         }
272         else if (value.getClass().isArray()) {
273             return Arrays.asList((Object[]) value);
274         }
275         else if (value instanceof Enumeration) {
276             List answer = new ArrayList();
277             for (Enumeration e = (Enumeration) value; e.hasMoreElements();) {
278                 answer.add(e.nextElement());
279             }
280             return answer;
281         }
282         else {
283             // lets assume its a collection of 1
284             return Collections.singletonList(value);
285         }
286     }
287 
288     /***
289      * Converts the value parameter into a <code>Collection</code>.
290      *
291      * @param value value to convert
292      * @return a Collection
293      */
294     public Collection asCollection(Object value) {
295         if (value == null) {
296             return Collections.EMPTY_LIST;
297         }
298         else if (value instanceof Collection) {
299             return (Collection) value;
300         }
301         else if (value instanceof Map) {
302             Map map = (Map) value;
303             return map.entrySet();
304         }
305         else if (value.getClass().isArray()) {
306             if (value.getClass().getComponentType().isPrimitive()) {
307                 return InvokerHelper.primitiveArrayToList(value);
308             }
309             return Arrays.asList((Object[]) value);
310         }
311         else if (value instanceof MethodClosure) {
312             MethodClosure method = (MethodClosure) value;
313             IteratorClosureAdapter adapter = new IteratorClosureAdapter(method.getDelegate());
314             method.call(adapter);
315             return adapter.asList();
316         }
317         else if (value instanceof String) {
318             return DefaultGroovyMethods.toList((String) value);
319         }
320         else if (value instanceof File) {
321             try {
322                 return DefaultGroovyMethods.readLines((File) value);
323             }
324             catch (IOException e) {
325                 throw new GroovyRuntimeException("Error reading file: " + value, e);
326             }
327         }
328         else {
329             // lets assume its a collection of 1
330             return Collections.singletonList(value);
331         }
332     }
333 
334     public Iterator asIterator(Object value) {
335         if (value == null) {
336             return Collections.EMPTY_LIST.iterator();
337         }
338         if (value instanceof Iterator) {
339             return (Iterator) value;
340         }
341         if (value instanceof NodeList) {
342             final NodeList nodeList = (NodeList) value;
343             return new Iterator() {
344                 private int current = 0;
345 
346                 public boolean hasNext() {
347                     return current < nodeList.getLength();
348                 }
349 
350                 public Object next() {
351                     Node node = nodeList.item(current++);
352                     return node;
353                 }
354 
355                 public void remove() {
356                     throw new UnsupportedOperationException("Cannot remove() from an Enumeration");
357                 }
358             };
359         }
360         else if (value instanceof Enumeration) {
361             final Enumeration enumeration = (Enumeration) value;
362             return new Iterator() {
363                 private Object last;
364 
365                 public boolean hasNext() {
366                     return enumeration.hasMoreElements();
367                 }
368 
369                 public Object next() {
370                     last = enumeration.nextElement();
371                     return last;
372                 }
373 
374                 public void remove() {
375                     throw new UnsupportedOperationException("Cannot remove() from an Enumeration");
376                 }
377             };
378         }
379         else if (value instanceof Matcher) {
380             final Matcher matcher = (Matcher) value;
381             return new Iterator() {
382                 private boolean found = false;
383                 private boolean done = false;
384 
385                 public boolean hasNext() {
386                     if (done) {
387                         return false;
388                     }
389                     if (!found) {
390                         found = matcher.find();
391                         if (!found) {
392                             done = true;
393                         }
394                     }
395                     return found;
396                 }
397 
398                 public Object next() {
399                     if (!found) {
400                         if (!hasNext()) {
401                             throw new NoSuchElementException();
402                         }
403                     }
404                     found = false;
405                     return matcher.group();
406                 }
407 
408                 public void remove() {
409                     throw new UnsupportedOperationException();
410                 }
411             };
412         }
413         else {
414             try {
415                 // lets try see if there's an iterator() method
416                 final Method method = value.getClass().getMethod("iterator", EMPTY_TYPES);
417 
418                 if (method != null) {
419                     AccessController.doPrivileged(new PrivilegedAction() {
420                         public Object run() {
421                             method.setAccessible(true);
422                             return null;
423                         }
424                     });
425 
426                     return (Iterator) method.invoke(value, EMPTY_ARGUMENTS);
427                 }
428             }
429             catch (Exception e) {
430                 //  ignore
431             }
432         }
433         return asCollection(value).iterator();
434     }
435 
436     /***
437      * @return true if the two objects are null or the objects are equal
438      */
439     public boolean objectsEqual(Object left, Object right) {
440         if (left == right) {
441             return true;
442         }
443         if (left != null) {
444             if (right == null) {
445                 return false;
446             }
447             if (left instanceof Comparable) {
448                 return compareTo(left, right) == 0;
449             }
450             else {
451                 return left.equals(right);
452             }
453         }
454         return false;
455     }
456 
457     public String inspect(Object self) {
458         return format(self, true);
459     }
460 
461     /***
462      * Compares the two objects handling nulls gracefully and performing numeric type coercion if required
463      */
464     public int compareTo(Object left, Object right) {
465         //System.out.println("Comparing: " + left + " to: " + right);
466         if (left == right) {
467             return 0;
468         }
469         if (left == null) {
470             return -1;
471         }
472         else if (right == null) {
473             return 1;
474         }
475         if (left instanceof Comparable) {
476             if (left instanceof Number) {
477                 if (isValidCharacterString(right)) {
478                     return asCharacter((Number) left).compareTo(asCharacter((String) right));
479                 }
480                 return DefaultGroovyMethods.compareTo((Number) left, asNumber(right));
481             }
482             else if (left instanceof Character) {
483                 if (isValidCharacterString(right)) {
484                     return ((Character) left).compareTo(asCharacter((String) right));
485                 }
486                 else if (right instanceof Number) {
487                     return ((Character) left).compareTo(asCharacter((Number) right));
488                 }
489             }
490             else if (right instanceof Number) {
491                 if (isValidCharacterString(left)) {
492                     return asCharacter((String) left).compareTo(asCharacter((Number) right));
493                 }
494                 return DefaultGroovyMethods.compareTo(asNumber(left), (Number) right);
495             }
496             else if (left instanceof String && right instanceof Character) {
497                 return ((String) left).compareTo(right.toString());
498             }
499             Comparable comparable = (Comparable) left;
500             return comparable.compareTo(right);
501         }
502         if (left.getClass().isArray()) {
503             Collection leftList = asCollection(left);
504             if (right.getClass().isArray()) {
505                 right = asCollection(right);
506             }
507             return ((Comparable) leftList).compareTo(right);
508         }
509         /*** todo we might wanna do some type conversion here */
510         throw new GroovyRuntimeException("Cannot compare values: " + left + " and " + right);
511     }
512 
513     /***
514      * A helper method to provide some better toString() behaviour such as turning arrays
515      * into tuples
516      */
517     public String toString(Object arguments) {
518         return format(arguments, false);
519     }
520 
521     /***
522      * A helper method to format the arguments types as a comma-separated list
523      */
524     public String toTypeString(Object[] arguments) {
525         if (arguments == null) {
526             return "null";
527         }
528         StringBuffer argBuf = new StringBuffer();
529         for (int i = 0; i < arguments.length; i++) {
530             if (i > 0) {
531                 argBuf.append(", ");
532             }
533             argBuf.append(arguments[i] != null ? arguments[i].getClass().getName() : "null");
534         }
535         return argBuf.toString();
536     }
537 
538     protected String format(Object arguments, boolean verbose) {
539         if (arguments == null) {
540             return "null";
541         }
542         else if (arguments.getClass().isArray()) {
543             return format(asCollection(arguments), verbose);
544         }
545         else if (arguments instanceof Range) {
546             Range range = (Range) arguments;
547             if (verbose) {
548                 return range.inspect();
549             }
550             else {
551                 return range.toString();
552             }
553         }
554         else if (arguments instanceof List) {
555             List list = (List) arguments;
556             StringBuffer buffer = new StringBuffer("[");
557             boolean first = true;
558             for (Iterator iter = list.iterator(); iter.hasNext();) {
559                 if (first) {
560                     first = false;
561                 }
562                 else {
563                     buffer.append(", ");
564                 }
565                 buffer.append(format(iter.next(), verbose));
566             }
567             buffer.append("]");
568             return buffer.toString();
569         }
570         else if (arguments instanceof Map) {
571             Map map = (Map) arguments;
572             if (map.isEmpty()) {
573                 return "[:]";
574             }
575             StringBuffer buffer = new StringBuffer("[");
576             boolean first = true;
577             for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
578                 if (first) {
579                     first = false;
580                 }
581                 else {
582                     buffer.append(", ");
583                 }
584                 Map.Entry entry = (Map.Entry) iter.next();
585                 buffer.append(format(entry.getKey(), verbose));
586                 buffer.append(":");
587                 buffer.append(format(entry.getValue(), verbose));
588             }
589             buffer.append("]");
590             return buffer.toString();
591         }
592         else if (arguments instanceof Element) {
593             Element node = (Element) arguments;
594             OutputFormat format = new OutputFormat(node.getOwnerDocument());
595             format.setOmitXMLDeclaration(true);
596             format.setIndenting(true);
597             format.setLineWidth(0);
598             format.setPreserveSpace(true);
599             StringWriter sw = new StringWriter();
600             XMLSerializer serializer = new XMLSerializer(sw, format);
601             try {
602                 serializer.asDOMSerializer();
603                 serializer.serialize(node);
604             }
605             catch (IOException e) {
606             }
607             return sw.toString();
608         }
609         else if (arguments instanceof String) {
610             if (verbose) {
611                 return "\"" + arguments + "\"";
612             }
613             else {
614                 return (String) arguments;
615             }
616         }
617         else {
618             return arguments.toString();
619         }
620     }
621 
622     /***
623      * Looks up the given property of the given object
624      */
625     public Object getProperty(Object object, String property) {
626         if (object == null) {
627             throw new NullPointerException("Cannot get property: " + property + " on null object");
628         }
629         else if (object instanceof GroovyObject) {
630             GroovyObject pogo = (GroovyObject) object;
631             return pogo.getProperty(property);
632         }
633         else if (object instanceof Map) {
634             Map map = (Map) object;
635             return map.get(property);
636         }
637         else {
638             return metaRegistry.getMetaClass(object.getClass()).getProperty(object, property);
639         }
640     }
641 
642     /***
643      * Sets the property on the given object
644      */
645     public void setProperty(Object object, String property, Object newValue) {
646         if (object == null) {
647             throw new GroovyRuntimeException("Cannot set property on null object");
648         }
649         else if (object instanceof GroovyObject) {
650             GroovyObject pogo = (GroovyObject) object;
651             pogo.setProperty(property, newValue);
652         }
653         else if (object instanceof Map) {
654             Map map = (Map) object;
655             map.put(property, newValue);
656         }
657         else {
658             metaRegistry.getMetaClass(object.getClass()).setProperty(object, property, newValue);
659         }
660     }
661 
662     /***
663      * Looks up the given attribute (field) on the given object
664      */
665     public Object getAttribute(Object object, String attribute) {
666         if (object == null) {
667             throw new NullPointerException("Cannot get attribute: " + attribute + " on null object");
668 
669             /***
670              } else if (object instanceof GroovyObject) {
671              GroovyObject pogo = (GroovyObject) object;
672              return pogo.getAttribute(attribute);
673              } else if (object instanceof Map) {
674              Map map = (Map) object;
675              return map.get(attribute);
676              */
677         }
678         else {
679             return metaRegistry.getMetaClass(object.getClass()).getAttribute(object, attribute);
680         }
681     }
682 
683     /***
684      * Sets the given attribute (field) on the given object
685      */
686     public void setAttribute(Object object, String attribute, Object newValue) {
687         if (object == null) {
688             throw new GroovyRuntimeException("Cannot set attribute on null object");
689             /*
690         } else if (object instanceof GroovyObject) {
691             GroovyObject pogo = (GroovyObject) object;
692             pogo.setProperty(attribute, newValue);
693         } else if (object instanceof Map) {
694             Map map = (Map) object;
695             map.put(attribute, newValue);
696             */
697         }
698         else {
699             metaRegistry.getMetaClass(object.getClass()).setAttribute(object, attribute, newValue);
700         }
701     }
702 
703     /***
704      * Returns the method pointer for the given object name
705      */
706     public Closure getMethodPointer(Object object, String methodName) {
707         if (object == null) {
708             throw new NullPointerException("Cannot access method pointer for '" + methodName + "' on null object");
709         }
710         return metaRegistry.getMetaClass(object.getClass()).getMethodPointer(object, methodName);
711     }
712 
713 
714     /***
715      * Attempts to load the given class via name using the current class loader
716      * for this code or the thread context class loader
717      */
718     protected Class loadClass(String type) {
719         try {
720             return getClass().getClassLoader().loadClass(type);
721         }
722         catch (ClassNotFoundException e) {
723             try {
724                 return Thread.currentThread().getContextClassLoader().loadClass(type);
725             }
726             catch (ClassNotFoundException e2) {
727                 try {
728                     return Class.forName(type);
729                 }
730                 catch (ClassNotFoundException e3) {
731                 }
732             }
733             throw new GroovyRuntimeException("Could not load type: " + type, e);
734         }
735     }
736 
737     /***
738      * Find the right hand regex within the left hand string and return a matcher.
739      *
740      * @param left  string to compare
741      * @param right regular expression to compare the string to
742      * @return
743      */
744     public Matcher objectFindRegex(Object left, Object right) {
745         String stringToCompare;
746         if (left instanceof String) {
747             stringToCompare = (String) left;
748         }
749         else {
750             stringToCompare = toString(left);
751         }
752         String regexToCompareTo;
753         if (right instanceof String) {
754             regexToCompareTo = (String) right;
755         }
756         else if (right instanceof Pattern) {
757             Pattern pattern = (Pattern) right;
758             return pattern.matcher(stringToCompare);
759         }
760         else {
761             regexToCompareTo = toString(right);
762         }
763         Matcher matcher = Pattern.compile(regexToCompareTo).matcher(stringToCompare);
764         return matcher;
765     }
766 
767     /***
768      * Find the right hand regex within the left hand string and return a matcher.
769      *
770      * @param left  string to compare
771      * @param right regular expression to compare the string to
772      * @return
773      */
774     public boolean objectMatchRegex(Object left, Object right) {
775         Pattern pattern;
776         if (right instanceof Pattern) {
777             pattern = (Pattern) right;
778         }
779         else {
780             pattern = Pattern.compile(toString(right));
781         }
782         String stringToCompare = toString(left);
783         Matcher matcher = pattern.matcher(stringToCompare);
784         RegexSupport.setLastMatcher(matcher);
785         return matcher.matches();
786     }
787 
788     /***
789      * Compile a regular expression from a string.
790      *
791      * @param regex
792      * @return
793      */
794     public Pattern regexPattern(Object regex) {
795         return Pattern.compile(regex.toString());
796     }
797 
798     public Object asType(Object object, Class type) {
799         if (object == null) {
800             return null;
801         }
802         // TODO we should move these methods to groovy method, like g$asType() so that
803         // we can use operator overloading to customize on a per-type basis
804         if (type.isArray()) {
805             return asArray(object, type);
806 
807         }
808         if (type.isInstance(object)) {
809             return object;
810         }
811         if (type.isAssignableFrom(Collection.class)) {
812             if (object.getClass().isArray()) {
813                 // lets call the collections constructor
814                 // passing in the list wrapper
815                 Collection answer = null;
816                 try {
817                     answer = (Collection) type.newInstance();
818                 }
819                 catch (Exception e) {
820                     throw new ClassCastException("Could not instantiate instance of: " + type.getName() + ". Reason: " + e);
821                 }
822 
823                 // we cannot just wrap in a List as we support primitive type arrays
824                 int length = Array.getLength(object);
825                 for (int i = 0; i < length; i++) {
826                     Object element = Array.get(object, i);
827                     answer.add(element);
828                 }
829                 return answer;
830             }
831         }
832         if (type.equals(String.class)) {
833             return object.toString();
834         }
835         if (type.equals(Character.class)) {
836             if (object instanceof Number) {
837                 return asCharacter((Number) object);
838             }
839             else {
840                 String text = object.toString();
841                 if (text.length() == 1) {
842                     return new Character(text.charAt(0));
843                 }
844                 else {
845                     throw new ClassCastException("Cannot cast: " + text + " to a Character");
846                 }
847             }
848         }
849         if (Number.class.isAssignableFrom(type)) {
850             if (object instanceof Character) {
851                 return new Integer(((Character) object).charValue());
852             }
853             else if (object instanceof String) {
854                 String c = (String) object;
855                 if (c.length() == 1) {
856                     return new Integer(c.charAt(0));
857                 }
858                 else {
859                     throw new ClassCastException("Cannot cast: '" + c + "' to an Integer");
860                 }
861             }
862         }
863         if (object instanceof Number) {
864             Number n = (Number) object;
865             if (type.isPrimitive()) {
866                 if (type == byte.class) {
867                     return new Byte(n.byteValue());
868                 }
869                 if (type == char.class) {
870                     return new Character((char) n.intValue());
871                 }
872                 if (type == short.class) {
873                     return new Short(n.shortValue());
874                 }
875                 if (type == int.class) {
876                     return new Integer(n.intValue());
877                 }
878                 if (type == long.class) {
879                     return new Long(n.longValue());
880                 }
881                 if (type == float.class) {
882                     return new Float(n.floatValue());
883                 }
884                 if (type == double.class) {
885                     Double answer = new Double(n.doubleValue());
886                     //throw a runtime exception if conversion would be out-of-range for the type.
887                     if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
888                             || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
889                         throw new GroovyRuntimeException("Automatic coercion of " + n.getClass().getName()
890                                 + " value " + n + " to double failed.  Value is out of range.");
891                     }
892                     return answer;
893                 }
894             }
895             else {
896                 if (Number.class.isAssignableFrom(type)) {
897                     if (type == Byte.class) {
898                         return new Byte(n.byteValue());
899                     }
900                     if (type == Character.class) {
901                         return new Character((char) n.intValue());
902                     }
903                     if (type == Short.class) {
904                         return new Short(n.shortValue());
905                     }
906                     if (type == Integer.class) {
907                         return new Integer(n.intValue());
908                     }
909                     if (type == Long.class) {
910                         return new Long(n.longValue());
911                     }
912                     if (type == Float.class) {
913                         return new Float(n.floatValue());
914                     }
915                     if (type == Double.class) {
916                         Double answer = new Double(n.doubleValue());
917                         //throw a runtime exception if conversion would be out-of-range for the type.
918                         if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
919                                 || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
920                             throw new GroovyRuntimeException("Automatic coercion of " + n.getClass().getName()
921                                     + " value " + n + " to double failed.  Value is out of range.");
922                         }
923                         return answer;
924                     }
925 
926                 }
927             }
928         }
929         if (type == Boolean.class) {
930             return asBool(object) ? Boolean.TRUE : Boolean.FALSE;
931         }
932         Object[] args = null;
933         if (object instanceof Collection) {
934             Collection list = (Collection) object;
935             args = list.toArray();
936         }
937         else if (object instanceof Object[]) {
938             args = (Object[]) object;
939         }
940         if (args != null) {
941             // lets try invoke the constructor with the list as arguments
942             // such as for creating a Dimension, Point, Color etc.
943             try {
944                 return invokeConstructorOf(type, args);
945             }
946             catch (Exception e) {
947                 // lets ignore exception and return the original object
948                 // as the caller has more context to be able to throw a more
949                 // meaningful exception
950             }
951 
952         }
953         return object;
954     }
955 
956     public Object asArray(Object object, Class type) {
957         Collection list = asCollection(object);
958         int size = list.size();
959         Class elementType = type.getComponentType();
960         Object array = Array.newInstance(elementType, size);
961         int idx = 0;
962 
963         if (boolean.class.equals(elementType)) {
964             for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
965                 Object element = iter.next();
966                 Array.setBoolean(array, idx, asBool(element));
967             }
968         }
969         else if (byte.class.equals(elementType)) {
970             for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
971                 Object element = iter.next();
972                 Array.setByte(array, idx, asByte(element));
973             }
974         }
975         else if (char.class.equals(elementType)) {
976             for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
977                 Object element = iter.next();
978                 Array.setChar(array, idx, asChar(element));
979             }
980         }
981         else if (double.class.equals(elementType)) {
982             for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
983                 Object element = iter.next();
984                 Array.setDouble(array, idx, asDouble(element));
985             }
986         }
987         else if (float.class.equals(elementType)) {
988             for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
989                 Object element = iter.next();
990                 Array.setFloat(array, idx, asFloat(element));
991             }
992         }
993         else if (int.class.equals(elementType)) {
994             for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
995                 Object element = iter.next();
996                 Array.setInt(array, idx, asInt(element));
997             }
998         }
999         else if (long.class.equals(elementType)) {
1000             for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
1001                 Object element = iter.next();
1002                 Array.setLong(array, idx, asLong(element));
1003             }
1004         }
1005         else if (short.class.equals(elementType)) {
1006             for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
1007                 Object element = iter.next();
1008                 Array.setShort(array, idx, asShort(element));
1009             }
1010         }
1011         else {
1012             for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
1013                 Object element = iter.next();
1014                 Object coercedElement = asType(element, elementType);
1015                 Array.set(array, idx, coercedElement);
1016             }
1017         }
1018         return array;
1019     }
1020 
1021     public Number asNumber(Object value) {
1022         if (value instanceof Number) {
1023             return (Number) value;
1024         }
1025         else if (value instanceof String) {
1026             String s = (String) value;
1027 
1028             if (s.length() == 1) {
1029                 return new Integer(s.charAt(0));
1030             }
1031             else {
1032                 return new BigDecimal(s);
1033             }
1034         }
1035         else if (value instanceof Character) {
1036             return new Integer(((Character) value).charValue());
1037         }
1038         else {
1039             throw new GroovyRuntimeException("Could not convert object: " + value + " into a Number");
1040         }
1041     }
1042 
1043     public byte asByte(Object element) {
1044         return asNumber(element).byteValue();
1045     }
1046 
1047     public char asChar(Object element) {
1048         if (element instanceof String) {
1049             return asCharacter((String) element).charValue();
1050         }
1051         return asCharacter(asNumber(element)).charValue();
1052     }
1053 
1054     public float asFloat(Object element) {
1055         return asNumber(element).floatValue();
1056     }
1057 
1058     public double asDouble(Object element) {
1059         return asNumber(element).doubleValue();
1060     }
1061 
1062     public short asShort(Object element) {
1063         return asNumber(element).shortValue();
1064     }
1065 
1066     public int asInt(Object element) {
1067         return asNumber(element).intValue();
1068     }
1069 
1070     public long asLong(Object element) {
1071         return asNumber(element).longValue();
1072     }
1073 
1074     public boolean asBool(Object object) {
1075         /*
1076         if (object instanceof Boolean) {
1077             Boolean booleanValue = (Boolean) object;
1078             return booleanValue.booleanValue();
1079         }
1080         else if (object instanceof Matcher) {
1081             Matcher matcher = (Matcher) object;
1082             RegexSupport.setLastMatcher(matcher);
1083             return matcher.find();
1084         }
1085         else if (object instanceof Collection) {
1086             Collection collection = (Collection) object;
1087             return !collection.isEmpty();
1088         }
1089         else if (object instanceof String) {
1090             String string = (String) object;
1091             return string.length() > 0;
1092         }
1093         else if (object instanceof Number) {
1094             Number n = (Number) object;
1095             return n.doubleValue() != 0;
1096         }
1097         else {
1098             return object != null;
1099         }
1100         */
1101         return AsmClassGenerator.asBool(object);
1102     }
1103 
1104     protected Character asCharacter(Number value) {
1105         return new Character((char) value.intValue());
1106     }
1107 
1108     protected Character asCharacter(String text) {
1109         return new Character(text.charAt(0));
1110     }
1111 
1112     /***
1113      * @return true if the given value is a valid character string (i.e. has length of 1)
1114      */
1115     protected boolean isValidCharacterString(Object value) {
1116         if (value instanceof String) {
1117             String s = (String) value;
1118             if (s.length() == 1) {
1119                 return true;
1120             }
1121         }
1122         return false;
1123     }
1124 
1125     public void removeMetaClass(Class clazz) {
1126         getMetaRegistry().removeMetaClass(clazz);
1127     }
1128 }