/******************************************************************************* * 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; /* */ 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; } } } }