/******************************************************************************* * 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.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.*; /** * Remote VM implementation of the MethodProxy */ final class REMMethodProxy extends REMAccessibleObjectProxy implements IREMMethodProxy { private IBeanTypeProxy fDeclaringType; private String fMethodName; private IBeanTypeProxy[] fParameterTypes; private IBeanTypeProxy fReturnType; REMMethodProxy(REMProxyFactoryRegistry aRegistry, Integer anID) { super(aRegistry, anID); } public IBeanTypeProxy getClassType() { if (fDeclaringType == null) fDeclaringType = (IBeanTypeProxy) REMStandardBeanProxyConstants .getConstants(fFactory) .getMethodDeclaringClassMessage() .invokeCatchThrowableExceptions( this); return fDeclaringType; } public String getName() { if (fMethodName == null) { IStringBeanProxy proxy = (IStringBeanProxy) REMStandardBeanProxyConstants .getConstants(fFactory) .getMethodMethodNameMessage() .invokeCatchThrowableExceptions( this); if (proxy != null) fMethodName = proxy.stringValue(); else fMethodName = ""; //$NON-NLS-1$ } return fMethodName; } public synchronized IBeanTypeProxy[] getParameterTypes() { if (fParameterTypes == null) { IArrayBeanProxy parmTypes = (IArrayBeanProxy) REMStandardBeanProxyConstants.getConstants(fFactory) .getMethodParameterTypesMessage().invokeCatchThrowableExceptions(this); if (parmTypes == null) fParameterTypes = new IBeanTypeProxy[0]; // There was some error, only way null is returned else { int len = parmTypes.getLength(); fParameterTypes = new IBeanTypeProxy[len]; for (int i = 0; i < len; i++) try { fParameterTypes[i] = (IBeanTypeProxy) parmTypes.get(i); } catch (ThrowableProxy e) { } fFactory.releaseProxy(parmTypes); // Don't need the array on the server anymore. } } return fParameterTypes; } public IBeanTypeProxy getReturnType() { if (fReturnType == null) fReturnType = (IBeanTypeProxy) REMStandardBeanProxyConstants .getConstants(fFactory) .getMethodReturnTypeMessage() .invokeCatchThrowableExceptions( this); return fReturnType; } 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. * * NOTE: This is in IREMMethodProxy only so that other REM proxy implementations can access it. */ public IBeanProxy invokeWithParms(IBeanProxy subject, final Object[] parms) throws ThrowableProxy { IREMConnection connect = fFactory.getFreeConnection(); REMStandardBeanProxyFactory proxyFactory = (REMStandardBeanProxyFactory) fFactory.getBeanProxyFactory(); proxyFactory.startTransaction(); // This is definately a transaction, so start it. try { Commands.ValueObject subjectValue = new Commands.ValueObject(); if (subject != null) ((IREMBeanProxy) subject).renderBean(subjectValue); Commands.ValueObject parmsValue = new Commands.ValueObject(); class Retriever implements Commands.ValueRetrieve { int index = 0; Object[] array; Commands.ValueObject worker = new Commands.ValueObject(); IStandardBeanTypeProxyFactory typeFactory = fFactory.getBeanTypeProxyFactory(); public Retriever(Object[] anArray) { array = anArray; } public void reset() { index = 0; } 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; } }; Retriever retriever = null; if (parms != null) { // Have a local definition of the retriever so that the retriever can create // another one of itself if necessary. parmsValue.setArrayIDS(retriever = new Retriever(parms), parms.length, Commands.OBJECT_CLASS); // Create Object[]. } Commands.ValueObject returnValue = new Commands.ValueObject(); try { invoke(connect, proxyFactory, subjectValue, parmsValue, returnValue); return proxyFactory.getBeanProxy(returnValue); } catch (CommandException e) { if (!e.isRecoverable()) { // Close the connection and try again. fFactory.closeConnection(connect); connect = null; connect = fFactory.getFreeConnection(); try { if (retriever != null) retriever.reset(); invoke(connect, proxyFactory, subjectValue, parmsValue, returnValue); return proxyFactory.getBeanProxy(returnValue); } catch (CommandException eAgain) { // Failed again. Just close and print trace. fFactory.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) fFactory.returnConnection(connect); } } private void invoke( IREMConnection connect, REMStandardBeanProxyFactory proxyFactory, Commands.ValueObject subjectValue, Commands.ValueObject parmsValue, Commands.ValueObject returnValue) throws ThrowableProxy, CommandException { try { connect.invokeMethod(getID().intValue(), 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$ fFactory.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$ fFactory.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$ fFactory.releaseProxy(e); // Since it's no longer needed, get rid of now instead of GC time. return null; } } /** * The type proxy is constant proxy out of the method factory. */ public IBeanTypeProxy getTypeProxy() { return ((REMMethodProxyFactory) fFactory.getMethodProxyFactory()).methodType; } /** * The bean is being released, clear out the fields so they can be GC'd if necessary. * Usually only big objects and proxy fields need to be cleared. */ public void release() { fDeclaringType = null; fParameterTypes = null; fReturnType = null; super.release(); } }