/* * Software Name : ATK * * Copyright (C) 2007 - 2012 France Télécom * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ------------------------------------------------------------------ * File Name : JATKInterpreter.java * * Created : 27/11/2008 * Author(s) : Yvain Leyral */ package com.orange.atk.interpreter.atkCore; import java.lang.reflect.Method; import java.util.ArrayList; import org.apache.log4j.Logger; import com.orange.atk.interpreter.ast.ASTBOOLEAN; import com.orange.atk.interpreter.ast.ASTCOMMENT; import com.orange.atk.interpreter.ast.ASTFLOAT; import com.orange.atk.interpreter.ast.ASTFUNCTION; import com.orange.atk.interpreter.ast.ASTINCLUDE; import com.orange.atk.interpreter.ast.ASTLOOP; import com.orange.atk.interpreter.ast.ASTNUMBER; import com.orange.atk.interpreter.ast.ASTSETVAR; import com.orange.atk.interpreter.ast.ASTSTRING; import com.orange.atk.interpreter.ast.ASTStart; import com.orange.atk.interpreter.ast.ASTTABLE; import com.orange.atk.interpreter.ast.ASTVARIABLE; import com.orange.atk.interpreter.ast.SimpleNode; import com.orange.atk.interpreter.ast.SoloMethods; import com.orange.atk.interpreter.parser.ATKScriptParserVisitor; import com.orange.atk.phone.PhoneInterface; import com.orange.atk.platform.Platform; import com.orange.atk.results.logger.log.ResultLogger; /** * Interpreter for the Java Accelerator ToolKit (JATK) */ public class JATKInterpreter implements ATKScriptParserVisitor { // Common errors private static final String LOOP_VALUE_IS_NEGATIVE = "Loop value is negative"; //$NON-NLS-1$ private static final String STOPMAIN_HAS_NOT_BEEN_CALLED = "StopMainLog has not been called"; //$NON-NLS-1$ private static final String IS_NOT_A_VARIABLE = " is not a variable..."; //$NON-NLS-1$ // Represents the current log system private ResultLogger mainLogger; // Stack used to store temporary informations private JATKInterpreterStack stack = new JATKInterpreterStack(); // Table which stores(variable,value) information private JATKVariableTable variables = new JATKVariableTable(); // represents the internal state of the interpreter private JATKInterpreterInternalState internalState = new JATKInterpreterInternalState(); // used this class as a proxy for actions with the phone private ActionToExecute actions; private PhoneInterface phoneInterface = null; /** * Constructor * * @param p * phone tested * @param l * logger used to store information * @param currentScript * current script tested * @param logDir * folder where result files are stored * @param includeDir * folder where include file are stored */ public JATKInterpreter(PhoneInterface p, ResultLogger l, String currentScript, String logDir, String includeDir) { internalState.setCurrentScript(currentScript); internalState.setLogDir(logDir + Platform.FILE_SEPARATOR); phoneInterface = p; mainLogger = l; mainLogger.setInterpreter(this); actions = new ActionToExecute(this); } /** * @see ast.ATKScriptParserVisitor#visit(ast.ASTFUNCTION, java.lang.Object) */ public Object visit(ASTFUNCTION node, Object data) { return runAction(node, data); } private Object runAction(SimpleNode node, Object data) { // visit children node.childrenAccept(this, data); // analyze the name part String functionName = node.getValue(); if ((phoneInterface.getCnxStatus()!=PhoneInterface.CNX_STATUS_AVAILABLE)||(mainLogger.isStopATK())) { Logger.getLogger(this.getClass() ).debug("["+this.getClass().getName()+"] Close JATK "); mainLogger.interrupt(); return Boolean.FALSE; } //get variables Variable[] tablevariables = new Variable[stack.size()]; tablevariables = stack.toArray(tablevariables); //empty stack while(! stack.empty()) stack.pop(); if(new SoloMethods().isSoloMethod(functionName)){ try { return actions.actionExecuteSoloMethod((ASTFUNCTION)node, tablevariables); } catch (Exception e) { Logger.getLogger(this.getClass() ).debug("erreur during execution of "+functionName); e.printStackTrace(); } } else { //SEARCH function in action class and invoke it. Method[] functions = actions.getClass().getMethods(); for (Method function : functions) if(function.getName().toLowerCase(). equals("action"+functionName.toLowerCase()) ) { try { return function.invoke(actions, node, tablevariables ); } catch (Exception e) { Logger.getLogger(this.getClass() ).debug("erreur during execution of "+function.getName()); e.printStackTrace(); } } } //we don't have found the function getMainLogger().addErrorToDocumentLogger( functionName + " is not a valid function", node.getLineNumber(), internalState.getCurrentScript()); return Boolean.FALSE; /* * Could not happens anymore due to control in actions class } catch * (ClassCastException ex) { mainLogger.addErrorToLog("Invalid given * argument", node .getLineNumber(), internalState.getCurrentScript()); * ex.printStackTrace(); return Boolean.FALSE; } */ } /** * @see ast.ATKScriptParserVisitor#visit(ast.ASTLISTARGS, java.lang.Object) */ public Object visit(ASTCOMMENT node, Object data) { // Logger.getLogger(this.getClass() ).debug("read comment value : "+node.getValue()); return node.childrenAccept(this, data); } /** * @see ast.ATKScriptParserVisitor#visit(ast.ASTLOOP, java.lang.Object) */ public Object visit(ASTLOOP node, Object data) { Integer nbLoop = null; //int nbNodes = node.jjtGetNumChildren(); // On obtient le nombre de loop (=n) // puis on repetera n fois children.Accept node.jjtGetChild(0).jjtAccept(this, data); nbLoop = stack.popInteger(); if (nbLoop < 0) { getMainLogger() .addErrorToDocumentLogger(LOOP_VALUE_IS_NEGATIVE, node.getLineNumber(), getInternalState().getCurrentScript()); } //Logger.getLogger(this.getClass() ).debug("Loop n = " + nbLoop); int previousLoopValue = internalState.getLoopValue(); // number of loop specified for the loop for (int i = 0; i < nbLoop; i++) { // childs are visited, excepted the first one (the number of // loop) //Logger.getLogger(this.getClass() ).debug("NbLoop = " + i); internalState.setLoopValue(i); for (int j = 1; j < node.jjtGetNumChildren(); j++) { Object res = node.jjtGetChild(j).jjtAccept(this, data); if (res != null) { if (!((Boolean) res).booleanValue()) { return Boolean.FALSE; } } } } internalState.setLoopValue(previousLoopValue); return Boolean.TRUE; } /** * @see ast.ATKScriptParserVisitor#visit(ast.ASTNUMBER, java.lang.Object) */ public Object visit(ASTINCLUDE node, Object data) { // If include as not been already parsed if (node.jjtGetNumChildren()==1) { return runAction(node, data); } else { for (int j = 1; j < node.jjtGetNumChildren(); j++) { Object res = node.jjtGetChild(j).jjtAccept(this, data); if (res != null) { if (!((Boolean) res).booleanValue()) { return Boolean.FALSE; } } } } return Boolean.TRUE; } /** * @see ast.ATKScriptParserVisitor#visit(ast.ASTNUMBER, java.lang.Object) */ public Object visit(ASTNUMBER node, Object data) { // push the value of integer stack.pushInteger(Integer.parseInt(node.getValue())); return Boolean.TRUE; } /** * @see ast.ATKScriptParserVisitor#visit(ast.ASTSETVAR, java.lang.Object) */ public Object visit(ASTSETVAR node, Object data) { // We expect two elements in the stack node.childrenAccept(this, data); // The stack should contain two elements: // One string for the variable name // One element (a String or a Integer) // First element of the stack is the variable // value if (stack.isTopInteger()) { // Variable type is an integer Integer o = stack.popInteger(); String variableName = "_"+stack.popString().trim(); // Save the variable getVariables().addIntegerVariable(variableName, o); } else { // Variable type is a String String o = stack.popString(); String variableName = "_"+stack.popString().trim(); // Save the variable getVariables().addStringVariable(variableName, o); } return Boolean.TRUE; } // Entry point of the interpreter /** * Entry point of the interpreter * * @see ast.ATKScriptParserVisitor#visit(ast.ASTStart, java.lang.Object) */ public Object visit(ASTStart node, Object data) { // Start of interpreter Boolean res = (Boolean) node.childrenAccept(this, Boolean.TRUE); // End of interpreter // test if StopMainLog has been called /*if (getMainLogger().isAlive()) { getMainLogger() .addErrorToDocumentLogger(STOPMAIN_HAS_NOT_BEEN_CALLED, 0, null); getMainLogger().interrupt(); return Boolean.FALSE; }*/ if (res == null) { // Logger.getLogger(this.getClass() ).warn("res == null"); return Boolean.FALSE; } return res; } /** * @see ast.ATKScriptParserVisitor#visit(ast.ASTSTRING, java.lang.Object) */ public Object visit(ASTSTRING node, Object data) { // push the value of integer stack.pushString(node.getValue()); return Boolean.TRUE; } /** * @see ast.ATKScriptParserVisitor#visit(ast.ASTTABLE, java.lang.Object) */ public Object visit(ASTTABLE node, Object data) { String marker = "TABLEMARKER#"+Math.random(); stack.pushString(marker); // visit children node.childrenAccept(this, data); //empty stack until marker ArrayList<Variable> reversetable = new ArrayList<Variable>(); Variable temp = stack.pop(); while ( !(temp.isString() && temp.getString().equals(marker) )){ reversetable.add(temp); temp = stack.pop(); } //reverse table ArrayList<Variable> table = new ArrayList<Variable>(); for(int i=reversetable.size()-1 ; i>=0; i--) table.add(reversetable.get(i)); stack.pushTable(table); return Boolean.TRUE; } /** * @see ast.ATKScriptParserVisitor#visit(ast.ASTVARIABLE, java.lang.Object) */ public Object visit(ASTVARIABLE node, Object data) { // check if the referenced value has been previously defined if (!getVariables().isVariable(node.getValue().trim())) { getMainLogger().addErrorToDocumentLogger(node.getValue() + IS_NOT_A_VARIABLE, node.getLineNumber(), internalState.getCurrentScript()); return Boolean.FALSE; } // if yes, get the value and return it Variable var = getVariables().getVariable(node.getValue().trim()); if (var.isInteger()) { stack.pushInteger(var.getInteger()); } else if (var.isString()) { stack.pushString(var.getString()); } /* * else { mainLogger.addErrorToLog("Unknown type... ", * node.getLineNumber(), internalState.getCurrentScript()); return * Boolean.FALSE; } */ return Boolean.TRUE; } /** * Default visit function * * @see ast.ATKScriptParserVisitor#visit(ast.SimpleNode, java.lang.Object) */ public Object visit(SimpleNode node, Object data) { return node.childrenAccept(this, data); } protected ResultLogger getMainLogger() { return mainLogger; } protected JATKInterpreterStack getStack() { return stack; } protected JATKVariableTable getVariables() { return variables; } /** * This function returns the object which stores current state of * interpreter * * @return an OCTKInterpreterInternalState object */ protected JATKInterpreterInternalState getInternalState() { return internalState; } /** * @return interface to the phone tested */ public PhoneInterface getPhoneInterface() { return phoneInterface; } @Override public Object visit(ASTBOOLEAN node, Object data) { stack.pushBoolean(Boolean.parseBoolean(node.getValue())); return Boolean.TRUE; } @Override public Object visit(ASTFLOAT node, Object data) { stack.pushFloat(Float.parseFloat(node.getValue())); return Boolean.TRUE; } }