package lucli; /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Iterator; import java.util.Set; import java.util.StringTokenizer; import java.util.TreeMap; import jline.ArgumentCompletor; import jline.Completor; import jline.ConsoleReader; import jline.FileNameCompletor; import jline.History; import jline.SimpleCompletor; import org.apache.lucene.queryParser.ParseException; /** * Main class for lucli: the Lucene Command Line Interface. * This class handles mostly the actual CLI part, command names, help, etc. */ public class Lucli { final static String DEFAULT_INDEX = "index"; //directory "index" under the current directory final static String HISTORYFILE = ".lucli"; //history file in user's home directory public final static int MAX_TERMS = 100; //Maximum number of terms we're going to show // List of commands // To add another command, add it in here, in the list of addcomand(), and in the switch statement final static int NOCOMMAND = -2; final static int UNKOWN = -1; final static int INFO = 0; final static int SEARCH = 1; final static int OPTIMIZE = 2; final static int QUIT = 3; final static int HELP = 4; final static int COUNT = 5; final static int TERMS = 6; final static int INDEX = 7; final static int TOKENS = 8; final static int EXPLAIN = 9; final static int ANALYZER = 10; String historyFile; TreeMap<String,Command> commandMap = new TreeMap<String,Command>(); LuceneMethods luceneMethods; //current cli class we're using boolean enableReadline; //false: use plain java. True: shared library readline /** Main entry point. The first argument can be a filename with an application initialization file. */ public Lucli(String[] args) throws IOException { String line; historyFile = System.getProperty("user.home") + File.separator + HISTORYFILE; /* * Initialize the list of commands */ addCommand("info", INFO, "Display info about the current Lucene index. Example: info"); addCommand("search", SEARCH, "Search the current index. Example: search foo", 1); addCommand("count", COUNT, "Return the number of hits for a search. Example: count foo", 1); addCommand("optimize", OPTIMIZE, "Optimize the current index"); addCommand("quit", QUIT, "Quit/exit the program"); addCommand("help", HELP, "Display help about commands"); addCommand("terms", TERMS, "Show the first " + MAX_TERMS + " terms in this index. Supply a field name to only show terms in a specific field. Example: terms"); addCommand("index", INDEX, "Choose a different lucene index. Example index my_index", 1); addCommand("tokens", TOKENS, "Does a search and shows the top 10 tokens for each document. Verbose! Example: tokens foo", 1); addCommand("explain", EXPLAIN, "Explanation that describes how the document scored against query. Example: explain foo", 1); addCommand("analyzer", ANALYZER, "Specifies the Analyzer class to be used. Example: analyzer org.apache.lucene.analysis.SimpleAnalyzer", 1); //parse command line arguments parseArgs(args); ConsoleReader cr = new ConsoleReader(); //Readline.readHistoryFile(fullPath); cr.setHistory(new History(new File(historyFile))); // set completer with list of words Completor[] comp = new Completor[]{ new SimpleCompletor(getCommandsAsArray()), new FileNameCompletor() }; cr.addCompletor (new ArgumentCompletor(comp)); // main input loop luceneMethods = new LuceneMethods(DEFAULT_INDEX); while (true) { try { line = cr.readLine("lucli> "); if (line != null) { handleCommand(line, cr); } } catch (java.io.EOFException eof) { System.out.println("");//new line exit(); } catch (UnsupportedEncodingException enc) { enc.printStackTrace(System.err); } catch (ParseException pe) { pe.printStackTrace(System.err); } catch (IOException ioe) { ioe.printStackTrace(System.err); } } } private String[] getCommandsAsArray() { Set<String> commandSet = commandMap.keySet(); String[] commands = new String[commandMap.size()]; int i = 0; for (Iterator<String> iter = commandSet.iterator(); iter.hasNext();) { String cmd = iter.next(); commands[i++] = cmd; } return commands; } public static void main(String[] args) throws IOException { new Lucli(args); } private void handleCommand(String line, ConsoleReader cr) throws IOException, ParseException { String [] words = tokenizeCommand(line); if (words.length == 0) return; //white space String query = ""; if (line.trim().startsWith("#")) // # = comment return; //Command name and number of arguments switch (getCommandId(words[0], words.length - 1)) { case INFO: luceneMethods.info(); break; case SEARCH: for (int ii = 1; ii < words.length; ii++) { query += words[ii] + " "; } luceneMethods.search(query, false, false, cr); break; case COUNT: for (int ii = 1; ii < words.length; ii++) { query += words[ii] + " "; } luceneMethods.count(query); break; case QUIT: exit(); break; case TERMS: if(words.length > 1) luceneMethods.terms(words[1]); else luceneMethods.terms(null); break; case INDEX: LuceneMethods newLm = new LuceneMethods(words[1]); try { newLm.info(); //will fail if can't open the index luceneMethods = newLm; //OK, so we'll use the new one } catch (IOException ioe) { //problem we'll keep using the old one error(ioe.toString()); } break; case OPTIMIZE: luceneMethods.optimize(); break; case TOKENS: for (int ii = 1; ii < words.length; ii++) { query += words[ii] + " "; } luceneMethods.search(query, false, true, cr); break; case EXPLAIN: for (int ii = 1; ii < words.length; ii++) { query += words[ii] + " "; } luceneMethods.search(query, true, false, cr); break; case ANALYZER: luceneMethods.analyzer(words[1]); break; case HELP: help(); break; case NOCOMMAND: //do nothing break; case UNKOWN: System.out.println("Unknown command: " + words[0] + ". Type help to get a list of commands."); break; } } private String [] tokenizeCommand(String line) { StringTokenizer tokenizer = new StringTokenizer(line, " \t"); int size = tokenizer.countTokens(); String [] tokens = new String[size]; for (int ii = 0; tokenizer.hasMoreTokens(); ii++) { tokens[ii] = tokenizer.nextToken(); } return tokens; } private void exit() { System.exit(0); } /** * Add a command to the list of commands for the interpreter for a * command that doesn't take any parameters. * @param name - the name of the command * @param id - the unique id of the command * @param help - the help message for this command */ private void addCommand(String name, int id, String help) { addCommand(name, id, help, 0); } /** * Add a command to the list of commands for the interpreter. * @param name - the name of the command * @param id - the unique id of the command * @param help - the help message for this command * @param params - the minimum number of required params if any */ private void addCommand(String name, int id, String help, int params) { Command command = new Command(name, id, help, params); commandMap.put(name, command); } private int getCommandId(String name, int params) { name = name.toLowerCase(); //treat uppercase and lower case commands the same Command command = commandMap.get(name); if (command == null) { return(UNKOWN); } else { if(command.params > params) { error(command.name + " needs at least " + command.params + " arguments."); return (NOCOMMAND); } return (command.id); } } private void help() { Iterator<String> commands = commandMap.keySet().iterator(); while (commands.hasNext()) { Command command = commandMap.get(commands.next()); System.out.println("\t" + command.name + ": " + command.help); } } private void error(String message) { System.err.println("Error:" + message); } private void message(String text) { System.out.println(text); } /* * Parse command line arguments (currently none) */ private void parseArgs(String[] args) { if (args.length > 0) { usage(); System.exit(1); } } private void usage() { message("Usage: lucli.Lucli"); message("(currently, no parameters are supported)"); } private class Command { String name; int id; String help; int params; Command(String name, int id, String help, int params) { this.name = name; this.id = id; this.help = help; this.params = params; } /** * Prints out a usage message for this command. */ public String commandUsage() { return (name + ":" + help + ". Command takes " + params + " params"); } } }