Package edu.brown.terminal

Source Code of edu.brown.terminal.TokenCompletor

package edu.brown.terminal;

import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Pattern;

import jline.Completor;

import org.apache.log4j.Logger;
import org.hsqldb.Tokens;
import org.voltdb.catalog.Catalog;
import org.voltdb.catalog.Column;
import org.voltdb.catalog.Database;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Table;
import org.voltdb.types.QueryType;

import edu.brown.catalog.CatalogUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.utils.CollectionUtil;
import edu.brown.utils.StringUtil;

/**
* This is a class that holds a list of the table names for an instance of HStore
* @author gen
* @author pavlo
*/
public class TokenCompletor implements Completor {
    private static final Logger LOG = Logger.getLogger(TokenCompletor.class);
    private static final LoggerBoolean debug = new LoggerBoolean();

    protected static final String DELIMITER = " ";
    protected static final Pattern SPLIT = Pattern.compile("[" + DELIMITER + "]+");
   
    private static final String TABLE_PREFIXES[] = {
        "UPDATE",
        "FROM",
        "DESCRIBE"
    };
    private static final String COLUMN_PREFIXES[] = {
        "WHERE",
        "SET"
    };
    private static final String PROC_PREFIXES[] = {
        "EXEC"
    };
   
   
    final Catalog catalog;
   
    final SortedSet<String> emptyTokens = new TreeSet<String>();
    final SortedSet<String> allTokens = new TreeSet<String>();
    final SortedSet<String> sqlTokens = new TreeSet<String>();
    final SortedSet<String> specialTokens = new TreeSet<String>();
    final SortedSet<String> commandTokens = new TreeSet<String>();
    final SortedSet<String> tableTokens = new TreeSet<String>();
    final SortedSet<String> columnTokens = new TreeSet<String>();
    final SortedSet<String> procTokens = new TreeSet<String>();
   
    final Set<String> tablePrefixes = new HashSet<String>();
    final Set<String> columnPrefixes = new HashSet<String>();
    final Set<String> procPrefixes = new HashSet<String>();
   
    final Map<String, String> tokenCaseSensitive = new HashMap<String, String>();
   
