blob: ee7f450a091c7d31dc87130a4c584afb9c72452e [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
*******************************************************************************/
/*
*/
package org.eclipse.jem.internal.proxy.remote;
import java.io.*;
import java.util.*;
import java.util.logging.Level;
import org.eclipse.jem.internal.proxy.common.CommandException;
import org.eclipse.jem.internal.proxy.common.remote.*;
import org.eclipse.jem.internal.proxy.common.remote.Commands.ValueObject;
import org.eclipse.jem.internal.proxy.core.*;
import org.eclipse.jem.internal.proxy.initParser.tree.*;
/**
* The Remote proxy version of Expression.
*
* @since 1.0.0
*/
public class REMExpression extends Expression {
private IREMExpressionConnection connection;
private boolean closed; // Are we closed.
protected Commands.ValueObject workerValue; // A worker object so that we don't need to keep creating one and throwing it away.
protected Map beanTypeCache; // Use to cache pending BeanTypes. Used in conjunction with REMStandardBeanTypeFactory.
protected Map methodsCache; // Use to cache pending expression method proxies. Used in conjunction with REMProxyConsants.
protected Map fieldsCache; // Use to cache pending expression field proxies. Used in conjunction with REMProxyConsants.
/*
* This is very special list. It tries to eliminate unneeded traffic. For example a mark immediately followed by an endmark does
* not need to be sent. Many expressions can look like: mark, endmark, endtransaction. This is a do nothing and we don't want
* to create a connection to just send this. So this list is used to queue up these and remove them too when found as not needed.
*
* However, this is very tricky because all pushToProxy transactions that actually do something MUST call the processPending() method
* first to make sure any pending transactions are submitted. Because once a real type transaction, such as assignment occurs, any
* pending transaction is a valid transaction, and no longer a do-nothing transaction.
*
* Each transaction type uses a subclass of PendingTransaction to be an entry on the list.
*
* The pendings currently supported are:
* mark/endmark
* try/catch/endtry
* block/endblock
*
* See each individual transaction type to see how it is handled.
*/
protected List pendingTransactions;
/**
* PendingTransaction entry.
*
* @since 1.1.0
*/
protected abstract static class PendingTransaction {
/**
* The transaction is now being pushed. The implementation should
* actually do the push.
*
* @param remExpression The REMExpression for this transaction.
*
* @since 1.1.0
*/
public abstract void pushTransaction(REMExpression remExpression);
}
/**
* @param registry
*
* @since 1.0.0
*/
public REMExpression(REMProxyFactoryRegistry registry) {
super(registry);
}
/**
* Return the expression id for this REMExpression. This id is used on the remote vm to
* identify who the request is for.
* @return
*
* @since 1.1.0
*/
protected int getREMExpressionID() {
return this.hashCode();
}
/**
* Get the pending transactions list.
* @return
*
* @since 1.1.0
*/
protected List getPendingTransactions() {
if (pendingTransactions == null)
pendingTransactions = new ArrayList();
return pendingTransactions;
}
// Use this flag when debugging to test if errors are due to improper pending processing.
// If true they will be treated as if not pending and will be executed immediately.
private static final boolean EXECUTE_PENDING_IMMEDIATELY = false;
protected void addPendingTransaction(PendingTransaction pending) {
if (!EXECUTE_PENDING_IMMEDIATELY)
getPendingTransactions().add(pending);
else
pending.pushTransaction(this);
}
private boolean sentData; // Flag to indicate if we have sent anything yet to the remote vm. This is used for the pending optimizations.
/**
* Have we sent any data in this transaction yet.
* @return
*
* @since 1.1.0
*/
protected boolean haveSentData() {
return sentData;
}
/**
* @return Returns the connection.
*
* @since 1.1.0
*/
protected IREMExpressionConnection getConnection() {
if (connection == null) {
if (!sentData)
getREMBeanProxyFactory().startTransaction(); // This is the first time we send data, so start transaction.
sentData = true; // If we are getting a transaction, that means we are sending data.
connection = (IREMExpressionConnection) getREMRegistry().getFreeConnection();
// This will actually not be stopped until closeproxy. There could be a slight problem if the expression is never closed.
// But that shouldn't happen. This is to prevent any proxy that was released during the execution but was used by
// the expression from being released on the remote vm until after the expression is finished.
try {
if (workerValue == null)
workerValue = new Commands.ValueObject();
if (expressionProcesserController == null) {
byte trace = !isTraceSet() ? ExpressionCommands.TRACE_DEFAULT : (isTrace() ? ExpressionCommands.TRACE_ON : ExpressionCommands.TRACE_OFF);
connection.startExpressionProcessing(getREMExpressionID(), trace); // It is a new expression.
} else {
fillProxy(expressionProcesserController, workerValue);
connection.resumeExpression(getREMExpressionID(), workerValue);
expressionProcesserController = null;
}
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
if (!e.isRecoverable()) {
connection.close();
connection = null;
}
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
return connection;
}
/**
* General IOException occurred msg.
*/
protected static final String IO_EXCEPTION_MSG = ProxyRemoteMessages.REMExpression_IOExceptionSeeLog_INFO_;
protected static final String COMMAND_EXCEPTION_MSG = ProxyRemoteMessages.REMExpression_CommandExceptionSeeLog_INFO_;
/**
* Throw an an illegal state exception if some general error, in particular an I/O or Command Exception
* occurred so that callers know there is something wrong.
*
* @param msg
* @throws IllegalStateException
*
* @since 1.0.0
*/
protected void throwIllegalStateException(String msg) throws IllegalStateException {
throw new IllegalStateException(msg);
}
/**
* Return the registry as a REMProxyFactoryRegistry
* @return
*
* @since 1.0.0
*/
protected final REMProxyFactoryRegistry getREMRegistry() {
return (REMProxyFactoryRegistry) registry;
}
/**
* Return the bean proxy factory as a REMStandardBeanProxyFactory.
* @return
*
* @since 1.0.0
*/
protected final REMStandardBeanProxyFactory getREMBeanProxyFactory() {
return (REMStandardBeanProxyFactory) beanProxyFactory;
}
/**
* Process any pending transactions.
* <p>
* <b>Note: </b>It is required that all non-pending-participating transactions must
* call this method first to make sure pending transactions are sent. If this is
* not done, there will be errors in the expression.
*
*
* @since 1.1.0
*/
protected void processPendingTransactions() {
if (pendingTransactions != null && !pendingTransactions.isEmpty()) {
try {
for (int i = 0; i < pendingTransactions.size(); i++) {
((PendingTransaction) pendingTransactions.get(i)).pushTransaction(this);
}
} finally {
pendingTransactions.clear();
}
}
}
/**
* Get the pending entry from top. If top is 1, then get top entry (i.e. last one added), 2 is next one.
* @param fromTop
* @return entry requested, or <code>null</code> if no such entry.
*
* @since 1.1.0
*/
protected PendingTransaction getPendingEntryFromTop(int fromTop) {
if (pendingTransactions != null && pendingTransactions.size() >= fromTop) {
return (PendingTransaction) pendingTransactions.get(pendingTransactions.size()-fromTop);
} else
return null;
}
/**
* Pop up the top entry from the pending transactions queue.
* @param fromTop how many entries to pop from the pending transaction list.
*
*
* @since 1.1.0
*/
protected void popPendingEntry(int fromTop) {
if (pendingTransactions != null)
if (pendingTransactions.size() > fromTop) {
while(fromTop-- >0)
pendingTransactions.remove(pendingTransactions.size()-1);
} else
pendingTransactions.clear();
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushToProxy(org.eclipse.jem.internal.proxy.core.IProxy)
*/
protected void pushToProxy(IProxy proxy) {
if (proxy == null || proxy.isBeanProxy())
pushToProxy((IBeanProxy) proxy);
else
pushToExpressionProxy((ExpressionProxy) proxy);
}
private void pushToProxy(IBeanProxy proxy) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push proxy command is:
// PushExpressionCommand(push to proxy) followed by:
// ValueObject containing the rendered proxy.
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.PUSH_TO_PROXY_EXPRESSION_VALUE);
if (proxy == null)
workerValue.set();
else
((IREMBeanProxy) proxy).renderBean(workerValue);
connection.pushValueObject(workerValue);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#closeProxy()
*/
protected void closeProxy() {
if (!closed) {
try {
if (connection != null && connection.isConnected()) {
try {
connection.stopExpressionProcessing(getREMExpressionID());
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e, Level.INFO);
// Not throwing an illegal state here because we don't care, other than logging and not
// returning the connection to the registry that there was an error on close.
} finally {
getREMRegistry().returnConnection(connection);
}
}
} finally {
closed = true;
if (sentData)
getREMBeanProxyFactory().stopTransaction(); // Resume proxy releases. We've sent data at least once.
}
}
methodsCache = null;
fieldsCache = null;
beanTypeCache = null;
pendingTransactions = null;
connection = null;
}
private static final Object VOIDTYPE = new Object(); // A void type was sent in expression proxy resolution.
private static final Object NOTRESOLVED = new Object(); // A not resolved type was sent in expression proxy resolution.
/*
* Get the sender to use for pulling the expression proxy resolutions.
*/
private BeanProxyValueSender getExpressionProxiesSender() {
return new BeanProxyValueSender(getREMBeanProxyFactory()) {
/*
* (non-Javadoc)
*
* @see org.eclipse.jem.internal.proxy.remote.BeanProxyValueSender#sendValue(org.eclipse.jem.internal.proxy.common.remote.Commands.ValueObject)
*/
public void sendValue(ValueObject value) {
if (value.getType() == Commands.FLAG) {
switch (value.anInt) {
case ExpressionCommands.EXPRESSIONPROXY_NOTRESOLVED:
array[index++] = NOTRESOLVED;
break;
case ExpressionCommands.EXPRESSIONPROXY_VOIDTYPE:
array[index++] = VOIDTYPE;
break;
default:
// Shouldn't happen.
break;
}
} else
super.sendValue(value);
}
};
}
/*
* Process the pulled expression proxy resolutions.
*/
private void processpulledExpressionProxies(List expressionProxies, BeanProxyValueSender sender) {
// It is expected that each entry will coorespond to the next non-null expression proxy and will be the bean proxy or one of the special
// types.
int len = expressionProxies.size();
int j = 0;
Object[] resolveds = sender.getArray();
for (int i = 0; i < len; i++) {
ExpressionProxy ep = (ExpressionProxy) expressionProxies.get(i);
if (ep != null) {
Object resolved = resolveds[j++];
if (resolved == NOTRESOLVED)
fireProxyNotResolved(ep);
else if (resolved == VOIDTYPE)
fireProxyVoid(ep);
else
fireProxyResolved(ep, (IBeanProxy) resolved);
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jem.internal.proxy.core.Expression#pullProxyValue(int, java.util.List)
*/
protected IBeanProxy pullProxyValue(int proxycount, List expressionProxies) throws ThrowableProxy, NoExpressionValueException {
if (!haveSentData()) {
markAllProxiesNotResolved(expressionProxies);
return null; // We haven't pushed any commands, so there is nothing to do. Don't create a connection for this.
}
// If there are any pending transactions at this point in time, there is no need to send them. They would be do nothings anyway.
boolean processedExpressionProxies = false;
IREMExpressionConnection lclConnection = getConnection();
markInTransaction(lclConnection);
try {
Commands.ValueObject proxyids = null;
BeanProxyValueSender sender = null;
if (proxycount > 0) {
proxyids = createExpressionProxiesValueObject(proxycount, expressionProxies);
sender = getExpressionProxiesSender();
}
lclConnection.pullValue(getREMExpressionID(), proxyids, sender);
// If we got this far, then if there are proxies, we need to process these too.
if (proxycount > 0)
processpulledExpressionProxies(expressionProxies, sender);
processedExpressionProxies =true;
lclConnection.getFinalValue(workerValue); // Get the returned value.
return getREMBeanProxyFactory().getBeanProxy(workerValue);
} catch (CommandErrorException e) {
try {
if (e.getErrorCode() == ExpressionCommands.EXPRESSION_NOEXPRESSIONVALUE_EXCEPTION) {
// Need to turn it into a Throwable.
ThrowableProxy t = null;
try {
getREMBeanProxyFactory().getBeanProxy(e.getValue()); // This will cause a throw to occur, but we don't want it going out, we want to capture it.
} catch (ThrowableProxy e1) {
t = e1;
}
throw new REMNoExpressionValueException(t);
}
getREMBeanProxyFactory().processErrorReturn(e);
} catch (CommandException e1) {
ProxyPlugin.getPlugin().getLogger().log(e);
if (!e.isRecoverable()) {
lclConnection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
if (!e.isRecoverable()) {
lclConnection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
} finally {
markEndTransaction(lclConnection);
if (!processedExpressionProxies)
markAllProxiesNotResolved(expressionProxies); // We failed before we could process the expression proxies. So mark all as not resolved.
}
return null;
}
/**
* This is called by commands that write some data and will be reading data back immediately
* (i.e. pull value and invoke expression). If we are on a callback thread and have the
* used the connection from the callback thread, we need to tell the callback thread that
* it is in a transaction. This is needed because while reading data back there are
* sometimes calls back to the vm to get beantype data for new classes. This would
* normally be through a new connection so that it doesn't get stuck in the middle of the
* data being sent back. But when running on a callback the same connection is used. So it
* would stick data in the middle of the return stream of data. To prevent this we need
* to tell the callback thread that it is in a transaction during this call so that any
* such new connection requests will get a new connection.
* <p>
* This is not nestable (i.e. the first markEndTransaction will set it false, even if several nested
* markInTransactions are called).
* <p>
* markEndTransaction must be called in ALL cases, such use try/finally.
* @param remConnection the connection to see check against and mark in transaction for.
*
*
* @since 1.1.0
*/
protected void markInTransaction(IREMExpressionConnection remConnection) {
Thread thread = Thread.currentThread();
if (thread instanceof REMCallbackThread) {
// We are in a callback, and the callback connection is our connection, tell the callback that it is in transaction.
REMCallbackThread callbackThread = (REMCallbackThread) thread;
if (callbackThread.getConnection() == remConnection) {
callbackThread.setIntransaction(true);
}
}
}
/**
* Mark end of transaction.
* @param remConn REMConnection to test and mark not in connection for.
*
* @see REMExpression#markInTransaction(IREMExpressionConnection)
* @since 1.1.0
*/
protected void markEndTransaction(IREMExpressionConnection remConn) {
Thread thread = Thread.currentThread();
if (thread instanceof REMCallbackThread) {
// We are in a callback, and the callback connection is our connection, tell the callback that it is in transaction.
REMCallbackThread callbackThread = (REMCallbackThread) thread;
if (callbackThread.getConnection() == remConn) {
callbackThread.setIntransaction(false);
}
}
}
/**
* @param expressionProxies
*
* @since 1.1.0
*/
private Commands.ValueObject createExpressionProxiesValueObject(int actualCount, List expressionProxies) {
class ExpressionProxyRetriever implements Commands.ValueRetrieve {
Iterator expressionProxiesItr;
Commands.ValueObject worker = new Commands.ValueObject();
public ExpressionProxyRetriever(List expressionProxies) {
this.expressionProxiesItr = expressionProxies.iterator();
}
public Commands.ValueObject nextValue() {
worker.set(-1);
while (expressionProxiesItr.hasNext()) {
Object parm = expressionProxiesItr.next();
if (parm != null) {
worker.set(((ExpressionProxy) parm).getProxyID());
break;
}
}
return worker;
}
};
workerValue.setArrayIDS(new ExpressionProxyRetriever(expressionProxies), actualCount, Commands.INT);
return workerValue;
}
/*
* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushCastToProxy(org.eclipse.jem.internal.proxy.core.IProxyBeanType)
*/
protected void pushCastToProxy(IProxyBeanType type) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push cast to proxy command is:
// PushExpressionCommand(push cast to proxy) followed by:
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.CAST_EXPRESSION_VALUE);
fillProxy(type, workerValue);
connection.pushValueObject(workerValue);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
/**
* Push the proxy bean type in the format depending on expression proxy or beantype proxy.
* @param type
* @throws IOException
*
* @since 1.1.0
*/
protected void fillProxy(IProxy type, Commands.ValueObject value) throws IOException {
// ValueObject containing the rendered bean type proxy if IBeanTypeProxy or int (for expression proxy id) if expression proxy.
if (type.isBeanProxy()) {
((IREMBeanProxy) type).renderBean(value);
} else {
ExpressionProxy ep = (ExpressionProxy) type;
value.set(ep.getProxyID());
}
}
/*
* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushInstanceofToProxy(org.eclipse.jem.internal.proxy.core.IProxyBeanType)
*/
protected void pushInstanceofToProxy(IProxyBeanType type) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push instanceof to proxy command is:
// PushExpressionCommand(push instanceof to proxy) followed by:
// ValueObject containing the rendered bean type proxy or the String representing the name of class.
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.INSTANCEOF_EXPRESSION_VALUE);
fillProxy(type, workerValue);
connection.pushValueObject(workerValue);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
/*
* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushInfixToProxy(org.eclipse.jem.internal.proxy.initParser.tree.InfixOperator, int)
*/
protected void pushInfixToProxy(InfixOperator operator, InternalInfixOperandType operandType) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push infix to proxy command is:
// PushExpressionCommand(push infix to proxy) followed by:
// byte: operator
// byte: operandType
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.INFIX_EXPRESSION_VALUE);
connection.pushByte((byte) operator.getValue());
connection.pushByte((byte) operandType.getValue());
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
/*
* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushPrefixToProxy(org.eclipse.jem.internal.proxy.initParser.tree.PrefixOperator)
*/
protected void pushPrefixToProxy(PrefixOperator operator) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push prefix to proxy command is:
// PushExpressionCommand(push prefix to proxy) followed by:
// byte: operator
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.PREFIX_EXPRESSION_VALUE);
connection.pushByte((byte) operator.getValue());
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushArrayAccessToProxy(int)
*/
protected void pushArrayAccessToProxy(int indexCount) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push array access to proxy command is:
// PushExpressionCommand(push array acces to proxy) followed by:
// int: indexCount
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.ARRAY_ACCESS_EXPRESSION_VALUE);
connection.pushInt(indexCount);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
/*
* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushArrayCreationToProxy(org.eclipse.jem.internal.proxy.core.IProxyBeanType, int)
*/
protected void pushArrayCreationToProxy(IProxyBeanType type, int dimensionCount) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push array creation to proxy command is:
// PushExpressionCommand(push array creation to proxy) followed by:
// ValueObject containing the rendered bean type proxy or the expression proxy.
// int: dimension count
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.ARRAY_CREATION_EXPRESSION_VALUE);
fillProxy(type, workerValue);
connection.pushValueObject(workerValue);
connection.pushInt(dimensionCount);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
protected void pushArrayInitializerToProxy(IProxyBeanType type, int stripCount, int expressionCount) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push array initializer to proxy command is:
// PushExpressionCommand(push array initializer to proxy) followed by:
// ValueObject containing the rendered bean type proxy or expression proxy.
// int: strip count
// int: expression count
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.ARRAY_INITIALIZER_EXPRESSION_VALUE);
fillProxy(type, workerValue);
connection.pushValueObject(workerValue);
connection.pushInt(stripCount);
connection.pushInt(expressionCount);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
/*
* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushClassInstanceCreationToProxy(org.eclipse.jem.internal.proxy.core.IProxyBeanType, int)
*/
protected void pushClassInstanceCreationToProxy(IProxyBeanType type, int argumentCount) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push class instance creation to proxy command is:
// PushExpressionCommand(push class instance creation to proxy) followed by:
// ValueObject containing the rendered bean type proxy or the expression proxy
// int: argument count
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.CLASS_INSTANCE_CREATION_EXPRESSION_VALUE);
fillProxy(type, workerValue);
connection.pushValueObject(workerValue);
connection.pushInt(argumentCount);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
/*
* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushTypeReceiverToProxy(org.eclipse.jem.internal.proxy.core.IProxyBeanType)
*/
protected void pushTypeReceiverToProxy(IProxyBeanType type) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push type receiver to proxy command is:
// PushExpressionCommand(push type receiver to proxy) followed by:
// ValueObject containing the rendered bean type proxy or the expression proxy.
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.TYPERECEIVER_EXPRESSION_VALUE);
fillProxy(type, workerValue);
connection.pushValueObject(workerValue);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushFieldAccessToProxy(java.lang.String, boolean)
*/
protected void pushFieldAccessToProxy(Object field, boolean hasReceiver) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push field access to proxy command is:
// PushExpressionCommand(push field access to proxy) followed by:
// Commands.Value: fieldName or IProxyField
// boolean: hasReceiver
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.FIELD_ACCESS_EXPRESSION_VALUE);
if (field instanceof String) {
workerValue.set((String) field);
} else {
fillProxy((IProxy) field, workerValue);
}
connection.pushValueObject(workerValue);
connection.pushBoolean(hasReceiver);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushMethodInvocationToProxy(java.lang.String, boolean, int)
*/
protected void pushMethodInvocationToProxy(Object method, boolean hasReceiver, int argCount) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push method invocation to proxy command is:
// PushExpressionCommand(push method invocation to proxy) followed by:
// Commands.ValueObject: methodName or IMethodProxy
// boolean: hasReceiver
// int: argCount
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.METHOD_EXPRESSION_VALUE);
if (method instanceof String) {
workerValue.set((String) method);
} else {
fillProxy((IProxy) method, workerValue);
}
connection.pushValueObject(workerValue);
connection.pushBoolean(hasReceiver);
connection.pushInt(argCount);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushConditionalToProxy(int)
*/
protected void pushConditionalToProxy(InternalConditionalOperandType expressionType) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push conditional to proxy command is:
// PushExpressionCommand(push conditional to proxy) followed by:
// byte: expression type
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.CONDITIONAL_EXPRESSION_VALUE);
connection.pushByte((byte) expressionType.getValue());
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
/*
* A special one that takes the ThrowableProxy for no expression value and
* wrappers it prints its stack trace instead, but still makes it a subclass
* of NoExpressionValueException.
*
* @since 1.1.0
*/
private static class REMNoExpressionValueException extends NoExpressionValueException {
/**
* Comment for <code>serialVersionUID</code>
*
* @since 1.1.0
*/
private static final long serialVersionUID = 1692406777391812694L;
public REMNoExpressionValueException(ThrowableProxy e) {
super(e);
}
/* (non-Javadoc)
* @see java.lang.Throwable#getLocalizedMessage()
*/
public String getLocalizedMessage() {
return ((ThrowableProxy) getCause()).getProxyLocalizedMessage();
}
/* (non-Javadoc)
* @see java.lang.Throwable#getMessage()
*/
public String getMessage() {
return ((ThrowableProxy) getCause()).getProxyMessage();
}
/* (non-Javadoc)
* @see java.lang.Throwable#printStackTrace()
*/
public void printStackTrace() {
getCause().printStackTrace();
}
/* (non-Javadoc)
* @see java.lang.Throwable#printStackTrace(java.io.PrintStream)
*/
public void printStackTrace(PrintStream s) {
getCause().printStackTrace(s);
}
/* (non-Javadoc)
* @see java.lang.Throwable#printStackTrace(java.io.PrintWriter)
*/
public void printStackTrace(PrintWriter s) {
getCause().printStackTrace(s);
}
}
/*
* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushInvoke(int, java.util.List)
*/
protected void pushInvoke(int proxycount, List expressionProxies) throws ThrowableProxy, NoExpressionValueException {
if (!haveSentData()) {
markAllProxiesNotResolved(expressionProxies);
return; // We haven't pushed any commands, so there is nothing to do. Don't create a connection for this.
}
// If at this point there are pending transactions, there is no need to send them because they would all be do-nothings.
boolean processedExpressionProxies = false;
IREMExpressionConnection lclConnection = getConnection();
markInTransaction(lclConnection);
try {
Commands.ValueObject proxyids = null;
BeanProxyValueSender sender = null;
if (proxycount > 0) {
proxyids = createExpressionProxiesValueObject(proxycount, expressionProxies);
sender = getExpressionProxiesSender();
}
lclConnection.sync(getREMExpressionID(), proxyids, sender);
// If we got this far, then if there are proxies, we need to process these too.
if (proxycount > 0)
processpulledExpressionProxies(expressionProxies, sender);
processedExpressionProxies = true;
lclConnection.getFinalValue(workerValue); // We don't care what it is, we just need to see if there is an error.
} catch (CommandErrorException e) {
try {
if (e.getErrorCode() == ExpressionCommands.EXPRESSION_NOEXPRESSIONVALUE_EXCEPTION) {
// Need to turn it into a Throwable.
ThrowableProxy t = null;
try {
getREMBeanProxyFactory().getBeanProxy(e.getValue()); // This will cause a throw to occur, but we don't want it going out, we want to capture it.
} catch (ThrowableProxy e1) {
t = e1;
}
throw new REMNoExpressionValueException(t);
}
getREMBeanProxyFactory().processErrorReturn(e);
} catch (CommandException e1) {
ProxyPlugin.getPlugin().getLogger().log(e);
if (!e.isRecoverable()) {
lclConnection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
if (!e.isRecoverable()) {
lclConnection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
} finally {
markEndTransaction(lclConnection);
if (!processedExpressionProxies)
markAllProxiesNotResolved(expressionProxies); // We failed before we could process the expression proxies. So mark all as not resolved.
}
}
private static class REMBeanTypeExpressionProxy extends ExpressionProxy implements IBeanTypeExpressionProxy {
private String typeName;
/**
* @param proxyid
*
* @since 1.1.0
*/
private REMBeanTypeExpressionProxy(int proxyid, Expression expression) {
super(proxyid, BEANTYPE_EXPRESSION_PROXY, expression);
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public String getTypeName() {
return typeName;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.ExpressionProxy#toString()
*/
public String toString() {
return super.toString()+" - "+getTypeName(); //$NON-NLS-1$
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.IProxyBeanType#getMethodProxy(org.eclipse.jem.internal.proxy.core.IExpression, java.lang.String, org.eclipse.jem.internal.proxy.core.IProxyBeanType[])
*/
public IProxyMethod getMethodProxy(IExpression expression, String methodName, IProxyBeanType[] parameterTypes) {
REMProxyFactoryRegistry registry = (REMProxyFactoryRegistry) expression.getRegistry();
return ((REMMethodProxyFactory) registry.getMethodProxyFactory()).getMethodProxy(expression, this, methodName, parameterTypes);
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.IProxyBeanType#getMethodProxy(org.eclipse.jem.internal.proxy.core.IExpression, java.lang.String, java.lang.String[])
*/
public IProxyMethod getMethodProxy(IExpression expression, String methodName, String[] parameterTypes) {
REMProxyFactoryRegistry registry = (REMProxyFactoryRegistry) expression.getRegistry();
return ((REMMethodProxyFactory) registry.getMethodProxyFactory()).getMethodProxy(expression, this, methodName, parameterTypes);
}
public IProxyMethod getMethodProxy(IExpression expression, String methodName) {
return getMethodProxy(expression, methodName, (IProxyBeanType[]) null);
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.IProxyBeanType#getFieldProxy(org.eclipse.jem.internal.proxy.core.IExpression, java.lang.String)
*/
public IProxyField getFieldProxy(IExpression expression, String fieldName) {
REMProxyFactoryRegistry registry = (REMProxyFactoryRegistry) expression.getRegistry();
return ((REMMethodProxyFactory) registry.getMethodProxyFactory()).getFieldProxy(expression, this, fieldName);
}
}
private static class REMMethodExpressionProxy extends ExpressionProxy implements IProxyMethod {
/**
* @param proxyid
* @param proxyType
* @param expression
*
* @since 1.1.0
*/
private REMMethodExpressionProxy(int proxyid, Expression expression) {
super(proxyid, METHOD_EXPRESSION_PROXY, expression);
}
}
private static class REMFieldExpressionProxy extends ExpressionProxy implements IProxyField {
/**
* @param proxyid
* @param proxyType
* @param expression
*
* @since 1.1.0
*/
private REMFieldExpressionProxy(int proxyid, Expression expression) {
super(proxyid, FIELD_EXPRESSION_PROXY, expression);
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#createExpressionProxy(int)
*/
protected ExpressionProxy createExpressionProxy(int proxyType, int proxyID) {
switch (proxyType) {
case NORMAL_EXPRESSION_PROXY:
default:
return new ExpressionProxy(proxyID, NORMAL_EXPRESSION_PROXY, this);
case BEANTYPE_EXPRESSION_PROXY:
return new REMBeanTypeExpressionProxy(proxyID, this);
case METHOD_EXPRESSION_PROXY:
return new REMMethodExpressionProxy(proxyID, this);
case FIELD_EXPRESSION_PROXY:
return new REMFieldExpressionProxy(proxyID, this);
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushAssignmentToProxy(org.eclipse.jem.internal.proxy.core.ExpressionProxy)
*/
protected void pushAssignmentToProxy(ExpressionProxy proxy) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push assignment to proxy command is:
// PushExpressionCommand(push assignment to proxy) followed by:
// int: proxy id
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.ASSIGNMENT_PROXY_EXPRESSION_VALUE);
connection.pushInt(proxy.getProxyID());
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushAssignmentToProxy()
*/
protected void pushAssignmentToProxy() {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of the push assignment command is:
// PushAssignmentCommand.
connection.pushExpressionCommand(getREMExpressionID(), (byte) InternalExpressionTypes.ASSIGNMENT_EXPRESSION_VALUE);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
private void pushToExpressionProxy(ExpressionProxy proxy) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push to expression proxy command is:
// PushExpressionCommand(push expression proxy to proxy) followed by:
// int: proxy id
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.PUSH_TO_EXPRESSION_PROXY_EXPRESSION_VALUE);
connection.pushInt(proxy.getProxyID());
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
private static class BlockBegin extends PendingTransaction {
public int blockNumber;
public BlockBegin(int blockNumber) {
this.blockNumber = blockNumber;
}
public void pushTransaction(REMExpression remExpression) {
IREMExpressionConnection connection = remExpression.getConnection();
try {
// Format of push to block begin proxy command is:
// PushExpressionCommand(push block begin proxy to proxy) followed by:
// int: block id
connection.pushExpressionCommand(remExpression.getREMExpressionID(), (byte)InternalExpressionTypes.BLOCK_BEGIN_EXPRESSION_VALUE);
connection.pushInt(blockNumber);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
remExpression.markInvalid(e.getLocalizedMessage());
remExpression.throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushBlockBeginToProxy(int)
*/
protected void pushBlockBeginToProxy(int blockNumber) {
addPendingTransaction(new BlockBegin(blockNumber));
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushBlockEndToProxy(int)
*/
protected void pushBlockEndToProxy(int blockNumber) {
// See if the top pending transactions is BreakBlock(blockNumber). If it is then the BreakBlock can be thrown away.
PendingTransaction topEntry = getPendingEntryFromTop(1);
if (topEntry instanceof BlockBreak && ((BlockBreak) topEntry).blockNumber == blockNumber) {
popPendingEntry(1);
topEntry = getPendingEntryFromTop(1);
}
// See if the top pending transaction is now BeginBlock(blockNumber). If it is, then this transaction and the block begin
// can be thrown away because they are an empty block.
if (topEntry instanceof BlockBegin && ((BlockBegin) topEntry).blockNumber == blockNumber) {
popPendingEntry(1);
return;
}
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push to block end proxy command is:
// PushExpressionCommand(push block end proxy to proxy) followed by:
// int: block id
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.BLOCK_END_EXPRESSION_VALUE);
connection.pushInt(blockNumber);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
private static class BlockBreak extends PendingTransaction {
public int blockNumber;
public BlockBreak(int blockNumber) {
this.blockNumber = blockNumber;
}
public void pushTransaction(REMExpression remExpression) {
IREMExpressionConnection connection = remExpression.getConnection();
try {
// Format of push to block break proxy command is:
// PushExpressionCommand(push block break proxy to proxy) followed by:
// int: block id
connection.pushExpressionCommand(remExpression.getREMExpressionID(), (byte)InternalExpressionTypes.BLOCK_BREAK_EXPRESSION_VALUE);
connection.pushInt(blockNumber);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
remExpression.markInvalid(e.getLocalizedMessage());
remExpression.throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushBlockBreakToProxy(int)
*/
protected void pushBlockBreakToProxy(int blockNumber) {
// Even if there is no pending block begin for this block, we will pend the break.
// This is so that if the break occurred just before the block end, then it can be ignored.
addPendingTransaction(new BlockBreak(blockNumber));
}
private static class TryBegin extends PendingTransaction {
public final int tryNumber;
public TryBegin(int tryNumber) {
this.tryNumber = tryNumber;
}
public void pushTransaction(REMExpression remExpression) {
IREMExpressionConnection connection = remExpression.getConnection();
try {
// Format of push to try begin proxy command is:
// PushExpressionCommand(push try begin to proxy) followed by:
// int: try id
connection.pushExpressionCommand(remExpression.getREMExpressionID(), (byte)InternalExpressionTypes.TRY_BEGIN_EXPRESSION_VALUE);
connection.pushInt(tryNumber);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
remExpression.markInvalid(e.getLocalizedMessage());
remExpression.throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushTryBeginToProxy(int)
*/
protected void pushTryBeginToProxy(int tryNumber) {
addPendingTransaction(new TryBegin(tryNumber));
}
private static class TryCatch extends PendingTransaction {
public final int tryNumber;
private final IProxyBeanType exceptionType;
private final ExpressionProxy ep;
public TryCatch(int tryNumber, IProxyBeanType exceptionType, ExpressionProxy ep) {
this.tryNumber = tryNumber;
this.exceptionType = exceptionType;
this.ep = ep;
}
public void pushTransaction(REMExpression remExpression) {
IREMExpressionConnection connection = remExpression.getConnection();
try {
// Format of push to try begin proxy command is:
// PushExpressionCommand(push try begin to proxy) followed by:
// int: try id
// object: expression type (as beantype or as expression proxy)
// int: proxy id or (-1 if null).
connection.pushExpressionCommand(remExpression.getREMExpressionID(), (byte)InternalExpressionTypes.TRY_CATCH_EXPRESSION_VALUE);
connection.pushInt(tryNumber);
remExpression.fillProxy(exceptionType, remExpression.workerValue);
connection.pushValueObject(remExpression.workerValue);
if (ep != null)
connection.pushInt(ep.getProxyID());
else
connection.pushInt(-1);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
remExpression.markInvalid(e.getLocalizedMessage());
remExpression.throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
remExpression.markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
remExpression.throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
}
/*
* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushTryCatchClauseToProxy(int, org.eclipse.jem.internal.proxy.core.IProxyBeanType, org.eclipse.jem.internal.proxy.core.ExpressionProxy)
*/
protected void pushTryCatchClauseToProxy(int tryNumber, IProxyBeanType exceptionType, ExpressionProxy ep) {
addPendingTransaction(new TryCatch(tryNumber, exceptionType, ep));
}
private static class TryFinally extends PendingTransaction {
public final int tryNumber;
public TryFinally(int tryNumber) {
this.tryNumber = tryNumber;
}
public void pushTransaction(REMExpression remExpression) {
IREMExpressionConnection connection = remExpression.getConnection();
try {
// Format of push to try begin proxy command is:
// PushExpressionCommand(push try finally to proxy) followed by:
// int: try id
connection.pushExpressionCommand(remExpression.getREMExpressionID(), (byte)InternalExpressionTypes.TRY_FINALLY_EXPRESSION_VALUE);
connection.pushInt(tryNumber);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
remExpression.markInvalid(e.getLocalizedMessage());
remExpression.throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushTryFinallyClauseToProxy(int)
*/
protected void pushTryFinallyClauseToProxy(int tryNumber) {
addPendingTransaction(new TryFinally(tryNumber));
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushTryEndToProxy(int)
*/
protected void pushTryEndToProxy(int tryNumber) {
// This is a little tricky. We need to find if there is nothing but try/catch/finally for this tryNumber on the pending
// transactions up to the try begin, if there is nothing else, then we can throw the entire try away. That
// means there was no code at all in any of the try/catch/finally blocks.
int fromTop = 0;
while (true) {
PendingTransaction topEntry = getPendingEntryFromTop(++fromTop);
if (topEntry instanceof TryFinally) {
if (((TryFinally) topEntry).tryNumber != tryNumber)
break; // We met a finally that wasn't ours, so entire try group must be sent.
} else if (topEntry instanceof TryCatch) {
if (((TryCatch) topEntry).tryNumber != tryNumber)
break; // We met a catch that wasn't ours, so entire try group must be sent.
} else if (topEntry instanceof TryBegin) {
if (((TryBegin) topEntry).tryNumber == tryNumber) {
// We've met our try begin, and nothing but empty catch/finally in between, so the entire group can be thrown away
popPendingEntry(fromTop);
return;
} else
break; // We've hit a try begin that wasn't ours, so the entire try group must be sent.
} else
break; // We've hit something other than our try group, so process everything.
}
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push to try begin proxy command is:
// PushExpressionCommand(push try end to proxy) followed by:
// int: try id
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.TRY_END_EXPRESSION_VALUE);
connection.pushInt(tryNumber);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushThrowToProxy()
*/
protected void pushThrowToProxy() {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push to try begin proxy command is:
// PushExpressionCommand(push throw to proxy)
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.THROW_EXPRESSION_VALUE);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushRethrowToProxy(int)
*/
protected void pushRethrowToProxy(int tryNumber) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push to rethow proxy command is:
// PushExpressionCommand(push rethrow to proxy)
// int: try id
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.RETHROW_EXPRESSION_VALUE);
connection.pushInt(tryNumber);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushBeanTypeToProxy(org.eclipse.jem.internal.proxy.core.IBeanTypeExpressionProxy)
*/
protected void pushBeanTypeToProxy(IBeanTypeExpressionProxy proxy) {
// Push beantype to proxy is sent out of sequence without respect to where in expression we are,
// so no need to handle pending transactions at this point. They would not affect the result
// of this call.
IREMExpressionConnection connection = getConnection();
try {
// Format of push to beanType proxy command is:
// PushExpressionCommand(push bean type expression proxy)
// int: proxy id
// string: typename
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.PUSH_BEANTYPE_EXPRESSIONPROXY_EXPRESSION_VALUE);
REMBeanTypeExpressionProxy ep = (REMBeanTypeExpressionProxy) proxy;
connection.pushInt(ep.getProxyID());
connection.pushString(ep.getTypeName());
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushMethodToProxy(org.eclipse.jem.internal.proxy.core.ExpressionProxy, org.eclipse.jem.internal.proxy.core.IProxyBeanType, java.lang.String, org.eclipse.jem.internal.proxy.core.IProxyBeanType[])
*/
protected void pushMethodToProxy(ExpressionProxy proxy, IProxyBeanType declaringType, String methodName, IProxyBeanType[] parameterTypes) {
// Push method to proxy is sent out of sequence without respect to where in expression we are,
// so no need to handle pending transactions at this point. They would not affect the result
// of this call.
IREMExpressionConnection connection = getConnection();
try {
// Format of push to method proxy command is:
// PushExpressionCommand(push method type expression proxy)
// int: proxy id
// ValueObject: containing the rendered bean type proxy or the expression proxy for the declaring type
// string: method name
// int: number of parameter types
// ValueObject(s): containing the rendered bean type proxy or the expression proxy for the parameter types.
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.PUSH_METHOD_EXPRESSIONPROXY_EXPRESSION_VALUE);
connection.pushInt(proxy.getProxyID());
fillProxy(declaringType, workerValue);
connection.pushValueObject(workerValue);
connection.pushString(methodName);
if (parameterTypes == null || parameterTypes.length == 0)
connection.pushInt(0);
else {
connection.pushInt(parameterTypes.length);
for (int i = 0; i < parameterTypes.length; i++) {
fillProxy(parameterTypes[i], workerValue);
connection.pushValueObject(workerValue);
}
}
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushFieldToProxy(org.eclipse.jem.internal.proxy.core.ExpressionProxy, org.eclipse.jem.internal.proxy.core.IProxyBeanType, java.lang.String)
*/
protected void pushFieldToProxy(ExpressionProxy proxy, IProxyBeanType declaringType, String fieldName) {
// Push field to proxy is sent out of sequence without respect to where in expression we are,
// so no need to handle pending transactions at this point. They would not affect the result
// of this call.
IREMExpressionConnection connection = getConnection();
try {
// Format of push to field proxy command is:
// PushExpressionCommand(push field type expression proxy)
// int: proxy id
// ValueObject: containing the rendered bean type proxy or the expression proxy for the declaring type
// string: field name
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.PUSH_FIELD_EXPRESSIONPROXY_EXPRESSION_VALUE);
connection.pushInt(proxy.getProxyID());
fillProxy(declaringType, workerValue);
connection.pushValueObject(workerValue);
connection.pushString(fieldName);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
/**
* Get the map of IProxyMethods for a beantype. Meant to be used only in conjunction with REMProxyConstants.
* It is here so the REMProxyConstants can store pending proxies per expression.
*
* @param beanType
* @return
*
* @since 1.1.0
*/
public Map getMethods(IProxyBeanType beanType) {
if (methodsCache == null)
methodsCache = new HashMap();
Map methods = (Map) methodsCache.get(beanType.getTypeName());
if(methods == null){
methods = new HashMap(20);
methodsCache.put(beanType.getTypeName(),methods);
}
return methods;
}
/**
* Get the map of IProxyFields for a beantype. Meant to be used only in conjunction with REMProxyConstants.
* It is here so the REMProxyConstants can store pending proxies per expression.
*
* @param beanType
* @return
*
* @since 1.1.0
*/
public Map getFields(IProxyBeanType beanType) {
if (fieldsCache == null)
fieldsCache = new HashMap();
Map fields = (Map) fieldsCache.get(beanType.getTypeName());
if(fields == null){
fields = new HashMap(20);
fieldsCache.put(beanType.getTypeName(),fields);
}
return fields;
}
/**
* Get the map of IProxyBeanTypes for a beantype name. Meant to be used only in conjunction with REMSgtandardBeanTypeFactory.
* It is here so the REMStandardBeanTypeFactory can store pending proxies per expression.
*
* @param beanType
* @return
*
* @since 1.1.0
*/
public IProxyBeanType getBeanType(String beanTypeName) {
if (beanTypeCache == null)
beanTypeCache = new HashMap();
return (IProxyBeanType) beanTypeCache.get(beanTypeName);
}
/**
* Add the beantype expression proxy to the map of bean type expression proxies. Used in conjunction with REMStandardBeanTypeFactory.
* It is here so the REMStandardBeanTypeFactory can store pending proxies per expression.
* @param beanTypeName
* @param beantype
*
* @since 1.1.0
*/
public void addBeanType(String beanTypeName, IProxyBeanType beantype) {
beanTypeCache.put(beanTypeName, beantype);
}
/**
* Remove the beantype expression proxy from the map. This is called because there was a rollback due to an endmark.
* @param beanTypeName
*
* @since 1.1.0
*/
public void removeBeanType(String beanTypeName) {
beanTypeCache.remove(beanTypeName);
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushIfTestToProxy()
*/
protected void pushIfTestToProxy() {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push if test to proxy command is:
// PushExpressionCommand(push if test to proxy)
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.IF_TEST_EXPRESSION_VALUE);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushIfElseToProxy(org.eclipse.jem.internal.proxy.initParser.tree.InternalIfElseOperandType)
*/
protected void pushIfElseToProxy(InternalIfElseOperandType clauseType) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push conditional to proxy command is:
// PushExpressionCommand(push if/else clause to proxy) followed by:
// byte: clause type
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.IF_ELSE_EXPRESSION_VALUE);
connection.pushByte((byte) clauseType.getValue());
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.Expression#pushNewInstanceToProxy(java.lang.String, org.eclipse.jem.internal.proxy.core.IProxyBeanType)
*/
protected void pushNewInstanceToProxy(String initializationString, IProxyBeanType resultType) {
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push new instance from initstring to proxy command is:
// PushExpressionCommand(push new instance to proxy) followed by:
// string: init string
// ValueObject: containing the rendered bean type proxy or the expression proxy for the declaring type
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.NEW_INSTANCE_VALUE);
connection.pushString(initializationString);
fillProxy(resultType, workerValue);
connection.pushValueObject(workerValue);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
if (!e.isRecoverable()) {
connection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
}
}
private static class Mark extends PendingTransaction {
public int markID;
public Mark(int markID) {
this.markID = markID;
}
public void pushTransaction(REMExpression remExpression) {
IREMExpressionConnection connection = remExpression.getConnection();
try {
// Format of push mark to proxy command is:
// PushExpressionCommand(push mark to proxy) followed by:
// int: markID
connection.pushExpressionCommand(remExpression.getREMExpressionID(), (byte)InternalExpressionTypes.MARK_VALUE);
connection.pushInt(markID);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
remExpression.markInvalid(e.getLocalizedMessage());
remExpression.throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
}
protected void pushMarkToProxy(int markID) {
addPendingTransaction(new Mark(markID));
}
protected void pushEndmarkToProxy(int markID, boolean restore) {
// See if the top pending transaction is now Mark(markID). If it is, then this transaction and the mark begin
// can be thrown away because they are an empty block.
PendingTransaction topEntry = getPendingEntryFromTop(1);
if (topEntry instanceof Mark && ((Mark) topEntry).markID == markID) {
popPendingEntry(1);
return;
}
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push end mark to proxy command is:
// PushExpressionCommand(push end mark to proxy) followed by:
// int: markID
// boolean: restore
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.ENDMARK_VALUE);
connection.pushInt(markID);
connection.pushBoolean(restore);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
// This is the expression processor controller used to transfer.
// This is the guy that maintains continuity of the transaction as
// it is passed from one connection to another.
protected IBeanProxy expressionProcesserController;
protected void pushBeginTransferThreadToProxy() throws ThrowableProxy {
// If the controller is not null, that means we had already requested a transfer
// but had not used it in this thread so there is no need to do anything. It
// will be handled when switching back to the other thread.
// If the connection is null, no need to do anything since there is no connection
// to transfer.
if (connection != null && expressionProcesserController == null) {
IREMExpressionConnection lclConnection = getConnection();
markInTransaction(lclConnection);
try {
workerValue.set();
lclConnection.transferExpression(getREMExpressionID(), workerValue);
expressionProcesserController = getREMBeanProxyFactory().getBeanProxy(workerValue);
getREMRegistry().returnConnection(lclConnection);
this.connection = null;
} catch (CommandException e) {
ProxyPlugin.getPlugin().getLogger().log(e);
if (!e.isRecoverable()) {
lclConnection.close();
throwIllegalStateException(COMMAND_EXCEPTION_MSG);
}
} finally {
markEndTransaction(lclConnection);
}
}
}
protected void pushTransferThreadToProxy() {
// Don't need to do anything. The next time we need to push data across, we will get a connection and the getConnection()
// will hook up the expression processor controller for us. This way if nothing happens in this thread then we won't
// waste communication time on it.
}
private static class SubexpressionBegin extends PendingTransaction {
public int subexpressionNumber;
public SubexpressionBegin(int subexpressionNumber) {
this.subexpressionNumber = subexpressionNumber;
}
public void pushTransaction(REMExpression remExpression) {
IREMExpressionConnection connection = remExpression.getConnection();
try {
// Format of push to subexpression begin proxy command is:
// PushExpressionCommand(push subexpression begin proxy to proxy) followed by:
// int: subexpression id
connection.pushExpressionCommand(remExpression.getREMExpressionID(), (byte)InternalExpressionTypes.SUBEXPRESSION_BEGIN_EXPRESSION_VALUE);
connection.pushInt(subexpressionNumber);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
remExpression.markInvalid(e.getLocalizedMessage());
remExpression.throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
}
protected void pushSubexpressionBeginToProxy(int subexpressionNumber) {
addPendingTransaction(new SubexpressionBegin(subexpressionNumber));
}
protected void pushSubexpressionEndToProxy(int subexpressionNumber) {
// See if the top pending transactions is SubexpressionBegin(subexpressionNumber). If it is then the SubexpressionBegin can be thrown away.
PendingTransaction topEntry = getPendingEntryFromTop(1);
if (topEntry instanceof SubexpressionBegin && ((SubexpressionBegin) topEntry).subexpressionNumber == subexpressionNumber) {
popPendingEntry(1);
return;
}
processPendingTransactions();
IREMExpressionConnection connection = getConnection();
try {
// Format of push to block end proxy command is:
// PushExpressionCommand(push subexpression end proxy to proxy) followed by:
// int: subexpression id
connection.pushExpressionCommand(getREMExpressionID(), (byte)InternalExpressionTypes.SUBEXPRESSION_END_EXPRESSION_VALUE);
connection.pushInt(subexpressionNumber);
} catch (IOException e) {
connection.close();
ProxyPlugin.getPlugin().getLogger().log(e);
markInvalid(e.getLocalizedMessage());
throwIllegalStateException(IO_EXCEPTION_MSG);
}
}
}