| /******************************************************************************* |
| * 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.vm.remote; |
| |
| import java.io.DataInputStream; |
| import java.io.IOException; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import org.eclipse.jem.internal.proxy.common.*; |
| import org.eclipse.jem.internal.proxy.common.remote.Commands; |
| import org.eclipse.jem.internal.proxy.common.remote.ExpressionCommands; |
| import org.eclipse.jem.internal.proxy.initParser.tree.*; |
| |
| |
| /** |
| * This processes the commands for expression processing and sends them over |
| * to the common expression processer. |
| * |
| * This will be instantiated on the start of an expression. And then |
| * each expression request from the IDE will be sent into here. The |
| * reason this guy doesn't hold onto the connection and process the |
| * entire expression is because we need to return to the connection |
| * handler to keep the connection live (there is timeouts and stuff |
| * in there that we don't want to duplicate here). |
| * <p> |
| * If there are any expression processing errors (versus hard io errors) we |
| * will save up the error but don't do any more processing other than to make |
| * sure we read the complete subcommand. This is so that the inputstream is left |
| * in a valid state without standed data. |
| * <p> |
| * The at the sync point (either get value or sync subcommand) we will send back |
| * the error. |
| * |
| * @since 1.0.0 |
| */ |
| public class ExpressionProcesserController { |
| |
| |
| protected final RemoteVMServerThread server; |
| protected final ConnectionHandler connHandler; |
| protected final ExpressionProcesser exp; |
| protected Commands.ValueObject workerValue = new Commands.ValueObject(); // A worker value object so we don't need to keep creating them and releasing them. |
| private ClassLoader classLoader; |
| |
| /** |
| * Create with a default expression processer and use default flag for trace. |
| * @param server |
| * |
| * @since 1.0.0 |
| */ |
| public ExpressionProcesserController(RemoteVMServerThread server, ConnectionHandler connHandler) { |
| this(server, connHandler, new ExpressionProcesser(Boolean.getBoolean(ExpressionCommands.EXPRESSIONTRACE), Long.getLong(ExpressionCommands.EXPRESSIONTRACE_TIMER_THRESHOLD, -1L).longValue())); |
| } |
| |
| /** |
| * Construct with a default expression processer. |
| * @param server |
| * @param connHandler |
| * @param trace |
| * |
| * @since 1.1.0 |
| */ |
| public ExpressionProcesserController(RemoteVMServerThread server, ConnectionHandler connHandler, boolean trace) { |
| this(server, connHandler, new ExpressionProcesser(trace, Long.getLong(ExpressionCommands.EXPRESSIONTRACE_TIMER_THRESHOLD, -1L).longValue())); |
| } |
| |
| /** |
| * Create from a subclass with a given expression processer. |
| * |
| * @param server |
| * @param exp |
| * |
| * @since 1.0.0 |
| */ |
| protected ExpressionProcesserController(RemoteVMServerThread server, ConnectionHandler connHandler, ExpressionProcesser exp) { |
| this.server = server; |
| this.connHandler = connHandler; |
| this.exp = exp; |
| } |
| |
| /** |
| * Set the class loader to use for finding classes. If never set, or if <code>null</code>, then |
| * <code>Class.forName</code> will be used. |
| * |
| * @param classLoader |
| * |
| * @since 1.0.0 |
| */ |
| public void setClassLoader(ClassLoader classLoader) { |
| this.classLoader = classLoader; |
| } |
| |
| /* |
| * Array of primitive type names. Used to look up primtive types in primitive types array. |
| * |
| * @since 1.0.0 |
| */ |
| private static final List PRIMITIVE_NAMES = Arrays.asList(new String[] {"byte", "char", "short", "int", "long", "float", "double"}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ |
| private static final Class[] PRIMITIVE_TYPES = new Class[] {Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE}; |
| /** |
| * Load the class given the name. If not found, return null. |
| * |
| * @param className |
| * @return |
| * |
| * @since 1.0.0 |
| */ |
| protected Class loadClass(String className) throws ClassNotFoundException { |
| if (className == null) |
| return null; |
| else if (className.endsWith("[]")) { //$NON-NLS-1$ |
| // We have an array request instead. This is trickier. |
| return loadClass(MapTypes.getJNIFormatName(className)); |
| } else { |
| int primIndex = PRIMITIVE_NAMES.indexOf(className); |
| if (primIndex >= 0) |
| return PRIMITIVE_TYPES[primIndex]; |
| else if (classLoader == null) { |
| return Class.forName(className); |
| } else { |
| return classLoader.loadClass(className); |
| } |
| } |
| } |
| |
| /** |
| * Now process the input stream. If either throws occurs, this is a hard error and we must terminate |
| * the entire connection. The input stream is in an unknown state. |
| * |
| * @param in The input stream to get the data for the current sub-command. |
| * |
| * @throws CommandException |
| * @throws IOException |
| * @since 1.0.0 |
| */ |
| public void process(DataInputStream in) throws CommandException, IOException { |
| // In the following subcommand processing, we always read the entire subcommand from the stream. |
| // This is so that any errors during processing will not mess up the stream with unread data. |
| // |
| // Then we check if an error has occurred in the past. If it has, we simply break. This is because |
| // once an error occurred we don't want to continue wasting time evaluating, however we need to make |
| // sure that the stream is read completely so that we don't have a corrupted input stream. That way |
| // when all is done we can return the error and still have a valid connection socket. |
| byte subcommand = in.readByte(); |
| try { |
| switch (subcommand) { |
| case InternalExpressionTypes.PUSH_TO_PROXY_EXPRESSION_VALUE: |
| // Getting a proxy push. The value is sent as valueObject, so use that to read it in. |
| Commands.readValue(in, workerValue); |
| Object value = connHandler.getInvokableObject(workerValue); |
| if (value == null) |
| exp.pushExpression(null, MethodHelper.NULL_TYPE); |
| else if (workerValue.isPrimitive()) |
| exp.pushExpression(value, workerValue.getPrimitiveType()); |
| else |
| exp.pushExpression(value, value.getClass()); |
| break; |
| |
| case InternalExpressionTypes.CAST_EXPRESSION_VALUE: |
| // Get a cast request. The type is sent as valueObject. |
| Commands.readValue(in, workerValue); |
| try { |
| Class classValue = getBeanTypeValue(workerValue); |
| exp.pushCast(classValue); |
| } catch (FailedProxyException e) { |
| exp.processException(e.getCause()); // Let the processor know we have a stopping error. |
| } |
| break; |
| |
| case InternalExpressionTypes.INSTANCEOF_EXPRESSION_VALUE: |
| // Get a instanceof request. The type is sent as valueObject. |
| Commands.readValue(in, workerValue); |
| try { |
| Class classValue = getBeanTypeValue(workerValue); |
| exp.pushInstanceof(classValue); |
| } catch (FailedProxyException e) { |
| exp.processException(e.getCause()); // Let the processor know we have a stopping error. |
| } |
| break; |
| |
| case InternalExpressionTypes.INFIX_EXPRESSION_VALUE: |
| // Get an infix request. The operator and operand type are sent as bytes. |
| byte infix_operator = in.readByte(); |
| byte infix_operandType = in.readByte(); |
| exp.pushInfix(InfixOperator.get(infix_operator), InternalInfixOperandType.get(infix_operandType)); |
| break; |
| |
| case InternalExpressionTypes.PREFIX_EXPRESSION_VALUE: |
| // Get a prefix request. The operator is sent as byte. |
| byte prefix_operandType = in.readByte(); |
| exp.pushPrefix(PrefixOperator.get(prefix_operandType)); |
| break; |
| |
| case InternalExpressionTypes.ARRAY_ACCESS_EXPRESSION_VALUE: |
| // Get an array access request. The index cound is sent as int. |
| int arrayAccess_Indexcount = in.readInt(); |
| exp.pushArrayAccess(arrayAccess_Indexcount); |
| break; |
| |
| case InternalExpressionTypes.ARRAY_CREATION_EXPRESSION_VALUE: |
| // Get an array creation request. The type is sent as valueObject, followed by int dimension count. |
| Commands.readValue(in, workerValue); |
| int arrayCreation_dimCount = in.readInt(); |
| try { |
| Class classValue = getBeanTypeValue(workerValue); |
| exp.pushArrayCreation(classValue, arrayCreation_dimCount); |
| } catch (FailedProxyException e) { |
| exp.processException(e.getCause()); // Let the processor know we have a stopping error. |
| } |
| break; |
| |
| case InternalExpressionTypes.ARRAY_INITIALIZER_EXPRESSION_VALUE: |
| // Get an array initializer request. The type is sent as valueObject, followed by int expression count. |
| Commands.readValue(in, workerValue); |
| int stripCount = in.readInt(); |
| int arrayInitializer_expressionCount = in.readInt(); |
| try { |
| Class classValue = getBeanTypeValue(workerValue); |
| exp.pushArrayInitializer(classValue, stripCount, arrayInitializer_expressionCount); |
| } catch (FailedProxyException e) { |
| exp.processException(e.getCause()); // Let the processor know we have a stopping error. |
| } |
| break; |
| |
| case InternalExpressionTypes.CLASS_INSTANCE_CREATION_EXPRESSION_VALUE: |
| // Get a class instance creation request. The type is sent as valueObject, followed by int argument count. |
| Commands.readValue(in, workerValue); |
| int newInstance_argCount = in.readInt(); |
| try { |
| Class classValue = getBeanTypeValue(workerValue); |
| exp.pushClassInstanceCreation(classValue, newInstance_argCount); |
| } catch (FailedProxyException e) { |
| exp.processException(e.getCause()); // Let the processor know we have a stopping error. |
| } |
| break; |
| |
| case InternalExpressionTypes.TYPERECEIVER_EXPRESSION_VALUE: |
| // Get a type receiver request. The type is sent as valueObject. |
| Commands.readValue(in, workerValue); |
| try { |
| Class classValue = getBeanTypeValue(workerValue); |
| exp.pushExpression(classValue, classValue); |
| } catch (FailedProxyException e) { |
| exp.processException(e.getCause()); // Let the processor know we have a stopping error. |
| } |
| break; |
| |
| case InternalExpressionTypes.FIELD_ACCESS_EXPRESSION_VALUE: |
| // Get a field access request. Command.ValueObject, followed by hasReceiver as boolean. |
| Commands.readValue(in, workerValue); |
| boolean has_fieldAccess_receiver = in.readBoolean(); |
| try { |
| Object fieldAccess = getFieldValue(workerValue); |
| exp.pushFieldAccess(fieldAccess, workerValue.getType() == Commands.STRING, has_fieldAccess_receiver); |
| } catch (ClassCastException e) { |
| exp.processException(e); // Let the processor know we have a stopping error. |
| } catch (FailedProxyException e) { |
| exp.processException(e.getCause()); // Let the processor know we have a stopping error. |
| } |
| break; |
| |
| case InternalExpressionTypes.METHOD_EXPRESSION_VALUE: |
| // Get a method invocation request. Sent as Commands.ValueObject, followed by hasReceiver as boolean., and argCount as int. |
| Commands.readValue(in, workerValue); |
| boolean has_method_receiver = in.readBoolean(); |
| int method_argCount = in.readInt(); |
| try { |
| Object method = getMethodValue(workerValue); |
| exp.pushMethodInvocation(method, workerValue.getType() == Commands.STRING, has_method_receiver, method_argCount); |
| } catch (FailedProxyException e) { |
| exp.processException(e.getCause()); // Let the processor know we have a stopping error. |
| } |
| break; |
| |
| case InternalExpressionTypes.CONDITIONAL_EXPRESSION_VALUE: |
| // Get a conditional expression request. The expression type (ie. condition/true/false) is sent as a byte |
| exp.pushConditional(InternalConditionalOperandType.get(in.readByte())); |
| break; |
| |
| case InternalExpressionTypes.ASSIGNMENT_PROXY_EXPRESSION_VALUE: |
| // Get an assignment expression request. The proxy id is sent as an int. |
| int proxyid = in.readInt(); |
| exp.pushAssignment(new RemoteExpressionProxy(proxyid)); |
| break; |
| |
| case InternalExpressionTypes.ASSIGNMENT_EXPRESSION_VALUE: |
| // Get an assignment expression request. Nothing else to read from stream. |
| exp.pushAssignment(); |
| break; |
| |
| case InternalExpressionTypes.PUSH_TO_EXPRESSION_PROXY_EXPRESSION_VALUE: |
| // Get a push expression proxy expression. The proxy id is sent as an int. |
| // First test if a possible FailedExpressionProxy because we could of been pushing |
| // a failed reflection proxy. |
| proxyid = in.readInt(); |
| try { |
| exp.getExpressionProxy(proxyid, new Object[] {null, null}); |
| } catch (NoExpressionValueException e1) { |
| if (e1.getProxy() != null) { |
| FailedRemoteExpressionProxy failure = (FailedRemoteExpressionProxy) e1.getProxy(); |
| exp.processException((Throwable) failure.getValue()); |
| break; // Don't go on, we processed it. A standard no expression value should be passed on and let following code handle it. |
| } |
| } |
| exp.pushExpressionProxy(proxyid); |
| break; |
| |
| case InternalExpressionTypes.BLOCK_BEGIN_EXPRESSION_VALUE: |
| // Get a begin block proxy expression. The block id is sent as an int. |
| exp.pushBlockBegin(in.readInt()); |
| break; |
| |
| case InternalExpressionTypes.BLOCK_BREAK_EXPRESSION_VALUE: |
| // Get a break block proxy expression. The block id is sent as an int. |
| exp.pushBlockBreak(in.readInt()); |
| break; |
| |
| case InternalExpressionTypes.BLOCK_END_EXPRESSION_VALUE: |
| // Get a end block proxy expression. The block id is sent as an int. |
| exp.pushBlockEnd(in.readInt()); |
| break; |
| |
| case InternalExpressionTypes.TRY_BEGIN_EXPRESSION_VALUE: |
| // Get a try begin proxy expression. The try id is sent as an int. |
| exp.pushTryBegin(in.readInt()); |
| break; |
| |
| case InternalExpressionTypes.TRY_CATCH_EXPRESSION_VALUE: |
| int tryNumber = in.readInt(); |
| Commands.readValue(in, workerValue); |
| proxyid = in.readInt(); |
| try { |
| Class classValue = getBeanTypeValue(workerValue); |
| exp.pushTryCatchClause(tryNumber, classValue, proxyid != -1 ? new RemoteExpressionProxy(proxyid) : null); |
| } catch (FailedProxyException e) { |
| exp.processException(e.getCause()); // Let the processor know we have a stopping error. |
| } |
| break; |
| |
| case InternalExpressionTypes.TRY_FINALLY_EXPRESSION_VALUE: |
| // Get a try finally proxy expression. The try id is sent as an int. |
| exp.pushTryFinallyClause(in.readInt()); |
| break; |
| |
| case InternalExpressionTypes.TRY_END_EXPRESSION_VALUE: |
| // Get a try end proxy expression. The try id is sent as an int. |
| exp.pushTryEnd(in.readInt()); |
| break; |
| |
| case InternalExpressionTypes.THROW_EXPRESSION_VALUE: |
| exp.pushThrowException(); |
| break; |
| |
| case InternalExpressionTypes.RETHROW_EXPRESSION_VALUE: |
| // Get a rethrow proxy expression. The try id is sent as an int. |
| exp.pushTryRethrow(in.readInt()); |
| break; |
| |
| case InternalExpressionTypes.PUSH_BEANTYPE_EXPRESSIONPROXY_EXPRESSION_VALUE: |
| // Get the beantype expression proxy and resolve it. |
| proxyid = in.readInt(); |
| String typeName = Commands.readStringData(in); |
| try { |
| Class classValue = loadClass(typeName); |
| RemoteExpressionProxy rep = new RemoteExpressionProxy(proxyid); |
| rep.setProxy(classValue, Class.class); |
| exp.allocateExpressionProxy(rep); |
| } catch (ClassNotFoundException e) { |
| FailedRemoteExpressionProxy rep = new FailedRemoteExpressionProxy(proxyid); |
| rep.setProxy(e, e.getClass()); |
| exp.allocateExpressionProxy(rep); |
| } catch (LinkageError e) { |
| FailedRemoteExpressionProxy rep = new FailedRemoteExpressionProxy(proxyid); |
| rep.setProxy(e, e.getClass()); |
| exp.allocateExpressionProxy(rep); |
| } |
| break; |
| |
| case InternalExpressionTypes.PUSH_METHOD_EXPRESSIONPROXY_EXPRESSION_VALUE: |
| // Get the Method expression proxy and resolve it. |
| // Comes over as: |
| // int for proxy id for the method |
| // beanTypeValue for declaring class (either beantype or expression proxy) |
| // string for method name |
| // int for arg count |
| // beanTypeValue(s) for arg types (as many as arg count). |
| proxyid = in.readInt(); |
| Commands.ValueObject decClassValue = Commands.readValue(in, new Commands.ValueObject()); |
| String methodName = Commands.readStringData(in); |
| int argCount = in.readInt(); |
| Commands.ValueObject[] args = null; |
| if (argCount > 0) { |
| args = new Commands.ValueObject[argCount]; |
| for (int i = 0; i < argCount; i++) { |
| args[i] = Commands.readValue(in, new Commands.ValueObject()); |
| } |
| } |
| Class decClass = null; |
| Class[] argClasses = null; |
| try { |
| decClass = getBeanTypeValue(decClassValue); |
| argClasses = null; |
| if (argCount>0) { |
| argClasses = new Class[argCount]; |
| for (int i = 0; i < argCount; i++) { |
| argClasses[i] = getBeanTypeValue(args[i]); |
| } |
| } |
| // Now get the method itself. |
| Method m = decClass.getMethod(methodName, argClasses); |
| RemoteExpressionProxy rep = new RemoteExpressionProxy(proxyid); |
| rep.setProxy(m, Method.class); |
| exp.allocateExpressionProxy(rep); |
| } catch (FailedProxyException e) { |
| FailedRemoteExpressionProxy rep = new FailedRemoteExpressionProxy(proxyid); |
| rep.setProxy(e.getCause(), e.getCause().getClass()); |
| exp.allocateExpressionProxy(rep); |
| } catch (NoSuchMethodException e) { |
| // The default trace doesn't show what method was being searched for, so recreate with that. |
| StringBuffer s = new StringBuffer(); |
| s.append(decClass.getName()); |
| s.append('.'); |
| s.append(methodName); |
| s.append('('); |
| if (argClasses != null) { |
| for (int i = 0; i < argClasses.length; i++) { |
| if (i > 0) |
| s.append(','); |
| s.append(argClasses[i].getName()); |
| } |
| } |
| s.append(')'); |
| NoSuchMethodException ne = new NoSuchMethodException(s.toString()); |
| ne.setStackTrace(e.getStackTrace()); |
| FailedRemoteExpressionProxy rep = new FailedRemoteExpressionProxy(proxyid); |
| rep.setProxy(ne, ne.getClass()); |
| exp.allocateExpressionProxy(rep); |
| } |
| break; |
| |
| case InternalExpressionTypes.PUSH_FIELD_EXPRESSIONPROXY_EXPRESSION_VALUE: |
| // Get the Filed expression proxy and resolve it. |
| // Comes over as: |
| // int for proxy id for the field |
| // beanTypeValue for declaring class (either beantype or expression proxy) |
| // string for field name |
| proxyid = in.readInt(); |
| decClassValue = Commands.readValue(in, new Commands.ValueObject()); |
| String fieldName = Commands.readStringData(in); |
| try { |
| decClass = getBeanTypeValue(decClassValue); |
| // Now get the field itself. |
| Field f = decClass.getField(fieldName); |
| RemoteExpressionProxy rep = new RemoteExpressionProxy(proxyid); |
| rep.setProxy(f, Method.class); |
| exp.allocateExpressionProxy(rep); |
| } catch (FailedProxyException e) { |
| FailedRemoteExpressionProxy rep = new FailedRemoteExpressionProxy(proxyid); |
| rep.setProxy(e.getCause(), e.getCause().getClass()); |
| exp.allocateExpressionProxy(rep); |
| } catch (NoSuchFieldException e) { |
| FailedRemoteExpressionProxy rep = new FailedRemoteExpressionProxy(proxyid); |
| rep.setProxy(e, e.getClass()); |
| exp.allocateExpressionProxy(rep); |
| } |
| break; |
| |
| case InternalExpressionTypes.IF_TEST_EXPRESSION_VALUE: |
| // Get a if test expression request. |
| exp.pushIfElse(); |
| break; |
| |
| case InternalExpressionTypes.IF_ELSE_EXPRESSION_VALUE: |
| // Get a if/else expression clause request. The clause type (ie. true/false) is sent as a byte |
| exp.pushIfElse(InternalIfElseOperandType.get(in.readByte())); |
| break; |
| |
| case InternalExpressionTypes.NEW_INSTANCE_VALUE: |
| // Get a new instance from string. |
| String initString = Commands.readStringData(in); |
| workerValue = Commands.readValue(in, new Commands.ValueObject()); |
| try { |
| Class classValue = getBeanTypeValue(workerValue); |
| exp.pushNewInstanceFromString(initString, classValue, classLoader); |
| } catch (FailedProxyException e) { |
| exp.processException(e.getCause()); // Let the processor know we have a stopping error. |
| } |
| break; |
| |
| case InternalExpressionTypes.MARK_VALUE: |
| // Do a mark. |
| int markID = in.readInt(); |
| exp.pushMark(markID); |
| break; |
| |
| case InternalExpressionTypes.ENDMARK_VALUE: |
| // Do an end mark. |
| markID = in.readInt(); |
| boolean restore = in.readBoolean(); |
| exp.pushEndmark(markID, restore); |
| break; |
| |
| case InternalExpressionTypes.SUBEXPRESSION_BEGIN_EXPRESSION_VALUE: |
| // Get a begin subexpression proxy expression. The subexpression id is sent as an int. |
| exp.pushSubexpressionBegin(in.readInt()); |
| break; |
| |
| case InternalExpressionTypes.SUBEXPRESSION_END_EXPRESSION_VALUE: |
| // Get a end subexpression proxy expression. The subexpression id is sent as an int. |
| exp.pushSubexpressionEnd(in.readInt()); |
| break; |
| |
| } |
| |
| } catch (RuntimeException e) { |
| exp.processException(e); |
| } |
| |
| workerValue.set(); // Clear it out so nothing being held onto. |
| } |
| |
| /** |
| * This is an exception that is thrown from the getBeanType, field, method (reflect type stuff) |
| * that wrappers the real throwable that occurred during the previous reflection. This is |
| * because reflection is done out of sequence with the use of the reflect value. So we need |
| * to store the reflection exception in this exception and then store this exception in |
| * a {@link FailedRemoteExpressionProxy}. This will then be picked up when trying to be |
| * used and it will get the true exception out of the {@link Throwable#getCause()}. |
| * |
| * @since 1.1.0 |
| */ |
| private static class FailedProxyException extends Exception { |
| /** |
| * Comment for <code>serialVersionUID</code> |
| * |
| * @since 1.1.0 |
| */ |
| private static final long serialVersionUID = 2872325672166348923L; |
| |
| public FailedProxyException(Throwable realThrowable) { |
| super(realThrowable); |
| } |
| } |
| |
| /** |
| * Get the beantype (class) out of the value object sent in. It can handle the beantype sent or |
| * as an expression proxy to a beantype expression proxy. |
| * |
| * @param value |
| * @return |
| * @throws FailedProxyException Wrappers the real throwable that caused the bean type to not be found. |
| * |
| * @since 1.1.0 |
| */ |
| protected Class getBeanTypeValue(Commands.ValueObject value) throws FailedProxyException { |
| Object beantype = connHandler.getInvokableObject(value); |
| // It is either a type directly or is an expression proxy. |
| if (value.type == Commands.INT) { |
| // It is an expression proxy request. |
| Object[] expvalue = new Object[2]; |
| try { |
| exp.getExpressionProxy(((Integer) beantype).intValue(), expvalue); |
| beantype = expvalue[0]; |
| } catch (NoExpressionValueException e) { |
| // See if there is a failed proxy. |
| if (e.getProxy() != null) { |
| FailedRemoteExpressionProxy failure = (FailedRemoteExpressionProxy) e.getProxy(); |
| throw new FailedProxyException((Throwable) failure.getValue()); |
| } else |
| throw new FailedProxyException(new ClassNotFoundException()); // This shouldn't of occurred. |
| } |
| } |
| return (Class) beantype; |
| } |
| |
| /** |
| * Get the method out of the value object sent in. It can handle the method sent or |
| * as an expression proxy to a method expression proxy. |
| * @param value |
| * @return method if a method or string if a string or get the method if an expression proxy. |
| * @throws FailedProxyException Wrappers the real Throwable that caused the method to not be found. |
| * |
| * @since 1.1.0 |
| */ |
| protected Object getMethodValue(Commands.ValueObject value) throws FailedProxyException { |
| Object method = connHandler.getInvokableObject(value); |
| // It is either a method directly or is an expression proxy. |
| if (value.type == Commands.INT) { |
| // It is an expression proxy request. |
| Object[] expvalue = new Object[2]; |
| try { |
| exp.getExpressionProxy(((Integer) method).intValue(), expvalue); |
| method = expvalue[0]; |
| } catch (NoExpressionValueException e) { |
| // See if there is a failed proxy. |
| if (e.getProxy() != null) { |
| FailedRemoteExpressionProxy failure = (FailedRemoteExpressionProxy) e.getProxy(); |
| throw new FailedProxyException((Throwable) failure.getValue()); |
| } else |
| throw new FailedProxyException(new NoSuchMethodException()); // This shouldn't of occurred. |
| } |
| } |
| return method; |
| } |
| |
| /** |
| * Get the field out of the value object sent in. It can handle the field sent or |
| * as an expression proxy to a field expression proxy. |
| * @param value |
| * @return field if a field or string if a string or get the field if an expression proxy. |
| * @throws FailedProxyException Wrappers the real throwable that caused the field to not be found. |
| * |
| * @since 1.1.0 |
| */ |
| protected Object getFieldValue(Commands.ValueObject value) throws FailedProxyException { |
| Object field = connHandler.getInvokableObject(value); |
| // It is either a field directly or is an expression proxy. |
| if (value.type == Commands.INT) { |
| // It is an expression proxy request. |
| Object[] expvalue = new Object[2]; |
| try { |
| exp.getExpressionProxy(((Integer) field).intValue(), expvalue); |
| field = expvalue[0]; |
| } catch (NoExpressionValueException e) { |
| // See if there is a failed proxy. |
| if (e.getProxy() != null) { |
| FailedRemoteExpressionProxy failure = (FailedRemoteExpressionProxy) e.getProxy(); |
| throw new FailedProxyException((Throwable) failure.getValue()); |
| } else |
| throw new FailedProxyException(new NoSuchFieldException()); // This shouldn't of occurred. |
| |
| } |
| } |
| return field; |
| } |
| |
| /** |
| * Pull the Expression Proxy value into the result object. |
| * @param proxyID |
| * @param result |
| * @return <code>true</code> if value could be returned, <code>false</code> if it was no expression value assigned. |
| * |
| * @since 1.1.0 |
| */ |
| public boolean pullExpressionProxyValue(int proxyID, Object[] result) { |
| try { |
| exp.pullExpressionProxyValue(proxyID, result); |
| return true; |
| } catch (NoExpressionValueException e) { |
| } |
| return false; |
| } |
| |
| private static class RemoteExpressionProxy implements InternalExpressionProxy { |
| |
| |
| private final int proxyID; |
| private Object value; |
| private Class type; |
| private boolean set; |
| |
| public RemoteExpressionProxy(int proxyID) { |
| this.proxyID = proxyID; |
| |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.initParser.tree.InternalExpressionProxy#getProxyID() |
| */ |
| public int getProxyID() { |
| return proxyID; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.initParser.tree.InternalExpressionProxy#getType() |
| */ |
| public Class getType() { |
| return type; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.initParser.tree.InternalExpressionProxy#getValue() |
| */ |
| public Object getValue() { |
| return value; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.initParser.tree.InternalExpressionProxy#isSet() |
| */ |
| public boolean isSet() { |
| return set; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.initParser.tree.InternalExpressionProxy#setProxy(java.lang.Object, java.lang.Class) |
| */ |
| public void setProxy(Object value, Class type) { |
| this.value = value; |
| this.type = type; |
| set = true; |
| } |
| } |
| |
| /** |
| * Used for the java.lang.reflect things (class, field, method) to indicate |
| * why they aren't found. |
| * <p> |
| * The exception will be placed into value, BUT this should never be sent |
| * back to the caller. It is intended only as a place-holder for subsequent |
| * usage. Use the {@link RemoteExpressionProxy#isFailedExpression()} method |
| * to determine if it is a failed one. |
| * <p> |
| * This is used because the reflect calls are done out of sequence from where |
| * they are used and so if there was an error, the error is reported in the |
| * wrong place. |
| * |
| * @since 1.1.0 |
| */ |
| private static class FailedRemoteExpressionProxy extends RemoteExpressionProxy { |
| |
| public FailedRemoteExpressionProxy(int proxyID) { |
| super(proxyID); |
| } |
| |
| public boolean isSet() { |
| return false; // This should never be considered to be set. It is holder of info only. |
| } |
| |
| } |
| |
| |
| /** |
| * Pull the value. |
| * |
| * @return r[0] is the value, r[1] is the type of the value. |
| * @throws NoExpressionValueException |
| * |
| * @since 1.0.0 |
| */ |
| public Object[] pullValue() throws NoExpressionValueException { |
| Object[] result = new Object[2]; |
| exp.pullValue(result); |
| return result; |
| } |
| |
| /** |
| * Close out things. |
| * |
| * @since 1.0.0 |
| */ |
| public void close() { |
| exp.close(); |
| } |
| |
| /** |
| * Get the throwable error. |
| * @return |
| * |
| * @since 1.1.0 |
| */ |
| public Throwable getErrorThrowable() { |
| return exp.getErrorThrowable(); |
| } |
| |
| /** |
| * Return whether there were no errors or not. |
| * @return |
| * |
| * @since 1.1.0 |
| */ |
| public boolean noErrors() { |
| return exp.noErrors(); |
| } |
| |
| /** |
| * Return whether there is a no expression value exception or not. |
| * @return |
| * |
| * @since 1.1.0 |
| */ |
| public boolean isNoExpressionValue() { |
| return exp.isNoExpressionValue(); |
| } |
| |
| } |