gclc clean up. socket and swt configured for current stable gclc
gclc items moved around. gclc ready for release. gclc internationalization gclc extract command interface socket server issue (close socket) "fixed" swt minor improvments (user con't input commands while the application is actually running one, the history keeps track of mispelled commands to).
This commit is contained in:
parent
87a668d308
commit
1ffe321898
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2014)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* Socket implementation of GCLC.
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
* modify and/or redistribute the software under the terms of the CeCILL
|
||||
* license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
* "http://www.cecill.info".
|
||||
*
|
||||
* As a counterpart to the access to the source code and rights to copy,
|
||||
* modify and redistribute granted by the license, users are provided only
|
||||
* with a limited warranty and the software's author, the holder of the
|
||||
* economic rights, and the successive licensors have only limited
|
||||
* liability.
|
||||
*
|
||||
* In this respect, the user's attention is drawn to the risks associated
|
||||
* with loading, using, modifying and/or developing or reproducing the
|
||||
* software by the user in light of its specific status of free software,
|
||||
* that may mean that it is complicated to manipulate, and that also
|
||||
* therefore means that it is reserved for developers and experienced
|
||||
* professionals having in-depth computer knowledge. Users are therefore
|
||||
* encouraged to load and test the software's suitability as regards their
|
||||
* requirements in conditions enabling the security of their systems and/or
|
||||
* data to be ensured and, more generally, to use and operate it in the
|
||||
* same conditions as regards security.
|
||||
*
|
||||
* The fact that you are presently reading this means that you have had
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
/**
|
||||
* gclc-socket:fr.bigeon.gclc.socket.ConsoleRunnable.java
|
||||
* Created on: Jun 1, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
|
||||
/** A runnable class that will actually have the application running.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class ConsoleRunnable implements Runnable {
|
||||
|
||||
/** The actual application */
|
||||
private final ConsoleApplication app;
|
||||
/** The synchronization object */
|
||||
private final Object promptingLock;
|
||||
|
||||
/** @param app the application
|
||||
* @param promptingLock the synchronization object */
|
||||
public ConsoleRunnable(ConsoleApplication app, Object promptingLock) {
|
||||
super();
|
||||
this.app = app;
|
||||
this.promptingLock = promptingLock;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run() */
|
||||
@Override
|
||||
public void run() {
|
||||
app.start();
|
||||
synchronized (promptingLock) {
|
||||
// release all waiting elements before ending
|
||||
promptingLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/** Stop the application (it will finish its current operation) */
|
||||
public void stop() {
|
||||
app.exit();
|
||||
}
|
||||
|
||||
}
|
@ -44,7 +44,10 @@ import java.io.PipedOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.ConsoleManager;
|
||||
@ -70,16 +73,20 @@ import fr.bigeon.smu.StringEncoder;
|
||||
* @author Emmanuel Bigeon */
|
||||
public class SocketConsoleApplicationShell implements Runnable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final String INTERRUPTION_WHILE_WORKING = "Interruption while application was working"; //$NON-NLS-1$
|
||||
/** The end of line character */
|
||||
protected static final String EOL = "\n"; //$NON-NLS-1$
|
||||
/** The encoder */
|
||||
private static final StringEncoder ENCODER = new StringEncoder("%", Arrays.asList(EOL)); //$NON-NLS-1$
|
||||
private static final StringEncoder ENCODER = new StringEncoder("%", //$NON-NLS-1$
|
||||
Arrays.asList(EOL));
|
||||
/** The class logger */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(SocketConsoleApplicationShell.class.getName());
|
||||
/** The listening port */
|
||||
private final int port;
|
||||
/** The output */
|
||||
private PrintWriter output;
|
||||
/** The input reader */
|
||||
private BufferedReader input;
|
||||
/** The input */
|
||||
private final PipedInputStream consoleInput = new PipedInputStream();
|
||||
/** The application */
|
||||
@ -88,180 +95,174 @@ public class SocketConsoleApplicationShell implements Runnable {
|
||||
private final String close;
|
||||
/** The running status */
|
||||
private boolean running;
|
||||
/** If the prompt should be next activity */
|
||||
private boolean doPrompt = false;
|
||||
/** An object to lock on for prompt */
|
||||
private final Object promptingLock = new Object();
|
||||
|
||||
/** The console manager implementation */
|
||||
private final ConsoleManager consoleManager = new ConsoleManager() {
|
||||
|
||||
private String prompt = new String();
|
||||
private StringBuffer buffer = new StringBuffer();
|
||||
|
||||
@Override
|
||||
public void setPrompt(String prompt) {
|
||||
this.prompt = prompt;
|
||||
}
|
||||
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public String prompt(String message) {
|
||||
buffer.append(message);
|
||||
String userInput = new String();
|
||||
boolean prompting = true;
|
||||
while (prompting) {
|
||||
output.println(ENCODER.encode(buffer.toString()));
|
||||
try {
|
||||
synchronized (promptingLock) {
|
||||
doPrompt = true;
|
||||
promptingLock.notify();
|
||||
}
|
||||
userInput = input.readLine();
|
||||
doPrompt = false;
|
||||
prompting = false;
|
||||
} catch (final IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
buffer = new StringBuffer();
|
||||
return userInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prompt() {
|
||||
return prompt(prompt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(String message) {
|
||||
buffer.append(message + EOL);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println() {
|
||||
buffer.append(EOL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(String text) {
|
||||
buffer.append(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrompt() {
|
||||
return prompt;
|
||||
}
|
||||
};
|
||||
private final ThreadedServerConsoleManager consoleManager = new ThreadedServerConsoleManager(
|
||||
ENCODER, promptingLock);
|
||||
/** The auto close flag. if this is true, every request closes the session
|
||||
* after its call */
|
||||
private final boolean autoClose;
|
||||
/** The server socket */
|
||||
private ServerSocket serverSocket;
|
||||
/** The application shutdown string */
|
||||
private final String applicationShutdown;
|
||||
|
||||
/** The runnable class that will actually have the application running.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
private class ConsoleRunnable implements Runnable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public ConsoleRunnable() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run() */
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
running = true;
|
||||
app.start();
|
||||
running = false;
|
||||
synchronized (promptingLock) {
|
||||
promptingLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** TODO Describe SocketConsoleApplicationShell.java Constructor
|
||||
/** Create a socket application shell which will listen on the given port
|
||||
* and close session upon the provided string reception by client
|
||||
*
|
||||
* @param port the port to listen to
|
||||
* @param close the session closing command */
|
||||
public SocketConsoleApplicationShell(int port, String close) {
|
||||
* @param close the session closing command
|
||||
* @param applicationShutdown the appication shut down command */
|
||||
public SocketConsoleApplicationShell(int port, String close,
|
||||
String applicationShutdown) {
|
||||
this.port = port;
|
||||
this.close = close;
|
||||
this.applicationShutdown = applicationShutdown;
|
||||
this.autoClose = false;
|
||||
}
|
||||
|
||||
/** TODO Describe SocketConsoleApplicationShell.java Constructor
|
||||
/** Create a socket application shell which will listen on the given port
|
||||
* and auto close session after one instruction
|
||||
*
|
||||
* @param port the port to listen to
|
||||
* @param autoClose if the session must be closed once the request has been
|
||||
* sent */
|
||||
public SocketConsoleApplicationShell(int port, boolean autoClose) {
|
||||
* sent
|
||||
* @param applicationShutdown the application shutdown command */
|
||||
public SocketConsoleApplicationShell(int port, boolean autoClose,
|
||||
String applicationShutdown) {
|
||||
this.port = port;
|
||||
this.close = null;
|
||||
this.autoClose = autoClose;
|
||||
this.applicationShutdown = applicationShutdown;
|
||||
this.close = autoClose ? null : "close"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run() */
|
||||
@Override
|
||||
public void run() {
|
||||
try (ServerSocket serverSocket = new ServerSocket(port)) {
|
||||
final ConsoleRunnable runnable = new ConsoleRunnable();
|
||||
try (ServerSocket actualServerSocket = new ServerSocket(port)) {
|
||||
this.serverSocket = actualServerSocket;
|
||||
final ConsoleRunnable runnable = new ConsoleRunnable(app,
|
||||
promptingLock);
|
||||
final Thread appTh = new Thread(runnable);
|
||||
running = true;
|
||||
try (PipedOutputStream outStream = new PipedOutputStream();
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outStream))) {
|
||||
BufferedWriter writer = new BufferedWriter(
|
||||
new OutputStreamWriter(outStream))) {
|
||||
consoleInput.connect(outStream);
|
||||
try (BufferedReader inBuf = new BufferedReader(new InputStreamReader(consoleInput))) {
|
||||
input = inBuf;
|
||||
while (running) {
|
||||
try (Socket clientSocket = serverSocket.accept();
|
||||
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
|
||||
BufferedReader in = new BufferedReader(
|
||||
new InputStreamReader(clientSocket.getInputStream()));) {
|
||||
output = out;
|
||||
// Initiate application
|
||||
if (!appTh.isAlive()) {
|
||||
appTh.start();
|
||||
} else {
|
||||
output.println("Reconnected"); //$NON-NLS-1$
|
||||
}
|
||||
synchronized (promptingLock) {
|
||||
String ln;
|
||||
if (!doPrompt) try {
|
||||
promptingLock.wait();
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
while (running && (ln = in.readLine()) != null) {
|
||||
if (ln.equals(close)) {
|
||||
break;
|
||||
}
|
||||
writer.write(ln + EOL);
|
||||
writer.flush();
|
||||
try {
|
||||
promptingLock.wait();
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (autoClose) running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try (InputStreamReader isr = new InputStreamReader(
|
||||
consoleInput);
|
||||
BufferedReader inBuf = new BufferedReader(isr);) {
|
||||
consoleManager.setInput(inBuf);
|
||||
runSokectServer(appTh, writer);
|
||||
// Close the application
|
||||
// Pass command to application
|
||||
writer.write(applicationShutdown + EOL);
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Communication error between client and server", e); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
/** @param appTh the application thread
|
||||
* @param writer the writer to the application
|
||||
* @throws IOException if the communication with the client failed */
|
||||
private void runSokectServer(Thread appTh,
|
||||
BufferedWriter writer) throws IOException {
|
||||
while (running) {
|
||||
try (Socket clientSocket = serverSocket.accept();
|
||||
PrintWriter out = new PrintWriter(
|
||||
clientSocket.getOutputStream(), true);
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(
|
||||
clientSocket.getInputStream()));) {
|
||||
// this is not threaded to avoid several clients at the same
|
||||
// time
|
||||
consoleManager.setOutput(out);
|
||||
// Initiate application
|
||||
if (!appTh.isAlive()) {
|
||||
appTh.start();
|
||||
} else {
|
||||
out.println("Reconnected"); //$NON-NLS-1$
|
||||
}
|
||||
communicate(writer, in);
|
||||
} catch (SocketException e) {
|
||||
LOGGER.log(Level.INFO, "Socket closed", e); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** active communication between server and client
|
||||
*
|
||||
* @param writer the writer to the application
|
||||
* @param in the input from the client
|
||||
* @throws IOException if the communication failed */
|
||||
private void communicate(BufferedWriter writer,
|
||||
BufferedReader in) throws IOException {
|
||||
synchronized (promptingLock) {
|
||||
if (!consoleManager.isPrompting()) {
|
||||
try {
|
||||
// wait for application to finish its operation
|
||||
promptingLock.wait();
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.SEVERE, INTERRUPTION_WHILE_WORKING, e);
|
||||
}
|
||||
}
|
||||
if (autoClose) {
|
||||
communicateOnce(in, writer);
|
||||
} else {
|
||||
communicateLoop(in, writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @param in the input from the client
|
||||
* @param writer the output to the client
|
||||
* @throws IOException if the communication failed */
|
||||
private void communicateOnce(BufferedReader in,
|
||||
BufferedWriter writer) throws IOException {
|
||||
String ln;
|
||||
if ((ln = in.readLine()) != null) {
|
||||
if (ln.equals(close)) {
|
||||
return;
|
||||
}
|
||||
// Pass command to application
|
||||
writer.write(ln + EOL);
|
||||
writer.flush();
|
||||
try {
|
||||
// Wait for application process to
|
||||
// finish
|
||||
promptingLock.wait();
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.SEVERE, INTERRUPTION_WHILE_WORKING, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @param in the input from the client
|
||||
* @param writer the output to the client
|
||||
* @throws IOException if the communication failed */
|
||||
private void communicateLoop(BufferedReader in,
|
||||
BufferedWriter writer) throws IOException {
|
||||
String ln;
|
||||
while (running && (ln = in.readLine()) != null) {
|
||||
if (ln.equals(close)) {
|
||||
break;
|
||||
}
|
||||
// Pass command to application
|
||||
writer.write(ln + EOL);
|
||||
writer.flush();
|
||||
try {
|
||||
// Wait for application process to
|
||||
// finish
|
||||
promptingLock.wait();
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.SEVERE, INTERRUPTION_WHILE_WORKING, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,4 +276,21 @@ public class SocketConsoleApplicationShell implements Runnable {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
/** This method will request the server to stop.
|
||||
* <p>
|
||||
* In most cases, this will terminate communication on every client. On some
|
||||
* cases, the */
|
||||
public void stop() {
|
||||
running = false;
|
||||
try {
|
||||
serverSocket.close();
|
||||
} catch (IOException e) {
|
||||
LOGGER.log(Level.SEVERE, "Exception in closing socket server", e); //$NON-NLS-1$
|
||||
}
|
||||
synchronized (promptingLock) {
|
||||
promptingLock.notifyAll();
|
||||
}
|
||||
app.exit();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2014)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* Socket implementation of GCLC.
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
* modify and/or redistribute the software under the terms of the CeCILL
|
||||
* license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
* "http://www.cecill.info".
|
||||
*
|
||||
* As a counterpart to the access to the source code and rights to copy,
|
||||
* modify and redistribute granted by the license, users are provided only
|
||||
* with a limited warranty and the software's author, the holder of the
|
||||
* economic rights, and the successive licensors have only limited
|
||||
* liability.
|
||||
*
|
||||
* In this respect, the user's attention is drawn to the risks associated
|
||||
* with loading, using, modifying and/or developing or reproducing the
|
||||
* software by the user in light of its specific status of free software,
|
||||
* that may mean that it is complicated to manipulate, and that also
|
||||
* therefore means that it is reserved for developers and experienced
|
||||
* professionals having in-depth computer knowledge. Users are therefore
|
||||
* encouraged to load and test the software's suitability as regards their
|
||||
* requirements in conditions enabling the security of their systems and/or
|
||||
* data to be ensured and, more generally, to use and operate it in the
|
||||
* same conditions as regards security.
|
||||
*
|
||||
* The fact that you are presently reading this means that you have had
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
/**
|
||||
* gclc-socket:fr.bigeon.gclc.socket.ThreadedServerConsoleManager.java
|
||||
* Created on: Jun 1, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleManager;
|
||||
import fr.bigeon.smu.StringEncoder;
|
||||
|
||||
/** The console manager for socket communication
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class ThreadedServerConsoleManager implements ConsoleManager {
|
||||
|
||||
/** The eol character */
|
||||
private static final String EOL = "\n"; //$NON-NLS-1$
|
||||
/** The class logger */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(ThreadedServerConsoleManager.class.getName());
|
||||
/** The prompting sequence */
|
||||
private String prompt = new String();
|
||||
/** The buffer of data to send to the user */
|
||||
private StringBuilder buffer = new StringBuilder();
|
||||
/** The synchronized object */
|
||||
private final Object promptingLock;
|
||||
/** The output to write data comming from the application */
|
||||
private PrintWriter output;
|
||||
/** The encoder to encode data coming from the application */
|
||||
private final StringEncoder encoder;
|
||||
/** The input to wait data from the user */
|
||||
private BufferedReader input;
|
||||
/** the prompting status */
|
||||
private boolean doPrompt;
|
||||
|
||||
/** Create the console manager.
|
||||
*
|
||||
* @param encoder the encoder for output
|
||||
* @param promptingLock the synchronization object */
|
||||
public ThreadedServerConsoleManager(StringEncoder encoder,
|
||||
Object promptingLock) {
|
||||
super();
|
||||
this.encoder = encoder;
|
||||
this.promptingLock = promptingLock;
|
||||
}
|
||||
|
||||
/** @param input the input to set */
|
||||
public void setInput(BufferedReader input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
/** @param output the output to set */
|
||||
public void setOutput(PrintWriter output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrompt(String prompt) {
|
||||
this.prompt = prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prompt(String message) {
|
||||
buffer.append(message);
|
||||
String userInput = new String();
|
||||
boolean prompting = true;
|
||||
while (prompting) {
|
||||
// Send buffer content
|
||||
output.println(encoder.encode(buffer.toString()));
|
||||
try {
|
||||
synchronized (promptingLock) {
|
||||
doPrompt = true;
|
||||
promptingLock.notify();
|
||||
}
|
||||
userInput = input.readLine();
|
||||
doPrompt = false;
|
||||
prompting = false;
|
||||
} catch (final IOException e) {
|
||||
LOGGER.log(Level.SEVERE, "input reading error", e); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
// Renew buffer
|
||||
buffer = new StringBuilder();
|
||||
return userInput;
|
||||
}
|
||||
|
||||
/** @return the prompting status */
|
||||
public synchronized boolean isPrompting() {
|
||||
return doPrompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prompt() {
|
||||
return prompt(prompt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(String message) {
|
||||
buffer.append(message + EOL);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println() {
|
||||
buffer.append(EOL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(String text) {
|
||||
buffer.append(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrompt() {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2014)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* Socket implementation of GCLC.
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
* modify and/or redistribute the software under the terms of the CeCILL
|
||||
* license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
* "http://www.cecill.info".
|
||||
*
|
||||
* As a counterpart to the access to the source code and rights to copy,
|
||||
* modify and redistribute granted by the license, users are provided only
|
||||
* with a limited warranty and the software's author, the holder of the
|
||||
* economic rights, and the successive licensors have only limited
|
||||
* liability.
|
||||
*
|
||||
* In this respect, the user's attention is drawn to the risks associated
|
||||
* with loading, using, modifying and/or developing or reproducing the
|
||||
* software by the user in light of its specific status of free software,
|
||||
* that may mean that it is complicated to manipulate, and that also
|
||||
* therefore means that it is reserved for developers and experienced
|
||||
* professionals having in-depth computer knowledge. Users are therefore
|
||||
* encouraged to load and test the software's suitability as regards their
|
||||
* requirements in conditions enabling the security of their systems and/or
|
||||
* data to be ensured and, more generally, to use and operate it in the
|
||||
* same conditions as regards security.
|
||||
*
|
||||
* The fact that you are presently reading this means that you have had
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
/**
|
||||
* gclc-socket:fr.bigeon.gclc.socket.ConsoleRunnableTest.java
|
||||
* Created on: Jun 1, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.ConsoleManager;
|
||||
import fr.bigeon.gclc.system.SystemConsoleManager;
|
||||
|
||||
/** Test class for {@link ConsoleRunnable}
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
@SuppressWarnings({"static-method", "unused"})
|
||||
public class ConsoleRunnableTest {
|
||||
|
||||
/**
|
||||
* Test method for {@link fr.bigeon.gclc.socket.ConsoleRunnable#ConsoleRunnable(fr.bigeon.gclc.ConsoleApplication, java.lang.Object)}.
|
||||
*/
|
||||
@Test
|
||||
public void testConsoleRunnable() {
|
||||
Object lock = new Object();
|
||||
ConsoleApplication app = new ConsoleTestApplication(
|
||||
new SystemConsoleManager());
|
||||
ConsoleRunnable runnable = new ConsoleRunnable(app, lock);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link fr.bigeon.gclc.socket.ConsoleRunnable#run()}.
|
||||
*/
|
||||
@Test
|
||||
public void testRunFlow() {
|
||||
Object lock = new Object();
|
||||
ConsoleApplication app = new ConsoleTestApplication(
|
||||
new ConsoleManager() {
|
||||
|
||||
@Override
|
||||
public void setPrompt(String prompt) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrompt() {
|
||||
// Not used in test
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prompt() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) { // NOSONAR
|
||||
// do nothing
|
||||
}
|
||||
return "mock"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prompt(String message) {
|
||||
return prompt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(String message) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(String text) {
|
||||
// do nothing
|
||||
}
|
||||
});
|
||||
ConsoleRunnable runnable = new ConsoleRunnable(app, lock);
|
||||
|
||||
Thread th = new Thread(runnable);
|
||||
th.start();
|
||||
|
||||
runnable.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link fr.bigeon.gclc.socket.ConsoleRunnable#stop()}.
|
||||
*/
|
||||
@Test
|
||||
public void testStop() {
|
||||
Object lock = new Object();
|
||||
ConsoleApplication app = new ConsoleTestApplication(
|
||||
new ConsoleManager() {
|
||||
|
||||
@Override
|
||||
public void setPrompt(String prompt) {
|
||||
throw new RuntimeException("Not implemented yet"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrompt() {
|
||||
throw new RuntimeException("Not implemented yet"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prompt() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "mock"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prompt(String message) {
|
||||
throw new RuntimeException("Not implemented yet"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(String message) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println() {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(String text) {
|
||||
//
|
||||
}
|
||||
});
|
||||
ConsoleRunnable runnable = new ConsoleRunnable(app, lock);
|
||||
runnable.stop();
|
||||
Thread th = new Thread(runnable);
|
||||
th.start();
|
||||
runnable.stop();
|
||||
runnable.stop();
|
||||
}
|
||||
|
||||
/** Test method for {@link fr.bigeon.gclc.socket.ConsoleRunnable#stop()}. */
|
||||
@Test
|
||||
public void testRun() {
|
||||
Object lock = new Object();
|
||||
ConsoleApplication app = new ConsoleTestApplication(
|
||||
new ConsoleManager() {
|
||||
|
||||
@Override
|
||||
public void setPrompt(String prompt) {
|
||||
throw new RuntimeException("Not implemented yet"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrompt() {
|
||||
throw new RuntimeException("Not implemented yet"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prompt() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "exit"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prompt(String message) {
|
||||
throw new RuntimeException("Not implemented yet"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(String message) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println() {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(String text) {
|
||||
//
|
||||
}
|
||||
});
|
||||
ConsoleRunnable runnable = new ConsoleRunnable(app, lock);
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
}
|
@ -39,16 +39,18 @@ import fr.bigeon.gclc.ConsoleManager;
|
||||
import fr.bigeon.gclc.command.Command;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
|
||||
/** TODO Describe ConsoleTestApplication.java
|
||||
* @author Emmanuel Bigeon
|
||||
*
|
||||
*/
|
||||
/** A test-purpose application
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class ConsoleTestApplication extends ConsoleApplication {
|
||||
|
||||
/** Exit command */
|
||||
public static final String EXIT = "exit"; //$NON-NLS-1$
|
||||
|
||||
/** @param manager the manager */
|
||||
@SuppressWarnings("nls")
|
||||
public ConsoleTestApplication(final ConsoleManager manager) {
|
||||
super(manager, "exit",
|
||||
super(manager, EXIT,
|
||||
"Welcome to the test application. Type help or test.",
|
||||
"See you");
|
||||
addHelpCommand("help");
|
||||
@ -66,9 +68,7 @@ public class ConsoleTestApplication extends ConsoleApplication {
|
||||
}
|
||||
});
|
||||
} catch (final InvalidCommandName e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2014)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* Socket implementation of GCLC.
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
* modify and/or redistribute the software under the terms of the CeCILL
|
||||
* license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
* "http://www.cecill.info".
|
||||
*
|
||||
* As a counterpart to the access to the source code and rights to copy,
|
||||
* modify and redistribute granted by the license, users are provided only
|
||||
* with a limited warranty and the software's author, the holder of the
|
||||
* economic rights, and the successive licensors have only limited
|
||||
* liability.
|
||||
*
|
||||
* In this respect, the user's attention is drawn to the risks associated
|
||||
* with loading, using, modifying and/or developing or reproducing the
|
||||
* software by the user in light of its specific status of free software,
|
||||
* that may mean that it is complicated to manipulate, and that also
|
||||
* therefore means that it is reserved for developers and experienced
|
||||
* professionals having in-depth computer knowledge. Users are therefore
|
||||
* encouraged to load and test the software's suitability as regards their
|
||||
* requirements in conditions enabling the security of their systems and/or
|
||||
* data to be ensured and, more generally, to use and operate it in the
|
||||
* same conditions as regards security.
|
||||
*
|
||||
* The fact that you are presently reading this means that you have had
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
/**
|
||||
* gclc-socket:fr.bigeon.gclc.socket.SocketConsoleApplicationTest.java
|
||||
* Created on: Jun 1, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Socket;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.smu.StringEncoder;
|
||||
|
||||
/** Test class for {@link SocketConsoleApplicationShell}
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
@SuppressWarnings({"static-method", "unused", "javadoc", "nls"})
|
||||
public class SocketConsoleApplicationTest {
|
||||
|
||||
private static final StringEncoder ENCODER = new StringEncoder("%",
|
||||
Arrays.asList("\n")); //$NON-NLS-1$
|
||||
|
||||
@Test
|
||||
public void integrationTest() {
|
||||
Thread server = TestServer.startServer(false);
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
final String hostName = "127.0.0.1";
|
||||
final int portNumber = 3300;
|
||||
|
||||
try (Socket kkSocket = new Socket(hostName, portNumber);
|
||||
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(),
|
||||
true);
|
||||
BufferedReader in = new BufferedReader(
|
||||
new InputStreamReader(kkSocket.getInputStream()));) {
|
||||
|
||||
String fromServer;
|
||||
int i = 0;
|
||||
String[] cmds = {"help", "test", "close"};
|
||||
while ((fromServer = in.readLine()) != null) {
|
||||
System.out.println("Server: \n" + ENCODER.decode(fromServer));
|
||||
if (fromServer.equals("Bye.")) {
|
||||
break;
|
||||
}
|
||||
|
||||
final String fromUser = cmds[i];
|
||||
if (fromUser != null) {
|
||||
System.out.println("Client: " + fromUser);
|
||||
out.println(fromUser);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
TestServer.closeServer();
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
server = TestServer.startServer(true);
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
try (Socket kkSocket = new Socket(hostName, portNumber);
|
||||
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(),
|
||||
true);
|
||||
BufferedReader in = new BufferedReader(
|
||||
new InputStreamReader(kkSocket.getInputStream()));) {
|
||||
|
||||
String fromServer;
|
||||
int i = 0;
|
||||
String[] cmds = {"help", "test", "close"};
|
||||
while ((fromServer = in.readLine()) != null) {
|
||||
// System.out.println("Server: \n" + ENCODER.decode(fromServer));
|
||||
if (fromServer.equals("Bye.")) {
|
||||
break;
|
||||
}
|
||||
|
||||
final String fromUser = cmds[i];
|
||||
if (fromUser != null) {
|
||||
// System.out.println("Client: " + fromUser);
|
||||
out.println(fromUser);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
TestServer.closeServer();
|
||||
|
||||
}
|
||||
}
|
@ -34,26 +34,58 @@
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
/** TODO Describe TestServer.java
|
||||
* @author Emmanuel Bigeon
|
||||
*
|
||||
*/
|
||||
/** A test server
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
@SuppressWarnings({"javadoc", "nls"})
|
||||
public class TestServer {
|
||||
|
||||
private static SocketConsoleApplicationShell SHELL;
|
||||
private static Thread server;
|
||||
|
||||
/** @param args no argument */
|
||||
@SuppressWarnings("nls")
|
||||
public static void main(String[] args) {
|
||||
final SocketConsoleApplicationShell shell = new SocketConsoleApplicationShell(
|
||||
3300, "close");
|
||||
final ConsoleTestApplication app = new ConsoleTestApplication(
|
||||
shell.getConsoleManager());
|
||||
shell.setApplication(app);
|
||||
final Thread serverTh = new Thread(shell, "gclcServer");
|
||||
serverTh.start();
|
||||
public static void main(String... args) {
|
||||
try {
|
||||
serverTh.join();
|
||||
startServer(false).join();
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Thread getServer() {
|
||||
if (server == null) {
|
||||
server = new Thread(getShell(), "gclcServer");
|
||||
server.start();
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
/** @return */
|
||||
private static SocketConsoleApplicationShell getShell() {
|
||||
if (SHELL == null) {
|
||||
SHELL = new SocketConsoleApplicationShell(3300, "close",
|
||||
ConsoleTestApplication.EXIT);
|
||||
final ConsoleTestApplication app = new ConsoleTestApplication(
|
||||
SHELL.getConsoleManager());
|
||||
SHELL.setApplication(app);
|
||||
}
|
||||
return SHELL;
|
||||
}
|
||||
|
||||
public static Thread startServer(boolean autoClose) {
|
||||
if (SHELL == null) {
|
||||
SHELL = new SocketConsoleApplicationShell(3300, autoClose,
|
||||
ConsoleTestApplication.EXIT);
|
||||
final ConsoleTestApplication app = new ConsoleTestApplication(
|
||||
SHELL.getConsoleManager());
|
||||
SHELL.setApplication(app);
|
||||
server = null;
|
||||
}
|
||||
return getServer();
|
||||
}
|
||||
|
||||
public static void closeServer() {
|
||||
SHELL.stop();
|
||||
SHELL = null;
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@
|
||||
<dependency>
|
||||
<groupId>fr.bigeon</groupId>
|
||||
<artifactId>collections</artifactId>
|
||||
<version>1.0.1-SNAPSHOT</version>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<inceptionYear>2015</inceptionYear>
|
||||
|
@ -52,15 +52,75 @@ import org.eclipse.swt.widgets.Text;
|
||||
|
||||
import fr.bigeon.collections.ArrayRibbon;
|
||||
import fr.bigeon.collections.Ribbon;
|
||||
import fr.bigeon.gclc.CommandRequestListener;
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.ConsoleManager;
|
||||
|
||||
/** A SWT component to connect to gclc {@link ConsoleApplication}
|
||||
* <p>
|
||||
*
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class SWTConsole extends Composite implements ConsoleManager, CommandRequestListener {
|
||||
public class SWTConsole extends Composite implements ConsoleManager {
|
||||
/** A key listener to validate commands and manage the history of commands
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public static final class HistoryTextKeyListener extends KeyAdapter {
|
||||
|
||||
/** The size of commands history */
|
||||
private static final int DEFAULT_HISTORY_SIZE = 10;
|
||||
/** The history ribbon */
|
||||
private final Ribbon<String> commands;
|
||||
/** The current index in history search */
|
||||
private int currentIndex = 0;
|
||||
/** The console to write the commands in */
|
||||
private final Text consoleInput;
|
||||
/** The console to notify of command validation */
|
||||
private final SWTConsole console;
|
||||
|
||||
/** @param console the console
|
||||
* @param consoleInput the text to write commands in */
|
||||
public HistoryTextKeyListener(SWTConsole console, Text consoleInput) {
|
||||
super();
|
||||
this.console = console;
|
||||
this.consoleInput = consoleInput;
|
||||
this.commands = new ArrayRibbon<>(DEFAULT_HISTORY_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
// Enter validates the command if prompting
|
||||
if (e.keyCode == '\r') {
|
||||
commands.add(consoleInput.getText());
|
||||
console.validateInput();
|
||||
currentIndex = -1;
|
||||
}
|
||||
|
||||
// Upper arrow retrieves previous commands
|
||||
if (e.keyCode == SWT.ARROW_UP &&
|
||||
currentIndex < commands.size() - 1) {
|
||||
currentIndex++;
|
||||
consoleInput.setText(
|
||||
commands.get(commands.size() - currentIndex - 1));
|
||||
consoleInput.setSelection(consoleInput.getText().length());
|
||||
}
|
||||
|
||||
// Lower arrow retrieves next commands
|
||||
if (e.keyCode == SWT.ARROW_DOWN) {
|
||||
if (currentIndex == 0) {
|
||||
currentIndex--;
|
||||
consoleInput.setText(new String());
|
||||
} else if (currentIndex > 0) {
|
||||
consoleInput.setText(commands
|
||||
.get(commands.size() - (--currentIndex) - 1));
|
||||
consoleInput.setSelection(consoleInput.getText().length());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final int LAYOUT_NB_COLUMNS = 2;
|
||||
/** The cmd prefix in the output console */
|
||||
private static final String CMD_PREFIX = "[CMD] "; //$NON-NLS-1$
|
||||
/** The console output text field */
|
||||
@ -78,25 +138,19 @@ public class SWTConsole extends Composite implements ConsoleManager, CommandRequ
|
||||
/** The object for thread synchronization with the prompt */
|
||||
private final Object promptLock = new Object();
|
||||
|
||||
/** The ribbon of commands */
|
||||
private final Ribbon<String> commands;
|
||||
/** The current index in the ribbon */
|
||||
private int currentIndex = 0;
|
||||
|
||||
/** Create the composite.
|
||||
*
|
||||
*
|
||||
* @param parent the prent composite
|
||||
* @param style the composite style */
|
||||
public SWTConsole(Composite parent, int style) {
|
||||
super(parent, style);
|
||||
|
||||
// inner elements
|
||||
commands = new ArrayRibbon<>(10);
|
||||
setLayout(new GridLayout(LAYOUT_NB_COLUMNS, false));
|
||||
|
||||
setLayout(new GridLayout(2, false));
|
||||
|
||||
consoleOutput = new Text(this, SWT.BORDER | SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL | SWT.MULTI);
|
||||
consoleOutput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
|
||||
consoleOutput = new Text(this, SWT.BORDER | SWT.READ_ONLY | SWT.WRAP |
|
||||
SWT.V_SCROLL | SWT.MULTI);
|
||||
consoleOutput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true,
|
||||
LAYOUT_NB_COLUMNS, 1));
|
||||
consoleOutput.setRedraw(true);
|
||||
consoleOutput.addFocusListener(new FocusAdapter() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@ -110,45 +164,28 @@ public class SWTConsole extends Composite implements ConsoleManager, CommandRequ
|
||||
lblPromptlabel.setText(prompt);
|
||||
|
||||
consoleInput = new Text(this, SWT.BORDER);
|
||||
consoleInput.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
|
||||
consoleInput.addKeyListener(new KeyAdapter() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
// Enter validates the command if prompting
|
||||
if (e.keyCode == '\r' && prompting) {
|
||||
synchronized (promptLock) {
|
||||
command = consoleInput.getText();
|
||||
prompting = false;
|
||||
consoleInput.setText(new String());
|
||||
consoleOutput.append(CMD_PREFIX + command + System.lineSeparator());
|
||||
currentIndex = -1;
|
||||
promptLock.notifyAll();
|
||||
}
|
||||
}
|
||||
consoleInput.setLayoutData(
|
||||
new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
|
||||
consoleInput.addKeyListener(
|
||||
new HistoryTextKeyListener(this, consoleInput));
|
||||
|
||||
// Upper arrow retrieves previous commands
|
||||
if (e.keyCode == SWT.ARROW_UP) {
|
||||
if (currentIndex < commands.size() - 1) {
|
||||
currentIndex++;
|
||||
consoleInput.setText(commands.get(commands.size() - currentIndex - 1));
|
||||
consoleInput.setSelection(consoleInput.getText().length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lower arrow retrieves next commands
|
||||
if (e.keyCode == SWT.ARROW_DOWN) {
|
||||
if (currentIndex == 0) {
|
||||
currentIndex--;
|
||||
consoleInput.setText(new String());
|
||||
} else if (currentIndex > 0) {
|
||||
consoleInput.setText(commands.get(commands.size() - (--currentIndex) - 1));
|
||||
consoleInput.setSelection(consoleInput.getText().length());
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected void validateInput() {
|
||||
if (prompting) {
|
||||
synchronized (promptLock) {
|
||||
command = consoleInput.getText();
|
||||
prompting = false;
|
||||
consoleInput.setText(new String());
|
||||
consoleInput.setEnabled(false);
|
||||
consoleOutput
|
||||
.append(CMD_PREFIX + command + System.lineSeparator());
|
||||
promptLock.notifyAll();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -156,21 +193,6 @@ public class SWTConsole extends Composite implements ConsoleManager, CommandRequ
|
||||
// Disable the check that prevents subclassing of SWT components
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#setPrompt(java.lang.String) */
|
||||
@Override
|
||||
public void setPrompt(final String prompt) {
|
||||
this.prompt = prompt;
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
lblPromptlabel.setText(prompt);
|
||||
lblPromptlabel.pack();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#getPrompt() */
|
||||
@Override
|
||||
@ -178,76 +200,6 @@ public class SWTConsole extends Composite implements ConsoleManager, CommandRequ
|
||||
return prompt;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt() */
|
||||
@Override
|
||||
public String prompt() {
|
||||
synchronized (promptLock) {
|
||||
try {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
consoleInput.setFocus();
|
||||
}
|
||||
});
|
||||
prompting = true;
|
||||
promptLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
command = null;
|
||||
}
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt(java.lang.String) */
|
||||
@Override
|
||||
public String prompt(final String message) {
|
||||
synchronized (promptLock) {
|
||||
try {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
lblPromptlabel.setText(message);
|
||||
// relayout
|
||||
SWTConsole.this.layout();
|
||||
consoleInput.setFocus();
|
||||
}
|
||||
});
|
||||
prompting = true;
|
||||
promptLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
command = null;
|
||||
} finally {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
lblPromptlabel.setText(prompt);
|
||||
lblPromptlabel.pack();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#println(java.lang.String) */
|
||||
@Override
|
||||
public void println(final String message) {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
consoleOutput.append(message + System.lineSeparator());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#print(java.lang.String) */
|
||||
@Override
|
||||
@ -274,6 +226,78 @@ public class SWTConsole extends Composite implements ConsoleManager, CommandRequ
|
||||
});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#println(java.lang.String) */
|
||||
@Override
|
||||
public void println(final String message) {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
consoleOutput.append(message + System.lineSeparator());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt() */
|
||||
@Override
|
||||
public String prompt() {
|
||||
synchronized (promptLock) {
|
||||
try {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
consoleInput.setEnabled(true);
|
||||
consoleInput.setFocus();
|
||||
}
|
||||
});
|
||||
prompting = true;
|
||||
promptLock.wait();
|
||||
} catch (final InterruptedException e) {
|
||||
command = null;
|
||||
}
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt(java.lang.String) */
|
||||
@Override
|
||||
public String prompt(final String message) {
|
||||
synchronized (promptLock) {
|
||||
try {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
lblPromptlabel.setText(message);
|
||||
// relayout
|
||||
SWTConsole.this.layout();
|
||||
consoleInput.setEnabled(true);
|
||||
consoleInput.setFocus();
|
||||
}
|
||||
});
|
||||
prompting = true;
|
||||
promptLock.wait();
|
||||
} catch (final InterruptedException e) {
|
||||
command = null;
|
||||
} finally {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
lblPromptlabel.setText(prompt);
|
||||
lblPromptlabel.pack();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.swt.widgets.Composite#setFocus() */
|
||||
@Override
|
||||
@ -282,11 +306,18 @@ public class SWTConsole extends Composite implements ConsoleManager, CommandRequ
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* fr.bigeon.gclc.CommandRequestListener#commandRequest(java.lang.String) */
|
||||
* @see fr.bigeon.gclc.ConsoleManager#setPrompt(java.lang.String) */
|
||||
@Override
|
||||
public void commandRequest(String request) {
|
||||
commands.add(request);
|
||||
public void setPrompt(final String prompt) {
|
||||
this.prompt = prompt;
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
lblPromptlabel.setText(prompt);
|
||||
lblPromptlabel.pack();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -43,49 +43,40 @@ import org.eclipse.swt.layout.FillLayout;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
import fr.bigeon.gclc.CommandRequestListener;
|
||||
import fr.bigeon.gclc.ConsoleManager;
|
||||
|
||||
/** A shell containing a {@link SWTConsole}
|
||||
* <p>
|
||||
*
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class SWTConsoleShell extends Shell {
|
||||
|
||||
/** The console component */
|
||||
private final SWTConsole console;
|
||||
private SWTConsole console;
|
||||
|
||||
/** Create the shell.
|
||||
*
|
||||
*
|
||||
* @param display the display */
|
||||
public SWTConsoleShell(Display display) {
|
||||
super(display, SWT.SHELL_TRIM);
|
||||
setLayout(new FillLayout(SWT.HORIZONTAL));
|
||||
|
||||
console = new SWTConsole(this, SWT.NONE);
|
||||
createContents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create contents of the shell.
|
||||
*/
|
||||
protected void createContents() {
|
||||
setText("Console Application"); //$NON-NLS-1$
|
||||
setSize(450, 300);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkSubclass() {
|
||||
// Disable the check that prevents subclassing of SWT components
|
||||
}
|
||||
|
||||
/** Create contents of the shell. */
|
||||
protected void createContents() {
|
||||
console = new SWTConsole(this, SWT.NONE);
|
||||
setText("Console Application"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** @return the console manager */
|
||||
public ConsoleManager getManager() {
|
||||
return console;
|
||||
}
|
||||
|
||||
/** @return the element awaiting commands */
|
||||
public CommandRequestListener getCommandListener() {
|
||||
return console;
|
||||
}
|
||||
}
|
||||
|
@ -38,45 +38,55 @@ import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* Unit test for simple App.
|
||||
*/
|
||||
public class AppTest
|
||||
extends TestCase
|
||||
{
|
||||
/**
|
||||
* Create the test case
|
||||
/** Unit test for simple App. */
|
||||
public class AppTest extends TestCase {
|
||||
protected static final long TWO_SECONDS = 2000;
|
||||
|
||||
/** Create the test case
|
||||
*
|
||||
* @param testName name of the test case
|
||||
*/
|
||||
public AppTest( String testName )
|
||||
{
|
||||
super( testName );
|
||||
* @param testName name of the test case */
|
||||
public AppTest(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the suite of tests being tested
|
||||
*/
|
||||
public static Test suite()
|
||||
{
|
||||
return new TestSuite( AppTest.class );
|
||||
/** @return the suite of tests being tested */
|
||||
public static Test suite() {
|
||||
return new TestSuite(AppTest.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rigourous Test :-)
|
||||
*/
|
||||
/** Rigourous Test :-) */
|
||||
@SuppressWarnings("static-method")
|
||||
public void testApp()
|
||||
{
|
||||
public void testApp() {
|
||||
// Display display = new Display();
|
||||
// final Shell shell = new Shell(display);
|
||||
// shell.setLayout(new GridLayout(1, false));
|
||||
// SWTConsole swtConsole = new SWTConsole(shell, SWT.NONE);
|
||||
// swtConsole.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true,
|
||||
// 1, 1));
|
||||
// swtConsole.setLayoutData(
|
||||
// new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
|
||||
// final ConsoleApplication appl = new ConsoleApplication(swtConsole,
|
||||
// "exit",
|
||||
// "Hello", "See you");
|
||||
// "exit", "Hello", "See you");
|
||||
// try {
|
||||
// appl.add(new Command("long") {
|
||||
//
|
||||
// @Override
|
||||
// public String tip() {
|
||||
// return "a long running command";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void execute(String... args) {
|
||||
// try {
|
||||
// Thread.sleep(TWO_SECONDS);
|
||||
// } catch (InterruptedException e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// } catch (InvalidCommandName e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// shell.pack();
|
||||
// shell.open();
|
||||
// Thread applThread = new Thread(new Runnable() {
|
||||
@ -94,9 +104,11 @@ public class AppTest
|
||||
// });
|
||||
// applThread.start();
|
||||
// while (!shell.isDisposed()) {
|
||||
// if (!display.readAndDispatch()) display.sleep();
|
||||
// if (!display.readAndDispatch()) {
|
||||
// display.sleep();
|
||||
// }
|
||||
// }
|
||||
// display.dispose();
|
||||
assertTrue( true );
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ package fr.bigeon.gclc;
|
||||
* @author Emmanuel Bigeon */
|
||||
public interface CommandRequestListener {
|
||||
/** Indicates that the given command was requested to the application
|
||||
*
|
||||
*
|
||||
* @param command the command */
|
||||
void commandRequest(String command);
|
||||
}
|
||||
|
@ -39,26 +39,31 @@ package fr.bigeon.gclc;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import fr.bigeon.gclc.command.Command;
|
||||
import fr.bigeon.gclc.command.HelpExecutor;
|
||||
import fr.bigeon.gclc.command.ICommand;
|
||||
import fr.bigeon.gclc.command.ICommandProvider;
|
||||
import fr.bigeon.gclc.command.SubedCommand;
|
||||
import fr.bigeon.gclc.command.UnrecognizedCommand;
|
||||
import fr.bigeon.gclc.exception.CommandParsingException;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
import fr.bigeon.gclc.i18n.Messages;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.SystemConsoleManager;
|
||||
import fr.bigeon.gclc.prompt.CLIPrompterMessages;
|
||||
import fr.bigeon.gclc.system.SystemConsoleManager;
|
||||
|
||||
/** <p>
|
||||
* A {@link ConsoleApplication} is an application that require the user to input
|
||||
* commands.
|
||||
* <p>
|
||||
* A typical use case is the following:
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* {@link ConsoleApplication} app = new {@link ConsoleApplication#ConsoleApplication(String, String, String) ConsoleApplication("exit", "welcome", "see you latter")};
|
||||
* app.{@link ConsoleApplication#add(Command) add}("my_command", new {@link Command MyCommand()});
|
||||
* app.{@link ConsoleApplication#add(ICommand) add}("my_command", new {@link ICommand MyCommand()});
|
||||
* app.start();
|
||||
* </pre>
|
||||
* <p>
|
||||
@ -70,6 +75,9 @@ import fr.bigeon.gclc.system.SystemConsoleManager;
|
||||
* @author Emmanuel BIGEON */
|
||||
public class ConsoleApplication implements ICommandProvider {
|
||||
|
||||
/** The class logger */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(ConsoleApplication.class.getName());
|
||||
/** The welcome message */
|
||||
private final String header;
|
||||
/** The good bye message */
|
||||
@ -98,132 +106,42 @@ public class ConsoleApplication implements ICommandProvider {
|
||||
* @param exit the keyword for the exit command of this application
|
||||
* @param welcome the header message to display on launch of this
|
||||
* application
|
||||
* @param goodbye the message to display on exit */
|
||||
* @param goodbye the message to display on exit
|
||||
* @throws InvalidCommandName if the exit command name is invalid */
|
||||
public ConsoleApplication(ConsoleManager manager, String exit,
|
||||
String welcome, String goodbye) {
|
||||
String welcome, String goodbye) throws InvalidCommandName {
|
||||
this(manager, welcome, goodbye);
|
||||
try {
|
||||
root.add(new ExitCommand(exit, this));
|
||||
} catch (InvalidCommandName e) {
|
||||
throw new RuntimeException("Invalid exit command name", e); //$NON-NLS-1$
|
||||
}
|
||||
root.add(new ExitCommand(exit, this));
|
||||
}
|
||||
|
||||
/** @param exit the keyword for the exit command of this application
|
||||
* @param welcome the header message to display on launch of this
|
||||
* application
|
||||
* @param goodbye the message to display on exit */
|
||||
public ConsoleApplication(String exit, String welcome, String goodbye) {
|
||||
* @param goodbye the message to display on exit
|
||||
* @throws InvalidCommandName if the exit command name is invalid */
|
||||
public ConsoleApplication(String exit, String welcome,
|
||||
String goodbye) throws InvalidCommandName {
|
||||
this(new SystemConsoleManager(), welcome, goodbye);
|
||||
try {
|
||||
root.add(new ExitCommand(exit, this));
|
||||
} catch (InvalidCommandName e) {
|
||||
throw new RuntimeException("Invalid exit command name", e); //$NON-NLS-1$
|
||||
}
|
||||
root.add(new ExitCommand(exit, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean add(Command cmd) throws InvalidCommandName {
|
||||
public final boolean add(ICommand cmd) throws InvalidCommandName {
|
||||
return root.add(cmd);
|
||||
}
|
||||
|
||||
/** Launches the prompting application */
|
||||
public final void start() {
|
||||
if (header != null) manager.println(header);
|
||||
running = true;
|
||||
do {
|
||||
String cmd = manager.prompt();
|
||||
if (cmd.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
for (CommandRequestListener listener : listeners) {
|
||||
listener.commandRequest(cmd);
|
||||
}
|
||||
interpretCommand(cmd);
|
||||
} while (running);
|
||||
if (footer != null) manager.println(footer);
|
||||
}
|
||||
|
||||
/** @param cmd the command to interpret */
|
||||
public final void interpretCommand(String cmd) {
|
||||
List<String> args = new ArrayList<>();
|
||||
// parse the string to separate arguments
|
||||
int index = 0;
|
||||
int startIndex = 0;
|
||||
boolean escaped = false;
|
||||
boolean inString = false;
|
||||
while (index < cmd.length()) {
|
||||
if (escaped) {
|
||||
escaped = false;
|
||||
} else if (cmd.charAt(index) == '\\') {
|
||||
escaped = true;
|
||||
} else if (cmd.charAt(index) == ' ') {
|
||||
if (!inString) {
|
||||
if (startIndex != index) {
|
||||
String arg = cmd.substring(startIndex, index);
|
||||
if (!arg.isEmpty()) {
|
||||
args.add(arg);
|
||||
}
|
||||
}
|
||||
startIndex = index + 1;
|
||||
}
|
||||
} else if (cmd.charAt(index) == '"') {
|
||||
if (inString) {
|
||||
inString = false;
|
||||
args.add(cmd.substring(startIndex + 1, index));
|
||||
startIndex = index + 2;
|
||||
index++;
|
||||
if (index < cmd.length() && cmd.charAt(index) != ' ') {
|
||||
manager.println("Command line cannot be parsed"); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
} else if (startIndex == index) {
|
||||
inString = true;
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
if (startIndex < cmd.length()) {
|
||||
String arg = cmd.substring(startIndex, index);
|
||||
if (!arg.isEmpty()) {
|
||||
args.add(arg);
|
||||
}
|
||||
}
|
||||
if (args.size() > 0) {
|
||||
try {
|
||||
executeSub(
|
||||
args.get(0),
|
||||
Arrays.copyOfRange(args.toArray(new String[0]), 1,
|
||||
args.size()));
|
||||
} catch (CommandRunException e) {
|
||||
manager.println("The command '" + cmd + "' failed due to:"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
manager.println(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Exit this running application before next command prompt */
|
||||
public final void exit() {
|
||||
running = false;
|
||||
}
|
||||
|
||||
/** Adds help command on the given key
|
||||
*
|
||||
*
|
||||
* @param cmd the handle for help
|
||||
* @return if the help command was added */
|
||||
public final boolean addHelpCommand(String cmd) {
|
||||
try {
|
||||
return root.add(new HelpExecutor(cmd, manager, root));
|
||||
} catch (InvalidCommandName e) {
|
||||
return false;
|
||||
}
|
||||
* @return if the help command was added
|
||||
* @throws InvalidCommandName if the help command was not valid */
|
||||
public final boolean addHelpCommand(String cmd) throws InvalidCommandName {
|
||||
return root.add(new HelpExecutor(cmd, manager, root));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommandProvider#get(java.lang.String) */
|
||||
@Override
|
||||
public final Command get(String command) {
|
||||
return root.get(command);
|
||||
/** @param listener the listener to remove. */
|
||||
public final void addListener(CommandRequestListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@ -235,14 +153,100 @@ public class ConsoleApplication implements ICommandProvider {
|
||||
root.executeSub(command, args);
|
||||
}
|
||||
|
||||
/** Exit this running application before next command prompt */
|
||||
public final void exit() {
|
||||
running = false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommandProvider#get(java.lang.String) */
|
||||
@Override
|
||||
public final ICommand get(String command) {
|
||||
return root.get(command);
|
||||
}
|
||||
|
||||
/** @return the manager */
|
||||
public final ConsoleManager getManager() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
/** @param listener the listener to remove. */
|
||||
public final void addListener(CommandRequestListener listener) {
|
||||
listeners.add(listener);
|
||||
/** @param cmd the command to interpret */
|
||||
public final void interpretCommand(String cmd) {
|
||||
List<String> args;
|
||||
try {
|
||||
args = splitCommand(cmd);
|
||||
} catch (CommandParsingException e1) {
|
||||
manager.println("Command line cannot be parsed"); //$NON-NLS-1$
|
||||
LOGGER.log(Level.INFO, "Invalid user command " + cmd, e1); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
if (!args.isEmpty()) {
|
||||
try {
|
||||
executeSub(args.get(0), Arrays.copyOfRange(
|
||||
args.toArray(new String[0]), 1, args.size()));
|
||||
} catch (final CommandRunException e) {
|
||||
LOGGER.log(Level.WARNING, "Command failed: " + cmd, e); //$NON-NLS-1$
|
||||
manager.println(Messages
|
||||
.getString("ConsoleApplication.cmd.failed", cmd)); //$NON-NLS-1$
|
||||
manager.println(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Splits a command in the diferrent arguments
|
||||
*
|
||||
* @param cmd the command to split in its parts
|
||||
* @return the list of argument preceded by the command name
|
||||
* @throws CommandParsingException if the parsing of the command failed */
|
||||
private static List<String> splitCommand(String cmd) throws CommandParsingException {
|
||||
final List<String> args = new ArrayList<>();
|
||||
// parse the string to separate arguments
|
||||
int index = 0;
|
||||
int startIndex = 0;
|
||||
boolean escaped = false;
|
||||
boolean inString = false;
|
||||
while (index < cmd.length()) {
|
||||
char c = cmd.charAt(index);
|
||||
index++;
|
||||
if (escaped || c == '\\') {
|
||||
escaped = !escaped;
|
||||
continue;
|
||||
}
|
||||
if (c == ' ' && !inString) {
|
||||
final String arg = cmd.substring(startIndex, index - 1);
|
||||
if (!arg.isEmpty()) {
|
||||
args.add(arg);
|
||||
}
|
||||
startIndex = index;
|
||||
} else if (c == '"') {
|
||||
if (inString) {
|
||||
inString = false;
|
||||
args.add(endOfString(cmd, startIndex, index));
|
||||
index++;
|
||||
startIndex = index;
|
||||
}
|
||||
inString = startIndex == index - 1;
|
||||
}
|
||||
}
|
||||
final String arg = cmd.substring(startIndex, cmd.length());
|
||||
if (!arg.isEmpty()) {
|
||||
args.add(arg);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
/** @param cmd the command to parse
|
||||
* @param startIndex the starting point of the parsing
|
||||
* @param index the index of the current position
|
||||
* @return the argument
|
||||
* @throws CommandParsingException if the end of string does not mark end of
|
||||
* command and is not followed by a space */
|
||||
private static String endOfString(String cmd, int startIndex,
|
||||
int index) throws CommandParsingException {
|
||||
if (index + 1 < cmd.length() && cmd.charAt(index + 1) != ' ') {
|
||||
throw new CommandParsingException("Misplaced quote"); //$NON-NLS-1$
|
||||
}
|
||||
return cmd.substring(startIndex + 1, index - 1);
|
||||
}
|
||||
|
||||
/** @param listener the listener to remove */
|
||||
@ -254,36 +258,53 @@ public class ConsoleApplication implements ICommandProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Launches the prompting application */
|
||||
public final void start() {
|
||||
if (header != null) {
|
||||
manager.println(header);
|
||||
}
|
||||
running = true;
|
||||
do {
|
||||
final String cmd = manager.prompt();
|
||||
if (cmd.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
for (final CommandRequestListener listener : listeners) {
|
||||
listener.commandRequest(cmd);
|
||||
}
|
||||
interpretCommand(cmd);
|
||||
} while (running);
|
||||
if (footer != null) {
|
||||
manager.println(footer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** <p>
|
||||
* A command to exit a {@link ConsoleApplication}.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
class ExitCommand extends Command {
|
||||
class ExitCommand implements ICommand {
|
||||
/** The exit command manual message key */
|
||||
private static final String EXIT_MAN = "exit.man"; //$NON-NLS-1$
|
||||
/** The tip of the exit command */
|
||||
private static final String EXIT = "exit.tip"; //$NON-NLS-1$
|
||||
/** The application that will be exited when this command runs */
|
||||
private final ConsoleApplication app;
|
||||
/** The exit command name */
|
||||
private final String name;
|
||||
|
||||
/** @param name the name of the command
|
||||
* @param app the application to exit */
|
||||
public ExitCommand(String name, ConsoleApplication app) {
|
||||
super(name);
|
||||
this.name = name;
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return CLIPrompterMessages.getString(EXIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void help(ConsoleManager manager, String... args) {
|
||||
manager.println(CLIPrompterMessages
|
||||
.getString(EXIT_MAN, (Object[]) args));
|
||||
/** The actions to take before exiting */
|
||||
public void beforeExit() {
|
||||
// Do nothing by default
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -292,8 +313,21 @@ class ExitCommand extends Command {
|
||||
app.exit();
|
||||
}
|
||||
|
||||
/** The actions to take before exiting */
|
||||
public void beforeExit() {
|
||||
// Do nothing by default
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#getCommandName() */
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void help(ConsoleManager manager, String... args) {
|
||||
manager.println(
|
||||
CLIPrompterMessages.getString(EXIT_MAN, (Object[]) args));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return CLIPrompterMessages.getString(EXIT);
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
|
||||
/** <p>
|
||||
* A command to execute. It is mandatory that it has a name and that name cannot
|
||||
@ -59,12 +59,12 @@ import fr.bigeon.gclc.ConsoleManager;
|
||||
* <p>
|
||||
* The default behavior for the brief message is to print the tip preceeded by a
|
||||
* couple of spaces.
|
||||
*
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public abstract class Command {
|
||||
public abstract class Command implements ICommand {
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
private static final String EOL_LINUX = "\n"; //$NON-NLS-1$
|
||||
/** The name of the command */
|
||||
@ -76,41 +76,34 @@ public abstract class Command {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/** @return the command's name */
|
||||
/** @return a brief description of the command */
|
||||
protected String brief() {
|
||||
return " " + tip(); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#getCommandName() */
|
||||
@Override
|
||||
public final String getCommandName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/** @param args the arguments of the command (some expect an empty array) */
|
||||
public abstract void execute(String... args);
|
||||
|
||||
/** This prints the help associated to this command.
|
||||
* <p>
|
||||
* The default behavior is to print:
|
||||
*
|
||||
* <pre>
|
||||
* [Command name]
|
||||
* [brief message]
|
||||
*
|
||||
* Usage:
|
||||
* [Usage pattern]
|
||||
*
|
||||
* [Usage details]
|
||||
* </pre>
|
||||
*
|
||||
* @param manager the manager to print the data
|
||||
* @param args the arguments called with the help */
|
||||
public void help(ConsoleManager manager, String... args) {
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#help(fr.bigeon.gclc.ConsoleManager,
|
||||
* java.lang.String) */
|
||||
@Override
|
||||
public final void help(ConsoleManager manager, String... args) {
|
||||
manager.println(getCommandName());
|
||||
manager.println(brief());
|
||||
manager.println();
|
||||
manager.println("Usage:"); //$NON-NLS-1$
|
||||
manager.println(usagePattern());
|
||||
manager.println();
|
||||
String details = usageDetail();
|
||||
final String details = usageDetail();
|
||||
if (details != null && !details.isEmpty()) {
|
||||
manager.print(details);
|
||||
if (!(details.endsWith(EOL_LINUX) || details.endsWith(System.lineSeparator()))) {
|
||||
if (!(details.endsWith(EOL_LINUX) ||
|
||||
details.endsWith(System.lineSeparator()))) {
|
||||
manager.println();
|
||||
}
|
||||
}
|
||||
@ -119,7 +112,7 @@ public abstract class Command {
|
||||
/** <p>
|
||||
* This method return the detail of the help. It immediatly follows the
|
||||
* {@link #usagePattern() usage pattern}.
|
||||
*
|
||||
*
|
||||
* @return the detailed help (should end with end of line or be empty) */
|
||||
@SuppressWarnings("static-method")
|
||||
protected String usageDetail() {
|
||||
@ -129,17 +122,9 @@ public abstract class Command {
|
||||
/** <p>
|
||||
* This prints the usage pattern for the command. It follows the brief
|
||||
* introduction on the command ({@link #brief()})
|
||||
*
|
||||
*
|
||||
* @return the usage pattern */
|
||||
protected String usagePattern() {
|
||||
return getCommandName();
|
||||
}
|
||||
|
||||
/** @return a brief description of the command */
|
||||
protected String brief() {
|
||||
return " " + tip(); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** @return a tip on the command */
|
||||
public abstract String tip();
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** <p>
|
||||
@ -50,10 +51,14 @@ import java.util.Set;
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class CommandParameters {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final int STRINGARG_NUMBER_OF_ELEMENTS = 2;
|
||||
/** Boolean arguments */
|
||||
private final HashMap<String, Boolean> boolArgs = new HashMap<>();
|
||||
private final Map<String, Boolean> boolArgs = new HashMap<>();
|
||||
/** String arguments */
|
||||
private final HashMap<String, String> stringArgs = new HashMap<>();
|
||||
private final Map<String, String> stringArgs = new HashMap<>();
|
||||
/** Arguments restriction on the named ones */
|
||||
private final boolean strict;
|
||||
/** additional (unnamed) parameters */
|
||||
@ -65,49 +70,26 @@ public class CommandParameters {
|
||||
@SuppressWarnings("boxing")
|
||||
public CommandParameters(Set<String> bools, Set<String> strings,
|
||||
boolean strict) {
|
||||
for (String string : bools) {
|
||||
for (final String string : bools) {
|
||||
boolArgs.put(string, false);
|
||||
}
|
||||
for (String string : strings) {
|
||||
for (final String string : strings) {
|
||||
stringArgs.put(string, null);
|
||||
}
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
/** @param args the arguments to parse
|
||||
* @return if the arguments were parsed */
|
||||
@SuppressWarnings("boxing")
|
||||
public boolean parseArgs(String... args) {
|
||||
int i = 0;
|
||||
while (i < args.length) {
|
||||
String name = args[i];
|
||||
if (name.startsWith("-")) { //$NON-NLS-1$
|
||||
name = name.substring(1);
|
||||
if (boolArgs.containsKey(name)) {
|
||||
boolArgs.put(name, true);
|
||||
} else if (stringArgs.containsKey(name)) {
|
||||
i++;
|
||||
if (!(args.length > i)) {
|
||||
return false;
|
||||
}
|
||||
stringArgs.put(name, args[i]);
|
||||
} else if (strict) {
|
||||
return false;
|
||||
} else {
|
||||
additional.add(name);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @param key the key
|
||||
* @return the associated value, null if it was not specified */
|
||||
public String get(String key) {
|
||||
return stringArgs.get(key);
|
||||
}
|
||||
|
||||
/** @return additional non parsed parameters */
|
||||
public List<String> getAdditionals() {
|
||||
return Collections.unmodifiableList(additional);
|
||||
}
|
||||
|
||||
/** @param key the key
|
||||
* @return if the key was specified */
|
||||
@SuppressWarnings("boxing")
|
||||
@ -115,17 +97,63 @@ public class CommandParameters {
|
||||
return boolArgs.get(key);
|
||||
}
|
||||
|
||||
/** @param string the key
|
||||
* @param value the value */
|
||||
public void set(String string, String value) {
|
||||
if (stringArgs.containsKey(string)) {
|
||||
stringArgs.put(string, value);
|
||||
/** @param args the arguments to parse
|
||||
* @return if the arguments were parsed */
|
||||
public boolean parseArgs(String... args) {
|
||||
int i = 0;
|
||||
while (i < args.length) {
|
||||
String next = null;
|
||||
if (i < args.length - 1) {
|
||||
next = args[i + 1];
|
||||
}
|
||||
int p = parseArg(args[i], next);
|
||||
if (p == 0) {
|
||||
return false;
|
||||
}
|
||||
i += p;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/** @return additional non parsed parameters */
|
||||
public List<String> getAdditionals() {
|
||||
return Collections.unmodifiableList(additional);
|
||||
/** Attempt to parse an argument.
|
||||
* <p>
|
||||
* This method return 0 if the parsing was incorrect, or the number of
|
||||
* parsed elements.
|
||||
*
|
||||
* @param arg the argument
|
||||
* @param next the next element
|
||||
* @return the number of element read */
|
||||
private int parseArg(String arg, String next) {
|
||||
if (!arg.startsWith("-")) { //$NON-NLS-1$
|
||||
return 1;
|
||||
}
|
||||
String name = arg.substring(1);
|
||||
if (boolArgs.containsKey(name)) {
|
||||
boolArgs.put(name, Boolean.TRUE);
|
||||
return 1;
|
||||
}
|
||||
if (stringArgs.containsKey(name)) {
|
||||
return parseStringArg(name, next);
|
||||
}
|
||||
if (strict) {
|
||||
return 0;
|
||||
}
|
||||
additional.add(name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Add a string arg value
|
||||
*
|
||||
* @param name the string arg name
|
||||
* @param next the string arg value
|
||||
* @return 2 or 0 if next is invalid */
|
||||
private int parseStringArg(String name, String next) {
|
||||
if (next == null) {
|
||||
return 0;
|
||||
}
|
||||
stringArgs.put(name, next);
|
||||
return STRINGARG_NUMBER_OF_ELEMENTS;
|
||||
}
|
||||
|
||||
/** @param string the key
|
||||
@ -136,4 +164,12 @@ public class CommandParameters {
|
||||
boolArgs.put(string, value);
|
||||
}
|
||||
}
|
||||
|
||||
/** @param string the key
|
||||
* @param value the value */
|
||||
public void set(String string, String value) {
|
||||
if (stringArgs.containsKey(string)) {
|
||||
stringArgs.put(string, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,37 +46,29 @@ import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class CommandProvider implements ICommandProvider {
|
||||
/** The minus character */
|
||||
private static final String MINUS = "-"; //$NON-NLS-1$
|
||||
/** The space character */
|
||||
private static final String SPACE = " "; //$NON-NLS-1$
|
||||
/** The commands map */
|
||||
protected final Set<Command> commands;
|
||||
protected final Set<ICommand> commands;
|
||||
/** The error command to be executed when the command isn't recognized */
|
||||
protected final Command error;
|
||||
protected final ICommand error;
|
||||
|
||||
/** @param error the error command */
|
||||
public CommandProvider(Command error) {
|
||||
public CommandProvider(ICommand error) {
|
||||
super();
|
||||
commands = new HashSet<>();
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommandProvider#get(java.lang.String) */
|
||||
@Override
|
||||
public Command get(String commandName) {
|
||||
for (Command command : commands) {
|
||||
if (command.getCommandName().equals(commandName)) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommandProvider#add(java.lang.String,
|
||||
* fr.bigeon.gclc.command.Command) */
|
||||
@Override
|
||||
public boolean add(Command value) throws InvalidCommandName {
|
||||
String name = value.getCommandName();
|
||||
if (name == null || name.startsWith("-") || name.contains(" ")) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
public boolean add(ICommand value) throws InvalidCommandName {
|
||||
final String name = value.getCommandName();
|
||||
if (name == null || name.startsWith(MINUS) || name.contains(SPACE)) {
|
||||
throw new InvalidCommandName();
|
||||
}
|
||||
return commands.add(value);
|
||||
@ -84,7 +76,7 @@ public class CommandProvider implements ICommandProvider {
|
||||
|
||||
@Override
|
||||
public void executeSub(String cmd, String... args) {
|
||||
for (Command command : commands) {
|
||||
for (final ICommand command : commands) {
|
||||
if (command.getCommandName().equals(cmd)) {
|
||||
command.execute(args);
|
||||
return;
|
||||
@ -92,4 +84,16 @@ public class CommandProvider implements ICommandProvider {
|
||||
}
|
||||
error.execute(cmd);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommandProvider#get(java.lang.String) */
|
||||
@Override
|
||||
public ICommand get(String commandName) {
|
||||
for (final ICommand command : commands) {
|
||||
if (command.getCommandName().equals(commandName)) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -38,27 +38,32 @@
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.prompt.CLIPrompterMessages;
|
||||
|
||||
/** <p>
|
||||
* TODO
|
||||
/** A command to print help of an other command.
|
||||
* <p>
|
||||
* This command will display the help of an other command
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class HelpExecutor extends Command {
|
||||
|
||||
/** The command to execute the help of */
|
||||
private final Command cmd;
|
||||
private final ICommand cmd;
|
||||
/** The console manager */
|
||||
private final ConsoleManager consoleManager;
|
||||
|
||||
/** @param cmdName the command name
|
||||
* @param consoleManager the manager for the console
|
||||
* @param cmd the command to execute the help of */
|
||||
public HelpExecutor(String cmdName, ConsoleManager consoleManager, Command cmd) {
|
||||
public HelpExecutor(String cmdName, ConsoleManager consoleManager,
|
||||
ICommand cmd) {
|
||||
super(cmdName);
|
||||
this.cmd = cmd;
|
||||
if (consoleManager == null) throw new NullPointerException("Argument cannot be null: ConsoleManager"); //$NON-NLS-1$
|
||||
if (consoleManager == null) {
|
||||
throw new NullPointerException(
|
||||
"Argument cannot be null: ConsoleManager"); //$NON-NLS-1$
|
||||
}
|
||||
this.consoleManager = consoleManager;
|
||||
}
|
||||
|
||||
@ -70,15 +75,17 @@ public class HelpExecutor extends Command {
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#help() */
|
||||
* @see fr.bigeon.gclc.command.Command#brief() */
|
||||
@Override
|
||||
public void help(ConsoleManager manager, String... args) {
|
||||
manager.println(getCommandName());
|
||||
manager.println(" A command to get help for other commands"); //$NON-NLS-1$
|
||||
manager.println();
|
||||
manager.println("Usage"); //$NON-NLS-1$
|
||||
manager.println(" " + getCommandName() + " <otherCommand>"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
manager.println();
|
||||
protected String brief() {
|
||||
return " A command to get help for other commands"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usagePattern() */
|
||||
@Override
|
||||
protected String usagePattern() {
|
||||
return getCommandName() + " <otherCommand>"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
77
gclc/src/main/java/fr/bigeon/gclc/command/ICommand.java
Normal file
77
gclc/src/main/java/fr/bigeon/gclc/command/ICommand.java
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright Bigeon Emmanuel (2014)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* provide a generic framework for console applications.
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
* modify and/or redistribute the software under the terms of the CeCILL
|
||||
* license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
* "http://www.cecill.info".
|
||||
*
|
||||
* As a counterpart to the access to the source code and rights to copy,
|
||||
* modify and redistribute granted by the license, users are provided only
|
||||
* with a limited warranty and the software's author, the holder of the
|
||||
* economic rights, and the successive licensors have only limited
|
||||
* liability.
|
||||
*
|
||||
* In this respect, the user's attention is drawn to the risks associated
|
||||
* with loading, using, modifying and/or developing or reproducing the
|
||||
* software by the user in light of its specific status of free software,
|
||||
* that may mean that it is complicated to manipulate, and that also
|
||||
* therefore means that it is reserved for developers and experienced
|
||||
* professionals having in-depth computer knowledge. Users are therefore
|
||||
* encouraged to load and test the software's suitability as regards their
|
||||
* requirements in conditions enabling the security of their systems and/or
|
||||
* data to be ensured and, more generally, to use and operate it in the
|
||||
* same conditions as regards security.
|
||||
*
|
||||
* The fact that you are presently reading this means that you have had
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
/**
|
||||
* gclc:fr.bigeon.gclc.command.ICommand.java
|
||||
* Created on: May 31, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
|
||||
/** The contract of commands
|
||||
* <p>
|
||||
* This interface describe the contract of commands
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public interface ICommand {
|
||||
|
||||
/** @param args the arguments of the command (some expect an empty array) */
|
||||
void execute(String... args);
|
||||
|
||||
/** @return the command's name */
|
||||
String getCommandName();
|
||||
|
||||
/** This prints the help associated to this command.
|
||||
* <p>
|
||||
* The default behavior is to print:
|
||||
*
|
||||
* <pre>
|
||||
* [Command name]
|
||||
* [brief message]
|
||||
*
|
||||
* Usage:
|
||||
* [Usage pattern]
|
||||
*
|
||||
* [Usage details]
|
||||
* </pre>
|
||||
*
|
||||
* @param manager the manager to print the data
|
||||
* @param args the arguments called with the help */
|
||||
void help(ConsoleManager manager, String... args);
|
||||
|
||||
/** @return a tip on the command */
|
||||
String tip();
|
||||
|
||||
}
|
@ -45,25 +45,14 @@ import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
* @author Emmanuel BIGEON */
|
||||
public interface ICommandProvider {
|
||||
|
||||
/** <p>
|
||||
* This method provide the command with the given name found. If no command
|
||||
* with this name is found, an error command is usually returned. If there
|
||||
* are several commands with the same name, the behavior is unspecified.
|
||||
* Depending on the implementation, it may return an error command or the
|
||||
* first command with this name found.
|
||||
*
|
||||
* @param command the name of the command the user wishes to execute
|
||||
* @return the command to execute */
|
||||
public Command get(String command);
|
||||
|
||||
/** <p>
|
||||
* Adds a command to this provider, if no command was associated with the
|
||||
* given key
|
||||
*
|
||||
*
|
||||
* @param value the command to execute
|
||||
* @return if the command was added
|
||||
* @throws InvalidCommandName if the command name is invalid */
|
||||
public boolean add(Command value) throws InvalidCommandName;
|
||||
public boolean add(ICommand value) throws InvalidCommandName;
|
||||
|
||||
/** <p>
|
||||
* This method executes the command with the given name found. If no command
|
||||
@ -71,9 +60,20 @@ public interface ICommandProvider {
|
||||
* are several commands with the same name, the behavior is unspecified.
|
||||
* Depending on the implementation, it may run an error command or prompt
|
||||
* the user for a choice.
|
||||
*
|
||||
*
|
||||
* @param command the name of the command the user wishes to execute
|
||||
* @param args the arguments for the command */
|
||||
public void executeSub(String command, String... args);
|
||||
|
||||
/** <p>
|
||||
* This method provide the command with the given name found. If no command
|
||||
* with this name is found, an error command is usually returned. If there
|
||||
* are several commands with the same name, the behavior is unspecified.
|
||||
* Depending on the implementation, it may return an error command or the
|
||||
* first command with this name found.
|
||||
*
|
||||
* @param command the name of the command the user wishes to execute
|
||||
* @return the command to execute */
|
||||
public ICommand get(String command);
|
||||
|
||||
}
|
@ -43,7 +43,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
|
||||
/** <p>
|
||||
* A command relying on the {@link CommandParameters} to store parameters values
|
||||
@ -51,7 +51,8 @@ import fr.bigeon.gclc.ConsoleManager;
|
||||
* @author Emmanuel BIGEON */
|
||||
public abstract class ParametrizedCommand extends Command {
|
||||
|
||||
/** If the command may use interactive prompting for required parameters that
|
||||
/** If the command may use interactive prompting for required parameters
|
||||
* that
|
||||
* were not provided on execution */
|
||||
private boolean interactive = true;
|
||||
/** The manager */
|
||||
@ -62,7 +63,8 @@ public abstract class ParametrizedCommand extends Command {
|
||||
private final Map<String, Boolean> stringParams = new HashMap<>();
|
||||
/** The parameters mandatory status */
|
||||
private final Map<String, Boolean> params = new HashMap<>();
|
||||
/** The restriction of provided parameters on execution to declared paramters
|
||||
/** The restriction of provided parameters on execution to declared
|
||||
* paramters
|
||||
* in the status maps. */
|
||||
private final boolean strict;
|
||||
|
||||
@ -85,7 +87,7 @@ public abstract class ParametrizedCommand extends Command {
|
||||
|
||||
/** <p>
|
||||
* Add a parameter to the defined parameters
|
||||
*
|
||||
*
|
||||
* @param param the parameter identification
|
||||
* @param stringOrBool if the parameter is a parameter with an argument
|
||||
* @param needed if the parameter is required */
|
||||
@ -106,27 +108,32 @@ public abstract class ParametrizedCommand extends Command {
|
||||
}
|
||||
}
|
||||
|
||||
/** @param parameters the command parameters */
|
||||
protected abstract void doExecute(CommandParameters parameters);
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#execute(java.lang.String[]) */
|
||||
@SuppressWarnings("boxing")
|
||||
@Override
|
||||
public final void execute(String... args) {
|
||||
CommandParameters parameters = new CommandParameters(
|
||||
final CommandParameters parameters = new CommandParameters(
|
||||
boolParams.keySet(), stringParams.keySet(), strict);
|
||||
if (!parameters.parseArgs(args)) {
|
||||
// ERROR the parameters could not be correctly parsed
|
||||
manager.println("Unable to read arguments"); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
List<String> toProvide = new ArrayList<>();
|
||||
for (String string : params.keySet()) {
|
||||
final List<String> toProvide = new ArrayList<>();
|
||||
for (final String string : params.keySet()) {
|
||||
if (params.get(string) && parameters.get(string) == null) {
|
||||
if (!interactive) return;
|
||||
if (!interactive) {
|
||||
return;
|
||||
}
|
||||
toProvide.add(string);
|
||||
}
|
||||
}
|
||||
// for each needed parameters that is missing, prompt the user.
|
||||
for (String string : toProvide) {
|
||||
for (final String string : toProvide) {
|
||||
String value = manager.prompt(string);
|
||||
while (value.isEmpty()) {
|
||||
value = manager.prompt(string);
|
||||
@ -135,7 +142,4 @@ public abstract class ParametrizedCommand extends Command {
|
||||
}
|
||||
doExecute(parameters);
|
||||
}
|
||||
|
||||
/** @param parameters the command parameters */
|
||||
protected abstract void doExecute(CommandParameters parameters);
|
||||
}
|
||||
|
@ -38,123 +38,91 @@ package fr.bigeon.gclc.command;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleManager;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
|
||||
/** <p>
|
||||
* A subed command is a command that can execute sub commands depending on the
|
||||
* first argument.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class SubedCommand extends Command implements ICommandProvider {
|
||||
public class SubedCommand implements ICommandProvider, ICommand {
|
||||
|
||||
/** The tab character */
|
||||
private static final String TAB = "\t"; //$NON-NLS-1$
|
||||
/** <p>
|
||||
* The command to execute when this command is called with no sub arguments.
|
||||
* This may be null, in which case the command should have arguments. */
|
||||
private final Command noArgCommand;
|
||||
private final ICommand noArgCommand;
|
||||
/** A tip on this command. */
|
||||
private final String tip;
|
||||
/** The provider */
|
||||
private final CommandProvider provider;
|
||||
/** The name of the command */
|
||||
private final String name;
|
||||
|
||||
/** @param name the name of the command
|
||||
* @param error the error to execute when called with wrong usage */
|
||||
public SubedCommand(String name, Command error) {
|
||||
super(name);
|
||||
public SubedCommand(String name, ICommand error) {
|
||||
this.name = name;
|
||||
provider = new CommandProvider(error);
|
||||
noArgCommand = null;
|
||||
tip = null;
|
||||
}
|
||||
|
||||
/** @param name the name of the command
|
||||
* @param error the error to execute when called with wrong usage
|
||||
* @param tip the help tip associated */
|
||||
public SubedCommand(String name, Command error, String tip) {
|
||||
super(name);
|
||||
provider = new CommandProvider(error);
|
||||
noArgCommand = null;
|
||||
this.tip = tip;
|
||||
}
|
||||
|
||||
/** @param name the name of the command
|
||||
* @param noArgCommand the command to execute
|
||||
* @param error the error to execute when called with wrong usage
|
||||
* @param tip the help tip associated */
|
||||
public SubedCommand(String name, Command error, Command noArgCommand,
|
||||
String tip) {
|
||||
super(name);
|
||||
provider = new CommandProvider(error);
|
||||
this.noArgCommand = noArgCommand;
|
||||
this.tip = tip;
|
||||
}
|
||||
|
||||
/** @param name the name of the command
|
||||
* @param noArgCommand the command to execute when no extra parameter are
|
||||
* provided
|
||||
* @param error the error to execute when called with wrong usage */
|
||||
public SubedCommand(String name, Command error, Command noArgCommand) {
|
||||
super(name);
|
||||
public SubedCommand(String name, ICommand error, ICommand noArgCommand) {
|
||||
this.name = name;
|
||||
provider = new CommandProvider(error);
|
||||
this.noArgCommand = noArgCommand;
|
||||
tip = null;
|
||||
}
|
||||
|
||||
/** @param name the name of the command
|
||||
* @param noArgCommand the command to execute
|
||||
* @param error the error to execute when called with wrong usage
|
||||
* @param tip the help tip associated */
|
||||
public SubedCommand(String name, ICommand error, ICommand noArgCommand,
|
||||
String tip) {
|
||||
this.name = name;
|
||||
provider = new CommandProvider(error);
|
||||
this.noArgCommand = noArgCommand;
|
||||
this.tip = tip;
|
||||
}
|
||||
|
||||
/** @param name the name of the command
|
||||
* @param error the error to execute when called with wrong usage
|
||||
* @param tip the help tip associated */
|
||||
public SubedCommand(String name, ICommand error, String tip) {
|
||||
this.name = name;
|
||||
provider = new CommandProvider(error);
|
||||
noArgCommand = null;
|
||||
this.tip = tip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(ICommand value) throws InvalidCommandName {
|
||||
return provider.add(value);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.acide.Command#execute(java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(String... args) {
|
||||
if (args.length == 0 || args[0].startsWith("-")) { //$NON-NLS-1$
|
||||
if (noArgCommand != null)
|
||||
if (noArgCommand != null) {
|
||||
noArgCommand.execute(args);
|
||||
else provider.error.execute(args);
|
||||
} else {
|
||||
executeSub(args[0], Arrays.copyOfRange(args, 1, args.length));
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#help() */
|
||||
@Override
|
||||
public void help(ConsoleManager manager, String... args) {
|
||||
if (args.length != 0 && !args[0].startsWith("-")) { //$NON-NLS-1$
|
||||
// Specific
|
||||
Command c = get(args[0]);
|
||||
if (c != null)
|
||||
c.help(manager, Arrays.copyOfRange(args, 1, args.length));
|
||||
else {
|
||||
} else {
|
||||
provider.error.execute(args);
|
||||
}
|
||||
} else {
|
||||
// Generic
|
||||
if (noArgCommand != null)
|
||||
if (noArgCommand.tip() != null)
|
||||
manager.println("\t" + noArgCommand.tip()); //$NON-NLS-1$
|
||||
for (Command cmd : provider.commands) {
|
||||
if (cmd.tip() == null)
|
||||
manager.println("\t" + cmd.getCommandName()); //$NON-NLS-1$
|
||||
else manager.println("\t" + cmd.getCommandName() + ": " + //$NON-NLS-1$ //$NON-NLS-2$
|
||||
cmd.tip());
|
||||
}
|
||||
executeSub(args[0], Arrays.copyOfRange(args, 1, args.length));
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#tip() */
|
||||
@Override
|
||||
public String tip() {
|
||||
return tip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command get(String commandName) {
|
||||
return provider.get(commandName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Command value) throws InvalidCommandName {
|
||||
return provider.add(value);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* fr.bigeon.gclc.command.ICommandProvider#executeSub(java.lang.String,
|
||||
@ -164,6 +132,53 @@ public class SubedCommand extends Command implements ICommandProvider {
|
||||
provider.executeSub(command, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICommand get(String commandName) {
|
||||
return provider.get(commandName);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#getCommandName() */
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#help() */
|
||||
@Override
|
||||
public void help(ConsoleManager manager, String... args) {
|
||||
if (args.length != 0 && !args[0].startsWith("-")) { //$NON-NLS-1$
|
||||
// Specific
|
||||
final ICommand c = get(args[0]);
|
||||
if (c != null) {
|
||||
c.help(manager, Arrays.copyOfRange(args, 1, args.length));
|
||||
} else {
|
||||
provider.error.execute(args);
|
||||
}
|
||||
} else {
|
||||
// Generic
|
||||
if (noArgCommand != null && noArgCommand.tip() != null) {
|
||||
manager.println(TAB + noArgCommand.tip());
|
||||
}
|
||||
for (final ICommand cmd : provider.commands) {
|
||||
if (cmd.tip() == null) {
|
||||
manager.println(TAB + cmd.getCommandName());
|
||||
} else {
|
||||
manager.println(TAB + cmd.getCommandName() + ": " + //$NON-NLS-1$
|
||||
cmd.tip());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#tip() */
|
||||
@Override
|
||||
public String tip() {
|
||||
return tip;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString() */
|
||||
@Override
|
||||
|
@ -38,14 +38,14 @@
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.prompt.CLIPrompterMessages;
|
||||
|
||||
/** <p>
|
||||
* The error message for unrecognized commands
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public final class UnrecognizedCommand extends Command {
|
||||
public final class UnrecognizedCommand implements ICommand {
|
||||
/** The unrecognized command key */
|
||||
private static final String UNRECOGNIZED_CMD = "unrecognized.cmd"; //$NON-NLS-1$
|
||||
/** The unrecognized command key */
|
||||
@ -55,7 +55,6 @@ public final class UnrecognizedCommand extends Command {
|
||||
|
||||
/** @param manager the console manager to use */
|
||||
public UnrecognizedCommand(ConsoleManager manager) {
|
||||
super(new String());
|
||||
if (manager == null) {
|
||||
throw new NullPointerException("The argument cannot be null"); //$NON-NLS-1$
|
||||
}
|
||||
@ -63,8 +62,20 @@ public final class UnrecognizedCommand extends Command {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
public void execute(String... args) {
|
||||
if (args.length > 0) {
|
||||
manager.println(CLIPrompterMessages.getString(UNRECOGNIZED_CMD,
|
||||
(Object[]) args));
|
||||
} else {
|
||||
manager.println(CLIPrompterMessages.getString(EXPECTED_CMD));
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#getCommandName() */
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -75,10 +86,7 @@ public final class UnrecognizedCommand extends Command {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String... args) {
|
||||
if (args.length > 0)
|
||||
manager.println(CLIPrompterMessages.getString(UNRECOGNIZED_CMD,
|
||||
(Object[]) args));
|
||||
else manager.println(CLIPrompterMessages.getString(EXPECTED_CMD));
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -35,8 +35,17 @@
|
||||
|
||||
/** gclc:fr.bigeon.gclc.command.package-info.java
|
||||
* Created on: Sep 6, 2014 */
|
||||
/** <p>
|
||||
* TODO
|
||||
/** This package groups elements related to
|
||||
* {@link fr.bigeon.gclc.command.ICommand}
|
||||
* <p>
|
||||
* There are some implementations, such as the
|
||||
* {@link fr.bigeon.gclc.command.ParametrizedCommand} for commands with a
|
||||
* predefined set of flags and option taking a string as value, the
|
||||
* {@link fr.bigeon.gclc.command.SubedCommand} for a command that is declined in
|
||||
* a set of sub commands, the {@link fr.bigeon.gclc.command.HelpExecutor} for
|
||||
* help display of other commands and the
|
||||
* {@link fr.bigeon.gclc.command.UnrecognizedCommand} that should not be
|
||||
* directly accessible to the user, but will be used in case of error in typing.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
package fr.bigeon.gclc.command;
|
@ -33,14 +33,33 @@
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
/**
|
||||
* gclc:fr.bigeon.gclc.system.package-info.java
|
||||
* Created on: Dec 19, 2014
|
||||
* gclc:fr.bigeon.gclc.exception.CommandParsingException.java
|
||||
* Created on: Jun 1, 2016
|
||||
*/
|
||||
/**
|
||||
* <p>
|
||||
* The basic system based console manager elements
|
||||
package fr.bigeon.gclc.exception;
|
||||
|
||||
/** An exception raised during command parsing
|
||||
*
|
||||
* @author Emmanuel BIGEON
|
||||
*
|
||||
*/
|
||||
package fr.bigeon.gclc.system;
|
||||
* @author Emmanuel Bigeon */
|
||||
public class CommandParsingException extends Exception {
|
||||
|
||||
/** svuid */
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** @param message an explaination
|
||||
* @param cause the cause */
|
||||
public CommandParsingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/** @param message an explaination */
|
||||
public CommandParsingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/** @param cause the cause */
|
||||
public CommandParsingException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
@ -45,21 +45,21 @@ package fr.bigeon.gclc.exception;
|
||||
public class CommandRunException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** @param message a message */
|
||||
public CommandRunException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/** @param message a message
|
||||
* @param cause the cause */
|
||||
public CommandRunException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/** @param message a message */
|
||||
public CommandRunException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Throwable#getLocalizedMessage() */
|
||||
@Override
|
||||
|
@ -46,7 +46,7 @@ package fr.bigeon.gclc.exception;
|
||||
public class InvalidCommandName extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
81
gclc/src/main/java/fr/bigeon/gclc/i18n/Messages.java
Normal file
81
gclc/src/main/java/fr/bigeon/gclc/i18n/Messages.java
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright Bigeon Emmanuel (2014)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* provide a generic framework for console applications.
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
* modify and/or redistribute the software under the terms of the CeCILL
|
||||
* license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
* "http://www.cecill.info".
|
||||
*
|
||||
* As a counterpart to the access to the source code and rights to copy,
|
||||
* modify and redistribute granted by the license, users are provided only
|
||||
* with a limited warranty and the software's author, the holder of the
|
||||
* economic rights, and the successive licensors have only limited
|
||||
* liability.
|
||||
*
|
||||
* In this respect, the user's attention is drawn to the risks associated
|
||||
* with loading, using, modifying and/or developing or reproducing the
|
||||
* software by the user in light of its specific status of free software,
|
||||
* that may mean that it is complicated to manipulate, and that also
|
||||
* therefore means that it is reserved for developers and experienced
|
||||
* professionals having in-depth computer knowledge. Users are therefore
|
||||
* encouraged to load and test the software's suitability as regards their
|
||||
* requirements in conditions enabling the security of their systems and/or
|
||||
* data to be ensured and, more generally, to use and operate it in the
|
||||
* same conditions as regards security.
|
||||
*
|
||||
* The fact that you are presently reading this means that you have had
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
/**
|
||||
* gclc:fr.bigeon.gclc.i18n.Messages.java
|
||||
* Created on: Jun 1, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.i18n;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/** Internationalization class.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class Messages {
|
||||
/** The resource bundle name */
|
||||
private static final String BUNDLE_NAME = "fr.bigeon.gclc.l10n.messages"; //$NON-NLS-1$
|
||||
|
||||
/** The resource bundle */
|
||||
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
|
||||
.getBundle(BUNDLE_NAME);
|
||||
|
||||
/** The class logger */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(Messages.class.getName());
|
||||
|
||||
/** Utility class */
|
||||
private Messages() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/** Get formatted internationalized messages
|
||||
*
|
||||
* @param key the message key
|
||||
* @param args the formatting arguments
|
||||
* @return the formatted internationalized message */
|
||||
public static String getString(String key, Object... args) {
|
||||
try {
|
||||
return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);
|
||||
} catch (MissingResourceException e) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Unrecognized internationalization message key: " + key, e); //$NON-NLS-1$
|
||||
return '!' + key + '!';
|
||||
}
|
||||
}
|
||||
}
|
@ -36,7 +36,9 @@
|
||||
* gclc:fr.bigeon.gclc.ConsoleManager.java
|
||||
* Created on: Dec 19, 2014
|
||||
*/
|
||||
package fr.bigeon.gclc;
|
||||
package fr.bigeon.gclc.manager;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/** <p>
|
||||
* A console manager is in charge of the basic prompts and prints on a console.
|
||||
@ -47,28 +49,31 @@ package fr.bigeon.gclc;
|
||||
* @author Emmanuel BIGEON */
|
||||
public interface ConsoleManager {
|
||||
|
||||
/** <p>
|
||||
* Set a prompting prefix.
|
||||
*
|
||||
* @param prompt the prompt */
|
||||
void setPrompt(String prompt);
|
||||
|
||||
/** @return the prompt prefix */
|
||||
String getPrompt();
|
||||
|
||||
/** @param text the message to print (without line break at the end). */
|
||||
void print(String text);
|
||||
|
||||
/** Prints an end of line */
|
||||
void println();
|
||||
|
||||
/** @param message the message to print */
|
||||
void println(String message);
|
||||
|
||||
/** @return the user inputed string */
|
||||
String prompt();
|
||||
|
||||
/** @param message the message to prompt the user
|
||||
* @return the user inputed string */
|
||||
String prompt(String message);
|
||||
|
||||
/** @param message the message to print */
|
||||
void println(String message);
|
||||
|
||||
/** Prints an end of line */
|
||||
void println();
|
||||
|
||||
/** @param text the message to print (without line break at the end). */
|
||||
void print(String text);
|
||||
/** <p>
|
||||
* Set a prompting prefix.
|
||||
*
|
||||
* @param prompt the prompt */
|
||||
void setPrompt(String prompt);
|
||||
|
||||
/** @throws IOException if the close raised an exception */
|
||||
void close() throws IOException;
|
||||
}
|
@ -36,33 +36,107 @@
|
||||
* gclc:fr.bigeon.gclc.system.SystemConsoleManager.java
|
||||
* Created on: Dec 19, 2014
|
||||
*/
|
||||
package fr.bigeon.gclc.system;
|
||||
package fr.bigeon.gclc.manager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleManager;
|
||||
|
||||
/**
|
||||
/** A console using the input stream and print stream.
|
||||
* <p>
|
||||
* TODO
|
||||
* The default constructor will use the system standart input and output.
|
||||
*
|
||||
* @author Emmanuel BIGEON
|
||||
*
|
||||
*/
|
||||
public class SystemConsoleManager implements ConsoleManager {
|
||||
* @author Emmanuel BIGEON */
|
||||
public class SystemConsoleManager implements ConsoleManager { // NOSONAR
|
||||
|
||||
/** The default prompt */
|
||||
public static final String DEFAULT_PROMPT = ">"; //$NON-NLS-1$
|
||||
|
||||
/** The logger */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(SystemConsoleManager.class.getName());
|
||||
|
||||
/** The command prompt. It can be changed. */
|
||||
private String prompt = DEFAULT_PROMPT;
|
||||
|
||||
/** The print stream */
|
||||
private final PrintStream out;
|
||||
/** The input stream */
|
||||
private final InputStream in;
|
||||
|
||||
/** This default constructor relies on the system defined standart output
|
||||
* and input stream. */
|
||||
public SystemConsoleManager() {
|
||||
out = System.out; // NOSONAR
|
||||
in = System.in;
|
||||
}
|
||||
|
||||
/** @param out the output stream
|
||||
* @param in the input stream */
|
||||
public SystemConsoleManager(PrintStream out, InputStream in) {
|
||||
super();
|
||||
this.out = out;
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
/** @return the prompt */
|
||||
@Override
|
||||
public String getPrompt() {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#print(java.lang.Object) */
|
||||
@Override
|
||||
public void print(String object) {
|
||||
out.print(object);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#println() */
|
||||
@Override
|
||||
public void println() {
|
||||
out.println();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#println(java.lang.Object) */
|
||||
@Override
|
||||
public void println(String object) {
|
||||
out.println(object);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt() */
|
||||
@Override
|
||||
public String prompt() {
|
||||
return prompt(new String() + prompt);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt(java.lang.String) */
|
||||
@Override
|
||||
public String prompt(String message) {
|
||||
String result = new String();
|
||||
out.print(message + ' ');
|
||||
char c;
|
||||
try {
|
||||
c = (char) in.read();
|
||||
while (c != System.lineSeparator().charAt(0)) {
|
||||
result += c;
|
||||
c = (char) in.read();
|
||||
}
|
||||
while (in.available() != 0) {
|
||||
in.read();
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to read prompt", e); //$NON-NLS-1$
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** @param prompt the prompt to set */
|
||||
@Override
|
||||
public void setPrompt(String prompt) {
|
||||
@ -70,56 +144,10 @@ public class SystemConsoleManager implements ConsoleManager {
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt()
|
||||
*/
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#close() */
|
||||
@Override
|
||||
public String prompt() {
|
||||
return prompt(new String() + prompt);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String prompt(String message) {
|
||||
String result = new String();
|
||||
System.out.print(message + ' ');
|
||||
char c;
|
||||
try {
|
||||
c = (char) System.in.read();
|
||||
while (c != System.lineSeparator().charAt(0)) {
|
||||
result += c;
|
||||
c = (char) System.in.read();
|
||||
}
|
||||
while (System.in.available() != 0)
|
||||
System.in.read();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#println(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void println(String object) {
|
||||
System.out.println(object);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#print(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void print(String object) {
|
||||
System.out.print(object);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#println() */
|
||||
@Override
|
||||
public void println() {
|
||||
System.out.println();
|
||||
public void close() throws IOException {
|
||||
in.close();
|
||||
}
|
||||
|
||||
}
|
@ -39,8 +39,10 @@ package fr.bigeon.gclc.prompt;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
|
||||
/** <p>
|
||||
* The {@link CLIPrompter} class is a utility class that provides method to
|
||||
@ -49,6 +51,14 @@ import fr.bigeon.gclc.ConsoleManager;
|
||||
* @author Emmanuel BIGEON */
|
||||
public class CLIPrompter {
|
||||
|
||||
/** message key for format error in prompting a choice */
|
||||
private static final String PROMPTCHOICE_FORMATERR = "promptchoice.formaterr"; //$NON-NLS-1$
|
||||
/** message key for out of bound error in prompting a choice */
|
||||
private static final String PROMPTCHOICE_OUTOFBOUNDS = "promptchoice.outofbounds"; //$NON-NLS-1$
|
||||
/** message key for first form of no in prompting a choice */
|
||||
private static final String PROMPTBOOL_CHOICES_NO1 = "promptbool.choices.no1"; //$NON-NLS-1$
|
||||
/** message key for first form of yes in prompting a choice */
|
||||
private static final String PROMPTBOOL_CHOICES_YES1 = "promptbool.choices.yes1"; //$NON-NLS-1$
|
||||
@SuppressWarnings("javadoc")
|
||||
private static final String BOOL_CHOICES = "promptbool.choices"; //$NON-NLS-1$
|
||||
@SuppressWarnings("javadoc")
|
||||
@ -57,203 +67,67 @@ public class CLIPrompter {
|
||||
private static final String PROMPT = "prompt.lineprompt"; //$NON-NLS-1$
|
||||
@SuppressWarnings("javadoc")
|
||||
private static final String LIST_CHOICE_SEP = "promptlist.multi.sepkey"; //$NON-NLS-1$
|
||||
/** The class logger */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(CLIPrompter.class.getName());
|
||||
|
||||
/** @param manager the manager
|
||||
* @param prompt the prompting message
|
||||
* @param reprompt the prompting message after empty input
|
||||
* @return the non empty input */
|
||||
public static String promptNonEmpty(ConsoleManager manager, String prompt,
|
||||
String reprompt) {
|
||||
String res = manager.prompt(prompt);
|
||||
while (res.isEmpty())
|
||||
res = manager.prompt(reprompt);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Prompt for a text with several lines.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param message the prompting message
|
||||
* @param ender the ender character
|
||||
* @return the text */
|
||||
public static String promptLongText(ConsoleManager manager, String message,
|
||||
String ender) {
|
||||
manager.println(message +
|
||||
CLIPrompterMessages.getString(
|
||||
"promptlongtext.exit.dispkey", ender)); //$NON-NLS-1$
|
||||
String res = manager.prompt(PROMPT);
|
||||
String line = res;
|
||||
while (!line.equals(ender)) {
|
||||
line = manager.prompt(PROMPT);
|
||||
if (!line.equals(ender)) res += System.lineSeparator() + line;
|
||||
}
|
||||
return res.equals(ender) ? "" : res; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** Prompt for a text with several lines.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param message the prompting message
|
||||
* @return the text */
|
||||
public static String promptLongText(ConsoleManager manager, String message) {
|
||||
return promptLongText(manager, message,
|
||||
CLIPrompterMessages.getString("promptlongtext.exit.defaultkey")); //$NON-NLS-1$
|
||||
/** Utility class */
|
||||
private CLIPrompter() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
* @param message the prompt message
|
||||
* @return the integer */
|
||||
public static int promptInteger(ConsoleManager manager, String message) {
|
||||
boolean still = true;
|
||||
int r = 0;
|
||||
while (still) {
|
||||
String result = manager.prompt(message);
|
||||
try {
|
||||
if (result.isEmpty()) {
|
||||
still = true;
|
||||
continue;
|
||||
}
|
||||
r = Integer.parseInt(result);
|
||||
still = false;
|
||||
} catch (Exception e) {
|
||||
still = true;
|
||||
}
|
||||
* @param choices the choices
|
||||
* @param cancel the cancel option if it exists
|
||||
* @return the number of choices plus one (or the number of choices if there
|
||||
* is a cancel) */
|
||||
private static <U> int listChoices(ConsoleManager manager, List<U> choices,
|
||||
String cancel) {
|
||||
int index = 0;
|
||||
for (final U u : choices) {
|
||||
manager.println(index++ + ") " + u); //$NON-NLS-1$
|
||||
}
|
||||
return r;
|
||||
if (cancel != null) {
|
||||
manager.println(index + ") " + cancel); //$NON-NLS-1$
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
* @param message the prompting message
|
||||
* @return the choice */
|
||||
public static boolean promptBoolean(ConsoleManager manager, String message) {
|
||||
String result = manager.prompt(message +
|
||||
CLIPrompterMessages.getString(BOOL_CHOICES));
|
||||
public static boolean promptBoolean(ConsoleManager manager,
|
||||
String message) {
|
||||
String result = manager
|
||||
.prompt(message + CLIPrompterMessages.getString(BOOL_CHOICES));
|
||||
boolean first = true;
|
||||
String choices = CLIPrompterMessages
|
||||
.getString("promptbool.choices.yes1") + //$NON-NLS-1$
|
||||
", " + //$NON-NLS-1$
|
||||
CLIPrompterMessages
|
||||
.getString("promptbool.choices.no1"); //$NON-NLS-1$
|
||||
while (!(result.equalsIgnoreCase(CLIPrompterMessages
|
||||
.getString("promptbool.choices.yes1")) || //$NON-NLS-1$
|
||||
CLIPrompterMessages
|
||||
.getString("promptbool.choices.no1").equalsIgnoreCase( //$NON-NLS-1$
|
||||
result) ||
|
||||
CLIPrompterMessages
|
||||
.getString("promptbool.choices.no2").equalsIgnoreCase( //$NON-NLS-1$
|
||||
result) || CLIPrompterMessages.getString(
|
||||
"promptbool.choices.yes2").equalsIgnoreCase(result))) { //$NON-NLS-1$
|
||||
final String choices = CLIPrompterMessages
|
||||
.getString(PROMPTBOOL_CHOICES_YES1) + ", " + //$NON-NLS-1$
|
||||
CLIPrompterMessages
|
||||
.getString(PROMPTBOOL_CHOICES_NO1);
|
||||
while (!(result.equalsIgnoreCase(
|
||||
CLIPrompterMessages.getString(PROMPTBOOL_CHOICES_YES1)) ||
|
||||
CLIPrompterMessages.getString(PROMPTBOOL_CHOICES_NO1)
|
||||
.equalsIgnoreCase(result) ||
|
||||
CLIPrompterMessages.getString("promptbool.choices.no2") //$NON-NLS-1$
|
||||
.equalsIgnoreCase(result) ||
|
||||
CLIPrompterMessages.getString("promptbool.choices.yes2") //$NON-NLS-1$
|
||||
.equalsIgnoreCase(result))) {
|
||||
if (!first) {
|
||||
|
||||
manager.println(CLIPrompterMessages.getString(
|
||||
"promptbool.choices.invalid", choices)); //$NON-NLS-1$
|
||||
result = manager.prompt(message +
|
||||
CLIPrompterMessages.getString(BOOL_CHOICES));
|
||||
|
||||
manager.println(CLIPrompterMessages
|
||||
.getString("promptbool.choices.invalid", choices)); //$NON-NLS-1$
|
||||
result = manager.prompt(
|
||||
message + CLIPrompterMessages.getString(BOOL_CHOICES));
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
return result.equalsIgnoreCase(CLIPrompterMessages
|
||||
.getString("promptbool.choices.yes1")) || //$NON-NLS-1$
|
||||
return result.equalsIgnoreCase(
|
||||
CLIPrompterMessages.getString(PROMPTBOOL_CHOICES_YES1)) ||
|
||||
result.equalsIgnoreCase(CLIPrompterMessages
|
||||
.getString("promptbool.choices.yes2")); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
* @param <U> The choices labels type
|
||||
* @param <T> The real choices objects
|
||||
* @param choices the list of labels (in order to be displayed)
|
||||
* @param choicesMap the map of label to actual objects
|
||||
* @param message the prompting message
|
||||
* @param cancel the cancel option if it exists (null otherwise)
|
||||
* @return the chosen object */
|
||||
@SuppressWarnings("boxing")
|
||||
public static <U, T> T promptChoice(ConsoleManager manager,
|
||||
List<U> choices,
|
||||
Map<U, T> choicesMap,
|
||||
String message, String cancel) {
|
||||
manager.println(message);
|
||||
int index = listChoices(manager, choices, cancel);
|
||||
String result = ""; //$NON-NLS-1$
|
||||
boolean keepOn = true;
|
||||
int r = -1;
|
||||
while (keepOn) {
|
||||
result = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||
try {
|
||||
r = Integer.parseInt(result);
|
||||
if (r >= 0 && r <= index)
|
||||
keepOn = false;
|
||||
else {
|
||||
manager.println(CLIPrompterMessages.getString(
|
||||
"promptchoice.outofbounds", 0, index)); //$NON-NLS-1$
|
||||
listChoices(manager, choices, cancel);
|
||||
}
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
keepOn = true;
|
||||
manager.println(CLIPrompterMessages.getString(
|
||||
"promptchoice.formaterr", 0, index)); //$NON-NLS-1$
|
||||
listChoices(manager, choices, cancel);
|
||||
}
|
||||
}
|
||||
if (r == index && cancel != null) return null;
|
||||
return choicesMap.get(choices.get(r));
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
* @param <U> The choices labels type
|
||||
* @param <T> The real choices objects
|
||||
* @param choicesMap the map of label to actual objects
|
||||
* @param message the prompting message
|
||||
* @param cancel the cancel option (or null)
|
||||
* @return the chosen object */
|
||||
public static <U, T> T promptChoice(ConsoleManager manager,
|
||||
Map<U, T> choicesMap,
|
||||
String message,
|
||||
String cancel) {
|
||||
return promptChoice(manager, new ArrayList<>(choicesMap.keySet()),
|
||||
choicesMap,
|
||||
message, cancel);
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
* @param <U> the type of choices
|
||||
* @param choices the list of choices
|
||||
* @param message the prompting message
|
||||
* @param cancel the cancel option, or null
|
||||
* @return the index of the choice */
|
||||
@SuppressWarnings("boxing")
|
||||
public static <U> Integer promptChoice(ConsoleManager manager,
|
||||
List<U> choices,
|
||||
String message,
|
||||
String cancel) {
|
||||
manager.println(message);
|
||||
int index = listChoices(manager, choices, cancel);
|
||||
String result = ""; //$NON-NLS-1$
|
||||
boolean keepOn = true;
|
||||
int r = -1;
|
||||
while (keepOn) {
|
||||
result = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||
try {
|
||||
r = Integer.parseInt(result);
|
||||
if (r >= 0 && r <= index)
|
||||
keepOn = false;
|
||||
else {
|
||||
manager.println(CLIPrompterMessages.getString(
|
||||
"promptchoice.outofbounds", 0, index)); //$NON-NLS-1$
|
||||
listChoices(manager, choices, cancel);
|
||||
}
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
keepOn = true;
|
||||
manager.println(CLIPrompterMessages.getString(
|
||||
"promptchoice.formaterr", 0, index)); //$NON-NLS-1$
|
||||
listChoices(manager, choices, cancel);
|
||||
}
|
||||
}
|
||||
if (r == index && cancel != null) return null;
|
||||
return r;
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
* @param keys the keys to be printed
|
||||
* @param choices the real choices
|
||||
@ -263,10 +137,12 @@ public class CLIPrompter {
|
||||
* @return the choice */
|
||||
@SuppressWarnings("boxing")
|
||||
public static <U> U promptChoice(ConsoleManager manager, List<String> keys,
|
||||
List<U> choices,
|
||||
String message, String cancel) {
|
||||
Integer index = promptChoice(manager, keys, message, cancel);
|
||||
if (index == null) return null;
|
||||
List<U> choices, String message,
|
||||
String cancel) {
|
||||
final Integer index = promptChoice(manager, keys, message, cancel);
|
||||
if (index == null) {
|
||||
return null;
|
||||
}
|
||||
return choices.get(index);
|
||||
}
|
||||
|
||||
@ -276,15 +152,53 @@ public class CLIPrompter {
|
||||
* @param choices the list of labels (in order to be displayed)
|
||||
* @param choicesMap the map of label to actual objects
|
||||
* @param message the prompting message
|
||||
* @return the chosen objects (or an empty list) */
|
||||
public static <U, T> List<T> promptMultiChoice(ConsoleManager manager, List<U> choices, Map<U, T> choicesMap,
|
||||
String message) {
|
||||
List<Integer> chs = promptMultiChoice(manager, choices, message);
|
||||
List<T> userChoices = new ArrayList<>();
|
||||
for (Integer integer : chs) {
|
||||
userChoices.add(choicesMap.get(integer));
|
||||
* @param cancel the cancel option if it exists (null otherwise)
|
||||
* @return the chosen object */
|
||||
public static <U, T> T promptChoice(ConsoleManager manager, List<U> choices,
|
||||
Map<U, T> choicesMap, String message,
|
||||
String cancel) {
|
||||
return choicesMap.get(choices.get(
|
||||
promptChoice(manager, choices, message, cancel).intValue()));
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
* @param <U> the type of choices
|
||||
* @param choices the list of choices
|
||||
* @param message the prompting message
|
||||
* @param cancel the cancel option, or null
|
||||
* @return the index of the choice */
|
||||
@SuppressWarnings("boxing")
|
||||
public static <U> Integer promptChoice(ConsoleManager manager,
|
||||
List<U> choices, String message,
|
||||
String cancel) {
|
||||
manager.println(message);
|
||||
final int index = listChoices(manager, choices, cancel);
|
||||
String result = ""; //$NON-NLS-1$
|
||||
boolean keepOn = true;
|
||||
int r = -1;
|
||||
while (keepOn) {
|
||||
result = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||
try {
|
||||
r = Integer.parseInt(result);
|
||||
if (r >= 0 && r <= index) {
|
||||
keepOn = false;
|
||||
} else {
|
||||
manager.println(CLIPrompterMessages
|
||||
.getString(PROMPTCHOICE_OUTOFBOUNDS, 0, index));
|
||||
listChoices(manager, choices, cancel);
|
||||
}
|
||||
|
||||
} catch (final NumberFormatException e) {
|
||||
keepOn = true;
|
||||
manager.println(CLIPrompterMessages
|
||||
.getString(PROMPTCHOICE_FORMATERR, 0, index));
|
||||
listChoices(manager, choices, cancel);
|
||||
}
|
||||
}
|
||||
return userChoices;
|
||||
if (r == index && cancel != null) {
|
||||
return null;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
@ -292,50 +206,101 @@ public class CLIPrompter {
|
||||
* @param <T> The real choices objects
|
||||
* @param choicesMap the map of label to actual objects
|
||||
* @param message the prompting message
|
||||
* @return the chosen objects */
|
||||
public static <U, T> List<T> promptMultiChoice(ConsoleManager manager, Map<U, T> choicesMap, String message) {
|
||||
return promptMultiChoice(manager, new ArrayList<>(choicesMap.keySet()), choicesMap, message);
|
||||
* @param cancel the cancel option (or null)
|
||||
* @return the chosen object */
|
||||
public static <U, T> T promptChoice(ConsoleManager manager,
|
||||
Map<U, T> choicesMap, String message,
|
||||
String cancel) {
|
||||
return promptChoice(manager, new ArrayList<>(choicesMap.keySet()),
|
||||
choicesMap, message, cancel);
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
* @param <U> the type of choices
|
||||
* @param choices the list of choices
|
||||
* @param message the prompting message
|
||||
* @return the indices of the choices */
|
||||
@SuppressWarnings("boxing")
|
||||
public static <U> List<Integer> promptMultiChoice(ConsoleManager manager, List<U> choices, String message) {
|
||||
manager.println(message);
|
||||
int index = listChoices(manager, choices, null);
|
||||
String result = ""; //$NON-NLS-1$
|
||||
boolean keepOn = true;
|
||||
List<Integer> chs = new ArrayList<>();
|
||||
while (keepOn) {
|
||||
keepOn = false;
|
||||
result = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||
String[] vals = result.split(CLIPrompterMessages.getString(LIST_CHOICE_SEP));
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
if (vals[i].isEmpty()) {
|
||||
* @param message the prompt message
|
||||
* @return the integer */
|
||||
public static int promptInteger(ConsoleManager manager, String message) {
|
||||
boolean still = true;
|
||||
int r = 0;
|
||||
while (still) {
|
||||
final String result = manager.prompt(message);
|
||||
try {
|
||||
if (result.isEmpty()) {
|
||||
still = true;
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
int r = Integer.parseInt(vals[i]);
|
||||
if (r >= 0 && r < index) {
|
||||
chs.add(r);
|
||||
} else {
|
||||
manager.println(CLIPrompterMessages.getString("promptchoice.outofbounds", 0, index)); //$NON-NLS-1$
|
||||
listChoices(manager, choices, null);
|
||||
keepOn = true;
|
||||
break;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
keepOn = true;
|
||||
manager.println(CLIPrompterMessages.getString("promptchoice.formaterr", 0, index)); //$NON-NLS-1$
|
||||
listChoices(manager, choices, null);
|
||||
break;
|
||||
}
|
||||
r = Integer.parseInt(result);
|
||||
still = false;
|
||||
} catch (final NumberFormatException e) {
|
||||
LOGGER.log(Level.INFO,
|
||||
"User input a non parsable integer: " + result, e); //$NON-NLS-1$
|
||||
still = true;
|
||||
}
|
||||
}
|
||||
return chs;
|
||||
return r;
|
||||
}
|
||||
|
||||
/** This methods prompt the user for a list of elements
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param message the message
|
||||
* @return the list of user inputs */
|
||||
public static List<String> promptList(ConsoleManager manager,
|
||||
String message) {
|
||||
return promptList(manager, message,
|
||||
CLIPrompterMessages.getString("promptlist.exit.defaultkey")); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** This methods prompt the user for a list of elements
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param message the message
|
||||
* @param ender the ending sequence for the list
|
||||
* @return the list of user inputs */
|
||||
public static List<String> promptList(ConsoleManager manager,
|
||||
String message, String ender) {
|
||||
final List<String> strings = new ArrayList<>();
|
||||
manager.println(
|
||||
message + CLIPrompterMessages.getString(LIST_DISP_KEY, ender));
|
||||
String res = null;
|
||||
while (!ender.equals(res)) {
|
||||
res = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||
if (!res.equals(ender)) {
|
||||
strings.add(res);
|
||||
}
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
|
||||
/** Prompt for a text with several lines.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param message the prompting message
|
||||
* @return the text */
|
||||
public static String promptLongText(ConsoleManager manager,
|
||||
String message) {
|
||||
return promptLongText(manager, message, CLIPrompterMessages
|
||||
.getString("promptlongtext.exit.defaultkey")); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** Prompt for a text with several lines.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param message the prompting message
|
||||
* @param ender the ender character
|
||||
* @return the text */
|
||||
public static String promptLongText(ConsoleManager manager, String message,
|
||||
String ender) {
|
||||
manager.println(message + CLIPrompterMessages
|
||||
.getString("promptlongtext.exit.dispkey", ender)); //$NON-NLS-1$
|
||||
String res = manager.prompt(PROMPT);
|
||||
String line = res;
|
||||
while (!line.equals(ender)) {
|
||||
line = manager.prompt(PROMPT);
|
||||
if (!line.equals(ender)) {
|
||||
res += System.lineSeparator() + line;
|
||||
}
|
||||
}
|
||||
return res.equals(ender) ? "" : res; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
@ -344,61 +309,120 @@ public class CLIPrompter {
|
||||
* @param message the message
|
||||
* @param <U> the type of elements
|
||||
* @return the choice */
|
||||
public static <U> List<U> promptMultiChoice(ConsoleManager manager, List<String> keys, List<U> choices,
|
||||
public static <U> List<U> promptMultiChoice(ConsoleManager manager,
|
||||
List<String> keys,
|
||||
List<U> choices,
|
||||
String message) {
|
||||
List<Integer> indices = promptMultiChoice(manager, keys, message);
|
||||
List<U> userChoices = new ArrayList<>();
|
||||
for (Integer integer : indices) {
|
||||
final List<Integer> indices = promptMultiChoice(manager, keys, message);
|
||||
final List<U> userChoices = new ArrayList<>();
|
||||
for (final Integer integer : indices) {
|
||||
userChoices.add(choices.get(integer.intValue()));
|
||||
}
|
||||
return userChoices;
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
* @param choices the choices
|
||||
* @param cancel the cancel option if it exists
|
||||
* @return the number of choices plus one (or the number of choices if there
|
||||
* is a cancel) */
|
||||
private static <U> int listChoices(ConsoleManager manager, List<U> choices,
|
||||
String cancel) {
|
||||
int index = 0;
|
||||
for (U u : choices) {
|
||||
manager.println((index++) + ") " + u); //$NON-NLS-1$
|
||||
* @param <U> The choices labels type
|
||||
* @param <T> The real choices objects
|
||||
* @param choices the list of labels (in order to be displayed)
|
||||
* @param choicesMap the map of label to actual objects
|
||||
* @param message the prompting message
|
||||
* @return the chosen objects (or an empty list) */
|
||||
public static <U, T> List<T> promptMultiChoice(ConsoleManager manager,
|
||||
List<U> choices,
|
||||
Map<U, T> choicesMap,
|
||||
String message) {
|
||||
final List<Integer> chs = promptMultiChoice(manager, choices, message);
|
||||
final List<T> userChoices = new ArrayList<>();
|
||||
for (final Integer integer : chs) {
|
||||
userChoices.add(choicesMap.get(integer));
|
||||
}
|
||||
if (cancel != null) {
|
||||
manager.println((index) + ") " + cancel); //$NON-NLS-1$
|
||||
}
|
||||
return index;
|
||||
return userChoices;
|
||||
}
|
||||
|
||||
/** This methods prompt the user for a list of elements
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param message the message
|
||||
* @param ender the ending sequence for the list
|
||||
* @return the list of user inputs */
|
||||
public static List<String> promptList(ConsoleManager manager,
|
||||
String message,
|
||||
String ender) {
|
||||
List<String> strings = new ArrayList<>();
|
||||
manager.println(message +
|
||||
CLIPrompterMessages.getString(LIST_DISP_KEY, ender));
|
||||
String res = null;
|
||||
while (!ender.equals(res)) {
|
||||
res = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||
if (!res.equals(ender)) strings.add(res);
|
||||
/** @param manager the manager
|
||||
* @param <U> the type of choices
|
||||
* @param choices the list of choices
|
||||
* @param message the prompting message
|
||||
* @return the indices of the choices */
|
||||
@SuppressWarnings("boxing")
|
||||
public static <U> List<Integer> promptMultiChoice(ConsoleManager manager,
|
||||
List<U> choices,
|
||||
String message) {
|
||||
manager.println(message);
|
||||
final int index = listChoices(manager, choices, null);
|
||||
String result = ""; //$NON-NLS-1$
|
||||
boolean keepOn = true;
|
||||
final List<Integer> chs = new ArrayList<>();
|
||||
while (keepOn) {
|
||||
keepOn = false;
|
||||
result = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||
final String[] vals = result
|
||||
.split(CLIPrompterMessages.getString(LIST_CHOICE_SEP));
|
||||
for (final String val : vals) {
|
||||
boolean added;
|
||||
try {
|
||||
added = addUserChoice(val, chs, index);
|
||||
} catch (final NumberFormatException e) {
|
||||
keepOn = true;
|
||||
manager.println(CLIPrompterMessages
|
||||
.getString(PROMPTCHOICE_FORMATERR, 0, index));
|
||||
listChoices(manager, choices, null);
|
||||
break;
|
||||
}
|
||||
if (!added) {
|
||||
manager.println(CLIPrompterMessages
|
||||
.getString(PROMPTCHOICE_OUTOFBOUNDS, 0, index));
|
||||
listChoices(manager, choices, null);
|
||||
keepOn = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings;
|
||||
return chs;
|
||||
}
|
||||
|
||||
/** This methods prompt the user for a list of elements
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param message the message
|
||||
* @return the list of user inputs */
|
||||
public static List<String> promptList(ConsoleManager manager, String message) {
|
||||
return promptList(manager, message,
|
||||
CLIPrompterMessages.getString("promptlist.exit.defaultkey")); //$NON-NLS-1$
|
||||
/** @param val the string to parse
|
||||
* @param chs the list of integers
|
||||
* @param index the max index of choice
|
||||
* @return if the parsing was done correctly */
|
||||
private static boolean addUserChoice(String val, List<Integer> chs,
|
||||
int index) {
|
||||
if (val.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
final int r;
|
||||
r = Integer.parseInt(val);
|
||||
if (r >= 0 && r < index) {
|
||||
chs.add(Integer.valueOf(r));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
* @param <U> The choices labels type
|
||||
* @param <T> The real choices objects
|
||||
* @param choicesMap the map of label to actual objects
|
||||
* @param message the prompting message
|
||||
* @return the chosen objects */
|
||||
public static <U, T> List<T> promptMultiChoice(ConsoleManager manager,
|
||||
Map<U, T> choicesMap,
|
||||
String message) {
|
||||
return promptMultiChoice(manager, new ArrayList<>(choicesMap.keySet()),
|
||||
choicesMap, message);
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
* @param prompt the prompting message
|
||||
* @param reprompt the prompting message after empty input
|
||||
* @return the non empty input */
|
||||
public static String promptNonEmpty(ConsoleManager manager, String prompt,
|
||||
String reprompt) {
|
||||
String res = manager.prompt(prompt);
|
||||
while (res.isEmpty()) {
|
||||
res = manager.prompt(reprompt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -41,41 +41,40 @@ package fr.bigeon.gclc.prompt;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
/** <p>
|
||||
* Utility class for the messages of the CLIPrompter
|
||||
*
|
||||
* @author Emmanuel BIGEON
|
||||
*/
|
||||
* @author Emmanuel BIGEON */
|
||||
public class CLIPrompterMessages {
|
||||
/**
|
||||
* The resource name
|
||||
*/
|
||||
/** The resource name */
|
||||
private static final String BUNDLE_NAME = "fr.bigeon.gclc.messages"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* The resource
|
||||
*/
|
||||
/** The resource */
|
||||
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
|
||||
.getBundle(BUNDLE_NAME);
|
||||
|
||||
/**
|
||||
* Utility class
|
||||
*/
|
||||
private CLIPrompterMessages() {}
|
||||
/** The logger */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(CLIPrompterMessages.class.getName());
|
||||
|
||||
/**
|
||||
* Return the formatted message corresponding to the given key
|
||||
*
|
||||
/** Utility class */
|
||||
private CLIPrompterMessages() {
|
||||
// Utility constructor
|
||||
}
|
||||
|
||||
/** Return the formatted message corresponding to the given key
|
||||
*
|
||||
* @param key the message's key
|
||||
* @param args the arguments
|
||||
* @return the formatted message
|
||||
*/
|
||||
* @return the formatted message */
|
||||
public static String getString(String key, Object... args) {
|
||||
try {
|
||||
return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);
|
||||
} catch (MissingResourceException e) {
|
||||
} catch (final MissingResourceException e) {
|
||||
LOGGER.log(Level.WARNING, "Unrecognized key: " + key, e); //$NON-NLS-1$
|
||||
return '!' + key + '!';
|
||||
}
|
||||
}
|
||||
|
@ -34,8 +34,14 @@
|
||||
*/
|
||||
/** gclc:fr.bigeon.gclc.prompt.package-info.java
|
||||
* Created on: Sep 6, 2014 */
|
||||
/** <p>
|
||||
* TODO
|
||||
/** Client prompting related objects.
|
||||
* <p>
|
||||
* This package is used for the formatting of prompts for the user. The
|
||||
* {@link fr.bigeon.gclc.prompt.CLIPrompter} class provides utility methods to
|
||||
* retrieve certain basic type of data from the user or to give list choices.
|
||||
* <p>
|
||||
* The {@link fr.bigeon.gclc.prompt.CLIPrompterMessages} class is used for
|
||||
* internationalization of the prompting methods.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
package fr.bigeon.gclc.prompt;
|
@ -41,27 +41,35 @@ package fr.bigeon.gclc.tools;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
/** A tool class for printing text in a console.
|
||||
*
|
||||
* @author Emmanuel BIGEON
|
||||
*
|
||||
*/
|
||||
* @author Emmanuel BIGEON */
|
||||
public class PrintUtils {
|
||||
|
||||
/** The continuation dot string */
|
||||
private static final String CONT_DOT = "..."; //$NON-NLS-1$
|
||||
/** The continuation dot string length */
|
||||
private static final int CONT_DOT_LENGTH = CONT_DOT.length();
|
||||
|
||||
/** Utility class */
|
||||
private PrintUtils() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/** @param text the text to print
|
||||
* @param nbCharacters the number of characters of the resulting text
|
||||
* @param indicateTooLong if an indication shell be given that the text
|
||||
* didn't fit
|
||||
* @return the text to print (will be of exactly nbCharacters). */
|
||||
public static String print(String text, int nbCharacters,
|
||||
boolean indicateTooLong) {
|
||||
boolean indicateTooLong) {
|
||||
String res = text;
|
||||
if (res.length() > nbCharacters) {
|
||||
// Cut
|
||||
if (indicateTooLong) {
|
||||
// With suspension dots
|
||||
res = res.substring(0, nbCharacters - 3) + "..."; //$NON-NLS-1$
|
||||
res = res.substring(0, nbCharacters - CONT_DOT_LENGTH) +
|
||||
CONT_DOT;
|
||||
} else {
|
||||
res = res.substring(0, nbCharacters);
|
||||
}
|
||||
@ -77,9 +85,10 @@ public class PrintUtils {
|
||||
* @param i the length of the wrap
|
||||
* @return the list of resulting strings */
|
||||
public static List<String> wrap(String description, int i) {
|
||||
String[] originalLines = description.split(System.lineSeparator());
|
||||
List<String> result = new ArrayList<>();
|
||||
for (String string : originalLines) {
|
||||
final String[] originalLines = description
|
||||
.split(System.lineSeparator());
|
||||
final List<String> result = new ArrayList<>();
|
||||
for (final String string : originalLines) {
|
||||
String toCut = string;
|
||||
while (toCut.length() > i) {
|
||||
int index = toCut.lastIndexOf(" ", i); //$NON-NLS-1$
|
||||
|
@ -0,0 +1 @@
|
||||
ConsoleApplication.cmd.failed=The command '{0}' failed due to :
|
Loading…
Reference in New Issue
Block a user