Compare commits
117 Commits
gclc-socke
...
process-0.
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ca2905b2a | |||
| 37cbe2eb95 | |||
| 9bc46c93a6 | |||
| 00c0e86d72 | |||
| eae7e0d69f | |||
| 926a8d72fa | |||
| 95ec674528 | |||
| 4d30402a42 | |||
| cdcf9f0fae | |||
| cce8a9504d | |||
| 119afe1660 | |||
| 7517251d1c | |||
| f8a37e7eee | |||
| 3598bb359e | |||
| e9fa6e209f | |||
| d4b695f60b | |||
| 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 |
4
gclc-process/.gitignore
vendored
Normal file
4
gclc-process/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/target/
|
||||||
|
/.classpath
|
||||||
|
/.project
|
||||||
|
/.settings/
|
||||||
95
gclc-process/pom.xml
Normal file
95
gclc-process/pom.xml
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
|
||||||
|
<!-- process, Distribution repositories and basic setup for Emmanuel Bigeon projects -->
|
||||||
|
<!-- Copyright (C) 2014-2018 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. -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 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.2</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.config</groupId>
|
||||||
|
<artifactId>ebigeon-config</artifactId>
|
||||||
|
<version>1.8.2</version>
|
||||||
|
</parent>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>fr.bigeon</groupId>
|
||||||
|
<artifactId>gclc</artifactId>
|
||||||
|
<version>2.0.5</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<tag>process-0.0.2</tag>
|
||||||
|
<developerConnection>scm:git:gogs@git.code.bigeon.net:emmanuel/gclc.git</developerConnection>
|
||||||
|
</scm>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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.util.List;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.command.CommandParameters;
|
||||||
|
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 forked command will actually print again all
|
||||||
|
* the command history to the output console.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author Emmanuel Bigeon */
|
||||||
|
public class CommandForeground extends ParametrizedCommand {
|
||||||
|
|
||||||
|
private final TaskPool pool;
|
||||||
|
|
||||||
|
/** Add the fork command.
|
||||||
|
*
|
||||||
|
* @param name the command name
|
||||||
|
* @param pool The pool to get joinable tasks from */
|
||||||
|
public CommandForeground(final String name, TaskPool pool) {
|
||||||
|
super(name, false);
|
||||||
|
this.pool = pool;
|
||||||
|
addParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private void addParameters() {
|
||||||
|
try {
|
||||||
|
addStringParameter("pid", false);
|
||||||
|
addStringParameter("delai", false);
|
||||||
|
} 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 {
|
||||||
|
String string = parameters.get("pid");
|
||||||
|
final List<String> additionals = parameters.getAdditionals();
|
||||||
|
if (string == null && !additionals.isEmpty()) {
|
||||||
|
string = additionals.get(0);
|
||||||
|
}
|
||||||
|
if (string == null) {
|
||||||
|
throw new CommandRunException(CommandRunExceptionType.USAGE,
|
||||||
|
"Missing process id", this);
|
||||||
|
}
|
||||||
|
// Join the command.
|
||||||
|
final Task cmd = pool.get(string);
|
||||||
|
if (!(cmd instanceof ForkTask)) {
|
||||||
|
throw new CommandRunException("No such forked process", this);
|
||||||
|
}
|
||||||
|
long delai = 0;
|
||||||
|
final String delaiOpt = parameters.get("delai");
|
||||||
|
if (delaiOpt != null) {
|
||||||
|
delai = Long.parseLong(delaiOpt) * 1000;
|
||||||
|
}
|
||||||
|
if (delai < 0) {
|
||||||
|
throw new CommandRunException("Join delai cannot be negative", this);
|
||||||
|
}
|
||||||
|
((ForkTask) cmd).join(out, in, delai);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
||||||
|
@Override
|
||||||
|
public String tip() {
|
||||||
|
return "Join the execution of a command, for a given amount of time";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||||
|
@Override
|
||||||
|
protected String usageDetail() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.command.Command#usagePattern() */
|
||||||
|
@Override
|
||||||
|
protected String usagePattern() {
|
||||||
|
return super.usagePattern() + " [(-pid) <id>] ([-delai <delai>])";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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.util.Arrays;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.command.Command;
|
||||||
|
import fr.bigeon.gclc.command.ICommand;
|
||||||
|
import fr.bigeon.gclc.command.ICommandProvider;
|
||||||
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
|
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 forked command will actually print again all
|
||||||
|
* the command history to the output console.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author Emmanuel Bigeon */
|
||||||
|
public class CommandFork extends Command {
|
||||||
|
|
||||||
|
private final TaskPool pool;
|
||||||
|
private final ICommandProvider provider;
|
||||||
|
private final int lines;
|
||||||
|
|
||||||
|
/** Add the fork command.
|
||||||
|
*
|
||||||
|
* @param name the command name
|
||||||
|
* @param provider the allowed command collection */
|
||||||
|
public CommandFork(final String name, ICommandProvider provider, TaskPool pool) {
|
||||||
|
this(name, provider, pool, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add the fork command.
|
||||||
|
*
|
||||||
|
* @param name the command name
|
||||||
|
* @param provider the allowed command collection */
|
||||||
|
public CommandFork(final String name, ICommandProvider provider, TaskPool pool,
|
||||||
|
int lines) {
|
||||||
|
super(name);
|
||||||
|
this.provider = provider;
|
||||||
|
this.pool = pool;
|
||||||
|
this.lines = lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final ConsoleOutput out, final ConsoleInput in, String... args)
|
||||||
|
throws CommandRunException {
|
||||||
|
if (args.length < 1) {
|
||||||
|
throw new CommandRunException("No command to fork", this);
|
||||||
|
}
|
||||||
|
final ICommand cmd = provider.get(args[0]);
|
||||||
|
final String[] inner = Arrays.copyOfRange(args, 1, args.length);
|
||||||
|
final ForkTask task = new ForkCommandTask(cmd, inner, lines);
|
||||||
|
final Thread th = new Thread(task);
|
||||||
|
pool.add(task);
|
||||||
|
th.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
||||||
|
@Override
|
||||||
|
public String tip() {
|
||||||
|
return "Command background launch";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||||
|
@Override
|
||||||
|
protected String usageDetail() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.command.Command#usagePattern() */
|
||||||
|
@Override
|
||||||
|
protected String usagePattern() {
|
||||||
|
return super.usagePattern() + " <command>";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package fr.bigeon.gclc.process;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.command.ICommand;
|
||||||
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Emmanuel Bigeon
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ForkCommandTask extends ForkTask {
|
||||||
|
private final ICommand command;
|
||||||
|
private final String[] args;
|
||||||
|
|
||||||
|
/** @param cmd the command
|
||||||
|
* @param args the arguements
|
||||||
|
* @param lines the number of print to store in the output */
|
||||||
|
public ForkCommandTask(final ICommand cmd, final String[] args, int lines) {
|
||||||
|
super(lines);
|
||||||
|
command = cmd;
|
||||||
|
this.args = Arrays.copyOf(args, args.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.process.Task#getName() */
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return command.getCommandName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.process.ForkTask#doRun() */
|
||||||
|
@Override
|
||||||
|
protected void doRun() throws CommandRunException {
|
||||||
|
command.execute(out, in, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
155
gclc-process/src/main/java/fr/bigeon/gclc/process/ForkTask.java
Normal file
155
gclc-process/src/main/java/fr/bigeon/gclc/process/ForkTask.java
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
|
import fr.bigeon.gclc.process.io.ConnectingConsoleInput;
|
||||||
|
import fr.bigeon.gclc.process.io.ConnectingConsoleOutput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @author Emmanuel Bigeon */
|
||||||
|
public abstract class ForkTask implements Task {
|
||||||
|
|
||||||
|
private final Set<InterruptionListener> listeners = new HashSet<>();
|
||||||
|
private boolean running = false;
|
||||||
|
|
||||||
|
protected final ConnectingConsoleInput in = new ConnectingConsoleInput();
|
||||||
|
protected final ConnectingConsoleOutput out;
|
||||||
|
private CommandRunException exception;
|
||||||
|
private final Object runLock = new Object();
|
||||||
|
|
||||||
|
/** @param lines the number of print to store in the output */
|
||||||
|
public ForkTask(int lines) {
|
||||||
|
out = new ConnectingConsoleOutput(ConnectingConsoleOutput.PERSIST, lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.process.Task#addInterruptionListener(fr.bigeon.gclc.
|
||||||
|
* process.InterruptionListener) */
|
||||||
|
@Override
|
||||||
|
public final void addInterruptionListener(final InterruptionListener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.process.Task#isRunning() */
|
||||||
|
@Override
|
||||||
|
public final boolean isRunning() {
|
||||||
|
synchronized (runLock) {
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param out the console output
|
||||||
|
* @param in the console input
|
||||||
|
* @param timeout the maximal wait (0 for ever) */
|
||||||
|
public final void join(final ConsoleOutput out, final ConsoleInput in, long timeout) {
|
||||||
|
synchronized (runLock) {
|
||||||
|
this.out.connect(out);
|
||||||
|
this.in.connect(in);
|
||||||
|
try {
|
||||||
|
if (running) {
|
||||||
|
runLock.wait(timeout);
|
||||||
|
}
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
// TODO log.
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
this.out.disconnect();
|
||||||
|
this.in.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see
|
||||||
|
* fr.bigeon.gclc.process.Task#rmInterruptionListener(fr.bigeon.gclc.process
|
||||||
|
* .InterruptionListener) */
|
||||||
|
@Override
|
||||||
|
public final void rmInterruptionListener(final InterruptionListener listener) {
|
||||||
|
listeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Runnable#run() */
|
||||||
|
@Override
|
||||||
|
public final void run() {
|
||||||
|
synchronized (runLock) {
|
||||||
|
running = true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
doRun();
|
||||||
|
} catch (final CommandRunException e) {
|
||||||
|
exception = e;
|
||||||
|
} finally {
|
||||||
|
setRunning(false);
|
||||||
|
}
|
||||||
|
for (final InterruptionListener interruptionListener : listeners) {
|
||||||
|
interruptionListener.interrupted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Actually run the fork. */
|
||||||
|
protected abstract void doRun() throws CommandRunException;
|
||||||
|
|
||||||
|
/** Get the excepion that caused a failure.
|
||||||
|
*
|
||||||
|
* @return the exception */
|
||||||
|
public final CommandRunException getException() {
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.process.Task#setRunning(boolean) */
|
||||||
|
@Override
|
||||||
|
public final void setRunning(final boolean running) {
|
||||||
|
synchronized (runLock) {
|
||||||
|
this.running = running;
|
||||||
|
runLock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Object getRunningLock() {
|
||||||
|
return runLock;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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,64 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package fr.bigeon.gclc.process;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.ApplicationAttachement;
|
||||||
|
import fr.bigeon.gclc.command.ICommandProvider;
|
||||||
|
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Emmanuel Bigeon
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ProcessAttachement implements ApplicationAttachement {
|
||||||
|
|
||||||
|
private final TaskPool pool;
|
||||||
|
|
||||||
|
/** @param pool the task pool to manage */
|
||||||
|
public ProcessAttachement(TaskPool pool) {
|
||||||
|
super();
|
||||||
|
this.pool = pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.ApplicationAttachement#attach(fr.bigeon.gclc.ConsoleApplication)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void attach(ICommandProvider application) throws InvalidCommandName {
|
||||||
|
application.add(new ProcessKill("kill", pool));
|
||||||
|
application.add(new ProcessList("list", pool));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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 ProcessClear extends Command {
|
||||||
|
/** The taskpool */
|
||||||
|
private final TaskPool pool;
|
||||||
|
|
||||||
|
/** @param name the command name
|
||||||
|
* @param pool the pool */
|
||||||
|
public ProcessClear(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 {
|
||||||
|
for (final String id : pool.getPIDs()) {
|
||||||
|
if (!pool.get(id).isRunning()) {
|
||||||
|
pool.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (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,82 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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-2018 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package fr.bigeon.gclc.process;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.ApplicationAttachement;
|
||||||
|
import fr.bigeon.gclc.command.ICommandProvider;
|
||||||
|
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||||
|
|
||||||
|
/** @author Emmanuel Bigeon */
|
||||||
|
public class ScreenAttachement implements ApplicationAttachement {
|
||||||
|
|
||||||
|
private final TaskPool pool;
|
||||||
|
private final int lines;
|
||||||
|
|
||||||
|
/** @param pool the task pool to manage */
|
||||||
|
public ScreenAttachement(TaskPool pool, int lines) {
|
||||||
|
super();
|
||||||
|
this.pool = pool;
|
||||||
|
this.lines = lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.ApplicationAttachement#attach(fr.bigeon.gclc.
|
||||||
|
* ConsoleApplication) */
|
||||||
|
@Override
|
||||||
|
public void attach(ICommandProvider application) throws InvalidCommandName {
|
||||||
|
application.add(new ProcessKill("terminate", pool));
|
||||||
|
application.add(new ProcessList("list", pool));
|
||||||
|
application.add(new ProcessClear("clear", pool));
|
||||||
|
application.add(new CommandForeground("fg", pool));
|
||||||
|
application.add(new CommandFork("fork", application, pool, lines));
|
||||||
|
}
|
||||||
|
}
|
||||||
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-2018 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);
|
||||||
|
}
|
||||||
149
gclc-process/src/main/java/fr/bigeon/gclc/process/TaskPool.java
Normal file
149
gclc-process/src/main/java/fr/bigeon/gclc/process/TaskPool.java
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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();
|
||||||
|
private final boolean autoClear;
|
||||||
|
|
||||||
|
/** Default constructor. */
|
||||||
|
public TaskPool() {
|
||||||
|
this(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Default constructor. */
|
||||||
|
public TaskPool(boolean autoClear) {
|
||||||
|
this.autoClear = autoClear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove a task from the pool
|
||||||
|
*
|
||||||
|
* @param pid the task id */
|
||||||
|
public void remove(String pid) {
|
||||||
|
synchronized (lock) {
|
||||||
|
running.remove(pid);
|
||||||
|
count = Math.min(count, Integer.parseInt(pid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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;
|
||||||
|
synchronized (lock) {
|
||||||
|
pid = getPID();
|
||||||
|
running.put(pid, cmd);
|
||||||
|
}
|
||||||
|
if (autoClear) {
|
||||||
|
cmd.addInterruptionListener(new InterruptionListener() {
|
||||||
|
@SuppressWarnings("synthetic-access")
|
||||||
|
@Override
|
||||||
|
public void interrupted() {
|
||||||
|
synchronized (lock) {
|
||||||
|
remove(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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return if the clearing of ended task is automatic */
|
||||||
|
public boolean isAutoClearing() {
|
||||||
|
return autoClear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Request all task to stop running.
|
||||||
|
* <p>
|
||||||
|
* This call does not guaranty end of execution, it is up to the task
|
||||||
|
* implementation to actually take into account the termination request. */
|
||||||
|
public void shutdown() {
|
||||||
|
synchronized (lock) {
|
||||||
|
for (final Task task : running.values()) {
|
||||||
|
task.setRunning(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
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;
|
||||||
|
private final ExecutorService threadPool;
|
||||||
|
|
||||||
|
/** @param name the command name
|
||||||
|
* @param pool the pool */
|
||||||
|
public TaskSpawner(final String name, final TaskPool pool,
|
||||||
|
ExecutorService threadPool) {
|
||||||
|
super(name);
|
||||||
|
this.pool = pool;
|
||||||
|
this.threadPool = threadPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param in the input
|
||||||
|
* @param out the output
|
||||||
|
* @param args the arguments
|
||||||
|
* @return the process to start and add to the pool
|
||||||
|
* @throws CommandRunException if the task creation failed */
|
||||||
|
protected abstract Task createTask(ConsoleOutput out, ConsoleInput in,
|
||||||
|
String... args) throws CommandRunException;
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.manager.
|
||||||
|
* ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||||
|
* java.lang.String[]) */
|
||||||
|
@Override
|
||||||
|
public final 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);
|
||||||
|
threadPool.execute(th);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package fr.bigeon.gclc.process.io;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
|
import fr.bigeon.gclc.tools.StringProvider;
|
||||||
|
|
||||||
|
/** @author Emmanuel Bigeon */
|
||||||
|
public final class ConnectingConsoleInput implements ConsoleInput {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger
|
||||||
|
.getLogger(ConnectingConsoleInput.class.getName());
|
||||||
|
private boolean close = false;
|
||||||
|
private StringProvider prompt;
|
||||||
|
private boolean prompting;
|
||||||
|
private final Object promptLock = new Object();
|
||||||
|
private final Object connectionLock = new Object();
|
||||||
|
private ConsoleInput connected;
|
||||||
|
private boolean disconnection;
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#close() */
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
close = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#getPrompt() */
|
||||||
|
@Override
|
||||||
|
public StringProvider getPrompt() {
|
||||||
|
return prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#interruptPrompt() */
|
||||||
|
@Override
|
||||||
|
public void interruptPrompt() {
|
||||||
|
synchronized (promptLock) {
|
||||||
|
prompting = false;
|
||||||
|
if (connected != null) {
|
||||||
|
connected.interruptPrompt();
|
||||||
|
}
|
||||||
|
promptLock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#isClosed() */
|
||||||
|
@Override
|
||||||
|
public boolean isClosed() {
|
||||||
|
return close;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt() */
|
||||||
|
@Override
|
||||||
|
public String prompt() throws IOException {
|
||||||
|
return prompt(prompt.apply());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#setPrompt(fr.bigeon.gclc.tools.
|
||||||
|
* StringProvider) */
|
||||||
|
@Override
|
||||||
|
public void setPrompt(StringProvider string) {
|
||||||
|
prompt = string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(long) */
|
||||||
|
@Override
|
||||||
|
public String prompt(long timeout) throws IOException {
|
||||||
|
return prompt(prompt.apply(), timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(java.lang.String) */
|
||||||
|
@Override
|
||||||
|
public String prompt(String message) throws IOException {
|
||||||
|
synchronized (promptLock) {
|
||||||
|
prompting = true;
|
||||||
|
}
|
||||||
|
while (prompting) {
|
||||||
|
synchronized (promptLock) {
|
||||||
|
if (connected == null) {
|
||||||
|
try {
|
||||||
|
promptLock.wait();
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Inerruption of console thread", e);
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final String res = connected.prompt(message);
|
||||||
|
synchronized (connectionLock) {
|
||||||
|
if (disconnection) {
|
||||||
|
disconnection = false;
|
||||||
|
} else if (prompting) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(java.lang.String, long) */
|
||||||
|
@Override
|
||||||
|
public String prompt(String message, long timeout) throws IOException {
|
||||||
|
if (timeout <= 0) {
|
||||||
|
return prompt(message);
|
||||||
|
}
|
||||||
|
final long end = System.currentTimeMillis() + timeout;
|
||||||
|
synchronized (promptLock) {
|
||||||
|
prompting = true;
|
||||||
|
}
|
||||||
|
while (prompting) {
|
||||||
|
synchronized (promptLock) {
|
||||||
|
if (connected == null) {
|
||||||
|
try {
|
||||||
|
promptLock.wait();
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Inerruption of console thread", e);
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final String res = connected.prompt(message,
|
||||||
|
end - System.currentTimeMillis());
|
||||||
|
synchronized (connectionLock) {
|
||||||
|
if (disconnection) {
|
||||||
|
disconnection = false;
|
||||||
|
} else if (prompting) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#setPrompt(java.lang.String) */
|
||||||
|
@Override
|
||||||
|
public void setPrompt(final String prompt) {
|
||||||
|
this.prompt = new StringProvider() {
|
||||||
|
@Override
|
||||||
|
public String apply() {
|
||||||
|
return prompt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect(ConsoleInput input) {
|
||||||
|
disconnect();
|
||||||
|
synchronized (promptLock) {
|
||||||
|
connected = input;
|
||||||
|
promptLock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect() {
|
||||||
|
synchronized (connectionLock) {
|
||||||
|
if (connected != null) {
|
||||||
|
disconnection = true;
|
||||||
|
synchronized (promptLock) {
|
||||||
|
connected.interruptPrompt();
|
||||||
|
}
|
||||||
|
connected = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
|
||||||
|
* Copyright (C) 2014-2018 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package fr.bigeon.gclc.process.io;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
|
|
||||||
|
/** @author Emmanuel Bigeon */
|
||||||
|
public class ConnectingConsoleOutput implements ConsoleOutput {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger
|
||||||
|
.getLogger(ConnectingConsoleOutput.class.getName());
|
||||||
|
/** If the undelivered message should be stored. */
|
||||||
|
public static final int QUEUE = 1;
|
||||||
|
/** If the messages should be stored in all cases. */
|
||||||
|
public static final int PERSIST = 1 << 1;
|
||||||
|
private ConsoleOutput output;
|
||||||
|
private boolean close = false;
|
||||||
|
|
||||||
|
private final boolean persistent;
|
||||||
|
private final boolean queued;
|
||||||
|
private final Deque<String> messages;
|
||||||
|
private final int lines;
|
||||||
|
|
||||||
|
/** @param style the type of redirected output
|
||||||
|
* @param lines the number of lines to store */
|
||||||
|
public ConnectingConsoleOutput(int style, int lines) {
|
||||||
|
super();
|
||||||
|
this.lines = lines;
|
||||||
|
queued = (style & QUEUE) != 0;
|
||||||
|
persistent = (style & PERSIST) != 0;
|
||||||
|
if (lines > 0) {
|
||||||
|
messages = new ArrayDeque<>(lines);
|
||||||
|
} else {
|
||||||
|
messages = new ArrayDeque<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void addMessage(String text) {
|
||||||
|
if (persistent || queued && output == null) {
|
||||||
|
if (messages.size() == lines) {
|
||||||
|
messages.poll();
|
||||||
|
}
|
||||||
|
messages.offer(text);
|
||||||
|
}
|
||||||
|
if (output != null) {
|
||||||
|
try {
|
||||||
|
output.print(text);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
LOGGER.severe("nable to print to connecting console");
|
||||||
|
LOGGER.log(Level.FINE, "Console error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.AutoCloseable#close() */
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
close = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleOutput#isClosed() */
|
||||||
|
@Override
|
||||||
|
public boolean isClosed() {
|
||||||
|
return close;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleOutput#print(java.lang.String) */
|
||||||
|
@Override
|
||||||
|
public void print(String text) {
|
||||||
|
addMessage(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleOutput#println() */
|
||||||
|
@Override
|
||||||
|
public void println() {
|
||||||
|
addMessage(System.lineSeparator());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleOutput#println(java.lang.String) */
|
||||||
|
@Override
|
||||||
|
public void println(String message) {
|
||||||
|
addMessage(message + System.lineSeparator());
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void connect(ConsoleOutput output) {
|
||||||
|
this.output = output;
|
||||||
|
for (final String string : messages) {
|
||||||
|
try {
|
||||||
|
output.print(string);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
LOGGER.severe("nable to print to connecting console");
|
||||||
|
LOGGER.log(Level.FINE, "Console error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!persistent) {
|
||||||
|
messages.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void disconnect() {
|
||||||
|
output = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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) -->
|
<!-- Copyright E. Bigeon (2014) -->
|
||||||
<!-- -->
|
<!-- -->
|
||||||
<!-- emmanuel@bigeon.fr -->
|
<!-- 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">
|
<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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>gclc-socket</artifactId>
|
<artifactId>gclc-socket</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.1.10-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<url>http://www.bigeon.fr/emmanuel</url>
|
<url>http://www.bigeon.fr/emmanuel</url>
|
||||||
<properties>
|
<properties>
|
||||||
@@ -78,32 +109,27 @@ of Emmanuel Bigeon. -->
|
|||||||
<project.scm.id>git.bigeon.net</project.scm.id>
|
<project.scm.id>git.bigeon.net</project.scm.id>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.11</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>fr.bigeon</groupId>
|
<groupId>fr.bigeon</groupId>
|
||||||
<artifactId>gclc</artifactId>
|
<artifactId>gclc</artifactId>
|
||||||
<version>1.3.1</version>
|
<version>2.0.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>fr.bigeon</groupId>
|
<groupId>fr.bigeon</groupId>
|
||||||
<artifactId>smu</artifactId>
|
<artifactId>smu</artifactId>
|
||||||
<version>0.0.5</version>
|
<version>0.0.9</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>fr.bigeon</groupId>
|
<groupId>fr.bigeon.config</groupId>
|
||||||
<artifactId>ebigeon-config</artifactId>
|
<artifactId>ebigeon-config</artifactId>
|
||||||
<version>1.7.1</version>
|
<version>1.8.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<name>GCLC Socket</name>
|
<name>GCLC Socket</name>
|
||||||
<description>Socket implementation of GCLC</description>
|
<description>Socket implementation of GCLC</description>
|
||||||
<scm>
|
<scm>
|
||||||
<developerConnection>scm:git:gogs@git.code.bigeon.net:emmanuel/gclc.git</developerConnection>
|
<developerConnection>scm:git:gogs@git.code.bigeon.net:emmanuel/gclc.git</developerConnection>
|
||||||
<tag>gclc-socket-1.1.0</tag>
|
<tag>HEAD</tag>
|
||||||
</scm>
|
</scm>
|
||||||
|
<groupId>fr.bigeon.gclc</groupId>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -1,133 +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.ConsoleRunnable.java
|
|
||||||
* Created on: Jun 1, 2016
|
|
||||||
*/
|
|
||||||
package fr.bigeon.gclc.socket;
|
|
||||||
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import fr.bigeon.gclc.ConsoleApplication;
|
|
||||||
|
|
||||||
/** A runnable class that will actually have the application running.
|
|
||||||
*
|
|
||||||
* @author Emmanuel Bigeon */
|
|
||||||
public class ConsoleRunnable implements Runnable {
|
|
||||||
|
|
||||||
/** The wait timeout */
|
|
||||||
private static final long TIMEOUT = 100;
|
|
||||||
/** The logger */
|
|
||||||
private static final Logger LOGGER = Logger
|
|
||||||
.getLogger(ConsoleRunnable.class.getName());
|
|
||||||
/** The actual application */
|
|
||||||
private final ConsoleApplication app;
|
|
||||||
/** The synchro object */
|
|
||||||
private final Object lock = new Object();
|
|
||||||
/** the state of this runnable */
|
|
||||||
private boolean running = true;
|
|
||||||
/** If a start is required */
|
|
||||||
private boolean startReq;
|
|
||||||
|
|
||||||
/** @param app the application */
|
|
||||||
public ConsoleRunnable(ConsoleApplication app) {
|
|
||||||
super();
|
|
||||||
this.app = app;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see java.lang.Runnable#run() */
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while (running) {
|
|
||||||
synchronized (lock) {
|
|
||||||
while (running && !startReq) {
|
|
||||||
try {
|
|
||||||
lock.wait(TIMEOUT);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOGGER.log(Level.SEVERE,
|
|
||||||
"Console application runnable interrupted wildly!", //$NON-NLS-1$
|
|
||||||
e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
startReq = false;
|
|
||||||
if (!running) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lock.notify();
|
|
||||||
}
|
|
||||||
app.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Stop the application (it will finish its current operation) */
|
|
||||||
public void stop() {
|
|
||||||
app.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return if the application is running */
|
|
||||||
public boolean isApplicationRunning() {
|
|
||||||
return app.isRunning();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param running the running to set */
|
|
||||||
public void setRunning(boolean running) {
|
|
||||||
synchronized (lock) {
|
|
||||||
this.running = running;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return the running */
|
|
||||||
public boolean isRunning() {
|
|
||||||
synchronized (lock) {
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Request a restart of application */
|
|
||||||
public void restart() {
|
|
||||||
synchronized (lock) {
|
|
||||||
startReq = true;
|
|
||||||
lock.notify();
|
|
||||||
try {
|
|
||||||
lock.wait(TIMEOUT);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Restart wait interrupted!", e); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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,284 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
import fr.bigeon.gclc.tools.ConstantString;
|
||||||
|
import fr.bigeon.gclc.tools.StringProvider;
|
||||||
|
|
||||||
|
/** 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 StringProvider prompt = new ConstantString("> "); //$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 StringProvider 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.apply());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(long) */
|
||||||
|
@Override
|
||||||
|
public String prompt(final long timeout) throws IOException {
|
||||||
|
return prompt(prompt.apply(), 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPrompt(final StringProvider prompt) {
|
||||||
|
this.prompt = prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPrompt(String prompt) {
|
||||||
|
setPrompt(new ConstantString(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)
|
* GCLC Socket, Socket implementation of GCLC
|
||||||
*
|
* Copyright (C) 2014-2017 E. Bigeon
|
||||||
* emmanuel@bigeon.fr
|
* mailto: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
|
* This software is governed by the CeCILL license under French law and
|
||||||
* abiding by the rules of distribution of free software. You can use,
|
* abiding by the rules of distribution of free software. You can use,
|
||||||
@@ -34,27 +31,17 @@
|
|||||||
*/
|
*/
|
||||||
package fr.bigeon.gclc.socket;
|
package fr.bigeon.gclc.socket;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.net.InetAddress;
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.PipedInputStream;
|
|
||||||
import java.io.PipedOutputStream;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import fr.bigeon.gclc.ConsoleApplication;
|
import fr.bigeon.gclc.ConsoleApplication;
|
||||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
|
||||||
import fr.bigeon.gclc.manager.PipedConsoleManager;
|
|
||||||
import fr.bigeon.gclc.manager.ReadingRunnable;
|
|
||||||
|
|
||||||
/** This is a socket communicating console consoleManager
|
/** This is a socket communicating console consoleManager.
|
||||||
* <p>
|
* <p>
|
||||||
* To use this application, the following flow should be used:
|
* To use this application, the following flow should be used:
|
||||||
*
|
*
|
||||||
@@ -72,118 +59,60 @@ import fr.bigeon.gclc.manager.ReadingRunnable;
|
|||||||
* end of the execution.
|
* end of the execution.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class SocketConsoleApplicationShell implements Runnable {
|
public final class SocketConsoleApplicationShell implements Runnable {
|
||||||
|
|
||||||
/** The runnable to forward output of application to socket.
|
/** The class logger. */
|
||||||
*
|
|
||||||
* @author Emmanuel Bigeon */
|
|
||||||
private final class OutputForwardRunnable implements Runnable {
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private final PrintWriter writer;
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private final Socket socket;
|
|
||||||
|
|
||||||
/** @param writer the writer
|
|
||||||
* @param socket the socket */
|
|
||||||
protected OutputForwardRunnable(PrintWriter writer, Socket socket) {
|
|
||||||
this.writer = writer;
|
|
||||||
this.socket = socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("synthetic-access")
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
while (!socket.isOutputShutdown()) {
|
|
||||||
while (!socket.isOutputShutdown() &&
|
|
||||||
!consoleManager.available()) {
|
|
||||||
waitASec();
|
|
||||||
}
|
|
||||||
if (socket.isOutputShutdown()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String m = consoleManager.readNextLine();
|
|
||||||
writer.println(m);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Unexpected problem in manager", //$NON-NLS-1$
|
|
||||||
e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The end of line character */
|
|
||||||
protected static final String EOL = "\n"; //$NON-NLS-1$
|
|
||||||
/** The class logger */
|
|
||||||
private static final Logger LOGGER = Logger
|
private static final Logger LOGGER = Logger
|
||||||
.getLogger(SocketConsoleApplicationShell.class.getName());
|
.getLogger(SocketConsoleApplicationShell.class.getName());
|
||||||
/** Time of wait */
|
/** The listening port. */
|
||||||
protected static final long ONE_TENTH_OF_SECOND = 100;
|
|
||||||
/** The listening port */
|
|
||||||
private final int port;
|
private final int port;
|
||||||
/** The input */
|
/** The running status. */
|
||||||
private final PipedInputStream consoleInput = new PipedInputStream();
|
|
||||||
/** The application */
|
|
||||||
private ConsoleApplication app;
|
|
||||||
/** The session closing command */
|
|
||||||
private final String close;
|
|
||||||
/** The running status */
|
|
||||||
private boolean running;
|
private boolean running;
|
||||||
|
/** The socket console interface. */
|
||||||
|
private SocketConsoleInterface sci;
|
||||||
|
/** The remote disconnection command. */
|
||||||
|
private ConnexionManager<Socket> rdc;
|
||||||
|
/** The application. */
|
||||||
|
private ConsoleApplication app;
|
||||||
|
|
||||||
/** The console manager implementation */
|
/** The server socket. */
|
||||||
private final PipedConsoleManager consoleManager;
|
|
||||||
/** The auto close flag. if this is true, every request closes the session
|
|
||||||
* after its call */
|
|
||||||
private final boolean autoClose;
|
|
||||||
/** The server socket */
|
|
||||||
private ServerSocket serverSocket;
|
private ServerSocket serverSocket;
|
||||||
/** The application shutdown string */
|
/** THe server address. */
|
||||||
private final String applicationShutdown;
|
private final InetAddress addr;
|
||||||
/** The charset for the communication. */
|
|
||||||
private final Charset charset;
|
|
||||||
|
|
||||||
/** Create a socket application shell which will listen on the given port
|
/** 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 port the part
|
||||||
* @param close the session closing command
|
* @param addr the inet address */
|
||||||
* @param applicationShutdown the appication shut down command
|
public SocketConsoleApplicationShell(final int port,
|
||||||
* @param charset the charset for communication
|
final InetAddress addr) {
|
||||||
* @throws IOException if the manager could not be created */
|
super();
|
||||||
public SocketConsoleApplicationShell(int port, String close,
|
|
||||||
String applicationShutdown, Charset charset) throws IOException {
|
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.close = close;
|
this.addr = addr;
|
||||||
this.applicationShutdown = applicationShutdown;
|
|
||||||
this.autoClose = false;
|
|
||||||
this.charset = charset;
|
|
||||||
//
|
|
||||||
consoleManager = new PipedConsoleManager();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create a socket application shell which will listen on the given port
|
/** Wait for the identified connection to disconnect.
|
||||||
* and auto close session after one instruction
|
|
||||||
*
|
*
|
||||||
* @param port the port to listen to
|
* @param id the connexion id. */
|
||||||
* @param autoClose if the session must be closed once the request has been
|
private void awaitDisconnexion(final String id) {
|
||||||
* sent
|
while (rdc.isConnected(id)) {
|
||||||
* @param applicationShutdown the appication shut down command
|
try {
|
||||||
* @param charset the charset for communication
|
rdc.waitDisconnexion(id);
|
||||||
* @throws IOException if the manager could not be created */
|
} catch (final InterruptedException e) {
|
||||||
public SocketConsoleApplicationShell(int port, boolean autoClose,
|
LOGGER.log(Level.SEVERE, "Unexpected interruption", e); //$NON-NLS-1$
|
||||||
String applicationShutdown, Charset charset) throws IOException {
|
Thread.currentThread().interrupt();
|
||||||
this.port = port;
|
}
|
||||||
this.autoClose = autoClose;
|
}
|
||||||
this.applicationShutdown = applicationShutdown;
|
sci.disconnect();
|
||||||
this.close = autoClose ? null : "close"; //$NON-NLS-1$
|
}
|
||||||
this.charset = charset;
|
|
||||||
//
|
/** If the port provided was 0, this allows to get the actual port.
|
||||||
consoleManager = new PipedConsoleManager();
|
* @return the local port
|
||||||
|
* @see java.net.ServerSocket#getLocalPort()
|
||||||
|
*/
|
||||||
|
public int getLocalPort() {
|
||||||
|
return serverSocket.getLocalPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -191,164 +120,69 @@ public class SocketConsoleApplicationShell implements Runnable {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// Create the server
|
// Create the server
|
||||||
try (ServerSocket actualServerSocket = new ServerSocket(port)) {
|
try (ServerSocket actualServerSocket = new ServerSocket(port, 1,
|
||||||
this.serverSocket = actualServerSocket;
|
addr)) {
|
||||||
|
serverSocket = actualServerSocket;
|
||||||
running = true;
|
running = true;
|
||||||
// Create the streams
|
// Create the streams
|
||||||
try (PipedOutputStream outStream = new PipedOutputStream();
|
runSokectServer();
|
||||||
BufferedWriter writer = new BufferedWriter(
|
} catch (final IOException e) {
|
||||||
new OutputStreamWriter(outStream, charset));
|
LOGGER.severe("Communication error between client and server"); //$NON-NLS-1$
|
||||||
InputStreamReader isr = new InputStreamReader(consoleInput,
|
LOGGER.log(Level.FINE,
|
||||||
charset);
|
|
||||||
BufferedReader inBuf = new BufferedReader(isr)) {
|
|
||||||
consoleInput.connect(outStream);
|
|
||||||
runSokectServer();
|
|
||||||
// Close the application
|
|
||||||
// Pass command to application
|
|
||||||
if (app.isRunning()) {
|
|
||||||
writer.write(applicationShutdown + EOL);
|
|
||||||
writer.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (
|
|
||||||
|
|
||||||
final IOException e) {
|
|
||||||
LOGGER.log(Level.SEVERE,
|
|
||||||
"Communication error between client and server", e); //$NON-NLS-1$
|
"Communication error between client and server", e); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @throws IOException if the communication with the client failed */
|
/** Acctually run the server loop on connexion.
|
||||||
|
*
|
||||||
|
* @throws IOException if the communication with the client failed */
|
||||||
private void runSokectServer() throws IOException {
|
private void runSokectServer() throws IOException {
|
||||||
final ConsoleRunnable runnable = new ConsoleRunnable(app);
|
while (running && app.isRunning()) {
|
||||||
Thread appThNext = new Thread(runnable, "gclc-ctrl"); //$NON-NLS-1$
|
LOGGER.info("Waiting client"); //$NON-NLS-1$
|
||||||
appThNext.start();
|
try (Socket clientSocket = serverSocket.accept();) {
|
||||||
while (running) {
|
|
||||||
LOGGER.info("Opening client"); //$NON-NLS-1$
|
|
||||||
try (Socket clientSocket = serverSocket.accept();
|
|
||||||
PrintWriter out = new PrintWriter(new OutputStreamWriter(
|
|
||||||
clientSocket.getOutputStream(), charset), true);
|
|
||||||
InputStreamReader isr = new InputStreamReader(
|
|
||||||
clientSocket.getInputStream(), charset);
|
|
||||||
BufferedReader in = new BufferedReader(isr);) {
|
|
||||||
// this is not threaded to avoid several clients at the same
|
|
||||||
// time
|
|
||||||
|
|
||||||
// Initiate application
|
sci.connect(clientSocket);
|
||||||
if (!runnable.isApplicationRunning()) {
|
|
||||||
LOGGER.info("Start application"); //$NON-NLS-1$
|
final String id = rdc.addConnexion(clientSocket);
|
||||||
startApplication(runnable);
|
rdc.lockDisconnexion(id);
|
||||||
} else {
|
awaitDisconnexion(id);
|
||||||
LOGGER.info("Reconnect to application"); //$NON-NLS-1$
|
rdc.releaseDisconnexionLock(id);
|
||||||
out.println("Reconnected"); //$NON-NLS-1$
|
} catch (final SocketException e) {
|
||||||
out.println(consoleManager.getPrompt());
|
|
||||||
}
|
|
||||||
communicate(clientSocket, out, in);
|
|
||||||
} catch (SocketException e) {
|
|
||||||
LOGGER.log(Level.INFO, "Socket closed"); //$NON-NLS-1$
|
LOGGER.log(Level.INFO, "Socket closed"); //$NON-NLS-1$
|
||||||
LOGGER.log(Level.FINE,
|
LOGGER.log(Level.FINE,
|
||||||
"Socket closed with exception (probably due to server interruption)", //$NON-NLS-1$
|
"Socket closed with exception (probably due to server interruption)", //$NON-NLS-1$
|
||||||
e);
|
e);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
LOGGER.info("Closing client"); //$NON-NLS-1$
|
LOGGER.info("Closing client"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
runnable.setRunning(false);
|
LOGGER.info("Closing Server"); //$NON-NLS-1$
|
||||||
consoleManager.type(applicationShutdown);
|
|
||||||
LOGGER.info("Out client"); //$NON-NLS-1$
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param runnable the runnable */
|
/** Set the application.
|
||||||
private void startApplication(ConsoleRunnable runnable) {
|
* <p>
|
||||||
runnable.restart();
|
* If the application is closed, the server will also close.
|
||||||
synchronized (this) {
|
|
||||||
try {
|
|
||||||
wait(ONE_TENTH_OF_SECOND);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Interruption in application start", //$NON-NLS-1$
|
|
||||||
e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** active communication between server and client
|
|
||||||
*
|
*
|
||||||
* @param socket the socket
|
* @param app the app to set */
|
||||||
* @param writer the writer to the application
|
public void setApplication(final ConsoleApplication app) {
|
||||||
* @param in the input from the client
|
|
||||||
* @throws IOException if the communication failed */
|
|
||||||
private void communicate(final Socket socket, final PrintWriter writer,
|
|
||||||
BufferedReader in) throws IOException {
|
|
||||||
Thread th = new Thread(new OutputForwardRunnable(writer, socket), "ClientComm"); //$NON-NLS-1$
|
|
||||||
th.start();
|
|
||||||
if (autoClose) {
|
|
||||||
communicateOnce(socket, in);
|
|
||||||
} else {
|
|
||||||
communicateLoop(socket, in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param socket the socket
|
|
||||||
* @param in the input from the client
|
|
||||||
* @throws IOException if the communication failed */
|
|
||||||
private void communicateOnce(Socket socket,
|
|
||||||
BufferedReader in) throws IOException {
|
|
||||||
ReadingRunnable reading = new ReadingRunnable(in);
|
|
||||||
Thread th = new Thread(reading, "gclcToApp"); //$NON-NLS-1$
|
|
||||||
th.start();
|
|
||||||
if (app.isRunning()) {
|
|
||||||
communicationContent(reading);
|
|
||||||
}
|
|
||||||
reading.setRunning(false);
|
|
||||||
socket.shutdownOutput();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param socket the socket
|
|
||||||
* @param in the input from the client
|
|
||||||
* @throws IOException if the communication failed */
|
|
||||||
private void communicateLoop(Socket socket,
|
|
||||||
BufferedReader in) throws IOException {
|
|
||||||
ReadingRunnable reading = new ReadingRunnable(in);
|
|
||||||
Thread th = new Thread(reading, "gclcToApp"); //$NON-NLS-1$
|
|
||||||
th.start();
|
|
||||||
while (app.isRunning() && communicationContent(reading)) {
|
|
||||||
// keep on going
|
|
||||||
}
|
|
||||||
reading.setRunning(false);
|
|
||||||
socket.shutdownOutput();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param reading the reading
|
|
||||||
* @return if the communication should be stopped.
|
|
||||||
* @throws IOException if the reading failed */
|
|
||||||
private boolean communicationContent(ReadingRunnable reading) throws IOException {
|
|
||||||
while (app.isRunning() && !reading.hasMessage()) {
|
|
||||||
synchronized (this) {
|
|
||||||
waitASec();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!app.isRunning()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String ln = reading.getMessage();
|
|
||||||
if (ln.equals(close)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Pass command to application
|
|
||||||
consoleManager.type(ln);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return the consoleManager */
|
|
||||||
public synchronized ConsoleManager getConsoleManager() {
|
|
||||||
return consoleManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param app the application to set */
|
|
||||||
public synchronized void setApplication(ConsoleApplication app) {
|
|
||||||
this.app = 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.
|
/** This method will request the server to stop.
|
||||||
* <p>
|
* <p>
|
||||||
* In most cases, this will terminate communication on every client. On some
|
* In most cases, this will terminate communication on every client. On some
|
||||||
@@ -357,22 +191,8 @@ public class SocketConsoleApplicationShell implements Runnable {
|
|||||||
running = false;
|
running = false;
|
||||||
try {
|
try {
|
||||||
serverSocket.close();
|
serverSocket.close();
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
LOGGER.log(Level.SEVERE, "Exception in closing socket server", e); //$NON-NLS-1$
|
LOGGER.log(Level.SEVERE, "Exception in closing socket server", e); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
app.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** a method to wait some time */
|
|
||||||
protected void waitASec() {
|
|
||||||
try {
|
|
||||||
synchronized (this) {
|
|
||||||
wait(ONE_TENTH_OF_SECOND);
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Interrupted wait", //$NON-NLS-1$
|
|
||||||
e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,182 +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.manager.ConsoleManager;
|
|
||||||
|
|
||||||
/** Test class for {@link ConsoleRunnable}
|
|
||||||
*
|
|
||||||
* @author Emmanuel Bigeon */
|
|
||||||
@SuppressWarnings({"unused", "javadoc"})
|
|
||||||
public class ConsoleRunnableTest {
|
|
||||||
|
|
||||||
/** <p>
|
|
||||||
* TODO
|
|
||||||
*
|
|
||||||
* @author Emmanuel Bigeon */
|
|
||||||
private static final class ConsoleManagerTestImplementation
|
|
||||||
implements ConsoleManager {
|
|
||||||
int i = 0;
|
|
||||||
String[] cmds;
|
|
||||||
|
|
||||||
/** @param cmds the commands to run */
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see fr.bigeon.gclc.manager.ConsoleManager#interruptPrompt() */
|
|
||||||
@Override
|
|
||||||
public void interruptPrompt() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Test method for
|
|
||||||
* {@link fr.bigeon.gclc.socket.ConsoleRunnable#ConsoleRunnable(fr.bigeon.gclc.ConsoleApplication)}
|
|
||||||
* . */
|
|
||||||
@Test
|
|
||||||
public void testConsoleRunnable() {
|
|
||||||
// ConsoleApplication app = new ConsoleTestApplication(
|
|
||||||
// new SystemConsoleManager());
|
|
||||||
// ConsoleRunnable runnable = new ConsoleRunnable(app);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Test method for {@link fr.bigeon.gclc.socket.ConsoleRunnable#run()}. */
|
|
||||||
@Test
|
|
||||||
public void testRunFlow() {
|
|
||||||
// ConsoleApplication app = new ConsoleTestApplication(
|
|
||||||
// new ConsoleManagerTestImplementation(
|
|
||||||
// new String[] {"test", ConsoleTestApplication.EXIT})); //$NON-NLS-1$
|
|
||||||
// ConsoleRunnable runnable = new ConsoleRunnable(app);
|
|
||||||
//
|
|
||||||
// Thread th = new Thread(runnable);
|
|
||||||
// th.start();
|
|
||||||
//
|
|
||||||
// runnable.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Test method for {@link fr.bigeon.gclc.socket.ConsoleRunnable#stop()}. */
|
|
||||||
@Test
|
|
||||||
public void testStop() {
|
|
||||||
// ConsoleApplication app = new ConsoleTestApplication(
|
|
||||||
// new ConsoleManagerTestImplementation(
|
|
||||||
// new String[] {"test", ConsoleTestApplication.EXIT})); //$NON-NLS-1$
|
|
||||||
// ConsoleRunnable runnable = new ConsoleRunnable(app);
|
|
||||||
// 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() {
|
|
||||||
// ConsoleApplication app = new ConsoleTestApplication(
|
|
||||||
// new ConsoleManagerTestImplementation(
|
|
||||||
// new String[] {"test", ConsoleTestApplication.EXIT})); //$NON-NLS-1$
|
|
||||||
// ConsoleRunnable runnable = new ConsoleRunnable(app);
|
|
||||||
// runnable.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright E. Bigeon (2014)
|
* GCLC Socket, Socket implementation of GCLC
|
||||||
*
|
* Copyright (C) 2014-2017 E. Bigeon
|
||||||
* emmanuel@bigeon.fr
|
* mailto: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
|
* This software is governed by the CeCILL license under French law and
|
||||||
* abiding by the rules of distribution of free software. You can use,
|
* abiding by the rules of distribution of free software. You can use,
|
||||||
@@ -35,6 +32,8 @@
|
|||||||
package fr.bigeon.gclc.socket;
|
package fr.bigeon.gclc.socket;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import fr.bigeon.gclc.ConsoleApplication;
|
import fr.bigeon.gclc.ConsoleApplication;
|
||||||
import fr.bigeon.gclc.command.Command;
|
import fr.bigeon.gclc.command.Command;
|
||||||
@@ -42,61 +41,118 @@ import fr.bigeon.gclc.command.ExitCommand;
|
|||||||
import fr.bigeon.gclc.command.HelpExecutor;
|
import fr.bigeon.gclc.command.HelpExecutor;
|
||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
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
|
/** A test-purpose application
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class ConsoleTestApplication extends ConsoleApplication {
|
public class ConsoleTestApplication {
|
||||||
|
|
||||||
/** Exit command */
|
/** Exit command */
|
||||||
public static final String EXIT = "exit"; //$NON-NLS-1$
|
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")
|
@SuppressWarnings("nls")
|
||||||
public ConsoleTestApplication(final ConsoleManager manager) {
|
public static ConsoleApplication create(final ConsoleOutput output,
|
||||||
super(manager, "Welcome to the test application. Type help or test.",
|
final ConsoleInput input,
|
||||||
"See you");
|
final ConnexionManager<Socket> manager) {
|
||||||
try {
|
try {
|
||||||
add(new ExitCommand(EXIT, this));
|
final ConsoleApplication application = new ConsoleApplication(
|
||||||
add(new HelpExecutor("help", manager, this.getRoot()));
|
output, input,
|
||||||
add(new Command("test") {
|
"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
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
return "A test command";
|
return "A test command";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.command.Command#usageDetail()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void execute(String... args) throws CommandRunException {
|
protected String usageDetail() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
// return null;
|
||||||
|
throw new RuntimeException("Not implemented yet");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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 {
|
try {
|
||||||
manager.println("Test command ran fine");
|
Thread.sleep(2000);
|
||||||
} catch (IOException e) {
|
output.println("Test command ran fine");
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
throw new CommandRunException("manager closed", e,
|
throw new CommandRunException("manager closed", e,
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
add(new Command("long") {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
return "A long run test command";
|
return "A long run test command";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.command.Command#usageDetail()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void execute(String... args) throws CommandRunException {
|
protected String usageDetail() {
|
||||||
try {
|
// TODO Auto-generated method stub
|
||||||
Thread.sleep(2000);
|
// return null;
|
||||||
manager.println("Test command ran fine");
|
throw new RuntimeException("Not implemented yet");
|
||||||
} catch (IOException | InterruptedException e) {
|
|
||||||
throw new CommandRunException("manager closed", e,
|
|
||||||
this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
application.add(
|
||||||
|
new RemoteDisconnectCommand<>("out", manager, true));
|
||||||
|
return application;
|
||||||
} catch (final InvalidCommandName e) {
|
} catch (final InvalidCommandName e) {
|
||||||
e.printStackTrace();
|
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)
|
* GCLC Socket, Socket implementation of GCLC
|
||||||
*
|
* Copyright (C) 2014-2017 E. Bigeon
|
||||||
* emmanuel@bigeon.fr
|
* mailto: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
|
* This software is governed by the CeCILL license under French law and
|
||||||
* abiding by the rules of distribution of free software. You can use,
|
* abiding by the rules of distribution of free software. You can use,
|
||||||
@@ -39,44 +36,45 @@
|
|||||||
package fr.bigeon.gclc.socket;
|
package fr.bigeon.gclc.socket;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
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.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.Arrays;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import fr.bigeon.smu.StringEncoder;
|
|
||||||
|
|
||||||
/** Test class for {@link SocketConsoleApplicationShell}
|
/** Test class for {@link SocketConsoleApplicationShell}
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
@SuppressWarnings({"static-method", "unused", "javadoc", "nls"})
|
@SuppressWarnings({"static-method", "javadoc", "nls"})
|
||||||
public class SocketConsoleApplicationTest {
|
public class SocketConsoleApplicationTest {
|
||||||
|
|
||||||
private static final StringEncoder ENCODER = new StringEncoder("%",
|
private static final Logger LOGGER = Logger
|
||||||
Arrays.asList("\n")); //$NON-NLS-1$
|
.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
|
@Test
|
||||||
public void integrationTest() {
|
public void testIntegration() throws IOException, InterruptedException {
|
||||||
Thread server;
|
Thread server;
|
||||||
try {
|
server = TestServer.getServer();
|
||||||
server = TestServer.startServer("bye");
|
Thread.sleep(1000);
|
||||||
} catch (IOException e3) {
|
|
||||||
assertNull(e3);
|
|
||||||
fail("unable to start server");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (InterruptedException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
final String hostName = "127.0.0.1";
|
final String hostName = "127.0.0.1";
|
||||||
final int portNumber = 3300;
|
final int portNumber = 3300;
|
||||||
|
|
||||||
@@ -87,32 +85,22 @@ public class SocketConsoleApplicationTest {
|
|||||||
new InputStreamReader(kkSocket.getInputStream()));) {
|
new InputStreamReader(kkSocket.getInputStream()));) {
|
||||||
|
|
||||||
String fromServer;
|
String fromServer;
|
||||||
int i = 0;
|
int i = -1;
|
||||||
String[] cmds = {"help", "toto", "test", "bye"};
|
final String[] cmds = {"help", "toto", "test", "out"};
|
||||||
while ((fromServer = in.readLine()) != null) {
|
while ((fromServer = in.readLine()) != null) {
|
||||||
System.out.println("Server: \n" + ENCODER.decode(fromServer));
|
i++;
|
||||||
if (fromServer.equals("Bye.")) {
|
fromServer = consumeToPrompt(fromServer, in);
|
||||||
|
if (fromServer == null || fromServer.equals("Bye.")) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
while (fromServer != null && !fromServer.equals("> ")) {
|
|
||||||
fromServer = in.readLine();
|
|
||||||
System.out
|
|
||||||
.println("Server: \n" + ENCODER.decode(fromServer));
|
|
||||||
}
|
|
||||||
if (fromServer == null) {
|
|
||||||
fail("Null pointer");
|
|
||||||
}
|
|
||||||
|
|
||||||
final String fromUser = cmds[i];
|
final String fromUser = cmds[i];
|
||||||
if (fromUser != null) {
|
if (fromUser != null) {
|
||||||
System.out.println("Client: " + fromUser);
|
LOGGER.fine("Client: " + fromUser);
|
||||||
out.println(fromUser);
|
out.println(fromUser);
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
assertEquals(4, i);
|
assertEquals("Disconnection command should close connection", 3, i);
|
||||||
} catch (final IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try (Socket kkSocket = new Socket(hostName, portNumber);
|
try (Socket kkSocket = new Socket(hostName, portNumber);
|
||||||
@@ -123,36 +111,31 @@ public class SocketConsoleApplicationTest {
|
|||||||
|
|
||||||
String fromServer;
|
String fromServer;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
String[] cmds = {"help", "toto", "test",
|
final String[] cmds = {"help", "toto", "test",
|
||||||
ConsoleTestApplication.EXIT};
|
ConsoleTestApplication.EXIT};
|
||||||
while ((fromServer = in.readLine()) != null) {
|
while ((fromServer = in.readLine()) != null) {
|
||||||
System.out.println("Server: \n" + ENCODER.decode(fromServer));
|
fromServer = consumeToPrompt(fromServer, in);
|
||||||
while (fromServer != null && !fromServer.equals("> ")) {
|
if (fromServer == null || fromServer.equals("Bye.")) {
|
||||||
System.out
|
|
||||||
.println("Server: \n" + ENCODER.decode(fromServer));
|
|
||||||
fromServer = in.readLine();
|
|
||||||
}
|
|
||||||
if (fromServer == null) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
System.out.println("Server: \n" + ENCODER.decode(fromServer));
|
LOGGER.info("Server: \n" + fromServer);
|
||||||
|
|
||||||
final String fromUser = cmds[i];
|
final String fromUser = cmds[i];
|
||||||
if (fromUser != null) {
|
if (fromUser != null) {
|
||||||
System.out.println("Client: " + fromUser);
|
LOGGER.info("Client: " + fromUser);
|
||||||
out.println(fromUser);
|
out.println(fromUser);
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
assertEquals(4, i);
|
assertEquals("Application exit command should close connection", 4,
|
||||||
} catch (final IOException e) {
|
i);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Thread.sleep(100);
|
|
||||||
} catch (InterruptedException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
Thread.sleep(100);
|
||||||
|
TestServer.closeServer();
|
||||||
|
server.join();
|
||||||
|
server = TestServer.getServer();
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
|
||||||
try (Socket kkSocket = new Socket(hostName, portNumber);
|
try (Socket kkSocket = new Socket(hostName, portNumber);
|
||||||
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(),
|
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(),
|
||||||
@@ -162,91 +145,25 @@ public class SocketConsoleApplicationTest {
|
|||||||
|
|
||||||
String fromServer;
|
String fromServer;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
String[] cmds = {"help", "toto", "test",
|
final String[] cmds = {"help", "toto", "test",
|
||||||
ConsoleTestApplication.EXIT};
|
ConsoleTestApplication.EXIT};
|
||||||
while ((fromServer = in.readLine()) != null) {
|
while ((fromServer = in.readLine()) != null) {
|
||||||
while (fromServer != null && !fromServer.equals("> ")) {
|
fromServer = consumeToPrompt(fromServer, in);
|
||||||
fromServer = in.readLine();
|
if (fromServer == null || fromServer.equals("Bye.")) {
|
||||||
System.out
|
|
||||||
.println("Server: \n" + ENCODER.decode(fromServer));
|
|
||||||
}
|
|
||||||
if (fromServer == null) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String fromUser = cmds[i];
|
final String fromUser = cmds[i];
|
||||||
if (fromUser != null) {
|
if (fromUser != null) {
|
||||||
System.out.println("Client: " + fromUser);
|
LOGGER.fine("Client: " + fromUser);
|
||||||
out.println(fromUser);
|
out.println(fromUser);
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
assertEquals(4, i);
|
assertEquals("Application exit command should close connection", 4,
|
||||||
} catch (final IOException e) {
|
i);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
TestServer.closeServer();
|
TestServer.closeServer();
|
||||||
try {
|
server.join();
|
||||||
Thread.sleep(100);
|
|
||||||
} catch (InterruptedException e2) {
|
|
||||||
e2.printStackTrace();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
server = TestServer.startServer(true);
|
|
||||||
} catch (IOException e2) {
|
|
||||||
assertNull(e2);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Thread.sleep(100);
|
|
||||||
} catch (InterruptedException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
try (Socket kkSocket = new Socket(hostName, portNumber);
|
|
||||||
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(),
|
|
||||||
true);
|
|
||||||
BufferedReader in = new BufferedReader(
|
|
||||||
new InputStreamReader(kkSocket.getInputStream()));) {
|
|
||||||
|
|
||||||
String fromServer;
|
|
||||||
int i = 0;
|
|
||||||
String[] cmds = {"help", "test", "close"};
|
|
||||||
while ((fromServer = in.readLine()) != null) {
|
|
||||||
assertTrue(i < 1);
|
|
||||||
while (fromServer != null && !fromServer.equals("> ") &&
|
|
||||||
!fromServer.equals("See you")) {
|
|
||||||
fromServer = in.readLine();
|
|
||||||
System.out
|
|
||||||
.println("Server: \n" + ENCODER.decode(fromServer));
|
|
||||||
}
|
|
||||||
if (fromServer == null || fromServer.equals("Bye.") ||
|
|
||||||
fromServer.equals("See you")) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String fromUser = cmds[i];
|
|
||||||
if (fromUser != null) {
|
|
||||||
System.out.println("Client: " + fromUser);
|
|
||||||
out.println(fromUser);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
assertEquals(1, i);
|
|
||||||
} catch (final IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
Thread srv = null;
|
|
||||||
try {
|
|
||||||
srv = TestServer.getServer();
|
|
||||||
} catch (IOException e1) {
|
|
||||||
assertNull(e1);
|
|
||||||
}
|
|
||||||
TestServer.closeServer();
|
|
||||||
try {
|
|
||||||
srv.join();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright E. Bigeon (2014)
|
* GCLC Socket, Socket implementation of GCLC
|
||||||
*
|
* Copyright (C) 2014-2017 E. Bigeon
|
||||||
* emmanuel@bigeon.fr
|
* mailto: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
|
* This software is governed by the CeCILL license under French law and
|
||||||
* abiding by the rules of distribution of free software. You can use,
|
* abiding by the rules of distribution of free software. You can use,
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright E. Bigeon (2014)
|
* GCLC Socket, Socket implementation of GCLC
|
||||||
*
|
* Copyright (C) 2014-2017 E. Bigeon
|
||||||
* emmanuel@bigeon.fr
|
* mailto: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
|
* This software is governed by the CeCILL license under French law and
|
||||||
* abiding by the rules of distribution of free software. You can use,
|
* abiding by the rules of distribution of free software. You can use,
|
||||||
@@ -35,7 +32,11 @@
|
|||||||
package fr.bigeon.gclc.socket;
|
package fr.bigeon.gclc.socket;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
import java.net.InetAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.ConsoleApplication;
|
||||||
|
|
||||||
/** A test server
|
/** A test server
|
||||||
*
|
*
|
||||||
@@ -44,19 +45,21 @@ import java.nio.charset.Charset;
|
|||||||
public class TestServer {
|
public class TestServer {
|
||||||
|
|
||||||
private static SocketConsoleApplicationShell SHELL;
|
private static SocketConsoleApplicationShell SHELL;
|
||||||
private static Thread server;
|
private static ConnexionManager<Socket> manager;
|
||||||
|
|
||||||
/** @param args no argument
|
private static Thread server;
|
||||||
* @throws IOException if the server starting failed */
|
private static PluggableConsoleInput input;
|
||||||
public static void main(String... args) throws IOException {
|
private static PluggableConsoleOutput output;
|
||||||
try {
|
|
||||||
startServer(false).join();
|
public static synchronized void closeServer() {
|
||||||
} catch (final InterruptedException e) {
|
SHELL.stop();
|
||||||
e.printStackTrace();
|
input.close();
|
||||||
}
|
output.close();
|
||||||
|
SHELL = null;
|
||||||
|
server = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Thread getServer() throws IOException {
|
public static synchronized Thread getServer() throws IOException {
|
||||||
if (server == null) {
|
if (server == null) {
|
||||||
server = new Thread(getShell(), "gclcServer");
|
server = new Thread(getShell(), "gclcServer");
|
||||||
server.start();
|
server.start();
|
||||||
@@ -64,43 +67,39 @@ public class TestServer {
|
|||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SocketConsoleApplicationShell getShell() throws IOException {
|
private static SocketConsoleApplicationShell getShell() throws UnknownHostException {
|
||||||
if (SHELL == null) {
|
if (SHELL == null) {
|
||||||
SHELL = new SocketConsoleApplicationShell(3300, "close",
|
input = new PluggableConsoleInput();
|
||||||
ConsoleTestApplication.EXIT, Charset.forName("UTF-8"));
|
input.setPrompt("> \n");
|
||||||
final ConsoleTestApplication app = new ConsoleTestApplication(
|
output = new PluggableConsoleOutput();
|
||||||
SHELL.getConsoleManager());
|
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);
|
SHELL.setApplication(app);
|
||||||
|
final Thread th = new Thread(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
app.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
th.start();
|
||||||
}
|
}
|
||||||
return SHELL;
|
return SHELL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Thread startServer(boolean autoClose) throws IOException {
|
/** @param args no argument
|
||||||
if (SHELL == null) {
|
* @throws IOException if the server starting failed */
|
||||||
SHELL = new SocketConsoleApplicationShell(3300, autoClose,
|
public static void main(final String... args) throws IOException {
|
||||||
ConsoleTestApplication.EXIT, Charset.forName("UTF-8"));
|
try {
|
||||||
final ConsoleTestApplication app = new ConsoleTestApplication(
|
getServer().join();
|
||||||
SHELL.getConsoleManager());
|
} catch (final InterruptedException e) {
|
||||||
SHELL.setApplication(app);
|
e.printStackTrace();
|
||||||
server = null;
|
|
||||||
}
|
}
|
||||||
return getServer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Thread startServer(String closeConnection) throws IOException {
|
|
||||||
if (SHELL == null) {
|
|
||||||
SHELL = new SocketConsoleApplicationShell(3300, closeConnection,
|
|
||||||
ConsoleTestApplication.EXIT, Charset.forName("UTF-8"));
|
|
||||||
final ConsoleTestApplication app = new ConsoleTestApplication(
|
|
||||||
SHELL.getConsoleManager());
|
|
||||||
SHELL.setApplication(app);
|
|
||||||
server = null;
|
|
||||||
}
|
|
||||||
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) -->
|
<!-- Copyright E. Bigeon (2015) -->
|
||||||
<!-- -->
|
<!-- -->
|
||||||
<!-- emmanuel@bigeon.fr -->
|
<!-- emmanuel@bigeon.fr -->
|
||||||
@@ -32,12 +63,10 @@
|
|||||||
<!-- The fact that you are presently reading this means that you have had -->
|
<!-- The fact that you are presently reading this means that you have had -->
|
||||||
<!-- knowledge of the CeCILL license and that you accept its terms. -->
|
<!-- 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"
|
<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">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
|
|
||||||
>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>gclc-swt</artifactId>
|
<artifactId>gclc-swt</artifactId>
|
||||||
<version>1.1.0-SNAPSHOT</version>
|
<version>1.1.5-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<url>http://www.bigeon.fr/emmanuel</url>
|
<url>http://www.bigeon.fr/emmanuel</url>
|
||||||
<properties>
|
<properties>
|
||||||
@@ -45,20 +74,20 @@
|
|||||||
<project.scm.id>git.bigeon.net</project.scm.id>
|
<project.scm.id>git.bigeon.net</project.scm.id>
|
||||||
</properties>
|
</properties>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>fr.bigeon</groupId>
|
<groupId>fr.bigeon.config</groupId>
|
||||||
<artifactId>ebigeon-config</artifactId>
|
<artifactId>ebigeon-config</artifactId>
|
||||||
<version>1.7.1</version>
|
<version>1.8.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>fr.bigeon</groupId>
|
<groupId>fr.bigeon</groupId>
|
||||||
<artifactId>gclc</artifactId>
|
<artifactId>gclc</artifactId>
|
||||||
<version>1.3.0</version>
|
<version>2.0.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>fr.bigeon</groupId>
|
<groupId>fr.bigeon</groupId>
|
||||||
<artifactId>collections</artifactId>
|
<artifactId>collections</artifactId>
|
||||||
<version>1.0.1</version>
|
<version>1.1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<inceptionYear>2015</inceptionYear>
|
<inceptionYear>2015</inceptionYear>
|
||||||
@@ -100,4 +129,5 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
</profile>
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
|
<groupId>fr.bigeon.gclc</groupId>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright E. Bigeon (2015)
|
* GCLC swt, provide a swt window for console applications
|
||||||
*
|
* Copyright (C) 2015-2017 E. Bigeon
|
||||||
* emmanuel@bigeon.fr
|
* mailto:emmanuel@bigeon.fr
|
||||||
*
|
|
||||||
* This software is a computer program whose purpose is to
|
|
||||||
* provide a swt window for console applications.
|
|
||||||
*
|
*
|
||||||
* This software is governed by the CeCILL license under French law and
|
* This software is governed by the CeCILL license under French law and
|
||||||
* abiding by the rules of distribution of free software. You can use,
|
* abiding by the rules of distribution of free software. You can use,
|
||||||
@@ -38,8 +35,6 @@
|
|||||||
*/
|
*/
|
||||||
package fr.bigeon.gclc.swt;
|
package fr.bigeon.gclc.swt;
|
||||||
|
|
||||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
|
||||||
|
|
||||||
/** This class represents an object used to send commands to a console
|
/** This class represents an object used to send commands to a console
|
||||||
* application.
|
* application.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -47,13 +42,16 @@ import fr.bigeon.gclc.manager.ConsoleManager;
|
|||||||
* and set, and then validate the input.
|
* and set, and then validate the input.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public interface ConsoleDelayIO extends ConsoleManager {
|
public interface ConsoleDelayIO {
|
||||||
/** Actually send the input as the prompt next input. */
|
/** Get the input text.
|
||||||
void validateInput();
|
* @return the non validated input */
|
||||||
|
String getInput();
|
||||||
|
|
||||||
/** @param input the input to set */
|
/** Set the input text.
|
||||||
|
*
|
||||||
|
* @param input the input to set */
|
||||||
void setInput(String input);
|
void setInput(String input);
|
||||||
|
|
||||||
/** @return the non validated input */
|
/** Actually send the input as the prompt next input. */
|
||||||
String getInput();
|
void validateInput();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright E. Bigeon (2015)
|
* GCLC swt, provide a swt window for console applications
|
||||||
*
|
* Copyright (C) 2015-2017 E. Bigeon
|
||||||
* emmanuel@bigeon.fr
|
* mailto:emmanuel@bigeon.fr
|
||||||
*
|
|
||||||
* This software is a computer program whose purpose is to
|
|
||||||
* provide a swt window for console applications.
|
|
||||||
*
|
*
|
||||||
* This software is governed by the CeCILL license under French law and
|
* This software is governed by the CeCILL license under French law and
|
||||||
* abiding by the rules of distribution of free software. You can use,
|
* abiding by the rules of distribution of free software. You can use,
|
||||||
@@ -45,40 +42,46 @@ import org.eclipse.swt.events.KeyEvent;
|
|||||||
import fr.bigeon.collections.ArrayRibbon;
|
import fr.bigeon.collections.ArrayRibbon;
|
||||||
import fr.bigeon.collections.Ribbon;
|
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 */
|
* @author Emmanuel Bigeon */
|
||||||
public final class HistoryTextKeyListener extends KeyAdapter {
|
public final class HistoryTextKeyListener extends KeyAdapter {
|
||||||
|
|
||||||
/** The size of commands history */
|
/** The size of commands history. */
|
||||||
private static final int DEFAULT_HISTORY_SIZE = 10;
|
private static final int DEFAULT_HISTORY_SIZE = 10;
|
||||||
/** The empty string constant */
|
/** The empty string constant. */
|
||||||
private static final String EMPTY = ""; //$NON-NLS-1$
|
private static final String EMPTY = ""; //$NON-NLS-1$
|
||||||
/** The history ribbon */
|
/** The history ribbon. */
|
||||||
private final Ribbon<String> commands;
|
private final Ribbon<String> commands;
|
||||||
/** The current index in history search */
|
/** The current index in history search. */
|
||||||
private int currentIndex = 0;
|
private int currentIndex = 0;
|
||||||
/** The console to notify of command validation */
|
/** The console to notify of command validation. */
|
||||||
private final ConsoleDelayIO console;
|
private final ConsoleDelayIO console;
|
||||||
|
|
||||||
/** @param console the console delayed */
|
/** Create the key listener that cycle the history.
|
||||||
public HistoryTextKeyListener(ConsoleDelayIO console) {
|
*
|
||||||
|
* @param console the console delayed */
|
||||||
|
public HistoryTextKeyListener(final ConsoleDelayIO console) {
|
||||||
super();
|
super();
|
||||||
this.console = console;
|
this.console = console;
|
||||||
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
|
@Override
|
||||||
public void keyPressed(KeyEvent e) {
|
public void keyPressed(final KeyEvent e) {
|
||||||
|
|
||||||
pressedKeyCode(e.keyCode);
|
pressedKeyCode(e.keyCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param keyCode the pressed key code */
|
/** Indicate a pressed key combination.
|
||||||
public void pressedKeyCode(int keyCode) {
|
*
|
||||||
|
* @param keyCode the pressed key code */
|
||||||
|
public void pressedKeyCode(final int keyCode) {
|
||||||
// Enter validates the command if prompting
|
// Enter validates the command if prompting
|
||||||
if (keyCode == '\r') {
|
if (keyCode == '\r') {
|
||||||
String input = console.getInput();
|
final String input = console.getInput();
|
||||||
if (!input.isEmpty()) {
|
if (!input.isEmpty()) {
|
||||||
commands.add(input);
|
commands.add(input);
|
||||||
}
|
}
|
||||||
@@ -90,7 +93,7 @@ public final class HistoryTextKeyListener extends KeyAdapter {
|
|||||||
if (keyCode == SWT.ARROW_UP &&
|
if (keyCode == SWT.ARROW_UP &&
|
||||||
currentIndex < commands.size() - 1) {
|
currentIndex < commands.size() - 1) {
|
||||||
currentIndex++;
|
currentIndex++;
|
||||||
String cmd = commands.get(commands.size() - currentIndex - 1);
|
final String cmd = commands.get(commands.size() - currentIndex - 1);
|
||||||
console.setInput(cmd);
|
console.setInput(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +103,7 @@ public final class HistoryTextKeyListener extends KeyAdapter {
|
|||||||
currentIndex--;
|
currentIndex--;
|
||||||
console.setInput(EMPTY);
|
console.setInput(EMPTY);
|
||||||
} else if (currentIndex > 0) {
|
} else if (currentIndex > 0) {
|
||||||
String cmd = commands
|
final String cmd = commands
|
||||||
.get(commands.size() - (--currentIndex) - 1);
|
.get(commands.size() - (--currentIndex) - 1);
|
||||||
console.setInput(cmd);
|
console.setInput(cmd);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright E. Bigeon (2015)
|
* GCLC swt, provide a swt window for console applications
|
||||||
*
|
* Copyright (C) 2015-2017 E. Bigeon
|
||||||
* emmanuel@bigeon.fr
|
* mailto:emmanuel@bigeon.fr
|
||||||
*
|
|
||||||
* This software is a computer program whose purpose is to
|
|
||||||
* provide a swt window for console applications.
|
|
||||||
*
|
*
|
||||||
* This software is governed by the CeCILL license under French law and
|
* This software is governed by the CeCILL license under French law and
|
||||||
* abiding by the rules of distribution of free software. You can use,
|
* 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 java.util.logging.Logger;
|
||||||
|
|
||||||
import org.eclipse.swt.SWT;
|
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.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
@@ -53,118 +48,114 @@ import org.eclipse.swt.widgets.Label;
|
|||||||
import org.eclipse.swt.widgets.Text;
|
import org.eclipse.swt.widgets.Text;
|
||||||
|
|
||||||
import fr.bigeon.gclc.ConsoleApplication;
|
import fr.bigeon.gclc.ConsoleApplication;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
|
import fr.bigeon.gclc.tools.ConstantString;
|
||||||
|
import fr.bigeon.gclc.tools.StringProvider;
|
||||||
|
|
||||||
/** A SWT component to connect to gclc {@link ConsoleApplication}
|
/** A SWT component to connect to gclc {@link ConsoleApplication}.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class SWTConsole extends Composite implements ConsoleDelayIO {
|
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;
|
||||||
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$
|
||||||
private static final String CMD_PREFIX = "[CMD] "; //$NON-NLS-1$
|
/** The class logger. */
|
||||||
/** The class logger */
|
private static final Logger LOGGER = Logger
|
||||||
private static final Logger LOGGER = Logger
|
|
||||||
.getLogger(SWTConsole.class.getName());
|
.getLogger(SWTConsole.class.getName());
|
||||||
/** The empty string constant */
|
/** The empty string constant. */
|
||||||
private static final String EMPTY = ""; //$NON-NLS-1$
|
private static final String EMPTY = ""; //$NON-NLS-1$
|
||||||
/** The console output text field */
|
/** The console output text field. */
|
||||||
private final Text consoleOutput;
|
private final Text consoleOutput;
|
||||||
/** The console input text field */
|
/** The console input text field. */
|
||||||
private final Text consoleInput;
|
private final Text consoleInput;
|
||||||
/** The prompt label */
|
/** The prompt label. */
|
||||||
private final Label lblPromptlabel;
|
private final Label lblPromptlabel;
|
||||||
/** The prompt text */
|
/** The prompt text. */
|
||||||
private String prompt = ">"; //$NON-NLS-1$
|
private StringProvider prompt = new ConstantString("> "); //$NON-NLS-1$
|
||||||
/** The command entered by the user */
|
/** The command entered by the user. */
|
||||||
private String command = null;
|
private String command = null;
|
||||||
/** If the prompt should be active */
|
/** If the prompt should be active. */
|
||||||
private boolean prompting = false;
|
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();
|
private final Object promptLock = new Object();
|
||||||
|
|
||||||
/** Create the composite.
|
/** Create the composite.
|
||||||
*
|
*
|
||||||
* @param parent the prent composite
|
* @param parent the prent composite
|
||||||
* @param style the composite style */
|
* @param style the composite style */
|
||||||
public SWTConsole(Composite parent, int style) {
|
public SWTConsole(final Composite parent, final int style) {
|
||||||
super(parent, style);
|
super(parent, style);
|
||||||
|
|
||||||
setLayout(new GridLayout(LAYOUT_NB_COLUMNS, false));
|
setLayout(new GridLayout(LAYOUT_NB_COLUMNS, false));
|
||||||
|
|
||||||
consoleOutput = new Text(this, SWT.BORDER | SWT.READ_ONLY | SWT.WRAP |
|
consoleOutput = new Text(this,
|
||||||
SWT.V_SCROLL | SWT.MULTI);
|
SWT.BORDER | SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL | SWT.MULTI);
|
||||||
consoleOutput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true,
|
consoleOutput.setLayoutData(
|
||||||
LAYOUT_NB_COLUMNS, 1));
|
new GridData(SWT.FILL, SWT.FILL, true, true, LAYOUT_NB_COLUMNS, 1));
|
||||||
consoleOutput.setRedraw(true);
|
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 = new Label(this, SWT.NONE);
|
||||||
lblPromptlabel.setText(prompt);
|
lblPromptlabel.setText(prompt.apply());
|
||||||
|
|
||||||
consoleInput = new Text(this, SWT.BORDER);
|
consoleInput = new Text(this, SWT.BORDER);
|
||||||
consoleInput.setLayoutData(
|
consoleInput.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
|
||||||
new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
|
|
||||||
consoleInput.addKeyListener(new HistoryTextKeyListener(this));
|
consoleInput.addKeyListener(new HistoryTextKeyListener(this));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@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 (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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void checkSubclass() {
|
protected void checkSubclass() {
|
||||||
// Disable the check that prevents subclassing of SWT components
|
// 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)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.ConsoleManager#getPrompt() */
|
* @see fr.bigeon.gclc.ConsoleManager#getPrompt() */
|
||||||
@Override
|
@Override
|
||||||
public String getPrompt() {
|
public StringProvider getPrompt() {
|
||||||
return prompt;
|
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)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.ConsoleManager#print(java.lang.String) */
|
* @see fr.bigeon.gclc.ConsoleManager#print(java.lang.String) */
|
||||||
@Override
|
@Override
|
||||||
@@ -173,7 +164,9 @@ public class SWTConsole extends Composite implements ConsoleDelayIO {
|
|||||||
@SuppressWarnings("synthetic-access")
|
@SuppressWarnings("synthetic-access")
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
consoleOutput.append(text);
|
if (!consoleOutput.isDisposed()) {
|
||||||
|
consoleOutput.append(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -186,7 +179,9 @@ public class SWTConsole extends Composite implements ConsoleDelayIO {
|
|||||||
@SuppressWarnings("synthetic-access")
|
@SuppressWarnings("synthetic-access")
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
consoleOutput.append(System.lineSeparator());
|
if (!consoleOutput.isDisposed()) {
|
||||||
|
consoleOutput.append(System.lineSeparator());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -199,7 +194,9 @@ public class SWTConsole extends Composite implements ConsoleDelayIO {
|
|||||||
@SuppressWarnings("synthetic-access")
|
@SuppressWarnings("synthetic-access")
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
consoleOutput.append(message + System.lineSeparator());
|
if (!consoleOutput.isDisposed()) {
|
||||||
|
consoleOutput.append(message + System.lineSeparator());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -215,20 +212,68 @@ public class SWTConsole extends Composite implements ConsoleDelayIO {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Display.getDefault().syncExec(new Runnable() {
|
Display.getDefault().syncExec(new Runnable() {
|
||||||
@SuppressWarnings("synthetic-access")
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
consoleInput.setEnabled(true);
|
if (!consoleInput.isDisposed()) {
|
||||||
consoleInput.setFocus();
|
consoleInput.setEnabled(true);
|
||||||
|
lblPromptlabel.setText(prompt.apply());
|
||||||
|
// relayout
|
||||||
|
SWTConsole.this.layout();
|
||||||
|
consoleInput.setFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
prompting = true;
|
prompting = true;
|
||||||
promptLock.notifyAll();
|
promptLock.notifyAll();
|
||||||
promptLock.wait();
|
while (prompting) {
|
||||||
|
promptLock.wait();
|
||||||
|
}
|
||||||
} catch (final InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
LOGGER.log(Level.WARNING,
|
LOGGER.log(Level.WARNING, "Error in synchronization of prompting", e); //$NON-NLS-1$
|
||||||
"Error in synchronization of prompting", e); //$NON-NLS-1$
|
|
||||||
command = null;
|
command = null;
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isDisposed()) {
|
||||||
|
throw new IOException("Input closed"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#prompt(long) */
|
||||||
|
@Override
|
||||||
|
public String prompt(final long timeout) throws IOException {
|
||||||
|
synchronized (promptLock) {
|
||||||
|
if (isDisposed()) {
|
||||||
|
throw new IOException();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Display.getDefault().syncExec(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!consoleInput.isDisposed()) {
|
||||||
|
consoleInput.setEnabled(true);
|
||||||
|
lblPromptlabel.setText(prompt.apply());
|
||||||
|
// relayout
|
||||||
|
SWTConsole.this.layout();
|
||||||
|
consoleInput.setFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
prompting = true;
|
||||||
|
command = null;
|
||||||
|
promptLock.notifyAll();
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
long cur = start;
|
||||||
|
while (prompting && start + timeout>cur) {
|
||||||
|
promptLock.wait((cur-start-timeout)/2);
|
||||||
|
cur = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Error in synchronization of prompting", e); //$NON-NLS-1$
|
||||||
|
command = null;
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isDisposed()) {
|
if (isDisposed()) {
|
||||||
@@ -250,11 +295,13 @@ public class SWTConsole extends Composite implements ConsoleDelayIO {
|
|||||||
@SuppressWarnings("synthetic-access")
|
@SuppressWarnings("synthetic-access")
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
lblPromptlabel.setText(message);
|
if (!consoleOutput.isDisposed()) {
|
||||||
// relayout
|
lblPromptlabel.setText(message);
|
||||||
SWTConsole.this.layout();
|
// relayout
|
||||||
consoleInput.setEnabled(true);
|
SWTConsole.this.layout();
|
||||||
consoleInput.setFocus();
|
consoleInput.setEnabled(true);
|
||||||
|
consoleInput.setFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
prompting = true;
|
prompting = true;
|
||||||
@@ -263,17 +310,19 @@ public class SWTConsole extends Composite implements ConsoleDelayIO {
|
|||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
} catch (final InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
LOGGER.log(Level.WARNING,
|
LOGGER.log(Level.WARNING, "Error in synchronization of prompting", e); //$NON-NLS-1$
|
||||||
"Error in synchronization of prompting", e); //$NON-NLS-1$
|
|
||||||
command = null;
|
command = null;
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
} finally {
|
} finally {
|
||||||
Display.getDefault().syncExec(new Runnable() {
|
Display.getDefault().syncExec(new Runnable() {
|
||||||
@SuppressWarnings("synthetic-access")
|
@SuppressWarnings("synthetic-access")
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
lblPromptlabel.setText(prompt);
|
if (!consoleOutput.isDisposed()) {
|
||||||
// relayout
|
lblPromptlabel.setText(prompt.apply());
|
||||||
SWTConsole.this.layout();
|
// relayout
|
||||||
|
SWTConsole.this.layout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -281,6 +330,15 @@ public class SWTConsole extends Composite implements ConsoleDelayIO {
|
|||||||
return command;
|
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)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.swt.widgets.Composite#setFocus() */
|
* @see org.eclipse.swt.widgets.Composite#setFocus() */
|
||||||
@Override
|
@Override
|
||||||
@@ -288,45 +346,39 @@ public class SWTConsole extends Composite implements ConsoleDelayIO {
|
|||||||
return consoleInput.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());
|
||||||
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.ConsoleManager#setPrompt(java.lang.String) */
|
* @see fr.bigeon.gclc.ConsoleManager#setPrompt(java.lang.String) */
|
||||||
@Override
|
@Override
|
||||||
public void setPrompt(final String prompt) {
|
public void setPrompt(final StringProvider prompt) {
|
||||||
this.prompt = prompt;
|
this.prompt = prompt;
|
||||||
Display.getDefault().syncExec(new Runnable() {
|
Display.getDefault().syncExec(new Runnable() {
|
||||||
@SuppressWarnings("synthetic-access")
|
@SuppressWarnings("synthetic-access")
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
lblPromptlabel.setText(prompt);
|
if (!consoleOutput.isDisposed()) {
|
||||||
// relayout
|
lblPromptlabel.setText(prompt.apply());
|
||||||
SWTConsole.this.layout();
|
// relayout
|
||||||
|
SWTConsole.this.layout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see fr.bigeon.gclc.manager.ConsoleManager#close() */
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void setPrompt(String prompt) {
|
||||||
synchronized (promptLock) {
|
setPrompt(new ConstantString(prompt));
|
||||||
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 */
|
/** @param string the text */
|
||||||
public void setText(String string) {
|
public void setText(final String string) {
|
||||||
consoleInput.setText(string);
|
consoleInput.setText(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,19 +389,38 @@ public class SWTConsole extends Composite implements ConsoleDelayIO {
|
|||||||
validateInput();
|
validateInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
* @see fr.bigeon.gclc.swt.ConsoleDelayIO#setInput(java.lang.String) */
|
*
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setInput(String input) {
|
public void validateInput() {
|
||||||
consoleInput.setText(input);
|
Display.getDefault().syncExec(new Runnable() {
|
||||||
consoleInput.setSelection(input.length());
|
@SuppressWarnings("synthetic-access")
|
||||||
}
|
@Override
|
||||||
|
public void run() {
|
||||||
/* (non-Javadoc)
|
consoleInput.setEnabled(false);
|
||||||
* @see fr.bigeon.gclc.swt.ConsoleDelayIO#getInput() */
|
}
|
||||||
@Override
|
});
|
||||||
public String getInput() {
|
synchronized (promptLock) {
|
||||||
return consoleInput.getText();
|
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)
|
* GCLC swt, provide a swt window for console applications
|
||||||
*
|
* Copyright (C) 2015-2017 E. Bigeon
|
||||||
* emmanuel@bigeon.fr
|
* mailto:emmanuel@bigeon.fr
|
||||||
*
|
|
||||||
* This software is a computer program whose purpose is to
|
|
||||||
* provide a swt window for console applications.
|
|
||||||
*
|
*
|
||||||
* This software is governed by the CeCILL license under French law and
|
* This software is governed by the CeCILL license under French law and
|
||||||
* abiding by the rules of distribution of free software. You can use,
|
* 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.Display;
|
||||||
import org.eclipse.swt.widgets.Shell;
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
|
||||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
|
||||||
|
|
||||||
/** A shell containing a {@link SWTConsole}
|
/** A shell containing a {@link SWTConsole}
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class SWTConsoleShell extends Shell {
|
public final class SWTConsoleShell extends Shell {
|
||||||
|
|
||||||
/** The console component */
|
/** The console component */
|
||||||
private SWTConsole console;
|
private SWTConsole console;
|
||||||
@@ -57,7 +52,7 @@ public class SWTConsoleShell extends Shell {
|
|||||||
/** Create the shell.
|
/** Create the shell.
|
||||||
*
|
*
|
||||||
* @param display the display */
|
* @param display the display */
|
||||||
public SWTConsoleShell(Display display) {
|
public SWTConsoleShell(final Display display) {
|
||||||
super(display, SWT.SHELL_TRIM);
|
super(display, SWT.SHELL_TRIM);
|
||||||
setLayout(new FillLayout(SWT.HORIZONTAL));
|
setLayout(new FillLayout(SWT.HORIZONTAL));
|
||||||
|
|
||||||
@@ -75,11 +70,6 @@ public class SWTConsoleShell extends Shell {
|
|||||||
setText("Console Application"); //$NON-NLS-1$
|
setText("Console Application"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the console manager */
|
|
||||||
public ConsoleManager getManager() {
|
|
||||||
return console;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.swt.widgets.Shell#dispose() */
|
* @see org.eclipse.swt.widgets.Shell#dispose() */
|
||||||
@Override
|
@Override
|
||||||
@@ -87,4 +77,9 @@ public class SWTConsoleShell extends Shell {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
console.close();
|
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)
|
* GCLC swt, provide a swt window for console applications
|
||||||
*
|
* Copyright (C) 2015-2017 E. Bigeon
|
||||||
* emmanuel@bigeon.fr
|
* mailto:emmanuel@bigeon.fr
|
||||||
*
|
|
||||||
* This software is a computer program whose purpose is to
|
|
||||||
* provide a swt window for console applications.
|
|
||||||
*
|
*
|
||||||
* This software is governed by the CeCILL license under French law and
|
* This software is governed by the CeCILL license under French law and
|
||||||
* abiding by the rules of distribution of free software. You can use,
|
* abiding by the rules of distribution of free software. You can use,
|
||||||
@@ -40,8 +37,6 @@ package fr.bigeon.gclc.swt;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -58,51 +53,6 @@ public class HistoryTextKeyListenerTest {
|
|||||||
ConsoleDelayIO io = new ConsoleDelayIO() {
|
ConsoleDelayIO io = new ConsoleDelayIO() {
|
||||||
private String input = "";
|
private String input = "";
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPrompt(String prompt) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String prompt(String message) throws IOException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String prompt() throws IOException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(String message) throws IOException {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println() throws IOException {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void print(String text) throws IOException {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isClosed() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPrompt() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateInput() {
|
public void validateInput() {
|
||||||
input = "";
|
input = "";
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright E. Bigeon (2015)
|
* GCLC swt, provide a swt window for console applications
|
||||||
*
|
* Copyright (C) 2015-2017 E. Bigeon
|
||||||
* emmanuel@bigeon.fr
|
* mailto:emmanuel@bigeon.fr
|
||||||
*
|
|
||||||
* This software is a computer program whose purpose is to
|
|
||||||
* provide a swt window for console applications.
|
|
||||||
*
|
*
|
||||||
* This software is governed by the CeCILL license under French law and
|
* This software is governed by the CeCILL license under French law and
|
||||||
* abiding by the rules of distribution of free software. You can use,
|
* abiding by the rules of distribution of free software. You can use,
|
||||||
@@ -39,7 +36,9 @@
|
|||||||
package fr.bigeon.gclc.swt;
|
package fr.bigeon.gclc.swt;
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@@ -48,10 +47,14 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import fr.bigeon.gclc.ConsoleApplication;
|
import fr.bigeon.gclc.ConsoleApplication;
|
||||||
import fr.bigeon.gclc.command.Command;
|
import fr.bigeon.gclc.command.Command;
|
||||||
|
import fr.bigeon.gclc.command.ExitCommand;
|
||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
|
|
||||||
/** <p>
|
/**
|
||||||
|
* <p>
|
||||||
* TODO
|
* TODO
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
@@ -59,66 +62,195 @@ import fr.bigeon.gclc.exception.InvalidCommandName;
|
|||||||
public class SWTConsoleShellTest {
|
public class SWTConsoleShellTest {
|
||||||
|
|
||||||
protected static final long TWO_SECONDS = 2000;
|
protected static final long TWO_SECONDS = 2000;
|
||||||
private static final Display DISPLAY = new Display();
|
private static final Display DISPLAY = Display.getDefault();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConsoleClose() {
|
public void test() {
|
||||||
final SWTConsoleShell shell = new SWTConsoleShell(DISPLAY);
|
final SWTConsoleShell shell = new SWTConsoleShell(DISPLAY);
|
||||||
final SWTConsole swtConsole = (SWTConsole) shell.getManager();
|
final SWTConsole swtConsole = shell.getManager();
|
||||||
swtConsole.close();
|
|
||||||
swtConsole.setPrompt(":");
|
|
||||||
try {
|
try {
|
||||||
final ConsoleApplication appl = new ConsoleApplication(swtConsole,
|
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") {
|
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
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
return "a long running command";
|
return "a long running command";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||||
@Override
|
@Override
|
||||||
public void execute(String... args) {
|
protected String usageDetail() {
|
||||||
try {
|
// TODO Auto-generated method stub
|
||||||
Thread.sleep(TWO_SECONDS);
|
// return null;
|
||||||
} catch (InterruptedException e) {
|
throw new RuntimeException("Not implemented yet");
|
||||||
// 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, this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// shell.pack();
|
// shell.pack();
|
||||||
shell.open();
|
shell.open();
|
||||||
Thread applThread = new Thread(new Runnable() {
|
final Thread applThread = new Thread(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
appl.start();
|
appl.start();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Thread testThread = new Thread(new Runnable() {
|
final Thread testThread = new Thread(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(TWO_SECONDS);
|
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
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -159,7 +291,7 @@ public class SWTConsoleShellTest {
|
|||||||
swtConsole.validateCommand();
|
swtConsole.validateCommand();
|
||||||
try {
|
try {
|
||||||
Thread.sleep(TWO_SECONDS);
|
Thread.sleep(TWO_SECONDS);
|
||||||
} catch (InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -169,6 +301,7 @@ public class SWTConsoleShellTest {
|
|||||||
shell.dispose();
|
shell.dispose();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
applThread.start();
|
applThread.start();
|
||||||
@@ -178,98 +311,21 @@ public class SWTConsoleShellTest {
|
|||||||
DISPLAY.sleep();
|
DISPLAY.sleep();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// DISPLAY.dispose();
|
swtConsole.setPrompt(">");
|
||||||
assertTrue(appl.getManager().isClosed());
|
try {
|
||||||
Thread.sleep(TWO_SECONDS);
|
swtConsole.prompt();
|
||||||
assertFalse(appl.isRunning());
|
fail("Prompting when closed should fail!");
|
||||||
} catch (InvalidCommandName e) {
|
} catch (final IOException e) {
|
||||||
// TODO Auto-generated catch block
|
assertNotNull(e);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// DISPLAY.dispose();
|
// DISPLAY.dispose();
|
||||||
assertTrue(appl.getManager().isClosed());
|
assertTrue(swtConsole.isClosed());
|
||||||
Thread.sleep(TWO_SECONDS);
|
Thread.sleep(TWO_SECONDS);
|
||||||
assertFalse(appl.isRunning());
|
assertFalse(appl.isRunning());
|
||||||
} catch (InvalidCommandName e) {
|
} catch (final InvalidCommandName e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>fr.bigeon</groupId>
|
<groupId>fr.bigeon</groupId>
|
||||||
<artifactId>gclc</artifactId>
|
<artifactId>gclc</artifactId>
|
||||||
<version>1.2.6</version>
|
<version>2.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<name>GCLC system command</name>
|
<name>GCLC system command</name>
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ import java.util.logging.Logger;
|
|||||||
import fr.bigeon.gclc.command.Command;
|
import fr.bigeon.gclc.command.Command;
|
||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
|
|
||||||
/** <p>
|
/** A command that will execute a system command.
|
||||||
* TODO
|
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class ExecSystemCommand extends Command {
|
public class ExecSystemCommand extends Command {
|
||||||
@@ -30,71 +30,68 @@ public class ExecSystemCommand extends Command {
|
|||||||
/** The class logger */
|
/** The class logger */
|
||||||
private static final Logger LOGGER = Logger
|
private static final Logger LOGGER = Logger
|
||||||
.getLogger(ExecSystemCommand.class.getName());
|
.getLogger(ExecSystemCommand.class.getName());
|
||||||
/** The manager for the application's user interface */
|
|
||||||
private final ConsoleManager manager;
|
|
||||||
|
|
||||||
/** @param name the name of the command (the input from the manager that
|
/***/
|
||||||
* should trigger this command)
|
public ExecSystemCommand() {
|
||||||
* @param manager the console manager for input and outputs */
|
super(COMMAND_DEFAULT_NAME);
|
||||||
public ExecSystemCommand(String name, ConsoleManager manager) {
|
|
||||||
super(name);
|
|
||||||
this.manager = manager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param manager the console manager for input and outputs */
|
/** @param name the name of the command (the input from the manager that
|
||||||
public ExecSystemCommand(ConsoleManager manager) {
|
* should trigger this command) */
|
||||||
super(COMMAND_DEFAULT_NAME);
|
public ExecSystemCommand(final String name) {
|
||||||
this.manager = manager;
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.ICommand#execute(java.lang.String[]) */
|
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.manager.
|
||||||
@SuppressWarnings("resource")
|
* ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||||
|
* java.lang.String[]) */
|
||||||
@Override
|
@Override
|
||||||
public void execute(String... args) throws CommandRunException {
|
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||||
|
final String... args) throws CommandRunException {
|
||||||
Process proc;
|
Process proc;
|
||||||
try {
|
try {
|
||||||
proc = Runtime.getRuntime().exec(args);
|
proc = Runtime.getRuntime().exec(args);
|
||||||
} catch (IOException e2) {
|
} catch (final IOException e2) {
|
||||||
LOGGER.log(Level.SEVERE, "Unable to run process", e2); //$NON-NLS-1$
|
LOGGER.log(Level.SEVERE, "Unable to run process", e2); //$NON-NLS-1$
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final InputStream is = proc
|
final InputStream is = proc
|
||||||
.getInputStream();
|
.getInputStream();
|
||||||
Thread th = new Thread(new Runnable() {
|
final Thread th = new Thread(new Runnable() {
|
||||||
|
|
||||||
@SuppressWarnings("synthetic-access")
|
@SuppressWarnings("synthetic-access")
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
readToEnd(is);
|
readToEnd(out, is);
|
||||||
is.close();
|
is.close();
|
||||||
} catch (CommandRunException e) {
|
} catch (final CommandRunException e) {
|
||||||
LOGGER.log(Level.WARNING,
|
LOGGER.log(Level.WARNING,
|
||||||
"Manager was closed in the meantime...", e); //$NON-NLS-1$
|
"Manager was closed in the meantime...", e); //$NON-NLS-1$
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
LOGGER.log(Level.WARNING, "Input stream was closed...", e); //$NON-NLS-1$
|
LOGGER.log(Level.WARNING, "Input stream was closed...", e); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
th.start();
|
th.start();
|
||||||
manager.setPrompt("");
|
in.setPrompt(""); //$NON-NLS-1$
|
||||||
final OutputStream os = proc.getOutputStream();
|
final OutputStream os = proc.getOutputStream();
|
||||||
try (BufferedWriter writer = new BufferedWriter(
|
try (BufferedWriter writer = new BufferedWriter(
|
||||||
new OutputStreamWriter(os))) {
|
new OutputStreamWriter(os))) {
|
||||||
while (th.isAlive()) {
|
while (th.isAlive()) {
|
||||||
String user;
|
String user;
|
||||||
try {
|
try {
|
||||||
user = manager.prompt();
|
user = in.prompt();
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
throw new CommandRunException(
|
throw new CommandRunException(
|
||||||
CommandRunExceptionType.INTERACTION,
|
CommandRunExceptionType.INTERACTION,
|
||||||
"manager was closed", e, this); //$NON-NLS-1$
|
"manager was closed", e, this); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
writer.write(user + EOL);
|
writer.write(user + EOL);
|
||||||
}
|
}
|
||||||
} catch (IOException e1) {
|
} catch (final IOException e1) {
|
||||||
throw new CommandRunException(CommandRunExceptionType.INTERACTION,
|
throw new CommandRunException(CommandRunExceptionType.INTERACTION,
|
||||||
"manager was closed", e1, this); //$NON-NLS-1$
|
"manager was closed", e1, this); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
@@ -103,23 +100,31 @@ public class ExecSystemCommand extends Command {
|
|||||||
/** @param is the input stream
|
/** @param is the input stream
|
||||||
* @throws CommandRunException if the manager was closed while writing the
|
* @throws CommandRunException if the manager was closed while writing the
|
||||||
* stream */
|
* stream */
|
||||||
protected void readToEnd(InputStream is) throws CommandRunException {
|
protected void readToEnd(final ConsoleOutput out,
|
||||||
|
final InputStream is) throws CommandRunException {
|
||||||
int c;
|
int c;
|
||||||
try {
|
try {
|
||||||
while ((c = is.read()) != -1) {
|
while ((c = is.read()) != -1) {
|
||||||
try {
|
try {
|
||||||
manager.print(Character.valueOf((char) c).toString());
|
out.print(Character.valueOf((char) c).toString());
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
throw new CommandRunException(
|
throw new CommandRunException(
|
||||||
CommandRunExceptionType.INTERACTION,
|
CommandRunExceptionType.INTERACTION,
|
||||||
"manager was closed", e, this); //$NON-NLS-1$
|
"manager was closed", e, this); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
LOGGER.log(Level.INFO, "input stream reading failed", e); //$NON-NLS-1$
|
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)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||||
@Override
|
@Override
|
||||||
@@ -140,11 +145,4 @@ public class ExecSystemCommand extends Command {
|
|||||||
return " CMD <system command>"; //$NON-NLS-1$
|
return " CMD <system command>"; //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
|
||||||
@Override
|
|
||||||
public String tip() {
|
|
||||||
return "Execute a system command"; //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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">
|
<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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>gclc</artifactId>
|
<artifactId>gclc</artifactId>
|
||||||
<version>1.3.2-SNAPSHOT</version>
|
<version>2.0.6-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<url>http://www.bigeon.fr/emmanuel</url>
|
<url>http://www.bigeon.fr/emmanuel</url>
|
||||||
<properties>
|
<properties>
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>fr.bigeon</groupId>
|
<groupId>fr.bigeon</groupId>
|
||||||
<artifactId>ebigeon-config</artifactId>
|
<artifactId>ebigeon-config</artifactId>
|
||||||
<version>1.7.0</version>
|
<version>1.7.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
@@ -83,6 +83,6 @@
|
|||||||
<scm>
|
<scm>
|
||||||
|
|
||||||
<developerConnection>scm:git:gogs@git.code.bigeon.net:emmanuel/gclc.git</developerConnection>
|
<developerConnection>scm:git:gogs@git.code.bigeon.net:emmanuel/gclc.git</developerConnection>
|
||||||
<tag>HEAD</tag>
|
<tag>gclc-1.3.5</tag>
|
||||||
</scm>
|
</scm>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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.command.ICommandProvider;
|
||||||
|
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(ICommandProvider application) throws InvalidCommandName;
|
||||||
|
}
|
||||||
@@ -38,13 +38,12 @@
|
|||||||
*/
|
*/
|
||||||
package fr.bigeon.gclc;
|
package fr.bigeon.gclc;
|
||||||
|
|
||||||
/** <p>
|
/** Command Request Listeners are listeners that are notified before a command
|
||||||
* Command Request Listeners are listeners that are notified before a command is
|
* is executed by the ConsoleApplication.
|
||||||
* executed by the ConsoleApplication,
|
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public interface CommandRequestListener {
|
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 */
|
* @param command the command */
|
||||||
void commandRequest(String command);
|
void commandRequest(String command);
|
||||||
|
|||||||
@@ -52,19 +52,21 @@ import fr.bigeon.gclc.exception.CommandRunException;
|
|||||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||||
import fr.bigeon.gclc.i18n.Messages;
|
import fr.bigeon.gclc.i18n.Messages;
|
||||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
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
|
* A {@link ConsoleApplication} is an application that require the user to input
|
||||||
* commands.
|
* commands.
|
||||||
* <p>
|
* <p>
|
||||||
* A typical use case is the following:
|
* A typical use case is the following:
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* {@link ConsoleManager} manager = new {@link fr.bigeon.gclc.manager.SystemConsoleManager#SystemConsoleManager()}
|
* {@link ConsoleOutput} out = new {@link fr.bigeon.gclc.manager.StreamConsoleOutput StreamConsoleOutput}();
|
||||||
* {@link ConsoleApplication} app = new {@link ConsoleApplication#ConsoleApplication(ConsoleManager, String, String) ConsoleApplication(manager, "welcome", "see you latter")};
|
* {@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#add(ICommand) add}("my_command", new {@link ICommand MyCommand()});
|
||||||
* app.{@link ConsoleApplication#start start}();
|
* app.{@link ConsoleApplication#start() start()};
|
||||||
* </pre>
|
* </pre>
|
||||||
* <p>
|
* <p>
|
||||||
* That will launch in the console application that will display "welcome",
|
* That will launch in the console application that will display "welcome",
|
||||||
@@ -73,42 +75,51 @@ import fr.bigeon.gclc.manager.ConsoleManager;
|
|||||||
* start method.
|
* start method.
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @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
|
private static final Logger LOGGER = Logger
|
||||||
.getLogger(ConsoleApplication.class.getName());
|
.getLogger(ConsoleApplication.class.getName());
|
||||||
/** The welcome message */
|
/** The welcome message. */
|
||||||
private final String header;
|
public final String header;
|
||||||
/** The good bye message */
|
/** The good bye message. */
|
||||||
private final String footer;
|
public final String footer;
|
||||||
/** The console manager */
|
/** The standard output for the application. */
|
||||||
protected final ConsoleManager manager;
|
private final ConsoleOutput out;
|
||||||
/** The container of commands */
|
/** The standard input for the application. */
|
||||||
private final SubedCommand root;
|
private final ConsoleInput in;
|
||||||
/** The state of this application */
|
/** The container of commands. */
|
||||||
|
public final SubedCommand root;
|
||||||
|
/** The state of this application. */
|
||||||
private boolean running;
|
private boolean running;
|
||||||
/** The listeners */
|
/** The listeners. */
|
||||||
private final List<CommandRequestListener> listeners = new ArrayList<>();
|
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 welcome the welcoming message
|
||||||
* @param goodbye the goodbye message */
|
* @param goodbye the goodbye message */
|
||||||
public ConsoleApplication(ConsoleManager manager, String welcome,
|
public ConsoleApplication(final ConsoleOutput out, final ConsoleInput in,
|
||||||
String goodbye) {
|
final String welcome,
|
||||||
this.header = welcome;
|
final String goodbye) {
|
||||||
this.footer = goodbye;
|
header = welcome;
|
||||||
this.manager = manager;
|
footer = goodbye;
|
||||||
|
this.in = in;
|
||||||
|
this.out = out;
|
||||||
root = new SubedCommand(""); //$NON-NLS-1$
|
root = new SubedCommand(""); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean add(ICommand cmd) throws InvalidCommandName {
|
public boolean add(final ICommand cmd) throws InvalidCommandName {
|
||||||
return root.add(cmd);
|
return root.add(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param listener the command listener */
|
/** Add a listener for command requests.
|
||||||
public final void addListener(CommandRequestListener listener) {
|
*
|
||||||
|
* @param listener the command listener */
|
||||||
|
public void addListener(final CommandRequestListener listener) {
|
||||||
listeners.add(listener);
|
listeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,98 +127,70 @@ public class ConsoleApplication implements ICommandProvider {
|
|||||||
* @see fr.bigeon.gclc.command.ICommandProvider#executeSub(java.lang.String,
|
* @see fr.bigeon.gclc.command.ICommandProvider#executeSub(java.lang.String,
|
||||||
* java.lang.String[]) */
|
* java.lang.String[]) */
|
||||||
@Override
|
@Override
|
||||||
public final void executeSub(String command,
|
public void executeSub(final ConsoleOutput output, final ConsoleInput input,
|
||||||
String... args) throws CommandRunException {
|
final String command,
|
||||||
root.executeSub(command, args);
|
final String... args) throws CommandRunException {
|
||||||
|
root.executeSub(output, input, command, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Signify to the application that no command should be inputed anymore */
|
/** Signify to the application that no command should be inputed anymore. */
|
||||||
public final void exit() {
|
public void exit() {
|
||||||
LOGGER.fine("Request exiting application..."); //$NON-NLS-1$
|
LOGGER.fine("Request exiting application..."); //$NON-NLS-1$
|
||||||
running = false;
|
running = false;
|
||||||
manager.interruptPrompt();
|
in.interruptPrompt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.ICommandProvider#get(java.lang.String) */
|
* @see fr.bigeon.gclc.command.ICommandProvider#get(java.lang.String) */
|
||||||
@Override
|
@Override
|
||||||
public final ICommand get(String command) {
|
public ICommand get(final String command) {
|
||||||
return root.get(command);
|
return root.get(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the manager */
|
/** Interpret a command line.
|
||||||
public final ConsoleManager getManager() {
|
* <p>
|
||||||
return manager;
|
* This method will split the command in its part and execute the command
|
||||||
}
|
* with {@link #executeSub(ConsoleOutput, ConsoleInput, String, String...)}.
|
||||||
|
*
|
||||||
/** @param cmd the command
|
* @param cmd the command
|
||||||
* @throws IOException if the command could not be parsed */
|
* @throws IOException if the command could not be parsed */
|
||||||
public final void interpretCommand(String cmd) throws IOException {
|
public void interpretCommand(final String cmd) throws IOException {
|
||||||
List<String> args;
|
List<String> args;
|
||||||
try {
|
try {
|
||||||
args = GCLCConstants.splitCommand(cmd);
|
args = GCLCConstants.splitCommand(cmd);
|
||||||
} catch (CommandParsingException e1) {
|
} catch (final CommandParsingException e1) {
|
||||||
manager.println("Command line cannot be parsed"); //$NON-NLS-1$
|
out.println("Command line cannot be parsed"); //$NON-NLS-1$
|
||||||
LOGGER.log(Level.INFO, "Invalid user command " + cmd, e1); //$NON-NLS-1$
|
LOGGER.log(Level.FINE, "Invalid user command " + cmd, e1); //$NON-NLS-1$
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!args.isEmpty()) {
|
if (!args.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
executeSub(args.get(0), Arrays.copyOfRange(
|
executeSub(out, in, args.get(0), Arrays.copyOfRange(
|
||||||
args.toArray(new String[0]), 1, args.size()));
|
args.toArray(new String[0]), 1, args.size()));
|
||||||
} catch (final CommandRunException e) {
|
} catch (final CommandRunException e) {
|
||||||
LOGGER.log(Level.WARNING, "Command failed: " + cmd, e); //$NON-NLS-1$
|
LOGGER.log(Level.FINE, "Command failed: " + cmd, e); //$NON-NLS-1$
|
||||||
manager.println(Messages
|
out.println(Messages
|
||||||
.getString("ConsoleApplication.cmd.failed", cmd)); //$NON-NLS-1$
|
.getString("ConsoleApplication.cmd.failed", cmd)); //$NON-NLS-1$
|
||||||
manager.println(e.getLocalizedMessage());
|
out.println(e.getLocalizedMessage());
|
||||||
if (e.getType() == CommandRunExceptionType.USAGE) {
|
if (e.getType() == CommandRunExceptionType.USAGE) {
|
||||||
e.getSource().help(getManager());
|
e.getSource().help(out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param listener the command listener to remove */
|
/** Test if the application is running.
|
||||||
public final void removeListener(CommandRequestListener listener) {
|
*
|
||||||
for (int i = 0; i < listeners.size(); i++) {
|
* @return the running status */
|
||||||
if (listeners.get(i) == listener) {
|
public boolean isRunning() {
|
||||||
listeners.remove(i);
|
return running;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start the application */
|
/** Remove a listener from this application.
|
||||||
public final void start() {
|
*
|
||||||
try {
|
* @param listener the command listener to remove */
|
||||||
running = true;
|
public void removeListener(final CommandRequestListener listener) {
|
||||||
if (header != null) {
|
listeners.remove(listener);
|
||||||
manager.println(header);
|
|
||||||
}
|
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
runLoop();
|
|
||||||
} while (running);
|
|
||||||
if (footer != null) {
|
|
||||||
try {
|
|
||||||
manager.println(footer);
|
|
||||||
} catch (IOException e) {
|
|
||||||
// The manager was closed
|
|
||||||
running = false;
|
|
||||||
LOGGER.log(Level.WARNING,
|
|
||||||
"The console manager was closed.", //$NON-NLS-1$
|
|
||||||
e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
running = false;
|
|
||||||
LOGGER.fine("Exiting application."); //$NON-NLS-1$
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The running loop content.
|
/** The running loop content.
|
||||||
@@ -216,7 +199,7 @@ public class ConsoleApplication implements ICommandProvider {
|
|||||||
* (restarting the loop). */
|
* (restarting the loop). */
|
||||||
private void runLoop() {
|
private void runLoop() {
|
||||||
try {
|
try {
|
||||||
final String cmd = manager.prompt();
|
final String cmd = in.prompt();
|
||||||
if (cmd == null || cmd.isEmpty()) {
|
if (cmd == null || cmd.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -224,36 +207,55 @@ public class ConsoleApplication implements ICommandProvider {
|
|||||||
listener.commandRequest(cmd);
|
listener.commandRequest(cmd);
|
||||||
}
|
}
|
||||||
interpretCommand(cmd);
|
interpretCommand(cmd);
|
||||||
} catch (InterruptedIOException e) {
|
} catch (final InterruptedIOException e) {
|
||||||
LOGGER.log(Level.INFO,
|
LOGGER.info(
|
||||||
"Prompt interrupted. It is likely the application is closing.", //$NON-NLS-1$
|
"Prompt interrupted. It is likely the application is closing."); //$NON-NLS-1$
|
||||||
|
LOGGER.log(Level.FINER, "Interruption of the prompt.", //$NON-NLS-1$
|
||||||
e);
|
e);
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
// The manager was closed
|
// The manager was closed
|
||||||
running = false;
|
running = false;
|
||||||
LOGGER.log(Level.WARNING,
|
LOGGER.warning(
|
||||||
"The console manager was closed. Closing the application as no one can reach it.", //$NON-NLS-1$
|
"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);
|
e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the running status */
|
/** Start the application. */
|
||||||
public boolean isRunning() {
|
public void start() {
|
||||||
return running;
|
try {
|
||||||
}
|
running = true;
|
||||||
|
if (header != null) {
|
||||||
/** @return the root */
|
out.println(header);
|
||||||
public SubedCommand getRoot() {
|
}
|
||||||
return root;
|
} catch (final IOException e) {
|
||||||
}
|
// The manager was closed
|
||||||
|
running = false;
|
||||||
/** @return the header */
|
LOGGER.warning(
|
||||||
public String getHeader() {
|
"The console manager was closed. Closing the application as no one can reach it."); //$NON-NLS-1$
|
||||||
return header;
|
LOGGER.log(Level.FINE,
|
||||||
}
|
"An exception caused the closing of the application", //$NON-NLS-1$
|
||||||
|
e);
|
||||||
/** @return the footer */
|
return;
|
||||||
public String getFooter() {
|
}
|
||||||
return footer;
|
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.
|
* arguments.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class GCLCConstants {
|
public final class GCLCConstants {
|
||||||
|
|
||||||
/** The escaping character */
|
/** The escaping character. */
|
||||||
private static final char ESCAPING_CHAR = getSystemEscapingChar();
|
private static final char ESCAPING_CHAR = getSystemEscapingChar();
|
||||||
|
|
||||||
/** Hide utility class constructor */
|
/** Hide utility class constructor. */
|
||||||
private GCLCConstants() {
|
private GCLCConstants() {
|
||||||
// utility class
|
// 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() {
|
private static char getSystemEscapingChar() {
|
||||||
return '\\';
|
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
|
* @param cmd the command to split in its parts
|
||||||
* @return the list of argument preceded by the command name
|
* @return the list of argument preceded by the command name
|
||||||
* @throws CommandParsingException if the parsing of the command failed */
|
* @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<>();
|
final List<String> args = new ArrayList<>();
|
||||||
// parse the string to separate arguments
|
// parse the string to separate arguments
|
||||||
int index = 0;
|
int index = 0;
|
||||||
@@ -77,7 +112,7 @@ public class GCLCConstants {
|
|||||||
boolean escaped = false;
|
boolean escaped = false;
|
||||||
boolean inString = false;
|
boolean inString = false;
|
||||||
while (index < cmd.length()) {
|
while (index < cmd.length()) {
|
||||||
char c = cmd.charAt(index);
|
final char c = cmd.charAt(index);
|
||||||
index++;
|
index++;
|
||||||
if (escaped || c == ESCAPING_CHAR) {
|
if (escaped || c == ESCAPING_CHAR) {
|
||||||
escaped = !escaped;
|
escaped = !escaped;
|
||||||
@@ -105,33 +140,4 @@ public class GCLCConstants {
|
|||||||
return args;
|
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 java.io.IOException;
|
||||||
|
|
||||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
|
|
||||||
/** <p>
|
/** A command to execute.
|
||||||
* A command to execute. It is mandatory that it has a name and that name cannot
|
* <p>
|
||||||
* start with minus character or contain spaces.
|
* It is mandatory that it has a name and that name cannot start with minus
|
||||||
|
* character or contain spaces.
|
||||||
* <p>
|
* <p>
|
||||||
* A command can be executed, with parameters that will be provided as an array
|
* A command can be executed, with parameters that will be provided as an array
|
||||||
* of strings.
|
* of strings.
|
||||||
@@ -65,22 +66,26 @@ import fr.bigeon.gclc.manager.ConsoleManager;
|
|||||||
* @author Emmanuel BIGEON */
|
* @author Emmanuel BIGEON */
|
||||||
public abstract class Command implements ICommand {
|
public abstract class Command implements ICommand {
|
||||||
|
|
||||||
/**
|
/** The linux end of line character. */
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static final String EOL_LINUX = "\n"; //$NON-NLS-1$
|
private static final String EOL_LINUX = "\n"; //$NON-NLS-1$
|
||||||
/** The empty string constant */
|
/** The name of the command. */
|
||||||
private static final String EMPTY = ""; //$NON-NLS-1$
|
|
||||||
/** The name of the command */
|
|
||||||
protected final String name;
|
protected final String name;
|
||||||
|
|
||||||
/** @param name the command name */
|
/** Create the command.
|
||||||
public Command(String name) {
|
*
|
||||||
|
* @param name the command name */
|
||||||
|
public Command(final String name) {
|
||||||
super();
|
super();
|
||||||
this.name = name;
|
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() {
|
protected String brief() {
|
||||||
return " " + tip(); //$NON-NLS-1$
|
return " " + tip(); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
@@ -92,12 +97,24 @@ public abstract class Command implements ICommand {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/** Prints a help content for this command to the console output.
|
||||||
* @see fr.bigeon.gclc.command.ICommand#help(fr.bigeon.gclc.ConsoleManager,
|
* <p>
|
||||||
* java.lang.String) */
|
* 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
|
@Override
|
||||||
public final void help(ConsoleManager manager,
|
public final void help(final ConsoleOutput manager,
|
||||||
String... args) throws IOException {
|
final String... args) throws IOException {
|
||||||
manager.println(getCommandName());
|
manager.println(getCommandName());
|
||||||
manager.println(brief());
|
manager.println(brief());
|
||||||
manager.println();
|
manager.println();
|
||||||
@@ -114,19 +131,16 @@ public abstract class Command implements ICommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** <p>
|
/** This method return the detail of the help.
|
||||||
* This method return the detail of the help. It immediatly follows the
|
* <p>
|
||||||
* {@link #usagePattern() usage pattern}.
|
* It immediatly follows the {@link #usagePattern() usage pattern}.
|
||||||
*
|
*
|
||||||
* @return the detailed help (should end with end of line or be empty) */
|
* @return the detailed help (should end with end of line or be empty) */
|
||||||
@SuppressWarnings("static-method")
|
protected abstract String usageDetail();
|
||||||
protected String usageDetail() {
|
|
||||||
return EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** <p>
|
/** This prints the usage pattern for the command.
|
||||||
* This prints the usage pattern for the command. It follows the brief
|
* <p>
|
||||||
* introduction on the command ({@link #brief()})
|
* It follows the brief introduction on the command ({@link #brief()})
|
||||||
*
|
*
|
||||||
* @return the usage pattern */
|
* @return the usage pattern */
|
||||||
protected String usagePattern() {
|
protected String usagePattern() {
|
||||||
|
|||||||
@@ -45,33 +45,34 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/** <p>
|
import fr.bigeon.gclc.exception.CommandParsingException;
|
||||||
* An object representing a collection of parameters. It is used for defaulting
|
|
||||||
* values.
|
/** An object representing a collection of parameters.
|
||||||
|
* <p>
|
||||||
|
* It is used for defaulting values.
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @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;
|
private static final int STRINGARG_NUMBER_OF_ELEMENTS = 2;
|
||||||
/** Boolean arguments */
|
/** Boolean arguments. */
|
||||||
private final Map<String, Boolean> booleanArguments = new HashMap<>();
|
private final Map<String, Boolean> booleanArguments = new HashMap<>();
|
||||||
/** String arguments */
|
/** String arguments. */
|
||||||
private final Map<String, String> stringArguments = new HashMap<>();
|
private final Map<String, String> stringArguments = new HashMap<>();
|
||||||
/** Arguments restriction on the named ones */
|
/** Arguments restriction on the named ones. */
|
||||||
private final boolean strict;
|
private final boolean strict;
|
||||||
/** additional (unnamed) parameters */
|
/** additional (unnamed) parameters. */
|
||||||
private final List<String> additional = new ArrayList<>();
|
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 strings the string parameters
|
||||||
* @param strict if the argument are restricted to the declared ones */
|
* @param strict if the argument are restricted to the declared ones */
|
||||||
@SuppressWarnings("boxing")
|
public CommandParameters(final Set<String> bools, final Set<String> strings,
|
||||||
public CommandParameters(Set<String> bools, Set<String> strings,
|
final boolean strict) {
|
||||||
boolean strict) {
|
|
||||||
for (final String string : bools) {
|
for (final String string : bools) {
|
||||||
booleanArguments.put(string, false);
|
booleanArguments.put(string, Boolean.FALSE);
|
||||||
}
|
}
|
||||||
for (final String string : strings) {
|
for (final String string : strings) {
|
||||||
stringArguments.put(string, null);
|
stringArguments.put(string, null);
|
||||||
@@ -79,41 +80,51 @@ public class CommandParameters {
|
|||||||
this.strict = strict;
|
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 */
|
* @return the associated value, null if it was not specified */
|
||||||
public String get(String key) {
|
public String get(final String key) {
|
||||||
return stringArguments.get(key);
|
return stringArguments.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return additional non parsed parameters */
|
/** Get the additional (unrecognized) arguments.
|
||||||
|
*
|
||||||
|
* @return additional non parsed parameters */
|
||||||
public List<String> getAdditionals() {
|
public List<String> getAdditionals() {
|
||||||
return Collections.unmodifiableList(additional);
|
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 */
|
* @return if the key was specified */
|
||||||
public boolean getBool(String key) {
|
public boolean getBool(final String key) {
|
||||||
return booleanArguments.containsKey(key) &&
|
return booleanArguments.containsKey(key) &&
|
||||||
booleanArguments.get(key).booleanValue();
|
booleanArguments.get(key).booleanValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param args the arguments to parse
|
/** Get the boolean arguments.
|
||||||
* @return if the arguments were parsed */
|
*
|
||||||
public boolean parseArgs(String... args) {
|
* @return the boolean arguments */
|
||||||
int i = 0;
|
public Set<String> getBooleanArgumentKeys() {
|
||||||
while (i < args.length) {
|
return booleanArguments.keySet();
|
||||||
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 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.
|
/** Attempt to parse an argument.
|
||||||
@@ -124,11 +135,15 @@ public class CommandParameters {
|
|||||||
* @param arg the argument
|
* @param arg the argument
|
||||||
* @param next the next element
|
* @param next the next element
|
||||||
* @return the number of element read */
|
* @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$
|
if (!arg.startsWith("-")) { //$NON-NLS-1$
|
||||||
|
if (strict) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
additional.add(arg);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
String name = arg.substring(1);
|
final String name = arg.substring(1);
|
||||||
if (booleanArguments.containsKey(name)) {
|
if (booleanArguments.containsKey(name)) {
|
||||||
booleanArguments.put(name, Boolean.TRUE);
|
booleanArguments.put(name, Boolean.TRUE);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -143,12 +158,33 @@ public class CommandParameters {
|
|||||||
return 1;
|
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 name the string arg name
|
||||||
* @param next the string arg value
|
* @param next the string arg value
|
||||||
* @return 2 or 0 if next is invalid */
|
* @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) {
|
if (next == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -156,30 +192,23 @@ public class CommandParameters {
|
|||||||
return STRINGARG_NUMBER_OF_ELEMENTS;
|
return STRINGARG_NUMBER_OF_ELEMENTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param string the key
|
/** Set a boolean parameter value.
|
||||||
|
*
|
||||||
|
* @param string the key
|
||||||
* @param value the value */
|
* @param value the value */
|
||||||
@SuppressWarnings("boxing")
|
public void set(final String string, final boolean value) {
|
||||||
public void set(String string, boolean value) {
|
|
||||||
if (booleanArguments.containsKey(string)) {
|
if (booleanArguments.containsKey(string)) {
|
||||||
booleanArguments.put(string, value);
|
booleanArguments.put(string, Boolean.valueOf(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param string the key
|
/** Set a string parameter value.
|
||||||
|
*
|
||||||
|
* @param string the key
|
||||||
* @param value the value */
|
* @param value the value */
|
||||||
public void set(String string, String value) {
|
public void set(final String string, final String value) {
|
||||||
if (stringArguments.containsKey(string)) {
|
if (stringArguments.containsKey(string)) {
|
||||||
stringArguments.put(string, value);
|
stringArguments.put(string, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the boolean arguments */
|
|
||||||
public Set<String> getBooleanArgumentKeys() {
|
|
||||||
return booleanArguments.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return the boolean arguments */
|
|
||||||
public Set<String> getStringArgumentKeys() {
|
|
||||||
return stringArguments.keySet();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,36 +42,48 @@ import java.util.List;
|
|||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||||
import fr.bigeon.gclc.i18n.Messages;
|
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 */
|
* @author Emmanuel BIGEON */
|
||||||
public class CommandProvider implements ICommandProvider {
|
public class CommandProvider implements ICommandProvider {
|
||||||
/** The minus character */
|
/** The minus character. */
|
||||||
private static final String MINUS = "-"; //$NON-NLS-1$
|
private static final String MINUS = "-"; //$NON-NLS-1$
|
||||||
/** The space character */
|
/** The space character. */
|
||||||
private static final String SPACE = " "; //$NON-NLS-1$
|
private static final String SPACE = " "; //$NON-NLS-1$
|
||||||
/** The commands map */
|
/** The commands map. */
|
||||||
protected final List<ICommand> commands;
|
protected final List<ICommand> commands;
|
||||||
|
|
||||||
/** Create a command provider */
|
/** Create a command provider. */
|
||||||
public CommandProvider() {
|
public CommandProvider() {
|
||||||
super();
|
super();
|
||||||
commands = new ArrayList<>();
|
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)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.ICommandProvider#add(java.lang.String,
|
* @see fr.bigeon.gclc.command.ICommandProvider#add(java.lang.String,
|
||||||
* fr.bigeon.gclc.command.Command) */
|
* fr.bigeon.gclc.command.Command) */
|
||||||
@Override
|
@Override
|
||||||
public boolean add(ICommand value) throws InvalidCommandName {
|
public final boolean add(final ICommand value) throws InvalidCommandName {
|
||||||
final String name = value.getCommandName();
|
final String name = value.getCommandName();
|
||||||
testCommandName(name);
|
testCommandName(name);
|
||||||
if (commands.contains(value)) {
|
if (commands.contains(value)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (ICommand iCommand : commands) {
|
for (final ICommand iCommand : commands) {
|
||||||
if (iCommand.getCommandName().equals(value.getCommandName())) {
|
if (iCommand.getCommandName().equals(value.getCommandName())) {
|
||||||
throw new InvalidCommandName(
|
throw new InvalidCommandName(
|
||||||
"Name already used: " + value.getCommandName()); //$NON-NLS-1$
|
"Name already used: " + value.getCommandName()); //$NON-NLS-1$
|
||||||
@@ -80,21 +92,18 @@ public class CommandProvider implements ICommandProvider {
|
|||||||
return commands.add(value);
|
return commands.add(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param name the command name
|
/* (non-Javadoc)
|
||||||
* @throws InvalidCommandName if the name is invalid */
|
* @see
|
||||||
private static void testCommandName(String name) throws InvalidCommandName {
|
* fr.bigeon.gclc.command.ICommandProvider#executeSub(fr.bigeon.gclc.manager
|
||||||
if (name == null || name.isEmpty() || name.startsWith(MINUS) ||
|
* .ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput, java.lang.String,
|
||||||
name.contains(SPACE)) {
|
* java.lang.String[]) */
|
||||||
throw new InvalidCommandName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeSub(String cmd,
|
public final void executeSub(final ConsoleOutput out, final ConsoleInput in,
|
||||||
String... args) throws CommandRunException {
|
final String cmd,
|
||||||
|
final String... args) throws CommandRunException {
|
||||||
for (final ICommand command : commands) {
|
for (final ICommand command : commands) {
|
||||||
if (command.getCommandName().equals(cmd)) {
|
if (command.getCommandName().equals(cmd)) {
|
||||||
command.execute(args);
|
command.execute(out, in, args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,7 +114,7 @@ public class CommandProvider implements ICommandProvider {
|
|||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.ICommandProvider#get(java.lang.String) */
|
* @see fr.bigeon.gclc.command.ICommandProvider#get(java.lang.String) */
|
||||||
@Override
|
@Override
|
||||||
public ICommand get(String commandName) {
|
public final ICommand get(final String commandName) {
|
||||||
for (final ICommand command : commands) {
|
for (final ICommand command : commands) {
|
||||||
if (command.getCommandName().equals(commandName)) {
|
if (command.getCommandName().equals(commandName)) {
|
||||||
return command;
|
return command;
|
||||||
|
|||||||
@@ -41,37 +41,42 @@ package fr.bigeon.gclc.command;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import fr.bigeon.gclc.ConsoleApplication;
|
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;
|
import fr.bigeon.gclc.prompt.CLIPrompterMessages;
|
||||||
|
|
||||||
/** <p>
|
/** A command to exit a {@link ConsoleApplication}.
|
||||||
* A command to exit a {@link ConsoleApplication}.
|
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @author Emmanuel BIGEON */
|
||||||
public class ExitCommand implements ICommand {
|
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$
|
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$
|
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;
|
private final ConsoleApplication app;
|
||||||
/** The exit command name */
|
/** The exit command name. */
|
||||||
private final String 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 */
|
* @param app the application to exit */
|
||||||
public ExitCommand(String name, ConsoleApplication app) {
|
public ExitCommand(final String name, final ConsoleApplication app) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.app = app;
|
this.app = app;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The actions to take before exiting */
|
/** The actions to take before exiting.
|
||||||
public void beforeExit() {
|
* <p>
|
||||||
|
* This method is intended to be overriden by sub classes. */
|
||||||
|
protected void beforeExit() {
|
||||||
// Do nothing by default
|
// Do nothing by default
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void execute(String... args) {
|
public final void execute(final ConsoleOutput output,
|
||||||
|
final ConsoleInput input, final String... args) {
|
||||||
beforeExit();
|
beforeExit();
|
||||||
app.exit();
|
app.exit();
|
||||||
}
|
}
|
||||||
@@ -84,14 +89,13 @@ public class ExitCommand implements ICommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void help(ConsoleManager manager,
|
public final void help(final ConsoleOutput manager,
|
||||||
String... args) throws IOException {
|
final String... args) throws IOException {
|
||||||
manager.println(
|
manager.println(
|
||||||
CLIPrompterMessages.getString(EXIT_MAN, (Object[]) args));
|
CLIPrompterMessages.getString(EXIT_MAN, (Object[]) args));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tip() {
|
public final String tip() {
|
||||||
return CLIPrompterMessages.getString(EXIT);
|
return CLIPrompterMessages.getString(EXIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,8 @@ import java.io.IOException;
|
|||||||
|
|
||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
import fr.bigeon.gclc.prompt.CLIPrompterMessages;
|
import fr.bigeon.gclc.prompt.CLIPrompterMessages;
|
||||||
|
|
||||||
/** A command to print help of an other command.
|
/** A command to print help of an other command.
|
||||||
@@ -50,37 +51,19 @@ import fr.bigeon.gclc.prompt.CLIPrompterMessages;
|
|||||||
* This command will display the help of an other command
|
* This command will display the help of an other command
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @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;
|
private final ICommand cmd;
|
||||||
/** The console manager */
|
|
||||||
private final ConsoleManager consoleManager;
|
|
||||||
|
|
||||||
/** @param cmdName the command name
|
/** Create the help command.
|
||||||
* @param consoleManager the manager for the console
|
*
|
||||||
|
* @param cmdName the command name
|
||||||
* @param cmd the command to execute the help of */
|
* @param cmd the command to execute the help of */
|
||||||
public HelpExecutor(String cmdName, ConsoleManager consoleManager,
|
public HelpExecutor(final String cmdName,
|
||||||
ICommand cmd) {
|
final ICommand cmd) {
|
||||||
super(cmdName);
|
super(cmdName);
|
||||||
this.cmd = cmd;
|
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(CommandRunExceptionType.INTERACTION,
|
|
||||||
"Console manager closed", e, this); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -94,13 +77,17 @@ public class HelpExecutor extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.Command#usagePattern() */
|
* @see fr.bigeon.gclc.command.ICommand#execute(ConsoleOutput, ConsoleInput,
|
||||||
|
* String[]) */
|
||||||
@Override
|
@Override
|
||||||
protected String usagePattern() {
|
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||||
if (cmd instanceof SubedCommand) {
|
final String... args) throws CommandRunException {
|
||||||
return getCommandName() + " <otherCommand>"; //$NON-NLS-1$
|
try {
|
||||||
|
cmd.help(out, args);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new CommandRunException(CommandRunExceptionType.INTERACTION,
|
||||||
|
"Console manager closed", e, this); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
return getCommandName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -109,4 +96,22 @@ public class HelpExecutor extends Command {
|
|||||||
public String tip() {
|
public String tip() {
|
||||||
return CLIPrompterMessages.getString("help.cmd.tip"); //$NON-NLS-1$
|
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 java.io.IOException;
|
||||||
|
|
||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
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>
|
* <p>
|
||||||
* This interface describe the contract of commands
|
* This interface describe the contract of commands
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public interface ICommand {
|
public interface ICommand {
|
||||||
|
|
||||||
/** @param args the arguments of the command (some expect an empty array)
|
/** Execute the command on the given output and input.
|
||||||
* @throws CommandRunException if the execution of the command failed for
|
*
|
||||||
* any reason */
|
* @param out the normal output
|
||||||
void execute(String... args) throws CommandRunException;
|
* @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();
|
String getCommandName();
|
||||||
|
|
||||||
/** This prints the help associated to this command.
|
/** This prints the help associated to this command.
|
||||||
* <p>
|
|
||||||
* The default behavior is to print:
|
|
||||||
*
|
*
|
||||||
* <pre>
|
* @param output the output to print the data
|
||||||
* [Command name]
|
|
||||||
* [brief message]
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
* [Usage pattern]
|
|
||||||
*
|
|
||||||
* [Usage details]
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param manager the manager to print the data
|
|
||||||
* @param args the arguments called with the help
|
* @param args the arguments called with the help
|
||||||
* @throws IOException if the manager was closed */
|
* @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();
|
String tip();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -38,45 +38,47 @@ package fr.bigeon.gclc.command;
|
|||||||
|
|
||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
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
|
||||||
* An ICommadProvider is a provider of commands that can register commands under
|
* under some keywords.
|
||||||
* some keywords.
|
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @author Emmanuel BIGEON */
|
||||||
public interface ICommandProvider {
|
public interface ICommandProvider {
|
||||||
|
|
||||||
/** <p>
|
/** Adds a command to this provider, if no command was associated with the
|
||||||
* Adds a command to this provider, if no command was associated with the
|
* given key.
|
||||||
* given key
|
|
||||||
*
|
*
|
||||||
* @param value the command to execute
|
* @param value the command to execute
|
||||||
* @return if the command was added
|
* @return if the command was added
|
||||||
* @throws InvalidCommandName if the command name is invalid */
|
* @throws InvalidCommandName if the command name is invalid */
|
||||||
public boolean add(ICommand value) throws InvalidCommandName;
|
boolean add(ICommand value) throws InvalidCommandName;
|
||||||
|
|
||||||
/** <p>
|
/** Execute the command with the given name.
|
||||||
* This method executes the command with the given name found. If no command
|
* <p>
|
||||||
* with this name is found, an error command is usually executed. If there
|
* If no command with this name is found, an error command is usually
|
||||||
* are several commands with the same name, the behavior is unspecified.
|
* executed. If there are several commands with the same name, the behavior
|
||||||
* Depending on the implementation, it may run an error command or prompt
|
* is unspecified. Depending on the implementation, it may run an error
|
||||||
* the user for a choice.
|
* 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 command the name of the command the user wishes to execute
|
||||||
* @param args the arguments for the command
|
* @param args the arguments for the command
|
||||||
* @throws CommandRunException if the command failed to run */
|
* @throws CommandRunException if the command failed to run */
|
||||||
public void executeSub(String command,
|
void executeSub(ConsoleOutput out, ConsoleInput in, String command,
|
||||||
String... args) throws CommandRunException;
|
String... args) throws CommandRunException;
|
||||||
|
|
||||||
/** <p>
|
/** Get the command with the given name.
|
||||||
* This method provide the command with the given name found. If no command
|
* <p>
|
||||||
* with this name is found, an error command is usually returned. If there
|
* If no command with this name is found, an error command is usually
|
||||||
* are several commands with the same name, the behavior is unspecified.
|
* returned. If there are several commands with the same name, the behavior
|
||||||
* Depending on the implementation, it may return an error command or the
|
* is unspecified. Depending on the implementation, it may return an error
|
||||||
* first command with this name found.
|
* command or the first command with this name found.
|
||||||
*
|
*
|
||||||
* @param command the name of the command the user wishes to execute
|
* @param command the name of the command the user wishes to execute
|
||||||
* @return the command to execute */
|
* @return the command to execute */
|
||||||
public ICommand get(String command);
|
ICommand get(String command);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -38,10 +38,8 @@
|
|||||||
*/
|
*/
|
||||||
package fr.bigeon.gclc.command;
|
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;
|
|
||||||
|
|
||||||
/** This implement a command that does nothing.
|
/** This implement a command that does nothing.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -50,28 +48,25 @@ import fr.bigeon.gclc.manager.ConsoleManager;
|
|||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public final class MockCommand implements ICommand {
|
public final class MockCommand implements ICommand {
|
||||||
|
|
||||||
/** The command name */
|
/** The command name. */
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
/** @param name the command name */
|
/** Create the command.
|
||||||
public MockCommand(String name) {
|
*
|
||||||
|
* @param name the command name */
|
||||||
|
public MockCommand(final String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.ICommand#execute(java.lang.String[]) */
|
* @see fr.bigeon.gclc.command.ICommand#execute(ConsoleOutput, ConsoleInput,
|
||||||
|
* String[]) */
|
||||||
@Override
|
@Override
|
||||||
public void execute(String... args) throws CommandRunException {
|
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||||
|
final String... args) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
|
||||||
@Override
|
|
||||||
public String tip() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.ICommand#getCommandName() */
|
* @see fr.bigeon.gclc.command.ICommand#getCommandName() */
|
||||||
@Override
|
@Override
|
||||||
@@ -83,9 +78,16 @@ public final class MockCommand implements ICommand {
|
|||||||
* @see fr.bigeon.gclc.command.ICommand#help(fr.bigeon.gclc.manager.
|
* @see fr.bigeon.gclc.command.ICommand#help(fr.bigeon.gclc.manager.
|
||||||
* ConsoleManager, java.lang.String[]) */
|
* ConsoleManager, java.lang.String[]) */
|
||||||
@Override
|
@Override
|
||||||
public void help(ConsoleManager manager,
|
public void help(final ConsoleOutput manager,
|
||||||
String... args) throws IOException {
|
final String... args) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
||||||
|
@Override
|
||||||
|
public String tip() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,203 +39,122 @@
|
|||||||
package fr.bigeon.gclc.command;
|
package fr.bigeon.gclc.command;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
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 java.util.Set;
|
||||||
|
|
||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
|
||||||
import fr.bigeon.gclc.exception.InvalidParameterException;
|
import fr.bigeon.gclc.exception.InvalidParameterException;
|
||||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
|
|
||||||
/** <p>
|
/** A command relying on the {@link CommandParameters} to store parameters
|
||||||
* A command relying on the {@link CommandParameters} to store parameters values
|
* values.
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @author Emmanuel BIGEON */
|
||||||
public abstract class ParametrizedCommand extends Command {
|
public abstract class ParametrizedCommand extends Command {
|
||||||
|
|
||||||
/** If the command may use interactive prompting for required parameters
|
private final ParametrizedCommandData data;
|
||||||
* that
|
|
||||||
* were not provided on execution */
|
|
||||||
private boolean interactive = true;
|
|
||||||
/** The manager */
|
|
||||||
protected final ConsoleManager manager;
|
|
||||||
/** 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 */
|
|
||||||
private final Map<String, Boolean> params = new HashMap<>();
|
|
||||||
/** The restriction of provided parameters on execution to declared
|
|
||||||
* 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 */
|
* @param name the name */
|
||||||
public ParametrizedCommand(ConsoleManager manager, String name) {
|
public ParametrizedCommand(final String name) {
|
||||||
this(manager, name, true);
|
this(name, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param name the name */
|
/** Create a parametrized command.
|
||||||
public ParametrizedCommand(String name) {
|
* <p>
|
||||||
this(null, name, true);
|
* Implementation are supposed to call the
|
||||||
}
|
* {@link #addBooleanParameter(String)} and
|
||||||
|
* {@link #addStringParameter(String, boolean)} method to set the
|
||||||
/** @param manager the manager
|
* parameters.
|
||||||
|
*
|
||||||
* @param name the name
|
* @param name the name
|
||||||
* @param strict if the arguments are restricted to the declared ones */
|
* @param strict if the arguments are restricted to the declared ones */
|
||||||
public ParametrizedCommand(ConsoleManager manager, String name,
|
public ParametrizedCommand(final String name, final boolean strict) {
|
||||||
boolean strict) {
|
|
||||||
super(name);
|
super(name);
|
||||||
this.manager = manager;
|
data = new ParametrizedCommandData(strict);
|
||||||
interactive = manager != null;
|
|
||||||
this.strict = strict;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param name the name
|
/** Add a boolean parameter to defined parmaters.
|
||||||
* @param strict if the arguments are restricted to the declared ones */
|
|
||||||
public ParametrizedCommand(String name, boolean strict) {
|
|
||||||
this(null, name, strict);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** <p>
|
|
||||||
* Add a parameter to the defined parameters
|
|
||||||
*
|
*
|
||||||
* @param param the parameter identification
|
* @param flag the boolean flag
|
||||||
* @param stringParameter if the parameter is a parameter with an argument
|
* @throws InvalidParameterException if the parameter is already defined as
|
||||||
* @param needed if the parameter is required
|
* a string parameter */
|
||||||
* @throws InvalidParameterException if the parameter was invalid */
|
protected final void addBooleanParameter(final String flag) throws InvalidParameterException {
|
||||||
protected void addParameter(String param, boolean stringParameter,
|
data.addBooleanParameter(flag);
|
||||||
boolean needed) throws InvalidParameterException {
|
|
||||||
if (params.containsKey(param)) {
|
|
||||||
checkParam(param, stringParameter, needed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (stringParameter) {
|
|
||||||
stringParams.put(param, Boolean.valueOf(needed));
|
|
||||||
params.put(param, Boolean.valueOf(needed));
|
|
||||||
} else {
|
|
||||||
if (needed) {
|
|
||||||
// ERROR the boolean parameters cannot be needed
|
|
||||||
throw new InvalidParameterException(
|
|
||||||
"Boolean parameter are present by their very nature. They should not be defined as needed"); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
boolParams.add(param);
|
|
||||||
params.put(param, Boolean.valueOf(false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param param the parameter
|
/** Add a string parameter to defined parmaters.
|
||||||
* @param stringParameter the string parameter type
|
*
|
||||||
* @param needed if the parameter is needed
|
* @param flag the parameter flag
|
||||||
* @throws InvalidParameterException if the new definition is invalid */
|
* @param needed if the parameter's absence should cause an exception
|
||||||
private void checkParam(String param, boolean stringParameter,
|
* @throws InvalidParameterException if the parameter is already defined as
|
||||||
boolean needed) throws InvalidParameterException {
|
* a boolean parameter */
|
||||||
if (stringParameter) {
|
protected final void addStringParameter(final String flag,
|
||||||
if (stringParams.containsKey(param)) {
|
final boolean needed) throws InvalidParameterException {
|
||||||
Boolean need = Boolean.valueOf(
|
data.addStringParameter(flag, needed);
|
||||||
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$
|
|
||||||
}
|
|
||||||
if (stringParams.containsKey(param) || needed) {
|
|
||||||
throw new InvalidParameterException(
|
|
||||||
"Parameter is already defined as string"); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param parameters the command parameters
|
/** 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 */
|
* @throws CommandRunException if the command failed */
|
||||||
protected abstract void doExecute(CommandParameters parameters) throws CommandRunException;
|
protected abstract void doExecute(ConsoleOutput out, ConsoleInput in,
|
||||||
|
CommandParameters parameters) throws CommandRunException;
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.Command#execute(java.lang.String[]) */
|
* @see fr.bigeon.gclc.command.Command#execute(java.lang.String[]) */
|
||||||
@SuppressWarnings("boxing")
|
|
||||||
@Override
|
@Override
|
||||||
public final void execute(String... args) throws CommandRunException {
|
public final void execute(final ConsoleOutput output,
|
||||||
final CommandParameters parameters = new CommandParameters(
|
final ConsoleInput input,
|
||||||
boolParams, stringParams.keySet(), strict);
|
final String... args) throws CommandRunException {
|
||||||
if (!parameters.parseArgs(args)) {
|
try {
|
||||||
// the parameters could not be correctly parsed
|
doExecute(output, input, data.getParameters(input, args));
|
||||||
throw new CommandRunException(CommandRunExceptionType.USAGE,
|
} catch (final IOException e) {
|
||||||
"Unable to read arguments", this); //$NON-NLS-1$
|
throw new CommandRunException("Unable to get parameters", e, this);
|
||||||
}
|
|
||||||
final List<String> toProvide = new ArrayList<>();
|
|
||||||
for (final Entry<String, Boolean> string : params.entrySet()) {
|
|
||||||
if (string.getValue() && parameters.get(string.getKey()) == null) {
|
|
||||||
if (!interactive) {
|
|
||||||
throw new CommandRunException(
|
|
||||||
CommandRunExceptionType.INTERACTION,
|
|
||||||
"Missing required parameter " + string.getKey(), //$NON-NLS-1$
|
|
||||||
this);
|
|
||||||
}
|
|
||||||
toProvide.add(string.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for each needed parameters that is missing, prompt the user.
|
|
||||||
fillParameters(toProvide, parameters);
|
|
||||||
doExecute(parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @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 {
|
|
||||||
for (final String string : toProvide) {
|
|
||||||
String value;
|
|
||||||
try {
|
|
||||||
value = manager.prompt(string);
|
|
||||||
while (value.isEmpty()) {
|
|
||||||
value = manager.prompt(string);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new CommandRunException(
|
|
||||||
CommandRunExceptionType.INTERACTION,
|
|
||||||
"Interactive command but manager closed...", e, this); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
parameters.set(string, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the set of boolean parameters */
|
/** Retrieve the boolean parameters (aka flags).
|
||||||
public Set<String> getBooleanParameters() {
|
*
|
||||||
return Collections.unmodifiableSet(boolParams);
|
* @return the set of boolean parameters */
|
||||||
|
public final Set<String> getBooleanParameters() {
|
||||||
|
return data.getBooleanParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the stringParams */
|
/** Retrieve the parameter names.
|
||||||
public Set<String> getStringParameters() {
|
*
|
||||||
return stringParams.keySet();
|
* @return the stringParams */
|
||||||
|
public final Set<String> getParameters() {
|
||||||
|
return data.getParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the stringParams */
|
/** Get the string parameters names.
|
||||||
public Set<String> getParameters() {
|
*
|
||||||
return params.keySet();
|
* @return the stringParams */
|
||||||
|
public final Set<String> getStringParameters() {
|
||||||
|
return data.getStringParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param param the parameter name
|
/** Test if a parameter is needed.
|
||||||
|
*
|
||||||
|
* @param param the parameter name
|
||||||
* @return if the parameter is needed */
|
* @return if the parameter is needed */
|
||||||
public boolean isNeeded(String param) {
|
public final boolean isNeeded(final String param) {
|
||||||
return params.containsKey(param) && params.get(param).booleanValue();
|
return data.isNeeded(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the strict */
|
/** If the command refuse unrecognized parameters.
|
||||||
public boolean isStrict() {
|
*
|
||||||
return strict;
|
* @return the strict */
|
||||||
}
|
public final boolean isStrict() {
|
||||||
|
return data.isStrict();
|
||||||
/** @return the interactive */
|
|
||||||
public boolean isInteractive() {
|
|
||||||
return interactive;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
* 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.ParametrizedCommand.java
|
||||||
|
* Created on: Dec 24, 2014
|
||||||
|
*/
|
||||||
|
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.InvalidParameterException;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
|
import fr.bigeon.gclc.manager.EmptyInput;
|
||||||
|
|
||||||
|
/** An object to handle standardized command parameters.
|
||||||
|
*
|
||||||
|
* @author Emmanuel BIGEON */
|
||||||
|
public final class ParametrizedCommandData {
|
||||||
|
|
||||||
|
/** 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. */
|
||||||
|
private final Map<String, Boolean> params = new HashMap<>();
|
||||||
|
/** The restriction of provided parameters on execution to declared paramters in
|
||||||
|
* the status maps. */
|
||||||
|
private final boolean strict;
|
||||||
|
|
||||||
|
public ParametrizedCommandData() {
|
||||||
|
this(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParametrizedCommandData(final boolean strict) {
|
||||||
|
this.strict = strict;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add a boolean parameter to defined parmaters.
|
||||||
|
*
|
||||||
|
* @param flag the boolean flag
|
||||||
|
* @throws InvalidParameterException if the parameter is already defined as a
|
||||||
|
* string parameter */
|
||||||
|
public 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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 */
|
||||||
|
public 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$
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CommandParameters getParameters(final ConsoleInput input,
|
||||||
|
final String... args)
|
||||||
|
throws IOException {
|
||||||
|
final CommandParameters parameters = new CommandParameters(boolParams,
|
||||||
|
stringParams.keySet(), strict);
|
||||||
|
try {
|
||||||
|
parameters.parseArgs(args);
|
||||||
|
} catch (final CommandParsingException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
final List<String> toProvide = new ArrayList<>();
|
||||||
|
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 IOException();
|
||||||
|
}
|
||||||
|
toProvide.add(string.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// for each needed parameters that is missing, prompt the user.
|
||||||
|
fillParameters(input, toProvide, parameters);
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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 IOException if the manager was closed */
|
||||||
|
private final static void fillParameters(final ConsoleInput input,
|
||||||
|
final List<String> toProvide, final CommandParameters parameters)
|
||||||
|
throws IOException {
|
||||||
|
for (final String string : toProvide) {
|
||||||
|
String value;
|
||||||
|
value = input.prompt(MessageFormat.format("value of {0}? ", string)); //$NON-NLS-1$
|
||||||
|
while (value.isEmpty()) {
|
||||||
|
value = input
|
||||||
|
.prompt(MessageFormat.format("value of {0}? (cannot be empty) ", //$NON-NLS-1$
|
||||||
|
string));
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,45 +52,64 @@ import fr.bigeon.gclc.GCLCConstants;
|
|||||||
import fr.bigeon.gclc.exception.CommandParsingException;
|
import fr.bigeon.gclc.exception.CommandParsingException;
|
||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
|
|
||||||
/** A command that will laucnh a series of command from a file
|
/** A command that will launch a series of command from a file.
|
||||||
* <p>
|
* <p>
|
||||||
* This command will read a file and execute each non empty non commented line
|
* This command will read a file and execute each non empty non commented line
|
||||||
* as a command of the application.
|
* as a command of the application.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class ScriptExecution extends Command {
|
public final class ScriptExecution extends Command {
|
||||||
|
|
||||||
/** The tab character */
|
/** The tab character. */
|
||||||
private static final String TAB = "\t"; //$NON-NLS-1$
|
private static final String TAB = "\t"; //$NON-NLS-1$
|
||||||
/** the space character */
|
/** the space character. */
|
||||||
private static final String SPACE = " "; //$NON-NLS-1$
|
private static final String SPACE = " "; //$NON-NLS-1$
|
||||||
/** The application */
|
/** The application. */
|
||||||
private final ConsoleApplication application;
|
private final ConsoleApplication application;
|
||||||
/** The commenting prefix */
|
/** The commenting prefix. */
|
||||||
private final String commentPrefix;
|
private final String commentPrefix;
|
||||||
/** The charset for files */
|
/** The charset for files. */
|
||||||
private final Charset charset;
|
private final Charset charset;
|
||||||
|
|
||||||
/** @param name the name of the command
|
/** Create the script command.
|
||||||
|
*
|
||||||
|
* @param name the name of the command
|
||||||
* @param application the application
|
* @param application the application
|
||||||
* @param commentPrefix the comment prefix in the script files
|
* @param commentPrefix the comment prefix in the script files
|
||||||
* @param charset the charset to use for files */
|
* @param charset the charset to use for files */
|
||||||
public ScriptExecution(String name, ConsoleApplication application,
|
public ScriptExecution(final String name, final ConsoleApplication application,
|
||||||
String commentPrefix, Charset charset) {
|
final String commentPrefix, final Charset charset) {
|
||||||
super(name);
|
super(name);
|
||||||
this.application = application;
|
this.application = application;
|
||||||
this.commentPrefix = commentPrefix;
|
this.commentPrefix = commentPrefix;
|
||||||
this.charset = charset;
|
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)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.ICommand#execute(java.lang.String[]) */
|
* @see fr.bigeon.gclc.command.ICommand#execute(java.lang.String[]) */
|
||||||
@Override
|
@Override
|
||||||
public void execute(String... args) throws CommandRunException {
|
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||||
|
final String... args) throws CommandRunException {
|
||||||
checkArgs(args);
|
checkArgs(args);
|
||||||
String scriptFile = args[0];
|
final String scriptFile = args[0];
|
||||||
String[] params = Arrays.copyOfRange(args, 1, args.length);
|
final String[] params = Arrays.copyOfRange(args, 1, args.length);
|
||||||
String cmd;
|
String cmd;
|
||||||
int lineNo = -1;
|
int lineNo = -1;
|
||||||
try (InputStreamReader fReader = new InputStreamReader(
|
try (InputStreamReader fReader = new InputStreamReader(
|
||||||
@@ -98,44 +117,35 @@ public class ScriptExecution extends Command {
|
|||||||
BufferedReader reader = new BufferedReader(fReader)) {
|
BufferedReader reader = new BufferedReader(fReader)) {
|
||||||
while ((cmd = reader.readLine()) != null) {
|
while ((cmd = reader.readLine()) != null) {
|
||||||
lineNo++;
|
lineNo++;
|
||||||
String cmdLine = readCommandLine(cmd, params);
|
final String cmdLine = readCommandLine(cmd, params);
|
||||||
if (cmdLine == null) {
|
if (cmdLine == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
List<String> ps = GCLCConstants.splitCommand(cmdLine);
|
final List<String> ps = GCLCConstants.splitCommand(cmdLine);
|
||||||
String command = ps.remove(0);
|
final String command = ps.remove(0);
|
||||||
application.executeSub(command, ps.toArray(new String[0]));
|
application.executeSub(out, in, command,
|
||||||
|
ps.toArray(new String[0]));
|
||||||
}
|
}
|
||||||
} catch (CommandParsingException e) {
|
} catch (final CommandParsingException e) {
|
||||||
throw new CommandRunException("Invalid command in script (" + //$NON-NLS-1$
|
throw new CommandRunException(MessageFormat.format(
|
||||||
e.getLocalizedMessage() + ")", //$NON-NLS-1$
|
"Invalid command in script ({0})", e.getLocalizedMessage()), //$NON-NLS-1$
|
||||||
e, this);
|
e, this);
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
throw new CommandRunException("Unable to read script", //$NON-NLS-1$
|
throw new CommandRunException("Unable to read script", //$NON-NLS-1$
|
||||||
e, this);
|
e, this);
|
||||||
} catch (CommandRunException e) {
|
} catch (final CommandRunException e) {
|
||||||
throw manageRunException(e, lineNo);
|
throw manageRunException(e, lineNo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param args the arguments
|
|
||||||
* @throws CommandRunException if the arguments were not the ones
|
|
||||||
* expected */
|
|
||||||
private void checkArgs(String[] args) throws CommandRunException {
|
|
||||||
if (args.length == 0) {
|
|
||||||
throw new CommandRunException(CommandRunExceptionType.USAGE,
|
|
||||||
"Expecting a file", this); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** This method will create the correct exception. The exception source must
|
/** This method will create the correct exception. The exception source must
|
||||||
* be this command.
|
* be this command.
|
||||||
*
|
*
|
||||||
* @param e the exception
|
* @param e the exception
|
||||||
* @param lineNo the line nu;ber
|
* @param lineNo the line nu;ber
|
||||||
* @return the exception to actually throw */
|
* @return the exception to actually throw */
|
||||||
private CommandRunException manageRunException(CommandRunException e,
|
private CommandRunException manageRunException(final CommandRunException e,
|
||||||
int lineNo) {
|
final int lineNo) {
|
||||||
if (e.getSource() == this) {
|
if (e.getSource() == this) {
|
||||||
// ensure closing?
|
// ensure closing?
|
||||||
return e;
|
return e;
|
||||||
@@ -147,28 +157,38 @@ public class ScriptExecution extends Command {
|
|||||||
e, this);
|
e, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param cmd the line
|
/** Read a line of the script.
|
||||||
|
*
|
||||||
|
* @param cmd the line
|
||||||
* @param params the formatting parameters
|
* @param params the formatting parameters
|
||||||
* @return the command if it is indeed one, null otherwise
|
* @return the command if it is indeed one, null otherwise
|
||||||
* @throws CommandRunException if the line stqrted with a space character */
|
* @throws CommandRunException if the line stqrted with a space character */
|
||||||
private String readCommandLine(String cmd,
|
private String readCommandLine(final String cmd,
|
||||||
Object[] params) throws CommandRunException {
|
final Object[] params) throws CommandRunException {
|
||||||
if (cmd.startsWith(SPACE) || cmd.startsWith(TAB)) {
|
if (cmd.startsWith(SPACE) || cmd.startsWith(TAB)) {
|
||||||
throw new CommandRunException(
|
throw new CommandRunException(
|
||||||
"Invalid command in script (line starts with space character)", //$NON-NLS-1$
|
"Invalid line in script (line starts with space character)", //$NON-NLS-1$
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
if (cmd.isEmpty() || cmd.startsWith(commentPrefix)) {
|
if (cmd.isEmpty() || cmd.startsWith(commentPrefix)) {
|
||||||
|
// Comment line
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return MessageFormat.format(cmd, params);
|
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)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
* @see fr.bigeon.gclc.command.Command#usageDetail() */
|
||||||
@Override
|
@Override
|
||||||
protected String usageDetail() {
|
protected String usageDetail() {
|
||||||
StringBuilder builder = new StringBuilder();
|
final StringBuilder builder = new StringBuilder();
|
||||||
builder.append(
|
builder.append(
|
||||||
" scriptfile: path to the file containing the script to execute."); //$NON-NLS-1$
|
" scriptfile: path to the file containing the script to execute."); //$NON-NLS-1$
|
||||||
builder.append(System.lineSeparator());
|
builder.append(System.lineSeparator());
|
||||||
@@ -179,18 +199,19 @@ public class ScriptExecution extends Command {
|
|||||||
builder.append(
|
builder.append(
|
||||||
"start with whitespace characters. The lines starting with"); //$NON-NLS-1$
|
"start with whitespace characters. The lines starting with"); //$NON-NLS-1$
|
||||||
builder.append(System.lineSeparator());
|
builder.append(System.lineSeparator());
|
||||||
builder.append("\"" + commentPrefix + //$NON-NLS-1$
|
builder.append('"');
|
||||||
"\" will be ignored as well as empty lines."); //$NON-NLS-1$
|
builder.append(commentPrefix);
|
||||||
|
builder.append("\" will be ignored as well as empty lines."); //$NON-NLS-1$
|
||||||
builder.append(System.lineSeparator());
|
builder.append(System.lineSeparator());
|
||||||
|
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.ICommand#tip() */
|
* @see fr.bigeon.gclc.command.Command#usagePattern() */
|
||||||
@Override
|
@Override
|
||||||
public String tip() {
|
protected String usagePattern() {
|
||||||
return "Execute a script"; //$NON-NLS-1$
|
return super.usagePattern() + " <scriptfile>"; //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,87 +41,92 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
|
|
||||||
/** <p>
|
/**
|
||||||
|
* <p>
|
||||||
* A subed command is a command that can execute sub commands depending on the
|
* A subed command is a command that can execute sub commands depending on the
|
||||||
* first argument.
|
* first argument.
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @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$
|
private static final String TAB = "\t"; //$NON-NLS-1$
|
||||||
/** <p>
|
/** The command to execute when this command is called with no sub
|
||||||
* The command to execute when this command is called with no sub arguments.
|
* arguments.
|
||||||
|
* <p>
|
||||||
* This may be null, in which case the command should have arguments. */
|
* This may be null, in which case the command should have arguments. */
|
||||||
private final ICommand noArgCommand;
|
private final ICommand noArgCommand;
|
||||||
/** A tip on this command. */
|
/** A tip on this command. */
|
||||||
private final String tip;
|
private final String tip;
|
||||||
/** The provider */
|
/** The name of the command. */
|
||||||
private final CommandProvider provider;
|
|
||||||
/** The name of the command */
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
/** @param name the name of the command */
|
/** Create the command that defines sub commands.
|
||||||
public SubedCommand(String name) {
|
*
|
||||||
|
* @param name the name of the command */
|
||||||
|
public SubedCommand(final String name) {
|
||||||
|
super();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
provider = new CommandProvider();
|
|
||||||
noArgCommand = null;
|
noArgCommand = null;
|
||||||
tip = 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
|
* @param noArgCommand the command to execute when no extra parameter are
|
||||||
* provided */
|
* provided */
|
||||||
public SubedCommand(String name, ICommand noArgCommand) {
|
public SubedCommand(final String name, final ICommand noArgCommand) {
|
||||||
|
super();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
provider = new CommandProvider();
|
|
||||||
this.noArgCommand = noArgCommand;
|
this.noArgCommand = noArgCommand;
|
||||||
tip = 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
|
* @param noArgCommand the command to execute
|
||||||
* @param tip the help tip associated */
|
* @param tip the help tip associated */
|
||||||
public SubedCommand(String name, ICommand noArgCommand,
|
public SubedCommand(final String name, final ICommand noArgCommand,
|
||||||
String tip) {
|
final String tip) {
|
||||||
|
super();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
provider = new CommandProvider();
|
|
||||||
this.noArgCommand = noArgCommand;
|
this.noArgCommand = noArgCommand;
|
||||||
this.tip = tip;
|
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 */
|
* @param tip the help tip associated */
|
||||||
public SubedCommand(String name, String tip) {
|
public SubedCommand(final String name, final String tip) {
|
||||||
|
super();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
provider = new CommandProvider();
|
|
||||||
noArgCommand = null;
|
noArgCommand = null;
|
||||||
this.tip = tip;
|
this.tip = tip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(ICommand value) throws InvalidCommandName {
|
|
||||||
return provider.add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.acide.Command#execute(java.lang.String[]) */
|
* @see fr.bigeon.acide.Command#execute(java.lang.String[]) */
|
||||||
@Override
|
@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 (args.length == 0 || args[0].startsWith("-")) { //$NON-NLS-1$
|
||||||
if (noArgCommand != null) {
|
if (noArgCommand != null) {
|
||||||
noArgCommand.execute(args);
|
noArgCommand.execute(output, input, args);
|
||||||
} else {
|
} else {
|
||||||
throw new CommandRunException("Unrecognized command", this); //$NON-NLS-1$
|
throw new CommandRunException("Unrecognized command", this); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
executeSub(args[0], Arrays.copyOfRange(args, 1, args.length));
|
executeSub(output, input, args[0],
|
||||||
} catch (CommandRunException e) {
|
Arrays.copyOfRange(args, 1, args.length));
|
||||||
|
} catch (final CommandRunException e) {
|
||||||
if (e.getSource() != null) {
|
if (e.getSource() != null) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@@ -131,21 +136,6 @@ public class SubedCommand implements ICommandProvider, ICommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (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)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.ICommand#getCommandName() */
|
* @see fr.bigeon.gclc.command.ICommand#getCommandName() */
|
||||||
@Override
|
@Override
|
||||||
@@ -156,27 +146,29 @@ public class SubedCommand implements ICommandProvider, ICommand {
|
|||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.Command#help() */
|
* @see fr.bigeon.gclc.command.Command#help() */
|
||||||
@Override
|
@Override
|
||||||
public void help(ConsoleManager manager,
|
public void help(final ConsoleOutput manager,
|
||||||
String... args) throws IOException {
|
final String... args) throws IOException {
|
||||||
if (args.length != 0 && !args[0].startsWith("-")) { //$NON-NLS-1$
|
if (args.length != 0 && !args[0].startsWith("-")) { //$NON-NLS-1$
|
||||||
// Specific
|
// Specific
|
||||||
final ICommand c = get(args[0]);
|
final ICommand c = get(args[0]);
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
c.help(manager, Arrays.copyOfRange(args, 1, args.length));
|
c.help(manager, Arrays.copyOfRange(args, 1, args.length));
|
||||||
|
} else {
|
||||||
|
manager.println("No command "+Arrays.toString(args));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Generic
|
// Generic
|
||||||
if (noArgCommand != null && noArgCommand.tip() != null) {
|
if (noArgCommand != null && noArgCommand.tip() != null) {
|
||||||
manager.println(TAB + noArgCommand.tip());
|
manager.println(TAB + noArgCommand.tip());
|
||||||
}
|
}
|
||||||
for (final ICommand cmd : provider.commands) {
|
for (final ICommand cmd : commands) {
|
||||||
if (cmd.tip() == null) {
|
if (cmd.tip() == null) {
|
||||||
manager.println(TAB + cmd.getCommandName());
|
manager.println(TAB + cmd.getCommandName());
|
||||||
} else {
|
} else {
|
||||||
manager.println(TAB + cmd.getCommandName() + ": " + //$NON-NLS-1$
|
manager.println(TAB + cmd.getCommandName() + ": " + //$NON-NLS-1$
|
||||||
cmd.tip());
|
cmd.tip());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +183,6 @@ public class SubedCommand implements ICommandProvider, ICommand {
|
|||||||
* @see java.lang.Object#toString() */
|
* @see java.lang.Object#toString() */
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SubedCommand " + provider; //$NON-NLS-1$
|
return "SubedCommand " + super.toString(); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,27 +38,33 @@
|
|||||||
*/
|
*/
|
||||||
package fr.bigeon.gclc.exception;
|
package fr.bigeon.gclc.exception;
|
||||||
|
|
||||||
/** An exception raised during command parsing
|
/** An exception raised during command parsing.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class CommandParsingException extends Exception {
|
public class CommandParsingException extends Exception {
|
||||||
|
|
||||||
/** svuid */
|
/** svuid. */
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/** @param message an explaination
|
/** Create the exception with a message.
|
||||||
* @param cause the cause */
|
*
|
||||||
public CommandParsingException(String message, Throwable cause) {
|
* @param message the message */
|
||||||
super(message, cause);
|
public CommandParsingException(final String message) {
|
||||||
}
|
|
||||||
|
|
||||||
/** @param message an explaination */
|
|
||||||
public CommandParsingException(String message) {
|
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param cause the cause */
|
/** Create the exception with a message and a cause.
|
||||||
public CommandParsingException(Throwable 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);
|
super(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,61 +40,69 @@ package fr.bigeon.gclc.exception;
|
|||||||
|
|
||||||
import fr.bigeon.gclc.command.ICommand;
|
import fr.bigeon.gclc.command.ICommand;
|
||||||
|
|
||||||
/** <p>
|
/** An exception thrown when a command failed to run correctly.
|
||||||
* An exception thrown when a command failed to run correctly.
|
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @author Emmanuel BIGEON */
|
||||||
public class CommandRunException extends Exception {
|
public final class CommandRunException extends Exception {
|
||||||
|
|
||||||
/**
|
/** the SVUID. */
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/** The type of run exception */
|
/** The type of run exception. */
|
||||||
private final CommandRunExceptionType type;
|
private final CommandRunExceptionType type;
|
||||||
/** The command that caused the error */
|
/** The command that caused the error. */
|
||||||
private final ICommand source;
|
private transient ICommand source;
|
||||||
|
|
||||||
/** @param message a message
|
/** Create the exception.
|
||||||
* @param source the source */
|
*
|
||||||
public CommandRunException(String message, ICommand source) {
|
* @param type the type of exception
|
||||||
super(message);
|
|
||||||
type = CommandRunExceptionType.EXECUTION;
|
|
||||||
this.source = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param message a message
|
|
||||||
* @param cause the cause
|
|
||||||
* @param source the source */
|
|
||||||
public CommandRunException(String message, Throwable cause,
|
|
||||||
ICommand source) {
|
|
||||||
super(message, cause);
|
|
||||||
type = CommandRunExceptionType.EXECUTION;
|
|
||||||
this.source = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param type the type of exception
|
|
||||||
* @param message the message
|
* @param message the message
|
||||||
* @param source the source */
|
* @param source the source */
|
||||||
public CommandRunException(CommandRunExceptionType type, String message,
|
public CommandRunException(final CommandRunExceptionType type,
|
||||||
ICommand source) {
|
final String message, final ICommand source) {
|
||||||
super(message);
|
super(message);
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.source = source;
|
this.source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param type the type of exception
|
/** Create the exception with a cause.
|
||||||
|
*
|
||||||
|
* @param type the type of exception
|
||||||
* @param message a message
|
* @param message a message
|
||||||
* @param cause the cause
|
* @param cause the cause
|
||||||
* @param source the source */
|
* @param source the source */
|
||||||
public CommandRunException(CommandRunExceptionType type, String message,
|
public CommandRunException(final CommandRunExceptionType type,
|
||||||
Throwable cause, ICommand source) {
|
final String message, final Throwable cause,
|
||||||
|
final ICommand source) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.source = source;
|
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)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Throwable#getLocalizedMessage() */
|
* @see java.lang.Throwable#getLocalizedMessage() */
|
||||||
@Override
|
@Override
|
||||||
@@ -106,12 +114,16 @@ public class CommandRunException extends Exception {
|
|||||||
return super.getLocalizedMessage();
|
return super.getLocalizedMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the source */
|
/** Get the exception raising command.
|
||||||
|
*
|
||||||
|
* @return the source */
|
||||||
public ICommand getSource() {
|
public ICommand getSource() {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the type */
|
/** Get the exception type.
|
||||||
|
*
|
||||||
|
* @return the type */
|
||||||
public CommandRunExceptionType getType() {
|
public CommandRunExceptionType getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,14 +38,14 @@
|
|||||||
*/
|
*/
|
||||||
package fr.bigeon.gclc.exception;
|
package fr.bigeon.gclc.exception;
|
||||||
|
|
||||||
/** The command run exception possible types
|
/** The command run exception possible types.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public enum CommandRunExceptionType {
|
public enum CommandRunExceptionType {
|
||||||
/** Type of exception due to a wrong usage */
|
/** Type of exception due to a wrong usage. */
|
||||||
USAGE,
|
USAGE,
|
||||||
/** Type of exception due to a problem in execution */
|
/** Type of exception due to a problem in execution. */
|
||||||
EXECUTION,
|
EXECUTION,
|
||||||
/** Type of exception due to the impossibility to interact with user */
|
/** Type of exception due to the impossibility to interact with user. */
|
||||||
INTERACTION;
|
INTERACTION;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,36 +38,39 @@
|
|||||||
*/
|
*/
|
||||||
package fr.bigeon.gclc.exception;
|
package fr.bigeon.gclc.exception;
|
||||||
|
|
||||||
/** <p>
|
/** Exception sent from the application when a command is added but the name of
|
||||||
* Exception sent from the application when a command is added but the name of
|
* the command is already used.
|
||||||
* the command is already used
|
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @author Emmanuel BIGEON */
|
||||||
public class InvalidCommandName extends Exception {
|
public class InvalidCommandName extends Exception {
|
||||||
|
|
||||||
/**
|
/** the SVUID. */
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/** Default constructor */
|
/** Default constructor. */
|
||||||
public InvalidCommandName() {
|
public InvalidCommandName() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param message the message
|
/** Create the exception with a message.
|
||||||
* @param cause the cause */
|
*
|
||||||
public InvalidCommandName(String message, Throwable cause) {
|
* @param message the message */
|
||||||
super(message, cause);
|
public InvalidCommandName(final String message) {
|
||||||
}
|
|
||||||
|
|
||||||
/** @param message the message */
|
|
||||||
public InvalidCommandName(String message) {
|
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param cause the cause */
|
/** Create the exception with a message and a cause.
|
||||||
public InvalidCommandName(Throwable 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);
|
super(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,24 +47,28 @@ package fr.bigeon.gclc.exception;
|
|||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class InvalidParameterException extends Exception {
|
public class InvalidParameterException extends Exception {
|
||||||
|
|
||||||
/**
|
/** the SVUID. */
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/** @param message the message
|
/** Create the exception with a message.
|
||||||
* @param cause the cause */
|
*
|
||||||
public InvalidParameterException(String message, Throwable cause) {
|
* @param message the message */
|
||||||
super(message, cause);
|
public InvalidParameterException(final String message) {
|
||||||
}
|
|
||||||
|
|
||||||
/** @param message the message */
|
|
||||||
public InvalidParameterException(String message) {
|
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param cause the cause */
|
/** Create the exception with a message and a cause.
|
||||||
public InvalidParameterException(Throwable cause) {
|
*
|
||||||
|
* @param message the message
|
||||||
|
* @param cause the cause */
|
||||||
|
public InvalidParameterException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create the exception with a cause.
|
||||||
|
*
|
||||||
|
* @param cause the cause */
|
||||||
|
public InvalidParameterException(final Throwable cause) {
|
||||||
super(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.
|
/** Internationalization class.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class Messages {
|
public final class Messages {
|
||||||
/** The resource bundle name */
|
/** The resource bundle name. */
|
||||||
private static final String BUNDLE_NAME = "fr.bigeon.gclc.l10n.messages"; //$NON-NLS-1$
|
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
|
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
|
||||||
.getBundle(BUNDLE_NAME);
|
.getBundle(BUNDLE_NAME);
|
||||||
|
|
||||||
/** The class logger */
|
/** The class logger. */
|
||||||
private static final Logger LOGGER = Logger
|
private static final Logger LOGGER = Logger
|
||||||
.getLogger(Messages.class.getName());
|
.getLogger(Messages.class.getName());
|
||||||
|
|
||||||
/** Utility class */
|
/** Utility class. */
|
||||||
private Messages() {
|
private Messages() {
|
||||||
// Utility class
|
// Utility class
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get formatted internationalized messages
|
/** Get formatted internationalized messages.
|
||||||
*
|
*
|
||||||
* @param key the message key
|
* @param key the message key
|
||||||
* @param args the formatting arguments
|
* @param args the formatting arguments
|
||||||
* @return the formatted internationalized message */
|
* @return the formatted internationalized message */
|
||||||
public static String getString(String key, Object... args) {
|
public static String getString(final String key, final Object... args) {
|
||||||
try {
|
try {
|
||||||
return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);
|
return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);
|
||||||
} catch (MissingResourceException e) {
|
} catch (final MissingResourceException e) {
|
||||||
LOGGER.log(Level.WARNING,
|
LOGGER.log(Level.WARNING,
|
||||||
"Unrecognized internationalization message key: " + key, e); //$NON-NLS-1$
|
"Unrecognized internationalization message key: " + key, e); //$NON-NLS-1$
|
||||||
return '!' + key + '!';
|
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;
|
||||||
118
gclc/src/main/java/fr/bigeon/gclc/manager/ConsoleInput.java
Normal file
118
gclc/src/main/java/fr/bigeon/gclc/manager/ConsoleInput.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.manager.ConsoleInput.java
|
||||||
|
* Created on: Nov 13, 2017
|
||||||
|
*/
|
||||||
|
package fr.bigeon.gclc.manager;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.tools.StringProvider;
|
||||||
|
|
||||||
|
/** 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 */
|
||||||
|
StringProvider 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);
|
||||||
|
|
||||||
|
void setPrompt(StringProvider string);
|
||||||
|
}
|
||||||
@@ -33,68 +33,44 @@
|
|||||||
* knowledge of the CeCILL license and that you accept its terms.
|
* knowledge of the CeCILL license and that you accept its terms.
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* gclc:fr.bigeon.gclc.ConsoleManager.java
|
* gclc:fr.bigeon.gclc.manager.ConsoleOutput.java
|
||||||
* Created on: Dec 19, 2014
|
* Created on: Nov 13, 2017
|
||||||
*/
|
*/
|
||||||
package fr.bigeon.gclc.manager;
|
package fr.bigeon.gclc.manager;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
|
|
||||||
/** <p>
|
/** A console output definition.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @author Emmanuel Bigeon */
|
||||||
public interface ConsoleManager {
|
public interface ConsoleOutput extends AutoCloseable {
|
||||||
|
|
||||||
/** @return the prompt prefix */
|
/** Test if the output is closed.
|
||||||
String getPrompt();
|
*
|
||||||
|
* @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
|
* @throws IOException if the manager is closed or could not read the
|
||||||
* prompt */
|
* prompt */
|
||||||
void print(String text) throws IOException;
|
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
|
* @throws IOException if the manager is closed or could not read the
|
||||||
* prompt */
|
* prompt */
|
||||||
void println() throws IOException;
|
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
|
* @throws IOException if the manager is closed or could not read the
|
||||||
* prompt */
|
* prompt */
|
||||||
void println(String message) throws IOException;
|
void println(String message) throws IOException;
|
||||||
|
|
||||||
/** @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;
|
|
||||||
|
|
||||||
/** @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;
|
|
||||||
|
|
||||||
/** <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();
|
|
||||||
|
|
||||||
/** Indicate to the manager that is should interrompt the prompting, if
|
|
||||||
* possible. */
|
|
||||||
void interruptPrompt();
|
|
||||||
}
|
}
|
||||||
124
gclc/src/main/java/fr/bigeon/gclc/manager/EmptyInput.java
Normal file
124
gclc/src/main/java/fr/bigeon/gclc/manager/EmptyInput.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.manager.EmptyInput.java
|
||||||
|
* Created on: Nov 13, 2017
|
||||||
|
*/
|
||||||
|
package fr.bigeon.gclc.manager;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.tools.ConstantString;
|
||||||
|
import fr.bigeon.gclc.tools.StringProvider;
|
||||||
|
|
||||||
|
/** 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 StringProvider getPrompt() {
|
||||||
|
return new ConstantString(""); //$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) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPrompt(StringProvider string) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
160
gclc/src/main/java/fr/bigeon/gclc/manager/PipedConsoleInput.java
Normal file
160
gclc/src/main/java/fr/bigeon/gclc/manager/PipedConsoleInput.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-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;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.tools.StringProvider;
|
||||||
|
|
||||||
|
/** 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 StringProvider 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPrompt(StringProvider string) {
|
||||||
|
innerManager.setPrompt(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -44,131 +44,110 @@ import java.io.InputStreamReader;
|
|||||||
import java.io.PipedInputStream;
|
import java.io.PipedInputStream;
|
||||||
import java.io.PipedOutputStream;
|
import java.io.PipedOutputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
/** This console manager allows to enter commands and retrieve the output as an
|
/** This console output allows to retrieve the output as an input.
|
||||||
* input.
|
|
||||||
* <p>
|
* <p>
|
||||||
* This console manager is used to internally pilot an application. This can be
|
* This console output is used to internally pilot an application. This can be
|
||||||
* used to test application behavior.
|
* used to test application behavior.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public final class PipedConsoleManager
|
public final class PipedConsoleOutput
|
||||||
implements ConsoleManager, AutoCloseable {
|
implements ConsoleOutput {
|
||||||
|
|
||||||
/** The encoding between streams */
|
/** The encoding between streams. */
|
||||||
private static final String UTF_8 = "UTF-8"; //$NON-NLS-1$
|
private static final String UTF_8 = "UTF-8"; //$NON-NLS-1$
|
||||||
/** THe inner manager */
|
/** THe inner manager. */
|
||||||
private final SystemConsoleManager innerManager;
|
private final StreamConsoleOutput innerManager;
|
||||||
/** The stream to pipe commands into */
|
/** The reader to get application return from. */
|
||||||
private final PipedOutputStream commandInput;
|
|
||||||
/** The reader to get application return from */
|
|
||||||
private final BufferedReader commandBuffOutput;
|
private final BufferedReader commandBuffOutput;
|
||||||
/** The stream to get application return from */
|
/** The stream to get application return from. */
|
||||||
private final PipedInputStream commandOutput;
|
private final PipedInputStream commandOutput;
|
||||||
/** The print writer for application to write return to */
|
/** The print writer for application to write return to. */
|
||||||
private final PrintStream outPrint;
|
private final PrintStream outPrint;
|
||||||
/** The stream for the application to read commands from */
|
/** The reading thread. */
|
||||||
private final PipedInputStream in;
|
|
||||||
/** The writing thread */
|
|
||||||
private final WritingRunnable writing;
|
|
||||||
/** The reading thread */
|
|
||||||
private final ReadingRunnable reading;
|
private final ReadingRunnable reading;
|
||||||
|
|
||||||
/** @throws IOException if the piping failed for streams */
|
/** Create a manager that will write and read through piped stream.
|
||||||
public PipedConsoleManager() throws IOException {
|
*
|
||||||
commandInput = new PipedOutputStream();
|
* @throws IOException if the piping failed for streams */
|
||||||
in = new PipedInputStream(commandInput);
|
public PipedConsoleOutput() throws IOException {
|
||||||
commandOutput = new PipedInputStream();
|
commandOutput = new PipedInputStream();
|
||||||
PipedOutputStream out = new PipedOutputStream(commandOutput);
|
final PipedOutputStream out = new PipedOutputStream(commandOutput);
|
||||||
commandBuffOutput = new BufferedReader(
|
commandBuffOutput = new BufferedReader(
|
||||||
new InputStreamReader(commandOutput, Charset.forName(UTF_8)));
|
new InputStreamReader(commandOutput, StandardCharsets.UTF_8));
|
||||||
outPrint = new PrintStream(out, true, UTF_8);
|
outPrint = new PrintStream(out, true, UTF_8);
|
||||||
innerManager = new SystemConsoleManager(outPrint, in,
|
innerManager = new StreamConsoleOutput(outPrint);
|
||||||
Charset.forName(UTF_8));
|
|
||||||
writing = new WritingRunnable(commandInput, Charset.forName(UTF_8));
|
|
||||||
reading = new ReadingRunnable(commandBuffOutput);
|
reading = new ReadingRunnable(commandBuffOutput);
|
||||||
Thread th = new Thread(writing, "write"); //$NON-NLS-1$
|
final Thread th = new Thread(reading, "GCLC console output forward"); //$NON-NLS-1$
|
||||||
th.start();
|
th.setDaemon(true);
|
||||||
th = new Thread(reading, "read"); //$NON-NLS-1$
|
|
||||||
th.start();
|
th.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/** Test if there is available data.
|
||||||
public String getPrompt() {
|
*
|
||||||
return innerManager.getPrompt();
|
* @return the content of the next line written by the application
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void print(String object) throws IOException {
|
|
||||||
innerManager.print(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println() throws IOException {
|
|
||||||
innerManager.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(String object) throws IOException {
|
|
||||||
innerManager.println(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String prompt() throws IOException {
|
|
||||||
return innerManager
|
|
||||||
.prompt(innerManager.getPrompt() + System.lineSeparator());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String prompt(String message) throws IOException {
|
|
||||||
return innerManager.prompt(message + System.lineSeparator());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPrompt(String prompt) {
|
|
||||||
innerManager.setPrompt(prompt);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
innerManager.close();
|
|
||||||
reading.setRunning(false);
|
|
||||||
writing.setRunning(false);
|
|
||||||
outPrint.close();
|
|
||||||
commandBuffOutput.close();
|
|
||||||
commandOutput.close();
|
|
||||||
in.close();
|
|
||||||
commandInput.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isClosed() {
|
|
||||||
return innerManager.isClosed();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param content the content to type to the application
|
|
||||||
* @throws IOException if the typing failed */
|
|
||||||
public void type(String content) throws IOException {
|
|
||||||
writing.addMessage(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return the content of the next line written by the application
|
|
||||||
* @throws IOException if the reading failed */
|
* @throws IOException if the reading failed */
|
||||||
public boolean available() throws IOException {
|
public boolean available() throws IOException {
|
||||||
return reading.hasMessage();
|
return reading.hasMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.manager.ConsoleManager#interruptPrompt() */
|
* @see java.lang.AutoCloseable#close() */
|
||||||
@Override
|
@Override
|
||||||
public void interruptPrompt() {
|
public void close() throws IOException {
|
||||||
innerManager.interruptPrompt();
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,44 +43,263 @@ import java.io.IOException;
|
|||||||
import java.io.InterruptedIOException;
|
import java.io.InterruptedIOException;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/** A runnable to read the piped output.
|
/** A runnable to read the piped output.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class ReadingRunnable implements Runnable {
|
public final class ReadingRunnable implements Runnable {
|
||||||
|
|
||||||
/** The closed pipe message */
|
/** 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$
|
private static final String CLOSED_PIPE = "Closed pipe"; //$NON-NLS-1$
|
||||||
/** Wait timeout */
|
/** Wait timeout. */
|
||||||
private static final long TIMEOUT = 1000;
|
private static final long TIMEOUT = 1000;
|
||||||
/** Class logger */
|
/** Class logger. */
|
||||||
private static final Logger LOGGER = Logger
|
private static final Logger LOGGER = Logger
|
||||||
.getLogger(ReadingRunnable.class.getName());
|
.getLogger(ReadingRunnable.class.getName());
|
||||||
/** Read messages */
|
/** Read messages. */
|
||||||
private final Deque<String> messages = new ArrayDeque<>();
|
private final Deque<String> messages = new ArrayDeque<>();
|
||||||
/** the reader */
|
/** the reader. */
|
||||||
private final BufferedReader reader;
|
private final BufferedReader reader;
|
||||||
/** the state of this runnable */
|
/** the state of this runnable. */
|
||||||
private boolean running = true;
|
private boolean running = true;
|
||||||
|
/** Synchro object. */
|
||||||
/** Synchro object */
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
/** The waiting status for a message */
|
/** The waiting status for a message. */
|
||||||
private boolean waiting;
|
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;
|
||||||
|
|
||||||
/** @param reader the input to read from */
|
/** Create a reading runnable.
|
||||||
public ReadingRunnable(BufferedReader reader) {
|
*
|
||||||
|
* @param reader the input to read from */
|
||||||
|
public ReadingRunnable(final BufferedReader reader) {
|
||||||
super();
|
super();
|
||||||
this.reader = reader;
|
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)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Runnable#run() */
|
* @see java.lang.Runnable#run() */
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
try {
|
try {
|
||||||
String line = reader.readLine();
|
String line = reader.readLine();
|
||||||
@@ -93,90 +312,43 @@ public class ReadingRunnable implements Runnable {
|
|||||||
line = stripNull(line);
|
line = stripNull(line);
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
messages.add(line);
|
messages.add(line);
|
||||||
lock.notify();
|
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;
|
||||||
}
|
}
|
||||||
} catch (InterruptedIOException e) {
|
|
||||||
LOGGER.log(Level.INFO, "Reading interrupted", e); //$NON-NLS-1$
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Unable to read from stream", e); //$NON-NLS-1$
|
|
||||||
running = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Strip the string from head NULL characters.
|
/** Set the running status for this reading runnable.
|
||||||
*
|
*
|
||||||
* @param line the line to strip the null character from
|
* @param running the running to set */
|
||||||
* @return the resulting string */
|
public void setRunning(final boolean running) {
|
||||||
private static String stripNull(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @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;
|
|
||||||
while (messages.isEmpty()) {
|
|
||||||
try {
|
|
||||||
lock.wait(TIMEOUT);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Thread interruption exception.", //$NON-NLS-1$
|
|
||||||
e);
|
|
||||||
}
|
|
||||||
if (messages.isEmpty() && !running) {
|
|
||||||
throw new IOException(CLOSED_PIPE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOGGER.finest("Polled: " + messages.peek()); //$NON-NLS-1$
|
|
||||||
waiting = false;
|
|
||||||
return messages.poll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param running the running to set */
|
|
||||||
public void setRunning(boolean running) {
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
this.running = running;
|
this.running = running;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the running */
|
/** Wait for the next message to be integratted.
|
||||||
public boolean isRunning() {
|
*
|
||||||
synchronized (lock) {
|
* @param timeout the timeout to wait
|
||||||
return running;
|
* @throws IOException if the next message was not delivered and the
|
||||||
}
|
* runnable stopped. */
|
||||||
}
|
private void waitMessage(final long timeout) throws IOException {
|
||||||
|
while (messages.isEmpty()) {
|
||||||
/** @return if a message is waiting
|
doWaitMessage(timeout);
|
||||||
* @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.notify();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -45,117 +45,89 @@ import java.io.InputStreamReader;
|
|||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.tools.ConstantString;
|
||||||
|
import fr.bigeon.gclc.tools.StringProvider;
|
||||||
|
|
||||||
/** A console using the input stream and print stream.
|
/** A console using the input stream and print stream.
|
||||||
* <p>
|
* <p>
|
||||||
* The default constructor will use the system standart input and output.
|
* The default constructor will use the system standart input and output.
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @author Emmanuel BIGEON */
|
||||||
public final class SystemConsoleManager implements ConsoleManager { // NOSONAR
|
public final class StreamConsoleInput implements ConsoleInput {
|
||||||
|
|
||||||
/** The default prompt */
|
/** The default prompt. */
|
||||||
public static final String DEFAULT_PROMPT = "> "; //$NON-NLS-1$
|
public static final StringProvider DEFAULT_PROMPT = new ConstantString("> "); //$NON-NLS-1$
|
||||||
|
|
||||||
/** The command prompt. It can be changed. */
|
/** The command prompt. It can be changed. */
|
||||||
private String prompt = DEFAULT_PROMPT;
|
private StringProvider prompt = DEFAULT_PROMPT;
|
||||||
|
|
||||||
/** The print stream */
|
/** The print stream. */
|
||||||
private final PrintStream out;
|
private final PrintStream out;
|
||||||
/** The input stream */
|
/** The input stream. */
|
||||||
private final BufferedReader in;
|
private final BufferedReader in;
|
||||||
|
|
||||||
/** If the manager is closed */
|
/** If the manager is closed. */
|
||||||
private boolean closed = false;
|
private boolean closed = false;
|
||||||
|
|
||||||
/** The prompting thread */
|
/** The prompting thread. */
|
||||||
private final Thread promptThread;
|
private final Thread promptThread;
|
||||||
|
|
||||||
/** The reading runnable */
|
/** The reading runnable. */
|
||||||
private final ReadingRunnable reading;
|
private final ReadingRunnable reading;
|
||||||
|
|
||||||
/** This default constructor relies on the system defined standart output
|
/** This default constructor relies on the system defined standart output
|
||||||
* and input stream. */
|
* and input stream. */
|
||||||
public SystemConsoleManager() {
|
public StreamConsoleInput() {
|
||||||
this(System.out, System.in, Charset.defaultCharset());
|
this(System.out, System.in, Charset.defaultCharset());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param out the output stream
|
/** Create the stream base console input.
|
||||||
|
*
|
||||||
|
* @param out the output stream
|
||||||
* @param in the input stream
|
* @param in the input stream
|
||||||
* @param charset the charset for the input */
|
* @param charset the charset for the input */
|
||||||
public SystemConsoleManager(PrintStream out, InputStream in,
|
public StreamConsoleInput(final PrintStream out, final InputStream in,
|
||||||
Charset charset) {
|
final Charset charset) {
|
||||||
super();
|
super();
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.in = new BufferedReader(new InputStreamReader(in, charset));
|
this.in = new BufferedReader(new InputStreamReader(in, charset));
|
||||||
reading = new ReadingRunnable(this.in);
|
reading = new ReadingRunnable(this.in);
|
||||||
promptThread = new Thread(reading, "prompt"); //$NON-NLS-1$
|
promptThread = new Thread(reading, "prompt"); //$NON-NLS-1$
|
||||||
|
promptThread.setDaemon(true);
|
||||||
promptThread.start();
|
promptThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the prompt */
|
/** Check that the console input is not closed.
|
||||||
@Override
|
*
|
||||||
public String getPrompt() {
|
* @throws IOException if the stream was closed */
|
||||||
return prompt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see fr.bigeon.gclc.ConsoleManager#print(java.lang.Object) */
|
|
||||||
@Override
|
|
||||||
public void print(String object) throws IOException {
|
|
||||||
checkOpen();
|
|
||||||
out.print(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @throws IOException if the stream was closed */
|
|
||||||
private void checkOpen() throws IOException {
|
private void checkOpen() throws IOException {
|
||||||
if (closed) {
|
if (closed) {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (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(String object) throws IOException {
|
|
||||||
checkOpen();
|
|
||||||
out.println(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see fr.bigeon.gclc.ConsoleManager#prompt() */
|
|
||||||
@Override
|
|
||||||
public String prompt() throws IOException {
|
|
||||||
return prompt(prompt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see fr.bigeon.gclc.ConsoleManager#prompt(java.lang.String) */
|
|
||||||
@Override
|
|
||||||
public String prompt(String message) throws IOException {
|
|
||||||
checkOpen();
|
|
||||||
out.print(message);
|
|
||||||
return reading.getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param prompt the prompt to set */
|
|
||||||
@Override
|
|
||||||
public void setPrompt(String prompt) {
|
|
||||||
this.prompt = prompt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.manager.ConsoleManager#close() */
|
* @see fr.bigeon.gclc.manager.ConsoleManager#close() */
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
closed = true;
|
closed = true;
|
||||||
reading.setRunning(false);
|
reading.setRunning(false);
|
||||||
|
promptThread.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleInput#getPrompt() */
|
||||||
|
@Override
|
||||||
|
public StringProvider 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)
|
/* (non-Javadoc)
|
||||||
@@ -165,12 +137,54 @@ public final class SystemConsoleManager implements ConsoleManager { // NOSONAR
|
|||||||
return closed;
|
return closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Beware, in this implementation this is the same as closing the manager.
|
/* (non-Javadoc)
|
||||||
*
|
* @see fr.bigeon.gclc.ConsoleManager#prompt() */
|
||||||
* @see fr.bigeon.gclc.manager.ConsoleManager#interruptPrompt() */
|
|
||||||
@Override
|
@Override
|
||||||
public void interruptPrompt() {
|
public String prompt() throws IOException {
|
||||||
reading.interrupt();
|
return prompt(prompt.apply());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see fr.bigeon.gclc.manager.ConsoleManager#prompt(long) */
|
||||||
|
@Override
|
||||||
|
public String prompt(final long timeout) throws IOException {
|
||||||
|
return prompt(prompt.apply(), 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 = new ConstantString(prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPrompt(StringProvider string) {
|
||||||
|
this.prompt = string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,89 +52,109 @@ import java.util.logging.Logger;
|
|||||||
* Messages are queued to be retrieved latter on.
|
* Messages are queued to be retrieved latter on.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class WritingRunnable implements Runnable {
|
public final class WritingRunnable implements Runnable {
|
||||||
|
|
||||||
/** Wait timeout */
|
/** Wait timeout. */
|
||||||
private static final long TIMEOUT = 1000;
|
private static final long TIMEOUT = 1000;
|
||||||
/** Class logger */
|
/** Class logger. */
|
||||||
private static final Logger LOGGER = Logger
|
private static final Logger LOGGER = Logger
|
||||||
.getLogger(WritingRunnable.class.getName());
|
.getLogger(WritingRunnable.class.getName());
|
||||||
/** Messages to write */
|
/** Messages to write. */
|
||||||
private final Deque<String> messages = new ArrayDeque<>();
|
private final Deque<String> messages = new ArrayDeque<>();
|
||||||
/** Stream to write to */
|
/** Stream to write to. */
|
||||||
private final OutputStream outPrint;
|
private final OutputStream outPrint;
|
||||||
/** The charset */
|
/** The charset. */
|
||||||
private final Charset charset;
|
private final Charset charset;
|
||||||
/** Runnable state */
|
/** Runnable state. */
|
||||||
private boolean running = true;
|
private boolean running = true;
|
||||||
|
|
||||||
/** Synchro object */
|
/** Synchro object. */
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
|
|
||||||
/** @param outPrint the output to print to
|
/** Create the writing runnable.
|
||||||
|
*
|
||||||
|
* @param outPrint the output to print to
|
||||||
* @param charset the charset of the stream */
|
* @param charset the charset of the stream */
|
||||||
public WritingRunnable(OutputStream outPrint, Charset charset) {
|
public WritingRunnable(final OutputStream outPrint, final Charset charset) {
|
||||||
super();
|
super();
|
||||||
this.outPrint = outPrint;
|
this.outPrint = outPrint;
|
||||||
this.charset = charset;
|
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)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Runnable#run() */
|
* @see java.lang.Runnable#run() */
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
while (messages.isEmpty()) {
|
while (messages.isEmpty()) {
|
||||||
try {
|
waitNextMessage();
|
||||||
lock.wait(TIMEOUT);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOGGER.log(Level.SEVERE,
|
|
||||||
"Thread interruption exception.", e); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
if (!running) {
|
if (!running) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String message = messages.poll();
|
writeMessage();
|
||||||
ByteBuffer buff = charset
|
|
||||||
.encode(message + System.lineSeparator());
|
|
||||||
if (buff.hasArray()) {
|
|
||||||
try {
|
|
||||||
outPrint.write(buff.array());
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Unable to write to stream", //$NON-NLS-1$
|
|
||||||
e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param message the message
|
/** Set the running status.
|
||||||
* @throws IOException if the pipe is closed */
|
*
|
||||||
public void addMessage(String message) throws IOException {
|
* @param running the running to set */
|
||||||
synchronized (lock) {
|
public void setRunning(final boolean running) {
|
||||||
if (!running) {
|
|
||||||
throw new IOException("Closed pipe"); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
messages.offer(message);
|
|
||||||
lock.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param running the running to set */
|
|
||||||
public void setRunning(boolean running) {
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
this.running = running;
|
this.running = running;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the running */
|
/** Wait for next message. */
|
||||||
public boolean isRunning() {
|
private void waitNextMessage() {
|
||||||
synchronized (lock) {
|
try {
|
||||||
return running;
|
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.Level;
|
||||||
import java.util.logging.Logger;
|
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.
|
* prompt the user.
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @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$
|
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$
|
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$
|
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$
|
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$
|
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$
|
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$
|
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$
|
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
|
private static final Logger LOGGER = Logger
|
||||||
.getLogger(CLIPrompter.class.getName());
|
.getLogger(CLIPrompter.class.getName());
|
||||||
|
|
||||||
/** Utility class */
|
/** Utility class. */
|
||||||
private CLIPrompter() {
|
private CLIPrompter() {
|
||||||
// Utility class
|
// 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 choices the choices
|
||||||
* @param cancel the cancel option if it exists
|
* @param cancel the cancel option if it exists
|
||||||
* @return the number of choices plus one (or the number of choices if there
|
* @return the number of choices plus one (or the number of choices if there
|
||||||
* is a cancel)
|
* is a cancel)
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
private static <U> int listChoices(ConsoleManager manager, List<U> choices,
|
private static <U> Integer listChoices(final ConsoleOutput output,
|
||||||
String cancel) throws IOException {
|
final List<U> choices,
|
||||||
|
final String cancel) throws IOException {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (final U u : choices) {
|
for (final U u : choices) {
|
||||||
manager.println(index++ + ") " + u); //$NON-NLS-1$
|
output.println(index++ + ") " + u); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
if (cancel != null) {
|
if (cancel != null) {
|
||||||
manager.println(index++ + ") " + cancel); //$NON-NLS-1$
|
output.println(index++ + ") " + cancel); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
return index - 1;
|
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
|
* @param message the prompting message
|
||||||
* @return the choice
|
* @return the choice
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
public static boolean promptBoolean(ConsoleManager manager,
|
public static boolean promptBoolean(final ConsoleOutput manager,
|
||||||
String message) throws IOException {
|
final ConsoleInput input,
|
||||||
String result = manager
|
final String message) throws IOException {
|
||||||
|
String result = input
|
||||||
.prompt(message + CLIPrompterMessages.getString(BOOL_CHOICES));
|
.prompt(message + CLIPrompterMessages.getString(BOOL_CHOICES));
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
final String choices = CLIPrompterMessages
|
final String choices = CLIPrompterMessages
|
||||||
@@ -120,7 +150,7 @@ public class CLIPrompter {
|
|||||||
|
|
||||||
manager.println(CLIPrompterMessages
|
manager.println(CLIPrompterMessages
|
||||||
.getString("promptbool.choices.invalid", choices)); //$NON-NLS-1$
|
.getString("promptbool.choices.invalid", choices)); //$NON-NLS-1$
|
||||||
result = manager.prompt(
|
result = input.prompt(
|
||||||
message + CLIPrompterMessages.getString(BOOL_CHOICES));
|
message + CLIPrompterMessages.getString(BOOL_CHOICES));
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
@@ -131,7 +161,10 @@ public class CLIPrompter {
|
|||||||
.getString("promptbool.choices.yes2")); //$NON-NLS-1$
|
.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 keys the keys to be printed
|
||||||
* @param choices the real choices
|
* @param choices the real choices
|
||||||
* @param message the message
|
* @param message the message
|
||||||
@@ -139,18 +172,24 @@ public class CLIPrompter {
|
|||||||
* @param <U> the type of elements
|
* @param <U> the type of elements
|
||||||
* @return the choice
|
* @return the choice
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
@SuppressWarnings("boxing")
|
public static <U> U promptChoice(final ConsoleOutput manager,
|
||||||
public static <U> U promptChoice(ConsoleManager manager, List<String> keys,
|
final ConsoleInput input,
|
||||||
List<U> choices, String message,
|
final List<String> keys,
|
||||||
String cancel) throws IOException {
|
final List<U> choices,
|
||||||
final Integer index = promptChoice(manager, keys, message, cancel);
|
final String message,
|
||||||
|
final String cancel) throws IOException {
|
||||||
|
final Integer index = promptChoice(manager, input, keys, message,
|
||||||
|
cancel);
|
||||||
if (index == null) {
|
if (index == null) {
|
||||||
return 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 <U> The choices labels type
|
||||||
* @param <T> The real choices objects
|
* @param <T> The real choices objects
|
||||||
* @param choices the list of labels (in order to be displayed)
|
* @param choices the list of labels (in order to be displayed)
|
||||||
@@ -159,60 +198,66 @@ public class CLIPrompter {
|
|||||||
* @param cancel the cancel option if it exists (null otherwise)
|
* @param cancel the cancel option if it exists (null otherwise)
|
||||||
* @return the chosen object
|
* @return the chosen object
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
public static <U, T> T promptChoice(ConsoleManager manager, List<U> choices,
|
public static <U, T> T promptChoice(final ConsoleOutput manager,
|
||||||
Map<U, T> choicesMap, String message,
|
final ConsoleInput input,
|
||||||
String cancel) throws IOException {
|
final List<U> choices,
|
||||||
Integer res = promptChoice(manager, choices, message, cancel);
|
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) {
|
if (res == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return choicesMap.get(choices.get(res.intValue()));
|
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 <U> the type of choices
|
||||||
* @param choices the list of choices
|
* @param choices the list of choices
|
||||||
* @param message the prompting message
|
* @param message the prompting message
|
||||||
* @param cancel the cancel option, or null
|
* @param cancel the cancel option, or null
|
||||||
* @return the index of the choice
|
* @return the index of the choice
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
@SuppressWarnings("boxing")
|
public static <U> Integer promptChoice(final ConsoleOutput manager,
|
||||||
public static <U> Integer promptChoice(ConsoleManager manager,
|
final ConsoleInput input,
|
||||||
List<U> choices, String message,
|
final List<U> choices,
|
||||||
String cancel) throws IOException {
|
final String message,
|
||||||
|
final String cancel) throws IOException {
|
||||||
manager.println(message);
|
manager.println(message);
|
||||||
final int index = listChoices(manager, choices, cancel);
|
final Integer index = listChoices(manager, choices, cancel);
|
||||||
String result = ""; //$NON-NLS-1$
|
String result;
|
||||||
boolean keepOn = true;
|
|
||||||
int r = -1;
|
int r = -1;
|
||||||
while (keepOn) {
|
while (true) {
|
||||||
result = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
result = input.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||||
try {
|
try {
|
||||||
r = Integer.parseInt(result);
|
r = Integer.parseInt(result);
|
||||||
if (r >= 0 && r <= index) {
|
if (r >= 0 && r <= index.intValue()) {
|
||||||
keepOn = false;
|
break;
|
||||||
} else {
|
|
||||||
manager.println(CLIPrompterMessages
|
|
||||||
.getString(PROMPTCHOICE_OUTOFBOUNDS, 0, index));
|
|
||||||
listChoices(manager, choices, cancel);
|
|
||||||
}
|
}
|
||||||
|
manager.println(CLIPrompterMessages
|
||||||
|
.getString(PROMPTCHOICE_OUTOFBOUNDS, ZERO, index));
|
||||||
} catch (final NumberFormatException e) {
|
} catch (final NumberFormatException e) {
|
||||||
LOGGER.log(Level.FINER,
|
LOGGER.log(Level.FINER,
|
||||||
"Unrecognized number. Prompting user again.", e); //$NON-NLS-1$
|
"Unrecognized number. Prompting user again.", e); //$NON-NLS-1$
|
||||||
keepOn = true;
|
|
||||||
manager.println(CLIPrompterMessages
|
manager.println(CLIPrompterMessages
|
||||||
.getString(PROMPTCHOICE_FORMATERR, 0, index));
|
.getString(PROMPTCHOICE_FORMATERR, ZERO, index));
|
||||||
listChoices(manager, choices, cancel);
|
|
||||||
}
|
}
|
||||||
|
listChoices(manager, choices, cancel);
|
||||||
}
|
}
|
||||||
if (r == index && cancel != null) {
|
if (r == index.intValue() && cancel != null) {
|
||||||
return 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 <U> The choices labels type
|
||||||
* @param <T> The real choices objects
|
* @param <T> The real choices objects
|
||||||
* @param choicesMap the map of label to actual objects
|
* @param choicesMap the map of label to actual objects
|
||||||
@@ -220,19 +265,24 @@ public class CLIPrompter {
|
|||||||
* @param cancel the cancel option (or null)
|
* @param cancel the cancel option (or null)
|
||||||
* @return the chosen object
|
* @return the chosen object
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
public static <U, T> T promptChoice(ConsoleManager manager,
|
public static <U, T> T promptChoice(final ConsoleOutput manager,
|
||||||
Map<U, T> choicesMap, String message,
|
final ConsoleInput input,
|
||||||
String cancel) throws IOException {
|
final Map<U, T> choicesMap,
|
||||||
return promptChoice(manager, new ArrayList<>(choicesMap.keySet()),
|
final String message,
|
||||||
choicesMap, message, cancel);
|
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
|
* @param message the prompt message
|
||||||
* @return the integer
|
* @return the integer
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
public static int promptInteger(ConsoleManager manager,
|
public static int promptInteger(final ConsoleInput manager,
|
||||||
String message) throws IOException {
|
final String message) throws IOException {
|
||||||
boolean still = true;
|
boolean still = true;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
while (still) {
|
while (still) {
|
||||||
@@ -245,42 +295,46 @@ public class CLIPrompter {
|
|||||||
r = Integer.parseInt(result);
|
r = Integer.parseInt(result);
|
||||||
still = false;
|
still = false;
|
||||||
} catch (final NumberFormatException e) {
|
} catch (final NumberFormatException e) {
|
||||||
LOGGER.log(Level.INFO,
|
LOGGER.info("User input a non parsable integer: " + result); //$NON-NLS-1$
|
||||||
"User input a non parsable integer: " + result, e); //$NON-NLS-1$
|
LOGGER.log(Level.FINEST, "Unrecognized integer", e); //$NON-NLS-1$
|
||||||
still = true;
|
still = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r;
|
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 manager the manager
|
||||||
|
* @param input the input
|
||||||
* @param message the message
|
* @param message the message
|
||||||
* @return the list of user inputs
|
* @return the list of user inputs
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
public static List<String> promptList(ConsoleManager manager,
|
public static List<String> promptList(final ConsoleOutput manager,
|
||||||
String message) throws IOException {
|
final ConsoleInput input,
|
||||||
return promptList(manager, message,
|
final String message) throws IOException {
|
||||||
|
return promptList(manager, input, message,
|
||||||
CLIPrompterMessages.getString("promptlist.exit.defaultkey")); //$NON-NLS-1$
|
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 manager the manager
|
||||||
|
* @param input the input
|
||||||
* @param message the message
|
* @param message the message
|
||||||
* @param ender the ending sequence for the list
|
* @param ender the ending sequence for the list
|
||||||
* @return the list of user inputs
|
* @return the list of user inputs
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
public static List<String> promptList(ConsoleManager manager,
|
public static List<String> promptList(final ConsoleOutput manager,
|
||||||
String message,
|
final ConsoleInput input,
|
||||||
String ender) throws IOException {
|
final String message,
|
||||||
|
final String ender) throws IOException {
|
||||||
final List<String> strings = new ArrayList<>();
|
final List<String> strings = new ArrayList<>();
|
||||||
manager.println(
|
manager.println(
|
||||||
message + CLIPrompterMessages.getString(LIST_DISP_KEY, ender));
|
message + CLIPrompterMessages.getString(LIST_DISP_KEY, ender));
|
||||||
String res = null;
|
String res = null;
|
||||||
while (!ender.equals(res)) {
|
while (!ender.equals(res)) {
|
||||||
res = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
res = input.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||||
if (!res.equals(ender)) {
|
if (!res.equals(ender)) {
|
||||||
strings.add(res);
|
strings.add(res);
|
||||||
}
|
}
|
||||||
@@ -291,49 +345,60 @@ public class CLIPrompter {
|
|||||||
/** Prompt for a text with several lines.
|
/** Prompt for a text with several lines.
|
||||||
*
|
*
|
||||||
* @param manager the manager
|
* @param manager the manager
|
||||||
|
* @param input the input
|
||||||
* @param message the prompting message
|
* @param message the prompting message
|
||||||
* @return the text
|
* @return the text
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
public static String promptLongText(ConsoleManager manager,
|
public static String promptLongText(final ConsoleOutput manager,
|
||||||
String message) throws IOException {
|
final ConsoleInput input,
|
||||||
return promptLongText(manager, message, CLIPrompterMessages
|
final String message) throws IOException {
|
||||||
|
return promptLongText(manager, input, message, CLIPrompterMessages
|
||||||
.getString("promptlongtext.exit.defaultkey")); //$NON-NLS-1$
|
.getString("promptlongtext.exit.defaultkey")); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Prompt for a text with several lines.
|
/** Prompt for a text with several lines.
|
||||||
*
|
*
|
||||||
* @param manager the manager
|
* @param manager the manager
|
||||||
|
* @param input the input
|
||||||
* @param message the prompting message
|
* @param message the prompting message
|
||||||
* @param ender the ender character
|
* @param ender the ender character
|
||||||
* @return the text
|
* @return the text
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
public static String promptLongText(ConsoleManager manager, String message,
|
public static String promptLongText(final ConsoleOutput manager,
|
||||||
String ender) throws IOException {
|
final ConsoleInput input,
|
||||||
|
final String message,
|
||||||
|
final String ender) throws IOException {
|
||||||
manager.println(message + CLIPrompterMessages
|
manager.println(message + CLIPrompterMessages
|
||||||
.getString("promptlongtext.exit.dispkey", ender)); //$NON-NLS-1$
|
.getString("promptlongtext.exit.dispkey", ender)); //$NON-NLS-1$
|
||||||
String res = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
final StringBuilder res = new StringBuilder();
|
||||||
String line = res;
|
String line;
|
||||||
while (!line.equals(ender)) {
|
do {
|
||||||
line = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
line = input.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||||
if (!line.equals(ender)) {
|
if (!line.equals(ender)) {
|
||||||
res += System.lineSeparator() + line;
|
res.append(line);
|
||||||
|
res.append(System.lineSeparator());
|
||||||
}
|
}
|
||||||
}
|
} while (!line.equals(ender));
|
||||||
return res.equals(ender) ? "" : res; //$NON-NLS-1$
|
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 keys the keys to be printed
|
||||||
* @param choices the real choices
|
* @param choices the real choices
|
||||||
* @param message the message
|
* @param message the message
|
||||||
* @param <U> the type of elements
|
* @param <U> the type of elements
|
||||||
* @return the choice
|
* @return the choice
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
public static <U> List<U> promptMultiChoice(ConsoleManager manager,
|
public static <U> List<U> promptMultiChoice(final ConsoleOutput manager,
|
||||||
List<String> keys,
|
final ConsoleInput input,
|
||||||
List<U> choices,
|
final List<String> keys,
|
||||||
String message) throws IOException {
|
final List<U> choices,
|
||||||
final List<Integer> indices = promptMultiChoice(manager, keys, message);
|
final String message) throws IOException {
|
||||||
|
final List<Integer> indices = promptMultiChoice(manager, input, keys,
|
||||||
|
message);
|
||||||
final List<U> userChoices = new ArrayList<>();
|
final List<U> userChoices = new ArrayList<>();
|
||||||
for (final Integer integer : indices) {
|
for (final Integer integer : indices) {
|
||||||
userChoices.add(choices.get(integer.intValue()));
|
userChoices.add(choices.get(integer.intValue()));
|
||||||
@@ -341,7 +406,10 @@ public class CLIPrompter {
|
|||||||
return userChoices;
|
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 <U> The choices labels type
|
||||||
* @param <T> The real choices objects
|
* @param <T> The real choices objects
|
||||||
* @param choices the list of labels (in order to be displayed)
|
* @param choices the list of labels (in order to be displayed)
|
||||||
@@ -349,11 +417,13 @@ public class CLIPrompter {
|
|||||||
* @param message the prompting message
|
* @param message the prompting message
|
||||||
* @return the chosen objects (or an empty list)
|
* @return the chosen objects (or an empty list)
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
public static <U, T> List<T> promptMultiChoice(ConsoleManager manager,
|
public static <U, T> List<T> promptMultiChoice(final ConsoleOutput manager,
|
||||||
List<U> choices,
|
final ConsoleInput input,
|
||||||
Map<U, T> choicesMap,
|
final List<U> choices,
|
||||||
String message) throws IOException {
|
final Map<U, T> choicesMap,
|
||||||
final List<Integer> chs = promptMultiChoice(manager, choices, message);
|
final String message) throws IOException {
|
||||||
|
final List<Integer> chs = promptMultiChoice(manager, input, choices,
|
||||||
|
message);
|
||||||
final List<T> userChoices = new ArrayList<>();
|
final List<T> userChoices = new ArrayList<>();
|
||||||
for (final Integer integer : chs) {
|
for (final Integer integer : chs) {
|
||||||
userChoices.add(choicesMap.get(choices.get(integer.intValue())));
|
userChoices.add(choicesMap.get(choices.get(integer.intValue())));
|
||||||
@@ -361,42 +431,45 @@ public class CLIPrompter {
|
|||||||
return userChoices;
|
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 <U> the type of choices
|
||||||
* @param choices the list of choices
|
* @param choices the list of choices
|
||||||
* @param message the prompting message
|
* @param message the prompting message
|
||||||
* @return the indices of the choices
|
* @return the indices of the choices
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
@SuppressWarnings("boxing")
|
public static <U> List<Integer> promptMultiChoice(final ConsoleOutput manager,
|
||||||
public static <U> List<Integer> promptMultiChoice(ConsoleManager manager,
|
final ConsoleInput input,
|
||||||
List<U> choices,
|
final List<U> choices,
|
||||||
String message) throws IOException {
|
final String message) throws IOException {
|
||||||
manager.println(message);
|
manager.println(message);
|
||||||
final int index = listChoices(manager, choices, null);
|
final Integer index = listChoices(manager, choices, null);
|
||||||
String result = ""; //$NON-NLS-1$
|
String result;
|
||||||
boolean keepOn = true;
|
boolean keepOn = true;
|
||||||
final List<Integer> chs = new ArrayList<>();
|
final List<Integer> chs = new ArrayList<>();
|
||||||
while (keepOn) {
|
while (keepOn) {
|
||||||
keepOn = false;
|
keepOn = false;
|
||||||
result = manager.prompt(CLIPrompterMessages.getString(PROMPT));
|
result = input.prompt(CLIPrompterMessages.getString(PROMPT));
|
||||||
final String[] vals = result
|
final String[] vals = result
|
||||||
.split(CLIPrompterMessages.getString(LIST_CHOICE_SEP));
|
.split(CLIPrompterMessages.getString(LIST_CHOICE_SEP));
|
||||||
for (final String val : vals) {
|
for (final String val : vals) {
|
||||||
boolean added;
|
boolean added;
|
||||||
try {
|
try {
|
||||||
added = addUserChoice(val, chs, index);
|
added = addUserChoice(val, chs, index.intValue());
|
||||||
} catch (final NumberFormatException e) {
|
} catch (final NumberFormatException e) {
|
||||||
LOGGER.log(Level.FINER,
|
LOGGER.log(Level.FINER,
|
||||||
"Unrecognized number. Prompting user again.", e); //$NON-NLS-1$
|
"Unrecognized number. Prompting user again.", e); //$NON-NLS-1$
|
||||||
keepOn = true;
|
keepOn = true;
|
||||||
manager.println(CLIPrompterMessages
|
manager.println(CLIPrompterMessages
|
||||||
.getString(PROMPTCHOICE_FORMATERR, 0, index));
|
.getString(PROMPTCHOICE_FORMATERR, ZERO, index));
|
||||||
listChoices(manager, choices, null);
|
listChoices(manager, choices, null);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!added) {
|
if (!added) {
|
||||||
manager.println(CLIPrompterMessages
|
manager.println(CLIPrompterMessages
|
||||||
.getString(PROMPTCHOICE_OUTOFBOUNDS, 0, index));
|
.getString(PROMPTCHOICE_OUTOFBOUNDS, ZERO, index));
|
||||||
listChoices(manager, choices, null);
|
listChoices(manager, choices, null);
|
||||||
keepOn = true;
|
keepOn = true;
|
||||||
}
|
}
|
||||||
@@ -405,45 +478,34 @@ public class CLIPrompter {
|
|||||||
return chs;
|
return chs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param val the string to parse
|
/** Prompt the user to select zero or more elements from a list.
|
||||||
* @param chs the list of integers
|
*
|
||||||
* @param index the max index of choice
|
* @param manager the manager
|
||||||
* @return if the parsing was done correctly */
|
* @param input the input
|
||||||
private static boolean addUserChoice(String val, List<Integer> chs,
|
|
||||||
int index) {
|
|
||||||
if (val.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
final int r;
|
|
||||||
r = Integer.parseInt(val);
|
|
||||||
if (r >= 0 && r <= index) {
|
|
||||||
chs.add(Integer.valueOf(r));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param manager the manager
|
|
||||||
* @param <U> The choices labels type
|
* @param <U> The choices labels type
|
||||||
* @param <T> The real choices objects
|
* @param <T> The real choices objects
|
||||||
* @param choicesMap the map of label to actual objects
|
* @param choicesMap the map of label to actual objects
|
||||||
* @param message the prompting message
|
* @param message the prompting message
|
||||||
* @return the chosen objects
|
* @return the chosen objects
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
public static <U, T> List<T> promptMultiChoice(ConsoleManager manager,
|
public static <U, T> List<T> promptMultiChoice(final ConsoleOutput manager,
|
||||||
Map<U, T> choicesMap,
|
final ConsoleInput input,
|
||||||
String message) throws IOException {
|
final Map<U, T> choicesMap,
|
||||||
return promptMultiChoice(manager, new ArrayList<>(choicesMap.keySet()),
|
final String message) throws IOException {
|
||||||
choicesMap, message);
|
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 prompt the prompting message
|
||||||
* @param reprompt the prompting message after empty input
|
* @param reprompt the prompting message after empty input
|
||||||
* @return the non empty input
|
* @return the non empty input
|
||||||
* @throws IOException if the manager was closed */
|
* @throws IOException if the manager was closed */
|
||||||
public static String promptNonEmpty(ConsoleManager manager, String prompt,
|
public static String promptNonEmpty(final ConsoleInput manager,
|
||||||
String reprompt) throws IOException {
|
final String prompt,
|
||||||
|
final String reprompt) throws IOException {
|
||||||
String res = manager.prompt(prompt);
|
String res = manager.prompt(prompt);
|
||||||
while (res.isEmpty()) {
|
while (res.isEmpty()) {
|
||||||
res = manager.prompt(reprompt);
|
res = manager.prompt(reprompt);
|
||||||
|
|||||||
@@ -44,37 +44,35 @@ import java.util.ResourceBundle;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
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 */
|
* @author Emmanuel BIGEON */
|
||||||
public class CLIPrompterMessages {
|
public final class CLIPrompterMessages {
|
||||||
/** The resource name */
|
/** The resource name. */
|
||||||
private static final String BUNDLE_NAME = "fr.bigeon.gclc.messages"; //$NON-NLS-1$
|
private static final String BUNDLE_NAME = "fr.bigeon.gclc.messages"; //$NON-NLS-1$
|
||||||
|
/** The resource. */
|
||||||
/** The resource */
|
|
||||||
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
|
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
|
||||||
.getBundle(BUNDLE_NAME);
|
.getBundle(BUNDLE_NAME);
|
||||||
|
/** The logger. */
|
||||||
/** The logger */
|
|
||||||
private static final Logger LOGGER = Logger
|
private static final Logger LOGGER = Logger
|
||||||
.getLogger(CLIPrompterMessages.class.getName());
|
.getLogger(CLIPrompterMessages.class.getName());
|
||||||
|
|
||||||
/** Utility class */
|
/** Utility class. */
|
||||||
private CLIPrompterMessages() {
|
private CLIPrompterMessages() {
|
||||||
// Utility constructor
|
// 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 key the message's key
|
||||||
* @param args the arguments
|
* @param args the arguments
|
||||||
* @return the formatted message */
|
* @return the formatted message */
|
||||||
public static String getString(String key, Object... args) {
|
public static String getString(final String key, final Object... args) {
|
||||||
try {
|
try {
|
||||||
return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);
|
return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);
|
||||||
} catch (final MissingResourceException e) {
|
} 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 + '!';
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
50
gclc/src/main/java/fr/bigeon/gclc/tools/ConstantString.java
Normal file
50
gclc/src/main/java/fr/bigeon/gclc/tools/ConstantString.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package fr.bigeon.gclc.tools;
|
||||||
|
|
||||||
|
public class ConstantString implements StringProvider {
|
||||||
|
private String string;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String apply() {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ConstantString(String string) {
|
||||||
|
this.string = string;
|
||||||
|
}
|
||||||
@@ -44,56 +44,61 @@ import java.util.List;
|
|||||||
/** A tool class for printing text in a console.
|
/** A tool class for printing text in a console.
|
||||||
*
|
*
|
||||||
* @author Emmanuel BIGEON */
|
* @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$
|
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();
|
private static final int CONT_DOT_LENGTH = CONT_DOT.length();
|
||||||
/** The empty string constant */
|
/** The empty string constant. */
|
||||||
private static final String EMPTY = ""; //$NON-NLS-1$
|
private static final String EMPTY = ""; //$NON-NLS-1$
|
||||||
|
|
||||||
/** Utility class */
|
/** Utility class. */
|
||||||
private PrintUtils() {
|
private PrintUtils() {
|
||||||
// Utility class
|
// 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 nbCharacters the number of characters of the resulting text
|
||||||
* @param indicateTooLong if an indication shell be given that the text
|
* @param indicateTooLong if an indication shell be given that the text
|
||||||
* didn't fit
|
* didn't fit
|
||||||
* @return the text to print (will be of exactly nbCharacters). */
|
* @return the text to print (will be of exactly nbCharacters). */
|
||||||
public static String print(String text, int nbCharacters,
|
public static String print(final String text, final int nbCharacters,
|
||||||
boolean indicateTooLong) {
|
final boolean indicateTooLong) {
|
||||||
String res = text;
|
StringBuilder res = new StringBuilder(text);
|
||||||
if (res.length() > nbCharacters) {
|
if (res.length() > nbCharacters) {
|
||||||
// Cut
|
// Cut
|
||||||
if (indicateTooLong) {
|
if (indicateTooLong) {
|
||||||
// With suspension dots
|
// With suspension dots
|
||||||
res = res.substring(0, nbCharacters - CONT_DOT_LENGTH) +
|
res = res.replace(nbCharacters - CONT_DOT_LENGTH, text.length(),
|
||||||
CONT_DOT;
|
CONT_DOT);
|
||||||
} else {
|
} else {
|
||||||
res = res.substring(0, nbCharacters);
|
res = res.replace(nbCharacters, text.length(), ""); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (res.length() < nbCharacters) {
|
while (res.length() < nbCharacters) {
|
||||||
// Add trailing space
|
// 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
|
* @param i the length of the wrap
|
||||||
* @return the list of resulting strings */
|
* @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
|
final String[] originalLines = description
|
||||||
.split(System.lineSeparator());
|
.split(System.lineSeparator());
|
||||||
final List<String> result = new ArrayList<>();
|
final List<String> result = new ArrayList<>();
|
||||||
for (final String string : originalLines) {
|
for (final String string : originalLines) {
|
||||||
String toCut = string;
|
String toCut = string;
|
||||||
while (toCut.length() > i) {
|
while (toCut.length() > i) {
|
||||||
int index = toCut.lastIndexOf(" ", i); //$NON-NLS-1$
|
int index = toCut.lastIndexOf(' ', i);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
result.add(toCut.substring(0, i));
|
result.add(toCut.substring(0, i));
|
||||||
index = i - 1;
|
index = i - 1;
|
||||||
|
|||||||
49
gclc/src/main/java/fr/bigeon/gclc/tools/StringProvider.java
Normal file
49
gclc/src/main/java/fr/bigeon/gclc/tools/StringProvider.java
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package fr.bigeon.gclc.tools;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string providing object.
|
||||||
|
* <p>
|
||||||
|
* Implementations of this interface will provide a string, this internal state
|
||||||
|
* of the object may be so that successive calls to the apply method return
|
||||||
|
* different results.
|
||||||
|
*
|
||||||
|
* @author Emmanuel
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface StringProvider {
|
||||||
|
String apply();
|
||||||
|
}
|
||||||
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;
|
||||||
@@ -16,7 +16,8 @@ promptbool.choices.no1=N
|
|||||||
promptbool.choices.no2=no
|
promptbool.choices.no2=no
|
||||||
|
|
||||||
promptchoice.outofbounds=Please choose something between {0} and {1}. The choices were:
|
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.defaultkey=\\q
|
||||||
promptlongtext.exit.dispkey=\ (exit with a new line made of "{0}")
|
promptlongtext.exit.dispkey=\ (exit with a new line made of "{0}")
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ import java.io.IOException;
|
|||||||
|
|
||||||
import fr.bigeon.gclc.command.ICommand;
|
import fr.bigeon.gclc.command.ICommand;
|
||||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||||
import fr.bigeon.gclc.manager.PipedConsoleManager;
|
import fr.bigeon.gclc.manager.PipedConsoleInput;
|
||||||
|
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@@ -54,14 +55,17 @@ import fr.bigeon.gclc.manager.PipedConsoleManager;
|
|||||||
@SuppressWarnings("javadoc")
|
@SuppressWarnings("javadoc")
|
||||||
public class CommandTestingApplication implements AutoCloseable {
|
public class CommandTestingApplication implements AutoCloseable {
|
||||||
|
|
||||||
private final ConsoleTestApplication application;
|
private final ConsoleApplication application;
|
||||||
private final Thread th;
|
private final Thread th;
|
||||||
private final PipedConsoleManager manager;
|
private final PipedConsoleOutput out;
|
||||||
|
private final PipedConsoleInput in;
|
||||||
|
|
||||||
/** @throws IOException if the streams cannot be build */
|
/** @throws IOException if the streams cannot be build */
|
||||||
public CommandTestingApplication() throws IOException {
|
public CommandTestingApplication() throws IOException {
|
||||||
manager = new PipedConsoleManager();
|
out = new PipedConsoleOutput();
|
||||||
application = new ConsoleTestApplication(manager);
|
in = new PipedConsoleInput(null);
|
||||||
|
application = new ConsoleApplication(out, in, "", "");
|
||||||
|
new ConsoleTestApplication().attach(application);
|
||||||
th = new Thread(new Runnable() {
|
th = new Thread(new Runnable() {
|
||||||
|
|
||||||
@SuppressWarnings("synthetic-access")
|
@SuppressWarnings("synthetic-access")
|
||||||
@@ -74,49 +78,46 @@ public class CommandTestingApplication implements AutoCloseable {
|
|||||||
th.start();
|
th.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
application.exit();
|
|
||||||
manager.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendCommand(String cmd) throws IOException {
|
|
||||||
manager.type(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param cmd the command
|
/** @param cmd the command
|
||||||
* @return if the command was added
|
* @return if the command was added
|
||||||
* @throws InvalidCommandName if the command name is invalid
|
* @throws InvalidCommandName if the command name is invalid
|
||||||
* @see fr.bigeon.gclc.ConsoleApplication#add(fr.bigeon.gclc.command.ICommand) */
|
* @see fr.bigeon.gclc.ConsoleApplication#add(fr.bigeon.gclc.command.ICommand) */
|
||||||
public final boolean add(ICommand cmd) throws InvalidCommandName {
|
public final boolean add(final ICommand cmd) throws InvalidCommandName {
|
||||||
return application.add(cmd);
|
return application.add(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
application.exit();
|
||||||
|
out.close();
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
|
||||||
/** @return the application */
|
/** @return the application */
|
||||||
public ConsoleTestApplication getApplication() {
|
public ConsoleApplication getApplication() {
|
||||||
return application;
|
return application;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return the next written line, null if it is the prompt
|
||||||
|
* @throws IOException if the reading failed */
|
||||||
|
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 */
|
/** @throws IOException if the writing failed */
|
||||||
public void waitAndStop() throws IOException {
|
public void waitAndStop() throws IOException {
|
||||||
manager.type(ConsoleTestApplication.EXIT);
|
in.type(ConsoleTestApplication.EXIT);
|
||||||
try {
|
try {
|
||||||
th.join();
|
th.join();
|
||||||
} catch (InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @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 {
|
|
||||||
String ret = manager.readNextLine();
|
|
||||||
if (ret.equals(manager.getPrompt())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,10 +41,16 @@ package fr.bigeon.gclc;
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
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 org.junit.Test;
|
||||||
|
|
||||||
@@ -54,9 +60,10 @@ import fr.bigeon.gclc.exception.CommandRunException;
|
|||||||
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
import fr.bigeon.gclc.exception.CommandRunExceptionType;
|
||||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||||
import fr.bigeon.gclc.i18n.Messages;
|
import fr.bigeon.gclc.i18n.Messages;
|
||||||
import fr.bigeon.gclc.manager.ConsoleManager;
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
import fr.bigeon.gclc.manager.SystemConsoleManager;
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
import fr.bigeon.gclc.manager.PipedConsoleManager;
|
import fr.bigeon.gclc.manager.PipedConsoleInput;
|
||||||
|
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||||
|
|
||||||
/** Test class for ConsoleApplication
|
/** Test class for ConsoleApplication
|
||||||
*
|
*
|
||||||
@@ -69,80 +76,99 @@ public class ConsoleApplicationTest {
|
|||||||
|
|
||||||
/** Test the base of a console application */
|
/** Test the base of a console application */
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void testConsoleApplication() {
|
||||||
ConsoleTestApplication app = new ConsoleTestApplication(
|
|
||||||
new SystemConsoleManager());
|
try (PipedOutputStream pout = new PipedOutputStream();
|
||||||
app.exit();
|
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
|
@Test
|
||||||
public void executionTest() {
|
public void testExecution() throws IOException, InterruptedException,
|
||||||
|
InvalidCommandName {
|
||||||
try (CommandTestingApplication application = new CommandTestingApplication()) {
|
try (CommandTestingApplication application = new CommandTestingApplication()) {
|
||||||
|
|
||||||
// remove welcome
|
// remove welcome
|
||||||
assertEquals(application.getApplication().getHeader(),
|
assertEquals("Header should be preserved",
|
||||||
|
application.getApplication().header,
|
||||||
application.readNextLine());
|
application.readNextLine());
|
||||||
// Remove first prompt
|
// Remove first prompt
|
||||||
assertNull(application.readNextLine());
|
|
||||||
application.sendCommand("");
|
application.sendCommand("");
|
||||||
assertNull(application.readNextLine());
|
|
||||||
application.sendCommand("test");
|
application.sendCommand("test");
|
||||||
assertEquals("Test command ran fine", application.readNextLine());
|
assertEquals("Test should run", "Test command ran fine",
|
||||||
assertNull(application.readNextLine());
|
application.readNextLine());
|
||||||
application.sendCommand("toto");
|
application.sendCommand("toto");
|
||||||
assertEquals(
|
assertEquals("Command fail should dispaly appropriate message",
|
||||||
Messages.getString("ConsoleApplication.cmd.failed", "toto"),
|
Messages.getString("ConsoleApplication.cmd.failed", "toto"),
|
||||||
application.readNextLine());
|
application.readNextLine());
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
"Unrecognized comment should result in a specific message.",
|
||||||
Messages.getString("CommandProvider.unrecognized", "toto"),
|
Messages.getString("CommandProvider.unrecognized", "toto"),
|
||||||
application.readNextLine());
|
application.readNextLine());
|
||||||
assertNull(application.readNextLine());
|
|
||||||
application.sendCommand("long");
|
application.sendCommand("long");
|
||||||
assertEquals("Waita minute", application.readNextLine());
|
assertEquals("Before wait should receive message", "Waita minute",
|
||||||
assertEquals("done!", application.readNextLine());
|
application.readNextLine());
|
||||||
|
assertEquals("Unexpected message", "done!",
|
||||||
|
application.readNextLine());
|
||||||
|
|
||||||
CommandRequestListener crl = new CommandRequestListener() {
|
final CommandRequestListener crl = new CommandRequestListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void commandRequest(String command) {
|
public void commandRequest(final String command) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
CommandRequestListener crl2 = new CommandRequestListener() {
|
final CommandRequestListener crl2 = new CommandRequestListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void commandRequest(String command) {
|
public void commandRequest(final String command) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
application.getApplication().addListener(crl);
|
application.getApplication().addListener(crl);
|
||||||
application.getApplication().addListener(crl2);
|
application.getApplication().addListener(crl2);
|
||||||
assertNull(application.readNextLine());
|
|
||||||
application.sendCommand("test");
|
application.sendCommand("test");
|
||||||
assertEquals("Test command ran fine", application.readNextLine());
|
assertEquals("Unexpected message", "Test command ran fine",
|
||||||
|
application.readNextLine());
|
||||||
application.getApplication().removeListener(crl2);
|
application.getApplication().removeListener(crl2);
|
||||||
application.getApplication().removeListener(crl);
|
application.getApplication().removeListener(crl);
|
||||||
application.getApplication().removeListener(crl);
|
application.getApplication().removeListener(crl);
|
||||||
|
|
||||||
assertTrue(application.getApplication().isRunning());
|
assertTrue("Unclosed application should be running",
|
||||||
|
application.getApplication().isRunning());
|
||||||
|
|
||||||
assertNull(application.readNextLine());
|
|
||||||
application.sendCommand("exit");
|
application.sendCommand("exit");
|
||||||
assertEquals(application.getApplication().getFooter(),
|
assertEquals("Footer should be preserved",
|
||||||
|
application.getApplication().footer,
|
||||||
application.readNextLine());
|
application.readNextLine());
|
||||||
assertFalse(application.getApplication().isRunning());
|
assertFalse("Stopped application should not be running",
|
||||||
} catch (IOException e1) {
|
application.getApplication().isRunning());
|
||||||
assertNull(e1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleApplication appli = null;
|
ConsoleApplication appli = null;
|
||||||
try (PipedConsoleManager manager = new PipedConsoleManager()) {
|
try (PipedConsoleOutput manager = new PipedConsoleOutput();
|
||||||
final ConsoleApplication app = new ConsoleApplication(manager, null,
|
PipedOutputStream pout = new PipedOutputStream();
|
||||||
null);
|
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;
|
appli = app;
|
||||||
app.add(new ExitCommand("exit", app));
|
app.add(new ExitCommand("exit", app));
|
||||||
|
|
||||||
Thread th = new Thread(new Runnable() {
|
final Thread th = new Thread(new Runnable() {
|
||||||
|
|
||||||
@SuppressWarnings("synthetic-access")
|
@SuppressWarnings("synthetic-access")
|
||||||
@Override
|
@Override
|
||||||
@@ -150,70 +176,72 @@ public class ConsoleApplicationTest {
|
|||||||
app.start();
|
app.start();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
th.start();
|
th.start();
|
||||||
|
in.type("exit");
|
||||||
manager.type("exit");
|
|
||||||
th.join();
|
th.join();
|
||||||
|
|
||||||
} catch (IOException | InvalidCommandName | InterruptedException e) {
|
|
||||||
assertNull(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assertNotNull(appli);
|
assertNotNull(
|
||||||
|
"Application should still exist even if the console input and output are closed.",
|
||||||
|
appli);
|
||||||
appli.start();
|
appli.start();
|
||||||
assertFalse(appli.isRunning());
|
assertFalse(
|
||||||
|
"Application should not start on closed console input and output",
|
||||||
|
appli.isRunning());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void interpretCommandTest() {
|
public void testInterpretCommand() throws InvalidCommandName, IOException {
|
||||||
try (PipedConsoleManager test = new PipedConsoleManager()) {
|
try (PipedConsoleInput test = new PipedConsoleInput(null);
|
||||||
ConsoleApplication appl = new ConsoleApplication(test, "", "");
|
PipedConsoleOutput out = new PipedConsoleOutput()) {
|
||||||
|
final ConsoleApplication appl = new ConsoleApplication(out, test,
|
||||||
|
"", "");
|
||||||
|
|
||||||
appl.interpretCommand("invalid cmd \"due to misplaced\"quote");
|
appl.interpretCommand("invalid cmd \"due to misplaced\"quote");
|
||||||
assertEquals("Command line cannot be parsed", test.readNextLine());
|
assertEquals("Specific error message expected",
|
||||||
|
"Command line cannot be parsed", out.readNextLine());
|
||||||
|
|
||||||
appl.interpretCommand("");
|
appl.interpretCommand("");
|
||||||
|
|
||||||
final String message = "message";
|
final String message = "message";
|
||||||
try {
|
appl.add(new ICommand() {
|
||||||
appl.add(new ICommand() {
|
|
||||||
|
|
||||||
@Override
|
/* (non-Javadoc)
|
||||||
public void execute(String... args) throws CommandRunException {
|
* @see fr.bigeon.gclc.command.ICommand#execute(fr.bigeon.gclc.
|
||||||
throw new CommandRunException(
|
* manager.ConsoleOutput, fr.bigeon.gclc.manager.ConsoleInput,
|
||||||
CommandRunExceptionType.USAGE, message, this);
|
* 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
|
@Override
|
||||||
public String getCommandName() {
|
public String getCommandName() {
|
||||||
return "fail";
|
return "fail";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void help(ConsoleManager manager,
|
public void help(final ConsoleOutput manager,
|
||||||
String... args) throws IOException {
|
final String... args) throws IOException {
|
||||||
manager.println(message);
|
manager.println(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
} catch (InvalidCommandName e) {
|
|
||||||
assertNull(e);
|
|
||||||
}
|
|
||||||
appl.interpretCommand("fail");
|
appl.interpretCommand("fail");
|
||||||
assertEquals(
|
assertEquals("Unexpected message",
|
||||||
Messages.getString("ConsoleApplication.cmd.failed", "fail"),
|
Messages.getString("ConsoleApplication.cmd.failed", "fail"),
|
||||||
test.readNextLine());
|
out.readNextLine());
|
||||||
assertEquals(message, test.readNextLine());
|
assertEquals("Unexpected message", message, out.readNextLine());
|
||||||
assertEquals(message, test.readNextLine());
|
assertEquals("Unexpected message", message, out.readNextLine());
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
assertNull(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,29 +39,47 @@ import java.io.IOException;
|
|||||||
import fr.bigeon.gclc.command.Command;
|
import fr.bigeon.gclc.command.Command;
|
||||||
import fr.bigeon.gclc.command.ExitCommand;
|
import fr.bigeon.gclc.command.ExitCommand;
|
||||||
import fr.bigeon.gclc.command.HelpExecutor;
|
import fr.bigeon.gclc.command.HelpExecutor;
|
||||||
|
import fr.bigeon.gclc.command.ICommandProvider;
|
||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
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
|
/** A test-purpose application
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class ConsoleTestApplication extends ConsoleApplication {
|
public class ConsoleTestApplication implements ApplicationAttachement {
|
||||||
|
|
||||||
/** Exit command */
|
/** Exit command */
|
||||||
public static final String EXIT = "exit"; //$NON-NLS-1$
|
public static final String EXIT = "exit"; //$NON-NLS-1$
|
||||||
/** Two seconds in milliseconds */
|
/** Two seconds in milliseconds */
|
||||||
protected static final long TWO_SECONDS = 2000;
|
protected static final long TWO_SECONDS = 2000;
|
||||||
|
|
||||||
/** @param manager the manager */
|
/***/
|
||||||
|
@Override
|
||||||
@SuppressWarnings("nls")
|
@SuppressWarnings("nls")
|
||||||
public ConsoleTestApplication(final ConsoleManager manager) {
|
public void attach(final ICommandProvider application) {
|
||||||
super(manager, "Welcome to the test application. Type help or test.",
|
|
||||||
"See you");
|
|
||||||
try {
|
try {
|
||||||
add(new ExitCommand(EXIT, this));
|
application.add(new ExitCommand(EXIT, (ConsoleApplication) application));
|
||||||
add(new HelpExecutor("help", manager, this.getRoot()));
|
application.add(new HelpExecutor("help",
|
||||||
add(new Command("test") {
|
((ConsoleApplication) 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
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
@@ -69,38 +87,31 @@ public class ConsoleTestApplication extends ConsoleApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(String... args) throws CommandRunException {
|
protected String usageDetail() {
|
||||||
try {
|
return null;
|
||||||
manager.println("Test command ran fine");
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new CommandRunException("manager closed", e,
|
|
||||||
this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
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
|
@Override
|
||||||
public String tip() {
|
public void execute(final ConsoleOutput out,
|
||||||
return "A long execution command";
|
final ConsoleInput in,
|
||||||
}
|
final String... args) throws CommandRunException {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(String... args) throws CommandRunException {
|
|
||||||
try {
|
try {
|
||||||
manager.println("Waita minute");
|
out.println("Waita minute");
|
||||||
Thread.sleep(TWO_SECONDS);
|
Thread.sleep(TWO_SECONDS);
|
||||||
manager.println("done!");
|
out.println("done!");
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
throw new CommandRunException("manager closed", e,
|
throw new CommandRunException("manager closed", e,
|
||||||
this);
|
this);
|
||||||
} catch (InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
throw new CommandRunException("wait interrupted", e,
|
throw new CommandRunException("wait interrupted", e,
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
add(new Command("failingCmd") {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
@@ -108,9 +119,31 @@ public class ConsoleTestApplication extends ConsoleApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(String... args) throws CommandRunException {
|
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);
|
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) {
|
} catch (final InvalidCommandName e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
*/
|
*/
|
||||||
package fr.bigeon.gclc;
|
package fr.bigeon.gclc;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
@@ -53,103 +54,74 @@ import fr.bigeon.gclc.exception.CommandParsingException;
|
|||||||
@SuppressWarnings({"nls", "static-method"})
|
@SuppressWarnings({"nls", "static-method"})
|
||||||
public class GCLCConstantsTest {
|
public class GCLCConstantsTest {
|
||||||
|
|
||||||
/**
|
/** Test method for
|
||||||
* Test method for {@link fr.bigeon.gclc.GCLCConstants#splitCommand(java.lang.String)}.
|
* {@link fr.bigeon.gclc.GCLCConstants#splitCommand(java.lang.String)}.
|
||||||
*/
|
*
|
||||||
|
* @throws CommandParsingException if an error occured */
|
||||||
@Test
|
@Test
|
||||||
public void testSplitCommand() {
|
public void testSplitCommand() throws CommandParsingException {
|
||||||
List<String> res;
|
List<String> res;
|
||||||
try {
|
res = GCLCConstants.splitCommand("aCommand");
|
||||||
res = GCLCConstants.splitCommand("aCommand");
|
assertTrue("single word command should have one element",
|
||||||
} catch (CommandParsingException e) {
|
res.size() == 1);
|
||||||
fail("Unable to parse simple command " + e.getLocalizedMessage()); //$NON-NLS-1$
|
assertTrue("Command should be preserved",
|
||||||
return;
|
res.get(0).equals("aCommand"));
|
||||||
}
|
|
||||||
assertTrue(res.size() == 1);
|
res = GCLCConstants.splitCommand("aCommand with some arguments");
|
||||||
assertTrue(res.get(0).equals("aCommand"));
|
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 {
|
try {
|
||||||
res = GCLCConstants.splitCommand("aCommand with some arguments");
|
// Wrong lines?
|
||||||
} catch (CommandParsingException e) {
|
|
||||||
fail("Unable to parse command with arguments " + //$NON-NLS-1$
|
|
||||||
e.getLocalizedMessage());
|
|
||||||
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$
|
|
||||||
e.getLocalizedMessage());
|
|
||||||
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$
|
|
||||||
e.getLocalizedMessage());
|
|
||||||
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$
|
|
||||||
e.getLocalizedMessage());
|
|
||||||
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$
|
|
||||||
e.getLocalizedMessage());
|
|
||||||
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"));
|
|
||||||
|
|
||||||
try {
|
|
||||||
res = GCLCConstants
|
|
||||||
.splitCommand("aCommand with \"some arguments\"");
|
|
||||||
} catch (CommandParsingException e) {
|
|
||||||
fail("Unable to parse command ending with string argument " + //$NON-NLS-1$
|
|
||||||
e.getLocalizedMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
assertTrue(res.size() == 3);
|
|
||||||
assertTrue(res.get(0).equals("aCommand"));
|
|
||||||
assertTrue(res.get(1).equals("with"));
|
|
||||||
assertTrue(res.get(2).equals("some arguments"));
|
|
||||||
|
|
||||||
// Wrong lines?
|
|
||||||
try {
|
|
||||||
res = GCLCConstants
|
res = GCLCConstants
|
||||||
.splitCommand("aCommand with \"some ar\"guments");
|
.splitCommand("aCommand with \"some ar\"guments");
|
||||||
fail("Parsing argument with string cut");
|
fail("Misplaced quotes should fail");
|
||||||
} catch (CommandParsingException e) {
|
} catch (final CommandParsingException e) {
|
||||||
// OK
|
// ok
|
||||||
assertTrue(e.getLocalizedMessage(), true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,55 +42,69 @@ import static org.junit.Assert.assertEquals;
|
|||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import fr.bigeon.gclc.exception.CommandParsingException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* TODO
|
* TODO
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon
|
* @author Emmanuel Bigeon */
|
||||||
*
|
@SuppressWarnings({"static-method", "nls"})
|
||||||
*/
|
|
||||||
public class CommandParametersTest {
|
public class CommandParametersTest {
|
||||||
|
|
||||||
/**
|
/** Test method for
|
||||||
* Test method for {@link fr.bigeon.gclc.command.CommandParameters#CommandParameters(java.util.Set, java.util.Set, boolean)}.
|
* {@link fr.bigeon.gclc.command.CommandParameters#CommandParameters(java.util.Set, java.util.Set, boolean)}.
|
||||||
*/
|
*
|
||||||
|
* @throws CommandParsingException if an unexpected exception is thrown */
|
||||||
@Test
|
@Test
|
||||||
public final void testCommandParameters(){
|
public final void testCommandParameters() throws CommandParsingException {
|
||||||
Set<String> strings = new HashSet<>();
|
final Set<String> strings = new HashSet<>();
|
||||||
Set<String> bools = new HashSet<>();
|
final Set<String> bools = new HashSet<>();
|
||||||
CommandParameters parameters = new CommandParameters(bools, strings,
|
CommandParameters parameters = new CommandParameters(bools, strings,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
assertFalse(parameters.parseArgs("-ungivenFlag"));
|
try {
|
||||||
|
parameters.parseArgs("-ungivenFlag");
|
||||||
|
fail("parse of unknown in strict should fail");
|
||||||
|
} catch (final CommandParsingException e) {
|
||||||
|
// ok
|
||||||
|
}
|
||||||
parameters = new CommandParameters(bools, strings, false);
|
parameters = new CommandParameters(bools, strings, false);
|
||||||
|
|
||||||
assertTrue(parameters.parseArgs("-ungivenFlag"));
|
parameters.parseArgs("-ungivenFlag");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Test method for
|
||||||
* Test method for {@link fr.bigeon.gclc.command.CommandParameters#get(java.lang.String)}.
|
* {@link fr.bigeon.gclc.command.CommandParameters#get(java.lang.String)}.
|
||||||
*/
|
*
|
||||||
|
* @throws CommandParsingException if an exception occired */
|
||||||
@Test
|
@Test
|
||||||
public final void testGet(){
|
public final void testGet() throws CommandParsingException {
|
||||||
Set<String> strings = new HashSet<>();
|
final Set<String> strings = new HashSet<>();
|
||||||
Set<String> bools = new HashSet<>();
|
final Set<String> bools = new HashSet<>();
|
||||||
|
|
||||||
bools.add("boolFlag");
|
bools.add("boolFlag");
|
||||||
strings.add("str");
|
strings.add("str");
|
||||||
|
|
||||||
CommandParameters parameters = new CommandParameters(bools, strings,
|
final CommandParameters parameters = new CommandParameters(bools,
|
||||||
true);
|
strings, true);
|
||||||
|
|
||||||
assertNull(parameters.get("ungiven"));
|
assertNull(parameters.get("ungiven"));
|
||||||
assertNull(parameters.get("str"));
|
assertNull(parameters.get("str"));
|
||||||
|
|
||||||
parameters.parseArgs("-ungiven", "val");
|
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("ungiven"));
|
||||||
assertNull(parameters.get("str"));
|
assertNull(parameters.get("str"));
|
||||||
|
|
||||||
@@ -98,18 +112,22 @@ public class CommandParametersTest {
|
|||||||
assertNull(parameters.get("ungiven"));
|
assertNull(parameters.get("ungiven"));
|
||||||
assertEquals("val", parameters.get("str"));
|
assertEquals("val", parameters.get("str"));
|
||||||
|
|
||||||
parameters.parseArgs("-ungiven");
|
try {
|
||||||
|
parameters.parseArgs("-ungiven");
|
||||||
|
fail("Invalid argument type parsing should fail");
|
||||||
|
} catch (final CommandParsingException e) {
|
||||||
|
// ok
|
||||||
|
}
|
||||||
assertNull(parameters.get("ungiven"));
|
assertNull(parameters.get("ungiven"));
|
||||||
assertEquals("val", parameters.get("str"));
|
assertEquals("val", parameters.get("str"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Test method for
|
||||||
* Test method for {@link fr.bigeon.gclc.command.CommandParameters#getAdditionals()}.
|
* {@link fr.bigeon.gclc.command.CommandParameters#getAdditionals()}. */
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
public final void testGetAdditionals(){
|
public final void testGetAdditionals() throws CommandParsingException {
|
||||||
Set<String> strings = new HashSet<>();
|
final Set<String> strings = new HashSet<>();
|
||||||
Set<String> bools = new HashSet<>();
|
final Set<String> bools = new HashSet<>();
|
||||||
|
|
||||||
bools.add("boolFlag");
|
bools.add("boolFlag");
|
||||||
strings.add("str");
|
strings.add("str");
|
||||||
@@ -120,7 +138,12 @@ public class CommandParametersTest {
|
|||||||
parameters.parseArgs("-boolFlag");
|
parameters.parseArgs("-boolFlag");
|
||||||
assertTrue(parameters.getAdditionals().isEmpty());
|
assertTrue(parameters.getAdditionals().isEmpty());
|
||||||
|
|
||||||
parameters.parseArgs("-ungiven");
|
try {
|
||||||
|
parameters.parseArgs("-ungiven");
|
||||||
|
fail("Should fail");
|
||||||
|
} catch (final CommandParsingException e) {
|
||||||
|
// ok
|
||||||
|
}
|
||||||
assertTrue(parameters.getAdditionals().isEmpty());
|
assertTrue(parameters.getAdditionals().isEmpty());
|
||||||
|
|
||||||
parameters = new CommandParameters(bools, strings, false);
|
parameters = new CommandParameters(bools, strings, false);
|
||||||
@@ -128,18 +151,19 @@ public class CommandParametersTest {
|
|||||||
parameters.parseArgs("-boolFlag");
|
parameters.parseArgs("-boolFlag");
|
||||||
assertTrue(parameters.getAdditionals().isEmpty());
|
assertTrue(parameters.getAdditionals().isEmpty());
|
||||||
|
|
||||||
parameters.parseArgs("-ungiven");
|
parameters.parseArgs("ungiven");
|
||||||
assertTrue(parameters.getAdditionals().contains("ungiven"));
|
assertTrue(parameters.getAdditionals().contains("ungiven"));
|
||||||
assertEquals(1, parameters.getAdditionals().size());
|
assertEquals(1, parameters.getAdditionals().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Test method for
|
||||||
* Test method for {@link fr.bigeon.gclc.command.CommandParameters#getBool(java.lang.String)}.
|
* {@link fr.bigeon.gclc.command.CommandParameters#getBool(java.lang.String)}.
|
||||||
*/
|
*
|
||||||
|
* @throws CommandParsingException if a command parsing failed */
|
||||||
@Test
|
@Test
|
||||||
public final void testGetBool(){
|
public final void testGetBool() throws CommandParsingException {
|
||||||
Set<String> strings = new HashSet<>();
|
final Set<String> strings = new HashSet<>();
|
||||||
Set<String> bools = new HashSet<>();
|
final Set<String> bools = new HashSet<>();
|
||||||
|
|
||||||
bools.add("boolFlag");
|
bools.add("boolFlag");
|
||||||
strings.add("str");
|
strings.add("str");
|
||||||
@@ -154,7 +178,12 @@ public class CommandParametersTest {
|
|||||||
assertTrue(parameters.getBool("boolFlag"));
|
assertTrue(parameters.getBool("boolFlag"));
|
||||||
assertFalse(parameters.getBool("ungiven"));
|
assertFalse(parameters.getBool("ungiven"));
|
||||||
|
|
||||||
parameters.parseArgs("-ungiven");
|
try {
|
||||||
|
parameters.parseArgs("-ungiven");
|
||||||
|
fail("unknown parameter should fail");
|
||||||
|
} catch (final CommandParsingException e) {
|
||||||
|
// ok
|
||||||
|
}
|
||||||
assertFalse(parameters.getBool("ungiven"));
|
assertFalse(parameters.getBool("ungiven"));
|
||||||
assertTrue(parameters.getBool("boolFlag"));
|
assertTrue(parameters.getBool("boolFlag"));
|
||||||
|
|
||||||
@@ -163,44 +192,61 @@ public class CommandParametersTest {
|
|||||||
assertFalse(parameters.getBool("ungiven"));
|
assertFalse(parameters.getBool("ungiven"));
|
||||||
assertFalse(parameters.getBool("boolFlag"));
|
assertFalse(parameters.getBool("boolFlag"));
|
||||||
|
|
||||||
parameters.parseArgs("-boolFlag");
|
try {
|
||||||
|
parameters.parseArgs("-boolFlag");
|
||||||
|
} catch (final CommandParsingException e) {
|
||||||
|
// ok
|
||||||
|
}
|
||||||
assertTrue(parameters.getBool("boolFlag"));
|
assertTrue(parameters.getBool("boolFlag"));
|
||||||
assertFalse(parameters.getBool("ungiven"));
|
assertFalse(parameters.getBool("ungiven"));
|
||||||
|
|
||||||
parameters.parseArgs("-ungiven");
|
try {
|
||||||
|
parameters.parseArgs("-ungiven");
|
||||||
|
} catch (final CommandParsingException e) {
|
||||||
|
// ok
|
||||||
|
}
|
||||||
assertFalse(parameters.getBool("ungiven"));
|
assertFalse(parameters.getBool("ungiven"));
|
||||||
assertTrue(parameters.getBool("boolFlag"));
|
assertTrue(parameters.getBool("boolFlag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Test method for
|
||||||
* Test method for {@link fr.bigeon.gclc.command.CommandParameters#parseArgs(java.lang.String[])}.
|
* {@link fr.bigeon.gclc.command.CommandParameters#parseArgs(java.lang.String[])}.
|
||||||
*/
|
*
|
||||||
|
* @throws CommandParsingException if a command parsing failed */
|
||||||
@Test
|
@Test
|
||||||
public final void testParseArgs(){
|
public final void testParseArgs() throws CommandParsingException {
|
||||||
Set<String> strings = new HashSet<>();
|
final Set<String> strings = new HashSet<>();
|
||||||
Set<String> bools = new HashSet<>();
|
final Set<String> bools = new HashSet<>();
|
||||||
|
|
||||||
bools.add("boolFlag");
|
bools.add("boolFlag");
|
||||||
strings.add("str");
|
strings.add("str");
|
||||||
|
|
||||||
CommandParameters parameters = new CommandParameters(bools, strings,
|
final CommandParameters parameters = new CommandParameters(bools,
|
||||||
true);
|
strings, true);
|
||||||
|
|
||||||
assertFalse(parameters.parseArgs("-ungivenFlag"));
|
|
||||||
assertFalse(parameters.parseArgs("-str"));
|
|
||||||
assertTrue(parameters.parseArgs("-boolFlag"));
|
|
||||||
assertTrue(parameters.parseArgs("-str", "-boolFlag"));
|
|
||||||
assertTrue(parameters.parseArgs("-boolFlag", "-str", "val"));
|
|
||||||
|
|
||||||
|
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
|
||||||
* Test method for {@link fr.bigeon.gclc.command.CommandParameters#set(java.lang.String, boolean)}.
|
* {@link fr.bigeon.gclc.command.CommandParameters#set(java.lang.String, boolean)}. */
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
public final void testSetStringBoolean(){
|
public final void testSetStringBoolean() {
|
||||||
Set<String> strings = new HashSet<>();
|
final Set<String> strings = new HashSet<>();
|
||||||
Set<String> bools = new HashSet<>();
|
final Set<String> bools = new HashSet<>();
|
||||||
|
|
||||||
bools.add("boolFlag");
|
bools.add("boolFlag");
|
||||||
strings.add("str");
|
strings.add("str");
|
||||||
@@ -233,13 +279,12 @@ public class CommandParametersTest {
|
|||||||
assertTrue(parameters.getBool("boolFlag"));
|
assertTrue(parameters.getBool("boolFlag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Test method for
|
||||||
* Test method for {@link fr.bigeon.gclc.command.CommandParameters#set(java.lang.String, java.lang.String)}.
|
* {@link fr.bigeon.gclc.command.CommandParameters#set(java.lang.String, java.lang.String)}. */
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
public final void testSetStringString(){
|
public final void testSetStringString() {
|
||||||
Set<String> strings = new HashSet<>();
|
final Set<String> strings = new HashSet<>();
|
||||||
Set<String> bools = new HashSet<>();
|
final Set<String> bools = new HashSet<>();
|
||||||
|
|
||||||
bools.add("boolFlag");
|
bools.add("boolFlag");
|
||||||
strings.add("str");
|
strings.add("str");
|
||||||
|
|||||||
@@ -38,68 +38,61 @@
|
|||||||
*/
|
*/
|
||||||
package fr.bigeon.gclc.command;
|
package fr.bigeon.gclc.command;
|
||||||
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import fr.bigeon.gclc.exception.InvalidCommandName;
|
import fr.bigeon.gclc.exception.InvalidCommandName;
|
||||||
|
|
||||||
/** <p>
|
/**
|
||||||
|
* <p>
|
||||||
* TODO
|
* TODO
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public class CommandProviderTest {
|
public class CommandProviderTest {
|
||||||
|
|
||||||
/** Test method for
|
/** Test method for
|
||||||
* {@link fr.bigeon.gclc.command.CommandProvider#add(fr.bigeon.gclc.command.ICommand)}. */
|
* {@link fr.bigeon.gclc.command.CommandProvider#add(fr.bigeon.gclc.command.ICommand)}.
|
||||||
|
*
|
||||||
|
* @throws InvalidCommandName if the test failed */
|
||||||
@Test
|
@Test
|
||||||
public final void testAdd() {
|
public final void testAdd() throws InvalidCommandName {
|
||||||
CommandProvider provider = new CommandProvider();
|
final CommandProvider provider = new CommandProvider();
|
||||||
try {
|
try {
|
||||||
provider.add(new MockCommand(null));
|
provider.add(new MockCommand(null));
|
||||||
fail("null name for command should be rejected");
|
fail("null name for command should be rejected");
|
||||||
} catch (InvalidCommandName e) {
|
} catch (final InvalidCommandName e) {
|
||||||
assertNotNull(e);
|
// ok
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
provider.add(new MockCommand(""));
|
provider.add(new MockCommand(""));
|
||||||
fail("null name for command should be rejected");
|
fail("null name for command should be rejected");
|
||||||
} catch (InvalidCommandName e) {
|
} catch (final InvalidCommandName e) {
|
||||||
assertNotNull(e);
|
// ok
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
provider.add(new MockCommand("-name"));
|
provider.add(new MockCommand("-name"));
|
||||||
fail("name with minus as starting character for command should be rejected");
|
fail("name with minus as starting character for command should be rejected");
|
||||||
} catch (InvalidCommandName e) {
|
} catch (final InvalidCommandName e) {
|
||||||
assertNotNull(e);
|
// ok
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
provider.add(new MockCommand("name command"));
|
provider.add(new MockCommand("name command"));
|
||||||
fail("name with space for command should be rejected");
|
fail("name with space for command should be rejected");
|
||||||
} catch (InvalidCommandName e) {
|
} catch (final InvalidCommandName e) {
|
||||||
assertNotNull(e);
|
// ok
|
||||||
}
|
|
||||||
ICommand mock = new MockCommand("name");
|
|
||||||
try {
|
|
||||||
provider.add(mock);
|
|
||||||
} catch (InvalidCommandName e) {
|
|
||||||
assertNull(e);
|
|
||||||
}
|
}
|
||||||
|
final ICommand mock = new MockCommand("name");
|
||||||
|
provider.add(mock);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
provider.add(new MockCommand(mock.getCommandName()));
|
provider.add(new MockCommand(mock.getCommandName()));
|
||||||
fail("already existing command name should be rejected");
|
fail("already existing command name should be rejected");
|
||||||
} catch (InvalidCommandName e) {
|
} catch (final InvalidCommandName e) {
|
||||||
assertNotNull(e);
|
// ok
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
provider.add(mock);
|
||||||
provider.add(mock);
|
|
||||||
} catch (InvalidCommandName e) {
|
|
||||||
assertNotNull(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,14 +38,18 @@
|
|||||||
*/
|
*/
|
||||||
package fr.bigeon.gclc.command;
|
package fr.bigeon.gclc.command;
|
||||||
|
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
import fr.bigeon.gclc.manager.PipedConsoleManager;
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
|
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||||
|
|
||||||
/** <p>
|
/** <p>
|
||||||
* TODO
|
* TODO
|
||||||
@@ -54,44 +58,82 @@ import fr.bigeon.gclc.manager.PipedConsoleManager;
|
|||||||
public class CommandTest {
|
public class CommandTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public final void test() {
|
public final void testCommand() throws IOException {
|
||||||
try (PipedConsoleManager test = new PipedConsoleManager()) {
|
try (PipedConsoleOutput test = new PipedConsoleOutput()) {
|
||||||
Command cmd;
|
Command cmd;
|
||||||
cmd = new Command("name") {
|
cmd = new Command("name") {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final ConsoleOutput out,
|
||||||
|
final ConsoleInput in,
|
||||||
|
final String... args) throws CommandRunException {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(String... args) throws CommandRunException {
|
protected String usageDetail() {
|
||||||
//
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
cmd.help(test);
|
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") {
|
cmd = new Command("name") {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final ConsoleOutput out,
|
||||||
|
final ConsoleInput in,
|
||||||
|
final String... args) throws CommandRunException {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(String... args) throws CommandRunException {
|
protected String usageDetail() {
|
||||||
//
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
cmd.help(test);
|
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") {
|
cmd = new Command("name") {
|
||||||
|
|
||||||
@Override
|
|
||||||
public String tip() {
|
|
||||||
return "tip";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.Command#brief() */
|
* @see fr.bigeon.gclc.command.Command#brief() */
|
||||||
@Override
|
@Override
|
||||||
@@ -100,19 +142,40 @@ public class CommandTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(String... args) throws CommandRunException {
|
public void execute(final ConsoleOutput out,
|
||||||
|
final ConsoleInput in,
|
||||||
|
final String... args) throws CommandRunException {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
};
|
|
||||||
cmd.help(test);
|
|
||||||
|
|
||||||
cmd = new Command("name") {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
return "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)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.command.Command#brief() */
|
* @see fr.bigeon.gclc.command.Command#brief() */
|
||||||
@Override
|
@Override
|
||||||
@@ -121,14 +184,47 @@ public class CommandTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(String... args) throws CommandRunException {
|
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);
|
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") {
|
cmd = new Command("name") {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final ConsoleOutput out,
|
||||||
|
final ConsoleInput in,
|
||||||
|
final String... args) throws CommandRunException {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
return "tip";
|
return "tip";
|
||||||
@@ -140,16 +236,32 @@ public class CommandTest {
|
|||||||
protected String usageDetail() {
|
protected String usageDetail() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(String... args) throws CommandRunException {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
cmd.help(test);
|
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") {
|
cmd = new Command("name") {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final ConsoleOutput out,
|
||||||
|
final ConsoleInput in,
|
||||||
|
final String... args) throws CommandRunException {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
return "tip";
|
return "tip";
|
||||||
@@ -161,15 +273,35 @@ public class CommandTest {
|
|||||||
protected String usageDetail() {
|
protected String usageDetail() {
|
||||||
return "details";
|
return "details";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(String... args) throws CommandRunException {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
cmd.help(test);
|
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") {
|
cmd = new Command("name") {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final ConsoleOutput out,
|
||||||
|
final ConsoleInput in,
|
||||||
|
final String... args) throws CommandRunException {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
return "tip";
|
return "tip";
|
||||||
@@ -181,16 +313,34 @@ public class CommandTest {
|
|||||||
protected String usageDetail() {
|
protected String usageDetail() {
|
||||||
return "details" + System.lineSeparator();
|
return "details" + System.lineSeparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(String... args) throws CommandRunException {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
cmd.help(test);
|
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") {
|
cmd = new Command("name") {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final ConsoleOutput out,
|
||||||
|
final ConsoleInput in,
|
||||||
|
final String... args) throws CommandRunException {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tip() {
|
public String tip() {
|
||||||
return "tip";
|
return "tip";
|
||||||
@@ -202,16 +352,25 @@ public class CommandTest {
|
|||||||
protected String usageDetail() {
|
protected String usageDetail() {
|
||||||
return "\n";
|
return "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(String... args) throws CommandRunException {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
cmd.help(test);
|
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());
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
assertNull(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,98 +39,79 @@
|
|||||||
package fr.bigeon.gclc.command;
|
package fr.bigeon.gclc.command;
|
||||||
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import fr.bigeon.gclc.exception.CommandRunException;
|
import fr.bigeon.gclc.exception.CommandRunException;
|
||||||
import fr.bigeon.gclc.manager.PipedConsoleManager;
|
import fr.bigeon.gclc.manager.ConsoleInput;
|
||||||
|
import fr.bigeon.gclc.manager.ConsoleOutput;
|
||||||
|
import fr.bigeon.gclc.manager.PipedConsoleOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* TODO
|
* TODO
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon
|
* @author Emmanuel Bigeon */
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class HelpExecutorTest {
|
public class HelpExecutorTest {
|
||||||
|
|
||||||
/**
|
/** Test method for
|
||||||
* Test method for {@link fr.bigeon.gclc.command.HelpExecutor#HelpExecutor(java.lang.String, fr.bigeon.gclc.manager.ConsoleManager, fr.bigeon.gclc.command.ICommand)}.
|
* {@link fr.bigeon.gclc.command.HelpExecutor#execute(ConsoleOutput, ConsoleInput, String...)}.
|
||||||
*/
|
*
|
||||||
|
* @throws CommandRunException if the test failed
|
||||||
|
* @throws IOException if the test failed */
|
||||||
@Test
|
@Test
|
||||||
public final void testHelpExecutor(){
|
public final void testExecute() throws CommandRunException, IOException {
|
||||||
HelpExecutor help;
|
final PipedConsoleOutput test = new PipedConsoleOutput();
|
||||||
try {
|
final HelpExecutor help = new HelpExecutor("?", new Command("mock") {
|
||||||
help = new HelpExecutor("?", null, new MockCommand("mock"));
|
|
||||||
fail("help is an interactive command, should need console manager");
|
|
||||||
} catch (Exception e) {
|
|
||||||
assertNotNull(e);
|
|
||||||
}
|
|
||||||
try (PipedConsoleManager test = new PipedConsoleManager()) {
|
|
||||||
help = new HelpExecutor("?", test, new MockCommand("mock"));
|
|
||||||
} catch (Exception e) {
|
|
||||||
assertNull(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Test method for {@link fr.bigeon.gclc.command.HelpExecutor#execute(java.lang.String[])}.
|
public void execute(final ConsoleOutput out, final ConsoleInput in,
|
||||||
*/
|
final String... args) throws CommandRunException {
|
||||||
@Test
|
//
|
||||||
public final void testExecute(){
|
|
||||||
try {
|
|
||||||
PipedConsoleManager test = new PipedConsoleManager();
|
|
||||||
HelpExecutor help = new HelpExecutor("?", test,
|
|
||||||
new Command("mock") {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(String... args) throws CommandRunException {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String tip() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
help.execute();
|
|
||||||
test.close();
|
|
||||||
|
|
||||||
try {
|
|
||||||
help.execute();
|
|
||||||
fail("manager closed shall provoke failure of help command execution");
|
|
||||||
} catch (Exception e) {
|
|
||||||
assertNotNull(e);
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
assertNull(e);
|
@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()}.
|
||||||
* Test method for {@link fr.bigeon.gclc.command.HelpExecutor#tip()}.
|
*
|
||||||
*/
|
* @throws IOException if the test failed */
|
||||||
@Test
|
@Test
|
||||||
public final void testTip(){
|
public final void testTip() throws IOException {
|
||||||
try (PipedConsoleManager test = new PipedConsoleManager()) {
|
try (PipedConsoleOutput test = new PipedConsoleOutput()) {
|
||||||
HelpExecutor help = new HelpExecutor("?", test,
|
final HelpExecutor help = new HelpExecutor("?",
|
||||||
new MockCommand("mock"));
|
new MockCommand("mock"));
|
||||||
help.tip();
|
assertNotNull("Tip should be provided", help.tip());
|
||||||
help.help(test);
|
help.help(test);
|
||||||
} catch (Exception e) {
|
|
||||||
assertNull(e);
|
|
||||||
}
|
}
|
||||||
try (PipedConsoleManager test = new PipedConsoleManager()) {
|
try (PipedConsoleOutput test = new PipedConsoleOutput()) {
|
||||||
HelpExecutor help = new HelpExecutor("?", test,
|
final HelpExecutor help = new HelpExecutor("?",
|
||||||
new SubedCommand("sub", new MockCommand("mock")));
|
new SubedCommand("sub", new MockCommand("mock")));
|
||||||
help.tip();
|
help.tip();
|
||||||
help.help(test);
|
help.help(test);
|
||||||
} catch (Exception e) {
|
|
||||||
assertNull(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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