package org.basex.core;
import static org.basex.core.Text.*;
import static org.basex.util.Token.*;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
import java.util.Scanner;
import org.basex.core.Commands.Cmd;
import org.basex.core.cmd.Exit;
import org.basex.query.QueryException;
import org.basex.server.Session;
import org.basex.util.Util;
import org.basex.util.list.StringList;
/**
* This is the abstract main class for the starter classes.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public abstract class Main {
/** Database context. */
public final Context context;
/** Output file for queries. */
protected OutputStream out = System.out;
/** Console mode. */
protected boolean console;
/** Session. */
protected Session session;
/** Verbose mode. */
protected boolean verbose;
/**
* Constructor.
* @param args command-line arguments
* @throws IOException I/O exception
*/
protected Main(final String[] args) throws IOException {
this(args, null);
}
/**
* Constructor.
* @param args command-line arguments
* @param ctx database context, or {@code null}
* @throws IOException I/O exception
*/
protected Main(final String[] args, final Context ctx) throws IOException {
context = ctx != null ? ctx : new Context();
parseArguments(args);
// console: turn on verbose mode
verbose |= console;
// guarantee correct shutdown of database context
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public synchronized void run() {
context.close();
}
});
}
/**
* Launches the console mode, which reads and executes user input.
*/
protected final void console() {
while(console) {
Util.out("> ");
for(final String in : inputs()) {
if(in.isEmpty()) continue;
try {
if(!execute(in)) {
Util.outln(BYE[new Random().nextInt(4)]);
return;
}
} catch(final IOException ex) {
Util.errln(ex);
}
}
}
}
/**
* Quits the console mode.
* @throws IOException I/O exception
*/
protected void quit() throws IOException {
execute(new Exit(), true);
if(out == System.out || out == System.err) out.flush();
else out.close();
}
/**
* Parses and executes the input string.
* @param in input commands
* @return {@code false} if the exit command was sent
* @throws IOException database exception
*/
protected final boolean execute(final String in) throws IOException {
final PasswordReader pr = new PasswordReader() {
@Override
public String password() {
Util.out(PASSWORD + COLS);
return md5(Util.password());
}
};
final CommandParser cp = new CommandParser(in, context).password(pr);
try {
for(final Command cmd : cp.parse()) {
if(cmd instanceof Exit) return false;
execute(cmd, verbose);
}
} catch(final QueryException ex) {
Util.debug(ex);
throw new BaseXException(ex);
}
return true;
}
/**
* Executes the specified command and optionally prints some information.
* @param cmd command to be run
* @param info verbose flag
* @throws IOException I/O exception
*/
protected final void execute(final Command cmd, final boolean info)
throws IOException {
final Session ss = session();
ss.execute(cmd);
if(info) Util.out(ss.info());
}
/**
* Returns multiple lines from standard input.
* @return list of strings
*/
static final StringList inputs() {
final StringList sl = new StringList();
// find end of input from interactive user input
final Scanner scan = new Scanner(System.in).useDelimiter("\\z");
if(scan.hasNext()) {
// catch several lines sent from redirected standard input
final Scanner lines = new Scanner(scan.next());
while(lines.hasNextLine()) sl.add(lines.nextLine());
}
// no more input: send exit command
if(sl.size() == 0) sl.add(Cmd.EXIT.toString());
return sl;
}
/**
* Returns the session.
* @return session
* @throws IOException I/O exception
*/
protected abstract Session session() throws IOException;
/**
* Parses the command-line arguments, specified by the user.
* @param args command-line arguments
* @throws IOException I/O exception
*/
protected abstract void parseArguments(final String[] args)
throws IOException;
}