    public TokenCompletor(Catalog catalog) throws Exception {
        this.catalog = catalog;
        Database catalog_db = CatalogUtil.getDatabase(catalog);
       
        // Core SQL Reserved Words from HSQLDB
        for (int i = 0; i < 1000; i++) {
            if (Tokens.isCoreKeyword(i)) {
                String keyword = Tokens.getKeyword(i);
                if (keyword != null) this.sqlTokens.add(keyword);
            }
        } // FOR

        // Special command tokens
        for (QueryType qtype : QueryType.values()) {
            if (qtype == QueryType.INVALID || qtype == QueryType.NOOP) continue;
            this.commandTokens.add(qtype.name());
        } // FOR
        for (HStoreTerminal.Command c : HStoreTerminal.Command.values()) {
            this.commandTokens.add(c.name());
            this.specialTokens.add(c.name());
        } // FOR
       
        // Catalog Keywords
        // Tables, columns, procedures names
        CollectionUtil.addAll(this.tablePrefixes, TABLE_PREFIXES);
        CollectionUtil.addAll(this.columnPrefixes, COLUMN_PREFIXES);
        for (Table catalog_tbl : CatalogUtil.getDataTables(catalog_db)) {
            this.tableTokens.add(catalog_tbl.getName());
            this.columnPrefixes.add(catalog_tbl.getName() + ".");
            for (Column catalog_col : catalog_tbl.getColumns()) {
                this.columnTokens.add(catalog_col.getName().toUpperCase());
            } // FOR
        } // FOR
       
        CollectionUtil.addAll(this.procPrefixes, PROC_PREFIXES);
        for (Procedure catalog_proc : catalog_db.getProcedures()) {
            String procName = catalog_proc.getName().toUpperCase();
            this.tokenCaseSensitive.put(procName, catalog_proc.getName());
            this.procTokens.add(procName);
        } // FOR
       
        this.allTokens.addAll(this.sqlTokens);
        this.allTokens.addAll(this.tableTokens);
        this.allTokens.addAll(this.columnTokens);
        this.allTokens.addAll(this.procTokens);
       
        if (debug.val)
            LOG.debug("Token Information:\n" + this.toString());
    }
   
    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    public int complete(String buffer, int cursor, List clist) {
        if (buffer == null || buffer.isEmpty()) {
            clist.addAll(this.commandTokens);
            return (0);
        }
       
        // Find the current token up to the previous space
        int lastIndex = buffer.lastIndexOf(DELIMITER);
        String tokens[] = SPLIT.split(buffer);
        String last = tokens[tokens.length - 1].trim().toUpperCase();
       
        if (debug.val) {
            LOG.debug("BUFFER: '" + buffer + "'");
            LOG.debug("CURSOR: " + cursor);
            LOG.debug("TOKENS: " + Arrays.toString(tokens));
        }
       
        // Figure out whether they are trying to enter in a SQL
        // token, or a name of an element in the database
        String prevToken = null;
        if (buffer.endsWith(DELIMITER) || tokens.length == 1) {
            prevToken = last;
        } else {
            prevToken = tokens[tokens.length-2].toUpperCase();
        }
        prevToken = prevToken.trim().toUpperCase();
       
        if (debug.val) LOG.debug("PREV: " + prevToken);
       
        // The first token must always be a SQL command token
        // Otherwise, check which candidates to use based on
        // what's in the previous token
        SortedSet<String> candidates = (tokens.length == 1 ? this.commandTokens : this.sqlTokens);
       
        // Check whether the buffer is "EXEC <ProcedureName>"
        // If it is, then we don't want to return any tokens for now
        // Ideally we want to be able to print the parameter info for this procedure
        if (tokens.length >= 2 &&
            tokens[0].equalsIgnoreCase(HStoreTerminal.Command.EXEC.name()) &&
            this.procTokens.contains(tokens[1].toUpperCase())) {
            if (debug.val) LOG.debug("EXEC COMMAND: '" + buffer + "'");
            candidates = this.emptyTokens;
        }
        // TABLE
        else if (this.tablePrefixes.contains(prevToken)) {
            if (debug.val) LOG.debug("TABLE PREFIX: '" + prevToken + "'");
            candidates = this.tableTokens;
        }
        // COLUMN
        else if (this.columnPrefixes.contains(prevToken)) {
            if (debug.val) LOG.debug("COLUMN PREFIX: " + prevToken);
            candidates = this.columnTokens;
        }
        // PROCEDURE
        else if (this.procPrefixes.contains(prevToken)) {
            if (debug.val) LOG.debug("PROC PREFIX: " + prevToken);
            candidates = this.procTokens;
        } else if (debug.val) {
            LOG.debug("Using all candidates!");
        }
        assert(candidates != null);
        if (debug.val) LOG.debug("CANDIDATES: " + candidates);
       
        if (buffer.endsWith(DELIMITER)) {
            for (String can : candidates) {
                if (this.tokenCaseSensitive.containsKey(can)) {
                    can = this.tokenCaseSensitive.get(can);
                }
                clist.add(can);
            } // FOR
           
        } else {
            Collection<String> matches = candidates.tailSet(last);
            if (debug.val) LOG.debug("MATCHES: " + matches);
            for (String can : matches) {
                if (debug.val) LOG.debug("Candidate: " + can);
   
                if (can.startsWith(last) == false || can.equalsIgnoreCase(last)) {
                    if (debug.val) LOG.debug("Invalid match!");
                    break;
                }
               
                // Fix capitalization
                if (this.tokenCaseSensitive.containsKey(can)) {
                    can = this.tokenCaseSensitive.get(can);
                }
               
                int index = can.indexOf(DELIMITER, cursor);
                if (index != -1) {
                    can = can.substring(0, index + 1);
                }
                clist.add(can);
            } // FOR
        }

        if (clist.size() == 1) {
            clist.set(0, ((String) clist.get(0)) + " ");
        }

        return (clist.size() == 0 ? -1 : lastIndex+1);
    }
   
    @Override
    public String toString() {
        Class<?> clazz = this.getClass();
        Map<String, Object> m = new LinkedHashMap<String, Object>();
        for (Field f : clazz.getDeclaredFields()) {
            if (f.getName().equalsIgnoreCase("catalog")) continue;
            if (f.getName().equalsIgnoreCase("allTokens")) continue;
           
            Object obj = null;
            try {
                obj = f.get(this);
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            }
            m.put(f.getName(), obj);
        } // FOR
        return StringUtil.formatMaps(m);
    }
   
}
TOP

Related Classes of edu.brown.terminal.TokenCompletor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.