I have 1 Interface called A
that needs to be implemented by a class I load dynamically after the program start. Lets call it B
.
This interface provides x (more than 1) Methods. Lets call em from a()
to z()
.
Now I have to wrap this class for some time measuring and control issues and run it in its own thread to be able to kill it if it takes too long.
Therefore I have invented class C
that wraps B
because B
doesn't implement runnable on its own.
The next part ist the Class the original Program should call. New Class D
. D
implements interface A
as well to hide the whole controlling part from the model.
Now I have to wrap the methods of the interface in D and send them over and Callable to C who unwraps them and executes them on Object B.
Here some example code who I imagined it can be:
public class D implements A {
private C ai;
public D(String aiName) {
ai = new C("trivialKi");
}
private void call(parameters, ORIGIN_METHOD origin) {
AiTaskExecutor task = new AiTaskExecutor(parameters, origin, ai);
FutureTask<Long> tsk = new FutureTask<Long>(task);
Thread thread = new Thread(tsk);
thread.start();
if (abort) {
tsk.cancel(true);
}
}
@Override
public void a(g g, f f, t t) {
call(g, f, t, ORIGIN_METHOD.a);
}
@Override
public void b(g g, t t, h h) {
call(g, t, h, ORIGIN_METHOD.b);
}
@Override
public void c(g g, t t, f f) {
call(g, t, f, ORIGIN_METHOD.c);
}
}
And in class C the obvious switch case with that enum to pass the parameters to the right method on the class B that is held in class C als private field.
Dou you have a better solution in mind? I personally don't like the enum thing and if the parameters are too different this does not work very well.
Is there a "standard" solution for things like that?
The standard solution for this is: Use a "Dynamic Proxy" (java.lang.reflect.Proxy
) for A. This saves you almost all your boilerplate code.
This site and Google contains enough usage examples for Proxy
.
Also: I propose not to use a new thread for each call - this is extremely expensive if the called methods are short. You can use the Callable
interface instead Runnable
and a threadpool Executor
instead. This also allows you to have return values in your interface :-)
EDIT
Just for fun I coded the dynamic proxy and the executor thing.
Given the following interface A
and a sample implementation B
:
interface A {
int a(int g, int f, int h);
int b(int x);
}
class B implements A {
@Override
public int a(int g, int f, int t) {
System.out.println("called a in thread "+Thread.currentThread().getName());
return 42;
}
@Override
public int b(int x) {
System.out.println("called b in thread "+Thread.currentThread().getName());
return 21;
}
}
A proper Callable
using reflection to call any java.lang.reflect.Method
looks like this:
class ReflectiveMethodCallable implements Callable<Object> {
private Object target;
private Method method;
private Object[] args;
public ReflectiveMethodCallable(Object target, Method method, Object[] args) {
this.target = target;
this.method = method;
this.args = args;
}
@Override
public Object call() throws Exception {
return method.invoke(target, args);
}
}
The part where such a ReflectiveMethodCallable
is created and given to an ExecutorService
is the InvocationHandler
of java.lang.reflect.Proxy
:
class MyInvocationHandler implements InvocationHandler {
private Object target;
private ExecutorService executorService;
public MyInvocationHandler(Object target, ExecutorService executorService) {
this.target = target;
this.executorService = executorService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Callable<Object> task = new ReflectiveMethodCallable(target, method, args);
Future<Object> future = executorService.submit(task);
return future.get();
}
catch(ExecutionException e1){
try {
throw e1.getCause();
} catch(InvocationTargetException e2){
throw e2.getCause();
}
}
}
}
The InvocationHandler
is used when creating a new Proxy
in createProxyFor
. The rest of the Main
class is used for a SSCCE example:
public class Main {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
// get B somehow
A a = new B();
// get proxy for B
A proxy = createProxyFor(a, executorService);
// call proxy
System.out.println("current thread: "+Thread.currentThread().getName());
int resultA = proxy.a(1,2,3);
System.out.println("calling a returned "+resultA);
int resultB = proxy.b(1);
System.out.println("calling b returned "+resultB);
}
static A createProxyFor(A a, ExecutorService executorService){
InvocationHandler h = new MyInvocationHandler(a, executorService);
A proxy = (A)Proxy.newProxyInstance(A.class.getClassLoader(), new Class[]{A.class}, h);
return proxy;
}
}
The output:
current thread: main
called a in thread pool-1-thread-1
calling a returned 42
called b in thread pool-1-thread-1
calling b returned 21
To finish up:
A
will be called in another thread.invoke
or in call
.