blob: 4d966561266b0e5532522e503ff55810be5700cb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jem.internal.proxy.vm.remote;
/*
* $RCSfile: CallbackHandler.java,v $
* $Revision: 1.7 $ $Date: 2005/08/24 20:39:08 $
*/
import java.net.Socket;
import java.io.*;
import org.eclipse.jem.internal.proxy.common.remote.Commands;
import org.eclipse.jem.internal.proxy.common.remote.UnexpectedExceptionCommandException;
import org.eclipse.jem.internal.proxy.common.*;
/**
* This is a handler for doing callbacks to the
* client.
*
* This is package protected because no one should
* use it from the outside. It is too critical that
* callback's work only in this specified way.
*/
class CallbackHandler extends ConnectionHandler implements ICallbackHandler {
public CallbackHandler(Socket sc, RemoteVMServerThread svr) {
super(sc, svr, null);
}
/**
* Initiate a stream callback request.
*/
public void initiateCallbackStream(int callbackID, int msgID) throws CommandException {
try {
Commands.sendCallbackStreamCommand(out, callbackID, msgID);
out.flush();
} catch (CommandException e) {
throw e;
} catch (Exception e) {
throw new UnexpectedExceptionCommandException(false, e);
}
run(); // Now run and wait for return. If no command exeception thrown, then it signals to continue.
}
/**
* Write bytes to the client. If bytesToWrite is -1, then this is end and
* no bytes are being written. Just write the -1 then.
*/
public void writeBytes(byte[] bytes, int bytesToWrite) throws CommandException {
try {
if (bytesToWrite != -1)
Commands.writeBytes(out, bytes, bytesToWrite);
else
out.writeInt(-1);
} catch (CommandException e) {
throw e;
} catch (Exception e) {
throw new UnexpectedExceptionCommandException(false, e);
}
}
/**
* Callback, but send the parm as an object, ie. it must
* be nothing but constants, e.g. String, Integer, or an
* array of constants. Constants should not be things like
* regular objects. This is because only standard java.lang
* type constants can be assured to be available on the other
* client. Also you don't want to send big objects, except
* maybe something like an array of bytes or strings. It must
* be constants that don't need to be sent back for any reason
* since their identity will be lost in the transfer.
*
* This should be used if there are no parms (i.e. it is null).
*/
public Object callbackAsConstants(int callbackID, int msgID, Object parm) throws CommandException {
try {
Commands.sendCallbackCommand(out, callbackID, msgID);
Commands.ValueObject v = new Commands.ValueObject();
sendObject(parm, SEND_AS_IS, v, out, false);
out.flush();
} catch (CommandException e) {
throw e;
} catch (Exception e) {
throw new UnexpectedExceptionCommandException(false, e);
}
return run(); // Now run and wait for return.
}
// A retriever is what handles the array part.
private class Retriever implements Commands.ValueRetrieve {
int index=0;
Object[] array;
Commands.ValueObject worker = new Commands.ValueObject();
public Retriever(Object[] anArray) {
array = anArray;
}
public Commands.ValueObject nextValue() {
Object parm = array[index++];
if (parm != null) {
if (parm instanceof ICallbackHandler.TransmitableArray) {
// It is another array, create a new retriever.
worker.setArrayIDS(new Retriever(((ICallbackHandler.TransmitableArray) parm).getArray()), ((ICallbackHandler.TransmitableArray) parm).getArray().length, Commands.OBJECT_CLASS);
} else {
// They may add some new ID's and if there is an error, they
// won't get released, but that is a slight chance we will have
// to take because we don't know which ones were new and which
// ones weren't.
fillInValue(parm, NOT_A_PRIMITIVE, worker);
}
} else
worker.set();
return worker;
}
};
private static final Object[] NULL_SENT = new Object[1];
/**
* Callback, but send the parm as IDs so that proxies
* will be created for the objects and can be referenced.
*
* This should be used even if there is only one parm.
*/
public Object callbackWithParms(int callbackID, int msgID, Object[] parms) throws CommandException {
try {
if (parms == null)
parms = NULL_SENT;
Commands.ValueObject v = new Commands.ValueObject();
v.setArrayIDS(new Retriever(parms), parms.length, Commands.OBJECT_CLASS);
Commands.sendCallbackCommand(out, callbackID, msgID);
Commands.writeValue(out, v, false);
out.flush();
} catch (CommandException e) {
throw e;
} catch (Exception e) {
throw new UnexpectedExceptionCommandException(false, e);
}
return run(); // Now run and wait for return.
}
/**
* A closeHandler has been requested. This is called when
* not waiting within a loop, so we need to do the cleanup ourselves.
*/
public void closeHandler() {
if (isConnected()) {
try {
Commands.sendQuitCommand(out);
} catch (IOException e) {
} finally {
if (in != null)
try {
in.close();
} catch (Exception e) {
}
if (out != null)
try {
out.close();
} catch (Exception e) {
}
close();
in = null;
out = null;
socket = null;
}
}
}
}