Init project
This commit is contained in:
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
## General ##
|
||||||
|
lib/
|
||||||
|
target/
|
||||||
|
|
||||||
|
## IDEA ##
|
||||||
|
.idea/
|
||||||
|
out/
|
||||||
|
*.iml
|
||||||
78
build.xml
Normal file
78
build.xml
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project name="Shell" default="build">
|
||||||
|
<property name="source.dir" location="src"/>
|
||||||
|
<property name="target.dir" location="target"/>
|
||||||
|
<property name="lib.dir" location="lib"/>
|
||||||
|
|
||||||
|
<property name="jline.version" value="2.11"/>
|
||||||
|
|
||||||
|
<target name="clear" description="Очистка целевой папки">
|
||||||
|
<delete dir="${target.dir}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="init" description="Подготовка к сборке">
|
||||||
|
<mkdir dir="${target.dir}/classes"/>
|
||||||
|
<mkdir dir="${target.dir}/release"/>
|
||||||
|
|
||||||
|
<condition property="check-libs">
|
||||||
|
<and>
|
||||||
|
<available file="${lib.dir}/jline.jar" type="file"/>
|
||||||
|
</and>
|
||||||
|
</condition>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="download-libs" unless="check-libs" depends="init" description="Загрузка библиотек">
|
||||||
|
<mkdir dir="${lib.dir}"/>
|
||||||
|
<get dest="${lib.dir}/jline.jar" src="http://search.maven.org/remotecontent?filepath=jline/jline/${jline.version}/jline-${jline.version}.jar" usetimestamp="true"/>
|
||||||
|
<get dest="${lib.dir}/jline-javadoc.jar" src="http://search.maven.org/remotecontent?filepath=jline/jline/${jline.version}/jline-${jline.version}-javadoc.jar" usetimestamp="true"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="download-javadoc" depends="init" description="Загрузка javadoc">
|
||||||
|
<get dest="${lib.dir}/jline-javadoc.jar" src="http://search.maven.org/remotecontent?filepath=jline/jline/${jline.version}/jline-${jline.version}-javadoc.jar" usetimestamp="true"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="compile" depends="init" description="Компиляция">
|
||||||
|
<path id="classpath">
|
||||||
|
<fileset dir="${lib.dir}">
|
||||||
|
<include name="*.jar"/>
|
||||||
|
<exclude name="*-javadoc.jar"/>
|
||||||
|
</fileset>
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<javac
|
||||||
|
classpathref="classpath"
|
||||||
|
srcdir="${source.dir}"
|
||||||
|
destdir="${target.dir}/classes"
|
||||||
|
compiler="javac1.7"
|
||||||
|
source="1.7"
|
||||||
|
target="1.7"
|
||||||
|
debug="true"
|
||||||
|
debuglevel="vars,lines,source"
|
||||||
|
encoding="UTF-8"
|
||||||
|
includeantruntime="false"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="build" depends="compile" description="Сборка проекта">
|
||||||
|
<tstamp>
|
||||||
|
<format property="build.time" pattern="yyyy-MM-dd HH:mm:ss"/>
|
||||||
|
</tstamp>
|
||||||
|
|
||||||
|
<jar destfile="${target.dir}/release/${ant.project.name}.jar">
|
||||||
|
<fileset dir="${target.dir}/classes"/>
|
||||||
|
|
||||||
|
<manifest>
|
||||||
|
<attribute name="Main-Class" value="ru.dmitriymx.Main"/>
|
||||||
|
<attribute name="Build-By" value="DmitriyMX"/>
|
||||||
|
<attribute name="Build-Date" value="${build.time}"/>
|
||||||
|
</manifest>
|
||||||
|
</jar>
|
||||||
|
|
||||||
|
<mkdir dir="${target.dir}/release/lib"/>
|
||||||
|
<copy todir="${target.dir}/release/lib">
|
||||||
|
<fileset dir="${lib.dir}">
|
||||||
|
<include name="*.jar"/>
|
||||||
|
<exclude name="*-javadoc.jar"/>
|
||||||
|
</fileset>
|
||||||
|
</copy>
|
||||||
|
</target>
|
||||||
|
</project>
|
||||||
41
src/ru/dmitriymx/shell/CommandCompleter.java
Normal file
41
src/ru/dmitriymx/shell/CommandCompleter.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package ru.dmitriymx.shell;
|
||||||
|
|
||||||
|
import jline.console.completer.ArgumentCompleter;
|
||||||
|
import jline.console.completer.Completer;
|
||||||
|
import jline.console.completer.StringsCompleter;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class CommandCompleter implements Completer {
|
||||||
|
private ArgumentCompleter.ArgumentDelimiter delimiter = new ArgumentCompleter.WhitespaceArgumentDelimiter();
|
||||||
|
private Map<String, IShellCommand> commandMap = new HashMap<>();
|
||||||
|
private Completer commandNamesCompleter;
|
||||||
|
|
||||||
|
public CommandCompleter(List<IShellCommand> commandList) {
|
||||||
|
for (IShellCommand command : commandList) {
|
||||||
|
commandMap.put(command.getName(), command);
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] commandNames = new String[commandMap.size()];
|
||||||
|
commandNames = commandMap.keySet().toArray(commandNames);
|
||||||
|
commandNamesCompleter = new StringsCompleter(commandNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int complete(String buffer, int cursor, List<CharSequence> candidates) {
|
||||||
|
ArgumentCompleter.ArgumentList parseCommandLine = parseLine(buffer, cursor);
|
||||||
|
int cursorArgument = parseCommandLine.getCursorArgumentIndex();
|
||||||
|
|
||||||
|
if (cursorArgument < 0) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return commandNamesCompleter.complete(buffer, cursor, candidates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArgumentCompleter.ArgumentList parseLine(String buffer, int cursor) {
|
||||||
|
return delimiter.delimit(buffer, cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/ru/dmitriymx/shell/IShellCommand.java
Normal file
8
src/ru/dmitriymx/shell/IShellCommand.java
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package ru.dmitriymx.shell;
|
||||||
|
|
||||||
|
public interface IShellCommand {
|
||||||
|
|
||||||
|
public String getName();
|
||||||
|
|
||||||
|
public void execute(final String[] args);
|
||||||
|
}
|
||||||
79
src/ru/dmitriymx/shell/LogAgent.java
Normal file
79
src/ru/dmitriymx/shell/LogAgent.java
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package ru.dmitriymx.shell;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.logging.*;
|
||||||
|
|
||||||
|
public class LogAgent {
|
||||||
|
private Logger logger;
|
||||||
|
|
||||||
|
public LogAgent() {
|
||||||
|
this(new LogFormatter(), new ConsoleHandler(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogAgent(Formatter formatter) {
|
||||||
|
this(formatter, new ConsoleHandler(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogAgent(ConsoleHandler consoleHandler) {
|
||||||
|
this(new LogFormatter(), consoleHandler, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogAgent(File logFile) {
|
||||||
|
this(new LogFormatter(), new ConsoleHandler(), logFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogAgent(Formatter formatter, ConsoleHandler consoleHandler, File logFile) {
|
||||||
|
logger = Logger.getLogger("Shell");
|
||||||
|
logger.setUseParentHandlers(false);
|
||||||
|
|
||||||
|
Handler[] handlers = logger.getHandlers();
|
||||||
|
for (Handler handler : handlers) {
|
||||||
|
logger.removeHandler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
consoleHandler.setFormatter(formatter);
|
||||||
|
logger.addHandler(consoleHandler);
|
||||||
|
|
||||||
|
if (logFile != null) {
|
||||||
|
try {
|
||||||
|
FileHandler fHandler = new FileHandler(logFile.getAbsolutePath(), true);
|
||||||
|
fHandler.setFormatter(formatter);
|
||||||
|
logger.addHandler(fHandler);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.WARNING, "Failed write log to " + logFile.getAbsolutePath(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void info(String message) {
|
||||||
|
logger.log(Level.INFO, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void info(String message, Object... params) {
|
||||||
|
logger.log(Level.INFO, String.format(message, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void warning(String message) {
|
||||||
|
logger.log(Level.WARNING, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void warning(String message, Object... params) {
|
||||||
|
logger.log(Level.WARNING, String.format(message, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void warning(String message, Throwable trow) {
|
||||||
|
logger.log(Level.WARNING, message, trow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void severe(String message) {
|
||||||
|
logger.log(Level.SEVERE, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void severe(String message, Object... params) {
|
||||||
|
logger.log(Level.SEVERE, String.format(message, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void severe(String message, Throwable trow) {
|
||||||
|
logger.log(Level.SEVERE, message, trow);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/ru/dmitriymx/shell/LogFormatter.java
Normal file
28
src/ru/dmitriymx/shell/LogFormatter.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package ru.dmitriymx.shell;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.logging.Formatter;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
|
public class LogFormatter extends Formatter {
|
||||||
|
private final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format(LogRecord record) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(SDF.format(record.getMillis()))
|
||||||
|
.append("[").append(record.getLevel().getName()).append("] ")
|
||||||
|
.append(record.getMessage()).append("\n");
|
||||||
|
|
||||||
|
Throwable thrown = record.getThrown();
|
||||||
|
if (thrown != null) {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
thrown.printStackTrace(new PrintWriter(sw));
|
||||||
|
sb.append(sw.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
172
src/ru/dmitriymx/shell/Shell.java
Normal file
172
src/ru/dmitriymx/shell/Shell.java
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
package ru.dmitriymx.shell;
|
||||||
|
|
||||||
|
import jline.console.ConsoleReader;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.logging.Formatter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Командная оболочка
|
||||||
|
*/
|
||||||
|
public class Shell implements Runnable {
|
||||||
|
private LogAgent log;
|
||||||
|
private Thread shellThread;
|
||||||
|
private String prompt;
|
||||||
|
private LinkedList<IShellCommand> commandList = new LinkedList<>();
|
||||||
|
private CommandCompleter commandCompleter;
|
||||||
|
protected ConsoleReader cReader;
|
||||||
|
protected boolean runned = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Создание командной оболочки
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public Shell() throws IOException {
|
||||||
|
this(new LogFormatter(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Создание командной оболочки
|
||||||
|
* @param logFile файл журналирования
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public Shell(File logFile) throws IOException {
|
||||||
|
this(new LogFormatter(), logFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Создание командной оболочки
|
||||||
|
* @param logFormatter свой вариант форматирования вывода
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public Shell(Formatter logFormatter) throws IOException {
|
||||||
|
this(logFormatter, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Создание командной оболочки
|
||||||
|
* @param logFormatter свой вариант форматирования вывода
|
||||||
|
* @param logFile файл журналирования
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public Shell(Formatter logFormatter, File logFile) throws IOException {
|
||||||
|
cReader = new ConsoleReader(System.in, System.out);
|
||||||
|
cReader.setExpandEvents(false);
|
||||||
|
log = new LogAgent(logFormatter, new ShellConsoleHandler(this), logFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получить объект журналирования
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public LogAgent getLog() {
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Установить текст приглашения
|
||||||
|
* @param prompt
|
||||||
|
*/
|
||||||
|
public void setPrompt(String prompt) {
|
||||||
|
this.prompt = prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавить команду
|
||||||
|
* @param command команда
|
||||||
|
*/
|
||||||
|
public void addCommand(IShellCommand command) {
|
||||||
|
commandList.add(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Удаление команды
|
||||||
|
* @param command удаляемая команда
|
||||||
|
*/
|
||||||
|
public void removeCommand(IShellCommand command) {
|
||||||
|
commandList.remove(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Удаление команды по её имени
|
||||||
|
* @param commandName имя команды
|
||||||
|
*/
|
||||||
|
public void removeCommand(String commandName) {
|
||||||
|
IShellCommand foundCmd = null;
|
||||||
|
|
||||||
|
for (IShellCommand command : commandList) {
|
||||||
|
if(command.getName().equalsIgnoreCase(commandName)) {
|
||||||
|
foundCmd = command;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundCmd != null) {
|
||||||
|
commandList.remove(foundCmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Запуск командной оболочки
|
||||||
|
*/
|
||||||
|
public void start() {
|
||||||
|
shellThread = new Thread(this, "Shell Thread");
|
||||||
|
try {
|
||||||
|
runned = true;
|
||||||
|
shellThread.join();
|
||||||
|
shellThread.start();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.severe("Shell thread exception: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Остановка командной оболочки
|
||||||
|
*/
|
||||||
|
public void stop() {
|
||||||
|
shellThread.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обработчик входящих комманд
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
cReader.setPrompt(prompt);
|
||||||
|
commandCompleter = new CommandCompleter(commandList);
|
||||||
|
cReader.addCompleter(commandCompleter);
|
||||||
|
Thread currentThread = Thread.currentThread();
|
||||||
|
|
||||||
|
String line;
|
||||||
|
try {
|
||||||
|
readerLoop:
|
||||||
|
while (!currentThread.isInterrupted() && (line = cReader.readLine()) != null) {
|
||||||
|
String[] parseLine = commandCompleter.parseLine(line, cReader.getCursorBuffer().cursor).getArguments();
|
||||||
|
if (parseLine.length == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String commandName = parseLine[0];
|
||||||
|
for (IShellCommand command : commandList) {
|
||||||
|
if (command.getName().equalsIgnoreCase(commandName)) {
|
||||||
|
if (parseLine.length == 1) {
|
||||||
|
command.execute(null);
|
||||||
|
} else {
|
||||||
|
String[] args = new String[parseLine.length - 1];
|
||||||
|
System.arraycopy(parseLine, 1, args, 0, args.length);
|
||||||
|
command.execute(args);
|
||||||
|
}
|
||||||
|
continue readerLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.warning("Unknow command \"%s\"", commandName);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.severe("Shell exception:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
cReader.removeCompleter(commandCompleter);
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/ru/dmitriymx/shell/ShellConsoleHandler.java
Normal file
27
src/ru/dmitriymx/shell/ShellConsoleHandler.java
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package ru.dmitriymx.shell;
|
||||||
|
|
||||||
|
import jline.console.ConsoleReader;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.logging.ConsoleHandler;
|
||||||
|
|
||||||
|
public class ShellConsoleHandler extends ConsoleHandler {
|
||||||
|
private Shell shell;
|
||||||
|
|
||||||
|
public ShellConsoleHandler(Shell shell) {
|
||||||
|
super();
|
||||||
|
this.shell = shell;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void flush() {
|
||||||
|
try {
|
||||||
|
shell.cReader.print(ConsoleReader.RESET_LINE + "");
|
||||||
|
shell.cReader.flush();
|
||||||
|
super.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
super.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user