Compare commits
142 Commits
gclc-socke
...
gclc-2.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a8d298485 | |||
| 50887f44bb | |||
| 3a5250d987 | |||
| ddc60652f1 | |||
| 206df88506 | |||
| d2cd059c01 | |||
| 90dab5a809 | |||
| d5f2d39808 | |||
| 36f39df87e | |||
| 82e8d1e1b7 | |||
| 0ebcd7b210 | |||
| d32ea6b4b0 | |||
| e5d5edcf63 | |||
| b80a3fc5b8 | |||
| 6bb937342e | |||
| 283090d361 | |||
| 83c02f82ec | |||
| fce2b01914 | |||
| 9b071a378f | |||
| 89e849c27f | |||
| 9747cf21b2 | |||
| 6f8c536f55 | |||
| b3224ad689 | |||
| 0feb069878 | |||
| b5f1463864 | |||
| 0bbe9d321d | |||
| 2e28e269e1 | |||
| e11d90378f | |||
| 6a0e68d312 | |||
| 3534e817e2 | |||
| 20193dd1e4 | |||
| 5df8321dee | |||
| 629d07bc32 | |||
| e32e2428e5 | |||
| db9f81c6a8 | |||
| 0a995394f9 | |||
| 0ca055db8e | |||
| b93c2b5220 | |||
| 8322454f72 | |||
| ab47d6573b | |||
| 6d496d701d | |||
| b4df39491e | |||
| 775a71b2ec | |||
| c9eb221d31 | |||
| 340a0317af | |||
| 35959a8d8a | |||
| 07645d7c0c | |||
| 99c0c9008b | |||
| 26265ad7e6 | |||
| 092883f4c3 | |||
| 25904c907d | |||
| ae55ebea29 | |||
| e989aff2f4 | |||
| 2f0c03a73b | |||
| ff9ace1033 | |||
| ffa54af3be | |||
| 269704f5a2 | |||
| aecc18cc83 | |||
| 063cad61cd | |||
| 201b6ad366 | |||
| bf8d76750f | |||
| 17ac47f15e | |||
| 7de2dadbe0 | |||
| 50395ba852 | |||
| 248c82cf50 | |||
| 6289ca1db9 | |||
| 5b6634eaf0 | |||
| 4737a16874 | |||
| bf0a3b30e5 | |||
| 5d25971b56 | |||
| c27872de94 | |||
| a12484a72a | |||
| ee0d91e455 | |||
| 719d7ada3f | |||
| c877450b2b | |||
| f3a8aafce1 | |||
| d2bc86fffc | |||
| 3b6ba337f1 | |||
| 6a117afcb3 | |||
| 7d41a9f4c6 | |||
| 90579d79a9 | |||
| b2c98ae940 | |||
| 1d6569cf69 | |||
| 072653c944 | |||
| ad17c7d5d7 | |||
| e469313baf | |||
| 543b1ef605 | |||
| 24f1fba97e | |||
| 88fe564e24 | |||
| efa492570e | |||
| d07795cb6a | |||
| f3c3580855 | |||
| 62f59722a6 | |||
| 3e31a38eb9 | |||
| 549ddc3e6f | |||
| d300e896e8 | |||
| 16514f9c25 | |||
| bb9f9c515b | |||
| 77c5ae64dd | |||
| 18c7f89564 | |||
| 5f185b52e9 | |||
| 2f5ea369b7 | |||
| ef708c3291 | |||
| 9e040d80c4 | |||
| e3ced7b961 | |||
| c9b2270786 | |||
| 99ebb23138 | |||
| d4f428d311 | |||
| e602a269f8 | |||
| d432914828 | |||
| 0cf54c4837 | |||
| c1692019a6 | |||
| 72362936be | |||
| 65b6be8283 | |||
| fd8dde32f1 | |||
| fff9f4ea74 | |||
| 9e5d8c4ca4 | |||
| a70be63894 | |||
| c2fa0f2c0b | |||
| 5280ee98bd | |||
| 1a207c8100 | |||
| 80d10d7d85 | |||
| ecc10994ca | |||
| 7289fc12ad | |||
| f44366ff05 | |||
| 70a71c06a7 | |||
| a0202de532 | |||
| caa00f2a61 | |||
| eed6f43aea | |||
| 59ab689a36 | |||
| 2bf1fa7c80 | |||
| 32e5f777fe | |||
| f8aeef14e3 | |||
| 763b7361ec | |||
| c151107207 | |||
| f95d2f114a | |||
| e04e7ceaa5 | |||
| 3c1c8e85c8 | |||
| 095a363520 | |||
| 932780e9d9 | |||
| d404d0ab69 | |||
| 8038db26f3 |
4
gclc-process/.gitignore
vendored
Normal file
4
gclc-process/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/target/
|
||||
/.classpath
|
||||
/.project
|
||||
/.settings/
|
||||
60
gclc-process/pom.xml
Normal file
60
gclc-process/pom.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
<!-- process, Distribution repositories and basic setup for Emmanuel Bigeon projects -->
|
||||
<!-- Copyright (C) 2014-2017 E. Bigeon -->
|
||||
<!-- mailto:emmanuel@bigeon.fr -->
|
||||
<!-- -->
|
||||
<!-- 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. -->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>fr.bigeon.gclc</groupId>
|
||||
<artifactId>process</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>process</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<parent>
|
||||
<groupId>fr.bigeon</groupId>
|
||||
<artifactId>ebigeon-config</artifactId>
|
||||
<version>1.8.0</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>fr.bigeon</groupId>
|
||||
<artifactId>gclc</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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-process:fr.bigeon.gclc.process.CommandFork.java
|
||||
* Created on: Nov 13, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.process;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import fr.bigeon.gclc.command.CommandParameters;
|
||||
import fr.bigeon.gclc.command.ICommand;
|
||||
import fr.bigeon.gclc.command.ICommandProvider;
|
||||
import fr.bigeon.gclc.command.ParametrizedCommand;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||
import fr.bigeon.gclc.exception.InvalidParameterException;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** A command that is launched inside an internal terminal.
|
||||
* <p>
|
||||
* Several things are to be considered before adding this command to an
|
||||
* application:
|
||||
* <ul>
|
||||
* <li>The commands will be able to run in parallel.
|
||||
* <li>The managing of the commands will be handled through piped systems and
|
||||
* buffered in so switching to a forled command will actually print again all
|
||||
* the command history to the output console.
|
||||
* </ul>
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class CommandFork extends ParametrizedCommand {
|
||||
|
||||
private final TaskPool pool = new TaskPool();
|
||||
private ICommandProvider provider;
|
||||
|
||||
/** Add the fork command.
|
||||
*
|
||||
* @param name the command name */
|
||||
public CommandFork(final String name) {
|
||||
super(name);
|
||||
addParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void addParameters() {
|
||||
try {
|
||||
addStringParameter("join", false);
|
||||
addBooleanParameter("list");
|
||||
} catch (final InvalidParameterException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ParametrizedCommand#doExecute(fr.bigeon.gclc.
|
||||
* manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* fr.bigeon.gclc.command.CommandParameters) */
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out, final ConsoleInput in,
|
||||
final CommandParameters parameters) throws CommandRunException {
|
||||
if (parameters.getBool("list")) {
|
||||
for (final String id : pool.getPIDs()) {
|
||||
try {
|
||||
out.println(id + "\t" + pool.get(id).getName());
|
||||
} catch (final IOException e) {
|
||||
throw new CommandRunException(
|
||||
CommandRunExceptionType.INTERACTION,
|
||||
"Failed to write to console", e, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final String string = parameters.get("join");
|
||||
if (string != null) {
|
||||
// Join the command.
|
||||
final ForkTask cmd = (ForkTask) pool.get(string);
|
||||
if (cmd == null) {
|
||||
throw new CommandRunException("No such fork process", this);
|
||||
}
|
||||
cmd.join(out, in);
|
||||
return;
|
||||
}
|
||||
|
||||
final List<String> strings = parameters.getAdditionals();
|
||||
final ICommand cmd = provider.get(strings.get(0));
|
||||
final String[] args = Arrays.copyOfRange(strings.toArray(new String[0]),
|
||||
1, strings.size());
|
||||
final ForkTask task = new ForkTask(cmd, args);
|
||||
final Thread th = new Thread(task);
|
||||
pool.add(task);
|
||||
th.start();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
||||
@Override
|
||||
public String tip() {
|
||||
// TODO Auto-generated method stub
|
||||
// return null;
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
// TODO Auto-generated method stub
|
||||
// return null;
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
|
||||
}
|
||||
127
gclc-process/src/main/java/fr/bigeon/gclc/process/ForkTask.java
Normal file
127
gclc-process/src/main/java/fr/bigeon/gclc/process/ForkTask.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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-process:fr.bigeon.gclc.process.ForkTask.java
|
||||
* Created on: Nov 13, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.process;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import fr.bigeon.gclc.command.ICommand;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon
|
||||
*
|
||||
*/
|
||||
public class ForkTask implements Task {
|
||||
|
||||
private final ICommand command;
|
||||
private final String[] args;
|
||||
private final Set<InterruptionListener> listeners = new HashSet<>();
|
||||
private boolean running = false;
|
||||
|
||||
/** @param cmd the command
|
||||
* @param args the arguements */
|
||||
public ForkTask(final ICommand cmd, final String[] args) {
|
||||
command = cmd;
|
||||
this.args = Arrays.copyOf(args, args.length);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.process.Task#addInterruptionListener(fr.bigeon.gclc.
|
||||
* process.InterruptionListener) */
|
||||
@Override
|
||||
public void addInterruptionListener(final InterruptionListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.process.Task#getName() */
|
||||
@Override
|
||||
public String getName() {
|
||||
return command.getCommandName();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.process.Task#isRunning() */
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return running;
|
||||
}
|
||||
|
||||
/** @param out the console output
|
||||
* @param in the console input */
|
||||
public void join(final ConsoleOutput out, final ConsoleInput in) {
|
||||
// TODO Auto-generated method stub
|
||||
//
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* fr.bigeon.gclc.process.Task#rmInterruptionListener(fr.bigeon.gclc.process
|
||||
* .InterruptionListener) */
|
||||
@Override
|
||||
public void rmInterruptionListener(final InterruptionListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run() */
|
||||
@Override
|
||||
public void run() {
|
||||
running = true;
|
||||
try {
|
||||
// TODO Auto-generated method stub
|
||||
//
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
} finally {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.process.Task#setRunning(boolean) */
|
||||
@Override
|
||||
public void setRunning(final boolean running) {
|
||||
this.running = running;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.proc.InterruptionListener.java
|
||||
* Created on: May 10, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.process;
|
||||
|
||||
/** A listener for interruption
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public interface InterruptionListener {
|
||||
/** Notification of an interuption of a listened object */
|
||||
void interrupted();
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.proc.ProcessList.java
|
||||
* Created on: May 10, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.process;
|
||||
|
||||
import fr.bigeon.gclc.command.Command;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** A command that will flag a task to stop
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class ProcessKill extends Command {
|
||||
/** The taskpool */
|
||||
private final TaskPool pool;
|
||||
|
||||
/** @param name the command name
|
||||
* @param pool the pool */
|
||||
public ProcessKill(final String name, final TaskPool pool) {
|
||||
super(name);
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.manager.
|
||||
* ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
pool.get(args[0]).setRunning(false);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
||||
@SuppressWarnings("nls")
|
||||
@Override
|
||||
public String tip() {
|
||||
return "Request a process to stop (softly)";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.proc.ProcessList.java
|
||||
* Created on: May 10, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.process;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import fr.bigeon.gclc.command.Command;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** A command to list current processes
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class ProcessList extends Command {
|
||||
/** The process pool */
|
||||
private final TaskPool pool;
|
||||
|
||||
/** @param name the command name
|
||||
* @param pool the pool */
|
||||
public ProcessList(final String name, final TaskPool pool) {
|
||||
super(name);
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.manager.
|
||||
* ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
final ArrayList<String> pids = new ArrayList<>(pool.getPIDs());
|
||||
Collections.sort(pids);
|
||||
for (final String string : pids) {
|
||||
try {
|
||||
out.println(MessageFormat.format("{0}\t{1}", string, //$NON-NLS-1$
|
||||
pool.get(string).getName()));
|
||||
} catch (final IOException e) {
|
||||
throw new CommandRunException(
|
||||
CommandRunExceptionType.INTERACTION,
|
||||
"Unable to communicate with user", e, this); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
||||
@SuppressWarnings("nls")
|
||||
@Override
|
||||
public String tip() {
|
||||
return "List all processes";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
78
gclc-process/src/main/java/fr/bigeon/gclc/process/Task.java
Normal file
78
gclc-process/src/main/java/fr/bigeon/gclc/process/Task.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.proc.ThreadCommand.java
|
||||
* Created on: May 10, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.process;
|
||||
|
||||
/** Tasks are named runnable that can be interrupted.
|
||||
* <p>
|
||||
* Good practice for those objects include an absence of interaction with the
|
||||
* user (otherwise the user may not know from which running command comes
|
||||
* information and requests) and unicity of the object to have a coherent
|
||||
* control through the {@link #setRunning(boolean)} method.
|
||||
* <p>
|
||||
* Typical cases where such command can be useful is for an application that
|
||||
* does long computations.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public interface Task extends Runnable {
|
||||
/** Add a listener for this command end of execution
|
||||
*
|
||||
* @param listener the listener */
|
||||
void addInterruptionListener(InterruptionListener listener);
|
||||
|
||||
/** Get the task name.
|
||||
*
|
||||
* @return the task name */
|
||||
String getName();
|
||||
|
||||
/** Test the running status of the task.
|
||||
*
|
||||
* @return if the command is supposed to be running */
|
||||
boolean isRunning();
|
||||
|
||||
/** Remove a listener of this command end of execution
|
||||
*
|
||||
* @param listener the listener */
|
||||
void rmInterruptionListener(InterruptionListener listener);
|
||||
|
||||
/** Set the running state.
|
||||
* <p>
|
||||
* This method should be only called by external objects with the false
|
||||
* argument. Calling this method with true has unspecified behavior and
|
||||
* could do nothing as well as restart the command for example.
|
||||
*
|
||||
* @param running the running state */
|
||||
void setRunning(boolean running);
|
||||
}
|
||||
115
gclc-process/src/main/java/fr/bigeon/gclc/process/TaskPool.java
Normal file
115
gclc-process/src/main/java/fr/bigeon/gclc/process/TaskPool.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.proc.TaskPool.java
|
||||
* Created on: May 10, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.process;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
/** A process pool.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class TaskPool {
|
||||
/** The running processes. */
|
||||
private final Map<String, Task> running = new HashMap<>();
|
||||
/** The count for process id. */
|
||||
private int count = 0;
|
||||
/** The lock for pid attribution synchronization. */
|
||||
private final Object lock = new Object();
|
||||
|
||||
/** Default constructor. */
|
||||
public TaskPool() {
|
||||
//
|
||||
}
|
||||
|
||||
/** Add a process in the pool.
|
||||
*
|
||||
* @param cmd the process
|
||||
* @return the pid */
|
||||
public String add(final Task cmd) {
|
||||
if (cmd == null) {
|
||||
throw new IllegalArgumentException("Task cannot be null"); //$NON-NLS-1$
|
||||
}
|
||||
final String pid = getPID();
|
||||
synchronized (lock) {
|
||||
running.put(pid, cmd);
|
||||
}
|
||||
cmd.addInterruptionListener(new InterruptionListener() {
|
||||
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void interrupted() {
|
||||
synchronized (lock) {
|
||||
running.remove(pid);
|
||||
count = Math.min(count, Integer.parseInt(pid));
|
||||
}
|
||||
cmd.rmInterruptionListener(this);
|
||||
}
|
||||
});
|
||||
return pid;
|
||||
}
|
||||
|
||||
/** Get a process by it associated identifier.
|
||||
*
|
||||
* @param pid the task id
|
||||
* @return the task, if any, associated to this id */
|
||||
public Task get(final String pid) {
|
||||
synchronized (lock) {
|
||||
return running.get(pid);
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the next process id.
|
||||
*
|
||||
* @return the process id */
|
||||
private String getPID() {
|
||||
synchronized (lock) {
|
||||
String pid;
|
||||
do {
|
||||
pid = Integer.toString(count++);
|
||||
} while (running.containsKey(pid));
|
||||
return pid;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the running processes' identifiers.
|
||||
*
|
||||
* @return the pids */
|
||||
public Collection<String> getPIDs() {
|
||||
return new HashSet<>(running.keySet());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.proc.ProcessList.java
|
||||
* Created on: May 10, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.process;
|
||||
|
||||
import fr.bigeon.gclc.command.Command;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** An abstract command to generate a task and return the control to the user
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public abstract class TaskSpawner extends Command {
|
||||
/** The process pool */
|
||||
private final TaskPool pool;
|
||||
|
||||
/** @param name the command name
|
||||
* @param pool the pool */
|
||||
public TaskSpawner(final String name, final TaskPool pool) {
|
||||
super(name);
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
/** @param in the input
|
||||
* @param out the output
|
||||
* @param args the arguments
|
||||
* @return the process to start and add to the pool */
|
||||
protected abstract Task createTask(ConsoleOutput out, ConsoleInput in,
|
||||
String... args);
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.manager.
|
||||
* ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
final Task task = createTask(out, in, args);
|
||||
final Thread th = new Thread(task);
|
||||
pool.add(task);
|
||||
th.start();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,35 @@
|
||||
|
||||
<!-- GCLC Socket, Socket implementation of GCLC -->
|
||||
<!-- Copyright (C) 2014-2017 E. Bigeon -->
|
||||
<!-- mailto:emmanuel@bigeon.fr -->
|
||||
<!-- -->
|
||||
<!-- 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. -->
|
||||
|
||||
|
||||
<!-- Copyright E. Bigeon (2014) -->
|
||||
<!-- -->
|
||||
<!-- emmanuel@bigeon.fr -->
|
||||
@@ -70,7 +101,7 @@ of Emmanuel Bigeon. -->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>gclc-socket</artifactId>
|
||||
<version>1.0.5-SNAPSHOT</version>
|
||||
<version>1.1.10-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<url>http://www.bigeon.fr/emmanuel</url>
|
||||
<properties>
|
||||
@@ -78,27 +109,21 @@ of Emmanuel Bigeon. -->
|
||||
<project.scm.id>git.bigeon.net</project.scm.id>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>fr.bigeon</groupId>
|
||||
<artifactId>gclc</artifactId>
|
||||
<version>1.2.2</version>
|
||||
<version>2.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>fr.bigeon</groupId>
|
||||
<artifactId>smu</artifactId>
|
||||
<version>0.0.4</version>
|
||||
<version>0.0.7</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<parent>
|
||||
<groupId>fr.bigeon</groupId>
|
||||
<artifactId>ebigeon-config</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.7.1</version>
|
||||
</parent>
|
||||
<name>GCLC Socket</name>
|
||||
<description>Socket implementation of GCLC</description>
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.ConnexionManager.java
|
||||
* Created on: Nov 18, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/** A manager for connected elements.
|
||||
* <p>
|
||||
* Connected elements are given an identifier (unique) at connexion.
|
||||
*
|
||||
* @author Emmanuel Bigeon
|
||||
* @param <T> the type of object connected */
|
||||
public interface ConnexionManager<T> {
|
||||
/** Add a connection in the name.
|
||||
*
|
||||
* @param handle the connected object
|
||||
* @return the name */
|
||||
String addConnexion(T handle);
|
||||
|
||||
/** Disconnect an element.
|
||||
*
|
||||
* @param id the element connection id
|
||||
* @return the object being disconnected */
|
||||
T disconnect(String id);
|
||||
|
||||
/** Get the connected object.
|
||||
*
|
||||
* @param id the connexion id
|
||||
* @return the object */
|
||||
T get(String id);
|
||||
|
||||
/** Get the connected elements' ids.
|
||||
*
|
||||
* @return the connected elements' ids */
|
||||
Collection<String> getConnected();
|
||||
|
||||
/** Test if a connection is active.
|
||||
*
|
||||
* @param id the connexion id
|
||||
* @return if the connection is active. */
|
||||
boolean isConnected(String id);
|
||||
|
||||
/** Add a lock on the disconnection.
|
||||
* <p>
|
||||
* This lock will <strong>not</strong> prevent calls to
|
||||
* {@link #disconnect(String)}. It will however stop them from completing
|
||||
* after the effective disconnection of the specified connection.
|
||||
* <p>
|
||||
* Calls to {@link #releaseDisconnexionLock(String)} remove a lock (at a
|
||||
* pace of one for one).
|
||||
*
|
||||
* @param id the connexion id */
|
||||
void lockDisconnexion(String id);
|
||||
|
||||
/** Release one lock on a disconnection
|
||||
*
|
||||
* @param id the connexion being released. */
|
||||
void releaseDisconnexionLock(String id);
|
||||
|
||||
/** Wait for calls to {@link #disconnect(String)}
|
||||
*
|
||||
* @param id the connexion id
|
||||
* @throws InterruptedException if the wait was interrupted. */
|
||||
void waitDisconnexion(String id) throws InterruptedException;
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.DConnexionManager.java
|
||||
* Created on: Nov 18, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/** Default implementation of the {@link ConnexionManager}.
|
||||
*
|
||||
* @author Emmanuel Bigeon
|
||||
* @param <T> the connected objects */
|
||||
public final class DConnexionManager<T> implements ConnexionManager<T> {
|
||||
|
||||
/** Class logger. */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(DConnexionManager.class.getName());
|
||||
/** The connected objects. */
|
||||
private final Map<String, T> connecteds = new HashMap<>();
|
||||
/** The locks for the connexions. */
|
||||
private final Map<String, Object> locks = new HashMap<>();
|
||||
/** The counter for the disconnexion locks. */
|
||||
private final Map<String, Integer> counters = new HashMap<>();
|
||||
/** The lock for modification of {@link #counters}. */
|
||||
private final Object counterLock = new Object();
|
||||
/** The count of connexions. */
|
||||
private int count = 0;
|
||||
|
||||
/** Default.constructor. */
|
||||
public DConnexionManager() {
|
||||
//
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* fr.bigeon.gclc.socket.ConnexionManager#addConnexion(java.lang.Object) */
|
||||
@Override
|
||||
public String addConnexion(final T handle) {
|
||||
final String newID = newID();
|
||||
connecteds.put(newID, handle);
|
||||
locks.put(newID, new Object());
|
||||
counters.put(newID, Integer.valueOf(0));
|
||||
return newID;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* fr.bigeon.gclc.socket.ConnexionManager#disconnect(java.lang.String) */
|
||||
@Override
|
||||
public T disconnect(final String id) {
|
||||
if (connecteds.containsKey(id)) {
|
||||
final T disc = connecteds.remove(id);
|
||||
final Object lock = locks.get(id);
|
||||
synchronized (lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
synchronized (counterLock) {
|
||||
while (counters.get(id).intValue() > 0) {
|
||||
try {
|
||||
counterLock.wait();
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.FINE, "Interruption of thread", e); //$NON-NLS-1$
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
return disc;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.socket.ConnexionManager#get(java.lang.String) */
|
||||
@Override
|
||||
public T get(final String id) {
|
||||
return connecteds.get(id);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.socket.ConnexionManager#getConnected() */
|
||||
@Override
|
||||
public Collection<String> getConnected() {
|
||||
return connecteds.keySet();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* fr.bigeon.gclc.socket.ConnexionManager#isConnected(java.lang.String) */
|
||||
@Override
|
||||
public boolean isConnected(final String id) {
|
||||
return connecteds.containsKey(id);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* fr.bigeon.gclc.socket.ConnexionManager#lockDisconnexion(java.lang.String) */
|
||||
@Override
|
||||
public void lockDisconnexion(final String id) {
|
||||
if (!connecteds.containsKey(id)) {
|
||||
return;
|
||||
}
|
||||
synchronized (counterLock) {
|
||||
counters.put(id, Integer.valueOf(counters.get(id).intValue() + 1));
|
||||
}
|
||||
}
|
||||
|
||||
/** Get a new identifier for connexion.
|
||||
*
|
||||
* @return a new ID */
|
||||
private String newID() {
|
||||
return "Client " + count++; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* fr.bigeon.gclc.socket.ConnexionManager#releaseDisconnexionLock(java.lang.
|
||||
* String) */
|
||||
@Override
|
||||
public void releaseDisconnexionLock(final String id) {
|
||||
synchronized (counterLock) {
|
||||
counters.put(id, Integer
|
||||
.valueOf(Math.max(counters.get(id).intValue() - 1, 0)));
|
||||
counterLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* fr.bigeon.gclc.socket.ConnexionManager#waitDisconnexion(java.lang.String) */
|
||||
@Override
|
||||
public void waitDisconnexion(final String id) throws InterruptedException {
|
||||
final Object lock = locks.get(id);
|
||||
while (connecteds.containsKey(id)) {
|
||||
synchronized (lock) {
|
||||
lock.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.PlugableConsoleInput.java
|
||||
* Created on: Nov 18, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ReadingRunnable;
|
||||
|
||||
/** A console input where the stream can be plugged.
|
||||
* <p>
|
||||
* This pluggable console input accepts an input and output to be connected to
|
||||
* it. The connexion cannot be concurrent, which mean that any connected stream
|
||||
* must be disconnected before a new call to
|
||||
* {@link #connect(InputStream, PrintStream)} is done.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class PluggableConsoleInput implements ConsoleInput {
|
||||
/** The ten constant. */
|
||||
private static final int TENTH = 10;
|
||||
/** Class logger. */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(PluggableConsoleInput.class.getName());
|
||||
/** The default time out. */
|
||||
private static final long TIMEOUT = 100;
|
||||
/** The prompting. */
|
||||
private boolean prompting = false;
|
||||
/** If the element is closed. */
|
||||
private boolean closed = false;
|
||||
/** The default prompt. */
|
||||
private String prompt = "> "; //$NON-NLS-1$
|
||||
/** If the input is plugged or buffering. */
|
||||
private boolean connected = false;
|
||||
/** The current connexion (if any). */
|
||||
private ReadingRunnable connexion;
|
||||
/** The interrupted status for prompts. */
|
||||
private boolean interrupted = false;
|
||||
/** The last hint hint. */
|
||||
private String hint;
|
||||
/** The output for hints. */
|
||||
private PrintStream output;
|
||||
|
||||
// Locks
|
||||
/** The lock for connexion and disconnexion of actual streams. */
|
||||
private final Object connexionLock = new Object();
|
||||
|
||||
/** Create the pluggable console input. */
|
||||
public PluggableConsoleInput() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#close() */
|
||||
@Override
|
||||
public void close() {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
/** Connect the given input stream to the input and output to the hints
|
||||
* writing.
|
||||
*
|
||||
* @param stream the input stream
|
||||
* @param out the output for hints.
|
||||
* @throws IOException if the input is already connected. */
|
||||
public void connect(final InputStream stream,
|
||||
final PrintStream out) throws IOException {
|
||||
synchronized (connexionLock) {
|
||||
if (connected) {
|
||||
throw new IOException(
|
||||
"Input already connected to an input stream"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
output = out;
|
||||
if (prompting) {
|
||||
out.print(hint);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
final InputStreamReader streamReader = new InputStreamReader(
|
||||
stream, StandardCharsets.UTF_8);
|
||||
final BufferedReader reader = new BufferedReader(streamReader);
|
||||
connexion = new ReadingRunnable(reader);
|
||||
final Thread th = new Thread(connexion, "GCLC Socket - Read input"); //$NON-NLS-1$
|
||||
th.start();
|
||||
connexionLock.notifyAll();
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Disconnect the current input and hint output. */
|
||||
public synchronized void disconnect() {
|
||||
synchronized (connexionLock) {
|
||||
if (!connected) {
|
||||
return;
|
||||
}
|
||||
connected = false;
|
||||
connexion.setRunning(false);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#getPrompt() */
|
||||
@Override
|
||||
public String getPrompt() {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#interruptPrompt() */
|
||||
@Override
|
||||
public void interruptPrompt() {
|
||||
interrupted = true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#isClosed() */
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
/** Test if a prompt is occuring.
|
||||
*
|
||||
* @return the prompting */
|
||||
public boolean isPrompting() {
|
||||
return prompting;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt() */
|
||||
@Override
|
||||
public String prompt() throws IOException {
|
||||
return prompt(prompt);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(long) */
|
||||
@Override
|
||||
public String prompt(final long timeout) throws IOException {
|
||||
return prompt(prompt, timeout);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(java.lang.String) */
|
||||
@Override
|
||||
public String prompt(final String message) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException();
|
||||
}
|
||||
prompting = true;
|
||||
hint = message;
|
||||
synchronized (connexionLock) {
|
||||
hint = message;
|
||||
if (connected) {
|
||||
output.print(message);
|
||||
output.flush();
|
||||
}
|
||||
}
|
||||
|
||||
String res = null;
|
||||
while (res == null && !interrupted) {
|
||||
try {
|
||||
res = waitMessageOrConnexion(TIMEOUT, TIMEOUT / TENTH);
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.FINE, "Interruption of thread", e); //$NON-NLS-1$
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
if (closed) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
prompting = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(java.lang.String,
|
||||
* long) */
|
||||
@Override
|
||||
public String prompt(final String message,
|
||||
final long timeout) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException();
|
||||
}
|
||||
prompting = true;
|
||||
synchronized (connexionLock) {
|
||||
hint = message;
|
||||
if (connected) {
|
||||
output.print(message);
|
||||
output.flush();
|
||||
}
|
||||
}
|
||||
|
||||
String res = null;
|
||||
final long tic = System.currentTimeMillis();
|
||||
long time = System.currentTimeMillis() - tic;
|
||||
while (res == null && !interrupted && time < timeout) {
|
||||
try {
|
||||
res = waitMessageOrConnexion(timeout - time,
|
||||
(timeout - time) / TENTH);
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.FINE, "Interruption of thread", e); //$NON-NLS-1$
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
time = System.currentTimeMillis() - tic;
|
||||
if (closed) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
prompting = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#setPrompt(java.lang.String) */
|
||||
@Override
|
||||
public void setPrompt(final String prompt) {
|
||||
this.prompt = prompt;
|
||||
}
|
||||
|
||||
/** Wait for a hint or connexion.
|
||||
*
|
||||
* @param messageTimeout the timeout on the current connexion hint waiting
|
||||
* @param connexionTimeout the timeout on the new connexion wait
|
||||
* @return the hint, or null if not connected or timed out.
|
||||
* @throws IOException if the reading failed.
|
||||
* @throws InterruptedException if the wait was interrupted */
|
||||
private String waitMessageOrConnexion(final long messageTimeout,
|
||||
final long connexionTimeout) throws IOException,
|
||||
InterruptedException {
|
||||
synchronized (connexionLock) {
|
||||
if (connected) {
|
||||
return connexion.getNextMessage(messageTimeout);
|
||||
}
|
||||
connexionLock.wait(connexionTimeout);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.PluggableConsoleOutput.java
|
||||
* Created on: Nov 18, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** An output that can be hotplugged to an actual output.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class PluggableConsoleOutput implements ConsoleOutput {
|
||||
|
||||
/** The actual output. */
|
||||
private PrintStream out;
|
||||
/** The buffered messages. */
|
||||
private final Deque<String> messages = new ArrayDeque<>();
|
||||
/** If this output is closed. */
|
||||
private boolean closed = false;
|
||||
|
||||
/** Default constructor. */
|
||||
public PluggableConsoleOutput() {
|
||||
//
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.AutoCloseable#close() */
|
||||
@Override
|
||||
public void close() {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
/** Set the output to write to.
|
||||
*
|
||||
* @param output the output to set */
|
||||
public synchronized void connect(final PrintStream output) {
|
||||
out = output;
|
||||
while (!messages.isEmpty()) {
|
||||
output.print(messages.pop());
|
||||
}
|
||||
}
|
||||
|
||||
/** Disconnects the output. */
|
||||
public synchronized void disconnect() {
|
||||
out = null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#isClosed() */
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#print(java.lang.String) */
|
||||
@Override
|
||||
public synchronized void print(final String text) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Closed output"); //$NON-NLS-1$
|
||||
}
|
||||
if (out == null) {
|
||||
messages.add(text);
|
||||
} else {
|
||||
out.print(text);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#println() */
|
||||
@Override
|
||||
public synchronized void println() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Closed output"); //$NON-NLS-1$
|
||||
}
|
||||
if (out == null) {
|
||||
messages.add("\n"); //$NON-NLS-1$
|
||||
} else {
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#println(java.lang.String) */
|
||||
@Override
|
||||
public synchronized void println(final String message) throws IOException {
|
||||
print(message);
|
||||
println();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.RemoteDisconnectCommand.java
|
||||
* Created on: Nov 18, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collection;
|
||||
|
||||
import fr.bigeon.gclc.command.Command;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** A {@link Command} to disconnect elements from a {@link ConnexionManager}.
|
||||
*
|
||||
* @author Emmanuel Bigeon
|
||||
* @param <T> the type of connected object */
|
||||
public final class RemoteDisconnectCommand<T> extends Command {
|
||||
|
||||
/** The connexion manager. */
|
||||
private final ConnexionManager<T> manager;
|
||||
/** If all connexion should be disconnected when no argument have been
|
||||
* specified. */
|
||||
private final boolean all;
|
||||
|
||||
/** Create the disconnection command.
|
||||
*
|
||||
* @param name the command name
|
||||
* @param manager the manager
|
||||
* @param all if all elements should be disconnected when no argument is
|
||||
* provided */
|
||||
public RemoteDisconnectCommand(final String name,
|
||||
final ConnexionManager<T> manager, final boolean all) {
|
||||
super(name);
|
||||
this.manager = manager;
|
||||
this.all = all;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.manager.
|
||||
* ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
if (args.length == 0 && all) {
|
||||
final Collection<String> coll = manager.getConnected();
|
||||
for (final String string : coll) {
|
||||
manager.disconnect(string);
|
||||
}
|
||||
}
|
||||
for (final String string : args) {
|
||||
if (manager.isConnected(string)) {
|
||||
manager.disconnect(string);
|
||||
} else {
|
||||
print(out, MessageFormat
|
||||
.format("[WARNING] {0} is not connected", string)); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Print a message if the output is defined.
|
||||
*
|
||||
* @param out the output
|
||||
* @param string the message
|
||||
* @throws CommandRunException if the output exists but cannot be printed
|
||||
* to */
|
||||
private void print(final ConsoleOutput out,
|
||||
final String string) throws CommandRunException {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.println(string);
|
||||
} catch (final IOException e) {
|
||||
throw new CommandRunException(
|
||||
CommandRunExceptionType.INTERACTION,
|
||||
"Unable to print to existing output", e, this); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
||||
@Override
|
||||
public String tip() {
|
||||
return "Close a connexion."; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@SuppressWarnings("nls")
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return MessageFormat.format(
|
||||
" If arguments are provided the corresponding connexions are closed, " +
|
||||
"otherwise{0}{1} are.",
|
||||
System.lineSeparator(), all ? "all connexions" : "none");
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2014)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* Socket implementation of GCLC.
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
@@ -34,26 +31,17 @@
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.InetAddress;
|
||||
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.manager.ConsoleManager;
|
||||
import fr.bigeon.smu.StringEncoder;
|
||||
|
||||
/** This is a socket communicating console consoleManager
|
||||
/** This is a socket communicating console consoleManager.
|
||||
* <p>
|
||||
* To use this application, the following flow should be used:
|
||||
*
|
||||
@@ -71,71 +59,60 @@ import fr.bigeon.smu.StringEncoder;
|
||||
* end of the execution.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class SocketConsoleApplicationShell implements Runnable {
|
||||
public final 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("%", //$NON-NLS-1$
|
||||
Arrays.asList(EOL));
|
||||
/** The class logger */
|
||||
/** The class logger. */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(SocketConsoleApplicationShell.class.getName());
|
||||
/** The listening port */
|
||||
/** The listening port. */
|
||||
private final int port;
|
||||
/** The input */
|
||||
private final PipedInputStream consoleInput = new PipedInputStream();
|
||||
/** The application */
|
||||
private ConsoleApplication app;
|
||||
/** The session closing command */
|
||||
private final String close;
|
||||
/** The running status */
|
||||
/** The running status. */
|
||||
private boolean running;
|
||||
/** An object to lock on for prompt */
|
||||
private final Object promptingLock = new Object();
|
||||
/** The socket console interface. */
|
||||
private SocketConsoleInterface sci;
|
||||
/** The remote disconnection command. */
|
||||
private ConnexionManager<Socket> rdc;
|
||||
/** The application. */
|
||||
private ConsoleApplication app;
|
||||
|
||||
/** The console manager implementation */
|
||||
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 */
|
||||
/** The server socket. */
|
||||
private ServerSocket serverSocket;
|
||||
/** The application shutdown string */
|
||||
private final String applicationShutdown;
|
||||
/** THe server address. */
|
||||
private final InetAddress addr;
|
||||
|
||||
/** Create a socket application shell which will listen on the given port
|
||||
* and close session upon the provided string reception by client
|
||||
* and network interface.
|
||||
*
|
||||
* @param port the port to listen to
|
||||
* @param close the session closing command
|
||||
* @param applicationShutdown the appication shut down command */
|
||||
public SocketConsoleApplicationShell(int port, String close,
|
||||
String applicationShutdown) {
|
||||
* @param port the part
|
||||
* @param addr the inet address */
|
||||
public SocketConsoleApplicationShell(final int port,
|
||||
final InetAddress addr) {
|
||||
super();
|
||||
this.port = port;
|
||||
this.close = close;
|
||||
this.applicationShutdown = applicationShutdown;
|
||||
this.autoClose = false;
|
||||
this.addr = addr;
|
||||
}
|
||||
|
||||
/** Create a socket application shell which will listen on the given port
|
||||
* and auto close session after one instruction
|
||||
/** Wait for the identified connection to disconnect.
|
||||
*
|
||||
* @param port the port to listen to
|
||||
* @param autoClose if the session must be closed once the request has been
|
||||
* sent
|
||||
* @param applicationShutdown the application shutdown command */
|
||||
public SocketConsoleApplicationShell(int port, boolean autoClose,
|
||||
String applicationShutdown) {
|
||||
this.port = port;
|
||||
this.autoClose = autoClose;
|
||||
this.applicationShutdown = applicationShutdown;
|
||||
this.close = autoClose ? null : "close"; //$NON-NLS-1$
|
||||
* @param id the connexion id. */
|
||||
private void awaitDisconnexion(final String id) {
|
||||
while (rdc.isConnected(id)) {
|
||||
try {
|
||||
rdc.waitDisconnexion(id);
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.SEVERE, "Unexpected interruption", e); //$NON-NLS-1$
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
sci.disconnect();
|
||||
}
|
||||
|
||||
/** If the port provided was 0, this allows to get the actual port.
|
||||
* @return the local port
|
||||
* @see java.net.ServerSocket#getLocalPort()
|
||||
*/
|
||||
public int getLocalPort() {
|
||||
return serverSocket.getLocalPort();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -143,146 +120,69 @@ public class SocketConsoleApplicationShell implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
// Create the server
|
||||
try (ServerSocket actualServerSocket = new ServerSocket(port)) {
|
||||
this.serverSocket = actualServerSocket;
|
||||
try (ServerSocket actualServerSocket = new ServerSocket(port, 1,
|
||||
addr)) {
|
||||
serverSocket = actualServerSocket;
|
||||
running = true;
|
||||
// Create the streams
|
||||
try (PipedOutputStream outStream = new PipedOutputStream();
|
||||
BufferedWriter writer = new BufferedWriter(
|
||||
new OutputStreamWriter(outStream));
|
||||
InputStreamReader isr = new InputStreamReader(consoleInput);
|
||||
BufferedReader inBuf = new BufferedReader(isr)) {
|
||||
consoleInput.connect(outStream);
|
||||
consoleManager.setInput(inBuf);
|
||||
runSokectServer(writer);
|
||||
// Close the application
|
||||
// Pass command to application
|
||||
if (app.isRunning()) {
|
||||
writer.write(applicationShutdown + EOL);
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
} catch (
|
||||
|
||||
final IOException e) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
runSokectServer();
|
||||
} catch (final IOException e) {
|
||||
LOGGER.severe("Communication error between client and server"); //$NON-NLS-1$
|
||||
LOGGER.log(Level.FINE,
|
||||
"Communication error between client and server", e); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
/** @param writer the writer to the application
|
||||
/** Acctually run the server loop on connexion.
|
||||
*
|
||||
* @throws IOException if the communication with the client failed */
|
||||
private void runSokectServer(BufferedWriter writer) throws IOException {
|
||||
final ConsoleRunnable runnable = new ConsoleRunnable(app,
|
||||
promptingLock);
|
||||
Thread appThOld = null;
|
||||
Thread appThNext = new Thread(runnable);
|
||||
while (running) {
|
||||
try (Socket clientSocket = serverSocket.accept();
|
||||
PrintWriter out = new PrintWriter(
|
||||
clientSocket.getOutputStream(), true);
|
||||
InputStreamReader isr = new InputStreamReader(
|
||||
clientSocket.getInputStream());
|
||||
BufferedReader in = new BufferedReader(isr);) {
|
||||
// this is not threaded to avoid several clients at the same
|
||||
// time
|
||||
consoleManager.setOutput(out);
|
||||
// Initiate application
|
||||
if (appThOld == null || !appThOld.isAlive()) {
|
||||
appThNext.start();
|
||||
// Prepare next start
|
||||
appThOld = appThNext;
|
||||
appThNext = new Thread(runnable);
|
||||
} else {
|
||||
out.println("Reconnected"); //$NON-NLS-1$
|
||||
}
|
||||
communicate(writer, in);
|
||||
} catch (SocketException e) {
|
||||
LOGGER.log(Level.INFO, "Socket closed", e); //$NON-NLS-1$
|
||||
private void runSokectServer() throws IOException {
|
||||
while (running && app.isRunning()) {
|
||||
LOGGER.info("Waiting client"); //$NON-NLS-1$
|
||||
try (Socket clientSocket = serverSocket.accept();) {
|
||||
|
||||
sci.connect(clientSocket);
|
||||
|
||||
final String id = rdc.addConnexion(clientSocket);
|
||||
rdc.lockDisconnexion(id);
|
||||
awaitDisconnexion(id);
|
||||
rdc.releaseDisconnexionLock(id);
|
||||
} catch (final SocketException e) {
|
||||
LOGGER.log(Level.INFO, "Socket closed"); //$NON-NLS-1$
|
||||
LOGGER.log(Level.FINE,
|
||||
"Socket closed with exception (probably due to server interruption)", //$NON-NLS-1$
|
||||
e);
|
||||
} catch (final IOException e) {
|
||||
throw e;
|
||||
}
|
||||
LOGGER.info("Closing client"); //$NON-NLS-1$
|
||||
}
|
||||
LOGGER.info("Closing Server"); //$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 (app.isRunning() && (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return the consoleManager */
|
||||
public synchronized ConsoleManager getConsoleManager() {
|
||||
return consoleManager;
|
||||
}
|
||||
|
||||
/** @param app the application to set */
|
||||
public synchronized void setApplication(ConsoleApplication app) {
|
||||
/** Set the application.
|
||||
* <p>
|
||||
* If the application is closed, the server will also close.
|
||||
*
|
||||
* @param app the app to set */
|
||||
public void setApplication(final ConsoleApplication app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
/** Set the connexion manager.
|
||||
*
|
||||
* @param rdc the rdc to set */
|
||||
public void setConnexionManager(final ConnexionManager<Socket> rdc) {
|
||||
this.rdc = rdc;
|
||||
}
|
||||
|
||||
/** Set the socket console interface.
|
||||
*
|
||||
* @param sci the console interface to set */
|
||||
public void setInterface(final SocketConsoleInterface sci) {
|
||||
this.sci = sci;
|
||||
}
|
||||
|
||||
/** This method will request the server to stop.
|
||||
* <p>
|
||||
* In most cases, this will terminate communication on every client. On some
|
||||
@@ -291,13 +191,8 @@ public class SocketConsoleApplicationShell implements Runnable {
|
||||
running = false;
|
||||
try {
|
||||
serverSocket.close();
|
||||
} catch (IOException e) {
|
||||
} catch (final IOException e) {
|
||||
LOGGER.log(Level.SEVERE, "Exception in closing socket server", e); //$NON-NLS-1$
|
||||
}
|
||||
synchronized (promptingLock) {
|
||||
promptingLock.notifyAll();
|
||||
}
|
||||
app.exit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.SocketConsoleInterface.java
|
||||
* Created on: Nov 18, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/** The interface for socket based access to console application.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class SocketConsoleInterface {
|
||||
|
||||
/** The application's input. */
|
||||
private final PluggableConsoleInput input;
|
||||
/** The application's output. */
|
||||
private final PluggableConsoleOutput output;
|
||||
|
||||
/** Create the interfacing object.
|
||||
*
|
||||
* @param input the input
|
||||
* @param output the output */
|
||||
public SocketConsoleInterface(final PluggableConsoleInput input,
|
||||
final PluggableConsoleOutput output) {
|
||||
super();
|
||||
this.input = input;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
/** Connect the application's input and outputs to the socket's.
|
||||
*
|
||||
* @param socket the socket
|
||||
* @throws IOException if the connection failed */
|
||||
public void connect(final Socket socket) throws IOException {
|
||||
final PrintStream printStream = new PrintStream(
|
||||
socket.getOutputStream(), true,
|
||||
StandardCharsets.UTF_8.name());
|
||||
output.connect(printStream);
|
||||
input.connect(socket.getInputStream(),
|
||||
printStream);
|
||||
}
|
||||
|
||||
/** Disconnect the input and output of the application from the socket's. */
|
||||
public void disconnect() {
|
||||
input.disconnect();
|
||||
output.disconnect();
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* 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.manager.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;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private boolean closed = false;
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#close() */
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// Do nothing
|
||||
this.closed = true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#isClosed() */
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.package-info.java
|
||||
* Created on: Nov 18, 2017
|
||||
*/
|
||||
/** This package define a framework to access
|
||||
* {@link fr.bigeon.gclc.ConsoleApplication} through a socket.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
package fr.bigeon.gclc.socket;
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* 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 java.io.IOException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.SystemConsoleManager;
|
||||
|
||||
/** Test class for {@link ConsoleRunnable}
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
@SuppressWarnings({"static-method", "unused", "javadoc"})
|
||||
public class ConsoleRunnableTest {
|
||||
|
||||
/** <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
private static final class ConsoleManagerTestImplementation
|
||||
implements ConsoleManager {
|
||||
int i = 0;
|
||||
String[] cmds;
|
||||
|
||||
/** @param cmds */
|
||||
public ConsoleManagerTestImplementation(String[] cmds) {
|
||||
super();
|
||||
this.cmds = cmds;
|
||||
}
|
||||
|
||||
@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
|
||||
}
|
||||
i++;
|
||||
if (i == cmds.length) {
|
||||
i = 0;
|
||||
}
|
||||
return cmds[i];
|
||||
}
|
||||
|
||||
@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
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#isClosed() */
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return i == cmds.length;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 ConsoleManagerTestImplementation(
|
||||
new String[] {"test", ConsoleTestApplication.EXIT})); //$NON-NLS-1$
|
||||
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 ConsoleManagerTestImplementation(
|
||||
new String[] {"test", ConsoleTestApplication.EXIT})); //$NON-NLS-1$
|
||||
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 ConsoleManagerTestImplementation(
|
||||
new String[] {"test", ConsoleTestApplication.EXIT})); //$NON-NLS-1$
|
||||
ConsoleRunnable runnable = new ConsoleRunnable(app, lock);
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2014)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* Socket implementation of GCLC.
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
@@ -35,6 +32,8 @@
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.Collection;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.command.Command;
|
||||
@@ -42,59 +41,118 @@ import fr.bigeon.gclc.command.ExitCommand;
|
||||
import fr.bigeon.gclc.command.HelpExecutor;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** A test-purpose application
|
||||
*
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class ConsoleTestApplication extends ConsoleApplication {
|
||||
public class ConsoleTestApplication {
|
||||
|
||||
/** Exit command */
|
||||
public static final String EXIT = "exit"; //$NON-NLS-1$
|
||||
|
||||
/** @param manager the manager */
|
||||
/** Create the test application.
|
||||
*
|
||||
* @param output the output
|
||||
* @param input the input
|
||||
* @param manager the manager
|
||||
* @return create the application */
|
||||
@SuppressWarnings("nls")
|
||||
public ConsoleTestApplication(final ConsoleManager manager) {
|
||||
super(manager, "Welcome to the test application. Type help or test.",
|
||||
"See you");
|
||||
public static ConsoleApplication create(final ConsoleOutput output,
|
||||
final ConsoleInput input,
|
||||
final ConnexionManager<Socket> manager) {
|
||||
try {
|
||||
add(new ExitCommand(EXIT, this));
|
||||
add(new HelpExecutor("help", manager, this.getRoot()));
|
||||
add(new Command("test") {
|
||||
final ConsoleApplication application = new ConsoleApplication(
|
||||
output, input,
|
||||
"Welcome to the test application. Type help or test.",
|
||||
"See you");
|
||||
application.add(new ExitCommand(EXIT, application) {
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ExitCommand#beforeExit() */
|
||||
@Override
|
||||
protected void beforeExit() {
|
||||
final Collection<String> coll = manager.getConnected();
|
||||
for (final String string : coll) {
|
||||
manager.disconnect(string);
|
||||
}
|
||||
}
|
||||
});
|
||||
application
|
||||
.add(new HelpExecutor("help", application.root));
|
||||
application.add(new Command("test") {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.
|
||||
* manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
try {
|
||||
output.println("Test command ran fine");
|
||||
} catch (final IOException e) {
|
||||
throw new CommandRunException("manager closed", e,
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "A test command";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail()
|
||||
*/
|
||||
@Override
|
||||
public void execute(String... args) throws CommandRunException {
|
||||
try {
|
||||
manager.println("Test command ran fine");
|
||||
} catch (IOException e) {
|
||||
throw new CommandRunException("manager closed", e);
|
||||
}
|
||||
protected String usageDetail() {
|
||||
// TODO Auto-generated method stub
|
||||
// return null;
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
});
|
||||
add(new Command("long") {
|
||||
application.add(new Command("long") {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.
|
||||
* manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
output.println("Test command ran fine");
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new CommandRunException("manager closed", e,
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "A long run test command";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail()
|
||||
*/
|
||||
@Override
|
||||
public void execute(String... args) throws CommandRunException {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
manager.println("Test command ran fine");
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new CommandRunException("manager closed", e);
|
||||
}
|
||||
protected String usageDetail() {
|
||||
// TODO Auto-generated method stub
|
||||
// return null;
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
});
|
||||
application.add(
|
||||
new RemoteDisconnectCommand<>("out", manager, true));
|
||||
return application;
|
||||
} catch (final InvalidCommandName e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.PluggableConsoleInputTest.java
|
||||
* Created on: Nov 18, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class PluggableConsoleInputTest {
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.socket.PluggableConsoleInput#close()}. */
|
||||
@Test
|
||||
public final void testClose() {
|
||||
final PluggableConsoleInput input = new PluggableConsoleInput();
|
||||
assertFalse("Input should not be initially closed", input.isClosed());
|
||||
input.close();
|
||||
assertTrue("Close should close the input", input.isClosed());
|
||||
|
||||
try {
|
||||
input.prompt();
|
||||
fail("Closed prompt should cause an IO");
|
||||
} catch (final IOException e) {
|
||||
// ok
|
||||
}
|
||||
try {
|
||||
input.prompt(10);
|
||||
fail("Closed prompt should cause an IO");
|
||||
} catch (final IOException e) {
|
||||
// ok
|
||||
}
|
||||
|
||||
final PluggableConsoleInput input2 = new PluggableConsoleInput();
|
||||
|
||||
final Thread th = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!input2.isPrompting()) {
|
||||
|
||||
}
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
input2.close();
|
||||
}
|
||||
});
|
||||
th.start();
|
||||
try {
|
||||
input.prompt();
|
||||
fail("Closed prompt should cause an IO");
|
||||
} catch (final IOException e) {
|
||||
// ok
|
||||
}
|
||||
final PluggableConsoleInput input3 = new PluggableConsoleInput();
|
||||
|
||||
final Thread th2 = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
input3.close();
|
||||
}
|
||||
});
|
||||
th2.start();
|
||||
try {
|
||||
input.prompt(2000);
|
||||
fail("Closed prompt should cause an IO");
|
||||
} catch (final IOException e) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testConnect() throws IOException, InterruptedException {
|
||||
final PluggableConsoleInput input = new PluggableConsoleInput();
|
||||
|
||||
input.disconnect();
|
||||
try (final PipedInputStream pis = new PipedInputStream();
|
||||
final PipedOutputStream pos = new PipedOutputStream();
|
||||
final PipedInputStream inner = new PipedInputStream(pos);
|
||||
final PipedOutputStream innerPos = new PipedOutputStream(pis);
|
||||
final PrintStream testIn = new PrintStream(innerPos, true, "UTF8");
|
||||
final PrintStream out = new PrintStream(pos)) {
|
||||
input.connect(pis, out);
|
||||
try {
|
||||
input.connect(pis, out);
|
||||
fail("Should not be able to connect already connected");
|
||||
} catch (final IOException e) {
|
||||
// ok
|
||||
}
|
||||
input.disconnect();
|
||||
|
||||
final Thread th = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
input.prompt("Test", 5000);
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
th.start();
|
||||
|
||||
while (!input.isPrompting()) {
|
||||
Thread.sleep(10);
|
||||
}
|
||||
|
||||
input.connect(pis, out);
|
||||
testIn.println("tac");
|
||||
|
||||
final Thread th2 = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
input.prompt("Test", 5000);
|
||||
fail("Prompt should io");
|
||||
} catch (final IOException e) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
});
|
||||
th2.start();
|
||||
while (!input.isPrompting()) {
|
||||
Thread.sleep(10);
|
||||
}
|
||||
|
||||
input.close();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.socket.PluggableConsoleInput#getPrompt()}. */
|
||||
@Test
|
||||
public final void testGetPrompt() {
|
||||
final PluggableConsoleInput input = new PluggableConsoleInput();
|
||||
assertEquals("Default prompt invalid", "> ", input.getPrompt());
|
||||
input.setPrompt("test");
|
||||
assertEquals("Prompt setting failed", "test", input.getPrompt());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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.RemoteDisconnectCommandTest.java
|
||||
* Created on: Nov 18, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class RemoteDisconnectCommandTest {
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.socket.RemoteDisconnectCommand#execute(fr.bigeon.gclc.manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput, java.lang.String[])}.
|
||||
*
|
||||
* @throws CommandRunException if the command unexpectedly failed.
|
||||
* @throws IOException if the output could not be written to */
|
||||
@Test
|
||||
public final void testExecute() throws CommandRunException, IOException {
|
||||
final DConnexionManager<String> manager = new DConnexionManager<>();
|
||||
final RemoteDisconnectCommand<String> cmd = new RemoteDisconnectCommand<>(
|
||||
"quit", manager, true);
|
||||
final RemoteDisconnectCommand<String> cmd2 = new RemoteDisconnectCommand<>(
|
||||
"quit", manager, false);
|
||||
manager.addConnexion("test");
|
||||
|
||||
cmd2.execute(null, null);
|
||||
assertFalse("No arguemnt should remova no connections",
|
||||
manager.getConnected().isEmpty());
|
||||
cmd.execute(null, null);
|
||||
assertTrue("No arguemnt should remova all connections",
|
||||
manager.getConnected().isEmpty());
|
||||
|
||||
final String name1 = manager.addConnexion("test");
|
||||
final String name2 = manager.addConnexion("test");
|
||||
|
||||
cmd.execute(null, null, name1);
|
||||
assertFalse("With argument shuld remove specified name",
|
||||
manager.getConnected().contains(name1));
|
||||
assertTrue("With argument shuld remove only specified name",
|
||||
manager.getConnected().contains(name2));
|
||||
|
||||
cmd.execute(null, null, name1);
|
||||
assertTrue("With argument shuld remove only specified name",
|
||||
manager.getConnected().contains(name2));
|
||||
|
||||
try (PipedConsoleOutput out = new PipedConsoleOutput()) {
|
||||
cmd.execute(out, null, name1);
|
||||
assertTrue("With argument shuld remove only specified name",
|
||||
manager.getConnected().contains(name2));
|
||||
|
||||
out.close();
|
||||
try {
|
||||
cmd.execute(out, null, name1);
|
||||
fail("Closed stream should cause error in printing");
|
||||
} catch (final CommandRunException e) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2014)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* Socket implementation of GCLC.
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
@@ -38,101 +35,135 @@
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
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 java.util.logging.Logger;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.smu.StringEncoder;
|
||||
|
||||
/** Test class for {@link SocketConsoleApplicationShell}
|
||||
*
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
@SuppressWarnings({"static-method", "unused", "javadoc", "nls"})
|
||||
@SuppressWarnings({"static-method", "javadoc", "nls"})
|
||||
public class SocketConsoleApplicationTest {
|
||||
|
||||
private static final StringEncoder ENCODER = new StringEncoder("%",
|
||||
Arrays.asList("\n")); //$NON-NLS-1$
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(SocketConsoleApplicationTest.class.getName());
|
||||
|
||||
/** @param in the input
|
||||
* @return the string
|
||||
* @throws IOException if the input reading failed */
|
||||
private String consumeToPrompt(final String server,
|
||||
final BufferedReader in) throws IOException {
|
||||
String fromServer = server;
|
||||
LOGGER.fine("Server: \n" + fromServer);
|
||||
while (fromServer != null && !fromServer.equals("Bye.") &&
|
||||
!fromServer.equals("> ")) {
|
||||
fromServer = in.readLine();
|
||||
LOGGER.fine("Server: \n" + fromServer);
|
||||
}
|
||||
return fromServer;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void integrationTest() {
|
||||
Thread server = TestServer.startServer(false);
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
public void testIntegration() throws IOException, InterruptedException {
|
||||
Thread server;
|
||||
server = TestServer.getServer();
|
||||
Thread.sleep(1000);
|
||||
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()));) {
|
||||
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(),
|
||||
true);
|
||||
BufferedReader in = new BufferedReader(
|
||||
new InputStreamReader(kkSocket.getInputStream()));) {
|
||||
|
||||
String fromServer;
|
||||
int i = 0;
|
||||
String[] cmds = {"help", "toto", "test", "close"};
|
||||
int i = -1;
|
||||
final String[] cmds = {"help", "toto", "test", "out"};
|
||||
while ((fromServer = in.readLine()) != null) {
|
||||
System.out.println("Server: \n" + ENCODER.decode(fromServer));
|
||||
if (fromServer.equals("Bye.")) {
|
||||
i++;
|
||||
fromServer = consumeToPrompt(fromServer, in);
|
||||
if (fromServer == null || fromServer.equals("Bye.")) {
|
||||
break;
|
||||
}
|
||||
|
||||
final String fromUser = cmds[i];
|
||||
if (fromUser != null) {
|
||||
System.out.println("Client: " + fromUser);
|
||||
LOGGER.fine("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();
|
||||
assertEquals("Disconnection command should close connection", 3, i);
|
||||
}
|
||||
|
||||
try (Socket kkSocket = new Socket(hostName, portNumber);
|
||||
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(),
|
||||
true);
|
||||
BufferedReader in = new BufferedReader(
|
||||
new InputStreamReader(kkSocket.getInputStream()));) {
|
||||
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"};
|
||||
final String[] cmds = {"help", "toto", "test",
|
||||
ConsoleTestApplication.EXIT};
|
||||
while ((fromServer = in.readLine()) != null) {
|
||||
// System.out.println("Server: \n" + ENCODER.decode(fromServer));
|
||||
if (fromServer.equals("Bye.")) {
|
||||
fromServer = consumeToPrompt(fromServer, in);
|
||||
if (fromServer == null || fromServer.equals("Bye.")) {
|
||||
break;
|
||||
}
|
||||
LOGGER.info("Server: \n" + fromServer);
|
||||
|
||||
final String fromUser = cmds[i];
|
||||
if (fromUser != null) {
|
||||
LOGGER.info("Client: " + fromUser);
|
||||
out.println(fromUser);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assertEquals("Application exit command should close connection", 4,
|
||||
i);
|
||||
}
|
||||
Thread.sleep(100);
|
||||
TestServer.closeServer();
|
||||
server.join();
|
||||
server = TestServer.getServer();
|
||||
Thread.sleep(1000);
|
||||
|
||||
|
||||
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;
|
||||
final String[] cmds = {"help", "toto", "test",
|
||||
ConsoleTestApplication.EXIT};
|
||||
while ((fromServer = in.readLine()) != null) {
|
||||
fromServer = consumeToPrompt(fromServer, in);
|
||||
if (fromServer == null || fromServer.equals("Bye.")) {
|
||||
break;
|
||||
}
|
||||
|
||||
final String fromUser = cmds[i];
|
||||
if (fromUser != null) {
|
||||
// System.out.println("Client: " + fromUser);
|
||||
LOGGER.fine("Client: " + fromUser);
|
||||
out.println(fromUser);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
assertEquals("Application exit command should close connection", 4,
|
||||
i);
|
||||
}
|
||||
TestServer.closeServer();
|
||||
|
||||
server.join();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2014)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* Socket implementation of GCLC.
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2014)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* Socket implementation of GCLC.
|
||||
* GCLC Socket, Socket implementation of GCLC
|
||||
* Copyright (C) 2014-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
@@ -34,25 +31,35 @@
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
|
||||
/** A test server
|
||||
*
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
@SuppressWarnings({"javadoc", "nls"})
|
||||
public class TestServer {
|
||||
|
||||
private static SocketConsoleApplicationShell SHELL;
|
||||
private static Thread server;
|
||||
private static ConnexionManager<Socket> manager;
|
||||
|
||||
/** @param args no argument */
|
||||
public static void main(String... args) {
|
||||
try {
|
||||
startServer(false).join();
|
||||
} catch (final InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
private static Thread server;
|
||||
private static PluggableConsoleInput input;
|
||||
private static PluggableConsoleOutput output;
|
||||
|
||||
public static synchronized void closeServer() {
|
||||
SHELL.stop();
|
||||
input.close();
|
||||
output.close();
|
||||
SHELL = null;
|
||||
server = null;
|
||||
}
|
||||
|
||||
public static Thread getServer() {
|
||||
public static synchronized Thread getServer() throws IOException {
|
||||
if (server == null) {
|
||||
server = new Thread(getShell(), "gclcServer");
|
||||
server.start();
|
||||
@@ -60,32 +67,39 @@ public class TestServer {
|
||||
return server;
|
||||
}
|
||||
|
||||
/** @return */
|
||||
private static SocketConsoleApplicationShell getShell() {
|
||||
private static SocketConsoleApplicationShell getShell() throws UnknownHostException {
|
||||
if (SHELL == null) {
|
||||
SHELL = new SocketConsoleApplicationShell(3300, "close",
|
||||
ConsoleTestApplication.EXIT);
|
||||
final ConsoleTestApplication app = new ConsoleTestApplication(
|
||||
SHELL.getConsoleManager());
|
||||
input = new PluggableConsoleInput();
|
||||
input.setPrompt("> \n");
|
||||
output = new PluggableConsoleOutput();
|
||||
manager = new DConnexionManager<>();
|
||||
SHELL = new SocketConsoleApplicationShell(3300,
|
||||
InetAddress.getByName("127.0.0.1"));
|
||||
final ConsoleApplication app = ConsoleTestApplication
|
||||
.create(output, input, manager);
|
||||
SHELL.setInterface(new SocketConsoleInterface(input, output));
|
||||
SHELL.setConnexionManager(manager);
|
||||
SHELL.setApplication(app);
|
||||
final Thread th = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
app.start();
|
||||
}
|
||||
});
|
||||
th.start();
|
||||
}
|
||||
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;
|
||||
/** @param args no argument
|
||||
* @throws IOException if the server starting failed */
|
||||
public static void main(final String... args) throws IOException {
|
||||
try {
|
||||
getServer().join();
|
||||
} catch (final InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return getServer();
|
||||
}
|
||||
|
||||
public static void closeServer() {
|
||||
SHELL.stop();
|
||||
SHELL = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,35 @@
|
||||
|
||||
<!-- GCLC swt, provide a swt window for console applications -->
|
||||
<!-- Copyright (C) 2015-2017 E. Bigeon -->
|
||||
<!-- mailto:emmanuel@bigeon.fr -->
|
||||
<!-- -->
|
||||
<!-- 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. -->
|
||||
|
||||
|
||||
<!-- Copyright E. Bigeon (2015) -->
|
||||
<!-- -->
|
||||
<!-- emmanuel@bigeon.fr -->
|
||||
@@ -32,12 +63,10 @@
|
||||
<!-- The fact that you are presently reading this means that you have had -->
|
||||
<!-- knowledge of the CeCILL license and that you accept its terms. -->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
|
||||
>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>gclc-swt</artifactId>
|
||||
<version>1.0.5-SNAPSHOT</version>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<url>http://www.bigeon.fr/emmanuel</url>
|
||||
<properties>
|
||||
@@ -47,18 +76,18 @@
|
||||
<parent>
|
||||
<groupId>fr.bigeon</groupId>
|
||||
<artifactId>ebigeon-config</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.7.1</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>fr.bigeon</groupId>
|
||||
<artifactId>gclc</artifactId>
|
||||
<version>1.2.2</version>
|
||||
<version>2.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>fr.bigeon</groupId>
|
||||
<artifactId>collections</artifactId>
|
||||
<version>1.0.1</version>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<inceptionYear>2015</inceptionYear>
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* GCLC swt, provide a swt window for console applications
|
||||
* Copyright (C) 2015-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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-swt:fr.bigeon.gclc.swt.ConsoleDelayIO.java
|
||||
* Created on: Nov 19, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.swt;
|
||||
|
||||
/** This class represents an object used to send commands to a console
|
||||
* application.
|
||||
* <p>
|
||||
* The sending of command is done in two phases. Define the input through get
|
||||
* and set, and then validate the input.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public interface ConsoleDelayIO {
|
||||
/** Get the input text.
|
||||
* @return the non validated input */
|
||||
String getInput();
|
||||
|
||||
/** Set the input text.
|
||||
*
|
||||
* @param input the input to set */
|
||||
void setInput(String input);
|
||||
|
||||
/** Actually send the input as the prompt next input. */
|
||||
void validateInput();
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2015)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* provide a swt window for console applications.
|
||||
* GCLC swt, provide a swt window for console applications
|
||||
* Copyright (C) 2015-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
@@ -41,47 +38,53 @@ package fr.bigeon.gclc.swt;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.KeyAdapter;
|
||||
import org.eclipse.swt.events.KeyEvent;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
|
||||
import fr.bigeon.collections.ArrayRibbon;
|
||||
import fr.bigeon.collections.Ribbon;
|
||||
|
||||
/** A key listener to validate commands and manage the history of commands
|
||||
/** A key listener to validate commands and manage the history of commands.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class HistoryTextKeyListener extends KeyAdapter {
|
||||
|
||||
/** The size of commands history */
|
||||
/** The size of commands history. */
|
||||
private static final int DEFAULT_HISTORY_SIZE = 10;
|
||||
/** The history ribbon */
|
||||
/** The empty string constant. */
|
||||
private static final String EMPTY = ""; //$NON-NLS-1$
|
||||
/** The history ribbon. */
|
||||
private final Ribbon<String> commands;
|
||||
/** The current index in history search */
|
||||
/** 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;
|
||||
/** The console to notify of command validation. */
|
||||
private final ConsoleDelayIO console;
|
||||
|
||||
/** @param console the console
|
||||
* @param consoleInput the text to write commands in */
|
||||
public HistoryTextKeyListener(SWTConsole console, Text consoleInput) {
|
||||
/** Create the key listener that cycle the history.
|
||||
*
|
||||
* @param console the console delayed */
|
||||
public HistoryTextKeyListener(final ConsoleDelayIO console) {
|
||||
super();
|
||||
this.console = console;
|
||||
this.consoleInput = consoleInput;
|
||||
this.commands = new ArrayRibbon<>(DEFAULT_HISTORY_SIZE);
|
||||
commands = new ArrayRibbon<>(DEFAULT_HISTORY_SIZE);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.swt.events.KeyAdapter#keyPressed(org.eclipse.swt.events.
|
||||
* KeyEvent) */
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
|
||||
public void keyPressed(final KeyEvent e) {
|
||||
pressedKeyCode(e.keyCode);
|
||||
}
|
||||
|
||||
/** @param keyCode */
|
||||
public void pressedKeyCode(int keyCode) {
|
||||
/** Indicate a pressed key combination.
|
||||
*
|
||||
* @param keyCode the pressed key code */
|
||||
public void pressedKeyCode(final int keyCode) {
|
||||
// Enter validates the command if prompting
|
||||
if (keyCode == '\r') {
|
||||
commands.add(consoleInput.getText());
|
||||
final String input = console.getInput();
|
||||
if (!input.isEmpty()) {
|
||||
commands.add(input);
|
||||
}
|
||||
console.validateInput();
|
||||
currentIndex = -1;
|
||||
}
|
||||
@@ -90,21 +93,19 @@ public final class HistoryTextKeyListener extends KeyAdapter {
|
||||
if (keyCode == SWT.ARROW_UP &&
|
||||
currentIndex < commands.size() - 1) {
|
||||
currentIndex++;
|
||||
String cmd = commands.get(commands.size() - currentIndex - 1);
|
||||
consoleInput.setText(cmd);
|
||||
consoleInput.setSelection(cmd.length());
|
||||
final String cmd = commands.get(commands.size() - currentIndex - 1);
|
||||
console.setInput(cmd);
|
||||
}
|
||||
|
||||
// Lower arrow retrieves next commands
|
||||
if (keyCode == SWT.ARROW_DOWN) {
|
||||
if (currentIndex == 0) {
|
||||
currentIndex--;
|
||||
consoleInput.setText(new String());
|
||||
console.setInput(EMPTY);
|
||||
} else if (currentIndex > 0) {
|
||||
String cmd = commands
|
||||
final String cmd = commands
|
||||
.get(commands.size() - (--currentIndex) - 1);
|
||||
consoleInput.setText(cmd);
|
||||
consoleInput.setSelection(cmd.length());
|
||||
console.setInput(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2015)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* provide a swt window for console applications.
|
||||
* GCLC swt, provide a swt window for console applications
|
||||
* Copyright (C) 2015-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
@@ -43,8 +40,6 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.FocusAdapter;
|
||||
import org.eclipse.swt.events.FocusEvent;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
@@ -53,42 +48,44 @@ import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** A SWT component to connect to gclc {@link ConsoleApplication}
|
||||
/** A SWT component to connect to gclc {@link ConsoleApplication}.
|
||||
* <p>
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class SWTConsole extends Composite implements ConsoleManager {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final class SWTConsole extends Composite
|
||||
implements ConsoleDelayIO, ConsoleInput, ConsoleOutput {
|
||||
/** The number of columns of the layout. */
|
||||
private static final int LAYOUT_NB_COLUMNS = 2;
|
||||
/** The cmd prefix in the output console */
|
||||
/** The cmd prefix in the output console. */
|
||||
private static final String CMD_PREFIX = "[CMD] "; //$NON-NLS-1$
|
||||
/** The class logger */
|
||||
/** The class logger. */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(SWTConsole.class.getName());
|
||||
/** The console output text field */
|
||||
/** The empty string constant. */
|
||||
private static final String EMPTY = ""; //$NON-NLS-1$
|
||||
/** The console output text field. */
|
||||
private final Text consoleOutput;
|
||||
/** The console input text field */
|
||||
/** The console input text field. */
|
||||
private final Text consoleInput;
|
||||
/** The prompt label */
|
||||
/** The prompt label. */
|
||||
private final Label lblPromptlabel;
|
||||
/** The prompt text */
|
||||
/** The prompt text. */
|
||||
private String prompt = ">"; //$NON-NLS-1$
|
||||
/** The command entered by the user */
|
||||
/** The command entered by the user. */
|
||||
private String command = null;
|
||||
/** If the prompt should be active */
|
||||
/** If the prompt should be active. */
|
||||
private boolean prompting = false;
|
||||
/** The object for thread synchronization with the prompt */
|
||||
/** The object for thread synchronization with the prompt. */
|
||||
private final Object promptLock = new Object();
|
||||
|
||||
/** Create the composite.
|
||||
*
|
||||
* @param parent the prent composite
|
||||
* @param style the composite style */
|
||||
public SWTConsole(Composite parent, int style) {
|
||||
public SWTConsole(final Composite parent, final int style) {
|
||||
super(parent, style);
|
||||
|
||||
setLayout(new GridLayout(LAYOUT_NB_COLUMNS, false));
|
||||
@@ -98,13 +95,6 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
consoleOutput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true,
|
||||
LAYOUT_NB_COLUMNS, 1));
|
||||
consoleOutput.setRedraw(true);
|
||||
consoleOutput.addFocusListener(new FocusAdapter() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
consoleInput.setFocus();
|
||||
}
|
||||
});
|
||||
|
||||
lblPromptlabel = new Label(this, SWT.NONE);
|
||||
lblPromptlabel.setText(prompt);
|
||||
@@ -112,51 +102,36 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
consoleInput = new Text(this, SWT.BORDER);
|
||||
consoleInput.setLayoutData(
|
||||
new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
|
||||
consoleInput
|
||||
.addKeyListener(new HistoryTextKeyListener(this, consoleInput));
|
||||
consoleInput.addKeyListener(new HistoryTextKeyListener(this));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected void validateInput() {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
consoleInput.setEnabled(false);
|
||||
}
|
||||
});
|
||||
synchronized (promptLock) {
|
||||
while (!prompting) {
|
||||
try {
|
||||
promptLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Interruption while waiting prompt", e); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
command = consoleInput.getText();
|
||||
prompting = false;
|
||||
consoleInput.setText(new String());
|
||||
consoleOutput.append(
|
||||
CMD_PREFIX + command + System.lineSeparator());
|
||||
}
|
||||
});
|
||||
promptLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkSubclass() {
|
||||
// Disable the check that prevents subclassing of SWT components
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#close() */
|
||||
@Override
|
||||
public void close() {
|
||||
synchronized (promptLock) {
|
||||
promptLock.notifyAll();
|
||||
}
|
||||
if (consoleInput.isDisposed()) {
|
||||
return;
|
||||
}
|
||||
consoleInput.setEnabled(false);
|
||||
consoleOutput.setEnabled(false);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.swt.ConsoleDelayIO#getInput() */
|
||||
@Override
|
||||
public String getInput() {
|
||||
return consoleInput.getText();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#getPrompt() */
|
||||
@Override
|
||||
@@ -164,6 +139,22 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#interruptPrompt() */
|
||||
@Override
|
||||
public void interruptPrompt() {
|
||||
synchronized (promptLock) {
|
||||
promptLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#isClosed() */
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return isDisposed();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#print(java.lang.String) */
|
||||
@Override
|
||||
@@ -172,7 +163,9 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
consoleOutput.append(text);
|
||||
if (!consoleOutput.isDisposed()) {
|
||||
consoleOutput.append(text);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -185,7 +178,9 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
consoleOutput.append(System.lineSeparator());
|
||||
if (!consoleOutput.isDisposed()) {
|
||||
consoleOutput.append(System.lineSeparator());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -198,7 +193,9 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
consoleOutput.append(message + System.lineSeparator());
|
||||
if (!consoleOutput.isDisposed()) {
|
||||
consoleOutput.append(message + System.lineSeparator());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -217,15 +214,20 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
consoleInput.setEnabled(true);
|
||||
consoleInput.setFocus();
|
||||
if (!consoleInput.isDisposed()) {
|
||||
consoleInput.setEnabled(true);
|
||||
consoleInput.setFocus();
|
||||
}
|
||||
}
|
||||
});
|
||||
prompting = true;
|
||||
promptLock.notifyAll();
|
||||
promptLock.wait();
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Error in synchronization of prompting", e); //$NON-NLS-1$
|
||||
command = null;
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
if (isDisposed()) {
|
||||
@@ -234,6 +236,16 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
return command;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(long)
|
||||
*/
|
||||
@Override
|
||||
public String prompt(final long timeout) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
// return null;
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt(java.lang.String) */
|
||||
@Override
|
||||
@@ -247,11 +259,13 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
lblPromptlabel.setText(message);
|
||||
// relayout
|
||||
SWTConsole.this.layout();
|
||||
consoleInput.setEnabled(true);
|
||||
consoleInput.setFocus();
|
||||
if (!consoleOutput.isDisposed()) {
|
||||
lblPromptlabel.setText(message);
|
||||
// relayout
|
||||
SWTConsole.this.layout();
|
||||
consoleInput.setEnabled(true);
|
||||
consoleInput.setFocus();
|
||||
}
|
||||
}
|
||||
});
|
||||
prompting = true;
|
||||
@@ -260,15 +274,20 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
throw new IOException();
|
||||
}
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Error in synchronization of prompting", e); //$NON-NLS-1$
|
||||
command = null;
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
lblPromptlabel.setText(prompt);
|
||||
// relayout
|
||||
SWTConsole.this.layout();
|
||||
if (!consoleOutput.isDisposed()) {
|
||||
lblPromptlabel.setText(prompt);
|
||||
// relayout
|
||||
SWTConsole.this.layout();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -276,6 +295,16 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
return command;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(java.lang.String, long)
|
||||
*/
|
||||
@Override
|
||||
public String prompt(final String message, final long timeout) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
// return null;
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.swt.widgets.Composite#setFocus() */
|
||||
@Override
|
||||
@@ -283,6 +312,14 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
return consoleInput.setFocus();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.swt.ConsoleDelayIO#setInput(java.lang.String) */
|
||||
@Override
|
||||
public void setInput(final String input) {
|
||||
consoleInput.setText(input);
|
||||
consoleInput.setSelection(input.length());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#setPrompt(java.lang.String) */
|
||||
@Override
|
||||
@@ -292,44 +329,61 @@ public class SWTConsole extends Composite implements ConsoleManager {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
lblPromptlabel.setText(prompt);
|
||||
// relayout
|
||||
SWTConsole.this.layout();
|
||||
if (!consoleOutput.isDisposed()) {
|
||||
lblPromptlabel.setText(prompt);
|
||||
// relayout
|
||||
SWTConsole.this.layout();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#close() */
|
||||
@Override
|
||||
public void close() {
|
||||
synchronized (promptLock) {
|
||||
promptLock.notify();
|
||||
}
|
||||
if (consoleInput.isDisposed()) {
|
||||
return;
|
||||
}
|
||||
consoleInput.setEnabled(false);
|
||||
consoleOutput.setEnabled(false);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#isClosed() */
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return isDisposed();
|
||||
}
|
||||
|
||||
/** @param string the text */
|
||||
public void setText(String string) {
|
||||
public void setText(final String string) {
|
||||
consoleInput.setText(string);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public void validateCommand() {
|
||||
validateInput();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void validateInput() {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
consoleInput.setEnabled(false);
|
||||
}
|
||||
});
|
||||
synchronized (promptLock) {
|
||||
while (!prompting) {
|
||||
try {
|
||||
promptLock.wait();
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Interruption while waiting prompt", e); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
command = consoleInput.getText();
|
||||
prompting = false;
|
||||
consoleInput.setText(EMPTY);
|
||||
consoleOutput.append(
|
||||
CMD_PREFIX + command + System.lineSeparator());
|
||||
}
|
||||
});
|
||||
promptLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2015)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* provide a swt window for console applications.
|
||||
* GCLC swt, provide a swt window for console applications
|
||||
* Copyright (C) 2015-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
@@ -43,13 +40,11 @@ import org.eclipse.swt.layout.FillLayout;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
|
||||
/** A shell containing a {@link SWTConsole}
|
||||
* <p>
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class SWTConsoleShell extends Shell {
|
||||
public final class SWTConsoleShell extends Shell {
|
||||
|
||||
/** The console component */
|
||||
private SWTConsole console;
|
||||
@@ -57,7 +52,7 @@ public class SWTConsoleShell extends Shell {
|
||||
/** Create the shell.
|
||||
*
|
||||
* @param display the display */
|
||||
public SWTConsoleShell(Display display) {
|
||||
public SWTConsoleShell(final Display display) {
|
||||
super(display, SWT.SHELL_TRIM);
|
||||
setLayout(new FillLayout(SWT.HORIZONTAL));
|
||||
|
||||
@@ -75,11 +70,6 @@ public class SWTConsoleShell extends Shell {
|
||||
setText("Console Application"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** @return the console manager */
|
||||
public ConsoleManager getManager() {
|
||||
return console;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.swt.widgets.Shell#dispose() */
|
||||
@Override
|
||||
@@ -87,4 +77,9 @@ public class SWTConsoleShell extends Shell {
|
||||
super.dispose();
|
||||
console.close();
|
||||
}
|
||||
|
||||
/** @return the input and output. */
|
||||
public SWTConsole getManager() {
|
||||
return console;
|
||||
}
|
||||
}
|
||||
|
||||
190
gclc-swt/src/main/java/fr/bigeon/gclc/swt/SWTConsoleView.java
Normal file
190
gclc-swt/src/main/java/fr/bigeon/gclc/swt/SWTConsoleView.java
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* GCLC swt, provide a swt window for console applications
|
||||
* Copyright (C) 2015-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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-swt:fr.bigeon.gclc.swt.SWTConsole.java
|
||||
* Created on: Apr 18, 2015
|
||||
*/
|
||||
package fr.bigeon.gclc.swt;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleInput;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||
import fr.bigeon.gclc.tools.AOutputForwardRunnable;
|
||||
|
||||
/** A SWT component to connect to gclc {@link ConsoleApplication}
|
||||
* <p>
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class SWTConsoleView extends Composite implements ConsoleDelayIO {
|
||||
/** The local implementation of the forwarding runnable
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
private final class ToSWTConsoleForwardRunnable
|
||||
extends AOutputForwardRunnable {
|
||||
/** The running status */
|
||||
private boolean running = true;
|
||||
|
||||
/** @param manager the manager */
|
||||
public ToSWTConsoleForwardRunnable(final PipedConsoleOutput manager) {
|
||||
super(manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void forwardLine(final String m) {
|
||||
appendConsoleOutput(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRunning() {
|
||||
return running && !isDisposed();
|
||||
}
|
||||
|
||||
/** @param running the running to set */
|
||||
public void setRunning(final boolean running) {
|
||||
this.running = running;
|
||||
}
|
||||
}
|
||||
|
||||
/** The class logger */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(SWTConsoleView.class.getName());
|
||||
/** The console output text field */
|
||||
private final Text consoleOutput;
|
||||
/** The console input text field */
|
||||
private final Text consoleInput;
|
||||
/** The input. */
|
||||
private PipedConsoleInput input;
|
||||
/** The forwarding runnable */
|
||||
private ToSWTConsoleForwardRunnable forward;
|
||||
|
||||
/** Create the composite.
|
||||
*
|
||||
* @param parent the prent composite
|
||||
* @param style the composite style */
|
||||
public SWTConsoleView(final Composite parent, final int style) {
|
||||
super(parent, style);
|
||||
|
||||
setLayout(new GridLayout(1, 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,
|
||||
1, 1));
|
||||
consoleOutput.setRedraw(true);
|
||||
|
||||
consoleInput = new Text(this, SWT.BORDER);
|
||||
consoleInput.setLayoutData(
|
||||
new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
|
||||
consoleInput.addKeyListener(new HistoryTextKeyListener(this));
|
||||
}
|
||||
|
||||
/** @param next the next message */
|
||||
protected void appendConsoleOutput(final String next) {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
consoleOutput.append(System.lineSeparator() + next);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkSubclass() {
|
||||
// Disable the check that prevents subclassing of SWT components
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.swt.ConsoleDelayIO#getInput() */
|
||||
@Override
|
||||
public String getInput() {
|
||||
return consoleInput.getText();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.swt.widgets.Composite#setFocus() */
|
||||
@Override
|
||||
public boolean setFocus() {
|
||||
return consoleInput.setFocus();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.swt.ConsoleDelayIO#setInput(java.lang.String) */
|
||||
@Override
|
||||
public void setInput(final String input) {
|
||||
consoleInput.setText(input);
|
||||
consoleInput.setSelection(input.length());
|
||||
}
|
||||
|
||||
/** Set the input and output.
|
||||
*
|
||||
* @param manager the output to set
|
||||
* @param input the input */
|
||||
public void setManager(final PipedConsoleOutput manager,
|
||||
final PipedConsoleInput input) {
|
||||
this.input = input;
|
||||
if (forward != null) {
|
||||
forward.setRunning(false);
|
||||
}
|
||||
forward = new ToSWTConsoleForwardRunnable(manager);
|
||||
final Thread th = new Thread(forward, "gclcToSWT"); //$NON-NLS-1$
|
||||
th.start();
|
||||
}
|
||||
|
||||
/** @param string the text */
|
||||
public void setText(final String string) {
|
||||
consoleInput.setText(string);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void validateInput() {
|
||||
try {
|
||||
input.type(getInput());
|
||||
} catch (final IOException e) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to input value to console", e); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
}
|
||||
39
gclc-swt/src/main/java/fr/bigeon/gclc/swt/package-info.java
Normal file
39
gclc-swt/src/main/java/fr/bigeon/gclc/swt/package-info.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* GCLC swt, provide a swt window for console applications
|
||||
* Copyright (C) 2015-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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-swt:fr.bigeon.gclc.swt.package-info.java
|
||||
* Created on: Nov 18, 2017
|
||||
*/
|
||||
/** SWT components for a frontend of GCLC applications.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
package fr.bigeon.gclc.swt;
|
||||
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2015)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* provide a swt window for console applications.
|
||||
* GCLC swt, provide a swt window for console applications
|
||||
* Copyright (C) 2015-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
@@ -34,24 +31,78 @@
|
||||
*/
|
||||
/**
|
||||
* gclc-swt:fr.bigeon.gclc.swt.HistoryTextKeyListenerTest.java
|
||||
* Created on: Jun 9, 2016
|
||||
* Created on: Nov 19, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.swt;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
/** <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon
|
||||
*
|
||||
*/
|
||||
* @author Emmanuel Bigeon */
|
||||
public class HistoryTextKeyListenerTest {
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.swt.HistoryTextKeyListener#keyPressed(org.eclipse.swt.events.KeyEvent)}. */
|
||||
@Test
|
||||
public void test() {
|
||||
public final void testKeyPressedKeyEvent() {
|
||||
ConsoleDelayIO io = new ConsoleDelayIO() {
|
||||
private String input = "";
|
||||
|
||||
@Override
|
||||
public void validateInput() {
|
||||
input = "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInput(String input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInput() {
|
||||
return input;
|
||||
}
|
||||
};
|
||||
HistoryTextKeyListener listener = new HistoryTextKeyListener(io);
|
||||
|
||||
// no effects
|
||||
assertEquals("", io.getInput());
|
||||
listener.pressedKeyCode(SWT.ARROW_UP);
|
||||
assertEquals("", io.getInput());
|
||||
listener.pressedKeyCode(SWT.ARROW_DOWN);
|
||||
assertEquals("", io.getInput());
|
||||
listener.pressedKeyCode('\r');
|
||||
assertEquals("", io.getInput());
|
||||
|
||||
io.setInput("cmd arg");
|
||||
listener.pressedKeyCode(SWT.ARROW_UP);
|
||||
assertEquals("cmd arg", io.getInput());
|
||||
listener.pressedKeyCode(SWT.ARROW_DOWN);
|
||||
assertEquals("cmd arg", io.getInput());
|
||||
listener.pressedKeyCode('\r');
|
||||
assertEquals("", io.getInput());
|
||||
|
||||
io.setInput("cmd arg2");
|
||||
listener.pressedKeyCode(SWT.ARROW_UP);
|
||||
assertEquals("cmd arg", io.getInput());
|
||||
listener.pressedKeyCode(SWT.ARROW_DOWN);
|
||||
assertEquals("", io.getInput());
|
||||
io.setInput("cmd arg2");
|
||||
listener.pressedKeyCode('\r');
|
||||
assertEquals("", io.getInput());
|
||||
listener.pressedKeyCode(SWT.ARROW_UP);
|
||||
assertEquals("cmd arg2", io.getInput());
|
||||
listener.pressedKeyCode(SWT.ARROW_UP);
|
||||
assertEquals("cmd arg", io.getInput());
|
||||
listener.pressedKeyCode(SWT.ARROW_UP);
|
||||
assertEquals("cmd arg", io.getInput());
|
||||
listener.pressedKeyCode(SWT.ARROW_DOWN);
|
||||
assertEquals("cmd arg2", io.getInput());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2015)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* provide a swt window for console applications.
|
||||
* GCLC swt, provide a swt window for console applications
|
||||
* Copyright (C) 2015-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
@@ -39,7 +36,9 @@
|
||||
package fr.bigeon.gclc.swt;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -48,76 +47,210 @@ import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.command.Command;
|
||||
import fr.bigeon.gclc.command.ExitCommand;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** <p>
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
@SuppressWarnings({"javadoc", "static-method", "nls", "deprecation"})
|
||||
public class SWTConsoleShellTest {
|
||||
|
||||
protected static final long TWO_SECONDS = 2000;
|
||||
private static final Display DISPLAY = new Display();
|
||||
private static final Display DISPLAY = Display.getDefault();
|
||||
|
||||
@Test
|
||||
public void testConsoleClose() {
|
||||
public void test() {
|
||||
final SWTConsoleShell shell = new SWTConsoleShell(DISPLAY);
|
||||
final SWTConsole swtConsole = (SWTConsole) shell.getManager();
|
||||
swtConsole.close();
|
||||
swtConsole.setPrompt(":");
|
||||
final SWTConsole swtConsole = shell.getManager();
|
||||
try {
|
||||
final ConsoleApplication appl = new ConsoleApplication(swtConsole,
|
||||
"exit", "Hello", "See you");
|
||||
swtConsole, "Hello", "See you");
|
||||
appl.add(new ExitCommand("exit", appl));
|
||||
appl.add(new Command("long") {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.
|
||||
* manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
try {
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "a long running command";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
public void execute(String... args) {
|
||||
try {
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
appl.add(new Command("test") {
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "a prompting running command";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String... args) throws CommandRunException {
|
||||
try {
|
||||
appl.getManager().prompt("Test");
|
||||
} catch (IOException e) {
|
||||
throw new CommandRunException("No input", e);
|
||||
}
|
||||
protected String usageDetail() {
|
||||
// TODO Auto-generated method stub
|
||||
// return null;
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
});
|
||||
// shell.pack();
|
||||
shell.open();
|
||||
Thread applThread = new Thread(new Runnable() {
|
||||
final Thread applThread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
appl.start();
|
||||
}
|
||||
});
|
||||
Thread testThread = new Thread(new Runnable() {
|
||||
final Thread testThread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
swtConsole.setText("test"); //$NON-NLS-1$
|
||||
swtConsole.validateCommand();
|
||||
}
|
||||
});
|
||||
try {
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
shell.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
applThread.start();
|
||||
testThread.start();
|
||||
while (!shell.isDisposed()) {
|
||||
if (!DISPLAY.readAndDispatch()) {
|
||||
DISPLAY.sleep();
|
||||
}
|
||||
}
|
||||
// DISPLAY.dispose();
|
||||
assertTrue(swtConsole.isClosed());
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
assertFalse(appl.isRunning());
|
||||
} catch (final InvalidCommandName e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConsoleClose() {
|
||||
final SWTConsoleShell shell = new SWTConsoleShell(DISPLAY);
|
||||
final SWTConsole swtConsole = shell.getManager();
|
||||
swtConsole.close();
|
||||
swtConsole.setPrompt(":");
|
||||
try {
|
||||
final ConsoleApplication appl = new ConsoleApplication(swtConsole,
|
||||
swtConsole, "Hello", "See you");
|
||||
appl.add(new ExitCommand("exit", appl));
|
||||
appl.add(new Command("long") {
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.
|
||||
* manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
try {
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "a long running command";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
// TODO Auto-generated method stub
|
||||
// return null;
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
});
|
||||
appl.add(new Command("test") {
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.
|
||||
* manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
try {
|
||||
swtConsole.prompt("Test");
|
||||
} catch (final IOException e) {
|
||||
throw new CommandRunException("No input", e, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "a prompting running command";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
// TODO Auto-generated method stub
|
||||
// return null;
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
});
|
||||
// shell.pack();
|
||||
shell.open();
|
||||
final Thread applThread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
appl.start();
|
||||
}
|
||||
});
|
||||
final Thread testThread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -158,7 +291,7 @@ public class SWTConsoleShellTest {
|
||||
swtConsole.validateCommand();
|
||||
try {
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -168,6 +301,7 @@ public class SWTConsoleShellTest {
|
||||
shell.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
applThread.start();
|
||||
@@ -177,98 +311,21 @@ public class SWTConsoleShellTest {
|
||||
DISPLAY.sleep();
|
||||
}
|
||||
}
|
||||
// DISPLAY.dispose();
|
||||
assertTrue(appl.getManager().isClosed());
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
assertFalse(appl.isRunning());
|
||||
} catch (InvalidCommandName e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
final SWTConsoleShell shell = new SWTConsoleShell(DISPLAY);
|
||||
final SWTConsole swtConsole = (SWTConsole) shell.getManager();
|
||||
try {
|
||||
final ConsoleApplication appl = new ConsoleApplication(swtConsole,
|
||||
"exit", "Hello", "See you");
|
||||
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();
|
||||
}
|
||||
}
|
||||
});
|
||||
// shell.pack();
|
||||
shell.open();
|
||||
Thread applThread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
appl.start();
|
||||
}
|
||||
});
|
||||
Thread testThread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
swtConsole.setText("test"); //$NON-NLS-1$
|
||||
swtConsole.validateCommand();
|
||||
}
|
||||
});
|
||||
try {
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
shell.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
applThread.start();
|
||||
testThread.start();
|
||||
while (!shell.isDisposed()) {
|
||||
if (!DISPLAY.readAndDispatch()) {
|
||||
DISPLAY.sleep();
|
||||
}
|
||||
swtConsole.setPrompt(">");
|
||||
try {
|
||||
swtConsole.prompt();
|
||||
fail("Prompting when closed should fail!");
|
||||
} catch (final IOException e) {
|
||||
assertNotNull(e);
|
||||
}
|
||||
// DISPLAY.dispose();
|
||||
assertTrue(appl.getManager().isClosed());
|
||||
assertTrue(swtConsole.isClosed());
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
assertFalse(appl.isRunning());
|
||||
} catch (InvalidCommandName e) {
|
||||
} catch (final InvalidCommandName e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (InterruptedException e) {
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* GCLC swt, provide a swt window for console applications
|
||||
* Copyright (C) 2015-2017 E. Bigeon
|
||||
* mailto:emmanuel@bigeon.fr
|
||||
*
|
||||
* 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-swt:fr.bigeon.gclc.swt.SWTConsoleShellTest.java
|
||||
* Created on: Jun 8, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.swt;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.command.Command;
|
||||
import fr.bigeon.gclc.command.ExitCommand;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleInput;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||
|
||||
/** <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
@SuppressWarnings({"javadoc", "static-method", "nls", "deprecation"})
|
||||
public class SWTConsoleViewTest {
|
||||
|
||||
protected static final long TWO_SECONDS = 2000;
|
||||
private static final Display DISPLAY = Display.getDefault();
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
final Shell shell = new Shell(DISPLAY);
|
||||
final SWTConsoleView swtConsole = new SWTConsoleView(shell, SWT.NONE);
|
||||
try (PipedConsoleOutput manager = new PipedConsoleOutput();
|
||||
PipedConsoleInput input = new PipedConsoleInput(System.out)) {
|
||||
swtConsole.setManager(manager, input);
|
||||
} catch (final IOException e2) {
|
||||
assertNull(e2);
|
||||
}
|
||||
try (PipedConsoleOutput manager = new PipedConsoleOutput();
|
||||
PipedConsoleInput input = new PipedConsoleInput(System.out)) {
|
||||
swtConsole.setManager(manager, input);
|
||||
final ConsoleApplication appl = new ConsoleApplication(manager,
|
||||
input,
|
||||
"Hello", "See you");
|
||||
appl.add(new ExitCommand("exit", appl));
|
||||
appl.add(new Command("long") {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput, java.lang.String[])
|
||||
*/
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
try {
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "a long running command";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
// TODO Auto-generated method stub
|
||||
// return null;
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
});
|
||||
// shell.pack();
|
||||
shell.open();
|
||||
final Thread applThread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
appl.start();
|
||||
}
|
||||
});
|
||||
final Thread testThread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
swtConsole.setText("test"); //$NON-NLS-1$
|
||||
swtConsole.validateInput();
|
||||
}
|
||||
});
|
||||
try {
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
shell.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
applThread.start();
|
||||
testThread.start();
|
||||
while (!shell.isDisposed()) {
|
||||
if (!DISPLAY.readAndDispatch()) {
|
||||
DISPLAY.sleep();
|
||||
}
|
||||
}
|
||||
} catch (final InvalidCommandName e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (final IOException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
4
gclc.system/.gitignore
vendored
Normal file
4
gclc.system/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/target/
|
||||
/.classpath
|
||||
/.project
|
||||
/.settings/
|
||||
41
gclc.system/pom.xml
Normal file
41
gclc.system/pom.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>net.bigeon</groupId>
|
||||
<artifactId>gclc.system</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<url>http://www.bigeon.net</url>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>fr.bigeon</groupId>
|
||||
<artifactId>gclc</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<name>GCLC system command</name>
|
||||
<description>Provide an exec command to execute system commands</description>
|
||||
<inceptionYear>2016</inceptionYear>
|
||||
<scm>
|
||||
<developerConnection>scm:git:gogs@git.code.bigeon.net:emmanuel/gclc.git</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
<parent>
|
||||
<groupId>fr.bigeon</groupId>
|
||||
<artifactId>ebigeon-config</artifactId>
|
||||
<version>1.7.1</version>
|
||||
</parent>
|
||||
</project>
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* gclc.system:net.bigeon.gclc.system.ExecSystemCommand.java
|
||||
* Created on: Jun 20, 2016
|
||||
*/
|
||||
package net.bigeon.gclc.system;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import fr.bigeon.gclc.command.Command;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** A command that will execute a system command.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class ExecSystemCommand extends Command {
|
||||
|
||||
/** The command default name */
|
||||
private static final String COMMAND_DEFAULT_NAME = "exec"; //$NON-NLS-1$
|
||||
/** The end of line separator */
|
||||
private static final String EOL = System.lineSeparator();
|
||||
/** The class logger */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(ExecSystemCommand.class.getName());
|
||||
|
||||
/***/
|
||||
public ExecSystemCommand() {
|
||||
super(COMMAND_DEFAULT_NAME);
|
||||
}
|
||||
|
||||
/** @param name the name of the command (the input from the manager that
|
||||
* should trigger this command) */
|
||||
public ExecSystemCommand(final String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.manager.
|
||||
* ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
Process proc;
|
||||
try {
|
||||
proc = Runtime.getRuntime().exec(args);
|
||||
} catch (final IOException e2) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to run process", e2); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
|
||||
final InputStream is = proc
|
||||
.getInputStream();
|
||||
final Thread th = new Thread(new Runnable() {
|
||||
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
readToEnd(out, is);
|
||||
is.close();
|
||||
} catch (final CommandRunException e) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Manager was closed in the meantime...", e); //$NON-NLS-1$
|
||||
} catch (final IOException e) {
|
||||
LOGGER.log(Level.WARNING, "Input stream was closed...", e); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
});
|
||||
th.start();
|
||||
in.setPrompt(""); //$NON-NLS-1$
|
||||
final OutputStream os = proc.getOutputStream();
|
||||
try (BufferedWriter writer = new BufferedWriter(
|
||||
new OutputStreamWriter(os))) {
|
||||
while (th.isAlive()) {
|
||||
String user;
|
||||
try {
|
||||
user = in.prompt();
|
||||
} catch (final IOException e) {
|
||||
throw new CommandRunException(
|
||||
CommandRunExceptionType.INTERACTION,
|
||||
"manager was closed", e, this); //$NON-NLS-1$
|
||||
}
|
||||
writer.write(user + EOL);
|
||||
}
|
||||
} catch (final IOException e1) {
|
||||
throw new CommandRunException(CommandRunExceptionType.INTERACTION,
|
||||
"manager was closed", e1, this); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
/** @param is the input stream
|
||||
* @throws CommandRunException if the manager was closed while writing the
|
||||
* stream */
|
||||
protected void readToEnd(final ConsoleOutput out,
|
||||
final InputStream is) throws CommandRunException {
|
||||
int c;
|
||||
try {
|
||||
while ((c = is.read()) != -1) {
|
||||
try {
|
||||
out.print(Character.valueOf((char) c).toString());
|
||||
} catch (final IOException e) {
|
||||
throw new CommandRunException(
|
||||
CommandRunExceptionType.INTERACTION,
|
||||
"manager was closed", e, this); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
LOGGER.log(Level.INFO, "input stream reading failed", e); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
||||
@Override
|
||||
public String tip() {
|
||||
return "Execute a system command"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return " The system command is a system dependend command like sh on linux or" + //$NON-NLS-1$
|
||||
System.lineSeparator() + "powershell on windows." + //$NON-NLS-1$
|
||||
System.lineSeparator() + System.lineSeparator() +
|
||||
" As an example if you give \"cat /etc/hostname\" as argument, on a linux" + //$NON-NLS-1$
|
||||
System.lineSeparator() +
|
||||
"system, you would get the computer name." + //$NON-NLS-1$
|
||||
System.lineSeparator();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usagePattern() */
|
||||
@Override
|
||||
protected String usagePattern() {
|
||||
return " CMD <system command>"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,11 @@
|
||||
## Version 1.2.6
|
||||
|
||||
* in script command failure report improved
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* command line reading now succeed to parse last argument if it is a string
|
||||
|
||||
## Version 1.1.0
|
||||
|
||||
* Parsing quoted string as one argument
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>gclc</artifactId>
|
||||
<version>1.2.3-SNAPSHOT</version>
|
||||
<version>2.0.2</version>
|
||||
<packaging>jar</packaging>
|
||||
<url>http://www.bigeon.fr/emmanuel</url>
|
||||
<properties>
|
||||
@@ -53,7 +53,7 @@
|
||||
<parent>
|
||||
<groupId>fr.bigeon</groupId>
|
||||
<artifactId>ebigeon-config</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.7.1</version>
|
||||
</parent>
|
||||
<build>
|
||||
<plugins>
|
||||
@@ -83,6 +83,6 @@
|
||||
<scm>
|
||||
|
||||
<developerConnection>scm:git:gogs@git.code.bigeon.net:emmanuel/gclc.git</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
<tag>gclc-2.0.2</tag>
|
||||
</scm>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.ApplicationAttachement.java
|
||||
* Created on: Apr 19, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc;
|
||||
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
|
||||
/** Represent a functionnality set that can be added to a console application.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public interface ApplicationAttachement {
|
||||
/** Attach this object to a console application.
|
||||
* <p>
|
||||
* The attaching usually consist in the addition of commands in the console
|
||||
* application. The attached command should be specific to the attachement
|
||||
* (typically, the generic help command or the script command should not be
|
||||
* added through this mechanism).
|
||||
*
|
||||
* @param application the application
|
||||
* @throws InvalidCommandName if a command name is invalid for the
|
||||
* application. */
|
||||
void attach(ConsoleApplication application) throws InvalidCommandName;
|
||||
}
|
||||
@@ -38,13 +38,12 @@
|
||||
*/
|
||||
package fr.bigeon.gclc;
|
||||
|
||||
/** <p>
|
||||
* Command Request Listeners are listeners that are notified before a command is
|
||||
* executed by the ConsoleApplication,
|
||||
/** Command Request Listeners are listeners that are notified before a command
|
||||
* is executed by the ConsoleApplication.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public interface CommandRequestListener {
|
||||
/** Indicates that the given command was requested to the application
|
||||
/** Indicates that the given command was requested to the application.
|
||||
*
|
||||
* @param command the command */
|
||||
void commandRequest(String command);
|
||||
|
||||
@@ -37,35 +37,36 @@
|
||||
package fr.bigeon.gclc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
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.ExitCommand;
|
||||
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.CommandRunExceptionType;
|
||||
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.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** <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")};
|
||||
* {@link ConsoleOutput} out = new {@link fr.bigeon.gclc.manager.StreamConsoleOutput StreamConsoleOutput}();
|
||||
* {@link ConsoleInput} in = new {@link fr.bigeon.gclc.manager.StreamConsoleInput StreamConsoleInput}();
|
||||
* {@link ConsoleApplication} app = new {@link ConsoleApplication}(out, in, "welcome", "see you latter")};
|
||||
* app.{@link ConsoleApplication#add(ICommand) add}("my_command", new {@link ICommand MyCommand()});
|
||||
* app.{@link ConsoleApplication#start start}();
|
||||
* app.{@link ConsoleApplication#start() start()};
|
||||
* </pre>
|
||||
* <p>
|
||||
* That will launch in the console application that will display "welcome",
|
||||
@@ -74,191 +75,187 @@ import fr.bigeon.gclc.manager.SystemConsoleManager;
|
||||
* start method.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class ConsoleApplication implements ICommandProvider {
|
||||
public final class ConsoleApplication implements ICommandProvider {
|
||||
|
||||
/** The class logger */
|
||||
/** The class logger. */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(ConsoleApplication.class.getName());
|
||||
/** The welcome message */
|
||||
private final String header;
|
||||
/** The good bye message */
|
||||
private final String footer;
|
||||
/** The console manager */
|
||||
protected final ConsoleManager manager;
|
||||
/** The container of commands */
|
||||
private final SubedCommand root;
|
||||
/** The state of this application */
|
||||
/** The welcome message. */
|
||||
public final String header;
|
||||
/** The good bye message. */
|
||||
public final String footer;
|
||||
/** The standard output for the application. */
|
||||
private final ConsoleOutput out;
|
||||
/** The standard input for the application. */
|
||||
private final ConsoleInput in;
|
||||
/** The container of commands. */
|
||||
public final SubedCommand root;
|
||||
/** The state of this application. */
|
||||
private boolean running;
|
||||
/** The listeners */
|
||||
/** The listeners. */
|
||||
private final List<CommandRequestListener> listeners = new ArrayList<>();
|
||||
|
||||
/** @param manager the manager
|
||||
/** Create a console application.
|
||||
*
|
||||
* @param out the output
|
||||
* @param in the input
|
||||
* @param welcome the welcoming message
|
||||
* @param goodbye the goodbye message */
|
||||
public ConsoleApplication(ConsoleManager manager, String welcome,
|
||||
String goodbye) {
|
||||
this.header = welcome;
|
||||
this.footer = goodbye;
|
||||
this.manager = manager;
|
||||
root = new SubedCommand(new String(), new UnrecognizedCommand(manager));
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
* @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
|
||||
* @throws InvalidCommandName if the exit command name is invalid
|
||||
* @deprecated since 1.2.0, use the {@link #add(ICommand)} method to add the
|
||||
* exit command */
|
||||
@Deprecated
|
||||
public ConsoleApplication(ConsoleManager manager, String exit,
|
||||
String welcome, String goodbye) throws InvalidCommandName {
|
||||
this(manager, welcome, goodbye);
|
||||
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
|
||||
* @throws InvalidCommandName if the exit command name is invalid
|
||||
* @deprecated since 1.2.0, use the {@link #add(ICommand)} method to add the
|
||||
* command and create this console using the
|
||||
* {@link #ConsoleApplication(ConsoleManager, String, String)}
|
||||
* method with a {@link SystemConsoleManager} as argument */
|
||||
@Deprecated
|
||||
public ConsoleApplication(String exit, String welcome,
|
||||
String goodbye) throws InvalidCommandName {
|
||||
this(new SystemConsoleManager(), welcome, goodbye);
|
||||
root.add(new ExitCommand(exit, this));
|
||||
public ConsoleApplication(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String welcome,
|
||||
final String goodbye) {
|
||||
header = welcome;
|
||||
footer = goodbye;
|
||||
this.in = in;
|
||||
this.out = out;
|
||||
root = new SubedCommand(""); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean add(ICommand cmd) throws InvalidCommandName {
|
||||
public boolean add(final ICommand cmd) throws InvalidCommandName {
|
||||
return root.add(cmd);
|
||||
}
|
||||
|
||||
/** Adds help command on the given key
|
||||
/** Add a listener for command requests.
|
||||
*
|
||||
* @param cmd the handle for help
|
||||
* @return if the help command was added
|
||||
* @throws InvalidCommandName if the help command was not valid
|
||||
* @deprecated since 1.2.0 use the {@link #add(ICommand)} with a
|
||||
* {@link HelpExecutor} instead */
|
||||
@Deprecated
|
||||
public final boolean addHelpCommand(String cmd) throws InvalidCommandName {
|
||||
return root.add(new HelpExecutor(cmd, manager, root));
|
||||
}
|
||||
|
||||
/** Add a command request listener.
|
||||
* <p>
|
||||
* A listener can listen several times to the same application.
|
||||
*
|
||||
* @param listener the listener to add. */
|
||||
public final void addListener(CommandRequestListener listener) {
|
||||
* @param listener the command listener */
|
||||
public void addListener(final CommandRequestListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* fr.bigeon.gclc.command.ICommandProvider#executeSub(java.lang.String,
|
||||
* @see fr.bigeon.gclc.command.ICommandProvider#executeSub(java.lang.String,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public final void executeSub(String command,
|
||||
String... args) throws CommandRunException {
|
||||
root.executeSub(command, args);
|
||||
public void executeSub(final ConsoleOutput output, final ConsoleInput input,
|
||||
final String command,
|
||||
final String... args) throws CommandRunException {
|
||||
root.executeSub(output, input, command, args);
|
||||
}
|
||||
|
||||
/** Exit this running application before next command prompt */
|
||||
public final void exit() {
|
||||
/** Signify to the application that no command should be inputed anymore. */
|
||||
public void exit() {
|
||||
LOGGER.fine("Request exiting application..."); //$NON-NLS-1$
|
||||
running = false;
|
||||
in.interruptPrompt();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommandProvider#get(java.lang.String) */
|
||||
@Override
|
||||
public final ICommand get(String command) {
|
||||
public ICommand get(final String command) {
|
||||
return root.get(command);
|
||||
}
|
||||
|
||||
/** @return the manager */
|
||||
public final ConsoleManager getManager() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
/** @param cmd the command to interpret
|
||||
* @throws IOException if the manager was closed */
|
||||
public final void interpretCommand(String cmd) throws IOException {
|
||||
/** Interpret a command line.
|
||||
* <p>
|
||||
* This method will split the command in its part and execute the command
|
||||
* with {@link #executeSub(ConsoleOutput, ConsoleInput, String, String...)}.
|
||||
*
|
||||
* @param cmd the command
|
||||
* @throws IOException if the command could not be parsed */
|
||||
public void interpretCommand(final String cmd) throws IOException {
|
||||
List<String> args;
|
||||
try {
|
||||
args = GCLCConstants.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$
|
||||
} catch (final CommandParsingException e1) {
|
||||
out.println("Command line cannot be parsed"); //$NON-NLS-1$
|
||||
LOGGER.log(Level.FINE, "Invalid user command " + cmd, e1); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
if (!args.isEmpty()) {
|
||||
try {
|
||||
executeSub(args.get(0), Arrays.copyOfRange(
|
||||
executeSub(out, in, 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
|
||||
LOGGER.log(Level.FINE, "Command failed: " + cmd, e); //$NON-NLS-1$
|
||||
out.println(Messages
|
||||
.getString("ConsoleApplication.cmd.failed", cmd)); //$NON-NLS-1$
|
||||
manager.println(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @param listener the listener to remove (once) */
|
||||
public final void removeListener(CommandRequestListener listener) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
if (listeners.get(i) == listener) {
|
||||
listeners.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Launches the prompting application */
|
||||
public final void start() {
|
||||
try {
|
||||
running = true;
|
||||
if (header != null) {
|
||||
manager.println(header);
|
||||
}
|
||||
do {
|
||||
final String cmd = manager.prompt();
|
||||
if (cmd == null || cmd.isEmpty()) {
|
||||
continue;
|
||||
out.println(e.getLocalizedMessage());
|
||||
if (e.getType() == CommandRunExceptionType.USAGE) {
|
||||
e.getSource().help(out);
|
||||
}
|
||||
for (final CommandRequestListener listener : listeners) {
|
||||
listener.commandRequest(cmd);
|
||||
}
|
||||
interpretCommand(cmd);
|
||||
} while (running);
|
||||
if (footer != null) {
|
||||
manager.println(footer);
|
||||
}
|
||||
LOGGER.fine("Exiting application."); //$NON-NLS-1$
|
||||
} catch (IOException e) {
|
||||
// The manager was closed
|
||||
running = false;
|
||||
LOGGER.log(Level.WARNING,
|
||||
"The console manager was closed. Closing the application as no one can reach it.", //$NON-NLS-1$
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
/** @return if the application is running */
|
||||
/** Test if the application is running.
|
||||
*
|
||||
* @return the running status */
|
||||
public boolean isRunning() {
|
||||
return running;
|
||||
}
|
||||
|
||||
/** @return the root */
|
||||
public SubedCommand getRoot() {
|
||||
return root;
|
||||
/** Remove a listener from this application.
|
||||
*
|
||||
* @param listener the command listener to remove */
|
||||
public void removeListener(final CommandRequestListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
/** The running loop content.
|
||||
* <p>
|
||||
* This consisting in getting the command, executing it and exiting
|
||||
* (restarting the loop). */
|
||||
private void runLoop() {
|
||||
try {
|
||||
final String cmd = in.prompt();
|
||||
if (cmd == null || cmd.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (final CommandRequestListener listener : listeners) {
|
||||
listener.commandRequest(cmd);
|
||||
}
|
||||
interpretCommand(cmd);
|
||||
} catch (final InterruptedIOException e) {
|
||||
LOGGER.info(
|
||||
"Prompt interrupted. It is likely the application is closing."); //$NON-NLS-1$
|
||||
LOGGER.log(Level.FINER, "Interruption of the prompt.", //$NON-NLS-1$
|
||||
e);
|
||||
} catch (final IOException e) {
|
||||
// The manager was closed
|
||||
running = false;
|
||||
LOGGER.warning(
|
||||
"The console manager was closed. Closing the application as no one can reach it."); //$NON-NLS-1$
|
||||
LOGGER.log(Level.FINE,
|
||||
"An exception caused the closing of the application", //$NON-NLS-1$
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Start the application. */
|
||||
public void start() {
|
||||
try {
|
||||
running = true;
|
||||
if (header != null) {
|
||||
out.println(header);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
// The manager was closed
|
||||
running = false;
|
||||
LOGGER.warning(
|
||||
"The console manager was closed. Closing the application as no one can reach it."); //$NON-NLS-1$
|
||||
LOGGER.log(Level.FINE,
|
||||
"An exception caused the closing of the application", //$NON-NLS-1$
|
||||
e);
|
||||
return;
|
||||
}
|
||||
do {
|
||||
runLoop();
|
||||
} while (running);
|
||||
if (footer != null) {
|
||||
try {
|
||||
out.println(footer);
|
||||
} catch (final IOException e) {
|
||||
// The manager was closed
|
||||
running = false;
|
||||
LOGGER.warning("Console manager alreaady closed."); //$NON-NLS-1$
|
||||
LOGGER.log(Level.FINE,
|
||||
"Exception raised by goodbye message printing... Application will still close.", //$NON-NLS-1$
|
||||
e);
|
||||
}
|
||||
}
|
||||
running = false;
|
||||
LOGGER.fine("Exiting application."); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,27 +49,62 @@ import fr.bigeon.gclc.exception.CommandParsingException;
|
||||
* arguments.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class GCLCConstants {
|
||||
public final class GCLCConstants {
|
||||
|
||||
/** The escaping character */
|
||||
/** The escaping character. */
|
||||
private static final char ESCAPING_CHAR = getSystemEscapingChar();
|
||||
|
||||
/** Hide utility class constructor */
|
||||
/** Hide utility class constructor. */
|
||||
private GCLCConstants() {
|
||||
// utility class
|
||||
}
|
||||
|
||||
/** @return the escaping character */
|
||||
/** Get the end of a string argument.
|
||||
*
|
||||
* @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(final String cmd, final int startIndex,
|
||||
final int index) throws CommandParsingException {
|
||||
if (index < cmd.length() && cmd.charAt(index) != ' ') {
|
||||
throw new CommandParsingException("Misplaced quote"); //$NON-NLS-1$
|
||||
}
|
||||
return cmd.substring(startIndex + 1, index - 1);
|
||||
}
|
||||
|
||||
/** Get the excaping character.
|
||||
*
|
||||
* @return the escaping character */
|
||||
private static char getSystemEscapingChar() {
|
||||
return '\\';
|
||||
}
|
||||
|
||||
/** Splits a command in the diferrent arguments
|
||||
*
|
||||
/** Remove escaping characters from the string.
|
||||
*
|
||||
* @param arg the string to remove excaping character from
|
||||
* @return the string without escape character */
|
||||
private static String removeEscaped(final String arg) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
int index = 0;
|
||||
int endIndex = arg.indexOf(ESCAPING_CHAR);
|
||||
while (endIndex != -1) {
|
||||
builder.append(arg.subSequence(index, endIndex));
|
||||
index = endIndex + 1;
|
||||
endIndex = arg.indexOf(ESCAPING_CHAR, index + 1);
|
||||
}
|
||||
builder.append(arg.substring(index));
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/** 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 */
|
||||
public static List<String> splitCommand(String cmd) throws CommandParsingException {
|
||||
public static List<String> splitCommand(final String cmd) throws CommandParsingException {
|
||||
final List<String> args = new ArrayList<>();
|
||||
// parse the string to separate arguments
|
||||
int index = 0;
|
||||
@@ -77,7 +112,7 @@ public class GCLCConstants {
|
||||
boolean escaped = false;
|
||||
boolean inString = false;
|
||||
while (index < cmd.length()) {
|
||||
char c = cmd.charAt(index);
|
||||
final char c = cmd.charAt(index);
|
||||
index++;
|
||||
if (escaped || c == ESCAPING_CHAR) {
|
||||
escaped = !escaped;
|
||||
@@ -98,40 +133,11 @@ public class GCLCConstants {
|
||||
inString = startIndex == index - 1;
|
||||
}
|
||||
}
|
||||
final String arg = cmd.substring(startIndex, cmd.length());
|
||||
if (!arg.isEmpty()) {
|
||||
if (startIndex < cmd.length()) {
|
||||
final String arg = cmd.substring(startIndex, cmd.length());
|
||||
args.add(arg);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
/** @param arg the string to remove excaping character from
|
||||
* @return the string without escape character */
|
||||
private static String removeEscaped(String arg) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int index = 0;
|
||||
int endIndex = arg.indexOf(ESCAPING_CHAR);
|
||||
while (endIndex != -1) {
|
||||
builder.append(arg.subSequence(index, endIndex));
|
||||
index = endIndex + 1;
|
||||
endIndex = arg.indexOf(ESCAPING_CHAR, index + 1);
|
||||
}
|
||||
builder.append(arg.substring(index));
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/** @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 < cmd.length() && cmd.charAt(index) != ' ') {
|
||||
throw new CommandParsingException("Misplaced quote"); //$NON-NLS-1$
|
||||
}
|
||||
return cmd.substring(startIndex + 1, index - 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,11 +40,12 @@ package fr.bigeon.gclc.command;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** <p>
|
||||
* A command to execute. It is mandatory that it has a name and that name cannot
|
||||
* start with minus character or contain spaces.
|
||||
/** A command to execute.
|
||||
* <p>
|
||||
* It is mandatory that it has a name and that name cannot start with minus
|
||||
* character or contain spaces.
|
||||
* <p>
|
||||
* A command can be executed, with parameters that will be provided as an array
|
||||
* of strings.
|
||||
@@ -65,20 +66,26 @@ import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
* @author Emmanuel BIGEON */
|
||||
public abstract class Command implements ICommand {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/** The linux end of line character. */
|
||||
private static final String EOL_LINUX = "\n"; //$NON-NLS-1$
|
||||
/** The name of the command */
|
||||
/** The name of the command. */
|
||||
protected final String name;
|
||||
|
||||
/** @param name the command name */
|
||||
public Command(String name) {
|
||||
/** Create the command.
|
||||
*
|
||||
* @param name the command name */
|
||||
public Command(final String name) {
|
||||
super();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/** @return a brief description of the command */
|
||||
/** Get the brief part of the command help.
|
||||
* <p>
|
||||
* This method may be overriden by implementations to improve the help
|
||||
* content. The default behavior is to print the tip.
|
||||
*
|
||||
* @return a brief description of the command
|
||||
* @see Command#help(ConsoleOutput, String...) */
|
||||
protected String brief() {
|
||||
return " " + tip(); //$NON-NLS-1$
|
||||
}
|
||||
@@ -90,12 +97,24 @@ public abstract class Command implements ICommand {
|
||||
return name;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#help(fr.bigeon.gclc.ConsoleManager,
|
||||
* java.lang.String) */
|
||||
/** Prints a help content for this command to the console output.
|
||||
* <p>
|
||||
* This help is following the given format:
|
||||
*
|
||||
* <pre>
|
||||
* [Command name]
|
||||
* [brief message]
|
||||
*
|
||||
* Usage:
|
||||
* [Usage pattern]
|
||||
*
|
||||
* [Usage details]
|
||||
* </pre>
|
||||
*
|
||||
* @see fr.bigeon.gclc.command.ICommand#help(ConsoleOutput, String...) */
|
||||
@Override
|
||||
public final void help(ConsoleManager manager,
|
||||
String... args) throws IOException {
|
||||
public final void help(final ConsoleOutput manager,
|
||||
final String... args) throws IOException {
|
||||
manager.println(getCommandName());
|
||||
manager.println(brief());
|
||||
manager.println();
|
||||
@@ -112,19 +131,16 @@ public abstract class Command implements ICommand {
|
||||
}
|
||||
}
|
||||
|
||||
/** <p>
|
||||
* This method return the detail of the help. It immediatly follows the
|
||||
* {@link #usagePattern() usage pattern}.
|
||||
/** This method return the detail of the help.
|
||||
* <p>
|
||||
* 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() {
|
||||
return new String();
|
||||
}
|
||||
protected abstract String usageDetail();
|
||||
|
||||
/** <p>
|
||||
* This prints the usage pattern for the command. It follows the brief
|
||||
* introduction on the command ({@link #brief()})
|
||||
/** This prints the usage pattern for the command.
|
||||
* <p>
|
||||
* It follows the brief introduction on the command ({@link #brief()})
|
||||
*
|
||||
* @return the usage pattern */
|
||||
protected String usagePattern() {
|
||||
|
||||
@@ -45,95 +45,106 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** <p>
|
||||
* An object representing a collection of parameters. It is used for defaulting
|
||||
* values.
|
||||
import fr.bigeon.gclc.exception.CommandParsingException;
|
||||
|
||||
/** An object representing a collection of parameters.
|
||||
* <p>
|
||||
* It is used for defaulting values.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class CommandParameters {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final class CommandParameters {
|
||||
/** Number of element for a string argument. */
|
||||
private static final int STRINGARG_NUMBER_OF_ELEMENTS = 2;
|
||||
/** Boolean arguments */
|
||||
private final Map<String, Boolean> boolArgs = new HashMap<>();
|
||||
/** String arguments */
|
||||
private final Map<String, String> stringArgs = new HashMap<>();
|
||||
/** Arguments restriction on the named ones */
|
||||
/** Boolean arguments. */
|
||||
private final Map<String, Boolean> booleanArguments = new HashMap<>();
|
||||
/** String arguments. */
|
||||
private final Map<String, String> stringArguments = new HashMap<>();
|
||||
/** Arguments restriction on the named ones. */
|
||||
private final boolean strict;
|
||||
/** additional (unnamed) parameters */
|
||||
/** additional (unnamed) parameters. */
|
||||
private final List<String> additional = new ArrayList<>();
|
||||
|
||||
/** @param bools the boolean parameters
|
||||
/** Create a command parameter object.
|
||||
*
|
||||
* @param bools the boolean parameters
|
||||
* @param strings the string parameters
|
||||
* @param strict if the argument are restricted to the declared ones */
|
||||
@SuppressWarnings("boxing")
|
||||
public CommandParameters(Set<String> bools, Set<String> strings,
|
||||
boolean strict) {
|
||||
public CommandParameters(final Set<String> bools, final Set<String> strings,
|
||||
final boolean strict) {
|
||||
for (final String string : bools) {
|
||||
boolArgs.put(string, false);
|
||||
booleanArguments.put(string, Boolean.FALSE);
|
||||
}
|
||||
for (final String string : strings) {
|
||||
stringArgs.put(string, null);
|
||||
stringArguments.put(string, null);
|
||||
}
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
/** @param key the key
|
||||
/** Get the value of a string argument.
|
||||
*
|
||||
* @param key the key
|
||||
* @return the associated value, null if it was not specified */
|
||||
public String get(String key) {
|
||||
return stringArgs.get(key);
|
||||
public String get(final String key) {
|
||||
return stringArguments.get(key);
|
||||
}
|
||||
|
||||
/** @return additional non parsed parameters */
|
||||
/** Get the additional (unrecognized) arguments.
|
||||
*
|
||||
* @return additional non parsed parameters */
|
||||
public List<String> getAdditionals() {
|
||||
return Collections.unmodifiableList(additional);
|
||||
}
|
||||
|
||||
/** @param key the key
|
||||
/** Get the value of a boolean argument.
|
||||
*
|
||||
* @param key the key
|
||||
* @return if the key was specified */
|
||||
@SuppressWarnings("boxing")
|
||||
public boolean getBool(String key) {
|
||||
return boolArgs.get(key);
|
||||
public boolean getBool(final String key) {
|
||||
return booleanArguments.containsKey(key) &&
|
||||
booleanArguments.get(key).booleanValue();
|
||||
}
|
||||
|
||||
/** @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;
|
||||
/** Get the boolean arguments.
|
||||
*
|
||||
* @return the boolean arguments */
|
||||
public Set<String> getBooleanArgumentKeys() {
|
||||
return booleanArguments.keySet();
|
||||
}
|
||||
|
||||
/** Get the string arguments.
|
||||
*
|
||||
* @return the boolean arguments */
|
||||
public Set<String> getStringArgumentKeys() {
|
||||
return stringArguments.keySet();
|
||||
}
|
||||
|
||||
/** Test if an argument exists in this object.
|
||||
*
|
||||
* @param key the key
|
||||
* @return if the key is present in string arguments or boolean ones. */
|
||||
public boolean hasArgument(final String key) {
|
||||
return stringArguments.containsKey(key) ||
|
||||
booleanArguments.containsKey(key);
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
private int parseArg(final String arg, final String next) {
|
||||
if (!arg.startsWith("-")) { //$NON-NLS-1$
|
||||
return strict ? 0 : 1;
|
||||
}
|
||||
final String name = arg.substring(1);
|
||||
if (booleanArguments.containsKey(name)) {
|
||||
booleanArguments.put(name, Boolean.TRUE);
|
||||
return 1;
|
||||
}
|
||||
String name = arg.substring(1);
|
||||
if (boolArgs.containsKey(name)) {
|
||||
boolArgs.put(name, Boolean.TRUE);
|
||||
return 1;
|
||||
}
|
||||
if (stringArgs.containsKey(name)) {
|
||||
if (stringArguments.containsKey(name)) {
|
||||
return parseStringArg(name, next);
|
||||
}
|
||||
if (strict) {
|
||||
@@ -143,33 +154,57 @@ public class CommandParameters {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Add a string arg value
|
||||
*
|
||||
/** Parse arguments.
|
||||
*
|
||||
* @param args the arguments to parse
|
||||
* @throws CommandParsingException if the arguments parsing failed */
|
||||
public void parseArgs(final String... args) throws CommandParsingException {
|
||||
int i = 0;
|
||||
while (i < args.length) {
|
||||
String next = null;
|
||||
if (i < args.length - 1) {
|
||||
next = args[i + 1];
|
||||
}
|
||||
final int p = parseArg(args[i], next);
|
||||
if (p == 0) {
|
||||
throw new CommandParsingException(
|
||||
"Invalid parameter " + args[i]); //$NON-NLS-1$
|
||||
}
|
||||
i += p;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
private int parseStringArg(final String name, final String next) {
|
||||
if (next == null) {
|
||||
return 0;
|
||||
}
|
||||
stringArgs.put(name, next);
|
||||
stringArguments.put(name, next);
|
||||
return STRINGARG_NUMBER_OF_ELEMENTS;
|
||||
}
|
||||
|
||||
/** @param string the key
|
||||
/** Set a boolean parameter value.
|
||||
*
|
||||
* @param string the key
|
||||
* @param value the value */
|
||||
@SuppressWarnings("boxing")
|
||||
public void set(String string, boolean value) {
|
||||
if (boolArgs.containsKey(string)) {
|
||||
boolArgs.put(string, value);
|
||||
public void set(final String string, final boolean value) {
|
||||
if (booleanArguments.containsKey(string)) {
|
||||
booleanArguments.put(string, Boolean.valueOf(value));
|
||||
}
|
||||
}
|
||||
|
||||
/** @param string the key
|
||||
/** Set a string parameter value.
|
||||
*
|
||||
* @param string the key
|
||||
* @param value the value */
|
||||
public void set(String string, String value) {
|
||||
if (stringArgs.containsKey(string)) {
|
||||
stringArgs.put(string, value);
|
||||
public void set(final String string, final String value) {
|
||||
if (stringArguments.containsKey(string)) {
|
||||
stringArguments.put(string, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,60 +36,85 @@
|
||||
* Created on: Aug 6, 2014 */
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
import fr.bigeon.gclc.i18n.Messages;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** <p>
|
||||
* A command provider is a map of key word to command to execute
|
||||
/** A command provider is a map of key word to command to execute.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class CommandProvider implements ICommandProvider {
|
||||
/** The minus character */
|
||||
/** The minus character. */
|
||||
private static final String MINUS = "-"; //$NON-NLS-1$
|
||||
/** The space character */
|
||||
/** The space character. */
|
||||
private static final String SPACE = " "; //$NON-NLS-1$
|
||||
/** The commands map */
|
||||
protected final Set<ICommand> commands;
|
||||
/** The commands map. */
|
||||
protected final List<ICommand> commands;
|
||||
|
||||
/** Create a command provider */
|
||||
/** Create a command provider. */
|
||||
public CommandProvider() {
|
||||
super();
|
||||
commands = new HashSet<>();
|
||||
commands = new ArrayList<>();
|
||||
}
|
||||
|
||||
/** Test the command name validity.
|
||||
*
|
||||
* @param name the command name
|
||||
* @throws InvalidCommandName if the name is invalid */
|
||||
private static void testCommandName(final String name) throws InvalidCommandName {
|
||||
if (name == null || name.isEmpty() || name.startsWith(MINUS) ||
|
||||
name.contains(SPACE)) {
|
||||
throw new InvalidCommandName();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommandProvider#add(java.lang.String,
|
||||
* fr.bigeon.gclc.command.Command) */
|
||||
@Override
|
||||
public boolean add(ICommand value) throws InvalidCommandName {
|
||||
public final boolean add(final ICommand value) throws InvalidCommandName {
|
||||
final String name = value.getCommandName();
|
||||
if (name == null || name.startsWith(MINUS) || name.contains(SPACE)) {
|
||||
throw new InvalidCommandName();
|
||||
testCommandName(name);
|
||||
if (commands.contains(value)) {
|
||||
return true;
|
||||
}
|
||||
for (final ICommand iCommand : commands) {
|
||||
if (iCommand.getCommandName().equals(value.getCommandName())) {
|
||||
throw new InvalidCommandName(
|
||||
"Name already used: " + value.getCommandName()); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
return commands.add(value);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* fr.bigeon.gclc.command.ICommandProvider#executeSub(fr.bigeon.gclc.manager
|
||||
* .ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput, java.lang.String,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void executeSub(String cmd,
|
||||
String... args) throws CommandRunException {
|
||||
public final void executeSub(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String cmd,
|
||||
final String... args) throws CommandRunException {
|
||||
for (final ICommand command : commands) {
|
||||
if (command.getCommandName().equals(cmd)) {
|
||||
command.execute(args);
|
||||
command.execute(out, in, args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new CommandRunException(
|
||||
Messages.getString("CommandProvider.unrecognized", cmd)); //$NON-NLS-1$
|
||||
Messages.getString("CommandProvider.unrecognized", cmd), null); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommandProvider#get(java.lang.String) */
|
||||
@Override
|
||||
public ICommand get(String commandName) {
|
||||
public final ICommand get(final String commandName) {
|
||||
for (final ICommand command : commands) {
|
||||
if (command.getCommandName().equals(commandName)) {
|
||||
return command;
|
||||
|
||||
@@ -41,37 +41,42 @@ package fr.bigeon.gclc.command;
|
||||
import java.io.IOException;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
import fr.bigeon.gclc.prompt.CLIPrompterMessages;
|
||||
|
||||
/** <p>
|
||||
* A command to exit a {@link ConsoleApplication}.
|
||||
/** A command to exit a {@link ConsoleApplication}.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class ExitCommand implements ICommand {
|
||||
/** The exit command manual message key */
|
||||
/** The exit command manual message key. */
|
||||
private static final String EXIT_MAN = "exit.man"; //$NON-NLS-1$
|
||||
/** The tip of the exit command */
|
||||
/** 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 */
|
||||
/** The application that will be exited when this command runs. */
|
||||
private final ConsoleApplication app;
|
||||
/** The exit command name */
|
||||
/** The exit command name. */
|
||||
private final String name;
|
||||
|
||||
/** @param name the name of the command
|
||||
/** Create the exiting command.
|
||||
*
|
||||
* @param name the name of the command
|
||||
* @param app the application to exit */
|
||||
public ExitCommand(String name, ConsoleApplication app) {
|
||||
public ExitCommand(final String name, final ConsoleApplication app) {
|
||||
this.name = name;
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
/** The actions to take before exiting */
|
||||
public void beforeExit() {
|
||||
/** The actions to take before exiting.
|
||||
* <p>
|
||||
* This method is intended to be overriden by sub classes. */
|
||||
protected void beforeExit() {
|
||||
// Do nothing by default
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void execute(String... args) {
|
||||
public final void execute(final ConsoleOutput output,
|
||||
final ConsoleInput input, final String... args) {
|
||||
beforeExit();
|
||||
app.exit();
|
||||
}
|
||||
@@ -84,14 +89,13 @@ public class ExitCommand implements ICommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void help(ConsoleManager manager,
|
||||
String... args) throws IOException {
|
||||
public final void help(final ConsoleOutput manager,
|
||||
final String... args) throws IOException {
|
||||
manager.println(
|
||||
CLIPrompterMessages.getString(EXIT_MAN, (Object[]) args));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
public final String tip() {
|
||||
return CLIPrompterMessages.getString(EXIT);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,9 @@ package fr.bigeon.gclc.command;
|
||||
import java.io.IOException;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
import fr.bigeon.gclc.prompt.CLIPrompterMessages;
|
||||
|
||||
/** A command to print help of an other command.
|
||||
@@ -49,50 +51,43 @@ import fr.bigeon.gclc.prompt.CLIPrompterMessages;
|
||||
* This command will display the help of an other command
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class HelpExecutor extends Command {
|
||||
public final class HelpExecutor extends Command {
|
||||
|
||||
/** The command to execute the help of */
|
||||
/** The command to execute the help of. */
|
||||
private final ICommand cmd;
|
||||
/** The console manager */
|
||||
private final ConsoleManager consoleManager;
|
||||
|
||||
/** @param cmdName the command name
|
||||
* @param consoleManager the manager for the console
|
||||
/** Create the help command.
|
||||
*
|
||||
* @param cmdName the command name
|
||||
* @param cmd the command to execute the help of */
|
||||
public HelpExecutor(String cmdName, ConsoleManager consoleManager,
|
||||
ICommand cmd) {
|
||||
public HelpExecutor(final String cmdName,
|
||||
final ICommand cmd) {
|
||||
super(cmdName);
|
||||
this.cmd = cmd;
|
||||
if (consoleManager == null) {
|
||||
throw new NullPointerException(
|
||||
"Argument cannot be null: ConsoleManager"); //$NON-NLS-1$
|
||||
}
|
||||
this.consoleManager = consoleManager;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#execute(java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(String... args) throws CommandRunException {
|
||||
try {
|
||||
cmd.help(consoleManager, args);
|
||||
} catch (IOException e) {
|
||||
throw new CommandRunException("Console manager closed", e); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#brief() */
|
||||
@Override
|
||||
protected String brief() {
|
||||
return " A command to get help for other commands"; //$NON-NLS-1$
|
||||
if (cmd instanceof SubedCommand) {
|
||||
return " A command to get help for other commands"; //$NON-NLS-1$
|
||||
}
|
||||
return " A command to retrieve help for " + cmd.getCommandName(); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usagePattern() */
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(ConsoleOutput, ConsoleInput,
|
||||
* String[]) */
|
||||
@Override
|
||||
protected String usagePattern() {
|
||||
return getCommandName() + " <otherCommand>"; //$NON-NLS-1$
|
||||
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
try {
|
||||
cmd.help(out, args);
|
||||
} catch (final IOException e) {
|
||||
throw new CommandRunException(CommandRunExceptionType.INTERACTION,
|
||||
"Console manager closed", e, this); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -101,4 +96,22 @@ public class HelpExecutor extends Command {
|
||||
public String tip() {
|
||||
return CLIPrompterMessages.getString("help.cmd.tip"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail()
|
||||
*/
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usagePattern() */
|
||||
@Override
|
||||
protected String usagePattern() {
|
||||
if (cmd instanceof SubedCommand) {
|
||||
return getCommandName() + " <otherCommand>"; //$NON-NLS-1$
|
||||
}
|
||||
return getCommandName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,43 +41,40 @@ package fr.bigeon.gclc.command;
|
||||
import java.io.IOException;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** The contract of commands
|
||||
/** 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)
|
||||
* @throws CommandRunException if the execution of the command failed for
|
||||
* any reason */
|
||||
void execute(String... args) throws CommandRunException;
|
||||
/** Execute the command on the given output and input.
|
||||
*
|
||||
* @param out the normal output
|
||||
* @param in the input
|
||||
* @param args the arguments
|
||||
* @throws CommandRunException if the command failed */
|
||||
void execute(ConsoleOutput out, ConsoleInput in,
|
||||
String... args) throws CommandRunException;
|
||||
|
||||
/** @return the command's name */
|
||||
/** Get teh command name.
|
||||
*
|
||||
* @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 output the output to print the data
|
||||
* @param args the arguments called with the help
|
||||
* @throws IOException if the manager was closed */
|
||||
void help(ConsoleManager manager, String... args) throws IOException;
|
||||
void help(ConsoleOutput output, String... args) throws IOException;
|
||||
|
||||
/** @return a tip on the command */
|
||||
/** Get a tip (brief helping message) for the command.
|
||||
*
|
||||
* @return a tip on the command */
|
||||
String tip();
|
||||
|
||||
}
|
||||
@@ -38,45 +38,47 @@ package fr.bigeon.gclc.command;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** <p>
|
||||
* An ICommadProvider is a provider of commands that can register commands under
|
||||
* some keywords.
|
||||
/** An ICommadProvider is a provider of commands that can register commands
|
||||
* under some keywords.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public interface ICommandProvider {
|
||||
|
||||
/** <p>
|
||||
* Adds a command to this provider, if no command was associated with the
|
||||
* given key
|
||||
/** 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(ICommand value) throws InvalidCommandName;
|
||||
boolean add(ICommand value) throws InvalidCommandName;
|
||||
|
||||
/** <p>
|
||||
* This method executes the command with the given name found. If no command
|
||||
* with this name is found, an error command is usually executed. If there
|
||||
* 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.
|
||||
/** Execute the command with the given name.
|
||||
* <p>
|
||||
* If no command with this name is found, an error command is usually
|
||||
* executed. If there 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 out the output
|
||||
* @param in the input
|
||||
* @param command the name of the command the user wishes to execute
|
||||
* @param args the arguments for the command
|
||||
* @throws CommandRunException if the command failed to run */
|
||||
public void executeSub(String command,
|
||||
String... args) throws CommandRunException;
|
||||
void executeSub(ConsoleOutput out, ConsoleInput in, String command,
|
||||
String... args) throws CommandRunException;
|
||||
|
||||
/** <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.
|
||||
/** Get the command with the given name.
|
||||
* <p>
|
||||
* 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);
|
||||
ICommand get(String command);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,68 +33,61 @@
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
/**
|
||||
* gclc:fr.bigeon.gclc.UnrecognizedCommand.java
|
||||
* Created on: Dec 23, 2014
|
||||
* gclc:fr.bigeon.gclc.command.MockCommand.java
|
||||
* Created on: Nov 18, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import java.io.IOException;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.prompt.CLIPrompterMessages;
|
||||
|
||||
/** <p>
|
||||
* The error message for unrecognized commands
|
||||
/** This implement a command that does nothing.
|
||||
* <p>
|
||||
* This class is intended for testing purpose only.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
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 */
|
||||
private static final String EXPECTED_CMD = "expected.cmd"; //$NON-NLS-1$
|
||||
/** The manager */
|
||||
private final ConsoleManager manager;
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class MockCommand implements ICommand {
|
||||
|
||||
/** @param manager the console manager to use */
|
||||
public UnrecognizedCommand(ConsoleManager manager) {
|
||||
if (manager == null) {
|
||||
throw new NullPointerException("The argument cannot be null"); //$NON-NLS-1$
|
||||
}
|
||||
this.manager = manager;
|
||||
/** The command name. */
|
||||
private final String name;
|
||||
|
||||
/** Create the command.
|
||||
*
|
||||
* @param name the command name */
|
||||
public MockCommand(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(ConsoleOutput, ConsoleInput,
|
||||
* String[]) */
|
||||
@Override
|
||||
public void execute(String... args) throws CommandRunException {
|
||||
|
||||
try {
|
||||
if (args.length > 0) {
|
||||
manager.println(CLIPrompterMessages.getString(UNRECOGNIZED_CMD,
|
||||
(Object[]) args));
|
||||
} else {
|
||||
manager.println(CLIPrompterMessages.getString(EXPECTED_CMD));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new CommandRunException("Manager closed", e); //$NON-NLS-1$
|
||||
}
|
||||
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String... args) {
|
||||
//
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#getCommandName() */
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return ""; //$NON-NLS-1$
|
||||
return name;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#help(fr.bigeon.gclc.manager.
|
||||
* ConsoleManager, java.lang.String[]) */
|
||||
@Override
|
||||
public void help(@SuppressWarnings("hiding") ConsoleManager manager,
|
||||
String... args) {
|
||||
// Nothing to do (no help provided as this is not a user command
|
||||
// (usually)
|
||||
public void help(final ConsoleOutput manager,
|
||||
final String... args) {
|
||||
//
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,122 +39,218 @@
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandParsingException;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||
import fr.bigeon.gclc.exception.InvalidParameterException;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
import fr.bigeon.gclc.manager.EmptyInput;
|
||||
|
||||
/** <p>
|
||||
* A command relying on the {@link CommandParameters} to store parameters values
|
||||
/** A command relying on the {@link CommandParameters} to store parameters
|
||||
* values.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public abstract class ParametrizedCommand extends Command {
|
||||
|
||||
/** If the command may use interactive prompting for required parameters
|
||||
* that
|
||||
* were not provided on execution */
|
||||
private boolean interactive = true;
|
||||
/** The manager */
|
||||
protected final ConsoleManager manager;
|
||||
/** The boolean parameters mandatory status */
|
||||
private final Map<String, Boolean> boolParams = new HashMap<>();
|
||||
/** The string parameters mandatory status */
|
||||
/** The boolean parameters mandatory status. */
|
||||
private final Set<String> boolParams = new HashSet<>();
|
||||
/** The string parameters mandatory status. */
|
||||
private final Map<String, Boolean> stringParams = new HashMap<>();
|
||||
/** The parameters mandatory status */
|
||||
/** The parameters mandatory status. */
|
||||
private final Map<String, Boolean> params = new HashMap<>();
|
||||
/** The restriction of provided parameters on execution to declared
|
||||
* paramters
|
||||
* in the status maps. */
|
||||
* paramters in the status maps. */
|
||||
private final boolean strict;
|
||||
|
||||
/** @param manager the manager
|
||||
/** Create a parametrized command.
|
||||
* <p>
|
||||
* Implementation are supposed to call the
|
||||
* {@link #addBooleanParameter(String)} and
|
||||
* {@link #addStringParameter(String, boolean)} method to set the
|
||||
* parameters.
|
||||
*
|
||||
* @param name the name */
|
||||
public ParametrizedCommand(ConsoleManager manager, String name) {
|
||||
this(manager, name, true);
|
||||
public ParametrizedCommand(final String name) {
|
||||
this(name, true);
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
/** Create a parametrized command.
|
||||
* <p>
|
||||
* Implementation are supposed to call the
|
||||
* {@link #addBooleanParameter(String)} and
|
||||
* {@link #addStringParameter(String, boolean)} method to set the
|
||||
* parameters.
|
||||
*
|
||||
* @param name the name
|
||||
* @param strict if the arguments are restricted to the declared ones */
|
||||
public ParametrizedCommand(ConsoleManager manager, String name,
|
||||
boolean strict) {
|
||||
public ParametrizedCommand(final String name, final boolean strict) {
|
||||
super(name);
|
||||
this.manager = manager;
|
||||
interactive = manager != null;
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
/** <p>
|
||||
* Add a parameter to the defined parameters
|
||||
/** Add a boolean parameter to defined parmaters.
|
||||
*
|
||||
* @param param the parameter identification
|
||||
* @param stringOrBool if the parameter is a parameter with an argument
|
||||
* @param needed if the parameter is required */
|
||||
@SuppressWarnings("boxing")
|
||||
protected void addParameter(String param, boolean stringOrBool,
|
||||
boolean needed) {
|
||||
if (params.containsKey(param)) {
|
||||
return;
|
||||
}
|
||||
params.put(param, needed);
|
||||
if (stringOrBool) {
|
||||
stringParams.put(param, needed);
|
||||
} else {
|
||||
if (needed) {
|
||||
// ERROR the boolean parameters cannot be needed
|
||||
}
|
||||
boolParams.put(param, needed);
|
||||
* @param flag the boolean flag
|
||||
* @throws InvalidParameterException if the parameter is already defined as
|
||||
* a string parameter */
|
||||
protected final void addBooleanParameter(final String flag) throws InvalidParameterException {
|
||||
if (params.containsKey(flag) && stringParams.containsKey(flag)) {
|
||||
throw new InvalidParameterException(
|
||||
"Parameter is already defined as string"); //$NON-NLS-1$
|
||||
}
|
||||
boolParams.add(flag);
|
||||
params.put(flag, Boolean.FALSE);
|
||||
}
|
||||
|
||||
/** @param parameters the command parameters */
|
||||
protected abstract void doExecute(CommandParameters parameters);
|
||||
/** Add a string parameter to defined parmaters.
|
||||
*
|
||||
* @param flag the parameter flag
|
||||
* @param needed if the parameter's absence should cause an exception
|
||||
* @throws InvalidParameterException if the parameter is already defined as
|
||||
* a boolean parameter */
|
||||
protected final void addStringParameter(final String flag,
|
||||
final boolean needed) throws InvalidParameterException {
|
||||
if (params.containsKey(flag)) {
|
||||
checkParam(flag, needed);
|
||||
return;
|
||||
}
|
||||
stringParams.put(flag, Boolean.valueOf(needed));
|
||||
params.put(flag, Boolean.valueOf(needed));
|
||||
}
|
||||
|
||||
/** Check a parameter.
|
||||
*
|
||||
* @param param the string parameter
|
||||
* @param needed if the parameter is needed
|
||||
* @throws InvalidParameterException if the new definition is invalid */
|
||||
private void checkParam(final String param,
|
||||
final boolean needed) throws InvalidParameterException {
|
||||
if (stringParams.containsKey(param)) {
|
||||
final Boolean need = Boolean
|
||||
.valueOf(needed || stringParams.get(param).booleanValue());
|
||||
stringParams.put(param, need);
|
||||
params.put(param, need);
|
||||
return;
|
||||
}
|
||||
throw new InvalidParameterException(
|
||||
"Parameter is already defined as boolean"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** Actually performs the execution after parsing the parameters.
|
||||
*
|
||||
* @param out the output
|
||||
* @param in the input
|
||||
* @param parameters the command parameters
|
||||
* @throws CommandRunException if the command failed */
|
||||
protected abstract void doExecute(ConsoleOutput out, ConsoleInput in,
|
||||
CommandParameters parameters) throws CommandRunException;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#execute(java.lang.String[]) */
|
||||
@SuppressWarnings("boxing")
|
||||
@Override
|
||||
public final void execute(String... args) throws CommandRunException {
|
||||
final CommandParameters parameters = new CommandParameters(
|
||||
boolParams.keySet(), stringParams.keySet(), strict);
|
||||
if (!parameters.parseArgs(args)) {
|
||||
// ERROR the parameters could not be correctly parsed
|
||||
throw new CommandRunException("Unable to read arguments"); //$NON-NLS-1$
|
||||
public final void execute(final ConsoleOutput output,
|
||||
final ConsoleInput input,
|
||||
final String... args) throws CommandRunException {
|
||||
final CommandParameters parameters = new CommandParameters(boolParams,
|
||||
stringParams.keySet(), strict);
|
||||
try {
|
||||
parameters.parseArgs(args);
|
||||
} catch (final CommandParsingException e) {
|
||||
throw new CommandRunException(CommandRunExceptionType.USAGE,
|
||||
"Unable to read arguments", e, this); //$NON-NLS-1$
|
||||
}
|
||||
final List<String> toProvide = new ArrayList<>();
|
||||
for (final String string : params.keySet()) {
|
||||
if (params.get(string) && parameters.get(string) == null) {
|
||||
if (!interactive) {
|
||||
return;
|
||||
for (final Entry<String, Boolean> string : params.entrySet()) {
|
||||
if (string.getValue().booleanValue() &&
|
||||
parameters.get(string.getKey()) == null) {
|
||||
if (input == null || input == EmptyInput.INSTANCE) {
|
||||
throw new CommandRunException(
|
||||
CommandRunExceptionType.INTERACTION,
|
||||
"Missing required parameter " + string.getKey(), //$NON-NLS-1$
|
||||
this);
|
||||
}
|
||||
toProvide.add(string);
|
||||
toProvide.add(string.getKey());
|
||||
}
|
||||
}
|
||||
// for each needed parameters that is missing, prompt the user.
|
||||
fillParameters(toProvide, parameters);
|
||||
doExecute(parameters);
|
||||
fillParameters(input, toProvide, parameters);
|
||||
doExecute(output, input, parameters);
|
||||
}
|
||||
|
||||
/** @param parameters the parameter list to complete
|
||||
/** Fill the undefined parameters.
|
||||
* <p>
|
||||
* This method prompts the user to fill the needed parameters.
|
||||
*
|
||||
* @param input the input to prompt through
|
||||
* @param parameters the parameter list to complete
|
||||
* @param toProvide the parameters to ask for
|
||||
* @throws CommandRunException if the manager was closed */
|
||||
private void fillParameters(List<String> toProvide,
|
||||
CommandParameters parameters) throws CommandRunException {
|
||||
private final void fillParameters(final ConsoleInput input,
|
||||
final List<String> toProvide,
|
||||
final CommandParameters parameters) throws CommandRunException {
|
||||
for (final String string : toProvide) {
|
||||
String value;
|
||||
try {
|
||||
value = manager.prompt(string);
|
||||
value = input
|
||||
.prompt(MessageFormat.format("value of {0}? ", string)); //$NON-NLS-1$
|
||||
while (value.isEmpty()) {
|
||||
value = manager.prompt(string);
|
||||
value = input.prompt(MessageFormat.format(
|
||||
"value of {0}? (cannot be empty) ", //$NON-NLS-1$
|
||||
string));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
} catch (final IOException e) {
|
||||
throw new CommandRunException(
|
||||
"Interactive command but manager closed...", e); //$NON-NLS-1$
|
||||
CommandRunExceptionType.INTERACTION,
|
||||
"Interactive command but manager closed...", e, this); //$NON-NLS-1$
|
||||
}
|
||||
parameters.set(string, value);
|
||||
}
|
||||
}
|
||||
|
||||
/** Retrieve the boolean parameters (aka flags).
|
||||
*
|
||||
* @return the set of boolean parameters */
|
||||
public final Set<String> getBooleanParameters() {
|
||||
return Collections.unmodifiableSet(boolParams);
|
||||
}
|
||||
|
||||
/** Retrieve the parameter names.
|
||||
*
|
||||
* @return the stringParams */
|
||||
public final Set<String> getParameters() {
|
||||
return params.keySet();
|
||||
}
|
||||
|
||||
/** Get the string parameters names.
|
||||
*
|
||||
* @return the stringParams */
|
||||
public final Set<String> getStringParameters() {
|
||||
return stringParams.keySet();
|
||||
}
|
||||
|
||||
/** Test if a parameter is needed.
|
||||
*
|
||||
* @param param the parameter name
|
||||
* @return if the parameter is needed */
|
||||
public final boolean isNeeded(final String param) {
|
||||
return params.containsKey(param) && params.get(param).booleanValue();
|
||||
}
|
||||
|
||||
/** If the command refuse unrecognized parameters.
|
||||
*
|
||||
* @return the strict */
|
||||
public final boolean isStrict() {
|
||||
return strict;
|
||||
}
|
||||
}
|
||||
|
||||
217
gclc/src/main/java/fr/bigeon/gclc/command/ScriptExecution.java
Normal file
217
gclc/src/main/java/fr/bigeon/gclc/command/ScriptExecution.java
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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.ScriptExecution.java
|
||||
* Created on: Jun 12, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.GCLCConstants;
|
||||
import fr.bigeon.gclc.exception.CommandParsingException;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** A command that will launch a series of command from a file.
|
||||
* <p>
|
||||
* This command will read a file and execute each non empty non commented line
|
||||
* as a command of the application.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class ScriptExecution extends Command {
|
||||
|
||||
/** The tab character. */
|
||||
private static final String TAB = "\t"; //$NON-NLS-1$
|
||||
/** the space character. */
|
||||
private static final String SPACE = " "; //$NON-NLS-1$
|
||||
/** The application. */
|
||||
private final ConsoleApplication application;
|
||||
/** The commenting prefix. */
|
||||
private final String commentPrefix;
|
||||
/** The charset for files. */
|
||||
private final Charset charset;
|
||||
|
||||
/** Create the script command.
|
||||
*
|
||||
* @param name the name of the command
|
||||
* @param application the application
|
||||
* @param commentPrefix the comment prefix in the script files
|
||||
* @param charset the charset to use for files */
|
||||
public ScriptExecution(final String name, final ConsoleApplication application,
|
||||
final String commentPrefix, final Charset charset) {
|
||||
super(name);
|
||||
this.application = application;
|
||||
this.commentPrefix = commentPrefix;
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
/** Check the arguments.
|
||||
*
|
||||
* @param args the arguments
|
||||
* @throws CommandRunException if the arguments were not the ones
|
||||
* expected */
|
||||
private void checkArgs(final String[] args) throws CommandRunException {
|
||||
if (args.length == 0) {
|
||||
throw new CommandRunException(CommandRunExceptionType.USAGE,
|
||||
"Expecting a file", this); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
checkArgs(args);
|
||||
final String scriptFile = args[0];
|
||||
final String[] params = Arrays.copyOfRange(args, 1, args.length);
|
||||
String cmd;
|
||||
int lineNo = -1;
|
||||
try (InputStreamReader fReader = new InputStreamReader(
|
||||
new FileInputStream(scriptFile), charset);
|
||||
BufferedReader reader = new BufferedReader(fReader)) {
|
||||
while ((cmd = reader.readLine()) != null) {
|
||||
lineNo++;
|
||||
final String cmdLine = readCommandLine(cmd, params);
|
||||
if (cmdLine == null) {
|
||||
continue;
|
||||
}
|
||||
final List<String> ps = GCLCConstants.splitCommand(cmdLine);
|
||||
final String command = ps.remove(0);
|
||||
application.executeSub(out, in, command,
|
||||
ps.toArray(new String[0]));
|
||||
}
|
||||
} catch (final CommandParsingException e) {
|
||||
throw new CommandRunException(MessageFormat.format(
|
||||
"Invalid command in script ({0})", e.getLocalizedMessage()), //$NON-NLS-1$
|
||||
e, this);
|
||||
} catch (final IOException e) {
|
||||
throw new CommandRunException("Unable to read script", //$NON-NLS-1$
|
||||
e, this);
|
||||
} catch (final CommandRunException e) {
|
||||
throw manageRunException(e, lineNo);
|
||||
}
|
||||
}
|
||||
|
||||
/** This method will create the correct exception. The exception source must
|
||||
* be this command.
|
||||
*
|
||||
* @param e the exception
|
||||
* @param lineNo the line nu;ber
|
||||
* @return the exception to actually throw */
|
||||
private CommandRunException manageRunException(final CommandRunException e,
|
||||
final int lineNo) {
|
||||
if (e.getSource() == this) {
|
||||
// ensure closing?
|
||||
return e;
|
||||
}
|
||||
return new CommandRunException(CommandRunExceptionType.EXECUTION,
|
||||
MessageFormat.format(
|
||||
"The script could not complete due to command failure at line {0} ({1})", //$NON-NLS-1$
|
||||
Integer.valueOf(lineNo), e.getLocalizedMessage()),
|
||||
e, this);
|
||||
}
|
||||
|
||||
/** Read a line of the script.
|
||||
*
|
||||
* @param cmd the line
|
||||
* @param params the formatting parameters
|
||||
* @return the command if it is indeed one, null otherwise
|
||||
* @throws CommandRunException if the line stqrted with a space character */
|
||||
private String readCommandLine(final String cmd,
|
||||
final Object[] params) throws CommandRunException {
|
||||
if (cmd.startsWith(SPACE) || cmd.startsWith(TAB)) {
|
||||
throw new CommandRunException(
|
||||
"Invalid line in script (line starts with space character)", //$NON-NLS-1$
|
||||
this);
|
||||
}
|
||||
if (cmd.isEmpty() || cmd.startsWith(commentPrefix)) {
|
||||
// Comment line
|
||||
return null;
|
||||
}
|
||||
return MessageFormat.format(cmd, params);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
||||
@Override
|
||||
public String tip() {
|
||||
return "Execute a script"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append(
|
||||
" scriptfile: path to the file containing the script to execute."); //$NON-NLS-1$
|
||||
builder.append(System.lineSeparator());
|
||||
builder.append(System.lineSeparator());
|
||||
builder.append(
|
||||
" The script file must contain one line commands. The lines must never"); //$NON-NLS-1$
|
||||
builder.append(System.lineSeparator());
|
||||
builder.append(
|
||||
"start with whitespace characters. The lines starting with"); //$NON-NLS-1$
|
||||
builder.append(System.lineSeparator());
|
||||
builder.append('"');
|
||||
builder.append(commentPrefix);
|
||||
builder.append("\" will be ignored as well as empty lines."); //$NON-NLS-1$
|
||||
builder.append(System.lineSeparator());
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usagePattern() */
|
||||
@Override
|
||||
protected String usagePattern() {
|
||||
return super.usagePattern() + " <scriptfile>"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,102 +40,102 @@ import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** <p>
|
||||
/**
|
||||
* <p>
|
||||
* A subed command is a command that can execute sub commands depending on the
|
||||
* first argument.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class SubedCommand implements ICommandProvider, ICommand {
|
||||
public final class SubedCommand extends CommandProvider implements ICommand {
|
||||
|
||||
/** The tab character */
|
||||
/** 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.
|
||||
/** The command to execute when this command is called with no sub
|
||||
* arguments.
|
||||
* <p>
|
||||
* This may be null, in which case the command should have arguments. */
|
||||
private final ICommand noArgCommand;
|
||||
/** A tip on this command. */
|
||||
private final String tip;
|
||||
/** The provider */
|
||||
private final CommandProvider provider;
|
||||
/** The name of the command */
|
||||
/** The name of the command. */
|
||||
private final String name;
|
||||
|
||||
/** @param name the name of the command */
|
||||
public SubedCommand(String name) {
|
||||
/** Create the command that defines sub commands.
|
||||
*
|
||||
* @param name the name of the command */
|
||||
public SubedCommand(final String name) {
|
||||
super();
|
||||
this.name = name;
|
||||
provider = new CommandProvider();
|
||||
noArgCommand = null;
|
||||
tip = null;
|
||||
}
|
||||
|
||||
/** @param name the name of the command
|
||||
/** Create the command that defines sub commands.
|
||||
*
|
||||
* @param name the name of the command
|
||||
* @param noArgCommand the command to execute when no extra parameter are
|
||||
* provided */
|
||||
public SubedCommand(String name, ICommand noArgCommand) {
|
||||
public SubedCommand(final String name, final ICommand noArgCommand) {
|
||||
super();
|
||||
this.name = name;
|
||||
provider = new CommandProvider();
|
||||
this.noArgCommand = noArgCommand;
|
||||
tip = null;
|
||||
}
|
||||
|
||||
/** @param name the name of the command
|
||||
/** Create the command that defines sub commands.
|
||||
*
|
||||
* @param name the name of the command
|
||||
* @param noArgCommand the command to execute
|
||||
* @param tip the help tip associated */
|
||||
public SubedCommand(String name, ICommand noArgCommand,
|
||||
String tip) {
|
||||
public SubedCommand(final String name, final ICommand noArgCommand,
|
||||
final String tip) {
|
||||
super();
|
||||
this.name = name;
|
||||
provider = new CommandProvider();
|
||||
this.noArgCommand = noArgCommand;
|
||||
this.tip = tip;
|
||||
}
|
||||
|
||||
/** @param name the name of the command
|
||||
/** Create the command that defines sub commands.
|
||||
*
|
||||
* @param name the name of the command
|
||||
* @param tip the help tip associated */
|
||||
public SubedCommand(String name, String tip) {
|
||||
public SubedCommand(final String name, final String tip) {
|
||||
super();
|
||||
this.name = name;
|
||||
provider = new CommandProvider();
|
||||
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) throws CommandRunException {
|
||||
public void execute(final ConsoleOutput output, final ConsoleInput input,
|
||||
final String... args) throws CommandRunException {
|
||||
if (args.length == 0 || args[0].startsWith("-")) { //$NON-NLS-1$
|
||||
if (noArgCommand != null) {
|
||||
noArgCommand.execute(args);
|
||||
noArgCommand.execute(output, input, args);
|
||||
} else {
|
||||
throw new CommandRunException("Unrecognized command"); //$NON-NLS-1$
|
||||
throw new CommandRunException("Unrecognized command", this); //$NON-NLS-1$
|
||||
}
|
||||
} else {
|
||||
executeSub(args[0], Arrays.copyOfRange(args, 1, args.length));
|
||||
|
||||
try {
|
||||
executeSub(output, input, args[0],
|
||||
Arrays.copyOfRange(args, 1, args.length));
|
||||
} catch (final CommandRunException e) {
|
||||
if (e.getSource() != null) {
|
||||
throw e;
|
||||
}
|
||||
throw new CommandRunException(CommandRunExceptionType.USAGE,
|
||||
e.getLocalizedMessage(), e, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* fr.bigeon.gclc.command.ICommandProvider#executeSub(java.lang.String,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void executeSub(String command,
|
||||
String... args) throws CommandRunException {
|
||||
provider.executeSub(command, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICommand get(String commandName) {
|
||||
return provider.get(commandName);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#getCommandName() */
|
||||
@Override
|
||||
@@ -146,8 +146,8 @@ public class SubedCommand implements ICommandProvider, ICommand {
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#help() */
|
||||
@Override
|
||||
public void help(ConsoleManager manager,
|
||||
String... args) throws IOException {
|
||||
public void help(final ConsoleOutput manager,
|
||||
final String... args) throws IOException {
|
||||
if (args.length != 0 && !args[0].startsWith("-")) { //$NON-NLS-1$
|
||||
// Specific
|
||||
final ICommand c = get(args[0]);
|
||||
@@ -156,17 +156,17 @@ public class SubedCommand implements ICommandProvider, ICommand {
|
||||
}
|
||||
} 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());
|
||||
}
|
||||
if (noArgCommand != null && noArgCommand.tip() != null) {
|
||||
manager.println(TAB + noArgCommand.tip());
|
||||
}
|
||||
for (final ICommand cmd : commands) {
|
||||
if (cmd.tip() == null) {
|
||||
manager.println(TAB + cmd.getCommandName());
|
||||
} else {
|
||||
manager.println(TAB + cmd.getCommandName() + ": " + //$NON-NLS-1$
|
||||
cmd.tip());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,6 @@ public class SubedCommand implements ICommandProvider, ICommand {
|
||||
* @see java.lang.Object#toString() */
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SubedCommand " + provider; //$NON-NLS-1$
|
||||
return "SubedCommand " + super.toString(); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,8 +44,6 @@
|
||||
* {@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;
|
||||
@@ -38,27 +38,33 @@
|
||||
*/
|
||||
package fr.bigeon.gclc.exception;
|
||||
|
||||
/** An exception raised during command parsing
|
||||
/** An exception raised during command parsing.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class CommandParsingException extends Exception {
|
||||
|
||||
/** svuid */
|
||||
/** 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) {
|
||||
/** Create the exception with a message.
|
||||
*
|
||||
* @param message the message */
|
||||
public CommandParsingException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/** @param cause the cause */
|
||||
public CommandParsingException(Throwable cause) {
|
||||
/** Create the exception with a message and a cause.
|
||||
*
|
||||
* @param message the message
|
||||
* @param cause the cause */
|
||||
public CommandParsingException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/** Create the exception with a message.
|
||||
*
|
||||
* @param cause the cause */
|
||||
public CommandParsingException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,26 +38,69 @@
|
||||
*/
|
||||
package fr.bigeon.gclc.exception;
|
||||
|
||||
/** <p>
|
||||
* An exception thrown when a command failed to run correctly.
|
||||
import fr.bigeon.gclc.command.ICommand;
|
||||
|
||||
/** An exception thrown when a command failed to run correctly.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class CommandRunException extends Exception {
|
||||
public final class CommandRunException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/** the SVUID. */
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** @param message a message */
|
||||
public CommandRunException(String message) {
|
||||
/** The type of run exception. */
|
||||
private final CommandRunExceptionType type;
|
||||
/** The command that caused the error. */
|
||||
private transient ICommand source;
|
||||
|
||||
/** Create the exception.
|
||||
*
|
||||
* @param type the type of exception
|
||||
* @param message the message
|
||||
* @param source the source */
|
||||
public CommandRunException(final CommandRunExceptionType type,
|
||||
final String message, final ICommand source) {
|
||||
super(message);
|
||||
this.type = type;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/** @param message a message
|
||||
* @param cause the cause */
|
||||
public CommandRunException(String message, Throwable cause) {
|
||||
/** Create the exception with a cause.
|
||||
*
|
||||
* @param type the type of exception
|
||||
* @param message a message
|
||||
* @param cause the cause
|
||||
* @param source the source */
|
||||
public CommandRunException(final CommandRunExceptionType type,
|
||||
final String message, final Throwable cause,
|
||||
final ICommand source) {
|
||||
super(message, cause);
|
||||
this.type = type;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/** Create the exception with type
|
||||
* {@link CommandRunExceptionType#EXECUTION}.
|
||||
*
|
||||
* @param message a message
|
||||
* @param source the source */
|
||||
public CommandRunException(final String message, final ICommand source) {
|
||||
super(message);
|
||||
type = CommandRunExceptionType.EXECUTION;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/** Create the exception with type {@link CommandRunExceptionType#EXECUTION}
|
||||
* and a cause.
|
||||
*
|
||||
* @param message a message
|
||||
* @param cause the cause
|
||||
* @param source the source */
|
||||
public CommandRunException(final String message, final Throwable cause,
|
||||
final ICommand source) {
|
||||
super(message, cause);
|
||||
type = CommandRunExceptionType.EXECUTION;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -71,4 +114,17 @@ public class CommandRunException extends Exception {
|
||||
return super.getLocalizedMessage();
|
||||
}
|
||||
|
||||
/** Get the exception raising command.
|
||||
*
|
||||
* @return the source */
|
||||
public ICommand getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/** Get the exception type.
|
||||
*
|
||||
* @return the type */
|
||||
public CommandRunExceptionType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.exception.CommandRunExceptionType.java
|
||||
* Created on: Jun 12, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.exception;
|
||||
|
||||
/** The command run exception possible types.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public enum CommandRunExceptionType {
|
||||
/** Type of exception due to a wrong usage. */
|
||||
USAGE,
|
||||
/** Type of exception due to a problem in execution. */
|
||||
EXECUTION,
|
||||
/** Type of exception due to the impossibility to interact with user. */
|
||||
INTERACTION;
|
||||
}
|
||||
@@ -38,16 +38,40 @@
|
||||
*/
|
||||
package fr.bigeon.gclc.exception;
|
||||
|
||||
/** <p>
|
||||
* Exception sent from the application when a command is added but the name of
|
||||
* the command
|
||||
/** Exception sent from the application when a command is added but the name of
|
||||
* the command is already used.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class InvalidCommandName extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/** the SVUID. */
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Default constructor. */
|
||||
public InvalidCommandName() {
|
||||
super();
|
||||
}
|
||||
|
||||
/** Create the exception with a message.
|
||||
*
|
||||
* @param message the message */
|
||||
public InvalidCommandName(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/** Create the exception with a message and a cause.
|
||||
*
|
||||
* @param message the message
|
||||
* @param cause the cause */
|
||||
public InvalidCommandName(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/** Create the exception with a cause.
|
||||
*
|
||||
* @param cause the cause */
|
||||
public InvalidCommandName(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
* Copyright E. Bigeon (2014)
|
||||
* Copyright Bigeon Emmanuel (2014)
|
||||
*
|
||||
* emmanuel@bigeon.fr
|
||||
*
|
||||
* This software is a computer program whose purpose is to
|
||||
* Socket implementation of GCLC.
|
||||
* 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,
|
||||
@@ -33,45 +33,43 @@
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
/**
|
||||
* gclc-socket:fr.bigeon.gclc.socket.ConsoleRunnable.java
|
||||
* Created on: Jun 1, 2016
|
||||
* gclc:fr.bigeon.gclc.exception.InvalidParameterException.java
|
||||
* Created on: Nov 19, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.socket;
|
||||
package fr.bigeon.gclc.exception;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
|
||||
/** A runnable class that will actually have the application running.
|
||||
/** This exception is thrown during command definitions to indicate a wrong
|
||||
* parameter definition.
|
||||
* <p>
|
||||
* This class is particularly used by
|
||||
* {@link fr.bigeon.gclc.command.ParametrizedCommand parameterized commands}.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class ConsoleRunnable implements Runnable {
|
||||
|
||||
/** The actual application */
|
||||
private final ConsoleApplication app;
|
||||
/** The synchronization object */
|
||||
private final Object promptingLock;
|
||||
public class InvalidParameterException extends Exception {
|
||||
|
||||
/** @param app the application
|
||||
* @param promptingLock the synchronization object */
|
||||
public ConsoleRunnable(ConsoleApplication app, Object promptingLock) {
|
||||
super();
|
||||
this.app = app;
|
||||
this.promptingLock = promptingLock;
|
||||
/** the SVUID. */
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Create the exception with a message.
|
||||
*
|
||||
* @param message the message */
|
||||
public InvalidParameterException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run() */
|
||||
@Override
|
||||
public void run() {
|
||||
app.start();
|
||||
synchronized (promptingLock) {
|
||||
// release all waiting elements before ending
|
||||
promptingLock.notifyAll();
|
||||
}
|
||||
/** Create the exception with a message and a cause.
|
||||
*
|
||||
* @param message the message
|
||||
* @param cause the cause */
|
||||
public InvalidParameterException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/** Stop the application (it will finish its current operation) */
|
||||
public void stop() {
|
||||
app.exit();
|
||||
/** Create the exception with a cause.
|
||||
*
|
||||
* @param cause the cause */
|
||||
public InvalidParameterException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.exception.package-info.java
|
||||
* Created on: Nov 13, 2017
|
||||
*/
|
||||
/** Exceptions package.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
package fr.bigeon.gclc.exception;
|
||||
@@ -47,32 +47,32 @@ import java.util.logging.Logger;
|
||||
/** Internationalization class.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class Messages {
|
||||
/** The resource bundle name */
|
||||
public final class Messages {
|
||||
/** The resource bundle name. */
|
||||
private static final String BUNDLE_NAME = "fr.bigeon.gclc.l10n.messages"; //$NON-NLS-1$
|
||||
|
||||
/** The resource bundle */
|
||||
/** The resource bundle. */
|
||||
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
|
||||
.getBundle(BUNDLE_NAME);
|
||||
|
||||
/** The class logger */
|
||||
/** The class logger. */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(Messages.class.getName());
|
||||
|
||||
/** Utility class */
|
||||
/** Utility class. */
|
||||
private Messages() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/** Get formatted internationalized messages
|
||||
*
|
||||
/** 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) {
|
||||
public static String getString(final String key, final Object... args) {
|
||||
try {
|
||||
return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);
|
||||
} catch (MissingResourceException e) {
|
||||
} catch (final MissingResourceException e) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Unrecognized internationalization message key: " + key, e); //$NON-NLS-1$
|
||||
return '!' + key + '!';
|
||||
|
||||
42
gclc/src/main/java/fr/bigeon/gclc/i18n/package-info.java
Normal file
42
gclc/src/main/java/fr/bigeon/gclc/i18n/package-info.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.package-info.java
|
||||
* Created on: Nov 13, 2017
|
||||
*/
|
||||
/** Internationalization package.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
package fr.bigeon.gclc.i18n;
|
||||
114
gclc/src/main/java/fr/bigeon/gclc/manager/ConsoleInput.java
Normal file
114
gclc/src/main/java/fr/bigeon/gclc/manager/ConsoleInput.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.manager.ConsoleInput.java
|
||||
* Created on: Nov 13, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.manager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
/** A console application input.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public interface ConsoleInput extends AutoCloseable {
|
||||
|
||||
/** Closes the input.
|
||||
*
|
||||
* @throws IOException if the close raised an exception */
|
||||
@Override
|
||||
void close() throws IOException;
|
||||
|
||||
/** Get the prompt string.
|
||||
*
|
||||
* @return the prompt prefix */
|
||||
String getPrompt();
|
||||
|
||||
/** Indicate to the input that is should interrompt the prompting, if
|
||||
* possible.
|
||||
* <p>
|
||||
* The pending {@link #prompt()} or {@link #prompt(String)} operations
|
||||
* should return immediatly. However the returned value can be anything
|
||||
* (from the partial prompt content to an empty string or even a null
|
||||
* pointer). */
|
||||
void interruptPrompt();
|
||||
|
||||
/** Test if the input is closed.
|
||||
* <p>
|
||||
* If this is true, {@link #prompt()} methods will return immediatly and a
|
||||
* null chain.
|
||||
*
|
||||
* @return if the manager is closed. */
|
||||
boolean isClosed();
|
||||
|
||||
/** Prompt the user.
|
||||
*
|
||||
* @return the user inputed string
|
||||
* @throws IOException if the manager is closed or could not read the prompt
|
||||
* @throws InterruptedIOException if the prompt was interrupted */
|
||||
String prompt() throws IOException;
|
||||
|
||||
/** Prompt the user, with an allotated time to answer.
|
||||
*
|
||||
* @param timeout the time to wait in milliseconds
|
||||
* @return the user inputed string, null if the timeout was reached
|
||||
* @throws IOException if the manager is closed or could not read the prompt
|
||||
* @throws InterruptedIOException if the prompt was interrupted */
|
||||
String prompt(long timeout) throws IOException;
|
||||
|
||||
/** Prompt the user, with a hint on what is prompted.
|
||||
*
|
||||
* @param message the message to prompt the user
|
||||
* @return the user inputed string
|
||||
* @throws IOException if the manager is closed or could not read the prompt
|
||||
* @throws InterruptedIOException if the prompt was interrupted */
|
||||
String prompt(String message) throws IOException;
|
||||
|
||||
/** Prompt the user, with a hint on what is prompted and an allotated time
|
||||
* to answer.
|
||||
*
|
||||
* @param timeout the time to wait in milliseconds
|
||||
* @param message the message to prompt the user
|
||||
* @return the user inputed string, null if the timeout was reached
|
||||
* @throws IOException if the manager is closed or could not read the prompt
|
||||
* @throws InterruptedIOException if the prompt was interrupted */
|
||||
String prompt(String message, long timeout) throws IOException;
|
||||
|
||||
/** Set a prompting prefix.
|
||||
*
|
||||
* @param prompt the prompt */
|
||||
void setPrompt(String prompt);
|
||||
}
|
||||
@@ -33,63 +33,44 @@
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
/**
|
||||
* gclc:fr.bigeon.gclc.ConsoleManager.java
|
||||
* Created on: Dec 19, 2014
|
||||
* gclc:fr.bigeon.gclc.manager.ConsoleOutput.java
|
||||
* Created on: Nov 13, 2017
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* Depending on the implementation, some manager may not support the prompt with
|
||||
* a message, in that case, the usual behavior is to prompt normally.
|
||||
/** A console output definition.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public interface ConsoleManager {
|
||||
* @author Emmanuel Bigeon */
|
||||
public interface ConsoleOutput extends AutoCloseable {
|
||||
|
||||
/** @return the prompt prefix */
|
||||
String getPrompt();
|
||||
/** Test if the output is closed.
|
||||
*
|
||||
* @return if the manager is closed. */
|
||||
boolean isClosed();
|
||||
|
||||
/** @param text the message to print (without line break at the end).
|
||||
/** Print a string.
|
||||
*
|
||||
* @param text the message to print (without line break at the end).
|
||||
* @throws IOException if the manager is closed or could not read the
|
||||
* prompt */
|
||||
void print(String text) throws IOException;
|
||||
|
||||
/** Prints an end of line
|
||||
*
|
||||
/** Prints an end of line.
|
||||
*
|
||||
* @throws IOException if the manager is closed or could not read the
|
||||
* prompt */
|
||||
void println() throws IOException;
|
||||
|
||||
/** @param message the message to print
|
||||
/** Print a string followed by an end of line.
|
||||
* <p>
|
||||
* This is the same as calling successively {@link #print(String)} and
|
||||
* {@link #println()}.
|
||||
*
|
||||
* @param message the message to print
|
||||
* @throws IOException if the manager is closed or could not read the
|
||||
* prompt */
|
||||
void println(String message) throws IOException;
|
||||
|
||||
/** @return the user inputed string
|
||||
* @throws IOException if the manager is closed or could not read the
|
||||
* prompt */
|
||||
String prompt() throws IOException;
|
||||
|
||||
/** @param message the message to prompt the user
|
||||
* @return the user inputed string
|
||||
* @throws IOException if the manager is closed or could not read the
|
||||
* prompt */
|
||||
String prompt(String message) throws IOException;
|
||||
|
||||
/** <p>
|
||||
* Set a prompting prefix.
|
||||
*
|
||||
* @param prompt the prompt */
|
||||
void setPrompt(String prompt);
|
||||
|
||||
/** Closes the manager.
|
||||
*
|
||||
* @throws IOException if the close raised an exception */
|
||||
void close() throws IOException;
|
||||
|
||||
/** @return if the manager is closed. */
|
||||
boolean isClosed();
|
||||
}
|
||||
117
gclc/src/main/java/fr/bigeon/gclc/manager/EmptyInput.java
Normal file
117
gclc/src/main/java/fr/bigeon/gclc/manager/EmptyInput.java
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.manager.EmptyInput.java
|
||||
* Created on: Nov 13, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.manager;
|
||||
|
||||
/** A console input that return empty to all prompting.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class EmptyInput implements ConsoleInput {
|
||||
|
||||
/** The empty prompter. */
|
||||
public static final ConsoleInput INSTANCE = new EmptyInput();
|
||||
/** The empty input. */
|
||||
private EmptyInput() {
|
||||
//
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#close() */
|
||||
@Override
|
||||
public void close() {
|
||||
//
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#getPrompt() */
|
||||
@Override
|
||||
public String getPrompt() {
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#interruptPrompt() */
|
||||
@Override
|
||||
public void interruptPrompt() {
|
||||
//
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#isClosed() */
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt() */
|
||||
@Override
|
||||
public String prompt() {
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(long) */
|
||||
@Override
|
||||
public String prompt(final long timeout) {
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(java.lang.String) */
|
||||
@Override
|
||||
public String prompt(final String message) {
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(java.lang.String,
|
||||
* long) */
|
||||
@Override
|
||||
public String prompt(final String message,
|
||||
final long timeout) {
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#setPrompt(java.lang.String) */
|
||||
@Override
|
||||
public void setPrompt(final String prompt) {
|
||||
//
|
||||
}
|
||||
|
||||
}
|
||||
153
gclc/src/main/java/fr/bigeon/gclc/manager/PipedConsoleInput.java
Normal file
153
gclc/src/main/java/fr/bigeon/gclc/manager/PipedConsoleInput.java
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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-test:fr.bigeon.gclc.test.TestConsoleManager.java
|
||||
* Created on: Nov 18, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.manager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/** This console input allows to enter commands and retrieve the output as an
|
||||
* input.
|
||||
* <p>
|
||||
* This console input is used to internally pilot an application. This can be
|
||||
* used to test application behavior.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class PipedConsoleInput
|
||||
implements ConsoleInput {
|
||||
|
||||
/** THe inner manager. */
|
||||
private final StreamConsoleInput innerManager;
|
||||
/** The stream to pipe commands into. */
|
||||
private final PipedOutputStream commandInput;
|
||||
/** The stream for the application to read commands from. */
|
||||
private final PipedInputStream in;
|
||||
/** The writing thread. */
|
||||
private final WritingRunnable writing;
|
||||
|
||||
/** Create a manager that will write and read through piped stream.
|
||||
*
|
||||
* @param outPrint the stream to write the prompting messages to
|
||||
* @throws IOException if the piping failed for streams */
|
||||
public PipedConsoleInput(final PrintStream outPrint) throws IOException {
|
||||
commandInput = new PipedOutputStream();
|
||||
in = new PipedInputStream(commandInput);
|
||||
innerManager = new StreamConsoleInput(outPrint, in,
|
||||
StandardCharsets.UTF_8);
|
||||
writing = new WritingRunnable(commandInput, StandardCharsets.UTF_8);
|
||||
final Thread th = new Thread(writing,
|
||||
"GCLC console piped input stream"); //$NON-NLS-1$
|
||||
th.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
writing.setRunning(false);
|
||||
in.close();
|
||||
innerManager.close();
|
||||
commandInput.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrompt() {
|
||||
return innerManager.getPrompt();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#interruptPrompt() */
|
||||
@Override
|
||||
public void interruptPrompt() {
|
||||
innerManager.interruptPrompt();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#isClosed() */
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return innerManager.isClosed();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt() */
|
||||
@Override
|
||||
public String prompt() throws IOException {
|
||||
return innerManager
|
||||
.prompt(innerManager.getPrompt() + System.lineSeparator());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#prompt(long) */
|
||||
@Override
|
||||
public String prompt(final long timeout) throws IOException {
|
||||
return innerManager.prompt(timeout);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(java.lang.String) */
|
||||
@Override
|
||||
public String prompt(final String message) throws IOException {
|
||||
return innerManager.prompt(message + System.lineSeparator());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(java.lang.String,
|
||||
* long) */
|
||||
@Override
|
||||
public String prompt(final String message, final long timeout) throws IOException {
|
||||
return innerManager.prompt(message + System.lineSeparator(), timeout);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#setPrompt(java.lang.String) */
|
||||
@Override
|
||||
public void setPrompt(final String prompt) {
|
||||
innerManager.setPrompt(prompt);
|
||||
}
|
||||
|
||||
/** Type a message in the input.
|
||||
*
|
||||
* @param content the content to type to the application
|
||||
* @throws IOException if the typing failed */
|
||||
public void type(final String content) throws IOException {
|
||||
writing.addMessage(content);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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-test:fr.bigeon.gclc.test.TestConsoleManager.java
|
||||
* Created on: Nov 18, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.manager;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/** This console output allows to retrieve the output as an input.
|
||||
* <p>
|
||||
* This console output is used to internally pilot an application. This can be
|
||||
* used to test application behavior.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class PipedConsoleOutput
|
||||
implements ConsoleOutput {
|
||||
|
||||
/** The encoding between streams. */
|
||||
private static final String UTF_8 = "UTF-8"; //$NON-NLS-1$
|
||||
/** THe inner manager. */
|
||||
private final StreamConsoleOutput innerManager;
|
||||
/** The reader to get application return from. */
|
||||
private final BufferedReader commandBuffOutput;
|
||||
/** The stream to get application return from. */
|
||||
private final PipedInputStream commandOutput;
|
||||
/** The print writer for application to write return to. */
|
||||
private final PrintStream outPrint;
|
||||
/** The reading thread. */
|
||||
private final ReadingRunnable reading;
|
||||
|
||||
/** Create a manager that will write and read through piped stream.
|
||||
*
|
||||
* @throws IOException if the piping failed for streams */
|
||||
public PipedConsoleOutput() throws IOException {
|
||||
commandOutput = new PipedInputStream();
|
||||
final PipedOutputStream out = new PipedOutputStream(commandOutput);
|
||||
commandBuffOutput = new BufferedReader(
|
||||
new InputStreamReader(commandOutput, StandardCharsets.UTF_8));
|
||||
outPrint = new PrintStream(out, true, UTF_8);
|
||||
innerManager = new StreamConsoleOutput(outPrint);
|
||||
reading = new ReadingRunnable(commandBuffOutput);
|
||||
final Thread th = new Thread(reading, "GCLC console output forward"); //$NON-NLS-1$
|
||||
th.setDaemon(true);
|
||||
th.start();
|
||||
}
|
||||
|
||||
/** Test if there is available data.
|
||||
*
|
||||
* @return the content of the next line written by the application
|
||||
* @throws IOException if the reading failed */
|
||||
public boolean available() throws IOException {
|
||||
return reading.hasMessage();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.AutoCloseable#close() */
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
reading.setRunning(false);
|
||||
innerManager.close();
|
||||
outPrint.close();
|
||||
commandBuffOutput.close();
|
||||
commandOutput.close();
|
||||
}
|
||||
|
||||
/** Wait for a specific message to arrive.
|
||||
* <p>
|
||||
* When this method returns, the message was appended to the data, it
|
||||
* <em>may or may not</em> be the next line of data.
|
||||
*
|
||||
* @param message the message
|
||||
* @return the thread to join to wait for message delivery
|
||||
* @see fr.bigeon.gclc.manager.ReadingRunnable#getWaitForDelivery(java.lang.String) */
|
||||
public Thread getWaitForDelivery(final String message) {
|
||||
return reading.getWaitForDelivery(message);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#isClosed() */
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return innerManager.isClosed();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#print(java.lang.String) */
|
||||
@Override
|
||||
public void print(final String object) throws IOException {
|
||||
innerManager.print(object);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#println() */
|
||||
@Override
|
||||
public void println() throws IOException {
|
||||
innerManager.println();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#println(java.lang.String) */
|
||||
@Override
|
||||
public void println(final String object) throws IOException {
|
||||
innerManager.println(object);
|
||||
}
|
||||
|
||||
/** Read the next line of data.
|
||||
*
|
||||
* @return the content of the next line written by the application
|
||||
* @throws IOException if the reading failed */
|
||||
public String readNextLine() throws IOException {
|
||||
return reading.getMessage();
|
||||
}
|
||||
}
|
||||
354
gclc/src/main/java/fr/bigeon/gclc/manager/ReadingRunnable.java
Normal file
354
gclc/src/main/java/fr/bigeon/gclc/manager/ReadingRunnable.java
Normal file
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* 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.test.utils.WritingRunnable.java
|
||||
* Created on: Nov 29, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.manager;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/** A runnable to read the piped output.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class ReadingRunnable implements Runnable {
|
||||
|
||||
/** The runnable to wait for arrival of a message in the queue.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
private final class ToWaitRunnable implements Runnable {
|
||||
/** The Object. */
|
||||
private final Object obj;
|
||||
/** The locking object. */
|
||||
private final Object start;
|
||||
/** The message. */
|
||||
private final String message;
|
||||
/** The started status. */
|
||||
private boolean started = false;
|
||||
|
||||
/** Create the waiting runnable.
|
||||
*
|
||||
* @param obj the object to lock on
|
||||
* @param start the object to notify when ready to wait
|
||||
* @param message the message to wait for */
|
||||
public ToWaitRunnable(final Object obj, final Object start,
|
||||
final String message) {
|
||||
this.obj = obj;
|
||||
this.start = start;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/** Test if the waiting runnable is started.
|
||||
*
|
||||
* @return the started */
|
||||
public boolean isStarted() {
|
||||
synchronized (start) {
|
||||
return started;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run() */
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (obj) {
|
||||
synchronized (start) {
|
||||
started = true;
|
||||
start.notifyAll();
|
||||
}
|
||||
while (isRunning()) {
|
||||
try {
|
||||
obj.wait();
|
||||
if (delivering.equals(message)) {
|
||||
return;
|
||||
}
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.SEVERE, THREAD_INTERRUPTION_EXCEPTION,
|
||||
e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The thread intteruption logging message. */
|
||||
private static final String THREAD_INTERRUPTION_EXCEPTION = "Thread interruption exception."; //$NON-NLS-1$
|
||||
/** The closed pipe message. */
|
||||
private static final String CLOSED_PIPE = "Closed pipe"; //$NON-NLS-1$
|
||||
/** Wait timeout. */
|
||||
private static final long TIMEOUT = 1000;
|
||||
/** Class logger. */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(ReadingRunnable.class.getName());
|
||||
/** Read messages. */
|
||||
private final Deque<String> messages = new ArrayDeque<>();
|
||||
/** the reader. */
|
||||
private final BufferedReader reader;
|
||||
/** the state of this runnable. */
|
||||
private boolean running = true;
|
||||
/** Synchro object. */
|
||||
private final Object lock = new Object();
|
||||
/** The waiting status for a message. */
|
||||
private boolean waiting;
|
||||
/** The blocker for a given message. */
|
||||
private final Map<String, Object> messageBlocker = new HashMap<>();
|
||||
/** The lock. */
|
||||
private final Object messageBlockerLock = new Object();
|
||||
/** The message being delivered. */
|
||||
private String delivering;
|
||||
|
||||
/** Create a reading runnable.
|
||||
*
|
||||
* @param reader the input to read from */
|
||||
public ReadingRunnable(final BufferedReader reader) {
|
||||
super();
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
/** Strip the string from head NULL characters.
|
||||
*
|
||||
* @param line the line to strip the null character from
|
||||
* @return the resulting string */
|
||||
private static String stripNull(final String line) {
|
||||
String res = line;
|
||||
while (res.length() > 0 && res.charAt(0) == 0) {
|
||||
LOGGER.severe(
|
||||
"NULL character heading the result of the read. This is a stream problem..."); //$NON-NLS-1$
|
||||
res = res.substring(1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** do wait for a message.
|
||||
* <p>This method should only be called inside a loop.
|
||||
* @param timeout the timeout of the wait.
|
||||
* @throws IOException if the runnable was stopped and no essage was found.
|
||||
*/
|
||||
private void doWaitMessage(final long timeout) throws IOException {
|
||||
try {
|
||||
lock.wait(timeout);
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.SEVERE, THREAD_INTERRUPTION_EXCEPTION, e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
if (messages.isEmpty() && !running) {
|
||||
throw new IOException(CLOSED_PIPE);
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the next message.
|
||||
*
|
||||
* @return the next read message
|
||||
* @throws IOException if the pipe is closed */
|
||||
public String getMessage() throws IOException {
|
||||
synchronized (lock) {
|
||||
if (!running) {
|
||||
throw new IOException(CLOSED_PIPE);
|
||||
}
|
||||
waiting = true;
|
||||
waitMessage(TIMEOUT);
|
||||
LOGGER.finest("Polled: " + messages.peek()); //$NON-NLS-1$
|
||||
waiting = false;
|
||||
notifyMessage(messages.peek());
|
||||
return messages.poll();
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the next message, but wait only a given time for it.
|
||||
*
|
||||
* @param timeout the read time out
|
||||
* @return The next message that was in the input
|
||||
* @throws IOException if the input was closed */
|
||||
public String getNextMessage(final long timeout) throws IOException {
|
||||
synchronized (lock) {
|
||||
if (!running) {
|
||||
throw new IOException(CLOSED_PIPE);
|
||||
}
|
||||
waiting = true;
|
||||
doWaitMessage(timeout);
|
||||
waiting = false;
|
||||
if (messages.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return messages.poll();
|
||||
}
|
||||
}
|
||||
|
||||
/** Get a waiting thread for a specific message delivery.
|
||||
*
|
||||
* @param message the message
|
||||
* @return the thread to join to wait for message delivery */
|
||||
public Thread getWaitForDelivery(final String message) {
|
||||
synchronized (messageBlockerLock) {
|
||||
if (!messageBlocker.containsKey(message)) {
|
||||
messageBlocker.put(message, new Object());
|
||||
}
|
||||
final Object obj = messageBlocker.get(message);
|
||||
final Object start = new Object();
|
||||
final ToWaitRunnable waitRunn = new ToWaitRunnable(obj, start,
|
||||
message);
|
||||
final Thread th = new Thread(waitRunn);
|
||||
|
||||
synchronized (start) {
|
||||
th.start();
|
||||
while (!waitRunn.isStarted()) {
|
||||
try {
|
||||
start.wait(TIMEOUT);
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.SEVERE, THREAD_INTERRUPTION_EXCEPTION,
|
||||
e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
return th;
|
||||
}
|
||||
}
|
||||
|
||||
/** Test if some data is available.
|
||||
*
|
||||
* @return if a message is waiting
|
||||
* @throws IOException if the pipe is closed */
|
||||
public boolean hasMessage() throws IOException {
|
||||
synchronized (lock) {
|
||||
if (!running) {
|
||||
throw new IOException(CLOSED_PIPE);
|
||||
}
|
||||
return !messages.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
/** Interrupts the wait on the next message by providing an empty
|
||||
* message. */
|
||||
public void interrupt() {
|
||||
synchronized (lock) {
|
||||
if (waiting) {
|
||||
messages.offer(""); //$NON-NLS-1$
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Test if this element is still running.
|
||||
*
|
||||
* @return the running */
|
||||
public boolean isRunning() {
|
||||
synchronized (lock) {
|
||||
return running;
|
||||
}
|
||||
}
|
||||
|
||||
/** Notify the arrival of a given message.
|
||||
*
|
||||
* @param message the message */
|
||||
private void notifyMessage(final String message) {
|
||||
synchronized (messageBlockerLock) {
|
||||
delivering = message;
|
||||
if (messageBlocker.containsKey(message)) {
|
||||
final Object mLock = messageBlocker.get(message);
|
||||
synchronized (mLock) {
|
||||
mLock.notifyAll();
|
||||
}
|
||||
messageBlocker.remove(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run() */
|
||||
@Override
|
||||
public void run() {
|
||||
while (running) {
|
||||
try {
|
||||
String line = reader.readLine();
|
||||
if (line == null) {
|
||||
// Buffer end
|
||||
running = false;
|
||||
return;
|
||||
}
|
||||
LOGGER.finer("Read: " + line); //$NON-NLS-1$
|
||||
line = stripNull(line);
|
||||
synchronized (lock) {
|
||||
messages.add(line);
|
||||
lock.notifyAll();
|
||||
}
|
||||
} catch (final InterruptedIOException e) {
|
||||
if (running) {
|
||||
LOGGER.info("Reading interrupted"); //$NON-NLS-1$
|
||||
}
|
||||
LOGGER.log(Level.FINER,
|
||||
"Read interruption was caused by an exception", e); //$NON-NLS-1$
|
||||
} catch (final IOException e) {
|
||||
LOGGER.log(Level.FINE, "The stream reading threw an exception", //$NON-NLS-1$
|
||||
e);
|
||||
if (running) {
|
||||
LOGGER.severe("Unable to read from stream"); //$NON-NLS-1$
|
||||
running = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Set the running status for this reading runnable.
|
||||
*
|
||||
* @param running the running to set */
|
||||
public void setRunning(final boolean running) {
|
||||
synchronized (lock) {
|
||||
this.running = running;
|
||||
}
|
||||
}
|
||||
|
||||
/** Wait for the next message to be integratted.
|
||||
*
|
||||
* @param timeout the timeout to wait
|
||||
* @throws IOException if the next message was not delivered and the
|
||||
* runnable stopped. */
|
||||
private void waitMessage(final long timeout) throws IOException {
|
||||
while (messages.isEmpty()) {
|
||||
doWaitMessage(timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
89
gclc/src/main/java/fr/bigeon/gclc/manager/SinkOutput.java
Normal file
89
gclc/src/main/java/fr/bigeon/gclc/manager/SinkOutput.java
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.manager.SinkOutput.java
|
||||
* Created on: Nov 13, 2017
|
||||
*/
|
||||
package fr.bigeon.gclc.manager;
|
||||
|
||||
/** A console output that absorbs every message.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class SinkOutput implements ConsoleOutput {
|
||||
|
||||
/** The sink output. */
|
||||
public static final ConsoleOutput INSTANCE = new SinkOutput();
|
||||
|
||||
/** Singleton constructor. */
|
||||
private SinkOutput() {
|
||||
//
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#close() */
|
||||
@Override
|
||||
public void close() {
|
||||
//
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#isClosed() */
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#print(java.lang.String) */
|
||||
@Override
|
||||
public void print(final String text) {
|
||||
//
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#println() */
|
||||
@Override
|
||||
public void println() {
|
||||
//
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleOutput#println(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void println(final String message) {
|
||||
//
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,121 +43,64 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/** A console using the input stream and print stream.
|
||||
* <p>
|
||||
* The default constructor will use the system standart input and output.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class SystemConsoleManager implements ConsoleManager { // NOSONAR
|
||||
public final class StreamConsoleInput implements ConsoleInput {
|
||||
|
||||
/** 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 default prompt. */
|
||||
public static final String DEFAULT_PROMPT = "> "; //$NON-NLS-1$
|
||||
|
||||
/** The command prompt. It can be changed. */
|
||||
private String prompt = DEFAULT_PROMPT;
|
||||
|
||||
/** The print stream */
|
||||
/** The print stream. */
|
||||
private final PrintStream out;
|
||||
/** The input stream */
|
||||
/** The input stream. */
|
||||
private final BufferedReader in;
|
||||
|
||||
/** If the manager is closed */
|
||||
/** If the manager is closed. */
|
||||
private boolean closed = false;
|
||||
|
||||
/** The prompting thread. */
|
||||
private final Thread promptThread;
|
||||
|
||||
/** The reading runnable. */
|
||||
private final ReadingRunnable reading;
|
||||
|
||||
/** This default constructor relies on the system defined standart output
|
||||
* and input stream. */
|
||||
public SystemConsoleManager() {
|
||||
this(System.out, System.in);
|
||||
public StreamConsoleInput() {
|
||||
this(System.out, System.in, Charset.defaultCharset());
|
||||
}
|
||||
|
||||
/** @param out the output stream
|
||||
* @param in the input stream */
|
||||
public SystemConsoleManager(PrintStream out, InputStream in) {
|
||||
/** Create the stream base console input.
|
||||
*
|
||||
* @param out the output stream
|
||||
* @param in the input stream
|
||||
* @param charset the charset for the input */
|
||||
public StreamConsoleInput(final PrintStream out, final InputStream in,
|
||||
final Charset charset) {
|
||||
super();
|
||||
this.out = out;
|
||||
this.in = new BufferedReader(new InputStreamReader(in));
|
||||
this.in = new BufferedReader(new InputStreamReader(in, charset));
|
||||
reading = new ReadingRunnable(this.in);
|
||||
promptThread = new Thread(reading, "prompt"); //$NON-NLS-1$
|
||||
promptThread.setDaemon(true);
|
||||
promptThread.start();
|
||||
}
|
||||
|
||||
/** @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) throws IOException {
|
||||
/** Check that the console input is not closed.
|
||||
*
|
||||
* @throws IOException if the stream was closed */
|
||||
private void checkOpen() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException();
|
||||
}
|
||||
out.print(object);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#println() */
|
||||
@Override
|
||||
public void println() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException();
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#println(java.lang.Object) */
|
||||
@Override
|
||||
public void println(String object) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException();
|
||||
}
|
||||
out.println(object);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt() */
|
||||
@Override
|
||||
public String prompt() throws IOException {
|
||||
return prompt(new String() + prompt);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt(java.lang.String) */
|
||||
@Override
|
||||
public String prompt(String message) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException();
|
||||
}
|
||||
String result = new String();
|
||||
out.print(message + ' ');
|
||||
char c;
|
||||
try {
|
||||
result = in.readLine();
|
||||
// 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) {
|
||||
this.prompt = prompt;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -165,6 +108,23 @@ public class SystemConsoleManager implements ConsoleManager { // NOSONAR
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
closed = true;
|
||||
reading.setRunning(false);
|
||||
promptThread.interrupt();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#getPrompt() */
|
||||
@Override
|
||||
public String getPrompt() {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
/** Beware, in this implementation this is the same as closing the manager.
|
||||
*
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#interruptPrompt() */
|
||||
@Override
|
||||
public void interruptPrompt() {
|
||||
reading.interrupt();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -174,4 +134,50 @@ public class SystemConsoleManager implements ConsoleManager { // NOSONAR
|
||||
return closed;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt() */
|
||||
@Override
|
||||
public String prompt() throws IOException {
|
||||
return prompt(prompt);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#prompt(long) */
|
||||
@Override
|
||||
public String prompt(final long timeout) throws IOException {
|
||||
return prompt(prompt, timeout);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt(java.lang.String) */
|
||||
@Override
|
||||
public String prompt(final String message) throws IOException {
|
||||
checkOpen();
|
||||
if (out != null) {
|
||||
out.print(message);
|
||||
out.flush();
|
||||
}
|
||||
return reading.getMessage();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#prompt(java.lang.String) */
|
||||
@Override
|
||||
public String prompt(final String message,
|
||||
final long timeout) throws IOException {
|
||||
checkOpen();
|
||||
if (out != null) {
|
||||
out.print(message);
|
||||
out.flush();
|
||||
}
|
||||
return reading.getNextMessage(timeout);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleInput#setPrompt(java.lang.String) */
|
||||
@Override
|
||||
public void setPrompt(final String prompt) {
|
||||
this.prompt = prompt;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.system.SystemConsoleManager.java
|
||||
* Created on: Dec 19, 2014
|
||||
*/
|
||||
package fr.bigeon.gclc.manager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
|
||||
/** A console using the input stream and print stream.
|
||||
* <p>
|
||||
* The default constructor will use the system standart input and output.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public final class StreamConsoleOutput implements ConsoleOutput {
|
||||
/** The print stream. */
|
||||
private final PrintStream out;
|
||||
/** If the manager is closed. */
|
||||
private boolean closed = false;
|
||||
|
||||
/** This default constructor relies on the system defined standart output
|
||||
* and input stream. */
|
||||
public StreamConsoleOutput() {
|
||||
this(System.out);
|
||||
}
|
||||
|
||||
/** Create a print stream based console output.
|
||||
*
|
||||
* @param out the output stream */
|
||||
public StreamConsoleOutput(final PrintStream out) {
|
||||
super();
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
/** Check the open status.
|
||||
*
|
||||
* @throws IOException if the stream was closed */
|
||||
private void checkOpen() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#close() */
|
||||
@Override
|
||||
public void close() {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.manager.ConsoleManager#isClosed() */
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#print(java.lang.Object) */
|
||||
@Override
|
||||
public void print(final String object) throws IOException {
|
||||
checkOpen();
|
||||
out.print(object);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#println() */
|
||||
@Override
|
||||
public void println() throws IOException {
|
||||
checkOpen();
|
||||
out.println();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.ConsoleManager#println(java.lang.Object) */
|
||||
@Override
|
||||
public void println(final String object) throws IOException {
|
||||
checkOpen();
|
||||
out.println(object);
|
||||
}
|
||||
}
|
||||
160
gclc/src/main/java/fr/bigeon/gclc/manager/WritingRunnable.java
Normal file
160
gclc/src/main/java/fr/bigeon/gclc/manager/WritingRunnable.java
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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.test.utils.WritingRunnable.java
|
||||
* Created on: Nov 29, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.manager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/** The runnable in charge of writing messages as they are read.
|
||||
* <p>
|
||||
* Messages are queued to be retrieved latter on.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public final class WritingRunnable implements Runnable {
|
||||
|
||||
/** Wait timeout. */
|
||||
private static final long TIMEOUT = 1000;
|
||||
/** Class logger. */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(WritingRunnable.class.getName());
|
||||
/** Messages to write. */
|
||||
private final Deque<String> messages = new ArrayDeque<>();
|
||||
/** Stream to write to. */
|
||||
private final OutputStream outPrint;
|
||||
/** The charset. */
|
||||
private final Charset charset;
|
||||
/** Runnable state. */
|
||||
private boolean running = true;
|
||||
|
||||
/** Synchro object. */
|
||||
private final Object lock = new Object();
|
||||
|
||||
/** Create the writing runnable.
|
||||
*
|
||||
* @param outPrint the output to print to
|
||||
* @param charset the charset of the stream */
|
||||
public WritingRunnable(final OutputStream outPrint, final Charset charset) {
|
||||
super();
|
||||
this.outPrint = outPrint;
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
/** Add a message in the queue.
|
||||
*
|
||||
* @param message the message
|
||||
* @throws IOException if the pipe is closed */
|
||||
public void addMessage(final String message) throws IOException {
|
||||
synchronized (lock) {
|
||||
if (!running) {
|
||||
throw new IOException("Closed pipe"); //$NON-NLS-1$
|
||||
}
|
||||
messages.offer(message);
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/** Test if the message is running.
|
||||
*
|
||||
* @return the running */
|
||||
public boolean isRunning() {
|
||||
synchronized (lock) {
|
||||
return running;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run() */
|
||||
@Override
|
||||
public void run() {
|
||||
while (running) {
|
||||
synchronized (lock) {
|
||||
while (messages.isEmpty()) {
|
||||
waitNextMessage();
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
writeMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Set the running status.
|
||||
*
|
||||
* @param running the running to set */
|
||||
public void setRunning(final boolean running) {
|
||||
synchronized (lock) {
|
||||
this.running = running;
|
||||
}
|
||||
}
|
||||
|
||||
/** Wait for next message. */
|
||||
private void waitNextMessage() {
|
||||
try {
|
||||
lock.wait(TIMEOUT);
|
||||
} catch (final InterruptedException e) {
|
||||
if (running) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Thread interruption exception.", e); //$NON-NLS-1$
|
||||
}
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/** Write next message to output. */
|
||||
private void writeMessage() {
|
||||
final String message = messages.poll();
|
||||
final ByteBuffer buff = charset
|
||||
.encode(message + System.lineSeparator());
|
||||
if (buff.hasArray()) {
|
||||
try {
|
||||
outPrint.write(buff.array());
|
||||
} catch (final IOException e) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to write to stream", //$NON-NLS-1$
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
gclc/src/main/java/fr/bigeon/gclc/manager/package-info.java
Normal file
42
gclc/src/main/java/fr/bigeon/gclc/manager/package-info.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.manager.package-info.java
|
||||
* Created on: Nov 13, 2017
|
||||
*/
|
||||
/** The console input and output definitions.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
package fr.bigeon.gclc.manager;
|
||||
42
gclc/src/main/java/fr/bigeon/gclc/package-info.java
Normal file
42
gclc/src/main/java/fr/bigeon/gclc/package-info.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.package-info.java
|
||||
* Created on: Nov 5, 2017
|
||||
*/
|
||||
/** A framework for commad line applications.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
package fr.bigeon.gclc;
|
||||
@@ -43,65 +43,95 @@ import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** <p>
|
||||
* The {@link CLIPrompter} class is a utility class that provides method to
|
||||
/** The {@link CLIPrompter} class is a utility class that provides method to
|
||||
* prompt the user.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class CLIPrompter {
|
||||
public final class CLIPrompter {
|
||||
|
||||
/** message key for format error in prompting a choice */
|
||||
/** The zero integer. */
|
||||
private static final Integer ZERO = Integer.valueOf(0);
|
||||
/** 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 */
|
||||
/** 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 */
|
||||
/** 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 */
|
||||
/** 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")
|
||||
/** Message key for boolean choosing. */
|
||||
private static final String BOOL_CHOICES = "promptbool.choices"; //$NON-NLS-1$
|
||||
@SuppressWarnings("javadoc")
|
||||
/** Message key for the list end of prompt symbol. */
|
||||
private static final String LIST_DISP_KEY = "promptlist.exit.dispkey"; //$NON-NLS-1$
|
||||
@SuppressWarnings("javadoc")
|
||||
/** Message key for the line prompt. */
|
||||
private static final String PROMPT = "prompt.lineprompt"; //$NON-NLS-1$
|
||||
@SuppressWarnings("javadoc")
|
||||
/** Message key for the separation of choices selection. */
|
||||
private static final String LIST_CHOICE_SEP = "promptlist.multi.sepkey"; //$NON-NLS-1$
|
||||
/** The class logger */
|
||||
/** The class logger. */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(CLIPrompter.class.getName());
|
||||
|
||||
/** Utility class */
|
||||
/** Utility class. */
|
||||
private CLIPrompter() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
/** Add a user choice to the list.
|
||||
*
|
||||
* @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(final String val,
|
||||
final List<Integer> chs,
|
||||
final 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;
|
||||
}
|
||||
|
||||
/** List the choices on the output.
|
||||
*
|
||||
* @param output 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)
|
||||
* @throws IOException if the manager was closed */
|
||||
private static <U> int listChoices(ConsoleManager manager, List<U> choices,
|
||||
String cancel) throws IOException {
|
||||
private static <U> Integer listChoices(final ConsoleOutput output,
|
||||
final List<U> choices,
|
||||
final String cancel) throws IOException {
|
||||
int index = 0;
|
||||
for (final U u : choices) {
|
||||
manager.println(index++ + ") " + u); //$NON-NLS-1$
|
||||
output.println(index++ + ") " + u); //$NON-NLS-1$
|
||||
}
|
||||
if (cancel != null) {
|
||||
manager.println(index + ") " + cancel); //$NON-NLS-1$
|
||||
output.println(index++ + ") " + cancel); //$NON-NLS-1$
|
||||
}
|
||||
return index;
|
||||
return Integer.valueOf(index - 1);
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
/** Prompt for a boolean value.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @param message the prompting message
|
||||
* @return the choice
|
||||
* @throws IOException if the manager was closed */
|
||||
public static boolean promptBoolean(ConsoleManager manager,
|
||||
String message) throws IOException {
|
||||
String result = manager
|
||||
public static boolean promptBoolean(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final String message) throws IOException {
|
||||
String result = input
|
||||
.prompt(message + CLIPrompterMessages.getString(BOOL_CHOICES));
|
||||
boolean first = true;
|
||||
final String choices = CLIPrompterMessages
|
||||
@@ -120,7 +150,7 @@ public class CLIPrompter {
|
||||
|
||||
manager.println(CLIPrompterMessages
|
||||
.getString("promptbool.choices.invalid", choices)); //$NON-NLS-1$
|
||||
result = manager.prompt(
|
||||
result = input.prompt(
|
||||
message + CLIPrompterMessages.getString(BOOL_CHOICES));
|
||||
}
|
||||
first = false;
|
||||
@@ -131,7 +161,10 @@ public class CLIPrompter {
|
||||
.getString("promptbool.choices.yes2")); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
/** Prompt for a choice.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @param keys the keys to be printed
|
||||
* @param choices the real choices
|
||||
* @param message the message
|
||||
@@ -139,18 +172,24 @@ public class CLIPrompter {
|
||||
* @param <U> the type of elements
|
||||
* @return the choice
|
||||
* @throws IOException if the manager was closed */
|
||||
@SuppressWarnings("boxing")
|
||||
public static <U> U promptChoice(ConsoleManager manager, List<String> keys,
|
||||
List<U> choices, String message,
|
||||
String cancel) throws IOException {
|
||||
final Integer index = promptChoice(manager, keys, message, cancel);
|
||||
public static <U> U promptChoice(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final List<String> keys,
|
||||
final List<U> choices,
|
||||
final String message,
|
||||
final String cancel) throws IOException {
|
||||
final Integer index = promptChoice(manager, input, keys, message,
|
||||
cancel);
|
||||
if (index == null) {
|
||||
return null;
|
||||
}
|
||||
return choices.get(index);
|
||||
return choices.get(index.intValue());
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
/** Prompt for a choice.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @param <U> The choices labels type
|
||||
* @param <T> The real choices objects
|
||||
* @param choices the list of labels (in order to be displayed)
|
||||
@@ -159,55 +198,66 @@ public class CLIPrompter {
|
||||
* @param cancel the cancel option if it exists (null otherwise)
|
||||
* @return the chosen object
|
||||
* @throws IOException if the manager was closed */
|
||||
public static <U, T> T promptChoice(ConsoleManager manager, List<U> choices,
|
||||
Map<U, T> choicesMap, String message,
|
||||
String cancel) throws IOException {
|
||||
return choicesMap.get(choices.get(
|
||||
promptChoice(manager, choices, message, cancel).intValue()));
|
||||
public static <U, T> T promptChoice(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final List<U> choices,
|
||||
final Map<U, T> choicesMap,
|
||||
final String message,
|
||||
final String cancel) throws IOException {
|
||||
final Integer res = promptChoice(manager, input, choices, message,
|
||||
cancel);
|
||||
if (res == null) {
|
||||
return null;
|
||||
}
|
||||
return choicesMap.get(choices.get(res.intValue()));
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
/** Prompt for a choice.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @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
|
||||
* @throws IOException if the manager was closed */
|
||||
@SuppressWarnings("boxing")
|
||||
public static <U> Integer promptChoice(ConsoleManager manager,
|
||||
List<U> choices, String message,
|
||||
String cancel) throws IOException {
|
||||
public static <U> Integer promptChoice(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final List<U> choices,
|
||||
final String message,
|
||||
final String cancel) throws IOException {
|
||||
manager.println(message);
|
||||
final int index = listChoices(manager, choices, cancel);
|
||||
String result = ""; //$NON-NLS-1$
|
||||
boolean keepOn = true;
|
||||
final Integer index = listChoices(manager, choices, cancel);
|
||||
String result;
|
||||
int r = -1;
|
||||
while (keepOn) {
|
||||
result = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||
while (true) {
|
||||
result = input.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);
|
||||
if (r >= 0 && r <= index.intValue()) {
|
||||
break;
|
||||
}
|
||||
|
||||
} catch (final NumberFormatException e) {
|
||||
keepOn = true;
|
||||
manager.println(CLIPrompterMessages
|
||||
.getString(PROMPTCHOICE_FORMATERR, 0, index));
|
||||
listChoices(manager, choices, cancel);
|
||||
.getString(PROMPTCHOICE_OUTOFBOUNDS, ZERO, index));
|
||||
} catch (final NumberFormatException e) {
|
||||
LOGGER.log(Level.FINER,
|
||||
"Unrecognized number. Prompting user again.", e); //$NON-NLS-1$
|
||||
manager.println(CLIPrompterMessages
|
||||
.getString(PROMPTCHOICE_FORMATERR, ZERO, index));
|
||||
}
|
||||
listChoices(manager, choices, cancel);
|
||||
}
|
||||
if (r == index && cancel != null) {
|
||||
if (r == index.intValue() && cancel != null) {
|
||||
return null;
|
||||
}
|
||||
return r;
|
||||
return Integer.valueOf(r);
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
/** Prompt for a choice.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @param <U> The choices labels type
|
||||
* @param <T> The real choices objects
|
||||
* @param choicesMap the map of label to actual objects
|
||||
@@ -215,19 +265,24 @@ public class CLIPrompter {
|
||||
* @param cancel the cancel option (or null)
|
||||
* @return the chosen object
|
||||
* @throws IOException if the manager was closed */
|
||||
public static <U, T> T promptChoice(ConsoleManager manager,
|
||||
Map<U, T> choicesMap, String message,
|
||||
String cancel) throws IOException {
|
||||
return promptChoice(manager, new ArrayList<>(choicesMap.keySet()),
|
||||
choicesMap, message, cancel);
|
||||
public static <U, T> T promptChoice(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final Map<U, T> choicesMap,
|
||||
final String message,
|
||||
final String cancel) throws IOException {
|
||||
return promptChoice(manager, input,
|
||||
new ArrayList<>(choicesMap.keySet()), choicesMap, message,
|
||||
cancel);
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
/** Prompt for an integer.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param message the prompt message
|
||||
* @return the integer
|
||||
* @throws IOException if the manager was closed */
|
||||
public static int promptInteger(ConsoleManager manager,
|
||||
String message) throws IOException {
|
||||
public static int promptInteger(final ConsoleInput manager,
|
||||
final String message) throws IOException {
|
||||
boolean still = true;
|
||||
int r = 0;
|
||||
while (still) {
|
||||
@@ -240,42 +295,46 @@ public class CLIPrompter {
|
||||
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$
|
||||
LOGGER.info("User input a non parsable integer: " + result); //$NON-NLS-1$
|
||||
LOGGER.log(Level.FINEST, "Unrecognized integer", e); //$NON-NLS-1$
|
||||
still = true;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/** This methods prompt the user for a list of elements
|
||||
/** This methods prompt the user for a list of elements.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @param message the message
|
||||
* @return the list of user inputs
|
||||
* @throws IOException if the manager was closed */
|
||||
public static List<String> promptList(ConsoleManager manager,
|
||||
String message) throws IOException {
|
||||
return promptList(manager, message,
|
||||
public static List<String> promptList(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final String message) throws IOException {
|
||||
return promptList(manager, input, message,
|
||||
CLIPrompterMessages.getString("promptlist.exit.defaultkey")); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** This methods prompt the user for a list of elements
|
||||
/** This methods prompt the user for a list of elements.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @param message the message
|
||||
* @param ender the ending sequence for the list
|
||||
* @return the list of user inputs
|
||||
* @throws IOException if the manager was closed */
|
||||
public static List<String> promptList(ConsoleManager manager,
|
||||
String message,
|
||||
String ender) throws IOException {
|
||||
public static List<String> promptList(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final String message,
|
||||
final String ender) throws IOException {
|
||||
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));
|
||||
res = input.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||
if (!res.equals(ender)) {
|
||||
strings.add(res);
|
||||
}
|
||||
@@ -286,49 +345,60 @@ public class CLIPrompter {
|
||||
/** Prompt for a text with several lines.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @param message the prompting message
|
||||
* @return the text
|
||||
* @throws IOException if the manager was closed */
|
||||
public static String promptLongText(ConsoleManager manager,
|
||||
String message) throws IOException {
|
||||
return promptLongText(manager, message, CLIPrompterMessages
|
||||
public static String promptLongText(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final String message) throws IOException {
|
||||
return promptLongText(manager, input, message, CLIPrompterMessages
|
||||
.getString("promptlongtext.exit.defaultkey")); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** Prompt for a text with several lines.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @param message the prompting message
|
||||
* @param ender the ender character
|
||||
* @return the text
|
||||
* @throws IOException if the manager was closed */
|
||||
public static String promptLongText(ConsoleManager manager, String message,
|
||||
String ender) throws IOException {
|
||||
public static String promptLongText(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final String message,
|
||||
final String ender) throws IOException {
|
||||
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);
|
||||
final StringBuilder res = new StringBuilder();
|
||||
String line;
|
||||
do {
|
||||
line = input.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||
if (!line.equals(ender)) {
|
||||
res += System.lineSeparator() + line;
|
||||
res.append(line);
|
||||
res.append(System.lineSeparator());
|
||||
}
|
||||
}
|
||||
return res.equals(ender) ? "" : res; //$NON-NLS-1$
|
||||
} while (!line.equals(ender));
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
/** Prompt the user to select zero or more elements from a list.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @param keys the keys to be printed
|
||||
* @param choices the real choices
|
||||
* @param message the message
|
||||
* @param <U> the type of elements
|
||||
* @return the choice
|
||||
* @throws IOException if the manager was closed */
|
||||
public static <U> List<U> promptMultiChoice(ConsoleManager manager,
|
||||
List<String> keys,
|
||||
List<U> choices,
|
||||
String message) throws IOException {
|
||||
final List<Integer> indices = promptMultiChoice(manager, keys, message);
|
||||
public static <U> List<U> promptMultiChoice(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final List<String> keys,
|
||||
final List<U> choices,
|
||||
final String message) throws IOException {
|
||||
final List<Integer> indices = promptMultiChoice(manager, input, keys,
|
||||
message);
|
||||
final List<U> userChoices = new ArrayList<>();
|
||||
for (final Integer integer : indices) {
|
||||
userChoices.add(choices.get(integer.intValue()));
|
||||
@@ -336,7 +406,10 @@ public class CLIPrompter {
|
||||
return userChoices;
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
/** Prompt the user to select zero or more elements from a list.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @param <U> The choices labels type
|
||||
* @param <T> The real choices objects
|
||||
* @param choices the list of labels (in order to be displayed)
|
||||
@@ -344,52 +417,59 @@ public class CLIPrompter {
|
||||
* @param message the prompting message
|
||||
* @return the chosen objects (or an empty list)
|
||||
* @throws IOException if the manager was closed */
|
||||
public static <U, T> List<T> promptMultiChoice(ConsoleManager manager,
|
||||
List<U> choices,
|
||||
Map<U, T> choicesMap,
|
||||
String message) throws IOException {
|
||||
final List<Integer> chs = promptMultiChoice(manager, choices, message);
|
||||
public static <U, T> List<T> promptMultiChoice(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final List<U> choices,
|
||||
final Map<U, T> choicesMap,
|
||||
final String message) throws IOException {
|
||||
final List<Integer> chs = promptMultiChoice(manager, input, choices,
|
||||
message);
|
||||
final List<T> userChoices = new ArrayList<>();
|
||||
for (final Integer integer : chs) {
|
||||
userChoices.add(choicesMap.get(integer));
|
||||
userChoices.add(choicesMap.get(choices.get(integer.intValue())));
|
||||
}
|
||||
return userChoices;
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
/** Prompt the user to select zero or more elements from a list.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @param <U> the type of choices
|
||||
* @param choices the list of choices
|
||||
* @param message the prompting message
|
||||
* @return the indices of the choices
|
||||
* @throws IOException if the manager was closed */
|
||||
@SuppressWarnings("boxing")
|
||||
public static <U> List<Integer> promptMultiChoice(ConsoleManager manager,
|
||||
List<U> choices,
|
||||
String message) throws IOException {
|
||||
public static <U> List<Integer> promptMultiChoice(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final List<U> choices,
|
||||
final String message) throws IOException {
|
||||
manager.println(message);
|
||||
final int index = listChoices(manager, choices, null);
|
||||
String result = ""; //$NON-NLS-1$
|
||||
final Integer index = listChoices(manager, choices, null);
|
||||
String result;
|
||||
boolean keepOn = true;
|
||||
final List<Integer> chs = new ArrayList<>();
|
||||
while (keepOn) {
|
||||
keepOn = false;
|
||||
result = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||
result = input.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);
|
||||
added = addUserChoice(val, chs, index.intValue());
|
||||
} catch (final NumberFormatException e) {
|
||||
LOGGER.log(Level.FINER,
|
||||
"Unrecognized number. Prompting user again.", e); //$NON-NLS-1$
|
||||
keepOn = true;
|
||||
manager.println(CLIPrompterMessages
|
||||
.getString(PROMPTCHOICE_FORMATERR, 0, index));
|
||||
.getString(PROMPTCHOICE_FORMATERR, ZERO, index));
|
||||
listChoices(manager, choices, null);
|
||||
break;
|
||||
}
|
||||
if (!added) {
|
||||
manager.println(CLIPrompterMessages
|
||||
.getString(PROMPTCHOICE_OUTOFBOUNDS, 0, index));
|
||||
.getString(PROMPTCHOICE_OUTOFBOUNDS, ZERO, index));
|
||||
listChoices(manager, choices, null);
|
||||
keepOn = true;
|
||||
}
|
||||
@@ -398,45 +478,34 @@ public class CLIPrompter {
|
||||
return chs;
|
||||
}
|
||||
|
||||
/** @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
|
||||
/** Prompt the user to select zero or more elements from a list.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param input the input
|
||||
* @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
|
||||
* @throws IOException if the manager was closed */
|
||||
public static <U, T> List<T> promptMultiChoice(ConsoleManager manager,
|
||||
Map<U, T> choicesMap,
|
||||
String message) throws IOException {
|
||||
return promptMultiChoice(manager, new ArrayList<>(choicesMap.keySet()),
|
||||
choicesMap, message);
|
||||
public static <U, T> List<T> promptMultiChoice(final ConsoleOutput manager,
|
||||
final ConsoleInput input,
|
||||
final Map<U, T> choicesMap,
|
||||
final String message) throws IOException {
|
||||
return promptMultiChoice(manager, input,
|
||||
new ArrayList<>(choicesMap.keySet()), choicesMap, message);
|
||||
}
|
||||
|
||||
/** @param manager the manager
|
||||
/** Prompt the user for a non empty text.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param prompt the prompting message
|
||||
* @param reprompt the prompting message after empty input
|
||||
* @return the non empty input
|
||||
* @throws IOException if the manager was closed */
|
||||
public static String promptNonEmpty(ConsoleManager manager, String prompt,
|
||||
String reprompt) throws IOException {
|
||||
public static String promptNonEmpty(final ConsoleInput manager,
|
||||
final String prompt,
|
||||
final String reprompt) throws IOException {
|
||||
String res = manager.prompt(prompt);
|
||||
while (res.isEmpty()) {
|
||||
res = manager.prompt(reprompt);
|
||||
|
||||
@@ -44,37 +44,35 @@ import java.util.ResourceBundle;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/** <p>
|
||||
* Utility class for the messages of the CLIPrompter
|
||||
/** Utility class for the messages of the CLIPrompter.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class CLIPrompterMessages {
|
||||
/** The resource name */
|
||||
public final class CLIPrompterMessages {
|
||||
/** 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);
|
||||
|
||||
/** The logger */
|
||||
/** The logger. */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(CLIPrompterMessages.class.getName());
|
||||
|
||||
/** Utility class */
|
||||
/** Utility class. */
|
||||
private CLIPrompterMessages() {
|
||||
// Utility constructor
|
||||
}
|
||||
|
||||
/** Return the formatted message corresponding to the given key
|
||||
/** Return the formatted message corresponding to the given key.
|
||||
*
|
||||
* @param key the message's key
|
||||
* @param args the arguments
|
||||
* @return the formatted message */
|
||||
public static String getString(String key, Object... args) {
|
||||
public static String getString(final String key, final Object... args) {
|
||||
try {
|
||||
return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);
|
||||
} catch (final MissingResourceException e) {
|
||||
LOGGER.log(Level.WARNING, "Unrecognized key: " + key, e); //$NON-NLS-1$
|
||||
LOGGER.warning("Unrecognized key: " + key); //$NON-NLS-1$
|
||||
LOGGER.log(Level.FINE, "Missing key in " + BUNDLE_NAME, e); //$NON-NLS-1$
|
||||
return '!' + key + '!';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.tools.AOutputForwardRunnable.java
|
||||
* Created on: Dec 1, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.tools;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||
|
||||
/** An incomplete implematation used to forward messages from a piped console.
|
||||
* <p>
|
||||
* This forwarding can be interrupted without closing the piped manager.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public abstract class AOutputForwardRunnable implements Runnable {
|
||||
|
||||
/** The class logger. */
|
||||
private static final Logger LOGGER = Logger
|
||||
.getLogger(AOutputForwardRunnable.class.getName());
|
||||
/** The default timeout (one tenth of second). */
|
||||
private static final long DEFAULT_TIMEOUT = 100;
|
||||
/** The manager. */
|
||||
private final PipedConsoleOutput manager;
|
||||
/** The timeout. */
|
||||
private final long timeout;
|
||||
|
||||
/** Create a forwarding runnable.
|
||||
*
|
||||
* @param manager the manager */
|
||||
public AOutputForwardRunnable(final PipedConsoleOutput manager) {
|
||||
super();
|
||||
this.manager = manager;
|
||||
timeout = DEFAULT_TIMEOUT;
|
||||
}
|
||||
|
||||
/** Create a forward runnable with the given timeout.
|
||||
* <p>
|
||||
* Short timeout will be very responsive to the application actual messages,
|
||||
* but may use computation time if the application is not verbose. Long
|
||||
* timeout will save computation time, but will read batches of messages at
|
||||
* once if the application is verbose. The right length for the timeout is
|
||||
* likely to depend on the application and the use of it.
|
||||
* <p>
|
||||
* If you do not know what timeout length to use, please use the
|
||||
* {@link #AOutputForwardRunnable(PipedConsoleOutput)} constructor.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param timeout the timeout between message requests. */
|
||||
public AOutputForwardRunnable(final PipedConsoleOutput manager,
|
||||
final long timeout) {
|
||||
super();
|
||||
this.manager = manager;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
/** Do forward the line.
|
||||
*
|
||||
* @param m the line to forward */
|
||||
protected abstract void forwardLine(String m);
|
||||
|
||||
/** Test if the runable is still running.
|
||||
*
|
||||
* @return if the thread should keep running */
|
||||
protected abstract boolean isRunning();
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run() */
|
||||
@Override
|
||||
public final void run() {
|
||||
try {
|
||||
while (isRunning()) {
|
||||
while (isRunning() && !manager.available()) {
|
||||
waitASec();
|
||||
}
|
||||
if (!isRunning()) {
|
||||
return;
|
||||
}
|
||||
final String m = manager.readNextLine();
|
||||
forwardLine(m);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
LOGGER.log(Level.SEVERE, "Unexpected problem in manager", //$NON-NLS-1$
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
/** a method to wait some time. */
|
||||
protected final void waitASec() {
|
||||
try {
|
||||
synchronized (this) {
|
||||
wait(timeout);
|
||||
}
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.log(Level.SEVERE, "Interrupted wait", //$NON-NLS-1$
|
||||
e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -44,54 +44,61 @@ import java.util.List;
|
||||
/** A tool class for printing text in a console.
|
||||
*
|
||||
* @author Emmanuel BIGEON */
|
||||
public class PrintUtils {
|
||||
public final class PrintUtils {
|
||||
|
||||
/** The continuation dot string */
|
||||
/** The continuation dot string. */
|
||||
private static final String CONT_DOT = "..."; //$NON-NLS-1$
|
||||
/** The continuation dot string length */
|
||||
/** The continuation dot string length. */
|
||||
private static final int CONT_DOT_LENGTH = CONT_DOT.length();
|
||||
/** The empty string constant. */
|
||||
private static final String EMPTY = ""; //$NON-NLS-1$
|
||||
|
||||
/** Utility class */
|
||||
/** Utility class. */
|
||||
private PrintUtils() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/** @param text the text to print
|
||||
/** Print the text possibly cutting it if it goes over the authorized length
|
||||
* and adding a mark of continuation.
|
||||
*
|
||||
* @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) {
|
||||
String res = text;
|
||||
public static String print(final String text, final int nbCharacters,
|
||||
final boolean indicateTooLong) {
|
||||
StringBuilder res = new StringBuilder(text);
|
||||
if (res.length() > nbCharacters) {
|
||||
// Cut
|
||||
if (indicateTooLong) {
|
||||
// With suspension dots
|
||||
res = res.substring(0, nbCharacters - CONT_DOT_LENGTH) +
|
||||
CONT_DOT;
|
||||
res = res.replace(nbCharacters - CONT_DOT_LENGTH, text.length(),
|
||||
CONT_DOT);
|
||||
} else {
|
||||
res = res.substring(0, nbCharacters);
|
||||
res = res.replace(nbCharacters, text.length(), ""); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
while (res.length() < nbCharacters) {
|
||||
// Add trailing space
|
||||
res = res + ' ';
|
||||
res.append(' ');
|
||||
}
|
||||
return res;
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
/** @param description the element to wrap in lines
|
||||
/** Wrap the text, cutting at spaces.
|
||||
*
|
||||
* @param description the element to wrap in lines
|
||||
* @param i the length of the wrap
|
||||
* @return the list of resulting strings */
|
||||
public static List<String> wrap(String description, int i) {
|
||||
public static List<String> wrap(final String description, final int i) {
|
||||
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$
|
||||
int index = toCut.lastIndexOf(' ', i);
|
||||
if (index == -1) {
|
||||
result.add(toCut.substring(0, i));
|
||||
index = i - 1;
|
||||
@@ -101,8 +108,9 @@ public class PrintUtils {
|
||||
toCut = toCut.substring(index + 1);
|
||||
}
|
||||
result.add(toCut);
|
||||
result.add(new String());
|
||||
result.add(EMPTY);
|
||||
}
|
||||
result.remove(result.size() - 1);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
42
gclc/src/main/java/fr/bigeon/gclc/tools/package-info.java
Normal file
42
gclc/src/main/java/fr/bigeon/gclc/tools/package-info.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.tools.package-info.java
|
||||
* Created on: Nov 13, 2017
|
||||
*/
|
||||
/** Tool classes.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
package fr.bigeon.gclc.tools;
|
||||
@@ -1,11 +1,12 @@
|
||||
exit.tip=Exit the application
|
||||
help.cmd.tip=Display an help tip
|
||||
|
||||
prompt.lineprompt=>
|
||||
prompt.lineprompt=>\
|
||||
|
||||
promptlist.exit.defaultkey=\\q
|
||||
promptlist.exit.dispkey=\ (exit with a new line made of "{0}")
|
||||
promptlist.prompt=>\
|
||||
promptlist.multi.sepkey=\
|
||||
|
||||
promptbool.choices=\ (Y/N)
|
||||
promptbool.choices.invalid=Invalid input. Please input one of {0}.
|
||||
@@ -15,7 +16,8 @@ promptbool.choices.no1=N
|
||||
promptbool.choices.no2=no
|
||||
|
||||
promptchoice.outofbounds=Please choose something between {0} and {1}. The choices were:
|
||||
promptchoice.formaterr=The input seems to be something that is not an integer.\nPlease choose something between {0} and {1}. The choices were:
|
||||
promptchoice.formaterr=The input seems to be something that is not an integer.\
|
||||
Please choose something between {0} and {1}. The choices were:
|
||||
|
||||
promptlongtext.exit.defaultkey=\\q
|
||||
promptlongtext.exit.dispkey=\ (exit with a new line made of "{0}")
|
||||
|
||||
124
gclc/src/test/java/fr/bigeon/gclc/CommandTestingApplication.java
Normal file
124
gclc/src/test/java/fr/bigeon/gclc/CommandTestingApplication.java
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.CommandTestingApplication.java
|
||||
* Created on: Jun 12, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import fr.bigeon.gclc.command.ICommand;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleInput;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
public class CommandTestingApplication implements AutoCloseable {
|
||||
|
||||
private final ConsoleApplication application;
|
||||
private final Thread th;
|
||||
private final PipedConsoleOutput out;
|
||||
private final PipedConsoleInput in;
|
||||
|
||||
/** @throws IOException if the streams cannot be build */
|
||||
public CommandTestingApplication() throws IOException {
|
||||
out = new PipedConsoleOutput();
|
||||
in = new PipedConsoleInput(null);
|
||||
application = new ConsoleApplication(out, in, "", "");
|
||||
new ConsoleTestApplication().attach(application);
|
||||
th = new Thread(new Runnable() {
|
||||
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
application.start();
|
||||
}
|
||||
});
|
||||
|
||||
th.start();
|
||||
}
|
||||
|
||||
/** @param cmd the command
|
||||
* @return if the command was added
|
||||
* @throws InvalidCommandName if the command name is invalid
|
||||
* @see fr.bigeon.gclc.ConsoleApplication#add(fr.bigeon.gclc.command.ICommand) */
|
||||
public final boolean add(final ICommand cmd) throws InvalidCommandName {
|
||||
return application.add(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
application.exit();
|
||||
out.close();
|
||||
in.close();
|
||||
}
|
||||
|
||||
/** @return the application */
|
||||
public ConsoleApplication getApplication() {
|
||||
return application;
|
||||
}
|
||||
|
||||
/** @return the next written line, null if it is the prompt
|
||||
* @throws IOException if the reading failed
|
||||
* @see fr.bigeon.gclc.manager.PipedConsoleManager#readNextLine() */
|
||||
public String readNextLine() throws IOException {
|
||||
final String ret = out.readNextLine();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void sendCommand(final String cmd) throws IOException {
|
||||
in.type(cmd);
|
||||
}
|
||||
|
||||
/** @throws IOException if the writing failed */
|
||||
public void waitAndStop() throws IOException {
|
||||
in.type(ConsoleTestApplication.EXIT);
|
||||
try {
|
||||
th.join();
|
||||
} catch (final InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -38,82 +38,210 @@
|
||||
*/
|
||||
package fr.bigeon.gclc;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.manager.SystemConsoleManager;
|
||||
import fr.bigeon.gclc.command.ExitCommand;
|
||||
import fr.bigeon.gclc.command.ICommand;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
import fr.bigeon.gclc.i18n.Messages;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleInput;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||
|
||||
/** Test class for ConsoleApplication
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
@SuppressWarnings("static-method")
|
||||
@SuppressWarnings({"javadoc", "nls", "static-method"})
|
||||
public class ConsoleApplicationTest {
|
||||
|
||||
/** 3 seconds in milliseconds */
|
||||
protected static final long THREE_SECONDS = 3000;
|
||||
|
||||
/** Test the base of a console application */
|
||||
@Test
|
||||
public void test() {
|
||||
ConsoleTestApplication app = new ConsoleTestApplication(
|
||||
new SystemConsoleManager());
|
||||
app.exit();
|
||||
public void testConsoleApplication() {
|
||||
|
||||
try (PipedOutputStream pout = new PipedOutputStream();
|
||||
PipedInputStream pis = new PipedInputStream(pout);
|
||||
BufferedReader buf = new BufferedReader(
|
||||
new InputStreamReader(pis, StandardCharsets.UTF_8));
|
||||
PipedConsoleInput in = new PipedConsoleInput(
|
||||
new PrintStream(pout))) {
|
||||
final ConsoleApplication app = new ConsoleApplication(null, in,
|
||||
"", "");
|
||||
app.exit();
|
||||
} catch (final IOException e) {
|
||||
fail("System Console Manager failed");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executionTest() {
|
||||
try {
|
||||
final PipedOutputStream src = new PipedOutputStream();
|
||||
InputStream in = new PipedInputStream(src);
|
||||
public void testExecution() throws IOException, InterruptedException,
|
||||
InvalidCommandName {
|
||||
try (CommandTestingApplication application = new CommandTestingApplication()) {
|
||||
|
||||
final PipedInputStream snk = new PipedInputStream();
|
||||
PrintStream out = new PrintStream(new PipedOutputStream(snk));
|
||||
final ConsoleTestApplication app = new ConsoleTestApplication(
|
||||
new SystemConsoleManager(System.out, in));
|
||||
Thread th = new Thread(new Runnable() {
|
||||
// remove welcome
|
||||
assertEquals("Header should be preserved",
|
||||
application.getApplication().header,
|
||||
application.readNextLine());
|
||||
// Remove first prompt
|
||||
application.sendCommand("");
|
||||
application.sendCommand("test");
|
||||
assertEquals("Test should run", "Test command ran fine",
|
||||
application.readNextLine());
|
||||
application.sendCommand("toto");
|
||||
assertEquals("Command fail should dispaly appropriate message",
|
||||
Messages.getString("ConsoleApplication.cmd.failed", "toto"),
|
||||
application.readNextLine());
|
||||
assertEquals(
|
||||
"Unrecognized comment should result in a specific message.",
|
||||
Messages.getString("CommandProvider.unrecognized", "toto"),
|
||||
application.readNextLine());
|
||||
application.sendCommand("long");
|
||||
assertEquals("Before wait should receive message", "Waita minute",
|
||||
application.readNextLine());
|
||||
assertEquals("Unexpected message", "done!",
|
||||
application.readNextLine());
|
||||
|
||||
final CommandRequestListener crl = new CommandRequestListener() {
|
||||
|
||||
@Override
|
||||
public void commandRequest(final String command) {
|
||||
//
|
||||
}
|
||||
};
|
||||
final CommandRequestListener crl2 = new CommandRequestListener() {
|
||||
|
||||
@Override
|
||||
public void commandRequest(final String command) {
|
||||
//
|
||||
}
|
||||
};
|
||||
application.getApplication().addListener(crl);
|
||||
application.getApplication().addListener(crl2);
|
||||
application.sendCommand("test");
|
||||
assertEquals("Unexpected message", "Test command ran fine",
|
||||
application.readNextLine());
|
||||
application.getApplication().removeListener(crl2);
|
||||
application.getApplication().removeListener(crl);
|
||||
application.getApplication().removeListener(crl);
|
||||
|
||||
assertTrue("Unclosed application should be running",
|
||||
application.getApplication().isRunning());
|
||||
|
||||
application.sendCommand("exit");
|
||||
assertEquals("Footer should be preserved",
|
||||
application.getApplication().footer,
|
||||
application.readNextLine());
|
||||
assertFalse("Stopped application should not be running",
|
||||
application.getApplication().isRunning());
|
||||
}
|
||||
|
||||
ConsoleApplication appli = null;
|
||||
try (PipedConsoleOutput manager = new PipedConsoleOutput();
|
||||
PipedOutputStream pout = new PipedOutputStream();
|
||||
PipedInputStream pis = new PipedInputStream(pout);
|
||||
BufferedReader buf = new BufferedReader(
|
||||
new InputStreamReader(pis, StandardCharsets.UTF_8));
|
||||
PipedConsoleInput in = new PipedConsoleInput(
|
||||
new PrintStream(pout))) {
|
||||
final ConsoleApplication app = new ConsoleApplication(manager, in,
|
||||
null, null);
|
||||
appli = app;
|
||||
app.add(new ExitCommand("exit", app));
|
||||
|
||||
final Thread th = new Thread(new Runnable() {
|
||||
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
app.start();
|
||||
}
|
||||
});
|
||||
|
||||
th.start();
|
||||
in.type("exit");
|
||||
th.join();
|
||||
}
|
||||
|
||||
Thread test = new Thread(new Runnable() {
|
||||
assertNotNull(
|
||||
"Application should still exist even if the console input and output are closed.",
|
||||
appli);
|
||||
appli.start();
|
||||
assertFalse(
|
||||
"Application should not start on closed console input and output",
|
||||
appli.isRunning());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterpretCommand() throws InvalidCommandName, IOException {
|
||||
try (PipedConsoleInput test = new PipedConsoleInput(null);
|
||||
PipedConsoleOutput out = new PipedConsoleOutput()) {
|
||||
final ConsoleApplication appl = new ConsoleApplication(out, test,
|
||||
"", "");
|
||||
|
||||
appl.interpretCommand("invalid cmd \"due to misplaced\"quote");
|
||||
assertEquals("Specific error message expected",
|
||||
"Command line cannot be parsed", out.readNextLine());
|
||||
|
||||
appl.interpretCommand("");
|
||||
|
||||
final String message = "message";
|
||||
appl.add(new ICommand() {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.
|
||||
* manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
throw new CommandRunException(CommandRunExceptionType.USAGE,
|
||||
message, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try (PrintWriter writer = new PrintWriter(src, true)) {
|
||||
writer.println("test");
|
||||
writer.println("toto");
|
||||
writer.println("long");
|
||||
writer.println("exit");
|
||||
}
|
||||
public String getCommandName() {
|
||||
return "fail";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void help(final ConsoleOutput manager,
|
||||
final String... args) throws IOException {
|
||||
manager.println(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "";
|
||||
}
|
||||
|
||||
});
|
||||
test.start();
|
||||
try {
|
||||
th.join();
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
test.join();
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
fail("pipe creation"); //$NON-NLS-1$
|
||||
appl.interpretCommand("fail");
|
||||
assertEquals("Unexpected message",
|
||||
Messages.getString("ConsoleApplication.cmd.failed", "fail"),
|
||||
out.readNextLine());
|
||||
assertEquals("Unexpected message", message, out.readNextLine());
|
||||
assertEquals("Unexpected message", message, out.readNextLine());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,18 +36,18 @@ package fr.bigeon.gclc;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.command.Command;
|
||||
import fr.bigeon.gclc.command.ExitCommand;
|
||||
import fr.bigeon.gclc.command.HelpExecutor;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
|
||||
/** A test-purpose application
|
||||
*
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class ConsoleTestApplication extends ConsoleApplication {
|
||||
public class ConsoleTestApplication implements ApplicationAttachement {
|
||||
|
||||
/** Exit command */
|
||||
public static final String EXIT = "exit"; //$NON-NLS-1$
|
||||
@@ -55,14 +55,30 @@ public class ConsoleTestApplication extends ConsoleApplication {
|
||||
protected static final long TWO_SECONDS = 2000;
|
||||
|
||||
/** @param manager the manager */
|
||||
@Override
|
||||
@SuppressWarnings("nls")
|
||||
public ConsoleTestApplication(final ConsoleManager manager) {
|
||||
super(manager, "Welcome to the test application. Type help or test.",
|
||||
"See you");
|
||||
public void attach(final ConsoleApplication application) {
|
||||
try {
|
||||
add(new ExitCommand(EXIT, this));
|
||||
add(new HelpExecutor("help", manager, this.getRoot()));
|
||||
add(new Command("test") {
|
||||
application.add(new ExitCommand(EXIT, application));
|
||||
application.add(new HelpExecutor("help",
|
||||
application.root));
|
||||
application.add(new Command("test") {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.
|
||||
* manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
try {
|
||||
out.println("Test command ran fine");
|
||||
} catch (final IOException e) {
|
||||
throw new CommandRunException("manager closed", e,
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
@@ -70,15 +86,31 @@ public class ConsoleTestApplication extends ConsoleApplication {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String... args) throws CommandRunException {
|
||||
try {
|
||||
manager.println("Test command ran fine");
|
||||
} catch (IOException e) {
|
||||
throw new CommandRunException("manager closed", e);
|
||||
}
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
add(new Command("long") {
|
||||
application.add(new Command("long") {
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.
|
||||
* manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
try {
|
||||
out.println("Waita minute");
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
out.println("done!");
|
||||
} catch (final IOException e) {
|
||||
throw new CommandRunException("manager closed", e,
|
||||
this);
|
||||
} catch (final InterruptedException e) {
|
||||
throw new CommandRunException("wait interrupted", e,
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
@@ -86,16 +118,30 @@ public class ConsoleTestApplication extends ConsoleApplication {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String... args) throws CommandRunException {
|
||||
try {
|
||||
manager.println("Waita minute");
|
||||
Thread.sleep(TWO_SECONDS);
|
||||
manager.println("done!");
|
||||
} catch (IOException e) {
|
||||
throw new CommandRunException("manager closed", e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new CommandRunException("wait interrupted", e);
|
||||
}
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
application.add(new Command("failingCmd") {
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.
|
||||
* manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||
* java.lang.String[]) */
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
throw new CommandRunException("Failing command", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "A long execution command";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (final InvalidCommandName e) {
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
*/
|
||||
package fr.bigeon.gclc;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@@ -53,84 +54,74 @@ import fr.bigeon.gclc.exception.CommandParsingException;
|
||||
@SuppressWarnings({"nls", "static-method"})
|
||||
public class GCLCConstantsTest {
|
||||
|
||||
/**
|
||||
* Test method for {@link fr.bigeon.gclc.GCLCConstants#splitCommand(java.lang.String)}.
|
||||
*/
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.GCLCConstants#splitCommand(java.lang.String)}.
|
||||
*
|
||||
* @throws CommandParsingException if an error occured */
|
||||
@Test
|
||||
public void testSplitCommand() {
|
||||
public void testSplitCommand() throws CommandParsingException {
|
||||
List<String> res;
|
||||
try {
|
||||
res = GCLCConstants.splitCommand("aCommand");
|
||||
} catch (CommandParsingException e) {
|
||||
fail("Unable to parse simple command"); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
assertTrue(res.size() == 1);
|
||||
assertTrue(res.get(0).equals("aCommand"));
|
||||
res = GCLCConstants.splitCommand("aCommand");
|
||||
assertTrue("single word command should have one element",
|
||||
res.size() == 1);
|
||||
assertTrue("Command should be preserved",
|
||||
res.get(0).equals("aCommand"));
|
||||
|
||||
res = GCLCConstants.splitCommand("aCommand with some arguments");
|
||||
assertEquals("Command size", 4, res.size());
|
||||
assertEquals("Elements should be preserved", "aCommand", res.get(0));
|
||||
assertTrue("Elements should be preserved", res.get(1).equals("with"));
|
||||
assertTrue("Elements should be preserved", res.get(2).equals("some"));
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(3).equals("arguments"));
|
||||
res = GCLCConstants.splitCommand("aCommand with some arguments");
|
||||
assertEquals("Command size", 4, res.size());
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(0).equals("aCommand"));
|
||||
assertTrue("Elements should be preserved", res.get(1).equals("with"));
|
||||
assertTrue("Elements should be preserved", res.get(2).equals("some"));
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(3).equals("arguments"));
|
||||
res = GCLCConstants.splitCommand("aCommand \"with some\" arguments");
|
||||
assertEquals("Command size", 3, res.size());
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(0).equals("aCommand"));
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(1).equals("with some"));
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(2).equals("arguments"));
|
||||
res = GCLCConstants.splitCommand("aCommand with\\ some arguments");
|
||||
assertEquals("Command size", 3, res.size());
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(0).equals("aCommand"));
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(1).equals("with some"));
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(2).equals("arguments"));
|
||||
res = GCLCConstants.splitCommand("aCommand wi\\\"th some arguments");
|
||||
assertEquals("Command size", 4, res.size());
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(0).equals("aCommand"));
|
||||
assertTrue("Elements should be preserved", res.get(1).equals("wi\"th"));
|
||||
assertTrue("Elements should be preserved", res.get(2).equals("some"));
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(3).equals("arguments"));
|
||||
|
||||
res = GCLCConstants.splitCommand("aCommand with \"some arguments\"");
|
||||
assertEquals("Command size", 3, res.size());
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(0).equals("aCommand"));
|
||||
assertTrue("Elements should be preserved", res.get(1).equals("with"));
|
||||
assertTrue("Elements should be preserved",
|
||||
res.get(2).equals("some arguments"));
|
||||
|
||||
try {
|
||||
res = GCLCConstants.splitCommand("aCommand with some arguments");
|
||||
} catch (CommandParsingException e) {
|
||||
fail("Unable to parse command with arguments"); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
assertTrue(res.size() == 4);
|
||||
assertTrue(res.get(0).equals("aCommand"));
|
||||
assertTrue(res.get(1).equals("with"));
|
||||
assertTrue(res.get(2).equals("some"));
|
||||
assertTrue(res.get(3).equals("arguments"));
|
||||
try {
|
||||
res = GCLCConstants.splitCommand("aCommand with some arguments");
|
||||
} catch (CommandParsingException e) {
|
||||
fail("Unable to parse command with arguments and double whitspaces"); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
assertTrue(res.size() == 4);
|
||||
assertTrue(res.get(0).equals("aCommand"));
|
||||
assertTrue(res.get(1).equals("with"));
|
||||
assertTrue(res.get(2).equals("some"));
|
||||
assertTrue(res.get(3).equals("arguments"));
|
||||
try {
|
||||
res = GCLCConstants
|
||||
.splitCommand("aCommand \"with some\" arguments");
|
||||
} catch (CommandParsingException e) {
|
||||
fail("Unable to parse command with string argument"); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
assertTrue(res.size() == 3);
|
||||
assertTrue(res.get(0).equals("aCommand"));
|
||||
assertTrue(res.get(1).equals("with some"));
|
||||
assertTrue(res.get(2).equals("arguments"));
|
||||
try {
|
||||
res = GCLCConstants.splitCommand("aCommand with\\ some arguments");
|
||||
} catch (CommandParsingException e) {
|
||||
fail("Unable to parse command with arguments with escaped whitspaces"); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
assertTrue(res.size() == 3);
|
||||
assertTrue(res.get(0).equals("aCommand"));
|
||||
assertTrue(res.get(1).equals("with some"));
|
||||
assertTrue(res.get(2).equals("arguments"));
|
||||
try {
|
||||
res = GCLCConstants
|
||||
.splitCommand("aCommand wi\\\"th some arguments");
|
||||
} catch (CommandParsingException e) {
|
||||
fail("Unable to parse command with string argument"); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
assertTrue(res.size() == 4);
|
||||
assertTrue(res.get(0).equals("aCommand"));
|
||||
assertTrue(res.get(1).equals("wi\"th"));
|
||||
assertTrue(res.get(2).equals("some"));
|
||||
assertTrue(res.get(3).equals("arguments"));
|
||||
|
||||
// Wrong lines?
|
||||
try {
|
||||
// Wrong lines?
|
||||
res = GCLCConstants
|
||||
.splitCommand("aCommand with \"some ar\"guments");
|
||||
fail("Parsing argument with string cut");
|
||||
} catch (CommandParsingException e) {
|
||||
// OK
|
||||
fail("Misplaced quotes should fail");
|
||||
} catch (final CommandParsingException e) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* 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.CommandParametersTest.java
|
||||
* Created on: Nov 18, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandParsingException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
@SuppressWarnings({"static-method", "nls"})
|
||||
public class CommandParametersTest {
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.CommandParameters#CommandParameters(java.util.Set, java.util.Set, boolean)}.
|
||||
*
|
||||
* @throws CommandParsingException if an unexpected exception is thrown */
|
||||
@Test
|
||||
public final void testCommandParameters() throws CommandParsingException {
|
||||
final Set<String> strings = new HashSet<>();
|
||||
final Set<String> bools = new HashSet<>();
|
||||
CommandParameters parameters = new CommandParameters(bools, strings,
|
||||
true);
|
||||
|
||||
try {
|
||||
parameters.parseArgs("-ungivenFlag");
|
||||
fail("parse of unknown in strict should fail");
|
||||
} catch (final CommandParsingException e) {
|
||||
// ok
|
||||
}
|
||||
parameters = new CommandParameters(bools, strings, false);
|
||||
|
||||
parameters.parseArgs("-ungivenFlag");
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.CommandParameters#get(java.lang.String)}.
|
||||
*
|
||||
* @throws CommandParsingException if an exception occired */
|
||||
@Test
|
||||
public final void testGet() throws CommandParsingException {
|
||||
final Set<String> strings = new HashSet<>();
|
||||
final Set<String> bools = new HashSet<>();
|
||||
|
||||
bools.add("boolFlag");
|
||||
strings.add("str");
|
||||
|
||||
final CommandParameters parameters = new CommandParameters(bools,
|
||||
strings, true);
|
||||
|
||||
assertNull(parameters.get("ungiven"));
|
||||
assertNull(parameters.get("str"));
|
||||
|
||||
try {
|
||||
parameters.parseArgs("-ungiven", "val");
|
||||
fail("Missing parameter should fail for strict element");
|
||||
} catch (final CommandParsingException e) {
|
||||
// ok
|
||||
}
|
||||
assertNull(parameters.get("ungiven"));
|
||||
assertNull(parameters.get("str"));
|
||||
|
||||
parameters.parseArgs("-str", "val");
|
||||
assertNull(parameters.get("ungiven"));
|
||||
assertEquals("val", parameters.get("str"));
|
||||
|
||||
try {
|
||||
parameters.parseArgs("-ungiven");
|
||||
fail("Invalid argument type parsing should fail");
|
||||
} catch (final CommandParsingException e) {
|
||||
// ok
|
||||
}
|
||||
assertNull(parameters.get("ungiven"));
|
||||
assertEquals("val", parameters.get("str"));
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.CommandParameters#getAdditionals()}. */
|
||||
@Test
|
||||
public final void testGetAdditionals() throws CommandParsingException {
|
||||
final Set<String> strings = new HashSet<>();
|
||||
final Set<String> bools = new HashSet<>();
|
||||
|
||||
bools.add("boolFlag");
|
||||
strings.add("str");
|
||||
|
||||
CommandParameters parameters = new CommandParameters(bools, strings,
|
||||
true);
|
||||
|
||||
parameters.parseArgs("-boolFlag");
|
||||
assertTrue(parameters.getAdditionals().isEmpty());
|
||||
|
||||
try {
|
||||
parameters.parseArgs("-ungiven");
|
||||
fail("Should fail");
|
||||
} catch (final CommandParsingException e) {
|
||||
// ok
|
||||
}
|
||||
assertTrue(parameters.getAdditionals().isEmpty());
|
||||
|
||||
parameters = new CommandParameters(bools, strings, false);
|
||||
|
||||
parameters.parseArgs("-boolFlag");
|
||||
assertTrue(parameters.getAdditionals().isEmpty());
|
||||
|
||||
parameters.parseArgs("-ungiven");
|
||||
assertTrue(parameters.getAdditionals().contains("ungiven"));
|
||||
assertEquals(1, parameters.getAdditionals().size());
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.CommandParameters#getBool(java.lang.String)}.
|
||||
*
|
||||
* @throws CommandParsingException */
|
||||
@Test
|
||||
public final void testGetBool() throws CommandParsingException {
|
||||
final Set<String> strings = new HashSet<>();
|
||||
final Set<String> bools = new HashSet<>();
|
||||
|
||||
bools.add("boolFlag");
|
||||
strings.add("str");
|
||||
|
||||
CommandParameters parameters = new CommandParameters(bools, strings,
|
||||
true);
|
||||
|
||||
assertFalse(parameters.getBool("ungiven"));
|
||||
assertFalse(parameters.getBool("boolFlag"));
|
||||
|
||||
parameters.parseArgs("-boolFlag");
|
||||
assertTrue(parameters.getBool("boolFlag"));
|
||||
assertFalse(parameters.getBool("ungiven"));
|
||||
|
||||
try {
|
||||
parameters.parseArgs("-ungiven");
|
||||
fail("unknown parameter should fail");
|
||||
} catch (final CommandParsingException e) {
|
||||
// ok
|
||||
}
|
||||
assertFalse(parameters.getBool("ungiven"));
|
||||
assertTrue(parameters.getBool("boolFlag"));
|
||||
|
||||
parameters = new CommandParameters(bools, strings, false);
|
||||
|
||||
assertFalse(parameters.getBool("ungiven"));
|
||||
assertFalse(parameters.getBool("boolFlag"));
|
||||
|
||||
try {
|
||||
parameters.parseArgs("-boolFlag");
|
||||
} catch (final CommandParsingException e) {
|
||||
// ok
|
||||
}
|
||||
assertTrue(parameters.getBool("boolFlag"));
|
||||
assertFalse(parameters.getBool("ungiven"));
|
||||
|
||||
try {
|
||||
parameters.parseArgs("-ungiven");
|
||||
} catch (final CommandParsingException e) {
|
||||
// ok
|
||||
}
|
||||
assertFalse(parameters.getBool("ungiven"));
|
||||
assertTrue(parameters.getBool("boolFlag"));
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.CommandParameters#parseArgs(java.lang.String[])}.
|
||||
*
|
||||
* @throws CommandParsingException */
|
||||
@Test
|
||||
public final void testParseArgs() throws CommandParsingException {
|
||||
final Set<String> strings = new HashSet<>();
|
||||
final Set<String> bools = new HashSet<>();
|
||||
|
||||
bools.add("boolFlag");
|
||||
strings.add("str");
|
||||
|
||||
final CommandParameters parameters = new CommandParameters(bools,
|
||||
strings, true);
|
||||
|
||||
try {
|
||||
parameters.parseArgs("-ungivenFlag");
|
||||
fail("Strict should fail with flag");
|
||||
} catch (final CommandParsingException e) {
|
||||
// ok
|
||||
}
|
||||
try {
|
||||
parameters.parseArgs("-str");
|
||||
fail("String argument without second element should fail");
|
||||
} catch (final CommandParsingException e) {
|
||||
// ok
|
||||
}
|
||||
parameters.parseArgs("-boolFlag");
|
||||
parameters.parseArgs("-str", "-boolFlag");
|
||||
parameters.parseArgs("-boolFlag", "-str", "val");
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.CommandParameters#set(java.lang.String, boolean)}. */
|
||||
@Test
|
||||
public final void testSetStringBoolean() {
|
||||
final Set<String> strings = new HashSet<>();
|
||||
final Set<String> bools = new HashSet<>();
|
||||
|
||||
bools.add("boolFlag");
|
||||
strings.add("str");
|
||||
|
||||
CommandParameters parameters = new CommandParameters(bools, strings,
|
||||
true);
|
||||
|
||||
assertFalse(parameters.getBool("ungiven"));
|
||||
assertFalse(parameters.getBool("boolFlag"));
|
||||
|
||||
parameters.set("boolFlag", true);
|
||||
assertTrue(parameters.getBool("boolFlag"));
|
||||
assertFalse(parameters.getBool("ungiven"));
|
||||
|
||||
parameters.set("ungiven", true);
|
||||
assertFalse(parameters.getBool("ungiven"));
|
||||
assertTrue(parameters.getBool("boolFlag"));
|
||||
|
||||
parameters = new CommandParameters(bools, strings, false);
|
||||
|
||||
assertFalse(parameters.getBool("ungiven"));
|
||||
assertFalse(parameters.getBool("boolFlag"));
|
||||
|
||||
parameters.set("boolFlag", true);
|
||||
assertTrue(parameters.getBool("boolFlag"));
|
||||
assertFalse(parameters.getBool("ungiven"));
|
||||
|
||||
parameters.set("ungiven", true);
|
||||
assertFalse(parameters.getBool("ungiven"));
|
||||
assertTrue(parameters.getBool("boolFlag"));
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.CommandParameters#set(java.lang.String, java.lang.String)}. */
|
||||
@Test
|
||||
public final void testSetStringString() {
|
||||
final Set<String> strings = new HashSet<>();
|
||||
final Set<String> bools = new HashSet<>();
|
||||
|
||||
bools.add("boolFlag");
|
||||
strings.add("str");
|
||||
|
||||
CommandParameters parameters = new CommandParameters(bools, strings,
|
||||
true);
|
||||
|
||||
assertNull(parameters.get("ungiven"));
|
||||
assertNull(parameters.get("str"));
|
||||
|
||||
parameters.set("ungiven", "val");
|
||||
assertNull(parameters.get("ungiven"));
|
||||
assertNull(parameters.get("str"));
|
||||
|
||||
parameters.set("str", "val");
|
||||
assertNull(parameters.get("ungiven"));
|
||||
assertEquals("val", parameters.get("str"));
|
||||
|
||||
parameters.set("ungiven", "val");
|
||||
assertNull(parameters.get("ungiven"));
|
||||
assertEquals("val", parameters.get("str"));
|
||||
|
||||
parameters = new CommandParameters(bools, strings, false);
|
||||
|
||||
assertNull(parameters.get("ungiven"));
|
||||
assertNull(parameters.get("str"));
|
||||
|
||||
parameters.set("ungiven", "val");
|
||||
assertNull(parameters.get("ungiven"));
|
||||
assertNull(parameters.get("str"));
|
||||
|
||||
parameters.set("str", "val");
|
||||
assertNull(parameters.get("ungiven"));
|
||||
assertEquals("val", parameters.get("str"));
|
||||
|
||||
parameters.set("ungiven", "val");
|
||||
assertNull(parameters.get("ungiven"));
|
||||
assertEquals("val", parameters.get("str"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.CommandProviderTest.java
|
||||
* Created on: Nov 19, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class CommandProviderTest {
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.CommandProvider#add(fr.bigeon.gclc.command.ICommand)}.
|
||||
*
|
||||
* @throws InvalidCommandName */
|
||||
@Test
|
||||
public final void testAdd() throws InvalidCommandName {
|
||||
final CommandProvider provider = new CommandProvider();
|
||||
try {
|
||||
provider.add(new MockCommand(null));
|
||||
fail("null name for command should be rejected");
|
||||
} catch (final InvalidCommandName e) {
|
||||
// ok
|
||||
}
|
||||
try {
|
||||
provider.add(new MockCommand(""));
|
||||
fail("null name for command should be rejected");
|
||||
} catch (final InvalidCommandName e) {
|
||||
// ok
|
||||
}
|
||||
try {
|
||||
provider.add(new MockCommand("-name"));
|
||||
fail("name with minus as starting character for command should be rejected");
|
||||
} catch (final InvalidCommandName e) {
|
||||
// ok
|
||||
}
|
||||
try {
|
||||
provider.add(new MockCommand("name command"));
|
||||
fail("name with space for command should be rejected");
|
||||
} catch (final InvalidCommandName e) {
|
||||
// ok
|
||||
}
|
||||
final ICommand mock = new MockCommand("name");
|
||||
provider.add(mock);
|
||||
|
||||
try {
|
||||
provider.add(new MockCommand(mock.getCommandName()));
|
||||
fail("already existing command name should be rejected");
|
||||
} catch (final InvalidCommandName e) {
|
||||
// ok
|
||||
}
|
||||
|
||||
provider.add(mock);
|
||||
}
|
||||
|
||||
}
|
||||
376
gclc/src/test/java/fr/bigeon/gclc/command/CommandTest.java
Normal file
376
gclc/src/test/java/fr/bigeon/gclc/command/CommandTest.java
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* 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.CommandTest.java
|
||||
* Created on: Nov 19, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||
|
||||
/** <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class CommandTest {
|
||||
|
||||
@Test
|
||||
public final void testCommand() throws IOException {
|
||||
try (PipedConsoleOutput test = new PipedConsoleOutput()) {
|
||||
Command cmd;
|
||||
cmd = new Command("name") {
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
cmd.help(test);
|
||||
|
||||
// name
|
||||
assertEquals("First line should be command name", "name",
|
||||
test.readNextLine());
|
||||
// tip
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
// Usage
|
||||
test.readNextLine();
|
||||
// details
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
assertFalse("Only 6 line should be printed", test.available());
|
||||
|
||||
cmd = new Command("name") {
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
cmd.help(test);
|
||||
// name
|
||||
assertEquals("First line should be command name", "name",
|
||||
test.readNextLine());
|
||||
// tip
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
// Usage
|
||||
test.readNextLine();
|
||||
// details
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
assertFalse("Only 6 line should be printed", test.available());
|
||||
|
||||
cmd = new Command("name") {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#brief() */
|
||||
@Override
|
||||
protected String brief() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "tip";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
cmd.help(test);
|
||||
// name
|
||||
assertEquals("First line should be command name", "name",
|
||||
test.readNextLine());
|
||||
// tip
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
// Usage
|
||||
test.readNextLine();
|
||||
// details
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
assertFalse("Only 6 line should be printed", test.available());
|
||||
|
||||
cmd = new Command("name") {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#brief() */
|
||||
@Override
|
||||
protected String brief() {
|
||||
return "brief";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "tip";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
cmd.help(test);
|
||||
// name
|
||||
assertEquals("First line should be command name", "name",
|
||||
test.readNextLine());
|
||||
// tip
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
// Usage
|
||||
test.readNextLine();
|
||||
// details
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
assertFalse("Only 6 line should be printed", test.available());
|
||||
|
||||
cmd = new Command("name") {
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "tip";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
cmd.help(test);
|
||||
// name
|
||||
assertEquals("First line should be command name", "name",
|
||||
test.readNextLine());
|
||||
// tip
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
// Usage
|
||||
test.readNextLine();
|
||||
// details
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
assertFalse("Only 6 line should be printed", test.available());
|
||||
|
||||
cmd = new Command("name") {
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "tip";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return "details";
|
||||
}
|
||||
};
|
||||
cmd.help(test);
|
||||
|
||||
// name
|
||||
assertEquals("First line should be command name", "name",
|
||||
test.readNextLine());
|
||||
// tip
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
// Usage
|
||||
test.readNextLine();
|
||||
// pattern
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
// details
|
||||
assertEquals("Unexpected detail", "details", test.readNextLine());
|
||||
assertFalse("Only 6 line should be printed", test.available());
|
||||
|
||||
cmd = new Command("name") {
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "tip";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return "details" + System.lineSeparator();
|
||||
}
|
||||
};
|
||||
cmd.help(test);
|
||||
// name
|
||||
assertEquals("First line should be command name", "name",
|
||||
test.readNextLine());
|
||||
// tip
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
// Usage
|
||||
test.readNextLine();
|
||||
// pattern
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
// details
|
||||
assertEquals("Unexpected detail", "details", test.readNextLine());
|
||||
assertFalse("Only 6 line should be printed", test.available());
|
||||
|
||||
cmd = new Command("name") {
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "tip";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return "\n";
|
||||
}
|
||||
};
|
||||
cmd.help(test);
|
||||
// name
|
||||
assertEquals("First line should be command name", "name",
|
||||
test.readNextLine());
|
||||
// tip
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
// Usage
|
||||
test.readNextLine();
|
||||
// pattern
|
||||
test.readNextLine();
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
//
|
||||
assertTrue("Section line is empty", test.readNextLine().isEmpty());
|
||||
assertFalse("Only 6 line should be printed", test.available());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
118
gclc/src/test/java/fr/bigeon/gclc/command/HelpExecutorTest.java
Normal file
118
gclc/src/test/java/fr/bigeon/gclc/command/HelpExecutorTest.java
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.HelpExecutorTest.java
|
||||
* Created on: Nov 19, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class HelpExecutorTest {
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.HelpExecutor#execute(java.lang.String[])}.
|
||||
*
|
||||
* @throws CommandRunException
|
||||
* @throws IOException */
|
||||
@Test
|
||||
public final void testExecute() throws CommandRunException, IOException {
|
||||
final PipedConsoleOutput test = new PipedConsoleOutput();
|
||||
final HelpExecutor help = new HelpExecutor("?", new Command("mock") {
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
help.execute(test, null);
|
||||
test.close();
|
||||
|
||||
try {
|
||||
help.execute(test, null);
|
||||
fail("manager closed shall provoke failure of help command execution");
|
||||
} catch (final Exception e) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
|
||||
/** Test method for {@link fr.bigeon.gclc.command.HelpExecutor#tip()}.
|
||||
*
|
||||
* @throws IOException */
|
||||
@Test
|
||||
public final void testTip() throws IOException {
|
||||
try (PipedConsoleOutput test = new PipedConsoleOutput()) {
|
||||
final HelpExecutor help = new HelpExecutor("?",
|
||||
new MockCommand("mock"));
|
||||
assertNotNull("Tip should be provided", help.tip());
|
||||
help.help(test);
|
||||
}
|
||||
try (PipedConsoleOutput test = new PipedConsoleOutput()) {
|
||||
final HelpExecutor help = new HelpExecutor("?",
|
||||
new SubedCommand("sub", new MockCommand("mock")));
|
||||
help.tip();
|
||||
help.help(test);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,684 @@
|
||||
/*
|
||||
* 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.ParametrizedCommandTest.java
|
||||
* Created on: Nov 18, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.InvalidParameterException;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleInput;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class ParametrizedCommandTest {
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.ParametrizedCommand#addParameter(java.lang.String, boolean, boolean)}.
|
||||
*
|
||||
* @throws InvalidParameterException */
|
||||
@Test
|
||||
public final void testAddParameter() throws InvalidParameterException {
|
||||
ParametrizedCommand cmd = new ParametrizedCommand("name") {
|
||||
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
cmd = new ParametrizedCommand("name", true) {
|
||||
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
// XXX Boolean flag should not be specified mandatory! They are by
|
||||
// nature qualified
|
||||
final String str = "str";
|
||||
assertTrue(cmd.getBooleanParameters().isEmpty());
|
||||
assertTrue(cmd.getStringParameters().isEmpty());
|
||||
cmd.addBooleanParameter("boolFlag");
|
||||
assertEquals(1, cmd.getBooleanParameters().size());
|
||||
assertTrue(cmd.getStringParameters().isEmpty());
|
||||
cmd.addStringParameter(str, false);
|
||||
assertEquals(1, cmd.getBooleanParameters().size());
|
||||
assertEquals(1, cmd.getStringParameters().size());
|
||||
assertFalse(cmd.isNeeded(str));
|
||||
cmd.addBooleanParameter("boolFlag");
|
||||
assertEquals(1, cmd.getBooleanParameters().size());
|
||||
assertEquals(1, cmd.getStringParameters().size());
|
||||
cmd.addStringParameter(str, true);
|
||||
assertEquals(1, cmd.getBooleanParameters().size());
|
||||
assertEquals(1, cmd.getStringParameters().size());
|
||||
assertTrue(cmd.isNeeded(str));
|
||||
cmd.addStringParameter(str, false);
|
||||
assertEquals(1, cmd.getBooleanParameters().size());
|
||||
assertEquals(1, cmd.getStringParameters().size());
|
||||
assertTrue(cmd.isNeeded(str));
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.ParametrizedCommand#execute(java.lang.String[])}.
|
||||
*
|
||||
* @throws CommandRunException
|
||||
* @throws InterruptedException
|
||||
* @throws IOException */
|
||||
@Test
|
||||
public final void testExecute() throws CommandRunException,
|
||||
InterruptedException, IOException {
|
||||
final String addParam = "additional";
|
||||
final String str1 = "str1";
|
||||
final String str2 = "str2";
|
||||
final String bool1 = "bool1";
|
||||
final String bool2 = "bool2";
|
||||
|
||||
// Test on command with no needed elements
|
||||
ParametrizedCommand cmd = new ParametrizedCommand("name", false) {
|
||||
private boolean evenCall = true;
|
||||
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
assertTrue(parameters.getBooleanArgumentKeys().isEmpty());
|
||||
assertTrue(parameters.getStringArgumentKeys().isEmpty());
|
||||
if (evenCall) {
|
||||
assertTrue(parameters.getAdditionals().isEmpty());
|
||||
evenCall = false;
|
||||
} else {
|
||||
assertEquals(1, parameters.getAdditionals().size());
|
||||
assertTrue(parameters.getAdditionals().contains(addParam));
|
||||
evenCall = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
cmd.execute(null, null);
|
||||
cmd.execute(null, null, "-" + addParam);
|
||||
cmd.execute(null, null, addParam);
|
||||
cmd.execute(null, null, "-" + addParam, addParam);
|
||||
cmd = new ParametrizedCommand("name", false) {
|
||||
private int call = 0;
|
||||
{
|
||||
|
||||
try {
|
||||
addStringParameter(str1, false);
|
||||
addStringParameter(str2, false);
|
||||
addBooleanParameter(bool1);
|
||||
addBooleanParameter(bool2);
|
||||
} catch (final InvalidParameterException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
assertEquals(2, parameters.getBooleanArgumentKeys().size());
|
||||
assertEquals(2, parameters.getStringArgumentKeys().size());
|
||||
switch (call) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
assertNull(parameters.get(str1));
|
||||
assertNull(parameters.get(str2));
|
||||
assertFalse(parameters.getBool(bool1));
|
||||
assertFalse(parameters.getBool(bool2));
|
||||
call++;
|
||||
break;
|
||||
case 4:
|
||||
assertEquals(str2, parameters.get(str1));
|
||||
assertNull(parameters.get(str2));
|
||||
assertFalse(parameters.getBool(bool1));
|
||||
assertFalse(parameters.getBool(bool2));
|
||||
call++;
|
||||
break;
|
||||
case 5:
|
||||
assertEquals(str2, parameters.get(str1));
|
||||
assertNull(parameters.get(str2));
|
||||
assertTrue(parameters.getBool(bool1));
|
||||
assertFalse(parameters.getBool(bool2));
|
||||
call = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
cmd.execute(null, null);
|
||||
cmd.execute(null, null, "-" + addParam);
|
||||
cmd.execute(null, null, addParam);
|
||||
cmd.execute(null, null, "-" + addParam, addParam);
|
||||
cmd.execute(null, null, "-" + str1, str2);
|
||||
cmd.execute(null, null, "-" + str1, str2, "-" + bool1);
|
||||
cmd = new ParametrizedCommand("name", true) {
|
||||
private int call = 0;
|
||||
{
|
||||
|
||||
try {
|
||||
addStringParameter(str1, false);
|
||||
addStringParameter(str2, false);
|
||||
addBooleanParameter(bool1);
|
||||
addBooleanParameter(bool2);
|
||||
} catch (final InvalidParameterException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
assertEquals(2, parameters.getBooleanArgumentKeys().size());
|
||||
assertEquals(2, parameters.getStringArgumentKeys().size());
|
||||
switch (call) {
|
||||
case 0:
|
||||
assertNull(parameters.get(str1));
|
||||
assertNull(parameters.get(str2));
|
||||
assertFalse(parameters.getBool(bool1));
|
||||
assertFalse(parameters.getBool(bool2));
|
||||
call++;
|
||||
break;
|
||||
case 1:
|
||||
assertEquals(str2, parameters.get(str1));
|
||||
assertNull(parameters.get(str2));
|
||||
assertFalse(parameters.getBool(bool1));
|
||||
assertFalse(parameters.getBool(bool2));
|
||||
call++;
|
||||
break;
|
||||
case 2:
|
||||
assertEquals(str2, parameters.get(str1));
|
||||
assertNull(parameters.get(str2));
|
||||
assertTrue(parameters.getBool(bool1));
|
||||
assertFalse(parameters.getBool(bool2));
|
||||
call = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
cmd.execute(null, null);
|
||||
cmd.execute(null, null, "-" + str1, str2);
|
||||
cmd.execute(null, null, "-" + str1, str2, "-" + bool1);
|
||||
try {
|
||||
cmd.execute(null, null, addParam);
|
||||
fail("Strict should fail with unexpected argument");
|
||||
} catch (final CommandRunException e) {
|
||||
// ok
|
||||
}
|
||||
try {
|
||||
cmd.execute(null, null, "-" + addParam);
|
||||
fail("Strict should fail with unexpected argument");
|
||||
} catch (final CommandRunException e) {
|
||||
// ok
|
||||
}
|
||||
// Test on command with missing needed elements
|
||||
cmd = new ParametrizedCommand("name", false) {
|
||||
private final int call = 0;
|
||||
{
|
||||
|
||||
try {
|
||||
addStringParameter(str1, true);
|
||||
addStringParameter(str2, false);
|
||||
addBooleanParameter(bool1);
|
||||
addBooleanParameter(bool2);
|
||||
} catch (final InvalidParameterException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
assertEquals(str2, parameters.get(str1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
cmd.execute(null, null, "-" + str1, str2);
|
||||
cmd.execute(null, null, "-" + str1, str2, "-" + bool1);
|
||||
cmd.execute(null, null, "-" + str1, str2, "-" + addParam);
|
||||
cmd.execute(null, null, "-" + str1, str2, addParam);
|
||||
cmd.execute(null, null, "-" + str1, str2, "-" + addParam, addParam);
|
||||
try {
|
||||
cmd.execute(null, null);
|
||||
fail("needed " + str1 + " not provided shall fail");
|
||||
} catch (final CommandRunException e) {
|
||||
// ok
|
||||
}
|
||||
cmd = new ParametrizedCommand("name", true) {
|
||||
private final int call = 0;
|
||||
{
|
||||
|
||||
try {
|
||||
addStringParameter(str1, true);
|
||||
addStringParameter(str2, false);
|
||||
addBooleanParameter(bool1);
|
||||
addBooleanParameter(bool2);
|
||||
} catch (final InvalidParameterException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
//
|
||||
assertEquals(str2, parameters.get(str1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
cmd.execute(null, null, "-" + str1, str2);
|
||||
cmd.execute(null, null, "-" + str1, str2, "-" + bool1);
|
||||
try {
|
||||
cmd.execute(null, null, "-" + str1, str2, addParam);
|
||||
fail("Additional parameter should cause failure");
|
||||
} catch (final CommandRunException e) {
|
||||
// ok
|
||||
}
|
||||
try {
|
||||
cmd.execute(null, null);
|
||||
fail("needed " + str1 + " not provided shall fail");
|
||||
} catch (final CommandRunException e) {
|
||||
// ok
|
||||
}
|
||||
try {
|
||||
cmd.execute(null, null, "-" + str1, str2, "-" + addParam);
|
||||
fail("unepected error");
|
||||
} catch (final CommandRunException e) {
|
||||
// ok
|
||||
}
|
||||
try {
|
||||
cmd.execute(null, null, "-" + str1, str2, "-" + addParam, addParam);
|
||||
fail("unepected error");
|
||||
} catch (final CommandRunException e) {
|
||||
// ok
|
||||
}
|
||||
// TODO Test of interactive not providing and providing all needed
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteInteractive() throws IOException,
|
||||
CommandRunException,
|
||||
InterruptedException {
|
||||
ParametrizedCommand cmd;
|
||||
final String addParam = "additional";
|
||||
final String str1 = "str1";
|
||||
final String str2 = "str2";
|
||||
final String bool1 = "bool1";
|
||||
final String bool2 = "bool2";
|
||||
|
||||
cmd = new ParametrizedCommand("name", false) {
|
||||
{
|
||||
try {
|
||||
addStringParameter(str1, true);
|
||||
addStringParameter(str2, false);
|
||||
addBooleanParameter(bool1);
|
||||
addBooleanParameter(bool2);
|
||||
} catch (final InvalidParameterException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) throws CommandRunException {
|
||||
if (!str2.equals(parameters.get(str1))) {
|
||||
throw new CommandRunException("Expected other argument",
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
try (PipedConsoleOutput out = new PipedConsoleOutput();
|
||||
PipedOutputStream pout = new PipedOutputStream();
|
||||
PipedInputStream pis = new PipedInputStream(pout);
|
||||
BufferedReader buf = new BufferedReader(
|
||||
new InputStreamReader(pis, StandardCharsets.UTF_8));
|
||||
PipedConsoleInput in = new PipedConsoleInput(
|
||||
new PrintStream(pout))) {
|
||||
cmd.execute(out, in, "-" + str1, str2);
|
||||
cmd.execute(out, in, "-" + str1, str2, "-" + bool1);
|
||||
cmd.execute(out, in, "-" + str1, str2, addParam);
|
||||
cmd.execute(out, in, "-" + str1, str2, "-" + addParam);
|
||||
cmd.execute(out, in, "-" + str1, str2, "-" + addParam, addParam);
|
||||
|
||||
final Thread th = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
assertEquals("value of " + str1 + "? ", buf.readLine());
|
||||
in.type("");
|
||||
assertEquals(
|
||||
"value of " + str1 + "? (cannot be empty) ",
|
||||
buf.readLine());
|
||||
in.type("");
|
||||
assertEquals(
|
||||
"value of " + str1 + "? (cannot be empty) ",
|
||||
buf.readLine());
|
||||
in.type(str2);
|
||||
} catch (final IOException e) {
|
||||
assertNull(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
th.start();
|
||||
|
||||
cmd.execute(out, in);
|
||||
|
||||
th.join();
|
||||
}
|
||||
try (PipedConsoleOutput out = new PipedConsoleOutput();
|
||||
PipedOutputStream pout = new PipedOutputStream();
|
||||
PipedInputStream pis = new PipedInputStream(pout);
|
||||
BufferedReader buf = new BufferedReader(
|
||||
new InputStreamReader(pis, StandardCharsets.UTF_8));
|
||||
PipedConsoleInput in = new PipedConsoleInput(
|
||||
new PrintStream(pout))) {
|
||||
|
||||
final Thread th = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
assertEquals("value of " + str1 + "? ", buf.readLine());
|
||||
in.type(str2);
|
||||
} catch (final IOException e) {
|
||||
assertNull(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
th.start();
|
||||
|
||||
cmd.execute(out, in, "-" + addParam);
|
||||
|
||||
th.join();
|
||||
}
|
||||
try {
|
||||
final PipedConsoleOutput out = new PipedConsoleOutput();
|
||||
final PipedConsoleInput test = new PipedConsoleInput(null);
|
||||
test.close();
|
||||
out.close();
|
||||
cmd.execute(out, test, "-" + str1, str2);
|
||||
cmd.execute(out, test, "-" + addParam);
|
||||
fail("Closed manager shall cause error");
|
||||
} catch (final CommandRunException e) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.ParametrizedCommand#ParametrizedCommand(fr.bigeon.gclc.manager.ConsoleManager, java.lang.String)}. */
|
||||
@Test
|
||||
public final void testParametrizedCommandConsoleManagerString() {
|
||||
ParametrizedCommand cmd = new ParametrizedCommand("name") {
|
||||
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
assertTrue(cmd.isStrict());
|
||||
cmd = new ParametrizedCommand("name") {
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
assertTrue(cmd.isStrict());
|
||||
cmd = new ParametrizedCommand("name") {
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
assertTrue(cmd.isStrict());
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.ParametrizedCommand#ParametrizedCommand(fr.bigeon.gclc.manager.ConsoleManager, java.lang.String, boolean)}. */
|
||||
@Test
|
||||
public final void testParametrizedCommandConsoleManagerStringBoolean() {
|
||||
ParametrizedCommand cmd = new ParametrizedCommand("name", false) {
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
assertFalse(cmd.isStrict());
|
||||
cmd = new ParametrizedCommand("name", false) {
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
assertFalse(cmd.isStrict());
|
||||
cmd = new ParametrizedCommand("name", false) {
|
||||
@Override
|
||||
protected void doExecute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final CommandParameters parameters) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
assertFalse(cmd.isStrict());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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.ScriptExecutionTest.java
|
||||
* Created on: Jun 12, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.ConsoleApplication;
|
||||
import fr.bigeon.gclc.ConsoleTestApplication;
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleInput;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||
|
||||
/** <p>
|
||||
* Test class for {@link ScriptExecution}
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
@SuppressWarnings("static-method")
|
||||
public class ScriptExecutionTest {
|
||||
|
||||
/**
|
||||
* Test method for {@link fr.bigeon.gclc.command.ScriptExecution#execute(java.lang.String[])}.
|
||||
*/
|
||||
@Test
|
||||
public void testExecute() {
|
||||
PipedConsoleOutput test;
|
||||
PipedConsoleInput in;
|
||||
try {
|
||||
in = new PipedConsoleInput(null);
|
||||
test = new PipedConsoleOutput();
|
||||
} catch (final IOException e2) {
|
||||
fail("creation of console manager failed"); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
final ConsoleApplication app = new ConsoleApplication(
|
||||
test, in, "", "");
|
||||
new ConsoleTestApplication().attach(app);
|
||||
final ScriptExecution exec = new ScriptExecution("script", app, "#", //$NON-NLS-1$ //$NON-NLS-2$
|
||||
Charset.forName("UTF-8"));
|
||||
try {
|
||||
exec.execute(test, in);
|
||||
fail("execution of script command with no file should fail"); //$NON-NLS-1$
|
||||
} catch (final CommandRunException e1) {
|
||||
// ok
|
||||
assertEquals(exec, e1.getSource());
|
||||
assertEquals(CommandRunExceptionType.USAGE, e1.getType());
|
||||
}
|
||||
|
||||
try {
|
||||
exec.execute(test, in,
|
||||
"src/test/resources/scripts/withprependSpace.txt"); //$NON-NLS-1$
|
||||
fail("execution of script with lines begining with space should fail"); //$NON-NLS-1$
|
||||
} catch (final CommandRunException e1) {
|
||||
// ok
|
||||
assertEquals(exec, e1.getSource());
|
||||
assertEquals(CommandRunExceptionType.EXECUTION, e1.getType());
|
||||
}
|
||||
|
||||
try {
|
||||
exec.execute(test, in,
|
||||
"src/test/resources/scripts/invalidCmdParse.txt"); //$NON-NLS-1$
|
||||
fail("execution of script with invalid command line should fail"); //$NON-NLS-1$
|
||||
} catch (final CommandRunException e1) {
|
||||
// ok
|
||||
assertEquals(exec, e1.getSource());
|
||||
assertEquals(CommandRunExceptionType.EXECUTION, e1.getType());
|
||||
}
|
||||
|
||||
try {
|
||||
exec.execute(test, in,
|
||||
"src/test/resources/scripts/invalidCmd.txt"); //$NON-NLS-1$
|
||||
fail("execution of script with invalid command should fail"); //$NON-NLS-1$
|
||||
} catch (final CommandRunException e1) {
|
||||
// ok
|
||||
assertEquals(exec, e1.getSource());
|
||||
assertEquals(CommandRunExceptionType.EXECUTION, e1.getType());
|
||||
}
|
||||
|
||||
try {
|
||||
exec.execute(test, in,
|
||||
"src/test/resources/scripts/failingCmdInvoc.txt"); //$NON-NLS-1$
|
||||
fail("execution of script with failing command should fail"); //$NON-NLS-1$
|
||||
} catch (final CommandRunException e1) {
|
||||
// ok
|
||||
assertEquals(exec, e1.getSource());
|
||||
assertEquals(CommandRunExceptionType.EXECUTION, e1.getType());
|
||||
}
|
||||
|
||||
try {
|
||||
exec.execute(test, in,
|
||||
"src/test/resources/scripts/someNonExisting.file"); //$NON-NLS-1$
|
||||
fail("execution of script with unexisting file should fail"); //$NON-NLS-1$
|
||||
} catch (final CommandRunException e1) {
|
||||
// ok
|
||||
assertEquals(exec, e1.getSource());
|
||||
assertEquals(CommandRunExceptionType.EXECUTION, e1.getType());
|
||||
}
|
||||
|
||||
try {
|
||||
exec.execute(test, in, "src/test/resources/script1.txt"); //$NON-NLS-1$
|
||||
exec.execute(test, in, "src/test/resources/script2.txt"); //$NON-NLS-1$
|
||||
exec.execute(test, in, "src/test/resources/script3.txt"); //$NON-NLS-1$
|
||||
exec.execute(test, in, "src/test/resources/script4.txt"); //$NON-NLS-1$
|
||||
exec.execute(test, in, "src/test/resources/script5.txt", "test"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
} catch (final CommandRunException e) {
|
||||
e.printStackTrace();
|
||||
fail("execution of wellformed script should not fail"); //$NON-NLS-1$
|
||||
}
|
||||
try {
|
||||
test.close();
|
||||
} catch (final IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.ScriptExecution#help(fr.bigeon.gclc.manager.ConsoleManager, String...)}. */
|
||||
@Test
|
||||
public void testHelp() {
|
||||
final ScriptExecution exec = new ScriptExecution("script", null, "#", //$NON-NLS-1$ //$NON-NLS-2$
|
||||
Charset.forName("UTF-8"));
|
||||
try (PipedConsoleOutput test = new PipedConsoleOutput()) {
|
||||
exec.help(test);
|
||||
exec.help(test, "ignored element");
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
fail("unexpected error in help invocation"); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
/** Test method for {@link fr.bigeon.gclc.command.ScriptExecution#tip()}. */
|
||||
@Test
|
||||
public void testTip() {
|
||||
final ScriptExecution exec = new ScriptExecution("script", null, "#", //$NON-NLS-1$ //$NON-NLS-2$
|
||||
Charset.forName("UTF-8"));
|
||||
assertNotNull("Tip should not be null", exec.tip());
|
||||
}
|
||||
}
|
||||
408
gclc/src/test/java/fr/bigeon/gclc/command/SubedCommandTest.java
Normal file
408
gclc/src/test/java/fr/bigeon/gclc/command/SubedCommandTest.java
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* 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.SubedCommandTest.java
|
||||
* Created on: Nov 18, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.command;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.exception.CommandRunException;
|
||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
@SuppressWarnings("all")
|
||||
public class SubedCommandTest {
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.SubedCommand#add(fr.bigeon.gclc.command.ICommand)}. */
|
||||
@Test
|
||||
public final void testAdd() {
|
||||
final SubedCommand cmd = new SubedCommand("name");
|
||||
|
||||
try {
|
||||
cmd.add(new MockCommand("id"));
|
||||
} catch (final InvalidCommandName e) {
|
||||
fail("addition of command with valid id failed");
|
||||
}
|
||||
try {
|
||||
cmd.add(new MockCommand("id"));
|
||||
fail("addition of command with already used id succeeded");
|
||||
} catch (final InvalidCommandName e) {
|
||||
//
|
||||
}
|
||||
try {
|
||||
cmd.add(new MockCommand(""));
|
||||
fail("addition of command with invalid id succeeded");
|
||||
} catch (final InvalidCommandName e) {
|
||||
//
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.SubedCommand#execute(java.lang.String[])}. */
|
||||
@Test
|
||||
public final void testExecute() {
|
||||
SubedCommand cmd = new SubedCommand("name");
|
||||
|
||||
final MockCommand mock = new MockCommand("id");
|
||||
try {
|
||||
cmd.add(mock);
|
||||
cmd.add(new Command("fail") {
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
throw new CommandRunException("Failing command", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (final InvalidCommandName e) {
|
||||
fail("addition of command with valid id failed");
|
||||
assertNotNull(e);
|
||||
}
|
||||
|
||||
try {
|
||||
cmd.execute(null, null, "id");
|
||||
} catch (final CommandRunException e) {
|
||||
fail("Unexpected exception when running mock command");
|
||||
assertNotNull(e);
|
||||
}
|
||||
try {
|
||||
cmd.execute(null, null, "fail");
|
||||
fail("Fail command error should be re thrown");
|
||||
} catch (final CommandRunException e) {
|
||||
assertNotNull(e);
|
||||
assertEquals(cmd, e.getSource());
|
||||
}
|
||||
try {
|
||||
cmd.execute(null, null);
|
||||
fail("Request for inexistent default command should fail");
|
||||
} catch (final CommandRunException e) {
|
||||
assertNotNull(e);
|
||||
assertEquals(cmd, e.getSource());
|
||||
}
|
||||
cmd = new SubedCommand("name", mock);
|
||||
|
||||
try {
|
||||
cmd.add(mock);
|
||||
cmd.add(new Command("fail") {
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
throw new CommandRunException("Failing command", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (final InvalidCommandName e) {
|
||||
fail("addition of command with valid id failed");
|
||||
assertNotNull(e);
|
||||
}
|
||||
|
||||
try {
|
||||
cmd.execute(null, null, "id");
|
||||
} catch (final CommandRunException e) {
|
||||
fail("Unexpected exception when running mock command");
|
||||
assertNotNull(e);
|
||||
}
|
||||
try {
|
||||
cmd.execute(null, null, "fail");
|
||||
fail("Fail command error should be re thrown");
|
||||
} catch (final CommandRunException e) {
|
||||
assertNotNull(e);
|
||||
assertEquals(cmd.get("fail"), e.getSource());
|
||||
}
|
||||
try {
|
||||
cmd.execute(null, null);
|
||||
} catch (final CommandRunException e) {
|
||||
fail("Request for default command should execute default command");
|
||||
assertNotNull(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.SubedCommand#executeSub(java.lang.String, java.lang.String[])}. */
|
||||
@Test
|
||||
public final void testExecuteSub() {
|
||||
final SubedCommand cmd = new SubedCommand("name");
|
||||
|
||||
final MockCommand mock = new MockCommand("id");
|
||||
try {
|
||||
cmd.add(mock);
|
||||
cmd.add(new Command("fail") {
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out,
|
||||
final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
throw new CommandRunException("Failing command", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String usageDetail() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (final InvalidCommandName e) {
|
||||
fail("addition of command with valid id failed");
|
||||
assertNotNull(e);
|
||||
}
|
||||
|
||||
try {
|
||||
cmd.executeSub(null, null,"id");
|
||||
} catch (final CommandRunException e) {
|
||||
fail("Unexpected exception when running mock command");
|
||||
assertNotNull(e);
|
||||
}
|
||||
try {
|
||||
cmd.executeSub(null, null, "fail");
|
||||
fail("Fail command error should be re thrown");
|
||||
} catch (final CommandRunException e) {
|
||||
assertNotNull(e);
|
||||
assertEquals(cmd.get("fail"), e.getSource());
|
||||
}
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.SubedCommand#get(java.lang.String)}. */
|
||||
@Test
|
||||
public final void testGet() {
|
||||
final SubedCommand cmd = new SubedCommand("name");
|
||||
|
||||
assertNull(cmd.get("id"));
|
||||
|
||||
final MockCommand mock = new MockCommand("id");
|
||||
try {
|
||||
cmd.add(mock);
|
||||
} catch (final InvalidCommandName e) {
|
||||
fail("addition of command with valid id failed");
|
||||
assertNotNull(e);
|
||||
}
|
||||
assertEquals(mock, cmd.get("id"));
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.SubedCommand#getCommandName()}. */
|
||||
@Test
|
||||
public final void testGetCommandName() {
|
||||
SubedCommand cmd = new SubedCommand("name");
|
||||
assertEquals("name", cmd.getCommandName());
|
||||
cmd = new SubedCommand("name with spaces");
|
||||
assertEquals("name with spaces", cmd.getCommandName());
|
||||
cmd = new SubedCommand("name", "some tip");
|
||||
assertEquals("name", cmd.getCommandName());
|
||||
cmd = new SubedCommand("name", new MockCommand(""));
|
||||
assertEquals("name", cmd.getCommandName());
|
||||
cmd = new SubedCommand("name", new MockCommand(""), "some tip");
|
||||
assertEquals("name", cmd.getCommandName());
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.SubedCommand#help(fr.bigeon.gclc.manager.ConsoleManager, java.lang.String[])}. */
|
||||
@Test
|
||||
public final void testHelp() {
|
||||
SubedCommand cmd = new SubedCommand("name");
|
||||
|
||||
ICommand mock = new MockCommand("id");
|
||||
try {
|
||||
cmd.add(mock);
|
||||
} catch (final InvalidCommandName e) {
|
||||
fail("addition of command with valid id failed");
|
||||
assertNotNull(e);
|
||||
}
|
||||
|
||||
try (PipedConsoleOutput manager = new PipedConsoleOutput()) {
|
||||
cmd.help(manager);
|
||||
assertEquals("\tid", manager.readNextLine());
|
||||
cmd.help(manager, "id");
|
||||
cmd.help(manager, "inexistent");
|
||||
} catch (final IOException e) {
|
||||
fail("Unexpected exception when running help");
|
||||
assertNotNull(e);
|
||||
}
|
||||
|
||||
cmd = new SubedCommand("name", mock);
|
||||
|
||||
try {
|
||||
cmd.add(mock);
|
||||
} catch (final InvalidCommandName e) {
|
||||
fail("addition of command with valid id failed");
|
||||
assertNotNull(e);
|
||||
}
|
||||
|
||||
try (PipedConsoleOutput manager = new PipedConsoleOutput()) {
|
||||
cmd.help(manager);
|
||||
assertEquals("\tid", manager.readNextLine());
|
||||
} catch (final IOException e) {
|
||||
fail("Unexpected exception when running help");
|
||||
assertNotNull(e);
|
||||
}
|
||||
|
||||
mock = new ICommand() {
|
||||
|
||||
@Override
|
||||
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||
final String... args) throws CommandRunException {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return "id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void help(final ConsoleOutput manager,
|
||||
final String... args) throws IOException {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tip() {
|
||||
return "tip";
|
||||
}
|
||||
};
|
||||
cmd = new SubedCommand("name", mock);
|
||||
|
||||
try {
|
||||
cmd.add(mock);
|
||||
} catch (final InvalidCommandName e) {
|
||||
fail("addition of command with valid id failed");
|
||||
assertNotNull(e);
|
||||
}
|
||||
|
||||
try (PipedConsoleOutput manager = new PipedConsoleOutput()) {
|
||||
cmd.help(manager);
|
||||
assertEquals("\ttip", manager.readNextLine());
|
||||
assertEquals("\tid: tip", manager.readNextLine());
|
||||
} catch (final IOException e) {
|
||||
fail("Unexpected exception when running help");
|
||||
assertNotNull(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.SubedCommand#SubedCommand(java.lang.String)}. */
|
||||
@Test
|
||||
public final void testSubedCommandString() {
|
||||
SubedCommand cmd = new SubedCommand("name");
|
||||
assertEquals("name", cmd.getCommandName());
|
||||
cmd = new SubedCommand("name with spaces");
|
||||
assertNull(cmd.tip());
|
||||
assertEquals("name with spaces", cmd.getCommandName());
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.SubedCommand#SubedCommand(java.lang.String, fr.bigeon.gclc.command.ICommand)}. */
|
||||
@Test
|
||||
public final void testSubedCommandStringICommand() {
|
||||
SubedCommand cmd = new SubedCommand("name", new MockCommand(""));
|
||||
assertEquals("name", cmd.getCommandName());
|
||||
cmd = new SubedCommand("name with spaces", new MockCommand(""));
|
||||
assertNull(cmd.tip());
|
||||
assertEquals("name with spaces", cmd.getCommandName());
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.SubedCommand#SubedCommand(java.lang.String, fr.bigeon.gclc.command.ICommand, java.lang.String)}. */
|
||||
@Test
|
||||
public final void testSubedCommandStringICommandString() {
|
||||
SubedCommand cmd = new SubedCommand("name", new MockCommand(""), "tip");
|
||||
assertEquals("name", cmd.getCommandName());
|
||||
cmd = new SubedCommand("name with spaces", new MockCommand(""), "tip");
|
||||
assertEquals("name with spaces", cmd.getCommandName());
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.command.SubedCommand#SubedCommand(java.lang.String, java.lang.String)}. */
|
||||
@Test
|
||||
public final void testSubedCommandStringString() {
|
||||
SubedCommand cmd = new SubedCommand("name", "tip");
|
||||
assertEquals("name", cmd.getCommandName());
|
||||
cmd = new SubedCommand("name with spaces", "tip");
|
||||
assertEquals("name with spaces", cmd.getCommandName());
|
||||
}
|
||||
|
||||
/** Test method for {@link fr.bigeon.gclc.command.SubedCommand#tip()}. */
|
||||
@Test
|
||||
public final void testTip() {
|
||||
SubedCommand cmd = new SubedCommand("name");
|
||||
assertNull(cmd.tip());
|
||||
cmd = new SubedCommand("name with spaces", new MockCommand(""), "tip");
|
||||
assertEquals("tip", cmd.tip());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.exception.CommandRunExceptionTest.java
|
||||
* Created on: Nov 19, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.exception;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.bigeon.gclc.command.ICommand;
|
||||
import fr.bigeon.gclc.command.MockCommand;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon
|
||||
*
|
||||
*/
|
||||
public class CommandRunExceptionTest {
|
||||
|
||||
/**
|
||||
* Test method for {@link fr.bigeon.gclc.exception.CommandRunException#getLocalizedMessage()}.
|
||||
*/
|
||||
@Test
|
||||
public final void testGetLocalizedMessage() {
|
||||
CommandRunException e;
|
||||
ICommand cmd = new MockCommand("name");
|
||||
String messageInner = "inner";
|
||||
String message = "message";
|
||||
e = new CommandRunException(message,
|
||||
new CommandRunException(messageInner, new MockCommand("name")), //$NON-NLS-1$
|
||||
cmd);
|
||||
|
||||
assertEquals(message + ": " + messageInner, e.getLocalizedMessage());
|
||||
e = new CommandRunException(message, cmd);
|
||||
assertEquals(message, e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.manager.ReadingRunnableTest.java
|
||||
* Created on: Dec 6, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.manager;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class ReadingRunnableTest {
|
||||
|
||||
/**
|
||||
*/
|
||||
@Before
|
||||
public void setUp() {}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.manager.ReadingRunnable#getMessage()}. */
|
||||
@Test
|
||||
public final void testGetMessage() {
|
||||
final BufferedReader reader = null;
|
||||
final ReadingRunnable runnable = new ReadingRunnable(reader);
|
||||
runnable.setRunning(false);
|
||||
|
||||
try {
|
||||
runnable.getMessage();
|
||||
fail("reading from closed runnable");
|
||||
} catch (final IOException e) {
|
||||
// ok
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.manager.ReadingRunnable#getWaitForDelivery(java.lang.String)}.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
* @throws IOException */
|
||||
@Test
|
||||
public final void testGetWaitForDelivery() throws InterruptedException,
|
||||
IOException {
|
||||
try (PipedOutputStream out = new PipedOutputStream();
|
||||
InputStream piped = new PipedInputStream(out);
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(piped, "UTF-8"))) {
|
||||
final ReadingRunnable runnable = new ReadingRunnable(reader);
|
||||
final Thread th0 = new Thread(runnable, "read");
|
||||
th0.start();
|
||||
final Thread th = runnable.getWaitForDelivery("msg");
|
||||
|
||||
out.write(Charset.forName("UTF-8")
|
||||
.encode("msg" + System.lineSeparator()).array());
|
||||
|
||||
final Thread th2 = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
runnable.getMessage();
|
||||
} catch (final IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, "get");
|
||||
th2.start();
|
||||
th.join();
|
||||
assertFalse("Runnable should have consumed every message",
|
||||
runnable.hasMessage());
|
||||
runnable.setRunning(false);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.manager.ReadingRunnable#hasMessage()}. */
|
||||
@Test
|
||||
public final void testHasMessage() {
|
||||
|
||||
final BufferedReader reader = null;
|
||||
final ReadingRunnable runnable = new ReadingRunnable(reader);
|
||||
runnable.setRunning(false);
|
||||
|
||||
try {
|
||||
runnable.getMessage();
|
||||
fail("reading from closed runnable");
|
||||
} catch (final IOException e) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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.manager.SystemConsoleManagerTest.java
|
||||
* Created on: Nov 19, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.manager;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
public class SystemConsoleManagerTest {
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.manager.SystemConsoleManager#isClosed()}.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException */
|
||||
@Test
|
||||
public final void testIsClosed() throws IOException, InterruptedException {
|
||||
final PipedOutputStream outStream = new PipedOutputStream();
|
||||
final InputStream in = new PipedInputStream(outStream);
|
||||
final PrintStream out = new PrintStream(outStream);
|
||||
final String test = "test";
|
||||
final StreamConsoleInput manager = new StreamConsoleInput(System.out,
|
||||
in, Charset.forName("UTF-8"));
|
||||
|
||||
final Thread th = new Thread(new Runnable() {
|
||||
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
out.println(test);
|
||||
}
|
||||
});
|
||||
|
||||
th.start();
|
||||
assertEquals(test, manager.prompt());
|
||||
assertFalse(manager.isClosed());
|
||||
manager.close();
|
||||
assertTrue(manager.isClosed());
|
||||
try {
|
||||
manager.prompt();
|
||||
fail("prompt on closed manager");
|
||||
} catch (final IOException e) {
|
||||
// ok
|
||||
}
|
||||
th.join();
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.manager.SystemConsoleManager#prompt()}.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException */
|
||||
@Test
|
||||
public final void testPrompt() throws IOException, InterruptedException {
|
||||
|
||||
final String test = "test";
|
||||
try (PipedOutputStream outStream = new PipedOutputStream();
|
||||
InputStream in = new PipedInputStream(outStream);
|
||||
final PrintStream out = new PrintStream(outStream);
|
||||
StreamConsoleInput manager = new StreamConsoleInput(System.out, in,
|
||||
Charset.forName("UTF-8"))) {
|
||||
|
||||
final Thread th = new Thread(new Runnable() {
|
||||
|
||||
@SuppressWarnings("synthetic-access")
|
||||
@Override
|
||||
public void run() {
|
||||
out.println(test);
|
||||
}
|
||||
});
|
||||
|
||||
th.start();
|
||||
assertEquals(test, manager.prompt());
|
||||
|
||||
th.join();
|
||||
}
|
||||
}
|
||||
|
||||
/** Test method for
|
||||
* {@link fr.bigeon.gclc.manager.SystemConsoleManager#setPrompt(java.lang.String)}.
|
||||
*
|
||||
* @throws IOException */
|
||||
@Test
|
||||
public final void testSetPrompt() throws IOException {
|
||||
try (PipedOutputStream outStream = new PipedOutputStream();
|
||||
InputStream in = new PipedInputStream(outStream);
|
||||
final PrintStream out = new PrintStream(outStream);
|
||||
StreamConsoleInput manager = new StreamConsoleInput(System.out, in,
|
||||
Charset.forName("UTF-8"))) {
|
||||
|
||||
final String prt = "++";
|
||||
manager.setPrompt(prt);
|
||||
assertEquals(prt, manager.getPrompt());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.prompt.CLIPrompterMessagesTest.java
|
||||
* Created on: Nov 19, 2016
|
||||
*/
|
||||
package fr.bigeon.gclc.prompt;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TODO
|
||||
*
|
||||
* @author Emmanuel Bigeon
|
||||
*
|
||||
*/
|
||||
public class CLIPrompterMessagesTest {
|
||||
|
||||
/**
|
||||
* Test method for {@link fr.bigeon.gclc.prompt.CLIPrompterMessages#getString(java.lang.String, java.lang.Object[])}.
|
||||
*/
|
||||
@Test
|
||||
public final void testGetString() {
|
||||
String key = "bad.key";
|
||||
assertEquals('!' + key + '!', CLIPrompterMessages.getString(key));
|
||||
assertEquals('!' + key + '!',
|
||||
CLIPrompterMessages.getString(key, "some arg"));
|
||||
assertEquals('!' + key + '!',
|
||||
CLIPrompterMessages.getString(key, new Object[] {}));
|
||||
}
|
||||
|
||||
}
|
||||
1212
gclc/src/test/java/fr/bigeon/gclc/prompt/CLIPrompterTest.java
Normal file
1212
gclc/src/test/java/fr/bigeon/gclc/prompt/CLIPrompterTest.java
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user