| /******************************************************************************* |
| * Copyright (c) 2001, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jem.internal.proxy.initParser; |
| /* |
| |
| |
| */ |
| |
| |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| |
| import org.eclipse.jem.internal.proxy.common.AmbiguousMethodException; |
| import org.eclipse.jem.internal.proxy.common.MethodHelper; |
| |
| public class Message extends Expression { |
| protected boolean trailingPeriod = false; |
| protected Method fMethod; |
| public Expression receiver; |
| public String message; |
| public boolean argsClosed = false; |
| public boolean insideArgsOpenedParen = false; |
| public boolean insideArgsClosedParen = false; |
| protected boolean isComplete = false; |
| public ArrayList arguments = new ArrayList(2); |
| |
| public Message(Expression aReceiver , char[] token , ClassLoader aClassLoader){ |
| receiver = aReceiver; |
| message = new String(token); |
| fClassLoader = aClassLoader; |
| } |
| public boolean isComplete(){ |
| return isComplete; |
| } |
| |
| /** |
| * Send the message to the receiver |
| */ |
| public Object evaluate() throws Exception { |
| cacheMethod(); |
| |
| // Get the array of arguments |
| Object[] args = new Object[arguments.size()]; |
| Iterator itr = arguments.iterator(); |
| for (int i = 0; i < arguments.size() ; i++){ |
| Expression anExpression = (Expression)itr.next(); |
| args[i] = anExpression.evaluate(); |
| } |
| |
| Object receiverValue = receiver.evaluate(); // So if evaluation exception thrown, we don't wrapper again. |
| |
| try { |
| return fMethod.invoke(receiverValue, args); |
| } catch (Exception e) { |
| throw new EvaluationException(e); |
| } |
| } |
| |
| /** |
| * Cache the message |
| */ |
| protected void cacheMethod() throws Exception { |
| if (fMethod == null) { |
| Class[] argTypes = new Class[arguments.size()]; |
| Iterator itr = arguments.iterator(); |
| for (int i=0; i<argTypes.length; i++) |
| argTypes[i] = getEvaluationTypeClass((Expression) itr.next()); |
| |
| try { |
| fMethod = MethodHelper.findCompatibleMethod(getEvaluationTypeClass(receiver), message, argTypes); |
| } catch (NoSuchMethodException e) { |
| throw new EvaluationException(e); |
| } catch (AmbiguousMethodException e) { |
| throw new EvaluationException(e); |
| } |
| } |
| } |
| |
| |
| /** |
| * getTypeClass method comment. |
| */ |
| public Class getTypeClass() throws Exception { |
| cacheMethod(); |
| return fMethod.getReturnType(); |
| } |
| |
| protected String getTypeClassName() { |
| return ""; // If we got this far, we don't know what it is. //$NON-NLS-1$ |
| } |
| /** |
| * push method comment. |
| */ |
| public Expression push(char[] token, char tokenDelimiter) { |
| |
| // If we are closed and we receive a . with no token then remember this |
| if ( argsClosed && !trailingPeriod && tokenDelimiter == DelimiterPeriod && token.length == 0 ) { |
| trailingPeriod = true; |
| return this; |
| } |
| // If we have been closed with a . and we receive a . then we are a field |
| if ( trailingPeriod && tokenDelimiter == DelimiterPeriod ) { |
| return new Field(this,token,fClassLoader); |
| } |
| // If we have been closed with a . and we receive a ( we are a message |
| if ( trailingPeriod && tokenDelimiter == DelimiterOpenParen ) { |
| return new Message(this,token,fClassLoader); |
| } |
| |
| // If we have been closed and we receive a , or a ) we are complete - this is a structural token intended for someone else, |
| // probably a message argument lower down the stack |
| if (argsClosed && (tokenDelimiter == DelimiterComma || tokenDelimiter == DelimiterCloseParen)){ |
| isComplete = true; |
| return this; |
| } |
| |
| |
| // If the args are opened and a token was supplied then it must be an argument |
| //if ( argsOpened && ( tokenDelimiter == DelimiterCloseParen || tokenDelimiter == DelimiterComma || |
| //tokenDelimiter == DelimiterSpace || tokenDelimiter == DelimiterQuote || tokenDelimiter == DelimiterPeriod)) { |
| if (!argsClosed){ |
| if ( arguments.size() > 0 ){ |
| Expression openArgument = (Expression)arguments.get(arguments.size()-1); |
| if ( !openArgument.isComplete() ) { |
| openArgument.push(token,tokenDelimiter); |
| // If the argument is complete and we received a ) then the message is complete |
| if ( openArgument.isComplete() && tokenDelimiter == DelimiterCloseParen){ |
| argsClosed = true; |
| } |
| return this; |
| } |
| } |
| |
| // We must have a new argument - process accordingly |
| Expression newArgument = null; |
| if (!insideArgsOpenedParen && tokenDelimiter == DelimiterOpenParen){ |
| insideArgsOpenedParen = true; |
| newArgument = new Statement(fClassLoader).push(token,tokenDelimiter); |
| newArgument = new MessageArgument(newArgument); |
| arguments.add(newArgument); |
| |
| } |
| if ( newArgument == null && (token.length > 0 || tokenDelimiter == DelimiterQuote || tokenDelimiter == DelimiterSingleQuote || tokenDelimiter == DelimiterOpenParen )) { |
| newArgument = new Statement(fClassLoader).push(token,tokenDelimiter); |
| newArgument = new MessageArgument(newArgument); |
| arguments.add(newArgument); |
| } |
| // If the token after the argument is a ) then the message is being closed |
| if ( !insideArgsOpenedParen && tokenDelimiter == DelimiterCloseParen ) { |
| argsClosed = true; |
| return this; |
| } |
| if ( insideArgsOpenedParen && tokenDelimiter == DelimiterCloseParen ) { |
| insideArgsClosedParen = true; |
| return this; |
| } |
| |
| // If the token after the argument is a , or a ' ' then the argument is being closed |
| if ( tokenDelimiter == DelimiterComma || tokenDelimiter == DelimiterSpace ) { |
| return this; |
| } |
| |
| // Otherwise the new argument is stil processing. Return it |
| // return newArgument; |
| } |
| |
| // If we don't have a message yet, then consume this one |
| if ( message.length() == 0 ) { |
| message = new String(token); |
| return this; |
| } |
| |
| return this; |
| } |
| public String toString(){ |
| |
| java.io.StringWriter writer = new java.io.StringWriter(); |
| writer.write("Msg Name=\""); //$NON-NLS-1$ |
| if ( message != null ) { |
| writer.write(message); |
| } else { |
| writer.write("UNNAMED"); //$NON-NLS-1$ |
| } |
| writer.write("\" Rcv=("); //$NON-NLS-1$ |
| if ( receiver != null ){ |
| writer.write(receiver.toString()); |
| } else { |
| writer.write("NONE"); //$NON-NLS-1$ |
| } |
| writer.write(')'); |
| if ( arguments != null ) { |
| writer.write("Args("); //$NON-NLS-1$ |
| Iterator iter = arguments.iterator(); |
| int i=1; |
| while(iter.hasNext()){ |
| writer.write(new Integer(i).toString()); |
| writer.write('('); |
| writer.write(iter.next().toString()); |
| writer.write("),"); //$NON-NLS-1$ |
| } |
| writer.write(')'); |
| } |
| |
| return writer.toString(); |
| |
| } |
| |
| /** |
| * Is the message result a primitive. |
| */ |
| public boolean isPrimitive() throws Exception { |
| cacheMethod(); |
| return fMethod.getReturnType().isPrimitive(); |
| } |
| } |