/******************************************************************************* * Copyright (c) 2004, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /* * $RCSfile: IDEExpression.java,v $ $Revision: 1.12 $ $Date: 2005/08/24 20:39:06 $ */ package org.eclipse.jem.internal.proxy.ide; import java.util.*; import org.eclipse.core.runtime.Platform; import org.eclipse.jem.internal.proxy.common.MethodHelper; import org.eclipse.jem.internal.proxy.core.*; import org.eclipse.jem.internal.proxy.core.ExpressionProxy.ProxyEvent; import org.eclipse.jem.internal.proxy.initParser.tree.*; /** * IDE expression processing. * * @since 1.0.0 */ public class IDEExpression extends Expression { private final IDEStandardBeanTypeProxyFactory beantypefactory; protected final ExpressionProcesser eproc; { boolean useTracing = !isTraceSet() ? "true".equalsIgnoreCase(Platform.getDebugOption(ProxyPlugin.getPlugin().getBundle().getSymbolicName() + ProxyLaunchSupport.EXPRESSION_TRACING)) : //$NON-NLS-1$ isTrace(); long threshold = Long.getLong(Platform.getDebugOption(ProxyPlugin.getPlugin().getBundle().getSymbolicName() + ProxyLaunchSupport.EXPRESSION_TRACEING_TIMER_THRESHOLD), -1L).longValue(); eproc = new ExpressionProcesser(useTracing, threshold); } private void processExpressionError() throws ThrowableProxy, NoExpressionValueException { if (!eproc.noErrors()) if (eproc.isNoExpressionValue()) throw (NoExpressionValueException) eproc.getErrorThrowable(); else { Throwable t = eproc.getErrorThrowable(); if (t instanceof ThrowableProxy) throw (ThrowableProxy) t; else throw new IDEThrowableProxy(eproc.getErrorThrowable(), beantypefactory.getBeanTypeProxy(t.getClass())); } } /** * Create the IDEExpression * * @param registry * * @since 1.0.0 */ public IDEExpression(ProxyFactoryRegistry registry) { super(registry); beantypefactory = (IDEStandardBeanTypeProxyFactory) registry.getBeanTypeProxyFactory(); } protected final IDEProxyFactoryRegistry getIDERegistry() { return (IDEProxyFactoryRegistry) registry; } protected final IDEStandardBeanTypeProxyFactory getIDEBeanTypeFactory() { return beantypefactory; } /* * (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) eproc.pushExpression(null, MethodHelper.NULL_TYPE); else if (proxy.isBeanProxy()) eproc.pushExpression(((IDEBeanProxy) proxy).getBean(), ((IDEBeanTypeProxy) ((IBeanProxy) proxy).getTypeProxy()).getTypeClass()); else eproc.pushExpressionProxy(((ExpressionProxy) proxy).getProxyID()); } /* * (non-Javadoc) * * @see org.eclipse.jem.internal.proxy.core.Expression#closeProxy() */ protected void closeProxy() { methodExpressionProxies = fieldExpressionProxies = null; eproc.close(); } /* * (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 { processExtensionProxies(proxycount, expressionProxies); processExpressionError(); Object result[] = new Object[2]; eproc.pullValue(result); IBeanProxy resultProxy = getIDERegistry().getBeanProxy((Class) result[1], result[0]); return resultProxy; } private void processExtensionProxies(int proxycount, List expressionProxies) { if (proxycount > 0) { int len = expressionProxies.size(); Object[] proxyResolution = new Object[2]; for (int i = 0; i < len; i++) { ExpressionProxy ep = (ExpressionProxy) expressionProxies.get(i); if (ep != null) { try { eproc.pullExpressionProxyValue(ep.getProxyID(), proxyResolution); if (proxyResolution[1] != Void.TYPE) fireProxyResolved(ep, getIDERegistry().getBeanProxy((Class) proxyResolution[1], proxyResolution[0])); else fireProxyVoid(ep); } catch (NoExpressionValueException e) { fireProxyNotResolved(ep); } } } } } /* * (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushCastToProxy(org.eclipse.jem.internal.proxy.core.IProxyBeanType) */ protected void pushCastToProxy(IProxyBeanType type) { try { eproc.pushCast(getIDEBeanTypeProxy(type).getTypeClass()); } catch (ThrowableProxy e) { eproc.processException(e); } } /* * (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushInstanceofToProxy(org.eclipse.jem.internal.proxy.core.IProxyBeanType) */ protected void pushInstanceofToProxy(IProxyBeanType type) { try { eproc.pushInstanceof(getIDEBeanTypeProxy(type).getTypeClass()); } catch (ThrowableProxy e) { eproc.processException(e); } } /** * Get the BeanType proxy and test if valid. Throw ThrowableProxy if not valid. * * @param type * @return * @throws ThrowableProxy * * @since 1.0.0 */ protected IDEBeanTypeProxy getIDEBeanTypeProxy(IProxyBeanType type) throws ThrowableProxy { IDEBeanTypeProxy typeProxy; if (type.isExpressionProxy()) { // It should already be resolved at this point. typeProxy = ((IDEBeanTypeExpressionProxy) type).getBeanTypeProxy(); } else typeProxy = (IDEBeanTypeProxy) type; if (!typeProxy.isValid()) { throw new IDEThrowableProxy( new Exception(typeProxy.getInitializationError()), getIDEBeanTypeFactory().getBeanTypeProxy(Exception.class)); } else return typeProxy; } /** * Get the BeanType proxy and test if valid. Throw ThrowableProxy if not valid. * @param type * @return * @throws ThrowableProxy * * @since 1.1.0 */ protected IDEBeanTypeProxy getIDEBeanTypeProxy(String type) throws ThrowableProxy { return (IDEBeanTypeProxy) registry.getBeanTypeProxyFactory().getBeanTypeProxy(type); } /* * (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushPrefixToProxy(org.eclipse.jem.internal.proxy.initParser.tree.PrefixOperator) */ protected void pushPrefixToProxy(PrefixOperator operator) { eproc.pushPrefix(operator); } /* * (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushInfixToProxy(org.eclipse.jem.internal.proxy.initParser.tree.InfixOperator, org.eclipse.jem.internal.proxy.initParser.tree.InternalInfixOperandType) */ protected void pushInfixToProxy(InfixOperator operator, InternalInfixOperandType operandType) { eproc.pushInfix(operator, operandType); } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushArrayAccessToProxy(int) */ protected void pushArrayAccessToProxy(int indexCount) { eproc.pushArrayAccess(indexCount); } /* * (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) { try { eproc.pushArrayCreation(getIDEBeanTypeProxy(type).getTypeClass(), dimensionCount); } catch (ThrowableProxy e) { eproc.processException(e); } } protected void pushArrayInitializerToProxy(IProxyBeanType type, int stripCount, int expressionCount) { try { eproc.pushArrayInitializer(getIDEBeanTypeProxy(type).getTypeClass(), stripCount, expressionCount); } catch (ThrowableProxy e) { eproc.processException(e); } } /* * (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) { try { eproc.pushClassInstanceCreation(getIDEBeanTypeProxy(type).getTypeClass(), argumentCount); } catch (ThrowableProxy e) { eproc.processException(e); } } /* * (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushTypeReceiverToProxy(org.eclipse.jem.internal.proxy.core.IProxyBeanType) */ protected void pushTypeReceiverToProxy(IProxyBeanType type) { try { Class c = getIDEBeanTypeProxy(type).getTypeClass(); eproc.pushExpression(c, c); // When as a receiver, the type is the same as the receiver. } catch (ThrowableProxy e) { eproc.processException(e); } catch (RuntimeException e) { eproc.processException(e); } } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushFieldAccessToProxy(java.lang.Object, boolean) */ protected void pushFieldAccessToProxy(Object field, boolean hasReceiver) { boolean isString = field instanceof String; try { eproc.pushFieldAccess(isString ? field : getIDEFieldProxy((IProxyField) field).getBean(), isString, hasReceiver); } catch (ThrowableProxy e) { eproc.processException(e); } } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushMethodInvocationToProxy(java.lang.Object, boolean, int) */ protected void pushMethodInvocationToProxy(Object method, boolean hasReceiver, int argCount) { boolean isString = method instanceof String; try { eproc.pushMethodInvocation(isString ? method : getIDEMethodProxy((IProxyMethod) method).getBean(), isString, hasReceiver, argCount); } catch (ThrowableProxy e) { eproc.processException(e); } } /* * (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushConditionalToProxy(org.eclipse.jem.internal.proxy.initParser.tree.InternalConditionalOperandType) */ protected void pushConditionalToProxy(InternalConditionalOperandType expressionType) { eproc.pushConditional(expressionType); } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushInvoke() */ protected void pushInvoke(int proxycount, List expressionProxies) throws ThrowableProxy, NoExpressionValueException { // In the IDE case do nothing. Nothing is pending. But still need to handle proxy resolution. processExtensionProxies(proxycount, expressionProxies); processExpressionError(); } /** * This is used as both an ExpressionProxy (i.e. IDE side) and the Expressions expression proxy result on the other side. * This makes it easier to just use same instance on both sides. * * @since 1.1.0 */ protected static class IDEExpressionProxy extends ExpressionProxy implements InternalExpressionProxy { protected IDEExpressionProxy(int proxyid, int proxyType, Expression expression) { super(proxyid, proxyType, expression); } private Object value; private Class type; private boolean set; /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.ExpressionProxy#dispose() */ protected void dispose() { super.dispose(); value = null; type = null; set = false; } /* (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#setProxy(java.lang.Object, java.lang.Class) */ public void setProxy(Object value, Class type) { this.value = value; this.type = type; set = true; } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.initParser.tree.InternalExpressionProxy#isSet() */ public boolean isSet() { return set; } } /** * The Expression proxy for IDE BeanTypes. * * @since 1.1.0 */ protected static class IDEBeanTypeExpressionProxy extends IDEExpressionProxy implements IBeanTypeExpressionProxy { private String typeName; private IDEBeanTypeProxy resolvedProxy; /** * @param proxyid * * @since 1.1.0 */ public IDEBeanTypeExpressionProxy(int proxyid, Expression expression) { super(proxyid, BEANTYPE_EXPRESSION_PROXY, expression); } /* * (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.IBeanTypeExpressionProxy#setTypeName(java.lang.String) */ public void setTypeName(String typeName) { this.typeName = typeName; } /* * (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.IProxyBeanType#getTypeName() */ 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$ } /** * Called by IDEExpression to resolve the beantype. * @param beantypeProxy * * @since 1.1.0 */ void setProxy(IDEBeanTypeProxy beantypeProxy) { this.resolvedProxy = beantypeProxy; setProxy(resolvedProxy.getTypeClass(), Class.class); } /** * Called by IDEExpression to get the resolved beantype proxy. * @return * * @since 1.1.0 */ IDEBeanTypeProxy getBeanTypeProxy() { return resolvedProxy; } /* * (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) { IProxyMethod method = ((IDEExpression) expression).getMethodExpressionProxy(this, methodName, parameterTypes); if (method == null) { // Need to go to the expression and create it. method = ((Expression) expression).createMethodExpressionProxy(this, methodName, parameterTypes); } return method; } /* (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) { return ((IDEMethodProxyFactory) expression.getRegistry().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) { IProxyField field = ((IDEExpression) expression).getFieldExpressionProxy(this, fieldName); if (field == null) { // Need to go to the expression and create it. field = ((Expression) expression).createFieldExpressionProxy(this, fieldName); } return field; } } /** * The Expression proxy for IDE BeanTypes. * * @since 1.1.0 */ protected static class IDEMethodExpressionProxy extends IDEExpressionProxy implements IProxyMethod { private String methodName; private IDEMethodProxy resolvedProxy; private ThrowableProxy errorThrowable; /** * @param proxyid * * @since 1.1.0 */ public IDEMethodExpressionProxy(int proxyid, Expression expression) { super(proxyid, METHOD_EXPRESSION_PROXY, expression); } /** * Set by IDEExpression with the method name. * @param methodName * * @since 1.1.0 */ void setMethodName(String methodName) { this.methodName = methodName; } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.ExpressionProxy#toString() */ public String toString() { return super.toString()+" - "+methodName; //$NON-NLS-1$ } /** * Called by IDEExpression to resolve the beantype. * @param methodProxy * * @since 1.1.0 */ void setProxy(IDEMethodProxy methodProxy) { this.resolvedProxy = methodProxy; setProxy(resolvedProxy.getBean(), Class.class); } /** * Called by IDEExpression to say there was error in creating the proxy. * @param errorThrowable * * @since 1.1.0 */ void setThrowable(ThrowableProxy errorThrowable) { this.errorThrowable = errorThrowable; } /** * Called by IDEExpression to get the resolved method proxy. * @return * @throws ThrowableProxy * * @since 1.1.0 */ IDEMethodProxy getMethodProxy() throws ThrowableProxy { if (errorThrowable != null) throw errorThrowable; return resolvedProxy; } } protected static class IDEFieldExpressionProxy extends IDEExpressionProxy implements IProxyField { private String fieldName; private IDEFieldProxy resolvedProxy; private ThrowableProxy errorThrowable; /** * @param proxyid * * @since 1.1.0 */ public IDEFieldExpressionProxy(int proxyid, Expression expression) { super(proxyid, FIELD_EXPRESSION_PROXY, expression); } /** * Set by IDEExpression with the method name. * @param fieldName * * @since 1.1.0 */ void setField(String fieldName) { this.fieldName = fieldName; } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.ExpressionProxy#toString() */ public String toString() { return super.toString()+" - "+fieldName; //$NON-NLS-1$ } /** * Called by IDEExpression to resolve the beantype. * @param fieldProxy * * @since 1.1.0 */ void setProxy(IDEFieldProxy fieldProxy) { this.resolvedProxy = fieldProxy; setProxy(resolvedProxy.getBean(), Class.class); } /** * Called by IDEExpression to say there was error in creating the proxy. * @param errorThrowable * * @since 1.1.0 */ void setThrowable(ThrowableProxy errorThrowable) { this.errorThrowable = errorThrowable; } /** * Called by IDEExpression to get the resolved field proxy. * @return * @throws ThrowableProxy * * @since 1.1.0 */ IDEFieldProxy getFieldProxy() throws ThrowableProxy { if (errorThrowable != null) throw errorThrowable; return resolvedProxy; } } /* * (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#createExpressionProxy(int, int) */ protected ExpressionProxy createExpressionProxy(int proxyType, int proxyID) { switch (proxyType) { case NORMAL_EXPRESSION_PROXY: default: return new IDEExpressionProxy(proxyID, NORMAL_EXPRESSION_PROXY, this); case BEANTYPE_EXPRESSION_PROXY: return new IDEBeanTypeExpressionProxy(proxyID, this); case METHOD_EXPRESSION_PROXY: return new IDEMethodExpressionProxy(proxyID, this); case FIELD_EXPRESSION_PROXY: return new IDEFieldExpressionProxy(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) { eproc.pushAssignment((InternalExpressionProxy) proxy); } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushAssignmentToProxy() */ protected void pushAssignmentToProxy() { eproc.pushAssignment(); } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushBlockBeginToProxy(int) */ protected void pushBlockBeginToProxy(int blockNumber) { eproc.pushBlockBegin(blockNumber); } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushBlockEndToProxy(int) */ protected void pushBlockEndToProxy(int blockNumber) { eproc.pushBlockEnd(blockNumber); } /* * (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushBlockBreakToProxy(int) */ protected void pushBlockBreakToProxy(int blockNumber) { eproc.pushBlockBreak(blockNumber); } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushTryBeginToProxy(int) */ protected void pushTryBeginToProxy(int tryNumber) { eproc.pushTryBegin(tryNumber); } /* * (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) { try { eproc.pushTryCatchClause(tryNumber, getIDEBeanTypeProxy(exceptionType).getTypeClass(), (InternalExpressionProxy) ep); } catch (ThrowableProxy e) { eproc.processException(e); } } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushTryFinallyClauseToProxy(int) */ protected void pushTryFinallyClauseToProxy(int tryNumber) { eproc.pushTryFinallyClause(tryNumber); } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushTryEndToProxy(int) */ protected void pushTryEndToProxy(int tryNumber) { eproc.pushTryEnd(tryNumber); } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushThrowToProxy() */ protected void pushThrowToProxy() { eproc.pushThrowException(); } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushRethrowToProxy(int) */ protected void pushRethrowToProxy(int tryNumber) { eproc.pushTryRethrow(tryNumber); } /* * (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushBeanTypeToProxy(org.eclipse.jem.internal.proxy.core.IBeanTypeExpressionProxy) */ protected void pushBeanTypeToProxy(IBeanTypeExpressionProxy proxy) { try { IDEBeanTypeExpressionProxy ep = (IDEBeanTypeExpressionProxy) proxy; IDEBeanTypeProxy typeProxy = getIDEBeanTypeProxy(proxy.getTypeName()); ep.setProxy(typeProxy); eproc.allocateExpressionProxy(ep); if (!typeProxy.isValid()) { Throwable cause = ((IDEInitErrorBeanTypeProxy) typeProxy).getCause(); if (cause == null) throw new IDEThrowableProxy( new Exception(typeProxy.getInitializationError()), getIDEBeanTypeFactory().getBeanTypeProxy(Exception.class)); else throw new IDEThrowableProxy( cause, getIDEBeanTypeFactory().getBeanTypeProxy(cause.getClass())); } } catch (ThrowableProxy e) { eproc.processException(e); } } /** * Get the map of IProxyBeanTypes for a beantype name. Meant to be used only in conjunction with IDEStandardBeanTypeFactory. * It is here so the IDDEStandardBeanTypeFactory 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 IDEStandardBeanTypeFactory. * It is here so the IDEStandardBeanTypeFactory 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); } /** * Keeping a local map of Method Expression Proxies so that we don't keep recreating them for each request from within this expression. * The map will be: declaringTypeName->(Map) methodName or IDEMethodKey -> method expression proxy. * @see IDEExpression#pushMethodToProxy(ExpressionProxy, IProxyBeanType, String, IProxyBeanType[]) for the actual implementation. */ protected Map methodExpressionProxies; /** * Keeping a local map of Field Expression Proxies so that we don't keep recreating them for each request from within this expression. * The map will be: declaringTypeName->(Map) fieldname -> field expression proxy. * @see IDEExpression#pushFieldToProxy(ExpressionProxy, IProxyBeanType, String) */ protected Map fieldExpressionProxies; /** * Keeping a local map of BeanType expression proxies so that we don't keep recreating them for each request from within this expression. * The map will be: typename->beanTypeExpressionProxy */ protected Map beanTypeCache; // Use to cache pending BeanTypes. Used in conjunction with IDEStandardBeanTypeFactory. /* * Used as the key to the methodCache when there are parms. * It allows the parms to be either IProxyBeanType without the * overhead of creating complicated strings. * * It will compare method name and each individual parm name without fluffing * up a string and building it up. * * For no parm methods, just the name of the method as a string will be the key. * * @since 1.1.0 */ private static class MethodKey { public String methodName; public IProxyBeanType[] parmTypes; public MethodKey(String methodName, IProxyBeanType[] parmTypes) { this.methodName = methodName; this.parmTypes = parmTypes; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { if (this == obj) return true; try { return ((MethodKey) obj).compareParms(parmTypes); } catch (ClassCastException e) { return false; } } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.remote.REMProxyConstants.MethodKey#hashCode() */ public int hashCode() { int h = methodName.hashCode();; for (int i = 0; i < parmTypes.length; i++) { h += parmTypes[i].getTypeName().hashCode(); } return h; } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.remote.REMProxyConstants.MethodKey#compareParms(java.lang.String[]) */ protected boolean compareParms(IProxyBeanType[] parms) { if (parms.length != parmTypes.length) return false; for (int i = 0; i < parms.length; i++) { if (!parmTypes[i].getTypeName().equals(parms[i].getTypeName())) return false; } return true; } } /* (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) { try { final Map methods = getMethods(declaringType); final Object key = getMethodKey(methodName, parameterTypes); methods.put(key, proxy); proxy.addProxyListener(new ExpressionProxy.ProxyAdapter() { public void proxyNotResolved(ProxyEvent event) { methods.remove(key); // Back it out. tis could happen due to endmark rollback. } }); IDEMethodExpressionProxy ep = (IDEMethodExpressionProxy) proxy; ep.setMethodName(methodName); // We resolve immediately. Any expression proxies should also be resolved at this point too. Class declaringClass = getIDEBeanTypeProxy(declaringType).getTypeClass(); Class[] parameterClasses; if (parameterTypes == null || parameterTypes.length == 0) parameterClasses = null; else { parameterClasses = new Class[parameterTypes.length]; for (int i = 0; i < parameterClasses.length; i++) { parameterClasses[i] = getIDEBeanTypeProxy(parameterTypes[i]).getTypeClass(); } } IDEMethodProxy methodProxy = ((IDEMethodProxyFactory) registry.getMethodProxyFactory()).getMethodProxy(declaringClass, methodName, parameterClasses); if (methodProxy == null) { String parms = ""; //$NON-NLS-1$ if (parameterTypes != null && parameterTypes.length > 0) { StringBuffer st = new StringBuffer(100); for (int i = 0; i < parameterClasses.length; i++) { if (i > 0) st.append(','); st.append(parameterTypes[i].getTypeName()); } parms = st.toString(); } throw new IDEThrowableProxy(new NoSuchMethodException("No method: "+declaringType+'.'+methodName+"("+parms+')'), //$NON-NLS-1$ //$NON-NLS-2$ getIDEBeanTypeFactory().getBeanTypeProxy(NoSuchMethodException.class)); } ep.setProxy(methodProxy); eproc.allocateExpressionProxy(ep); } catch (ThrowableProxy e) { ((IDEMethodExpressionProxy) proxy).setThrowable(e); // So we don't recreate throwable all of the time. eproc.processException(e); } } private Map getMethods(IProxyBeanType classtype) { if (methodExpressionProxies == null) methodExpressionProxies = new HashMap(); Map methods = (Map) methodExpressionProxies.get(classtype.getTypeName()); if (methods == null) methodExpressionProxies.put(classtype.getTypeName(), methods = new HashMap()); return methods; } private Object getMethodKey(String methodName, IProxyBeanType[] parameterTypes) { if (parameterTypes == null || parameterTypes.length == 0) return methodName; else return new MethodKey(methodName, parameterTypes); } private Map getFields(IProxyBeanType classtype) { if (fieldExpressionProxies == null) fieldExpressionProxies = new HashMap(); Map fields = (Map) fieldExpressionProxies.get(classtype.getTypeName()); if (fields == null) fieldExpressionProxies.put(classtype.getTypeName(), fields = new HashMap()); return fields; } /** * This is used by IDEBeanTypes and IDEBeanTypeExpressionProxy to access any already created Method Expression Proxies. * * @param declaringType * @param methodName * @param parameterTypes * @return IProxyMethod or <code>null</code> if not yet created. * * @since 1.1.0 */ IProxyMethod getMethodExpressionProxy(IProxyBeanType declaringType, String methodName, IProxyBeanType[] parameterTypes) { Map methods = getMethods(declaringType); Object key = getMethodKey(methodName, parameterTypes); return (IProxyMethod) methods.get(key); } /** * This is used by IDEBeanTypes and IDEBeanTypeExpressionProxy to access any already created Field Expression Proxies. * @param declaringType * @param fieldName * @return * * @since 1.1.0 */ IProxyField getFieldExpressionProxy(IProxyBeanType declaringType, String fieldName) { Map fields = getFields(declaringType); return (IProxyField) fields.get(fieldName); } /** * Get the IDEMethodProxy out of the already resolved Expression Proxy or IDEMethodProxy itself. * @param method * @return * @throws ThrowableProxy * * @since 1.1.0 */ protected IDEMethodProxy getIDEMethodProxy(IProxyMethod method) throws ThrowableProxy { IDEMethodProxy methodProxy; if (method.isExpressionProxy()) { // It should already be resolved at this point. methodProxy = ((IDEMethodExpressionProxy) method).getMethodProxy(); } else methodProxy = (IDEMethodProxy) method; return methodProxy; } /* (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, final String fieldName) { try { final Map fields = getFields(declaringType); fields.put(fieldName, proxy); proxy.addProxyListener(new ExpressionProxy.ProxyAdapter(){ public void proxyNotResolved(ExpressionProxy.ProxyEvent event) { fields.remove(fieldName); // this can happen due to an endmark. It could be one of the ones that are rolled back. } }); IDEFieldExpressionProxy ep = (IDEFieldExpressionProxy) proxy; // We resolve immediately. Any expression proxies should also be resolved at this point too. IDEFieldProxy fieldProxy = (IDEFieldProxy) getIDEBeanTypeProxy(declaringType).getFieldProxy(fieldName); if (fieldProxy == null) { throw new IDEThrowableProxy(new NoSuchFieldException("No field: "+declaringType+'.'+fieldName), //$NON-NLS-1$ getIDEBeanTypeFactory().getBeanTypeProxy(NoSuchFieldException.class)); } ep.setProxy(fieldProxy); eproc.allocateExpressionProxy(ep); } catch (ThrowableProxy e) { ((IDEFieldExpressionProxy) proxy).setThrowable(e); // So we don't recreate throwable all of the time. eproc.processException(e); } } /** * Get the IDEFieldProxy out of the already resolved Expression Proxy or IDEFieldProxy itself. * @param field * @return * @throws ThrowableProxy * * @since 1.1.0 */ protected IDEFieldProxy getIDEFieldProxy(IProxyField field) throws ThrowableProxy { IDEFieldProxy fieldProxy; if (field.isExpressionProxy()) { // It should already be resolved at this point. fieldProxy = ((IDEFieldExpressionProxy) field).getFieldProxy(); } else fieldProxy = (IDEFieldProxy) field; return fieldProxy; } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushIfTestToProxy() */ protected void pushIfTestToProxy() { eproc.pushIfElse(); } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.Expression#pushIfElseToProxy(org.eclipse.jem.internal.proxy.initParser.tree.InternalIfElseOperandType) */ protected void pushIfElseToProxy(InternalIfElseOperandType clauseType) { eproc.pushIfElse(clauseType); } /* (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) { try { eproc.pushNewInstanceFromString(initializationString, getIDEBeanTypeProxy(resultType).getTypeClass(), getIDERegistry().fClassLoader); } catch (ThrowableProxy e) { eproc.processException(e); } } protected void pushMarkToProxy(int markID) { eproc.pushMark(markID); } protected void pushEndmarkToProxy(int markID, boolean restore) { eproc.pushEndmark(markID, restore); } protected void pushBeginTransferThreadToProxy() { // For IDE it doesn't matter. Just go ahead and continue processing. } protected void pushTransferThreadToProxy() { // For IDE it doesn't matter. Just go ahead and continue processing. } protected void pushSubexpressionBeginToProxy(int subexpressionNumber) { eproc.pushSubexpressionBegin(subexpressionNumber); } protected void pushSubexpressionEndToProxy(int subexpressionNumber) { eproc.pushSubexpressionEnd(subexpressionNumber); } }