1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.codehaus.groovy.runtime;
47
48 import groovy.lang.*;
49
50 import java.beans.Introspector;
51 import java.io.IOException;
52 import java.io.InputStream;
53 import java.io.InputStreamReader;
54 import java.io.Reader;
55 import java.io.StringWriter;
56 import java.io.Writer;
57 import java.math.BigDecimal;
58 import java.math.BigInteger;
59 import java.util.ArrayList;
60 import java.util.Arrays;
61 import java.util.Collection;
62 import java.util.Collections;
63 import java.util.Enumeration;
64 import java.util.HashMap;
65 import java.util.Iterator;
66 import java.util.List;
67 import java.util.Map;
68 import java.util.regex.Matcher;
69 import java.util.regex.Pattern;
70
71 import org.apache.xml.serialize.OutputFormat;
72 import org.apache.xml.serialize.XMLSerializer;
73 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
74 import org.codehaus.groovy.runtime.typehandling.IntegerCache;
75 import org.w3c.dom.Element;
76
77 /***
78 * A static helper class to make bytecode generation easier and act as a facade over the Invoker
79 *
80 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
81 * @version $Revision: 4294 $
82 */
83 public class InvokerHelper {
84 public static final Object[] EMPTY_ARGS = {
85 };
86
87 private static final Object[] EMPTY_MAIN_ARGS = new Object[]{new String[0]};
88
89 private static final Invoker singleton = new Invoker();
90
91
92
93 public static MetaClass getMetaClass(Object object) {
94 return getInstance().getMetaClass(object);
95 }
96
97 public static void removeClass(Class clazz) {
98 getInstance().removeMetaClass(clazz);
99 Introspector.flushFromCaches(clazz);
100 }
101
102 public static Invoker getInstance() {
103 return singleton;
104 }
105
106 public static Object invokeNoArgumentsMethod(Object object, String methodName) {
107 return getInstance().invokeMethod(object, methodName, EMPTY_ARGS);
108 }
109
110 public static Object invokeMethod(Object object, String methodName, Object arguments) {
111 return getInstance().invokeMethod(object, methodName, arguments);
112 }
113
114 public static Object invokeSuperMethod(Object object, String methodName, Object arguments) {
115 return getInstance().invokeSuperMethod(object, methodName, arguments);
116 }
117
118 public static Object invokeMethodSafe(Object object, String methodName, Object arguments) {
119 if (object != null) {
120 return getInstance().invokeMethod(object, methodName, arguments);
121 }
122 return null;
123 }
124
125 public static Object invokeStaticMethod(Class type, String methodName, Object arguments) {
126 return getInstance().invokeStaticMethod(type, methodName, arguments);
127 }
128
129 public static Object invokeStaticMethod(String klass, String methodName, Object arguments) throws ClassNotFoundException {
130 Class type = InvokerHelper.class.forName(klass);
131 return getInstance().invokeStaticMethod(type, methodName, arguments);
132 }
133
134
135 public static Object invokeStaticNoArgumentsMethod(Class type, String methodName) {
136 return getInstance().invokeStaticMethod(type, methodName, EMPTY_ARGS);
137 }
138
139 public static Object invokeConstructorOf(Class type, Object arguments) {
140 return getInstance().invokeConstructorOf(type, arguments);
141 }
142
143 public static Object invokeConstructorOf(String klass, Object arguments) throws ClassNotFoundException {
144 Class type = InvokerHelper.class.forName(klass);
145 return getInstance().invokeConstructorOf(type, arguments);
146 }
147
148 public static Object invokeNoArgumentsConstructorOf(Class type) {
149 return getInstance().invokeConstructorOf(type, EMPTY_ARGS);
150 }
151
152 public static Object invokeClosure(Object closure, Object arguments) {
153 return getInstance().invokeMethod(closure, "doCall", arguments);
154 }
155
156 public static List asList(Object value) {
157 if (value == null) {
158 return Collections.EMPTY_LIST;
159 }
160 else if (value instanceof List) {
161 return (List) value;
162 }
163 else if (value.getClass().isArray()) {
164 return Arrays.asList((Object[]) value);
165 }
166 else if (value instanceof Enumeration) {
167 List answer = new ArrayList();
168 for (Enumeration e = (Enumeration) value; e.hasMoreElements();) {
169 answer.add(e.nextElement());
170 }
171 return answer;
172 }
173 else {
174
175 return Collections.singletonList(value);
176 }
177 }
178
179 public static String toString(Object arguments) {
180 if (arguments instanceof Object[])
181 return toArrayString((Object[])arguments);
182 else if (arguments instanceof Collection)
183 return toListString((Collection)arguments);
184 else if (arguments instanceof Map)
185 return toMapString((Map)arguments);
186 else if (arguments instanceof Collection)
187 return format(arguments, true);
188 else
189 return format(arguments, false);
190 }
191
192 public static String inspect(Object self) {
193 return format(self, true);
194 }
195
196 public static Object getAttribute(Object object, String attribute) {
197 return getInstance().getAttribute(object, attribute);
198 }
199
200 public static void setAttribute(Object object, String attribute, Object newValue) {
201 getInstance().setAttribute(object, attribute, newValue);
202 }
203
204 public static Object getProperty(Object object, String property) {
205 return getInstance().getProperty(object, property);
206 }
207
208 public static Object getPropertySafe(Object object, String property) {
209 if (object != null) {
210 return getInstance().getProperty(object, property);
211 }
212 return null;
213 }
214
215 public static void setProperty(Object object, String property, Object newValue) {
216 getInstance().setProperty(object, property, newValue);
217 }
218
219 /***
220 * This is so we don't have to reorder the stack when we call this method.
221 * At some point a better name might be in order.
222 */
223 public static void setProperty2(Object newValue, Object object, String property) {
224 getInstance().setProperty(object, property, newValue);
225 }
226
227
228 /***
229 * This is so we don't have to reorder the stack when we call this method.
230 * At some point a better name might be in order.
231 */
232 public static void setGroovyObjectProperty(Object newValue, GroovyObject object, String property) {
233 object.setProperty(property, newValue);
234 }
235
236 public static Object getGroovyObjectProperty(GroovyObject object, String property) {
237 return object.getProperty(property);
238 }
239
240
241 /***
242 * This is so we don't have to reorder the stack when we call this method.
243 * At some point a better name might be in order.
244 */
245 public static void setPropertySafe2(Object newValue, Object object, String property) {
246 if (object != null) {
247 setProperty2(newValue, object, property);
248 }
249 }
250
251 /***
252 * Returns the method pointer for the given object name
253 */
254 public static Closure getMethodPointer(Object object, String methodName) {
255 return getInstance().getMethodPointer(object, methodName);
256 }
257
258 public static Object negate(Object value) {
259 if (value instanceof Integer) {
260 Integer number = (Integer) value;
261 return IntegerCache.integerValue(-number.intValue());
262 }
263 else if (value instanceof Long) {
264 Long number = (Long) value;
265 return new Long(-number.longValue());
266 }
267 else if (value instanceof BigInteger) {
268 return ((BigInteger) value).negate();
269 }
270 else if (value instanceof BigDecimal) {
271 return ((BigDecimal) value).negate();
272 }
273 else if (value instanceof Double) {
274 Double number = (Double) value;
275 return new Double(-number.doubleValue());
276 }
277 else if (value instanceof Float) {
278 Float number = (Float) value;
279 return new Float(-number.floatValue());
280 }
281 else if (value instanceof ArrayList) {
282
283 ArrayList newlist = new ArrayList();
284 Iterator it = ((ArrayList) value).iterator();
285 for (; it.hasNext();) {
286 newlist.add(negate(it.next()));
287 }
288 return newlist;
289 }
290 else {
291 throw new GroovyRuntimeException("Cannot negate type " + value.getClass().getName() + ", value " + value);
292 }
293 }
294
295 /***
296 * Find the right hand regex within the left hand string and return a matcher.
297 *
298 * @param left string to compare
299 * @param right regular expression to compare the string to
300 * @return
301 */
302 public static Matcher findRegex(Object left, Object right) {
303 String stringToCompare;
304 if (left instanceof String) {
305 stringToCompare = (String) left;
306 }
307 else {
308 stringToCompare = toString(left);
309 }
310 String regexToCompareTo;
311 if (right instanceof String) {
312 regexToCompareTo = (String) right;
313 }
314 else if (right instanceof Pattern) {
315 Pattern pattern = (Pattern) right;
316 return pattern.matcher(stringToCompare);
317 }
318 else {
319 regexToCompareTo = toString(right);
320 }
321 Matcher matcher = Pattern.compile(regexToCompareTo).matcher(stringToCompare);
322 return matcher;
323 }
324
325
326 /***
327 * Find the right hand regex within the left hand string and return a matcher.
328 *
329 * @param left string to compare
330 * @param right regular expression to compare the string to
331 * @return
332 */
333 public static boolean matchRegex(Object left, Object right) {
334 Pattern pattern;
335 if (right instanceof Pattern) {
336 pattern = (Pattern) right;
337 }
338 else {
339 pattern = Pattern.compile(toString(right));
340 }
341 String stringToCompare = toString(left);
342 Matcher matcher = pattern.matcher(stringToCompare);
343 RegexSupport.setLastMatcher(matcher);
344 return matcher.matches();
345 }
346
347 public static Tuple createTuple(Object[] array) {
348 return new Tuple(array);
349 }
350
351 public static SpreadMap spreadMap(Object value) {
352 if (value instanceof Map) {
353 Object[] values = new Object[((Map) value).keySet().size() * 2];
354 int index = 0;
355 Iterator it = ((Map) value).keySet().iterator();
356 for (; it.hasNext();) {
357 Object key = it.next();
358 values[index++] = key;
359 values[index++] = ((Map) value).get(key);
360 }
361 return new SpreadMap(values);
362 }
363 else {
364 throw new SpreadMapEvaluatingException("Cannot spread the map " + value.getClass().getName() + ", value " + value);
365 }
366 }
367
368 public static List createList(Object[] values) {
369 ArrayList answer = new ArrayList(values.length);
370 for (int i = 0; i < values.length; i++) {
371 answer.add(values[i]);
372 }
373 return answer;
374 }
375
376 public static Map createMap(Object[] values) {
377 Map answer = new HashMap(values.length / 2);
378 int i = 0;
379 while (i < values.length - 1) {
380 if ((values[i] instanceof SpreadMap) && (values[i+1] instanceof Map)) {
381 Map smap = (Map) values[i+1];
382 Iterator iter = smap.keySet().iterator();
383 for (; iter.hasNext(); ) {
384 Object key = (Object) iter.next();
385 answer.put(key, smap.get(key));
386 }
387 i+=2;
388 }
389 else {
390 answer.put(values[i++], values[i++]);
391 }
392 }
393 return answer;
394 }
395
396 public static void assertFailed(Object expression, Object message) {
397 if (message == null || "".equals(message)) {
398 throw new AssertionError("Expression: " + expression);
399 }
400 else {
401 throw new AssertionError("" + message + ". Expression: " + expression);
402 }
403 }
404
405 public static Object runScript(Class scriptClass, String[] args) {
406 Binding context = new Binding(args);
407 Script script = createScript(scriptClass, context);
408 return invokeMethod(script, "run", EMPTY_ARGS);
409 }
410
411 public static Script createScript(Class scriptClass, Binding context) {
412
413 if (scriptClass == null) {
414 return new Script() {
415 public Object run() {
416 return null;
417 }
418 };
419 }
420 try {
421 final GroovyObject object = (GroovyObject) scriptClass.newInstance();
422 Script script = null;
423 if (object instanceof Script) {
424 script = (Script) object;
425 }
426 else {
427
428
429 script = new Script() {
430 public Object run() {
431 object.invokeMethod("main", EMPTY_MAIN_ARGS);
432 return null;
433 }
434 };
435 setProperties(object, context.getVariables());
436 }
437 script.setBinding(context);
438 return script;
439 }
440 catch (Exception e) {
441 throw new GroovyRuntimeException("Failed to create Script instance for class: " + scriptClass + ". Reason: " + e,
442 e);
443 }
444 }
445
446 /***
447 * Sets the properties on the given object
448 *
449 * @param object
450 * @param map
451 */
452 public static void setProperties(Object object, Map map) {
453 MetaClass mc = getInstance().getMetaClass(object);
454 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
455 Map.Entry entry = (Map.Entry) iter.next();
456 String key = entry.getKey().toString();
457
458 Object value = entry.getValue();
459 try {
460 mc.setProperty(object, key, value);
461 } catch (MissingPropertyException mpe) {}
462 }
463 }
464
465 public static String getVersion() {
466 String version = null;
467 Package p = Package.getPackage("groovy.lang");
468 if (p != null) {
469 version = p.getImplementationVersion();
470 }
471 if (version == null) {
472 version = "";
473 }
474 return version;
475 }
476
477 /***
478 * Writes the given object to the given stream
479 */
480 public static void write(Writer out, Object object) throws IOException {
481 if (object instanceof String) {
482 out.write((String) object);
483 }
484 else if (object instanceof Object[]) {
485 out.write(toArrayString((Object[]) object));
486 }
487 else if (object instanceof Map) {
488 out.write(toMapString((Map) object));
489 }
490 else if (object instanceof Collection) {
491 out.write(toListString((Collection) object));
492 }
493 else if (object instanceof Writable) {
494 Writable writable = (Writable) object;
495 writable.writeTo(out);
496 }
497 else if (object instanceof InputStream || object instanceof Reader) {
498
499 Reader reader;
500 if (object instanceof InputStream) {
501 reader = new InputStreamReader((InputStream) object);
502 }
503 else {
504 reader = (Reader) object;
505 }
506 char[] chars = new char[8192];
507 int i;
508 while ((i = reader.read(chars)) != -1) {
509 out.write(chars, 0, i);
510 }
511 reader.close();
512 }
513 else {
514 out.write(toString(object));
515 }
516 }
517
518 public static Iterator asIterator(Object o) {
519 return (Iterator) invokeMethod(o,"iterator",EMPTY_ARGS);
520 }
521
522 protected static String format(Object arguments, boolean verbose) {
523 if (arguments == null) {
524 return "null";
525 }
526 else if (arguments.getClass().isArray()) {
527 return format(DefaultTypeTransformation.asCollection(arguments), verbose);
528 }
529 else if (arguments instanceof Range) {
530 Range range = (Range) arguments;
531 if (verbose) {
532 return range.inspect();
533 }
534 else {
535 return range.toString();
536 }
537 }
538 else if (arguments instanceof List) {
539 List list = (List) arguments;
540 StringBuffer buffer = new StringBuffer("[");
541 boolean first = true;
542 for (Iterator iter = list.iterator(); iter.hasNext();) {
543 if (first) {
544 first = false;
545 }
546 else {
547 buffer.append(", ");
548 }
549 buffer.append(format(iter.next(), verbose));
550 }
551 buffer.append("]");
552 return buffer.toString();
553 }
554 else if (arguments instanceof Map) {
555 Map map = (Map) arguments;
556 if (map.isEmpty()) {
557 return "[:]";
558 }
559 StringBuffer buffer = new StringBuffer("[");
560 boolean first = true;
561 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
562 if (first) {
563 first = false;
564 }
565 else {
566 buffer.append(", ");
567 }
568 Map.Entry entry = (Map.Entry) iter.next();
569 buffer.append(format(entry.getKey(), verbose));
570 buffer.append(":");
571 if (entry.getValue()==map) {
572 buffer.append("this Map_");
573 } else {
574 buffer.append(format(entry.getValue(), verbose));
575 }
576 }
577 buffer.append("]");
578 return buffer.toString();
579 }
580 else if (arguments instanceof Element) {
581 Element node = (Element) arguments;
582 OutputFormat format = new OutputFormat(node.getOwnerDocument());
583 format.setOmitXMLDeclaration(true);
584 format.setIndenting(true);
585 format.setLineWidth(0);
586 format.setPreserveSpace(true);
587 StringWriter sw = new StringWriter();
588 XMLSerializer serializer = new XMLSerializer(sw, format);
589 try {
590 serializer.asDOMSerializer();
591 serializer.serialize(node);
592 }
593 catch (IOException e) {
594 }
595 return sw.toString();
596 }
597 else if (arguments instanceof String) {
598 if (verbose) {
599 String arg = ((String)arguments).replaceAll("//n", "////n");
600 arg = arg.replaceAll("//r", "////r");
601 arg = arg.replaceAll("//t", "////t");
602 arg = arg.replaceAll("//f", "////f");
603 arg = arg.replaceAll("//\"", "////\"");
604 arg = arg.replaceAll("////", "////");
605 return "\"" + arg + "\"";
606 }
607 else {
608 return (String) arguments;
609 }
610 }
611 else {
612 return arguments.toString();
613 }
614 }
615
616
617 /***
618 * A helper method to format the arguments types as a comma-separated list
619 */
620 public static String toTypeString(Object[] arguments) {
621 if (arguments == null) {
622 return "null";
623 }
624 StringBuffer argBuf = new StringBuffer();
625 for (int i = 0; i < arguments.length; i++) {
626 if (i > 0) {
627 argBuf.append(", ");
628 }
629 argBuf.append(arguments[i] != null ? arguments[i].getClass().getName() : "null");
630 }
631 return argBuf.toString();
632 }
633
634 /***
635 * A helper method to return the string representation of a map with bracket boundaries "[" and "]".
636 */
637 public static String toMapString(Map arg) {
638 return format(arg, true);
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661 }
662
663 /***
664 * A helper method to return the string representation of a list with bracket boundaries "[" and "]".
665 */
666 public static String toListString(Collection arg) {
667 if (arg == null) {
668 return "null";
669 }
670 if (arg.isEmpty()) {
671 return "[]";
672 }
673 String sbdry = "[";
674 String ebdry = "]";
675 StringBuffer buffer = new StringBuffer(sbdry);
676 boolean first = true;
677 for (Iterator iter = arg.iterator(); iter.hasNext();) {
678 if (first)
679 first = false;
680 else
681 buffer.append(", ");
682 Object elem = iter.next();
683 buffer.append(format(elem, true));
684 }
685 buffer.append(ebdry);
686 return buffer.toString();
687 }
688
689 /***
690 * A helper method to return the string representation of an arrray of objects
691 * with brace boundaries "{" and "}".
692 */
693 public static String toArrayString(Object[] arguments) {
694 if (arguments == null) {
695 return "null";
696 }
697 String sbdry = "{";
698 String ebdry = "}";
699 StringBuffer argBuf = new StringBuffer(sbdry);
700 for (int i = 0; i < arguments.length; i++) {
701 if (i > 0) {
702 argBuf.append(", ");
703 }
704 argBuf.append(format(arguments[i], true));
705 }
706 argBuf.append(ebdry);
707 return argBuf.toString();
708 }
709
710 public static List createRange(Object from, Object to, boolean inclusive) {
711 try {
712 return ScriptBytecodeAdapter.createRange(from,to,inclusive);
713 } catch (RuntimeException re) {
714 throw re;
715 } catch (Error e) {
716 throw e;
717 } catch (Throwable t) {
718 throw new RuntimeException(t);
719 }
720 }
721
722 public static Object bitNegate(Object value) {
723 if (value instanceof Integer) {
724 Integer number = (Integer) value;
725 return new Integer(~number.intValue());
726 }
727 else if (value instanceof Long) {
728 Long number = (Long) value;
729 return new Long(~number.longValue());
730 }
731 else if (value instanceof BigInteger) {
732 return ((BigInteger) value).not();
733
734 }
735 else if (value instanceof String) {
736
737 return DefaultGroovyMethods.negate(value.toString());
738 }
739 else if (value instanceof GString) {
740
741 return DefaultGroovyMethods.negate(value.toString());
742 }
743 else if (value instanceof ArrayList) {
744
745 ArrayList newlist = new ArrayList();
746 Iterator it = ((ArrayList) value).iterator();
747 for (; it.hasNext();) {
748 newlist.add(bitNegate(it.next()));
749 }
750 return newlist;
751 }
752 else {
753 throw new BitwiseNegateEvaluatingException("Cannot bitwise negate type " + value.getClass().getName() + ", value " + value);
754 }
755
756
757 }
758
759 }