001: package lucli;
002:
003: /* ====================================================================
004: * The Apache Software License, Version 1.1
005: *
006: * Copyright (c) 2001 The Apache Software Foundation. All rights
007: * reserved.
008: *
009: * Redistribution and use in source and binary forms, with or without
010: * modification, are permitted provided that the following conditions
011: * are met:
012: *
013: * 1. Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * 2. Redistributions in binary form must reproduce the above copyright
017: * notice, this list of conditions and the following disclaimer in
018: * the documentation and/or other materials provided with the
019: * distribution.
020: *
021: * 3. The end-user documentation included with the redistribution,
022: * if any, must include the following acknowledgment:
023: * "This product includes software developed by the
024: * Apache Software Foundation (http://www.apache.org/)."
025: * Alternately, this acknowledgment may appear in the software itself,
026: * if and wherever such third-party acknowledgments normally appear.
027: *
028: * 4. The names "Apache" and "Apache Software Foundation" and
029: * "Apache Lucene" must not be used to endorse or promote products
030: * derived from this software without prior written permission. For
031: * written permission, please contact apache@apache.org.
032: *
033: * 5. Products derived from this software may not be called "Apache",
034: * "Apache Lucene", nor may "Apache" appear in their name, without
035: * prior written permission of the Apache Software Foundation.
036: *
037: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
038: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
039: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
040: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
041: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
042: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
043: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
044: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
045: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
046: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
047: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
048: * SUCH DAMAGE.
049: * ====================================================================
050: *
051: * This software consists of voluntary contributions made by many
052: * individuals on behalf of the Apache Software Foundation. For more
053: * information on the Apache Software Foundation, please see
054: * <http://www.apache.org/>.
055: */
056:
057: import java.io.File;
058: import java.io.IOException;
059: import java.io.UnsupportedEncodingException;
060: import java.util.Iterator;
061: import java.util.Set;
062: import java.util.StringTokenizer;
063: import java.util.TreeMap;
064:
065: import jline.ArgumentCompletor;
066: import jline.Completor;
067: import jline.ConsoleReader;
068: import jline.FileNameCompletor;
069: import jline.History;
070: import jline.SimpleCompletor;
071:
072: import org.apache.lucene.queryParser.ParseException;
073:
074: /**
075: * Main class for lucli: the Lucene Command Line Interface.
076: * This class handles mostly the actual CLI part, command names, help, etc.
077: */
078: public class Lucli {
079:
080: final static String DEFAULT_INDEX = "index"; //directory "index" under the current directory
081: final static String HISTORYFILE = ".lucli"; //history file in user's home directory
082: public final static int MAX_TERMS = 100; //Maximum number of terms we're going to show
083:
084: // List of commands
085: // To add another command, add it in here, in the list of addcomand(), and in the switch statement
086: final static int NOCOMMAND = -2;
087: final static int UNKOWN = -1;
088: final static int INFO = 0;
089: final static int SEARCH = 1;
090: final static int OPTIMIZE = 2;
091: final static int QUIT = 3;
092: final static int HELP = 4;
093: final static int COUNT = 5;
094: final static int TERMS = 6;
095: final static int INDEX = 7;
096: final static int TOKENS = 8;
097: final static int EXPLAIN = 9;
098:
099: String historyFile;
100: TreeMap commandMap = new TreeMap();
101: LuceneMethods luceneMethods; //current cli class we're using
102: boolean enableReadline; //false: use plain java. True: shared library readline
103:
104: /**
105: Main entry point. The first argument can be a filename with an
106: application initialization file.
107: */
108:
109: public Lucli(String[] args) throws IOException {
110: String line;
111:
112: historyFile = System.getProperty("user.home") + File.separator
113: + HISTORYFILE;
114:
115: /*
116: * Initialize the list of commands
117: */
118: addCommand("info", INFO,
119: "Display info about the current Lucene index. Example: info");
120: addCommand("search", SEARCH,
121: "Search the current index. Example: search foo", 1);
122: addCommand(
123: "count",
124: COUNT,
125: "Return the number of hits for a search. Example: count foo",
126: 1);
127: addCommand("optimize", OPTIMIZE, "Optimize the current index");
128: addCommand("quit", QUIT, "Quit/exit the program");
129: addCommand("help", HELP, "Display help about commands");
130: addCommand(
131: "terms",
132: TERMS,
133: "Show the first "
134: + MAX_TERMS
135: + " terms in this index. Supply a field name to only show terms in a specific field. Example: terms");
136: addCommand(
137: "index",
138: INDEX,
139: "Choose a different lucene index. Example index my_index",
140: 1);
141: addCommand(
142: "tokens",
143: TOKENS,
144: "Does a search and shows the top 10 tokens for each document. Verbose! Example: tokens foo",
145: 1);
146: addCommand(
147: "explain",
148: EXPLAIN,
149: "Explanation that describes how the document scored against query. Example: explain foo",
150: 1);
151:
152: //parse command line arguments
153: parseArgs(args);
154:
155: ConsoleReader cr = new ConsoleReader();
156: //Readline.readHistoryFile(fullPath);
157: cr.setHistory(new History(new File(historyFile)));
158:
159: // set completer with list of words
160: Completor[] comp = new Completor[] {
161: new SimpleCompletor(getCommandsAsArray()),
162: new FileNameCompletor() };
163: cr.addCompletor(new ArgumentCompletor(comp));
164:
165: // main input loop
166: luceneMethods = new LuceneMethods(DEFAULT_INDEX);
167: while (true) {
168: try {
169: line = cr.readLine("lucli> ");
170: if (line != null) {
171: handleCommand(line, cr);
172: }
173: } catch (java.io.EOFException eof) {
174: System.out.println("");//new line
175: exit();
176: } catch (UnsupportedEncodingException enc) {
177: enc.printStackTrace(System.err);
178: } catch (ParseException pe) {
179: pe.printStackTrace(System.err);
180: } catch (IOException ioe) {
181: ioe.printStackTrace(System.err);
182: }
183: }
184: }
185:
186: private String[] getCommandsAsArray() {
187: Set commandSet = commandMap.keySet();
188: String[] commands = new String[commandMap.size()];
189: int i = 0;
190: for (Iterator iter = commandSet.iterator(); iter.hasNext();) {
191: String cmd = (String) iter.next();
192: commands[i++] = cmd;
193: }
194: return commands;
195: }
196:
197: public static void main(String[] args) throws IOException {
198: new Lucli(args);
199: }
200:
201: private void handleCommand(String line, ConsoleReader cr)
202: throws IOException, ParseException {
203: String[] words = tokenizeCommand(line);
204: if (words.length == 0)
205: return; //white space
206: String query = "";
207: if (line.trim().startsWith("#")) // # = comment
208: return;
209: //Command name and number of arguments
210: switch (getCommandId(words[0], words.length - 1)) {
211: case INFO:
212: luceneMethods.info();
213: break;
214: case SEARCH:
215: for (int ii = 1; ii < words.length; ii++) {
216: query += words[ii] + " ";
217: }
218: luceneMethods.search(query, false, false, cr);
219: break;
220: case COUNT:
221: for (int ii = 1; ii < words.length; ii++) {
222: query += words[ii] + " ";
223: }
224: luceneMethods.count(query);
225: break;
226: case QUIT:
227: exit();
228: break;
229: case TERMS:
230: if (words.length > 1)
231: luceneMethods.terms(words[1]);
232: else
233: luceneMethods.terms(null);
234: break;
235: case INDEX:
236: LuceneMethods newLm = new LuceneMethods(words[1]);
237: try {
238: newLm.info(); //will fail if can't open the index
239: luceneMethods = newLm; //OK, so we'll use the new one
240: } catch (IOException ioe) {
241: //problem we'll keep using the old one
242: error(ioe.toString());
243: }
244: break;
245: case OPTIMIZE:
246: luceneMethods.optimize();
247: break;
248: case TOKENS:
249: for (int ii = 1; ii < words.length; ii++) {
250: query += words[ii] + " ";
251: }
252: luceneMethods.search(query, false, true, cr);
253: break;
254: case EXPLAIN:
255: for (int ii = 1; ii < words.length; ii++) {
256: query += words[ii] + " ";
257: }
258: luceneMethods.search(query, true, false, cr);
259: break;
260: case HELP:
261: help();
262: break;
263: case NOCOMMAND: //do nothing
264: break;
265: case UNKOWN:
266: System.out.println("Unknown command: " + words[0]
267: + ". Type help to get a list of commands.");
268: break;
269: }
270: }
271:
272: private String[] tokenizeCommand(String line) {
273: StringTokenizer tokenizer = new StringTokenizer(line, " \t");
274: int size = tokenizer.countTokens();
275: String[] tokens = new String[size];
276: for (int ii = 0; tokenizer.hasMoreTokens(); ii++) {
277: tokens[ii] = tokenizer.nextToken();
278: }
279: return tokens;
280: }
281:
282: private void exit() {
283: System.exit(0);
284: }
285:
286: /**
287: * Add a command to the list of commands for the interpreter for a
288: * command that doesn't take any parameters.
289: * @param name - the name of the command
290: * @param id - the unique id of the command
291: * @param help - the help message for this command
292: */
293: private void addCommand(String name, int id, String help) {
294: addCommand(name, id, help, 0);
295: }
296:
297: /**
298: * Add a command to the list of commands for the interpreter.
299: * @param name - the name of the command
300: * @param id - the unique id of the command
301: * @param help - the help message for this command
302: * @param params - the minimum number of required params if any
303: */
304: private void addCommand(String name, int id, String help, int params) {
305: Command command = new Command(name, id, help, params);
306: commandMap.put(name, command);
307: }
308:
309: private int getCommandId(String name, int params) {
310: name = name.toLowerCase(); //treat uppercase and lower case commands the same
311: Command command = (Command) commandMap.get(name);
312: if (command == null) {
313: return (UNKOWN);
314: } else {
315: if (command.params > params) {
316: error(command.name + " needs at least "
317: + command.params + " arguments.");
318: return (NOCOMMAND);
319: }
320: return (command.id);
321: }
322: }
323:
324: private void help() {
325: Iterator commands = commandMap.keySet().iterator();
326: while (commands.hasNext()) {
327: Command command = (Command) commandMap.get(commands.next());
328: System.out.println("\t" + command.name + ": "
329: + command.help);
330:
331: }
332: }
333:
334: private void error(String message) {
335: System.err.println("Error:" + message);
336: }
337:
338: private void message(String text) {
339: System.out.println(text);
340: }
341:
342: /*
343: * Parse command line arguments (currently none)
344: */
345: private void parseArgs(String[] args) {
346: if (args.length > 0) {
347: usage();
348: System.exit(1);
349: }
350: }
351:
352: private void usage() {
353: message("Usage: lucli.Lucli");
354: message("(currently, no parameters are supported)");
355: }
356:
357: private class Command {
358: String name;
359: int id;
360: int numberArgs;
361: String help;
362: int params;
363:
364: Command(String name, int id, String help, int params) {
365: this .name = name;
366: this .id = id;
367: this .help = help;
368: this .params = params;
369: }
370:
371: /**
372: * Prints out a usage message for this command.
373: */
374: public String commandUsage() {
375: return (name + ":" + help + ". Command takes " + params + " params");
376: }
377:
378: }
379: }
|