You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bookkeeper.apache.org by si...@apache.org on 2018/02/17 07:06:02 UTC

[bookkeeper] branch master updated: Call static methods and build callbacks in MavenClassLoader

This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git


The following commit(s) were added to refs/heads/master by this push:
     new 353ca1d  Call static methods and build callbacks in MavenClassLoader
353ca1d is described below

commit 353ca1ddf941a9502e3ecd8fcc383fccfcd91c6f
Author: Ivan Kelly <iv...@apache.org>
AuthorDate: Sat Feb 17 15:05:53 2018 +0800

    Call static methods and build callbacks in MavenClassLoader
    
    To properly test some functionality we need to be able to call static
    methods (e.g. for the creation of ByteBuf), and also to be able to
    build callbacks (e.g. to call async methods).
    
    This patch implements methods for doing this. For static methods, you
    need to pass the className, the method name and a list of
    arguments. It first tries to find the method using non-primitive
    types, but falls back to trying primative types if possible.
    
    Invokation looks like:
    ```
    cl.callStaticMethod("org.apache.bookkeeper.client.BKException",
                        "create", [-101])
    ```
    
    For callbacks you specify an interface and the a groovy closure.
    It is assumed the closure will take as many arguments as the
    callback. The invokation handler doesn't check the method name
    called on the callback object, so it only works with callbacks
    with a single method.
    
    Invokation looks like:
    ```
    def callback = classLoader.createCallback(
        "org.apache.bookkeeper.client.AsyncCallback\$AddCallback",
            { rc, _ledger, entryId, ctx ->
                // do something
            })
    ```
    
    Author: Ivan Kelly <iv...@apache.org>
    
    Reviewers: Enrico Olivelli <eo...@gmail.com>, Sijie Guo <si...@apache.org>
    
    This closes #1156 from ivankelly/mvn-cl-adv
---
 .../apache/bookkeeper/tests/MavenClassLoader.java  | 45 ++++++++++++++++++++++
 .../bookkeeper/tests/MavenClassLoaderTest.java     |  9 +++++
 2 files changed, 54 insertions(+)

diff --git a/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/MavenClassLoader.java b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/MavenClassLoader.java
index a7091be..d25dbc2 100644
--- a/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/MavenClassLoader.java
+++ b/tests/integration-tests-utils/src/main/java/org/apache/bookkeeper/tests/MavenClassLoader.java
@@ -23,10 +23,14 @@ package org.apache.bookkeeper.tests;
 import com.google.common.collect.Lists;
 
 import java.io.File;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
@@ -102,6 +106,47 @@ public class MavenClassLoader implements AutoCloseable {
         return forArtifact("org.apache.bookkeeper:bookkeeper-server:" +  version);
     }
 
+    public Object getClass(String className) throws Exception {
+        return Class.forName(className, true, classloader);
+    }
+
+    public Object callStaticMethod(String className, String methodName, ArrayList<?> args) throws Exception {
+        Class<?> klass = Class.forName(className, true, classloader);
+
+        try {
+            Class<?>[] paramTypes = args.stream().map((a)-> a.getClass()).toArray(Class[]::new);
+            return klass.getMethod(methodName, paramTypes).invoke(null, args.stream().toArray(Object[]::new));
+        } catch (NoSuchMethodException nsme) {
+            // maybe the params are primitives
+            Class<?>[] paramTypes = args.stream().map((a) -> {
+                    Class<?> k = a.getClass();
+                    try {
+                        Object type = k.getField("TYPE").get(null);
+                        if (type instanceof Class<?>) {
+                            return (Class<?>)type;
+                        } else {
+                            return k;
+                        }
+                    } catch (IllegalAccessException | NoSuchFieldException nsfe) {
+                        return k;
+                    }
+                }).toArray(Class[]::new);
+            return klass.getMethod(methodName, paramTypes).invoke(null, args.stream().toArray(Object[]::new));
+        }
+    }
+
+    public Object createCallback(String interfaceName, Object closure) throws Exception {
+        return Proxy.newProxyInstance(classloader,
+                                      new Class<?>[]{ Class.forName(interfaceName, true, classloader) },
+                                      new InvocationHandler() {
+                                          @Override
+                                          public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
+                                              Method call = closure.getClass().getMethod("call", Object[].class);
+                                              return call.invoke(closure, (Object)args);
+                                          }
+                                      });
+    }
+
     public Object newInstance(String className, Object... args) throws Exception {
         Class<?> klass = Class.forName(className, true, classloader);
         return klass.getConstructor(Arrays.stream(args).map((a)-> a.getClass()).toArray(Class[]::new))
diff --git a/tests/integration-tests-utils/src/test/java/org/apache/bookkeeper/tests/MavenClassLoaderTest.java b/tests/integration-tests-utils/src/test/java/org/apache/bookkeeper/tests/MavenClassLoaderTest.java
index 9303557..e4d0533 100644
--- a/tests/integration-tests-utils/src/test/java/org/apache/bookkeeper/tests/MavenClassLoaderTest.java
+++ b/tests/integration-tests-utils/src/test/java/org/apache/bookkeeper/tests/MavenClassLoaderTest.java
@@ -20,6 +20,8 @@
  */
 package org.apache.bookkeeper.tests;
 
+import com.google.common.collect.Lists;
+
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -39,4 +41,11 @@ public class MavenClassLoaderTest {
                                    org.apache.zookeeper.KeeperException.NoNodeException.class));
     }
 
+    @Test
+    public void testStaticMethod() throws Exception {
+        Object o = MavenClassLoader.forBookKeeperVersion("4.6.0").callStaticMethod(
+                "org.apache.bookkeeper.client.BKException", "create", Lists.newArrayList(-101));
+        Assert.assertEquals(o.getClass().getName(),
+                            "org.apache.bookkeeper.client.BKException$BKLedgerFencedException");
+    }
 }

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.