diff --git a/gclc/src/main/java/fr/bigeon/gclc/command/ExitCommand.java b/gclc/src/main/java/fr/bigeon/gclc/command/ExitCommand.java index 8cf5932..cd14335 100644 --- a/gclc/src/main/java/fr/bigeon/gclc/command/ExitCommand.java +++ b/gclc/src/main/java/fr/bigeon/gclc/command/ExitCommand.java @@ -75,7 +75,8 @@ public class ExitCommand implements ICommand { } @Override - public void execute(final ConsoleOutput output, final ConsoleInput input, final String... args) { + public final void execute(final ConsoleOutput output, + final ConsoleInput input, final String... args) { beforeExit(); app.exit(); } @@ -83,18 +84,18 @@ public class ExitCommand implements ICommand { /* (non-Javadoc) * @see fr.bigeon.gclc.command.ICommand#getCommandName() */ @Override - public String getCommandName() { + public final String getCommandName() { return name; } @Override - public void help(final ConsoleOutput manager, + public final void help(final ConsoleOutput manager, final String... args) throws IOException { manager.println( CLIPrompterMessages.getString(EXIT_MAN, (Object[]) args)); } @Override - public String tip() { + public final String tip() { return CLIPrompterMessages.getString(EXIT); } } \ No newline at end of file diff --git a/gclc/src/main/java/fr/bigeon/gclc/command/ICommand.java b/gclc/src/main/java/fr/bigeon/gclc/command/ICommand.java index faa5174..0d22f8a 100644 --- a/gclc/src/main/java/fr/bigeon/gclc/command/ICommand.java +++ b/gclc/src/main/java/fr/bigeon/gclc/command/ICommand.java @@ -60,7 +60,9 @@ public interface ICommand { void execute(ConsoleOutput out, ConsoleInput in, String... args) throws CommandRunException; - /** @return the command's name */ + /** Get teh command name. + * + * @return the command's name */ String getCommandName(); /** This prints the help associated to this command. @@ -71,7 +73,7 @@ public interface ICommand { void help(ConsoleOutput output, String... args) throws IOException; /** Get a tip (brief helping message) for the command. - * + * * @return a tip on the command */ String tip(); diff --git a/gclc/src/main/java/fr/bigeon/gclc/command/SubedCommand.java b/gclc/src/main/java/fr/bigeon/gclc/command/SubedCommand.java index 014fc64..299fcc5 100644 --- a/gclc/src/main/java/fr/bigeon/gclc/command/SubedCommand.java +++ b/gclc/src/main/java/fr/bigeon/gclc/command/SubedCommand.java @@ -61,7 +61,7 @@ public final class SubedCommand extends CommandProvider implements ICommand { private final ICommand noArgCommand; /** A tip on this command. */ private final String tip; - /** The name of the command */ + /** The name of the command. */ private final String name; /** Create the command that defines sub commands. diff --git a/gclc/src/main/java/fr/bigeon/gclc/exception/CommandRunException.java b/gclc/src/main/java/fr/bigeon/gclc/exception/CommandRunException.java index 84c6a81..59dcec9 100644 --- a/gclc/src/main/java/fr/bigeon/gclc/exception/CommandRunException.java +++ b/gclc/src/main/java/fr/bigeon/gclc/exception/CommandRunException.java @@ -51,7 +51,7 @@ public final class CommandRunException extends Exception { /** The type of run exception. */ private final CommandRunExceptionType type; /** The command that caused the error. */ - private final ICommand source; + private transient ICommand source; /** Create the exception. * diff --git a/gclc/src/main/java/fr/bigeon/gclc/exception/package-info.java b/gclc/src/main/java/fr/bigeon/gclc/exception/package-info.java index d94c97d..135c428 100644 --- a/gclc/src/main/java/fr/bigeon/gclc/exception/package-info.java +++ b/gclc/src/main/java/fr/bigeon/gclc/exception/package-info.java @@ -1,3 +1,37 @@ +/* + * 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 diff --git a/gclc/src/main/java/fr/bigeon/gclc/i18n/package-info.java b/gclc/src/main/java/fr/bigeon/gclc/i18n/package-info.java index f883a39..805e079 100644 --- a/gclc/src/main/java/fr/bigeon/gclc/i18n/package-info.java +++ b/gclc/src/main/java/fr/bigeon/gclc/i18n/package-info.java @@ -1,3 +1,37 @@ +/* + * 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 diff --git a/gclc/src/main/java/fr/bigeon/gclc/manager/ReadingRunnable.java b/gclc/src/main/java/fr/bigeon/gclc/manager/ReadingRunnable.java index 06aa342..7fbfba9 100644 --- a/gclc/src/main/java/fr/bigeon/gclc/manager/ReadingRunnable.java +++ b/gclc/src/main/java/fr/bigeon/gclc/manager/ReadingRunnable.java @@ -128,14 +128,13 @@ public final class ReadingRunnable implements Runnable { private final BufferedReader reader; /** the state of this runnable. */ private boolean running = true; - /** Synchro object. */ private final Object lock = new Object(); /** The waiting status for a message. */ private boolean waiting; /** The blocker for a given message. */ private final Map messageBlocker = new HashMap<>(); - /** The lock */ + /** The lock. */ private final Object messageBlockerLock = new Object(); /** The message being delivered. */ private String delivering; @@ -162,6 +161,23 @@ public final class ReadingRunnable implements Runnable { return res; } + /** do wait for a message. + *

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 @@ -172,17 +188,7 @@ public final class ReadingRunnable implements Runnable { throw new IOException(CLOSED_PIPE); } waiting = true; - while (messages.isEmpty()) { - 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); - } - } + waitMessage(TIMEOUT); LOGGER.finest("Polled: " + messages.peek()); //$NON-NLS-1$ waiting = false; notifyMessage(messages.peek()); @@ -201,15 +207,7 @@ public final class ReadingRunnable implements Runnable { throw new IOException(CLOSED_PIPE); } waiting = true; - 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); - } + doWaitMessage(timeout); waiting = false; if (messages.isEmpty()) { return null; @@ -335,11 +333,22 @@ public final class ReadingRunnable implements Runnable { } /** Set the running status for this reading runnable. - * + * * @param running the running to set */ public void setRunning(final boolean running) { synchronized (lock) { this.running = running; } } + + /** Wait for the next message to be integratted. + * + * @param timeout the timeout to wait + * @throws IOException if the next message was not delivered and the + * runnable stopped. */ + private void waitMessage(final long timeout) throws IOException { + while (messages.isEmpty()) { + doWaitMessage(timeout); + } + } } diff --git a/gclc/src/main/java/fr/bigeon/gclc/manager/SinkOutput.java b/gclc/src/main/java/fr/bigeon/gclc/manager/SinkOutput.java index 70a6d5a..d03f643 100644 --- a/gclc/src/main/java/fr/bigeon/gclc/manager/SinkOutput.java +++ b/gclc/src/main/java/fr/bigeon/gclc/manager/SinkOutput.java @@ -38,8 +38,6 @@ */ package fr.bigeon.gclc.manager; -import java.io.IOException; - /** A console output that absorbs every message. * * @author Emmanuel Bigeon */ @@ -55,7 +53,7 @@ public final class SinkOutput implements ConsoleOutput { /* (non-Javadoc) * @see fr.bigeon.gclc.manager.ConsoleOutput#close() */ @Override - public void close() throws IOException { + public void close() { // } @@ -69,14 +67,14 @@ public final class SinkOutput implements ConsoleOutput { /* (non-Javadoc) * @see fr.bigeon.gclc.manager.ConsoleOutput#print(java.lang.String) */ @Override - public void print(final String text) throws IOException { + public void print(final String text) { // } /* (non-Javadoc) * @see fr.bigeon.gclc.manager.ConsoleOutput#println() */ @Override - public void println() throws IOException { + public void println() { // } @@ -84,7 +82,7 @@ public final class SinkOutput implements ConsoleOutput { * @see fr.bigeon.gclc.manager.ConsoleOutput#println(java.lang.String) */ @Override - public void println(final String message) throws IOException { + public void println(final String message) { // } diff --git a/gclc/src/main/java/fr/bigeon/gclc/manager/WritingRunnable.java b/gclc/src/main/java/fr/bigeon/gclc/manager/WritingRunnable.java index 9ba789a..34107db 100644 --- a/gclc/src/main/java/fr/bigeon/gclc/manager/WritingRunnable.java +++ b/gclc/src/main/java/fr/bigeon/gclc/manager/WritingRunnable.java @@ -85,7 +85,7 @@ public final class WritingRunnable implements Runnable { * * @param message the message * @throws IOException if the pipe is closed */ - public synchronized void addMessage(final String message) throws IOException { + public void addMessage(final String message) throws IOException { synchronized (lock) { if (!running) { throw new IOException("Closed pipe"); //$NON-NLS-1$ @@ -124,7 +124,7 @@ public final class WritingRunnable implements Runnable { /** Set the running status. * * @param running the running to set */ - public synchronized void setRunning(final boolean running) { + public void setRunning(final boolean running) { synchronized (lock) { this.running = running; } diff --git a/gclc/src/main/java/fr/bigeon/gclc/manager/package-info.java b/gclc/src/main/java/fr/bigeon/gclc/manager/package-info.java index efefc72..35a359d 100644 --- a/gclc/src/main/java/fr/bigeon/gclc/manager/package-info.java +++ b/gclc/src/main/java/fr/bigeon/gclc/manager/package-info.java @@ -1,3 +1,37 @@ +/* + * 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 diff --git a/gclc/src/main/java/fr/bigeon/gclc/tools/package-info.java b/gclc/src/main/java/fr/bigeon/gclc/tools/package-info.java index 2d866a8..1c0d5ba 100644 --- a/gclc/src/main/java/fr/bigeon/gclc/tools/package-info.java +++ b/gclc/src/main/java/fr/bigeon/gclc/tools/package-info.java @@ -1,3 +1,37 @@ +/* + * 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 diff --git a/gclc/src/test/java/fr/bigeon/gclc/command/CommandTest.java b/gclc/src/test/java/fr/bigeon/gclc/command/CommandTest.java index 299ddb7..3ad8b50 100644 --- a/gclc/src/test/java/fr/bigeon/gclc/command/CommandTest.java +++ b/gclc/src/test/java/fr/bigeon/gclc/command/CommandTest.java @@ -38,6 +38,10 @@ */ package fr.bigeon.gclc.command; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import org.junit.Test; @@ -78,6 +82,21 @@ public class CommandTest { }; cmd.help(test); + // name + assertEquals("First line should be command name", "name", + test.readNextLine()); + // tip + test.readNextLine(); + // + assertTrue("Section line is empty", test.readNextLine().isEmpty()); + // Usage + test.readNextLine(); + // details + test.readNextLine(); + // + assertTrue("Section line is empty", test.readNextLine().isEmpty()); + assertFalse("Only 6 line should be printed", test.available()); + cmd = new Command("name") { @Override @@ -98,6 +117,20 @@ public class CommandTest { } }; 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") { @@ -126,6 +159,20 @@ public class CommandTest { } }; 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") { @@ -154,6 +201,20 @@ public class CommandTest { } }; 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") { @@ -177,6 +238,20 @@ public class CommandTest { } }; 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") { @@ -200,6 +275,24 @@ public class CommandTest { } }; cmd.help(test); + + // name + assertEquals("First line should be command name", "name", + test.readNextLine()); + // tip + test.readNextLine(); + // + assertTrue("Section line is empty", test.readNextLine().isEmpty()); + // Usage + test.readNextLine(); + // pattern + test.readNextLine(); + // + assertTrue("Section line is empty", test.readNextLine().isEmpty()); + // details + assertEquals("Unexpected detail", "details", test.readNextLine()); + assertFalse("Only 6 line should be printed", test.available()); + cmd = new Command("name") { @Override @@ -222,6 +315,22 @@ public class CommandTest { } }; 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") { @@ -245,6 +354,22 @@ public class CommandTest { } }; 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()); } } diff --git a/gclc/src/test/java/fr/bigeon/gclc/command/HelpExecutorTest.java b/gclc/src/test/java/fr/bigeon/gclc/command/HelpExecutorTest.java index 04aac02..e504938 100644 --- a/gclc/src/test/java/fr/bigeon/gclc/command/HelpExecutorTest.java +++ b/gclc/src/test/java/fr/bigeon/gclc/command/HelpExecutorTest.java @@ -38,6 +38,7 @@ */ package fr.bigeon.gclc.command; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import java.io.IOException; @@ -95,25 +96,15 @@ public class HelpExecutorTest { } } - /** Test method for - * {@link fr.bigeon.gclc.command.HelpExecutor#HelpExecutor(java.lang.String, fr.bigeon.gclc.manager.ConsoleManager, fr.bigeon.gclc.command.ICommand)}. - * - * @throws IOException if an IO occurs */ - @Test - public final void testHelpExecutor() throws IOException { - HelpExecutor help; - help = new HelpExecutor("?", new MockCommand("mock")); - } - /** Test method for {@link fr.bigeon.gclc.command.HelpExecutor#tip()}. - * + * * @throws IOException */ @Test public final void testTip() throws IOException { try (PipedConsoleOutput test = new PipedConsoleOutput()) { final HelpExecutor help = new HelpExecutor("?", new MockCommand("mock")); - help.tip(); + assertNotNull("Tip should be provided", help.tip()); help.help(test); } try (PipedConsoleOutput test = new PipedConsoleOutput()) { diff --git a/gclc/src/test/java/fr/bigeon/gclc/manager/ReadingRunnableTest.java b/gclc/src/test/java/fr/bigeon/gclc/manager/ReadingRunnableTest.java index 41378b8..849c427 100644 --- a/gclc/src/test/java/fr/bigeon/gclc/manager/ReadingRunnableTest.java +++ b/gclc/src/test/java/fr/bigeon/gclc/manager/ReadingRunnableTest.java @@ -38,6 +38,7 @@ */ package fr.bigeon.gclc.manager; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.fail; import java.io.BufferedReader; @@ -51,7 +52,8 @@ import java.nio.charset.Charset; import org.junit.Before; import org.junit.Test; -/**

+/** + *

* TODO * * @author Emmanuel Bigeon */ @@ -85,7 +87,8 @@ public class ReadingRunnableTest { * @throws InterruptedException * @throws IOException */ @Test - public final void testGetWaitForDelivery() throws InterruptedException, IOException { + public final void testGetWaitForDelivery() throws InterruptedException, + IOException { try (PipedOutputStream out = new PipedOutputStream(); InputStream piped = new PipedInputStream(out); BufferedReader reader = new BufferedReader( @@ -111,7 +114,9 @@ public class ReadingRunnableTest { } }, "get"); th2.start(); - th.join(); + th.join(); + assertFalse("Runnable should have consumed every message", + runnable.hasMessage()); runnable.setRunning(false); out.close(); }