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