blob: 258ee8ba70edd274bc7a255d1b8ca5c4579cb6f3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 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
*******************************************************************************/
/*
* $RCSfile: REMInvokable.java,v $
* $Revision: 1.4 $ $Date: 2005/08/24 20:39:07 $
*/
package org.eclipse.jem.internal.proxy.remote;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jem.internal.proxy.common.CommandException;
import org.eclipse.jem.internal.proxy.common.remote.*;
import org.eclipse.jem.internal.proxy.core.*;
import org.eclipse.jem.internal.proxy.core.IInvokable;
/**
* Remote Invokable. This invokes on the remote vm, but it doesn't use a method proxy. Instead
* it sends the information to get the method to the remote vm along with the parms. That way
* it will do the lookup on the remote vm and we don't have the overhead of two calls, one to
* get the methodproxy and the other to actually do the invoke. This should typically be used
* only for infrequent calls so that cache of the method proxy is not needed.
*
* @since 1.0.0
*/
class REMInvokable implements IInvokable {
protected final IREMBeanTypeProxy beanType; // Beantype to get method from.
protected final String methodName; // Method name
protected final IBeanTypeProxy[] methodArgTypes; // Argument types (or null if no arguments).
protected final REMProxyFactoryRegistry factory; // Factory for this invokable
REMInvokable(IREMBeanTypeProxy beanType, String methodName, IBeanTypeProxy[] methodArgTypes) {
this.beanType = beanType;
this.methodName = methodName;
this.methodArgTypes = methodArgTypes;
this.factory = (REMProxyFactoryRegistry) beanType.getProxyFactoryRegistry();
}
public IBeanProxy invoke(IBeanProxy subject) throws ThrowableProxy {
return invoke(subject, (IBeanProxy[]) null);
}
public IBeanProxy invoke(IBeanProxy subject, IBeanProxy[] parms) throws ThrowableProxy {
return invokeWithParms(subject, parms);
}
/**
* The internal method that allows mixture of constants (e.g. String) with bean proxies.
* A parm value can be a REMMethodProxy.ParmArray. This means this parm is an array that
* needs to have a ValueRetriever created for it. This is used if the array has ID's in
* it and is not an existing array on the server or all constant values.
*
* NOTE: It is assumed that all IBeanTypeProxies of the parms have already been retrieved.
* It should still work, but it could be asking for them in the middle of the request
* if they are not first gotton.
*
*/
public IBeanProxy invokeWithParms(IBeanProxy subject, final Object[] parms) throws ThrowableProxy {
IREMConnection connect = factory.getFreeConnection();
REMStandardBeanProxyFactory proxyFactory = (REMStandardBeanProxyFactory) factory.getBeanProxyFactory();
proxyFactory.startTransaction(); // This is definately a transaction, so start it.
try {
// First need to send the method info.
Commands.ValueObject classValue = new Commands.ValueObject();
beanType.renderBean(classValue);
Commands.ValueObject parmTypesValue = new Commands.ValueObject();
if (methodArgTypes != null) {
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++];
((IREMBeanTypeProxy) parm).renderBean(worker);
return worker;
}
};
parmTypesValue.setArrayIDS(new Retriever(methodArgTypes), methodArgTypes.length, Commands.CLASS_CLASS); // Create Class[].
}
// Now we start building the actual invocation.
Commands.ValueObject subjectValue = new Commands.ValueObject();
if (subject != null)
((IREMBeanProxy) subject).renderBean(subjectValue);
Commands.ValueObject parmsValue = new Commands.ValueObject();
if (parms != null) {
// Have a local definition of the retriever so that the retriever can create
// another one of itself if necessary.
final IStandardBeanTypeProxyFactory typeFactory = factory.getBeanTypeProxyFactory();
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 IREMBeanProxy)
((IREMBeanProxy) parm).renderBean(worker);
else if (parm instanceof TransmitableArray) {
// It is another array, create a new retriever.
worker.setArrayIDS(
new Retriever(((TransmitableArray) parm).array),
((TransmitableArray) parm).array.length,
((TransmitableArray) parm).componentTypeID);
} else {
// It's an object. Need to get bean type so that we can send it.
IREMBeanProxy type = (IREMBeanProxy) typeFactory.getBeanTypeProxy(parm.getClass().getName());
if (type == null)
throw new IllegalArgumentException();
int classID = type.getID().intValue();
worker.setAsObject(parm, classID);
}
else
worker.set();
return worker;
}
};
parmsValue.setArrayIDS(new Retriever(parms), parms.length, Commands.OBJECT_CLASS); // Create Object[].
}
Commands.ValueObject returnValue = new Commands.ValueObject();
try {
invoke(connect, proxyFactory, classValue, parmTypesValue, subjectValue, parmsValue, returnValue);
return proxyFactory.getBeanProxy(returnValue);
} catch (CommandException e) {
if (!e.isRecoverable()) {
// Close the connection and try again.
factory.closeConnection(connect);
connect = null;
connect = factory.getFreeConnection();
try {
invoke(connect, proxyFactory, classValue, parmTypesValue, subjectValue, parmsValue, returnValue);
return proxyFactory.getBeanProxy(returnValue);
} catch (CommandException eAgain) {
// Failed again. Just close and print trace.
factory.closeConnection(connect);
connect = null;
ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, "", eAgain)); //$NON-NLS-1$
return null;
}
} else {
// A recoverable error, print trace and return
ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, "", e)); //$NON-NLS-1$
return null;
}
}
} finally {
proxyFactory.stopTransaction();
if (connect != null)
factory.returnConnection(connect);
}
}
private void invoke(
IREMConnection connect,
REMStandardBeanProxyFactory proxyFactory,
Commands.ValueObject classTypeValue,
Commands.ValueObject parmTypesValue,
Commands.ValueObject subjectValue,
Commands.ValueObject parmsValue,
Commands.ValueObject returnValue)
throws ThrowableProxy, CommandException {
try {
connect.invokeMethod(classTypeValue, methodName, parmTypesValue, subjectValue, parmsValue, returnValue);
} catch (CommandErrorException e) {
proxyFactory.processErrorReturn(e);
}
}
public IBeanProxy invoke(IBeanProxy subject, IBeanProxy parm) throws ThrowableProxy {
return invoke(subject, new IBeanProxy[] { parm });
}
public IBeanProxy invokeCatchThrowableExceptions(IBeanProxy subject) {
try {
return invoke(subject);
} catch (ThrowableProxy e) {
ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, "", e)); //$NON-NLS-1$
factory.releaseProxy(e); // Since it's no longer needed, get rid of now instead of GC time.
return null;
}
}
public IBeanProxy invokeCatchThrowableExceptions(IBeanProxy subject, IBeanProxy[] parms) {
try {
return invoke(subject, parms);
} catch (ThrowableProxy e) {
ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, "", e)); //$NON-NLS-1$
factory.releaseProxy(e); // Since it's no longer needed, get rid of now instead of GC time.
return null;
}
}
public IBeanProxy invokeCatchThrowableExceptions(IBeanProxy subject, IBeanProxy parm) {
try {
return invoke(subject, parm);
} catch (ThrowableProxy e) {
ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, "", e)); //$NON-NLS-1$
factory.releaseProxy(e); // Since it's no longer needed, get rid of now instead of GC time.
return null;
}
}
}