org.mpi.vasco.sieve.staticanalysis.templatecreator.TemplateCreator.java Source code

Java tutorial

Introduction

Here is the source code for org.mpi.vasco.sieve.staticanalysis.templatecreator.TemplateCreator.java

Source

/********************************************************************
Copyright (c) 2013 chengli.
All rights reserved. This program and the accompanying materials
are made available under the terms of the GNU Public License v2.0
which accompanies this distribution, and is available at
http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
    
Contributors:
chengli - initial API and implementation
    
Contact:
To distribute or use this code requires prior specific permission.
In this case, please contact chengli@mpi-sws.org.
********************************************************************/
/**
 * 
 */
package org.mpi.vasco.sieve.staticanalysis.templatecreator;

import japa.parser.ast.body.VariableDeclarator;
import japa.parser.ast.body.VariableDeclaratorId;
import japa.parser.ast.expr.AssignExpr;
import japa.parser.ast.expr.BinaryExpr;
import japa.parser.ast.expr.Expression;
import japa.parser.ast.expr.MethodCallExpr;
import japa.parser.ast.expr.NameExpr;
import japa.parser.ast.expr.VariableDeclarationExpr;

import java.io.StringReader;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParser;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.update.Update;

import org.eclipse.jdt.core.dom.BooleanLiteral;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;

import org.mpi.vasco.sieve.runtimelogic.staticinformation.StaticFPtoWPsStore;
import org.mpi.vasco.sieve.staticanalysis.codeparser.CodeNodeIdentifier;
import org.mpi.vasco.sieve.staticanalysis.codeparser.ExpressionParser;
import org.mpi.vasco.sieve.staticanalysis.templatecreator.template.DeleteOperation;
import org.mpi.vasco.sieve.staticanalysis.templatecreator.template.InsertOperation;
import org.mpi.vasco.sieve.staticanalysis.templatecreator.template.Operation;
import org.mpi.vasco.sieve.staticanalysis.templatecreator.template.ShadowOperationTemplate;
import org.mpi.vasco.sieve.staticanalysis.templatecreator.template.UniqueInsertOperation;
import org.mpi.vasco.sieve.staticanalysis.templatecreator.template.UpdateOperation;
import org.mpi.vasco.sieve.staticanalysis.datastructures.controlflowgraph.CFGGraph;
import org.mpi.vasco.sieve.staticanalysis.datastructures.controlflowgraph.CFGNode;

import org.mpi.vasco.util.annotationparser.InvariantParser;
import org.mpi.vasco.util.annotationparser.SchemaParser;
import org.mpi.vasco.util.commonfunc.FileOperations;
import org.mpi.vasco.util.commonfunc.StringOperations;
import org.mpi.vasco.util.crdtlib.dbannotationtypes.AosetTable;
import org.mpi.vasco.util.crdtlib.dbannotationtypes.ArsetTable;
import org.mpi.vasco.util.crdtlib.dbannotationtypes.AusetTable;
import org.mpi.vasco.util.crdtlib.dbannotationtypes.CrdtFactory;
import org.mpi.vasco.util.crdtlib.dbannotationtypes.UosetTable;
import org.mpi.vasco.util.crdtlib.dbannotationtypes.dbutil.DataField;
import org.mpi.vasco.util.crdtlib.dbannotationtypes.dbutil.DatabaseTable;
import org.mpi.vasco.util.crdtlib.dbannotationtypes.dbutil.RuntimeExceptionType;
import org.mpi.vasco.util.debug.Debug;

// TODO: Auto-generated Javadoc
/**
 * The Class TemplateCreator.
 */
public class TemplateCreator extends SourceCodeGenerator {

    /** The schema parser. */
    private SchemaParser schemaParser;

    /** The inv parser. */
    private InvariantParser invParser;

    /** The c jsql parser. */
    private CCJSqlParserManager cJsqlParser;

    /** The cfg list. */
    private List<CFGGraph<CodeNodeIdentifier, Expression>> cfgList;

    /** The Constant CLASS_NAME_STR. */
    public final static String CLASS_NAME_STR = "shadowOptemplate";

    /** The Constant LWWLTS_VALUE. */
    private final static String LWWLTS_VALUE = "lwwLts";

    /** The method specs. 
     * mapping from method name to frame conditions
     * */
    HashMap<String, List<String>> methodSpecs;

    List<ShadowOperationTemplate> tList;

    /** The table arg count. */
    private int tableArgCount = 0;

    /** The hashmap mapping from the method name to the pair (numOfPath, numOfTemplates) */
    private HashMap<String, PathTemplateNumPair> statisMap;

    /**
     * Instantiates a new template creator.
     *
     * @param sp the sp
     * @param invP the inv p
     * @param projectName the project name
     * @param cfgL the cfg l
     */
    public TemplateCreator(SchemaParser sp, InvariantParser invP, String projectName,
            List<CFGGraph<CodeNodeIdentifier, Expression>> cfgL) {
        super(projectName, CLASS_NAME_STR);
        this.setSchemaParser(sp);
        this.setInvParser(invP);
        this.setCfgList(cfgL);
        this.cJsqlParser = new CCJSqlParserManager();
        this.methodSpecs = new HashMap<String, List<String>>();
        this.statisMap = new HashMap<String, PathTemplateNumPair>();
    }

    /**
     * Gets the cfg list.
     *
     * @return the cfg list
     */
    public List<CFGGraph<CodeNodeIdentifier, Expression>> getCfgList() {
        return cfgList;
    }

    /**
     * Sets the cfg list.
     *
     * @param cfgList the cfg list
     */
    public void setCfgList(List<CFGGraph<CodeNodeIdentifier, Expression>> cfgList) {
        this.cfgList = cfgList;
    }

    //functions   

