001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2006 Kresten Krab Thorup <krab@gnu.org>
015: *
016: * Alternatively, the contents of this file may be used under the terms of
017: * either of the GNU General Public License Version 2 or later (the "GPL"),
018: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
019: * in which case the provisions of the GPL or the LGPL are applicable instead
020: * of those above. If you wish to allow use of your version of this file only
021: * under the terms of either the GPL or the LGPL, and not to allow others to
022: * use your version of this file under the terms of the CPL, indicate your
023: * decision by deleting the provisions above and replace them with the notice
024: * and other provisions required by the GPL or the LGPL. If you do not delete
025: * the provisions above, a recipient may use your version of this file under
026: * the terms of any one of the CPL, the GPL or the LGPL.
027: ***** END LICENSE BLOCK *****/package org.jruby.javasupport.proxy;
028:
029: import java.lang.reflect.Array;
030: import java.lang.reflect.Constructor;
031: import java.lang.reflect.InvocationTargetException;
032: import java.lang.reflect.Method;
033: import java.security.AccessController;
034: import java.security.PrivilegedActionException;
035: import java.security.PrivilegedExceptionAction;
036: import java.util.ArrayList;
037: import java.util.Arrays;
038: import java.util.HashMap;
039: import java.util.HashSet;
040: import java.util.Iterator;
041: import java.util.List;
042: import java.util.Map;
043: import java.util.Set;
044:
045: import org.jruby.Ruby;
046: import org.jruby.RubyArray;
047: import org.jruby.RubyClass;
048: import org.jruby.RubyFixnum;
049: import org.jruby.RubyModule;
050: import org.jruby.RubyObject;
051: import org.jruby.RubyNil;
052: import org.jruby.RubyString;
053: import org.jruby.exceptions.RaiseException;
054: import org.jruby.javasupport.JavaClass;
055: import org.jruby.javasupport.JavaObject;
056: import org.jruby.javasupport.JavaUtil;
057: import org.jruby.runtime.CallbackFactory;
058: import org.jruby.runtime.ObjectAllocator;
059: import org.jruby.runtime.builtin.IRubyObject;
060:
061: /**
062: * Generalized proxy for classes and interfaces.
063: *
064: * API looks a lot like java.lang.reflect.Proxy, except that you can specify a
065: * super class in addition to a set of interfaces.
066: *
067: * The main implication for users of this class is to handle the case where a
068: * proxy method overrides an existing method, because in this case the
069: * invocation handler should "default" to calling the super implementation
070: * {JavaProxyMethod.invokeSuper}.
071: *
072: *
073: * @author krab@trifork.com
074: * @see java.lang.reflect.Proxy
075: *
076: */
077: public class JavaProxyClass extends JavaProxyReflectionObject {
078: static ThreadLocal runtimeTLS = new ThreadLocal();
079: private final Class proxyClass;
080: private ArrayList methods = new ArrayList();
081: private HashMap methodMap = new HashMap();
082:
083: /* package scope */
084: JavaProxyClass(Class proxyClass) {
085: super (getThreadLocalRuntime(),
086: (RubyClass) getThreadLocalRuntime().getModule("Java")
087: .getClass("JavaProxyClass"));
088:
089: this .proxyClass = proxyClass;
090: }
091:
092: public Object getValue() {
093: return this ;
094: }
095:
096: private static Ruby getThreadLocalRuntime() {
097: return (Ruby) runtimeTLS.get();
098: }
099:
100: public static JavaProxyClass getProxyClass(Ruby runtime,
101: Class super Class, Class[] interfaces, Set names)
102: throws InvocationTargetException {
103: Object save = runtimeTLS.get();
104: runtimeTLS.set(runtime);
105: try {
106: ClassLoader loader = runtime.getJavaSupport()
107: .getJavaClassLoader();
108:
109: return JavaProxyClassFactory.newProxyClass(loader, null,
110: super Class, interfaces, names);
111: } finally {
112: runtimeTLS.set(save);
113: }
114: }
115:
116: public static JavaProxyClass getProxyClass(Ruby runtime,
117: Class super Class, Class[] interfaces)
118: throws InvocationTargetException {
119: return getProxyClass(runtime, super Class, interfaces, null);
120: }
121:
122: public static Object newProxyInstance(Ruby runtime,
123: Class super Class, Class[] interfaces,
124: Class[] constructorParameters, Object[] constructorArgs,
125: JavaProxyInvocationHandler handler)
126: throws IllegalArgumentException, InstantiationException,
127: IllegalAccessException, InvocationTargetException,
128: SecurityException, NoSuchMethodException {
129: JavaProxyClass jpc = getProxyClass(runtime, super Class,
130: interfaces);
131: JavaProxyConstructor cons = jpc
132: .getConstructor(constructorParameters == null ? new Class[0]
133: : constructorParameters);
134:
135: return cons.newInstance(constructorArgs, handler);
136:
137: }
138:
139: public Class getSuperclass() {
140: return proxyClass.getSuperclass();
141: }
142:
143: public Class[] getInterfaces() {
144: Class[] ifaces = proxyClass.getInterfaces();
145: Class[] result = new Class[ifaces.length - 1];
146: int pos = 0;
147: for (int i = 0; i < ifaces.length; i++) {
148: if (ifaces[i] != InternalJavaProxy.class) {
149: result[pos++] = ifaces[i];
150: }
151: }
152: return result;
153: }
154:
155: public JavaProxyConstructor[] getConstructors() {
156: Constructor[] cons = proxyClass.getConstructors();
157: JavaProxyConstructor[] result = new JavaProxyConstructor[cons.length];
158: for (int i = 0; i < cons.length; i++) {
159: result[i] = new JavaProxyConstructor(getRuntime(), this ,
160: cons[i]);
161: }
162: return result;
163: }
164:
165: public JavaProxyConstructor getConstructor(Class[] args)
166: throws SecurityException, NoSuchMethodException {
167:
168: Class[] realArgs = new Class[args.length + 1];
169: System.arraycopy(args, 0, realArgs, 0, args.length);
170: realArgs[args.length] = JavaProxyInvocationHandler.class;
171:
172: Constructor constructor = proxyClass.getConstructor(realArgs);
173: return new JavaProxyConstructor(getRuntime(), this , constructor);
174: }
175:
176: public JavaProxyMethod[] getMethods() {
177: return (JavaProxyMethod[]) methods
178: .toArray(new JavaProxyMethod[methods.size()]);
179: }
180:
181: public JavaProxyMethod getMethod(String name, Class[] parameterTypes) {
182: List methods = (List) methodMap.get(name);
183: if (methods != null) {
184: for (int i = methods.size(); --i >= 0;) {
185: ProxyMethodImpl jpm = (ProxyMethodImpl) methods.get(i);
186: if (jpm.matches(name, parameterTypes))
187: return jpm;
188: }
189: }
190: return null;
191: }
192:
193: /** return the class of instances of this proxy class */
194: Class getProxyClass() {
195: return proxyClass;
196: }
197:
198: public static class ProxyMethodImpl extends
199: JavaProxyReflectionObject implements JavaProxyMethod {
200: private final Method m;
201:
202: private Object state;
203:
204: private final Method sm;
205: private final Class[] parameterTypes;
206:
207: private final JavaProxyClass clazz;
208:
209: public ProxyMethodImpl(Ruby runtime, JavaProxyClass clazz,
210: Method m, Method sm) {
211: super (runtime, runtime.getModule("Java").getClass(
212: "JavaProxyMethod"));
213: this .m = m;
214: this .parameterTypes = m.getParameterTypes();
215: this .sm = sm;
216: this .clazz = clazz;
217: }
218:
219: public Method getMethod() {
220: return m;
221: }
222:
223: public Method getSuperMethod() {
224: return sm;
225: }
226:
227: public int getModifiers() {
228: return m.getModifiers();
229: }
230:
231: public String getName() {
232: return m.getName();
233: }
234:
235: public Class[] getExceptionTypes() {
236: return m.getExceptionTypes();
237: }
238:
239: public Class[] getParameterTypes() {
240: return parameterTypes;
241: }
242:
243: public Object getState() {
244: return state;
245: }
246:
247: public boolean hasSuperImplementation() {
248: return sm != null;
249: }
250:
251: public Object invoke(Object proxy, Object[] args)
252: throws IllegalArgumentException,
253: IllegalAccessException, InvocationTargetException,
254: NoSuchMethodException {
255:
256: if (!hasSuperImplementation())
257: throw new NoSuchMethodException();
258:
259: return sm.invoke(proxy, args);
260: }
261:
262: public void setState(Object state) {
263: this .state = state;
264: }
265:
266: public String toString() {
267: return m.toString();
268: }
269:
270: public Object defaultResult() {
271: Class rt = m.getReturnType();
272:
273: if (rt == Void.TYPE)
274: return null;
275: if (rt == Boolean.TYPE)
276: return Boolean.FALSE;
277: if (rt == Byte.TYPE)
278: return new Byte((byte) 0);
279: if (rt == Short.TYPE)
280: return new Short((short) 0);
281: if (rt == Integer.TYPE)
282: return new Integer(0);
283: if (rt == Long.TYPE)
284: return new Long(0L);
285: if (rt == Float.TYPE)
286: return new Float(0.0f);
287: if (rt == Double.TYPE)
288: return new Double(0.0);
289:
290: return null;
291: }
292:
293: public boolean matches(String name, Class[] parameterTypes) {
294: return m.getName().equals(name)
295: && Arrays.equals(this .parameterTypes,
296: parameterTypes);
297: }
298:
299: public Class getReturnType() {
300: return m.getReturnType();
301: }
302:
303: public static RubyClass createJavaProxyMethodClass(
304: Ruby runtime, RubyModule javaProxyModule) {
305: RubyClass result = javaProxyModule.defineClassUnder(
306: "JavaProxyMethod", runtime.getObject(),
307: ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
308:
309: CallbackFactory callbackFactory = runtime
310: .callbackFactory(JavaProxyClass.ProxyMethodImpl.class);
311:
312: JavaProxyReflectionObject.registerRubyMethods(runtime,
313: result);
314:
315: result.defineFastMethod("argument_types", callbackFactory
316: .getFastMethod("argument_types"));
317: result.defineFastMethod("declaring_class", callbackFactory
318: .getFastMethod("getDeclaringClass"));
319: result.defineFastMethod("super?", callbackFactory
320: .getFastMethod("super_p"));
321: result.defineFastMethod("arity", callbackFactory
322: .getFastMethod("arity"));
323: result.defineFastMethod("name", callbackFactory
324: .getFastMethod("name"));
325: result.defineFastMethod("inspect", callbackFactory
326: .getFastMethod("inspect"));
327: result.defineFastMethod("invoke", callbackFactory
328: .getFastOptMethod("do_invoke"));
329:
330: return result;
331: }
332:
333: public RubyObject name() {
334: return getRuntime().newString(getName());
335: }
336:
337: public JavaProxyClass getDeclaringClass() {
338: return clazz;
339: }
340:
341: public RubyArray argument_types() {
342: return buildRubyArray(getParameterTypes());
343: }
344:
345: public IRubyObject super _p() {
346: return hasSuperImplementation() ? getRuntime().getTrue()
347: : getRuntime().getFalse();
348: }
349:
350: public RubyFixnum arity() {
351: return getRuntime().newFixnum(getArity());
352: }
353:
354: protected String nameOnInspection() {
355: return getDeclaringClass().nameOnInspection() + "/"
356: + getName();
357: }
358:
359: public IRubyObject inspect() {
360: StringBuffer result = new StringBuffer();
361: result.append(nameOnInspection());
362: result.append("(");
363: Class[] parameterTypes = getParameterTypes();
364: for (int i = 0; i < parameterTypes.length; i++) {
365: result.append(parameterTypes[i].getName());
366: if (i < parameterTypes.length - 1) {
367: result.append(',');
368: }
369: }
370: result.append(")>");
371: return getRuntime().newString(result.toString());
372: }
373:
374: public IRubyObject do_invoke(IRubyObject[] nargs) {
375: if (nargs.length != 1 + getArity()) {
376: throw getRuntime().newArgumentError(nargs.length,
377: 1 + getArity());
378: }
379:
380: IRubyObject invokee = nargs[0];
381: if (!(invokee instanceof JavaObject)) {
382: throw getRuntime().newTypeError(
383: "invokee not a java object");
384: }
385: Object receiver_value = ((JavaObject) invokee).getValue();
386: Object[] arguments = new Object[nargs.length - 1];
387: System.arraycopy(nargs, 1, arguments, 0, arguments.length);
388:
389: Class[] parameterTypes = getParameterTypes();
390: for (int i = 0; i < arguments.length; i++) {
391: arguments[i] = JavaUtil.convertRubyToJava(
392: (IRubyObject) arguments[i], parameterTypes[i]);
393: }
394:
395: try {
396: Object javaResult = sm
397: .invoke(receiver_value, arguments);
398: return JavaUtil.convertJavaToRuby(getRuntime(),
399: javaResult, getReturnType());
400: } catch (IllegalArgumentException e) {
401: throw getRuntime().newTypeError(
402: "expected " + argument_types().inspect());
403: } catch (IllegalAccessException iae) {
404: throw getRuntime().newTypeError(
405: "illegal access on '" + sm.getName() + "': "
406: + iae.getMessage());
407: } catch (InvocationTargetException ite) {
408: ite.getTargetException().printStackTrace();
409: getRuntime().getJavaSupport().handleNativeException(
410: ite.getTargetException());
411: // This point is only reached if there was an exception handler
412: // installed.
413: return getRuntime().getNil();
414: }
415: }
416:
417: private int getArity() {
418: return getParameterTypes().length;
419: }
420:
421: }
422:
423: JavaProxyMethod initMethod(String name, String desc,
424: boolean hasSuper) {
425: Class proxy = proxyClass;
426: try {
427: Class[] parms = parse(proxy.getClassLoader(), desc);
428: Method m = proxy.getDeclaredMethod(name, parms);
429: Method sm = null;
430: if (hasSuper) {
431: sm = proxy.getDeclaredMethod("__super$" + name, parms);
432: }
433:
434: JavaProxyMethod jpm = new ProxyMethodImpl(getRuntime(),
435: this , m, sm);
436: methods.add(jpm);
437: List methodsWithName = (List) methodMap.get(name);
438: if (methodsWithName == null) {
439: methodsWithName = new ArrayList(2);
440: methodMap.put(name, methodsWithName);
441: }
442: methodsWithName.add(jpm);
443:
444: return jpm;
445: } catch (ClassNotFoundException e) {
446: throw new InternalError(e.getMessage());
447: } catch (SecurityException e) {
448: throw new InternalError(e.getMessage());
449: } catch (NoSuchMethodException e) {
450: throw new InternalError(e.getMessage());
451: }
452: }
453:
454: private static Class[] parse(final ClassLoader loader, String desc)
455: throws ClassNotFoundException {
456: List al = new ArrayList();
457: int idx = 1;
458: while (desc.charAt(idx) != ')') {
459:
460: int arr = 0;
461: while (desc.charAt(idx) == '[') {
462: idx += 1;
463: arr += 1;
464: }
465:
466: Class type;
467:
468: switch (desc.charAt(idx)) {
469: case 'L':
470: int semi = desc.indexOf(';', idx);
471: final String name = desc.substring(idx + 1, semi);
472: idx = semi;
473: try {
474: type = (Class) AccessController
475: .doPrivileged(new PrivilegedExceptionAction() {
476: public Object run()
477: throws ClassNotFoundException {
478: return Class.forName(name.replace(
479: '/', '.'), false, loader);
480: }
481: });
482: } catch (PrivilegedActionException e) {
483: throw (ClassNotFoundException) e.getException();
484: }
485: break;
486:
487: case 'B':
488: type = Byte.TYPE;
489: break;
490: case 'C':
491: type = Character.TYPE;
492: break;
493: case 'Z':
494: type = Boolean.TYPE;
495: break;
496: case 'S':
497: type = Short.TYPE;
498: break;
499: case 'I':
500: type = Integer.TYPE;
501: break;
502: case 'J':
503: type = Long.TYPE;
504: break;
505: case 'F':
506: type = Float.TYPE;
507: break;
508: case 'D':
509: type = Double.TYPE;
510: break;
511: default:
512: throw new InternalError("cannot parse " + desc + "["
513: + idx + "]");
514: }
515:
516: idx += 1;
517:
518: if (arr != 0) {
519: type = Array.newInstance(type, new int[arr]).getClass();
520: }
521:
522: al.add(type);
523: }
524:
525: return (Class[]) al.toArray(new Class[al.size()]);
526: }
527:
528: //
529: // Ruby-level methods
530: //
531:
532: public static RubyClass createJavaProxyClassClass(Ruby runtime,
533: RubyModule javaModule) {
534: RubyClass result = javaModule.defineClassUnder(
535: "JavaProxyClass", runtime.getObject(),
536: ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
537: CallbackFactory callbackFactory = runtime
538: .callbackFactory(JavaProxyClass.class);
539:
540: JavaProxyReflectionObject.registerRubyMethods(runtime, result);
541:
542: result.defineFastMethod("constructors", callbackFactory
543: .getFastMethod("constructors"));
544: result.defineFastMethod("superclass", callbackFactory
545: .getFastMethod("superclass"));
546: result.defineFastMethod("interfaces", callbackFactory
547: .getFastMethod("interfaces"));
548: result.defineFastMethod("methods", callbackFactory
549: .getFastMethod("methods"));
550:
551: result.getMetaClass().defineFastMethod(
552: "get",
553: callbackFactory.getFastSingletonMethod("get",
554: JavaClass.class));
555: result.getMetaClass().defineFastMethod(
556: "get_with_class",
557: callbackFactory.getFastSingletonMethod(
558: "get_with_class", RubyClass.class));
559:
560: return result;
561: }
562:
563: public static RubyObject get(IRubyObject recv, JavaClass type) {
564: try {
565: return getProxyClass(recv.getRuntime(), (Class) type
566: .getValue(), new Class[0]);
567: } catch (Error e) {
568: RaiseException ex = recv.getRuntime().newArgumentError(
569: "unable to create proxy class for "
570: + type.getValue());
571: ex.initCause(e);
572: throw ex;
573: } catch (InvocationTargetException e) {
574: RaiseException ex = recv.getRuntime().newArgumentError(
575: "unable to create proxy class for "
576: + type.getValue());
577: ex.initCause(e);
578: throw ex;
579: }
580: }
581:
582: private static final HashSet EXCLUDE_MODULES = new HashSet();
583: static {
584: EXCLUDE_MODULES.add("Kernel");
585: EXCLUDE_MODULES.add("Java");
586: EXCLUDE_MODULES.add("JavaProxyMethods");
587: EXCLUDE_MODULES.add("Enumerable");
588: }
589:
590: private static final HashSet EXCLUDE_METHODS = new HashSet();
591: static {
592: EXCLUDE_METHODS.add("class");
593: EXCLUDE_METHODS.add("finalize");
594: EXCLUDE_METHODS.add("initialize");
595: EXCLUDE_METHODS.add("java_class");
596: EXCLUDE_METHODS.add("java_object");
597: EXCLUDE_METHODS.add("__jcreate!");
598: EXCLUDE_METHODS.add("__jsend!");
599: }
600:
601: public static RubyObject get_with_class(IRubyObject recv,
602: RubyClass clazz) {
603: Ruby runtime = recv.getRuntime();
604:
605: // Let's only generate methods for those the user may actually
606: // intend to override. That includes any defined in the current
607: // class, and any ancestors that are also JavaProxyClasses (but none
608: // from any other ancestor classes). Methods defined in mixins will
609: // be considered intentionally overridden, except those from Kernel,
610: // Java, and JavaProxyMethods, as well as Enumerable.
611: // TODO: may want to exclude other common mixins?
612:
613: JavaClass javaClass = null;
614: Set names = new HashSet(); // need names ordered for key generation later
615: List interfaceList = new ArrayList();
616:
617: List ancestors = clazz.getAncestorList();
618: boolean skipRemainingClasses = false;
619: for (Iterator iter = ancestors.iterator(); iter.hasNext();) {
620: RubyModule ancestor = (RubyModule) iter.next();
621: if (ancestor instanceof RubyClass) {
622: if (skipRemainingClasses)
623: continue;
624: Map vars = ancestor.getInstanceVariables();
625: // we only collect methods and interfaces for
626: // user-defined proxy classes.
627: if (!vars.containsKey("@java_proxy_class")) {
628: skipRemainingClasses = true;
629: continue;
630: }
631:
632: // get JavaClass if this is the new proxy class; verify it
633: // matches if this is a superclass proxy.
634: IRubyObject var = (IRubyObject) vars.get("@java_class");
635: if (var == null) {
636: throw runtime
637: .newTypeError("no java_class defined for proxy (or ancestor): "
638: + ancestor);
639: } else if (!(var instanceof JavaClass)) {
640: throw runtime
641: .newTypeError("invalid java_class defined for proxy (or ancestor): "
642: + ancestor + ": " + var);
643: }
644: if (javaClass == null) {
645: javaClass = (JavaClass) var;
646: } else if (javaClass != var) {
647: throw runtime
648: .newTypeError("java_class defined for "
649: + clazz
650: + " ("
651: + javaClass
652: + ") does not match java_class for ancestor "
653: + ancestor + " (" + var + ")");
654: }
655: // get any included interfaces
656: var = (IRubyObject) vars.get("@java_interfaces");
657: if (var != null && !(var instanceof RubyNil)) {
658: if (!(var instanceof RubyArray)) {
659: throw runtime
660: .newTypeError("invalid java_interfaces defined for proxy (or ancestor): "
661: + ancestor + ": " + var);
662: }
663: RubyArray ifcArray = (RubyArray) var;
664: int size = ifcArray.size();
665: for (int i = size; --i >= 0;) {
666: IRubyObject ifc = ifcArray.eltInternal(i);
667: if (!(ifc instanceof JavaClass)) {
668: throw runtime
669: .newTypeError("invalid java interface defined for proxy (or ancestor): "
670: + ancestor + ": " + ifc);
671: }
672: Class interfaceClass = ((JavaClass) ifc)
673: .javaClass();
674: if (!interfaceClass.isInterface()) {
675: throw runtime
676: .newTypeError("invalid java interface defined for proxy (or ancestor): "
677: + ancestor
678: + ": "
679: + ifc
680: + " (not an interface)");
681: }
682: if (!interfaceList.contains(interfaceClass)) {
683: interfaceList.add(interfaceClass);
684: }
685: }
686: }
687: // set this class's method names in var @__java_ovrd_methods if this
688: // is the new class; otherwise, get method names from there if this is
689: // a proxy superclass.
690: var = (IRubyObject) vars.get("@__java_ovrd_methods");
691: if (var == null) {
692: // lock in the overridden methods for the new class, and any as-yet
693: // uninstantiated ancestor class.
694: Map methods;
695: RubyArray methodNames;
696: synchronized (methods = ancestor.getMethods()) {
697: methodNames = RubyArray.newArrayLight(runtime,
698: methods.size());
699: for (Iterator meths = methods.keySet()
700: .iterator(); meths.hasNext();) {
701: String methodName = (String) meths.next();
702: if (!EXCLUDE_METHODS.contains(methodName)) {
703: names.add(methodName);
704: methodNames.add(runtime
705: .newString(methodName));
706: }
707: }
708: }
709: // TODO: OK to just do a put here?
710: ancestor.setInstanceVariable(
711: "@__java_ovrd_methods", methodNames);
712: } else {
713: if (!(var instanceof RubyArray)) {
714: throw runtime
715: .newTypeError("invalid @__java_ovrd_methods defined for proxy: "
716: + ancestor + ": " + var);
717: }
718: RubyArray methodNames = (RubyArray) var;
719: int size = methodNames.size();
720: for (int i = size; --i >= 0;) {
721: IRubyObject methodName = methodNames
722: .eltInternal(i);
723: if (!(methodName instanceof RubyString)) {
724: throw runtime
725: .newTypeError("invalid method name defined for proxy (or ancestor): "
726: + ancestor
727: + ": "
728: + methodName);
729: }
730: names.add(methodName.asSymbol());
731: }
732: }
733: } else if (!EXCLUDE_MODULES.contains(ancestor.getName())) {
734: Map methods;
735: synchronized (methods = ancestor.getMethods()) {
736: for (Iterator meths = methods.keySet().iterator(); meths
737: .hasNext();) {
738: String methodName = (String) meths.next();
739: if (!EXCLUDE_METHODS.contains(methodName)) {
740: names.add(methodName);
741: }
742: }
743: }
744: }
745: }
746:
747: if (javaClass == null) {
748: throw runtime
749: .newArgumentError("unable to create proxy class: no java_class defined for "
750: + clazz);
751: }
752:
753: int interfaceCount = interfaceList.size();
754: Class[] interfaces = new Class[interfaceCount];
755: for (int i = interfaceCount; --i >= 0;) {
756: interfaces[i] = (Class) interfaceList.get(i);
757: }
758:
759: try {
760: return getProxyClass(recv.getRuntime(), javaClass
761: .javaClass(), interfaces, names);
762: } catch (Error e) {
763: RaiseException ex = recv.getRuntime().newArgumentError(
764: "unable to create proxy class for "
765: + javaClass.getValue() + " : "
766: + e.getMessage());
767: //e.printStackTrace();
768: ex.initCause(e);
769: throw ex;
770: } catch (InvocationTargetException e) {
771: RaiseException ex = recv.getRuntime().newArgumentError(
772: "unable to create proxy class for "
773: + javaClass.getValue() + " : "
774: + e.getMessage());
775: //e.printStackTrace();
776: ex.initCause(e);
777: throw ex;
778: }
779: }
780:
781: public RubyObject super class() {
782: return JavaClass.get(getRuntime(), getSuperclass());
783: }
784:
785: public RubyArray methods() {
786: return buildRubyArray(getMethods());
787: }
788:
789: public RubyArray interfaces() {
790: return buildRubyArray(getInterfaces());
791: }
792:
793: public RubyArray constructors() {
794: return buildRubyArray(getConstructors());
795: }
796:
797: public static void createJavaProxyModule(Ruby runtime) {
798: // TODO Auto-generated method stub
799:
800: RubyModule javaProxyModule = runtime.getModule("Java");
801: JavaProxyClass.createJavaProxyClassClass(runtime,
802: javaProxyModule);
803: ProxyMethodImpl.createJavaProxyMethodClass(runtime,
804: javaProxyModule);
805: JavaProxyConstructor.createJavaProxyConstructorClass(runtime,
806: javaProxyModule);
807: }
808:
809: public String nameOnInspection() {
810: return "[Proxy:" + getSuperclass().getName() + "]";
811: }
812: }
|