Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package org.jruby.java.proxies;
  
  import java.util.Arrays;
  import org.jruby.Ruby;
 
 public class JavaInterfaceTemplate {
 
     public static RubyModule createJavaInterfaceTemplateModule(ThreadContext context) {
         final Ruby runtime = context.runtime;
         RubyModule JavaInterfaceTemplate = runtime.defineModule("JavaInterfaceTemplate");
 
         RubyClass singleton = JavaInterfaceTemplate.getSingletonClass();
         singleton.addReadAttribute(context"java_class");
         singleton.defineAnnotatedMethods(JavaInterfaceTemplate.class);
 
         JavaInterfaceTemplate.defineAnnotatedMethods(Java.JavaProxyClassMethods.class);
 
         return JavaInterfaceTemplate;
     }
 
     // not intended to be called directly by users (private)
     // OLD TODO from Ruby code:
     // This should be implemented in JavaClass.java, where we can
     // check for reserved Ruby names, conflicting methods, etc.
     @JRubyMethod(visibility = .)
     public static IRubyObject implement(ThreadContext contextIRubyObject selfIRubyObject clazz) {
         if ( ! (clazz instanceof RubyModule) ) {
             final Ruby runtime = context.runtime;
             throw runtime.newTypeError(clazzruntime.getModule());
         }
 
         final RubyModule targetModule = (RubyModuleclazz;
         final JavaClass javaClass = getJavaClassForInterface(self);
 
         final Method[] javaInstanceMethods = javaClass.javaClass().getMethods();
         final DynamicMethod dummyMethodImpl = new DummyMethodImpl(targetModule);
 
         for (int i = 0; i < javaInstanceMethods.lengthi++) {
             final Method javaMethod = javaInstanceMethods[i];
             final String name = javaMethod.getName();
             if ( targetModule.searchMethod(name).isUndefined() ) {
                 targetModule.addMethod(namedummyMethodImpl); // only those not-defined
             }
         }
 
         return context.nil;
     }
 
     private static class DummyMethodImpl extends org.jruby.internal.runtime.methods.JavaMethod {
 
         DummyMethodImpl(RubyModule targetModule) {
             super(targetModule.);
         }
 
         @Override
         public final IRubyObject call(ThreadContext contextIRubyObject selfRubyModule clazzString nameIRubyObject[] argsBlock block) {
             return context.nil// dummy bodies for default impls
         }
 
     }
 
     @JRubyMethod(frame = true// framed for invokeSuper
     public static IRubyObject append_features(ThreadContext contextIRubyObject selfIRubyObject clazzBlock block) {
         if ( clazz instanceof RubyClass ) {
             appendFeaturesToClass(contextself, (RubyClassclazz);
         }
         else if ( clazz instanceof RubyModule ) {
             appendFeaturesToModule(contextself, (RubyModuleclazz);
         }
         else {
             throw context.runtime.newTypeError("received " + clazz + ", expected Class/Module");
         }
 
         return Helpers.invokeSuper(contextselfclazzblock);
     }
    private static void appendFeaturesToClass(ThreadContext contextfinal IRubyObject selffinal RubyClass clazz) {
        final Ruby runtime = context.runtime;
        checkAlreadyReified(clazzruntime);
        final JavaClass javaClass = getJavaClassForInterface(self);
        RubyArray javaInterfaces;
        if ( ! clazz.hasInstanceVariable("@java_interfaces") ) {
            javaInterfaces = RubyArray.newArray(runtimejavaClass);
            clazz.setInstanceVariable("@java_interfaces"javaInterfaces);
            initInterfaceImplMethods(contextclazz);
        }
        else {
            javaInterfaces = (RubyArrayclazz.getInstanceVariable("@java_interfaces");
            // we've already done the above priming logic, just add another interface
            // to the list of intentions unless we're past the point of no return or
            // already intend to implement the given interface
            if ( ! ( javaInterfaces.isFrozen() || javaInterfaces.includes(contextjavaClass) ) ) {
                javaInterfaces.append(javaClass);
            }
        }
    }
    private static void checkAlreadyReified(final RubyClass clazzRuby runtimethrows RaiseException {
        // not allowed for original (non-generated) Java classes
        // note: not allowing for any previously created class right now;
        // this restriction might be loosened later for generated classes
        if ( ( . && clazz.getReifiedClass() != null )
                ||
                ( clazz.hasInstanceVariable("@java_class")
                    && clazz.getInstanceVariable("@java_class").isTrue()
                    && !clazz.getSingletonClass().isMethodBound("java_proxy_class"false) )
                ||
                ( clazz.hasInstanceVariable("@java_proxy_class")
                    && clazz.getInstanceVariable("@java_proxy_class").isTrue() ) ) {
            throw runtime.newArgumentError("can not add Java interface to existing Java class");
        }
    }
    private static void initInterfaceImplMethods(ThreadContext contextfinal RubyClass clazz) {
        // setup new, etc unless this is a ConcreteJavaProxy subclass
        // For JRUBY-4571, check both these, since JavaProxy extension stuff adds the former and this code adds the latter
        if (!(clazz.isMethodBound("__jcreate!"false) || clazz.isMethodBound("__jcreate_meta!"false))) {
            // First we make modifications to the class, to adapt it to being
            // both a Ruby class and a proxy for a Java type
            RubyClass singleton = clazz.getSingletonClass();
            // list of interfaces we implement
            singleton.addReadAttribute(context"java_interfaces");
            if ( ( ! . && clazz.getSuperClass().getRealClass().hasInstanceVariable("@java_class") )
                || . ) {
                // superclass is a Java class...use old style impl for now
                // The replacement "new" allocates and inits the Ruby object as before, but
                // also instantiates our proxified Java object by calling __jcreate!
                final ObjectAllocator proxyAllocator = clazz.getAllocator();
                clazz.setAllocator(new ObjectAllocator() {
                    public IRubyObject allocate(Ruby runtimeRubyClass klazz) {
                        IRubyObject newObj = proxyAllocator.allocate(runtimeklazz);
                        Helpers.invoke(runtime.getCurrentContext(), newObj"__jcreate!");
                        return newObj;
                    }
                });
                // jcreate instantiates the proxy object which implements all interfaces
                // and which is wrapped and implemented by this object
                clazz.addMethod("__jcreate!"new InterfaceProxyFactory(clazz));
            } else {
                // The new "new" actually generates a real Java class to use for the Ruby class's
                // backing store, instantiates that, and then calls initialize on it.
                addRealImplClassNew(clazz);
            }
            // Next, we define a few private methods that we'll use to manipulate
            // the Java object contained within this Ruby object
            // Used by our duck-typification of Proc into interface types, to allow
            // coercing a simple proc into an interface parameter.
            clazz.addMethod("__jcreate_meta!"new InterfaceProxyFactory(clazz));
            // If we hold a Java object, we need a java_class accessor
            clazz.addMethod("java_class"new JavaClassAccessor(clazz));
            // Because we implement Java interfaces now, we need a new === that's
            // aware of those additional "virtual" supertypes
            if (!clazz.searchMethod("===").isUndefined()) {
                clazz.defineAlias("old_eqq""===");
                clazz.addMethod("==="new JavaMethodOne(clazz.) {
                    @Override
                    public IRubyObject call(ThreadContext contextIRubyObject selfRubyModule clazzString nameIRubyObject arg) {
                        // TODO: WRONG - get interfaces from class
                        if (arg.respondsTo("java_object")) {
                            IRubyObject interfaces = self.getMetaClass().getInstanceVariables().getInstanceVariable("@java_interfaces");
                            assert interfaces instanceof RubyArray : "interface list was not an array";
                            return context.runtime.newBoolean(((RubyArrayinterfaces).op_diff(
                                    ((JavaObjectarg.dataGetStruct()).java_class().interfaces()).equals(RubyArray.newArray(context.runtime)));
                        } else {
                            return Helpers.invoke(contextself"old_eqq"arg);
                        }
                    }
                });
            }
        }
        // Now we add an "implement" and "implement_all" methods to the class
        if ( ! clazz.isMethodBound("implement"false) ) {
            final RubyClass singleton = clazz.getSingletonClass();
            // implement is called to force this class to create stubs for all
            // methods in the given interface, so they'll show up in the list
            // of methods and be invocable without passing through method_missing
            singleton.addMethod("implement"new JavaMethodOne(clazz.) {
                @Override
                public IRubyObject call(ThreadContext contextIRubyObject selfRubyModule clazzString nameIRubyObject iface) {
                    final RubyArray ifaces = getJavaInterfaces(self);
                    if ( ifaces != null && ifaces.includes(contextiface) ) {
                        return Helpers.invoke(contextiface"implement"self);
                    }
                    return context.nil;
                }
            });
            // implement all forces implementation of all interfaces we intend
            // for this class to implement
            singleton.addMethod("implement_all"new JavaMethodOne(clazz.) {
                @Override
                public IRubyObject call(ThreadContext contextIRubyObject selfRubyModule clazzString nameIRubyObject arg) {
                    final RubyArray ifaces = getJavaInterfaces(self);
                    if ( ifaces == null ) return context.nil;
                    for ( int i = 0; i < ifaces.size(); i++ ) {
                        final RubyModule iface = Java.get_interface_module(context.runtimeifaces.eltInternal(i));
                        Helpers.invoke(contextiface"implement"self);
                    }
                    return ifaces;
                }
            });
        }
    }
    private static class InterfaceProxyFactory extends JavaMethodN { // __jcreate! and __jcreate_meta!
        InterfaceProxyFactory(final RubyClass clazz) { super(clazz.); }
        @Override
        public final IRubyObject call(ThreadContext contextIRubyObject selfRubyModule clazzString nameIRubyObject[] args) {
            return newInterfaceProxy(self);
        }
    }
    private static class JavaClassAccessor extends JavaMethodZero {
        JavaClassAccessor(final RubyClass klass) { super(klass.); }
        @Override
        public IRubyObject call(ThreadContext contextIRubyObject selfRubyModule clazzString name) {
            final Object wrapped = self.dataGetStruct();
            final Class<?> javaClass;
            if ( wrapped != null ) {
                javaClass = ((JavaObjectwrapped).getJavaClass();
            }
            else {
                javaClass = self.getClass(); // NOTE what is this for?
            }
            return JavaClass.get(context.runtimejavaClass);
        }
    }
    public static void addRealImplClassNew(final RubyClass clazz) {
        clazz.setAllocator(new ObjectAllocator() {
            private Constructor proxyConstructor;
            public IRubyObject allocate(Ruby runtimeRubyClass klazz) {
                // if we haven't been here before, reify the class
                Class reifiedClass = klazz.getReifiedClass();
                if ( == null || .getDeclaringClass() != reifiedClass) {
                    if (reifiedClass == null) {
                        reifiedClass = Java.generateRealClass(klazz);
                    }
                     = Java.getRealClassConstructor(runtimereifiedClass);
                }
                IRubyObject newObj = Java.constructProxy(runtimeklazz);
                return newObj;
            }
        });
    }
    private static IRubyObject newInterfaceProxy(final IRubyObject self) {
        final RubyClass current = self.getMetaClass();
        // construct the new interface impl and set it into the object
        IRubyObject newObject = Java.newInterfaceImpl(self, Java.getInterfacesFromRubyClass(current));
        JavaUtilities.set_java_object(selfselfnewObject);
        return newObject;
    }
    private static void appendFeaturesToModule(ThreadContext contextfinal IRubyObject selffinal RubyModule module) {
        // assuming the user wants a collection of interfaces that can be
        // included together. make it so.
        final Ruby runtime = context.runtime;
        // not allowed for existing Java interface modules
        if (module.getInstanceVariables().hasInstanceVariable("@java_class") &&
            module.getInstanceVariables().getInstanceVariable("@java_class").isTrue()) {
            throw runtime.newTypeError("can not add Java interface to existing Java interface");
        }
        // To turn a module into an "interface collection" we add a class instance
        // variable to hold the list of interfaces, and modify append_features
        // for this module to call append_features on each of those interfaces as
        // well
        synchronized (module) {
            if ( initInterfaceModules(selfmodule) ) { // true - initialized
                final RubyClass singleton = module.getSingletonClass();
                singleton.addMethod("append_features"new AppendFeatures(singleton));
            }
            else {
                // already set up append_features, just add the interface if we haven't already
                final RubyArray interfaceModules = getInterfaceModules(module);
                if ( ! interfaceModules.includes(contextself) ) {
                    interfaceModules.append(self);
                }
            }
        }
    }
    private static class AppendFeatures extends JavaMethodOneBlock {
        AppendFeatures(RubyModule singletonClass) { super(singletonClass.); }
        @Override
        public IRubyObject call(ThreadContext contextIRubyObject selfRubyModule clazzString nameIRubyObject argBlock block) {
            if ( ! ( arg instanceof RubyModule ) ) {
                throw context.runtime.newTypeError("append_features called with non-module");
            }
            final RubyModule target = (RubyModulearg;
            target.includegetInterfaceModules(self).toJavaArray() );
            return Helpers.invokeAs(contextclazz.getSuperClass(), selfnameargblock);
        }
    }
    public static IRubyObject extended(ThreadContext contextIRubyObject selfIRubyObject object) {
        if ( ! (self instanceof RubyModule) ) {
            throw context.runtime.newTypeError(selfcontext.runtime.getModule());
        }
        RubyClass singleton = object.getSingletonClass();
        singleton.include(new IRubyObject[] { self });
        return singleton;
    }
    @JRubyMethod(name = "[]", rest = true)
    public static IRubyObject op_aref(ThreadContext contextIRubyObject selfIRubyObject[] args) {
        return JavaProxy.op_aref(contextselfargs);
    }
    @JRubyMethod(name = "impl", rest = true)
    public static IRubyObject impl(ThreadContext contextIRubyObject selfIRubyObject[] argsfinal Block implBlock) {
        final Ruby runtime = context.runtime;
        if ( ! implBlock.isGiven() ) {
            throw runtime.newArgumentError("block required to call #impl on a Java interface");
        }
        final IRubyObject[] methodNames;
        if ( args.length == 0 ) methodNames = null;
        else {
            methodNames = args.clone();
            Arrays.sort(methodNames); // binarySearch needs a sorted array
        }
        RubyClass implClass = RubyClass.newClass(runtimeruntime.getObject());
        implClass.include(new IRubyObject[] { self });
        final IRubyObject implObject = implClass.callMethod(context"new");
        implClass.addMethod("method_missing"new BlockInterfaceImpl(implClassimplBlockmethodNames));
        return implObject;
    }
    private static class BlockInterfaceImpl extends org.jruby.internal.runtime.methods.JavaMethod {
        private final IRubyObject[] methodNames// RubySymbol[] (or RubyString[] on 1.8)
        private final Block implBlock;
        BlockInterfaceImpl(final RubyClass implClassfinal Block implBlockfinal IRubyObject[] methodNames) {
            super(implClass.);
            this. = implBlockthis. = methodNames;
        }
        @Override // method_missing impl
        public IRubyObject call(ThreadContext contextIRubyObject selfRubyModule clazzString nameIRubyObject[] argsBlock block) {
            Arity.checkArgumentCount(context.runtimenameargs.length, 1, -1);
            return callImpl(contextclazzblockargs);
        }
        private IRubyObject callImpl(ThreadContext contextRubyModule clazzBlock blockIRubyObject... args) {
            if (  == null ) return .call(contextargs); // "hot" path
            if ( . == 1 ) {
                if ( [0].equals(args[0]) ) return .call(contextargs);
            }
            else if ( Arrays.binarySearch(args[0]) >= 0 ) {
                return .call(contextargs);
            }
            return clazz.getSuperClass().callMethod(context"method_missing"argsblock);
        }
        @Override
        public final IRubyObject call(ThreadContext contextIRubyObject selfRubyModule klazzString nameIRubyObject arg0Block block) {
            return callImpl(contextklazzblockarg0); // avoids checkArgumentCount
        }
        @Override
        public final IRubyObject call(ThreadContext contextIRubyObject selfRubyModule klazzString nameIRubyObject arg0IRubyObject arg1Block block) {
            return callImpl(contextklazzblockarg0arg1); // avoids checkArgumentCount
        }
        @Override
        public final IRubyObject call(ThreadContext contextIRubyObject selfRubyModule klazzString nameIRubyObject arg0IRubyObject arg1IRubyObject arg2Block block) {
            return callImpl(contextklazzblockarg0arg1arg2); // avoids checkArgumentCount
        }
        //public DynamicMethod dup() { return this; }
    }
    @JRubyMethod(name = "new", rest = true)
    public static IRubyObject new_impl(ThreadContext contextIRubyObject selfIRubyObject[] argsBlock block) {
        final Ruby runtime = context.runtime;
        RubyClass implClass = (RubyClassself.getInstanceVariables().getInstanceVariable("@__implementation");
        if (implClass == null) {
            implClass = RubyClass.newClass(runtimeruntime.getClass("InterfaceJavaProxy"));
            implClass.include(new IRubyObject[] { self });
            Helpers.setInstanceVariable(implClassself"@__implementation");
        }
        return Helpers.invoke(contextimplClass"new"argsblock);
    }
    private static JavaClass getJavaClassForInterface(final IRubyObject module) {
        return (JavaClassmodule.getInstanceVariables().getInstanceVariable("@java_class");
    }
    private static RubyArray getJavaInterfaces(final IRubyObject module) {
        return (RubyArraymodule.getInstanceVariables().getInstanceVariable("@java_interfaces");
    }
    private static RubyArray getInterfaceModules(final IRubyObject module) {
        return (RubyArraymodule.getInstanceVariables().getInstanceVariable("@java_interface_mods");
    }
    private static boolean initInterfaceModules(final IRubyObject selffinal IRubyObject module) {
        if ( ! module.getInstanceVariables().hasInstanceVariable("@java_interface_mods") ) {
            final RubyArray interfaceMods = RubyArray.newArray(self.getRuntime(), self);
            module.getInstanceVariables().setInstanceVariable("@java_interface_mods"interfaceMods);
            return true;
        }
        return false;
    }