package org.archstudio.ljm;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.Socket;
@SuppressWarnings("rawtypes")
public class LJMProxyInvoker implements InvocationHandler {
protected String objectName;
protected Class[] interfaceClasses;
protected LJMEndpoint endpoint;
protected Socket socket;
protected InputStream is;
protected OutputStream os;
protected ObjectInputStream ois;
protected ObjectOutputStream oos;
public LJMProxyInvoker(String objectName, Class[] interfaceClasses, LJMEndpoint endpoint) {
this.objectName = objectName;
this.interfaceClasses = interfaceClasses;
this.endpoint = endpoint;
}
protected void connect() throws LJMException {
if (socket == null) {
try {
socket = new Socket(endpoint.getHost(), endpoint.getPort());
is = new BufferedInputStream(socket.getInputStream());
os = new BufferedOutputStream(socket.getOutputStream());
//Do NOT reverse these two lines
oos = new ObjectOutputStream(os);
// Note: ObjectOutputStream sends an initial short across the stream
// we have to flush the stream so that this short is sent and the client
// does not hang waiting for it.
oos.flush();
ois = new ObjectInputStream(is);
}
catch (IOException ioe) {
close();
throw new LJMException("Can't connect to remote host (" + endpoint.getHost() + " : "
+ endpoint.getPort() + ": " + ioe.toString(), ioe);
}
}
}
public void close() {
if (oos != null) {
try {
oos.writeBoolean(false);
}
catch (IOException ignored) {
}
}
try {
if (is != null) {
is.close();
}
}
catch (IOException ignored) {
}
try {
if (ois != null) {
ois.close();
}
}
catch (IOException ignored2) {
}
try {
if (os != null) {
os.close();
}
}
catch (IOException ignored3) {
}
try {
if (oos != null) {
oos.close();
}
}
catch (IOException ignored4) {
}
try {
if (socket != null) {
socket.close();
}
}
catch (IOException ignored5) {
}
is = null;
os = null;
ois = null;
oos = null;
socket = null;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return invoke(proxy, method, args, 5);
}
protected Object invoke(Object proxy, Method method, Object[] args, int retryCount) throws Throwable {
boolean connected = false;
int connectRetryCount = 2;
while (!connected) {
try {
connect();
connected = true;
}
catch (LJMException ljme) {
//Okay, let's back off and retry
connectRetryCount--;
if (connectRetryCount == 0) {
throw ljme;
}
try {
Thread.sleep(500);
}
catch (InterruptedException ie) {
}
}
}
//System.out.println("Invoking: " + endpoint.getHost() + " " + endpoint.getObjectName() + " " + method.getName());
try {
oos.writeBoolean(true);
oos.writeObject(endpoint.getObjectName());
oos.writeObject(method.getName());
oos.writeObject(ClassArrayEncoder.classArrayToStringArray(method.getParameterTypes()));
oos.writeObject(args);
oos.flush();
}
catch (IOException ioe1) {
//The method call failed, but we can retry.
close();
if (retryCount == 0) {
throw new LJMException("Call failed: " + ioe1.toString(), ioe1, true);
}
try {
Thread.sleep(500);
}
catch (InterruptedException ie) {
}
return invoke(proxy, method, args, retryCount - 1);
}
try {
int status = ois.readInt();
if (status == LJMServer.LJM_STAT_DONE) {
//System.out.println("Done0");
return null;
}
else if (status == LJMServer.LJM_STAT_RETVAL) {
Object o = ois.readObject();
//System.out.println("Done1");
return o;
}
else if (status == LJMServer.LJM_STAT_EXCEPTION) {
Object ot = ois.readObject();
//System.out.println("ot = " + ot);
//System.out.println("ot.class = " + ot.getClass());
Throwable t = (Throwable) ot;
//System.out.println("Done2");
t.printStackTrace();
throw t;
}
else if (status == LJMServer.LJM_STAT_ERROR) {
LJMException ljme = (LJMException) ois.readObject();
close();
//System.out.println("Done3");
throw ljme;
}
else {
close();
//System.out.println("Done4");
throw new LJMException("Protocol error.");
}
}
catch (IOException ioe2) {
close();
//The call completed. We should not retry.
//System.out.println("Done5");
throw new LJMException("Call completed but protocol failed: " + ioe2.toString(), true);
}
}
}