package org.archstudio.myx.java.conn; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.archstudio.myx.fw.IMyxName; import com.google.common.collect.Sets; /** * Myx brick: "Synchronous Multiway Proxy Impl" * * @see org.archstudio.myx.java.conn.SynchronousMultiwayProxyConnectorStub */ public class SynchronousMultiwayProxyConnector extends org.archstudio.myx.java.conn.SynchronousMultiwayProxyConnectorStub implements InvocationHandler, IMultiwayResults { protected Object[] returnValues = new Object[0]; protected Throwable[] exceptions = new Throwable[0]; protected ExecutorService asyncExecutor = null; public SynchronousMultiwayProxyConnector() { results = this; } @Override public void init() { asyncExecutor = Executors.newSingleThreadExecutor(); } @Override public void end() { if (asyncExecutor != null) { asyncExecutor.shutdown(); try { asyncExecutor.awaitTermination(5L, TimeUnit.SECONDS); } catch (InterruptedException ie) { } } } @Override public void interfaceConnected(IMyxName interfaceName, Object serviceObject) { super.interfaceConnected(interfaceName, serviceObject); if (OUT_OUT.equals(interfaceName)) { Object out1 = out.iterator().next(); Class<?> out1Class = out1.getClass(); ClassLoader outClassLoader = out1Class.getClassLoader(); Set<Class<?>> outInterfaceClasses = Sets.newHashSet(); while (out1Class != null) { outInterfaceClasses.addAll(Arrays.asList(out1Class.getInterfaces())); out1Class = out1Class.getSuperclass(); } in = Proxy.newProxyInstance(outClassLoader, outInterfaceClasses.toArray(new Class<?>[0]), this); } } @Override public void interfaceDisconnecting(IMyxName interfaceName, Object serviceObject) { if (OUT_OUT.equals(interfaceName)) { in = null; } super.interfaceDisconnecting(interfaceName, serviceObject); } @Override public Object[] getReturnValues() { return returnValues; } @Override public Throwable[] getExceptions() { return exceptions; } protected void reportCallProgress(int callee, int numCallees, Object returnValue, Throwable exception) { if (progress.size() == 0) { return; } final int fcallee = callee; final int fnumCallees = numCallees; final Object freturnValue = returnValue; final Throwable fexception = exception; final IMultiwayProgressListener[] pls = progress.toArray(new IMultiwayProgressListener[progress.size()]); asyncExecutor.execute(new Runnable() { @Override public void run() { for (IMultiwayProgressListener pl : pls) { pl.callProgress(fcallee, fnumCallees, freturnValue, fexception); } } }); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (in == null) { throw new RuntimeException("Disconnected proxy."); } synchronized (this) { Object[] rvs = new Object[out.size()]; Throwable[] exs = new Throwable[out.size()]; int i = 0; reportCallProgress(0, out.size(), null, null); for (Object trueServiceObject : out) { try { rvs[i] = method.invoke(trueServiceObject, args); reportCallProgress(i + 1, out.size(), rvs[i], null); } catch (Throwable t) { exs[i] = t; reportCallProgress(i + 1, out.size(), null, exs[i]); } i++; } returnValues = rvs; exceptions = exs; } return null; } }