    /**
     * Checks if is execute update method call expression.
     *
     * @param exp the exp
     * @return true, if is execute update method call expression
     */
    private boolean isExecuteUpdateMethodCallExpression(Expression exp) {
        if (ExpressionParser.isMethodCallExpression(exp)) {
            MethodCallExpr methodCallExpr = (MethodCallExpr) exp;
            if (methodCallExpr.getName().equals("executeUpdate")) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    private String assembleStringForBinaryExpr(List<CFGNode<CodeNodeIdentifier, Expression>> precedingNodeList,
            BinaryExpr binExpr) {
        List<Expression> operandList = ExpressionParser.getOperands((BinaryExpr) binExpr);
        String varValueString = "";
        for (Expression operand : operandList) {
            Debug.println("we get an operand: " + operand.toString());
            if (ExpressionParser.isLiteralExpression(operand)) {
                varValueString += StringOperations.trimDoubleQuotesHeadTail(operand.toString());
            } else {
                if (ExpressionParser.isNameExpr(operand)) {
                    varValueString += this.assembleStringForNameExpr(precedingNodeList, (NameExpr) operand);
                } else {
                    varValueString += "?";
                }
            }
        }
        return StringOperations.trimDoubleQuotesHeadTail(varValueString);
    }

    //find one update/insert/delete statement

    /**
     * Assemble string for name expr.
     *
     * @param precedingNodeList the preceding node list
     * @param nameExpr the name expr
     * @return the string
     */
    //TODO: currently we only support = or +=
    private String assembleStringForNameExpr(List<CFGNode<CodeNodeIdentifier, Expression>> precedingNodeList,
            NameExpr nameExpr) {
        Debug.println("Hello, you have a variable: " + nameExpr.getName());
        int index = precedingNodeList.size() - 1;
        while (index >= 0) {
            Expression expr = precedingNodeList.get(index).getNodeData();
            Debug.println("currently we work with expr: " + expr.toString());
            if (ExpressionParser.isAssignmentExpr(expr)) {
                //if the leftside is nameExpr, then check the right side is the string literal or some literal , return
                AssignExpr assignExpr = (AssignExpr) expr;
                assert (assignExpr.getOperator() == AssignExpr.Operator.assign);
                Expression target = assignExpr.getTarget();
                Expression value = assignExpr.getValue();
                Debug.println("target: " + target.toString());
                Debug.println("value: " + value.toString());
                // if the right side is not a string literal, then it must be a plus operator
                if (target.toString().equals(nameExpr.getName())) {
                    Debug.println("the assignment target is the one we want: " + target.toString());
                    if (ExpressionParser.isLiteralExpression(value)) {
                        return StringOperations.trimDoubleQuotesHeadTail(value.toString());
                    } else {
                        // it must be a binaryExpr
                        if (ExpressionParser.isBinaryExpr(value)) {
                            return this.assembleStringForBinaryExpr(precedingNodeList.subList(0, index),
                                    (BinaryExpr) value);
                        } else {
                            return "?";
                        }
                    }
                }
            } else if (ExpressionParser.isVariableDeclarationExpr(expr)) {
                //if it has initializer, then check whether it is string or not
                VariableDeclarationExpr varDeclExpr = (VariableDeclarationExpr) expr;
                //get the name of the variable
                Expression targetVarExpr = ExpressionParser.getMatchedVarDeclaration(varDeclExpr,
                        nameExpr.getName());
                // if it doesn't have initializer return ""
                if (targetVarExpr != null) {
                    //if the targetVarExpr is literal then return;
                    if (ExpressionParser.isLiteralExpression(targetVarExpr)) {
                        return StringOperations.trimDoubleQuotesHeadTail(targetVarExpr.toString());
                    } else {
                        // it must be a binaryExpr
                        if (ExpressionParser.isBinaryExpr(targetVarExpr)) {
                            return this.assembleStringForBinaryExpr(precedingNodeList.subList(0, index),
                                    (BinaryExpr) targetVarExpr);
                        } else {
                            return "?";
                        }
                    }
                }
            }
            index--;
        }
        return "";
    }

    /**
     * Find sql updating statement.
     *
     * @param precedingNodeList the preceding node list
     * @param cfgNode the cfg node
     * @return the string
     */
    private String findSqlUpdatingStatement(List<CFGNode<CodeNodeIdentifier, Expression>> precedingNodeList,
            CFGNode<CodeNodeIdentifier, Expression> cfgNode) {
        //get the argument from the argument of the executeUpdate function
        MethodCallExpr methodCallExpr = (MethodCallExpr) cfgNode.getNodeData();
        List<Expression> args = methodCallExpr.getArgs();
        /*
         * Fork into two branches: 
         * one for connection.execute()
         * one for preparestatement.executeUpdate()
         */
        if (args != null) {
            assert (args.size() == 1);
            Expression argExpr = args.get(0);
            //if this argument is a string, then please return this string
            if (ExpressionParser.isStringLiteralExpression(argExpr)) {
                return argExpr.toString();
            } else if (ExpressionParser.isNameExpr(argExpr)) {
                //if the argument is a variable, please find it along the path back the start of the function
                //* find the assignment expression
                return this.assembleStringForNameExpr(precedingNodeList, (NameExpr) argExpr);
            } else {
                System.err.println("This method has not been implemented!");
                return null;
            }
        } else {
            Expression scope = methodCallExpr.getScope();
            NameExpr namExpr = this.getNameExpr(scope);
            //find create preparestatement for this name expression
            return this.getUpdateSqlStatementFromPrepareStatement(precedingNodeList, namExpr);
        }
    }

    /**
     * Gets the update sql statement from prepare statement.
     *
     * @param precedingNodeList the preceding node list
     * @param preStat the pre stat
     * @return the update sql statement from prepare statement
     */
    private String getUpdateSqlStatementFromPrepareStatement(
            List<CFGNode<CodeNodeIdentifier, Expression>> precedingNodeList, NameExpr preStat) {
        int index = precedingNodeList.size() - 1;
        while (index >= 0) {
            Expression expr = precedingNodeList.get(index).getNodeData();
            if (ExpressionParser.isAssignmentExpr(expr)) {
                AssignExpr asExp = (AssignExpr) expr;
                Expression target = asExp.getTarget();
                if (target instanceof NameExpr) {
                    if (((NameExpr) target).getName().equals(preStat.getName())) {
                        //you find this
                        Expression value = asExp.getValue();
                        MethodCallExpr preDef = (MethodCallExpr) value;
                        return this.getSqlUpdateStringFromMethodCallExpr(precedingNodeList.subList(0, index),
                                preDef);
                    }
                }
            } else if (ExpressionParser.isVariableDeclarationExpr(expr)) {
                VariableDeclarationExpr vdExpr = (VariableDeclarationExpr) expr;
                List<VariableDeclarator> vars = vdExpr.getVars();
                if (vars != null) {
                    if (vars.size() == 1) {
                        VariableDeclarator varDec = vars.get(0);
                        VariableDeclaratorId varId = varDec.getId();
                        if (varId.toString().equals(preStat.getName())) {
                            //you find it
                            Expression varInit = varDec.getInit();
                            if (varInit instanceof MethodCallExpr) {
                                MethodCallExpr methodCExpr = (MethodCallExpr) varInit;
                                return this.getSqlUpdateStringFromMethodCallExpr(
                                        precedingNodeList.subList(0, index), methodCExpr);
                            }
                        }
                    }
                }
            }
            index--;
        }
        throw new RuntimeException("You cannot find this sql update statement");
    }

    /**
     * Gets the sql update string from method call expr.
     *
     * @param precedingNodeList the preceding node list
     * @param methodCExpr the method c expr
     * @return the sql update string from method call expr
     */
    private String getSqlUpdateStringFromMethodCallExpr(
            List<CFGNode<CodeNodeIdentifier, Expression>> precedingNodeList, MethodCallExpr methodCExpr) {
        List<Expression> args = methodCExpr.getArgs();
        assert (args != null);
        assert (args.size() == 1);
        Expression arg = args.get(0);
        if (arg instanceof NameExpr) {
            return this.assembleStringForNameExpr(precedingNodeList, (NameExpr) arg);
        } else {
            if (arg instanceof BinaryExpr) {
                return this.assembleStringForBinaryExpr(precedingNodeList, (BinaryExpr) arg);
            } else {
                return arg.toString();
            }
        }
    }

    /**
     * Gets the name expr.
     *
     * @param scope the scope
     * @return the name expr
     */
    private NameExpr getNameExpr(Expression scope) {
        if (scope instanceof NameExpr) {
            return (NameExpr) scope;
        } else {
            throw new RuntimeException("this expression not implemented yet " + scope.toString());
        }
    }

    //find all updating statements from a control flow graph
    /**
     * Find all sql updating statement.
     *
     * @param cfg the cfg
     * @return the list
     */
    public List<String> findAllSqlUpdatingStatement(CFGGraph<CodeNodeIdentifier, Expression> cfg) {
        List<String> updatingQueryList = new ArrayList<String>();
        //identify a function call executeUpdate
        List<CFGNode<CodeNodeIdentifier, Expression>> nodeList = cfg.getNodeListViaBFS();
        List<CFGNode<CodeNodeIdentifier, Expression>> precedingNodeList = new ArrayList<CFGNode<CodeNodeIdentifier, Expression>>();
        for (CFGNode<CodeNodeIdentifier, Expression> cfgNode : nodeList) {
            precedingNodeList.add(cfgNode);
            Expression expr = cfgNode.getNodeData();
            if (this.isExecuteUpdateMethodCallExpression(expr)) {
                Debug.println("Expr: " + expr.toString());
                String e = this.findSqlUpdatingStatement(precedingNodeList, cfgNode);
                if (e != null) {
                    Debug.println("I found a string: " + e);
                }
                updatingQueryList.add(e);
            }
        }
        return updatingQueryList;
    }

    /**
     * Creates the crdt unique insert operation.
     *
     * @param dT the d t
     * @return the operation
     */
    private Operation createCrdtUniqueInsertOperation(DatabaseTable dT) {
        UniqueInsertOperation uniqueInsertOp = new UniqueInsertOperation(dT.get_Table_Name(), dT);
        return uniqueInsertOp;
    }

    /**
     * Creates the insert operation.
     *
     * @param dT the d t
     * @return the operation
     */
    private Operation createInsertOperation(DatabaseTable dT) {
        InsertOperation insertOp = new InsertOperation(dT.get_Table_Name(), dT);
        return insertOp;
    }

    /**
     * Creates the update operation.
     *
     * @param dT the d t
     * @param updateStatement the update statement
     * @return the operation
     */
    private Operation createUpdateOperation(DatabaseTable dT, Update updateStatement) {
        List<Column> colList = updateStatement.getColumns();
        Iterator<Column> colIt = colList.iterator();
        List<DataField> dfList = new ArrayList<DataField>();
        while (colIt.hasNext()) {
            Column cL = colIt.next();
            DataField dF = dT.get_Data_Field(cL.getColumnName());
            assert (dF.isNotNormalDataType());
            dfList.add(dF);
        }
        UpdateOperation updateOp = new UpdateOperation(dT.get_Table_Name(), dT, dfList);
        return updateOp;
    }

    /**
     * Creates the delete operation.
     *
     * @param dT the d t
     * @return the operation
     */
    private Operation createDeleteOperation(DatabaseTable dT) {
        DeleteOperation deleteOp = new DeleteOperation(dT.get_Table_Name(), dT);
        return deleteOp;
    }

    //create crdt operations for a statement
    /**
     * Creates the crdt op for statement.
     *
     * @param updatingQuery the updating query
     * @return the operation
     */
    public Operation createCrdtOpForStatement(String updatingQuery) {
        updatingQuery = StringOperations.removeLastSemiColumn(updatingQuery);
        net.sf.jsqlparser.statement.Statement sqlStmt = null;
        try {
            sqlStmt = this.cJsqlParser.parse(new StringReader(updatingQuery));
        } catch (JSQLParserException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        if (sqlStmt instanceof Insert) {
            Insert insertStatement = (Insert) sqlStmt;
            String tableName = insertStatement.getTable().getName();
            DatabaseTable dTb = this.schemaParser.getTableByName(tableName);

            if (dTb == null) {
                try {
                    throw new RuntimeException("This table doesn't appear in the annotation list" + tableName);
                } catch (RuntimeException e) {
                    e.printStackTrace();
                    System.exit(RuntimeExceptionType.UNKNOWTABLENAME);
                }
            }

            if (dTb instanceof AosetTable || dTb instanceof AusetTable)
                return this.createCrdtUniqueInsertOperation(dTb);
            else if (dTb instanceof ArsetTable)
                return this.createInsertOperation(dTb);
            else {
                try {
                    throw new RuntimeException("The type of CRDT table " + dTb.get_CRDT_Table_Type()
                            + "is not supported by our framework or cannot be modified!");
                } catch (RuntimeException e) {
                    e.printStackTrace();
                    System.exit(RuntimeExceptionType.NOTDEFINEDCRDTTABLE);
                }
            }
        } else if (sqlStmt instanceof Update) {
            Update updateStatement = (Update) sqlStmt;
            String tableName = updateStatement.getTable().getName();
            DatabaseTable dTb = this.schemaParser.getTableByName(tableName);

            if (dTb == null) {
                try {
                    throw new RuntimeException("This table doesn't appear in the annotation list" + tableName);
                } catch (RuntimeException e) {
                    e.printStackTrace();
                    System.exit(RuntimeExceptionType.UNKNOWTABLENAME);
                }
            }

            if (dTb instanceof ArsetTable || dTb instanceof AusetTable || dTb instanceof UosetTable)
                return this.createUpdateOperation(dTb, updateStatement);
            else {
                try {
                    throw new RuntimeException("The type of CRDT table " + dTb.get_CRDT_Table_Type()
                            + "is not supported by our framework or cannot be modified!");
                } catch (RuntimeException e) {
                    e.printStackTrace();
                    System.exit(RuntimeExceptionType.NOTDEFINEDCRDTTABLE);
                }
            }

        } else if (sqlStmt instanceof Delete) {
            Delete deleteStatement = (Delete) sqlStmt;
            String tableName = deleteStatement.getTable().getName();
            DatabaseTable dTb = this.schemaParser.getTableByName(tableName);

            if (dTb == null) {
                try {
                    throw new RuntimeException("This table doesn't appear in the annotation list" + tableName);
                } catch (RuntimeException e) {
                    e.printStackTrace();
                    System.exit(RuntimeExceptionType.UNKNOWTABLENAME);
                }
            }

            if (dTb instanceof ArsetTable)
                return this.createDeleteOperation(dTb);
            else {
                try {
                    throw new RuntimeException("The type of CRDT table " + dTb.get_CRDT_Table_Type()
                            + "is not supported by our framework or cannot be modified!");
                } catch (RuntimeException e) {
                    e.printStackTrace();
                    System.exit(RuntimeExceptionType.NOTDEFINEDCRDTTABLE);
                }
            }
        } else {
            try {
                throw new RuntimeException("Could not identify the sql type " + updatingQuery);
            } catch (RuntimeException e) {
                e.printStackTrace();
                System.exit(RuntimeExceptionType.UNKNOWSQLQUERY);
            }
        }
        return null;
    }

    //create crdt operations for all statements for a control flow graph
    /**
     * Creates the shadow op template.
     *
     * @param cfg the cfg
     * @return the shadow operation template
     */
    public ShadowOperationTemplate createShadowOpTemplate(CFGGraph<CodeNodeIdentifier, Expression> cfg) {
        List<String> allUpdatingQueries = this.findAllSqlUpdatingStatement(cfg);
        ShadowOperationTemplate shdOpTemplate = null;
        if (allUpdatingQueries.size() > 0) {
            shdOpTemplate = new ShadowOperationTemplate();
            for (int i = 0; i < allUpdatingQueries.size(); i++) {
                String updatingQuery = allUpdatingQueries.get(i);
                //remove all double quotes
                updatingQuery = StringOperations.removeAllDoubleQuotesAndPlus(updatingQuery);
                updatingQuery = this.replaceContentAfterEqualSignFromUpdateQuery(updatingQuery);
                updatingQuery = this.replaceContentAfterValuesSignFromInsertQuery(updatingQuery);
                //System.out.println("analyze " + updatingQuery);
                Operation op = this.createCrdtOpForStatement(updatingQuery);
                shdOpTemplate.addOperation(op);
            }
        } else {
            Debug.println("No update sql statement are found");
        }
        return shdOpTemplate;
    }

    /**
     * Replace content after equal sign from update query.
     *
     * @param updatingQuery the updating query
     * @return the string
     */
    public String replaceContentAfterEqualSignFromUpdateQuery(String updatingQuery) {
        if (updatingQuery.startsWith("UPDATE") || updatingQuery.startsWith("update")) {
            String updatingQueryCopy = updatingQuery.toUpperCase();
            String _strAfterSetBeforeWhere = updatingQuery.substring(updatingQueryCopy.indexOf("SET") + 3,
                    updatingQueryCopy.indexOf("WHERE"));
            String[] subStrs = _strAfterSetBeforeWhere.split(",");
            String equalStr = "";
            for (int i = 0; i < subStrs.length; i++) {
                String _str = subStrs[i];
                if (_str.contains("=")) {
                    _str = _str.replaceAll("\\=.*", "\\=\\?");
                    if (i == 0) {
                        equalStr += _str;
                    } else {
                        equalStr += "," + _str;
                    }
                }
            }
            updatingQuery = updatingQuery.substring(0, updatingQueryCopy.indexOf("SET") + 3) + " " + equalStr
                    + updatingQuery.substring(updatingQueryCopy.indexOf("WHERE"));
            return updatingQuery;
        } else {
            return updatingQuery;
        }
    }

    public String replaceContentAfterValuesSignFromInsertQuery(String updatingQuery) {
        if (updatingQuery.startsWith("INSERT") || updatingQuery.startsWith("insert")) {
            String valueStr = updatingQuery.substring(updatingQuery.indexOf("VALUES (") + 8,
                    updatingQuery.lastIndexOf(')'));
            int numOfFields = valueStr.split(",").length;
            assert (numOfFields > 0);
            updatingQuery = updatingQuery.substring(0, updatingQuery.indexOf("VALUES (") + 8);
            for (int i = 0; i < numOfFields; i++) {
                updatingQuery += "?,";
            }
            updatingQuery = updatingQuery.substring(0, updatingQuery.length() - 1) + ")";
        }
        return updatingQuery;
    }

    public void addStatisInfo(String methodName, int numOfTemplate) {
        if (!this.statisMap.containsKey(methodName)) {
            PathTemplateNumPair pTp = new PathTemplateNumPair(0, 0);
            this.statisMap.put(methodName, pTp);
        }
        PathTemplateNumPair p = this.statisMap.get(methodName);
        p.addPathNum(1);
        p.addTemplateNum(numOfTemplate);
    }

    /**
     * Creates the all shadow op templates.
     *
     * @return the list
     */
    public List<ShadowOperationTemplate> createAllShadowOpTemplates() {
        Debug.println("----------------------------->create templates from reduced cfgs");
        List<ShadowOperationTemplate> templateList = new ArrayList<ShadowOperationTemplate>();
        for (CFGGraph<CodeNodeIdentifier, Expression> cfgGraph : this.getCfgList()) {
            Debug.println("----------> analyze one cfg");
            ShadowOperationTemplate shdOpTemplate = this.createShadowOpTemplate(cfgGraph);
            if (shdOpTemplate != null) {
                templateList.add(shdOpTemplate);
                this.addStatisInfo(cfgGraph.getCfgIdentifierPlainText(), 1);
            } else {
                Debug.println("template is empty");
                this.addStatisInfo(cfgGraph.getCfgIdentifierPlainText(), 0);
            }
            Debug.println("<---------- finish analyzing one cfg");
        }
        return templateList;
    }

    /**
     * Creates the all table variables.
     *
     * @param tableNameList the table name list
     * @return the list
     */
    private List<SingleVariableDeclaration> createAllTableVariables(HashSet<String> tableNameList) {
        List<SingleVariableDeclaration> varList = new ArrayList<SingleVariableDeclaration>();
        for (String tableName : tableNameList) {
            String tableClassName = tableName + DatabaseTableClassCreator.getTableSufixString();
            SingleVariableDeclaration varDecl = super.createVariableDeclaration(tableClassName,
                    tableClassName.toLowerCase(), false);
            varList.add(varDecl);
        }
        return varList;
    }

    /**
     * Creates the statements for unique insert operation.
     *
     * @param op the op
     * @return the linked hash map
     */
    private LinkedHashMap<Statement, List<SingleVariableDeclaration>> createStatementsForUniqueInsertOperation(
            UniqueInsertOperation op) {
        LinkedHashMap<Statement, List<SingleVariableDeclaration>> returnMap = new LinkedHashMap<Statement, List<SingleVariableDeclaration>>();
        List<SingleVariableDeclaration> varList = new ArrayList<SingleVariableDeclaration>();
        String tableInstanceName = (op.getTableName() + DatabaseTableClassCreator.getTableSufixString())
                .toLowerCase();
        String recordType = op.getTableName() + DatabaseRecordClassCreator.getRecordSufixString();
        String recordName = op.getUniqueParameterName();
        SingleVariableDeclaration recordVar = super.createVariableDeclaration(recordType, recordName, false);
        varList.add(recordVar);

        MethodInvocation methodInvocation = super.getASTNode().newMethodInvocation();
        methodInvocation.setExpression(super.getASTNode().newSimpleName(tableInstanceName));
        methodInvocation.setName(super.getASTNode().newSimpleName("uniqueInsert"));
        methodInvocation.arguments().add(super.getASTNode().newSimpleName(recordName));

        ExpressionStatement expSt = super.getASTNode().newExpressionStatement(methodInvocation);
        returnMap.put(expSt, varList);
        return returnMap;
    }

    /**
     * Creates the statements for insert operation.
     *
     * @param op the op
     * @return the linked hash map
     */
    private LinkedHashMap<Statement, List<SingleVariableDeclaration>> createStatementsForInsertOperation(
            InsertOperation op) {
        LinkedHashMap<Statement, List<SingleVariableDeclaration>> returnMap = new LinkedHashMap<Statement, List<SingleVariableDeclaration>>();
        List<SingleVariableDeclaration> varList = new ArrayList<SingleVariableDeclaration>();
        String tableInstanceName = (op.getTableName() + DatabaseTableClassCreator.getTableSufixString())
                .toLowerCase();
        String recordType = op.getTableName() + DatabaseRecordClassCreator.getRecordSufixString();
        String recordName = op.getUniqueParameterName();
        SingleVariableDeclaration recordVar = super.createVariableDeclaration(recordType, recordName, false);
        varList.add(recordVar);

        MethodInvocation methodInvocation = super.getASTNode().newMethodInvocation();
        methodInvocation.setExpression(super.getASTNode().newSimpleName(tableInstanceName));
        methodInvocation.setName(super.getASTNode().newSimpleName("insert"));
        methodInvocation.arguments().add(super.getASTNode().newSimpleName(recordName));

        ExpressionStatement expSt = super.getASTNode().newExpressionStatement(methodInvocation);
        returnMap.put(expSt, varList);
        return returnMap;
    }

    /**
     * Creates the statements for update operation.
     *
     * @param op the op
     * @return the linked hash map
     */
    private LinkedHashMap<Statement, List<SingleVariableDeclaration>> createStatementsForUpdateOperation(
            UpdateOperation op) {
        LinkedHashMap<Statement, List<SingleVariableDeclaration>> returnMap = new LinkedHashMap<Statement, List<SingleVariableDeclaration>>();
        List<SingleVariableDeclaration> varList = new ArrayList<SingleVariableDeclaration>();
        String tableInstanceName = (op.getTableName() + DatabaseTableClassCreator.getTableSufixString())
                .toLowerCase();
        String recordType = op.getTableName() + DatabaseRecordClassCreator.getRecordSufixString();
        String recordName = op.getUniqueParameterName();

        //first get this record
        MethodInvocation methodInvocation = super.getASTNode().newMethodInvocation();
        methodInvocation.setExpression(super.getASTNode().newSimpleName(tableInstanceName));
        methodInvocation.setName(super.getASTNode().newSimpleName("getRecord"));
        //get primary key from table
        List<DataField> pkList = this.schemaParser.getTableByName(op.getTableName()).getPrimaryKeyDataFieldList();
        for (DataField pk : pkList) {
            String paraName = op.getUniqueParameterName();
            methodInvocation.arguments().add(super.getASTNode().newSimpleName(paraName));
            SingleVariableDeclaration var = super.createVariableDeclaration(
                    CrdtFactory.getProperCrdtObject(pk.get_Crdt_Data_Type(), pk.get_Data_Type()), paraName, false);
            varList.add(var);
        }
        VariableDeclarationStatement varDeclStmt = super.createVariableDeclarationStatement(recordType, recordName,
                false, methodInvocation);
        returnMap.put(varDeclStmt, varList);

        List<DataField> modifiedDfList = op.getModifiedDataFields();
        for (DataField df : modifiedDfList) {
            List<SingleVariableDeclaration> newVarList = new ArrayList<SingleVariableDeclaration>();
            String paraName = op.getUniqueParameterName();
            MethodInvocation recordMInvoc = super.getASTNode().newMethodInvocation();
            recordMInvoc.setExpression(super.getASTNode().newSimpleName(recordName));
            recordMInvoc.setName(super.getASTNode().newSimpleName("update" + df.get_Data_Field_Name()));
            if (CrdtFactory.isLwwType(df.get_Crdt_Data_Type())) {
                recordMInvoc.arguments().add(super.getASTNode().newSimpleName(paraName));
                recordMInvoc.arguments().add(super.getASTNode().newSimpleName(LWWLTS_VALUE));
            } else {
                recordMInvoc.arguments().add(super.getASTNode().newSimpleName(paraName));
            }
            SingleVariableDeclaration var = super.createVariableDeclaration(
                    CrdtFactory.getProperCrdtObject(df.get_Crdt_Data_Type(), df.get_Data_Type()), paraName, false);
            newVarList.add(var);

            ExpressionStatement recordExpSt = super.getASTNode().newExpressionStatement(recordMInvoc);
            returnMap.put(recordExpSt, newVarList);
        }
        //update deleteflag
        if (this.schemaParser.getTableByName(op.getTableName()) instanceof ArsetTable) {
            List<SingleVariableDeclaration> flagVarList = new ArrayList<SingleVariableDeclaration>();
            MethodInvocation recordFlagMInvoc = super.getASTNode().newMethodInvocation();
            recordFlagMInvoc.setExpression(super.getASTNode().newSimpleName(recordName));
            recordFlagMInvoc.setName(super.getASTNode().newSimpleName("undelete"
                    + this.schemaParser.getTableByName(op.getTableName()).getDeletedFlag().get_Data_Field_Name()));
            recordFlagMInvoc.arguments().add(super.getASTNode().newSimpleName(LWWLTS_VALUE));
            ExpressionStatement flagExpSt = super.getASTNode().newExpressionStatement(recordFlagMInvoc);
            returnMap.put(flagExpSt, flagVarList);
        }

        //update lww
        List<SingleVariableDeclaration> flagVarList = new ArrayList<SingleVariableDeclaration>();
        MethodInvocation recordFlagMInvoc = super.getASTNode().newMethodInvocation();
        recordFlagMInvoc.setExpression(super.getASTNode().newSimpleName(recordName));
        recordFlagMInvoc.setName(super.getASTNode().newSimpleName(
                "update" + this.schemaParser.getTableByName(op.getTableName()).getLwwTs().get_Data_Field_Name()));
        recordFlagMInvoc.arguments().add(super.getASTNode().newSimpleName(LWWLTS_VALUE));
        ExpressionStatement flagExpSt = super.getASTNode().newExpressionStatement(recordFlagMInvoc);
        returnMap.put(flagExpSt, flagVarList);
        return returnMap;
    }

    /**
     * Creates the statements for delete operation.
     *
     * @param op the op
     * @return the linked hash map
     */
    private LinkedHashMap<Statement, List<SingleVariableDeclaration>> createStatementsForDeleteOperation(
            DeleteOperation op) {
        LinkedHashMap<Statement, List<SingleVariableDeclaration>> returnMap = new LinkedHashMap<Statement, List<SingleVariableDeclaration>>();
        List<SingleVariableDeclaration> varList = new ArrayList<SingleVariableDeclaration>();
        String tableInstanceName = (op.getTableName() + DatabaseTableClassCreator.getTableSufixString())
                .toLowerCase();

        MethodInvocation methodInvocation = super.getASTNode().newMethodInvocation();
        methodInvocation.setExpression(super.getASTNode().newSimpleName(tableInstanceName));
        methodInvocation.setName(super.getASTNode().newSimpleName("delete"));
        //get primary key from table
        List<DataField> pkList = this.schemaParser.getTableByName(op.getTableName()).getPrimaryKeyDataFieldList();
        for (DataField pk : pkList) {
            String paraName = op.getUniqueParameterName();
            methodInvocation.arguments().add(super.getASTNode().newSimpleName(paraName));
            SingleVariableDeclaration var = super.createVariableDeclaration(
                    CrdtFactory.getProperCrdtObject(pk.get_Crdt_Data_Type(), pk.get_Data_Type()), paraName, false);
            varList.add(var);
        }
        methodInvocation.arguments().add(super.getASTNode().newSimpleName(LWWLTS_VALUE));
        ExpressionStatement expSt = super.getASTNode().newExpressionStatement(methodInvocation);
        returnMap.put(expSt, varList);
        return returnMap;
    }

    /**
     * Generate code for shadow op template.
     *
     * @param shdOpTemplate the shd op template
     * @return the method declaration
     */
    private MethodDeclaration generateCodeForShadowOpTemplate(ShadowOperationTemplate shdOpTemplate) {
        String templateName = shdOpTemplate.getUniqueTemplateId();
        MethodDeclaration methodDeclaration = super.createMethodDeclaration(PrimitiveType.VOID, templateName,
                ModifierKeyword.PUBLIC_KEYWORD);
        String requireSpecs = JahobSpecsUtil.requirePrefix;
        String modifySpecs = JahobSpecsUtil.modifyPrefix;
        String ensureSpecs = JahobSpecsUtil.ensurePrefix;
        org.eclipse.jdt.core.dom.Block block = super.getASTNode().newBlock();
        List<Operation> opList = shdOpTemplate.getCrdtOpList();
        HashSet<String> tableNameList = new HashSet<String>();
        List<Statement> statementList = new ArrayList<Statement>();
        List<SingleVariableDeclaration> varList = new ArrayList<SingleVariableDeclaration>();
        List<String> insertTables = new ArrayList<String>();
        List<String> deleteTables = new ArrayList<String>();
        List<DataField> updateFields = new ArrayList<DataField>();
        for (int i = 0; i < opList.size(); i++) {
            Operation op = opList.get(i);
            tableNameList.add(op.getTableName());
            LinkedHashMap<Statement, List<SingleVariableDeclaration>> returnValue = null;
            if (op instanceof UniqueInsertOperation) {
                returnValue = this.createStatementsForUniqueInsertOperation((UniqueInsertOperation) op);
                insertTables.add(op.getTableName());
            } else if (op instanceof InsertOperation) {
                returnValue = this.createStatementsForInsertOperation((InsertOperation) op);
                insertTables.add(op.getTableName());
                updateFields.addAll(op.getTableInstance().getModifiableDataFieldList());
            } else if (op instanceof UpdateOperation) {
                returnValue = this.createStatementsForUpdateOperation((UpdateOperation) op);
                updateFields.addAll(((UpdateOperation) op).getModifiedDataFields());
            } else if (op instanceof DeleteOperation) {
                returnValue = this.createStatementsForDeleteOperation((DeleteOperation) op);
                deleteTables.add(op.getTableName());
            } else {
                throw new RuntimeException("can not be here");
            }

            Iterator<Entry<Statement, List<SingleVariableDeclaration>>> it = returnValue.entrySet().iterator();
            while (it.hasNext()) {
                Entry<Statement, List<SingleVariableDeclaration>> itEntry = it.next();
                statementList.add(itEntry.getKey());
                varList.addAll(itEntry.getValue());
            }
        }
        //get table vars
        List<String> missingTables = JahobSpecsUtil.findMissingTableForInvariants(tableNameList,
                this.getInvParser().getAllTables());
        tableNameList.addAll(missingTables);
        List<SingleVariableDeclaration> tableVars = this.createAllTableVariables(tableNameList);
        //requireSpecs += JahobSpecsUtil.getAllTableInitAndNotNull(tableVars);
        String invSpecs = JahobSpecsUtil.getInvSpecs(this.getInvParser().getInvariants(), tableVars);
        tableVars.addAll(varList);
        //requireSpecs += " & " + JahobSpecsUtil.getAllArgumentsNotNull(varList);
        for (SingleVariableDeclaration var : tableVars) {
            methodDeclaration.parameters().add(var);
        }
        //add the logical timestamp var
        SingleVariableDeclaration lwwLts = super.createVariableDeclaration(
                CrdtFactory.getLwwLogicalTimestampCrdtTypeString(), LWWLTS_VALUE, false);
        methodDeclaration.parameters().add(lwwLts);
        block.statements().addAll(statementList);
        methodDeclaration.setBody(block);

        List<String> specs = new ArrayList<String>();
        //requireSpecs += " & " + JahobSpecsUtil.getRequireNotNullClause(LWWLTS_VALUE);
        //requireSpecs += " & " +invSpecs + "\"";
        requireSpecs += invSpecs + "\"";
        modifySpecs += JahobSpecsUtil.getModifyClauseForTemplate(insertTables, deleteTables, updateFields);
        specs.add(requireSpecs);
        specs.add(modifySpecs);
        ensureSpecs += invSpecs + "\"";
        specs.add(ensureSpecs);
        this.methodSpecs.put(templateName, specs);
        return methodDeclaration;
    }

    /* (non-Javadoc)
     * @see staticanalysis.templatecreator.SourceCodeGenerator#generateCode()
     */
    /**
     * Generate code.
     *
     * @see staticanalysis.templatecreator.SourceCodeGenerator#generateCode()
     */
    @Override
    public void generateCode() {
        //first generate a class type
        TypeDeclaration type = this.createClass();

        List<ShadowOperationTemplate> templateList = this.createAllShadowOpTemplates();
        this.tList = templateList;
        for (int i = 0; i < templateList.size(); i++) {
            ShadowOperationTemplate shdOpTemplate = templateList.get(i);
            Debug.println("create template now");
            MethodDeclaration methodDecl = this.generateCodeForShadowOpTemplate(shdOpTemplate);
            type.bodyDeclarations().add(methodDecl);
        }
        super.addTypeDeclaration(type);
        super.writeToFile();

        //append specs
        super.reloadFileToFileContents();
        this.appendAllSpecs();
        super.writeToFileFromFileContents();
    }

    private String getWPFileName() {
        return this.getProjectName() + "_sieve_input.txt";
    }

    private String getWPFileFullPath() {
        String fileName = this.getWPFileName();
        return this.getCodePath() + "/" + fileName;
    }

    private void generateSieveInput() {
        String filePath = this.getWPFileFullPath();
        List<String> outputStrs = new ArrayList<String>();
        for (int i = 0; i < this.tList.size(); i++) {
            ShadowOperationTemplate shdOpTemplate = this.tList.get(i);
            shdOpTemplate.setSignature();
            //generate the signature
            String fingerPrint = shdOpTemplate.getFingerPrint();
            //read the file output by Jahob
            String wpFileName = this.getCodePath() + "/" + "sifter_shadowOptemplate_template"
                    + shdOpTemplate.getShdOpTemplateId() + ".vc";
            //generate a key pair (signature, formula)
            String wpStr = FileOperations.readFirstLineFromFile(wpFileName);
            outputStrs.add(fingerPrint + "\n" + StaticFPtoWPsStore.openerOfWeakestPrecondition + wpStr + "\n");
        }
        FileOperations.createFileByGivenFilePath(filePath);
        FileOperations.writeToFile(filePath, outputStrs);
    }

    public void printOutStatis() {
        Iterator it = this.statisMap.entrySet().iterator();
        int numOfTotalPath = 0;
        int numOfTotalTemplate = 0;
        while (it.hasNext()) {
            Map.Entry<String, PathTemplateNumPair> en = (Entry<String, PathTemplateNumPair>) it.next();
            String outputStr = en.getKey() + " & " + en.getValue().getNumOfPath() + " & "
                    + en.getValue().getNumOfTemplate();
            numOfTotalPath += en.getValue().getNumOfPath();
            numOfTotalTemplate += en.getValue().getNumOfTemplate();
            System.out.println(outputStr);
        }
        System.out.println("Generating " + numOfTotalPath + " paths " + numOfTotalTemplate + " templates");
    }

    /* (non-Javadoc)
     * @see staticanalysis.templatecreator.SourceCodeGenerator#createConstructorDeclaration()
     */
    /**
     * Creates the constructor declaration.
     *
     * @return the method declaration
     * @see staticanalysis.templatecreator.SourceCodeGenerator#createConstructorDeclaration()
     */
    @Override
    public MethodDeclaration createConstructorDeclaration() {
        // TODO Auto-generated method stub
        return null;
    }

    /* (non-Javadoc)
     * @see staticanalysis.templatecreator.SourceCodeGenerator#createFields()
     */
    /**
     * Creates the fields.
     *
     * @return the list
     * @see staticanalysis.templatecreator.SourceCodeGenerator#createFields()
     */
    @Override
    public List<FieldDeclaration> createFields() {
        // TODO Auto-generated method stub
        return null;
    }

    /* (non-Javadoc)
     * @see staticanalysis.templatecreator.SourceCodeGenerator#createFunctions()
     */
    /**
     * Creates the functions.
     *
     * @return the list
     * @see staticanalysis.templatecreator.SourceCodeGenerator#createFunctions()
     */
    @Override
    public List<MethodDeclaration> createFunctions() {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * Gets the schema parser.
     *
     * @return the schema parser
     */
    public SchemaParser getSchemaParser() {
        return schemaParser;
    }

    /**
     * Sets the schema parser.
     *
     * @param schemaParser the new schema parser
     */
    public void setSchemaParser(SchemaParser schemaParser) {
        this.schemaParser = schemaParser;
    }

    /**
     * Append all specs.
     */
    public void appendAllSpecs() {
        //insert all your method specs
        Iterator<Entry<String, List<String>>> it = this.methodSpecs.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, List<String>> entry = it.next();
            String methodName = entry.getKey();
            int insertIndex = super.findMethodBodyOffset(methodName);
            String methodSpecs = super.mergeMultipleSpecifications(entry.getValue());
            super.appendStringListToOffset(insertIndex, methodSpecs);
        }
    }

    /* (non-Javadoc)
     * @see staticanalysis.templatecreator.SourceCodeGenerator#generateAndExecuteJahobCommand()
     */
    @Override
    public void generateAndExecuteJahobCommand() {
        List<String> commands = new ArrayList<String>();
        commands.add(this.getJahobCommand());
        String shellScript = FileOperations.createShellScript(this.getCodePath(), "run" + this.getClassName(),
                commands);
        FileOperations.executeShellCommands(shellScript);
        this.generateSieveInput();
    }

    /* (non-Javadoc)
     * @see staticanalysis.templatecreator.SourceCodeGenerator#getJahobCommand()
     */
    @Override
    public String getJahobCommand() {
        return JahobSpecsUtil.getTableVerificationExecCommandForTemplate(this.getFullFilePath(), this.getCodePath(),
                this.schemaParser);
    }

    /**
     * Gets the inv parser.
     *
     * @return the invParser
     */
    public InvariantParser getInvParser() {
        return invParser;
    }

    /**
     * Sets the inv parser.
     *
     * @param invParser the invParser to set
     */
    public void setInvParser(InvariantParser invParser) {
        this.invParser = invParser;
    }

    /** This class is used to store the path and template numbers for a method*/
    public class PathTemplateNumPair {
        int numOfPath;
        int numOfTemplate;

        PathTemplateNumPair(int nOfPath, int nOfTemplate) {
            this.numOfPath = nOfPath;
            this.numOfTemplate = nOfTemplate;
        }

        public void addPathNum(int n) {
            this.numOfPath = this.numOfPath + n;
        }

        public void addTemplateNum(int t) {
            this.numOfTemplate = this.numOfTemplate + t;
        }

        public int getNumOfPath() {
            return this.numOfPath;
        }

        public int getNumOfTemplate() {
            return this.numOfTemplate;
        }
    }

}