";
+ }
}
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/ForkCommandTask.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/ForkCommandTask.java
new file mode 100644
index 0000000..3e1b82b
--- /dev/null
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/ForkCommandTask.java
@@ -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);
+ }
+
+}
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/ForkTask.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/ForkTask.java
index f19c504..7792741 100644
--- a/gclc-process/src/main/java/fr/bigeon/gclc/process/ForkTask.java
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/ForkTask.java
@@ -1,6 +1,6 @@
/*
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
- * Copyright (C) 2014-2017 E. Bigeon
+ * Copyright (C) 2014-2018 E. Bigeon
* mailto:emmanuel@bigeon.fr
*
* This software is governed by the CeCILL license under French law and
@@ -35,63 +35,70 @@
*/
package fr.bigeon.gclc.process;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
-import fr.bigeon.gclc.command.ICommand;
+import fr.bigeon.gclc.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;
/**
*
* TODO
*
- * @author Emmanuel Bigeon
- *
- */
-public class ForkTask implements Task {
+ * @author Emmanuel Bigeon */
+public abstract class ForkTask implements Task {
- private final ICommand command;
- private final String[] args;
private final Set listeners = new HashSet<>();
- private boolean running = false;
+ private boolean running = false;
- /** @param cmd the command
- * @param args the arguements */
- public ForkTask(final ICommand cmd, final String[] args) {
- command = cmd;
- this.args = Arrays.copyOf(args, args.length);
+ 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 void addInterruptionListener(final InterruptionListener listener) {
+ public final void addInterruptionListener(final InterruptionListener listener) {
listeners.add(listener);
}
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.process.Task#getName() */
- @Override
- public String getName() {
- return command.getCommandName();
- }
-
/* (non-Javadoc)
* @see fr.bigeon.gclc.process.Task#isRunning() */
@Override
- public boolean isRunning() {
- return running;
+ public final boolean isRunning() {
+ synchronized (runLock) {
+ return running;
+ }
}
/** @param out the console output
- * @param in the console input */
- public void join(final ConsoleOutput out, final ConsoleInput in) {
- // TODO Auto-generated method stub
- //
- throw new RuntimeException("Not implemented yet");
+ * @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)
@@ -99,29 +106,50 @@ public class ForkTask implements Task {
* fr.bigeon.gclc.process.Task#rmInterruptionListener(fr.bigeon.gclc.process
* .InterruptionListener) */
@Override
- public void rmInterruptionListener(final InterruptionListener listener) {
+ public final void rmInterruptionListener(final InterruptionListener listener) {
listeners.remove(listener);
}
/* (non-Javadoc)
* @see java.lang.Runnable#run() */
@Override
- public void run() {
- running = true;
- try {
- // TODO Auto-generated method stub
- //
- throw new RuntimeException("Not implemented yet");
- } finally {
- running = false;
+ 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 void setRunning(final boolean running) {
- this.running = running;
+ public final void setRunning(final boolean running) {
+ synchronized (runLock) {
+ this.running = running;
+ runLock.notifyAll();
+ }
}
+ protected final Object getRunningLock() {
+ return runLock;
+ }
}
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/InterruptionListener.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/InterruptionListener.java
index 0034f0c..4011921 100644
--- a/gclc-process/src/main/java/fr/bigeon/gclc/process/InterruptionListener.java
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/InterruptionListener.java
@@ -1,6 +1,6 @@
/*
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
- * Copyright (C) 2014-2017 E. Bigeon
+ * Copyright (C) 2014-2018 E. Bigeon
* mailto:emmanuel@bigeon.fr
*
* This software is governed by the CeCILL license under French law and
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessAttachement.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessAttachement.java
new file mode 100644
index 0000000..53c46d7
--- /dev/null
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessAttachement.java
@@ -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));
+ }
+
+}
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessClear.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessClear.java
new file mode 100644
index 0000000..db7deb7
--- /dev/null
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessClear.java
@@ -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;
+ }
+
+}
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessKill.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessKill.java
index 9364994..56a0d65 100644
--- a/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessKill.java
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessKill.java
@@ -1,6 +1,6 @@
/*
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
- * Copyright (C) 2014-2017 E. Bigeon
+ * Copyright (C) 2014-2018 E. Bigeon
* mailto:emmanuel@bigeon.fr
*
* This software is governed by the CeCILL license under French law and
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessList.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessList.java
index 61b5508..be7a6d8 100644
--- a/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessList.java
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/ProcessList.java
@@ -1,6 +1,6 @@
/*
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
- * Copyright (C) 2014-2017 E. Bigeon
+ * Copyright (C) 2014-2018 E. Bigeon
* mailto:emmanuel@bigeon.fr
*
* This software is governed by the CeCILL license under French law and
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/ScreenAttachement.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/ScreenAttachement.java
new file mode 100644
index 0000000..69ec006
--- /dev/null
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/ScreenAttachement.java
@@ -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));
+ }
+}
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/Task.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/Task.java
index c7aa3c9..ea9a476 100644
--- a/gclc-process/src/main/java/fr/bigeon/gclc/process/Task.java
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/Task.java
@@ -1,6 +1,6 @@
/*
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
- * Copyright (C) 2014-2017 E. Bigeon
+ * Copyright (C) 2014-2018 E. Bigeon
* mailto:emmanuel@bigeon.fr
*
* This software is governed by the CeCILL license under French law and
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/TaskPool.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/TaskPool.java
index c4fb770..8d10102 100644
--- a/gclc-process/src/main/java/fr/bigeon/gclc/process/TaskPool.java
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/TaskPool.java
@@ -1,6 +1,6 @@
/*
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
- * Copyright (C) 2014-2017 E. Bigeon
+ * Copyright (C) 2014-2018 E. Bigeon
* mailto:emmanuel@bigeon.fr
*
* This software is governed by the CeCILL license under French law and
@@ -47,13 +47,29 @@ public final class TaskPool {
/** The running processes. */
private final Map running = new HashMap<>();
/** The count for process id. */
- private int count = 0;
+ private int count = 0;
/** The lock for pid attribution synchronization. */
- private final Object lock = new Object();
+ 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.
@@ -64,22 +80,23 @@ public final class TaskPool {
if (cmd == null) {
throw new IllegalArgumentException("Task cannot be null"); //$NON-NLS-1$
}
- final String pid = getPID();
+ final String pid;
synchronized (lock) {
+ pid = getPID();
running.put(pid, cmd);
}
- cmd.addInterruptionListener(new InterruptionListener() {
-
- @SuppressWarnings("synthetic-access")
- @Override
- public void interrupted() {
- synchronized (lock) {
- running.remove(pid);
- count = Math.min(count, Integer.parseInt(pid));
+ if (autoClear) {
+ cmd.addInterruptionListener(new InterruptionListener() {
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void interrupted() {
+ synchronized (lock) {
+ remove(pid);
+ }
+ cmd.rmInterruptionListener(this);
}
- cmd.rmInterruptionListener(this);
- }
- });
+ });
+ }
return pid;
}
@@ -112,4 +129,21 @@ public final class TaskPool {
public Collection 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.
+ *
+ * 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);
+ }
+ }
+ }
}
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/TaskSpawner.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/TaskSpawner.java
index b287f72..7b9cbf1 100644
--- a/gclc-process/src/main/java/fr/bigeon/gclc/process/TaskSpawner.java
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/TaskSpawner.java
@@ -1,6 +1,6 @@
/*
* process, Distribution repositories and basic setup for Emmanuel Bigeon projects
- * Copyright (C) 2014-2017 E. Bigeon
+ * Copyright (C) 2014-2018 E. Bigeon
* mailto:emmanuel@bigeon.fr
*
* This software is governed by the CeCILL license under French law and
@@ -35,6 +35,8 @@
*/
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;
@@ -46,31 +48,35 @@ import fr.bigeon.gclc.manager.ConsoleOutput;
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) {
+ 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 */
+ * @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);
+ 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 void execute(final ConsoleOutput out, final ConsoleInput in,
+ 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);
- th.start();
+ threadPool.execute(th);
}
}
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/io/ConnectingConsoleInput.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/io/ConnectingConsoleInput.java
new file mode 100644
index 0000000..6cbbeff
--- /dev/null
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/io/ConnectingConsoleInput.java
@@ -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;
+ }
+ }
+ }
+}
diff --git a/gclc-process/src/main/java/fr/bigeon/gclc/process/io/ConnectingConsoleOutput.java b/gclc-process/src/main/java/fr/bigeon/gclc/process/io/ConnectingConsoleOutput.java
new file mode 100644
index 0000000..9292c45
--- /dev/null
+++ b/gclc-process/src/main/java/fr/bigeon/gclc/process/io/ConnectingConsoleOutput.java
@@ -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 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;
+ }
+}