package agg.attribute.parser.javaExpr;
/* JJT: 0.2.2 */
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import agg.attribute.impl.AttrSession;
import agg.attribute.impl.VerboseControl;
/**
* @version $Id: OpMemberNode.java,v 1.9 2010/09/23 08:15:01 olga Exp $
* @author $Author: olga $
*/
public class OpMemberNode extends MemberNode {
static final long serialVersionUID = 1L;
protected Method method = null;
protected Object receivingObj, returnObj;
OpMemberNode(String id) {
super(id);
}
public static Node jjtCreate(String id) {
return new OpMemberNode(id);
}
protected boolean isConstantExpr() {
return false;
}
protected String getMethodName() {
Class<?> c = getNodeClass();
String name = ((ASTMemberName) jjtGetChild(0)).name;
if (c == null) {
return "\"" + name + "\"";
}
return "[" + this.method.toString() + "]";
}
/*
* You can override these two methods in subclasses of SimpleNode to
* customize the way the node appears when the tree is dumped. If your
* output uses more than one line you should override toString(String),
* otherwise overriding toString() is probably all you need to do.
*/
public String toString() {
return this.identifier + " " + getMethodName();
}
/*
* Override this method if you want to customize how the node dumps out its
* children.
*/
public void dump(String prefix) {
// System.out.println( toString(prefix) );
AttrSession.logPrintln(VerboseControl.logJexParser, toString(prefix));
if (this.children != null) {
java.util.Enumeration<Node> e = this.children.elements();
e.nextElement();
while (e.hasMoreElements()) {
SimpleNode n = (SimpleNode) e.nextElement();
n.dump(prefix + " ");
}
}
}
protected static boolean areParamsCompatible(Class<?> sigTypes[],
Class<?> realTypes[]) {
if (realTypes == null) {
return (sigTypes.length == 0);
} else if (sigTypes.length == realTypes.length) {
for (int i = 0; i < sigTypes.length; i++) {
if (!sigTypes[i].isAssignableFrom(realTypes[i])) {
return false;
}
}
return true;
} else {
return false;
}
}
protected static Method getMethod(Class<?> clazz, String name,
Class<?> paramTypes[]) {
Method result = null, tmpMethod;
Method allMethods[];
try {
result = clazz.getMethod(name, paramTypes);
} catch (NoSuchMethodException ex) {
allMethods = clazz.getMethods();
for (int i = 0; i < allMethods.length; i++) {
tmpMethod = allMethods[i];
if (tmpMethod.getName().equals(name)
&& areParamsCompatible(tmpMethod.getParameterTypes(),
paramTypes)) {
result = tmpMethod;
}
}
}
return result;
}
protected void findMethod(SimpleNode recipient)
throws ASTWrongTypeException {
Class<?> recClass = recipient.getNodeClass();
String methodName = ((ASTMemberName) jjtGetChild(0)).name;
int nChildren = jjtGetNumChildren();
Node param;
Class<?> paramTypes[] = new Class<?>[nChildren - 1];
for (int i = 1; i < nChildren; i++) {
param = jjtGetChild(i);
param.checkContext();
paramTypes[i - 1] = ((SimpleNode)param).getNodeClass();
}
if (nChildren == 1) {
paramTypes = null;
}
this.method = getMethod(recClass, methodName, paramTypes);
/* Error, if method not found: */
if (this.method == null) {
String paramText;
if (paramTypes != null) {
paramText = "for parameter types \n (";
for (int i = 0; i < paramTypes.length; i++) {
paramText = paramText + paramTypes[i].toString();
if (i < paramTypes.length - 1) {
paramText = paramText + ", ";
}
}
paramText = paramText + ")";
} else {
paramText = "with an empty parameter list";
}
throw new ASTMemberException("No public method " + getMethodName()
+ "\n " + paramText + "\n in class "
+ recClass.toString() + " .");
}
}
public void invoke(SimpleNode recipient) {
if (this.method == null) {
checkContext(recipient);
}
int nChildren = jjtGetNumChildren();
Object params[] = new Object[nChildren - 1];
for (int i = 1; i < nChildren; i++) {
jjtGetChild(i).interpret();
params[i - 1] = stack.get(top--);
}
if (nChildren == 1) {
params = null;
}
this.receivingObj = stack.get(top);;
try {
this.returnObj = this.method.invoke(this.receivingObj, params);
// System.out.println("receivingObj=" + receivingObj );
// System.out.println("returnObj=" + returnObj );
AttrSession.logPrintln(VerboseControl.logJexParser,
"OpMemberNode: receivingObj=" + this.receivingObj);
AttrSession.logPrintln(VerboseControl.logJexParser,
"OpMemberNode: returnObj=" + this.returnObj);
} catch (IllegalAccessException ex1) {
throw new ASTMemberException("Cannot access method "
+ getMethodName() + Jex.addMessage(ex1));
} catch (IllegalArgumentException ex2) {
throw new ASTMemberException("Illegal arguments to method "
+ getMethodName() + Jex.addMessage(ex2));
} catch (InvocationTargetException ex3) {
// System.out.println(ex3.getTargetException().getMessage());
if (ex3.getTargetException() != null)
throw new ASTMemberException("Error while invoking method "
+ getMethodName() + " "
+ Jex.addMessage((Exception) ex3.getTargetException()));
throw new ASTMemberException("Error while invoking method "
+ getMethodName() + Jex.addMessage(ex3));
} catch (NullPointerException ex4) {
throw new ASTMemberException("Invoking method " + getMethodName()
+ " on a null object." + Jex.addMessage(ex4));
}
}
public void checkContext(SimpleNode recipient) throws ASTWrongTypeException {
findMethod(recipient);
setNodeClass(this.method.getReturnType());
}
public void interpret(SimpleNode recipient) {
invoke(recipient);
// stack[++top] = returnObj;
stack.add(++top, this.returnObj);
}
public Node copy() {
Node copy = super.copy();
((OpMemberNode) copy).method = this.method;
((OpMemberNode) copy).receivingObj = this.receivingObj;
((OpMemberNode) copy).returnObj = this.returnObj;
return copy;
}
}
/*
* $Log: OpMemberNode.java,v $
* Revision 1.9 2010/09/23 08:15:01 olga
* tuning
*
* Revision 1.8 2010/07/29 10:09:18 olga
* Array stack changed to Vector stack
*
* Revision 1.7 2010/05/05 16:16:27 olga
* tuning and tests
*
* Revision 1.6 2010/03/31 21:10:49 olga
* tuning
*
* Revision 1.5 2010/03/08 15:38:38 olga
* code optimizing
*
* Revision 1.4 2007/11/01 09:58:17 olga
* Code refactoring: generic types- done
*
* Revision 1.3 2007/09/10 13:05:47 olga
* In this update:
* - package xerces2.5.0 is not used anymore;
* - class com.objectspace.jgl.Pair is replaced by the agg own generic class agg.util.Pair;
* - bugs fixed in: usage of PACs in rules; match completion;
* usage of static method calls in attr. conditions
* - graph editing: added some new features
* Revision 1.2 2006/12/13 13:32:58 enrico
* reimplemented code
*
* Revision 1.1 2005/08/25 11:56:52 enrico *** empty log message ***
*
* Revision 1.1 2005/05/30 12:58:01 olga Version with Eclipse
*
* Revision 1.4 2005/05/09 11:42:04 olga -CPs: error of dangling condition check
* fixed. -Transformation: attr. exception handling. -Omondo XMI to XSL:
* importing
*
* Revision 1.3 2003/03/05 18:24:15 komm sorted/optimized import statements
*
* Revision 1.2 2003/01/15 11:36:00 olga Neue VerboseControl Konstante
* :logJexParser zum Testen
*
* Revision 1.1.1.1 2002/07/11 12:17:04 olga Imported sources
*
* Revision 1.5 2000/04/05 12:11:08 shultzke serialVersionUID aus V1.0.0
* generiert
*
* Revision 1.4 2000/03/14 10:59:56 shultzke Transformieren von Variablen auf
* Variablen sollte jetzt funktionieren Ueber das Design der Copy-Methode des
* abstrakten Syntaxbaumes sollte unbedingt diskutiert werden.
*
*/