20 package net.sf.gridarta.utils;
22 import java.awt.BorderLayout;
23 import java.awt.Color;
24 import java.awt.Component;
26 import java.awt.Frame;
27 import java.awt.Window;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.util.Queue;
32 import java.util.concurrent.ConcurrentLinkedQueue;
33 import javax.swing.Action;
34 import javax.swing.JDialog;
35 import javax.swing.JPanel;
36 import javax.swing.JScrollPane;
37 import javax.swing.JTextArea;
38 import javax.swing.JToolBar;
39 import javax.swing.SwingUtilities;
40 import net.
sf.japi.swing.action.ActionBuilder;
41 import net.
sf.japi.swing.action.ActionBuilderFactory;
42 import net.
sf.japi.swing.action.ActionMethod;
43 import org.apache.log4j.Category;
44 import org.apache.log4j.Logger;
45 import org.jetbrains.annotations.NotNull;
46 import org.jetbrains.annotations.Nullable;
69 private static final ActionBuilder
ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder(
"net.sf.gridarta");
83 private final String
key;
97 private final File
dir;
110 private final JTextArea
stdtxt =
new JTextArea(25, 80);
131 private final Action
controlStart = ACTION_BUILDER.createAction(
false,
"controlStart",
this);
138 private final Action
controlStop = ACTION_BUILDER.createAction(
false,
"controlStop",
this);
144 private final Object
lock =
new Object();
153 private ProcessRunner(@NotNull
final String key, @NotNull
final String[] command, @Nullable
final String dir) {
155 this.command = command.clone();
156 this.dir = dir == null ? null :
new File(dir);
157 setLayout(
new BorderLayout());
158 stdtxt.setFont(
new Font(
"monospaced", Font.PLAIN, stdtxt.getFont().getSize()));
159 stdtxt.setEditable(
false);
160 stdtxt.setFocusable(
false);
161 stdtxt.setLineWrap(
true);
162 stdtxt.setBackground(Color.BLACK);
163 stdtxt.setForeground(Color.WHITE);
164 final Component scrollPane =
new JScrollPane(stdtxt);
165 scrollPane.setFocusable(
true);
166 add(scrollPane, BorderLayout.CENTER);
167 final JToolBar toolBar =
new JToolBar();
168 toolBar.add(controlStart);
169 toolBar.add(controlStop);
170 toolBar.add(ACTION_BUILDER.createAction(
false,
"controlClear",
this));
172 controlStop.setEnabled(
false);
173 add(toolBar, BorderLayout.SOUTH);
181 public ProcessRunner(@NotNull
final String key, @NotNull
final String[] command) {
182 this(
key,
command,
new File(command[0]).getParent());
190 if (dialog == null || dialog.getOwner() != parent) {
193 assert dialog != null;
194 dialog.setVisible(
true);
195 assert dialog != null;
196 dialog.requestFocus();
206 assert dialog != null;
208 assert dialog != null;
209 dialog.setLocationRelativeTo(parent);
217 this.command = command.clone();
225 synchronized (
lock) {
226 if (process != null) {
229 process.getInputStream().close();
230 }
catch (
final IOException ignored) {
234 process.getErrorStream().close();
235 }
catch (
final IOException ignored) {
239 process.getOutputStream().close();
240 }
catch (
final IOException ignored) {
244 }
catch (
final IllegalThreadStateException ignored) {
245 LOG.error(
"Still running!");
252 process =
new ProcessBuilder(command).directory(dir).redirectErrorStream(
true).start();
253 final InputStream out = process.getInputStream();
254 final InputStream err = process.getErrorStream();
259 controlStop.setEnabled(
true);
260 controlStart.setEnabled(
false);
261 }
catch (
final IOException e) {
262 ACTION_BUILDER.showMessageDialog(
this,
"controlError", e);
272 if (process != null) {
275 controlStop.setEnabled(
false);
276 controlStart.setEnabled(
true);
296 private InputStream
in;
315 private CopyOutput(@NotNull
final String title, @NotNull
final JTextArea textArea) {
324 final byte[] buf =
new byte[4096];
327 final int bytesRead = in.read(buf);
328 if (bytesRead == -1) {
331 appender.
append(
new String(buf, 0, bytesRead));
340 }
catch (
final IOException e) {
341 appender.
append(title,
": ", e.toString());
351 private void start(@NotNull
final InputStream stream) {
353 if (LOG.isInfoEnabled()) {
354 LOG.info(
"Trying to stop previous stream.");
359 }
catch (
final IOException ignored) {
362 if (LOG.isInfoEnabled()) {
363 LOG.info(
"Stopped previous stream.");
368 new Thread(
this).start();
379 private static class Appender implements Runnable {
385 private final Queue<String>
texts =
new ConcurrentLinkedQueue<>();
397 Appender(@NotNull
final JTextArea textArea) {
405 public void append(@NotNull
final String... texts) {
406 for (
final String text : texts) {
407 this.texts.offer(text);
409 SwingUtilities.invokeLater(
this);
414 while (!texts.isEmpty()) {
415 textArea.append(texts.poll());
final Appender appender
JTextArea to write to.
String [] command
The command and arguments.
final CopyOutput stdout
CopyOutput for stdout.
void controlStop()
Action method for stopping.
void start(@NotNull final InputStream stream)
Start running.
final Queue< String > texts
Strings to append.
void showDialog(@NotNull final Frame parent)
Show a dialog if not already visible.
static String getString(@NotNull final ActionBuilder actionBuilder, @NotNull final String key, @NotNull final String defaultValue)
Returns the value of a key.
void controlStart()
Action method for starting.
final CopyOutput stderr
CopyOutput for stderr.
CopyOutput(@NotNull final String title, @NotNull final JTextArea textArea)
Create a CopyOutput.
void createDialog(@NotNull final Frame parent)
Create the dialog.
static final ActionBuilder ACTION_BUILDER
Action Builder.
void setCommand(@NotNull final String[] command)
Set the command to be executed by this ProcessRunner.
final JTextArea textArea
JTextArea to append to.
transient Process process
The Process.
InputStream in
BufferedReader to read from.
void append(@NotNull final String... texts)
Append text to the JTextArea.
Class for SwingUtilities to append text.
final String key
The i18n key.
Utility class for ActionBuilder related functions.
final JTextArea stdtxt
JTextArea with log.
static final Category LOG
The Logger for printing log messages.
static JLabel newLabel(@NotNull final ActionBuilder actionBuilder, @NotNull final String key)
Creates a new JLabel from a resource key.
ProcessRunner(@NotNull final String key, @NotNull final String[] command, @Nullable final String dir)
Creates a ProcessRunner for running the given command in the given directory.
ProcessRunner(@NotNull final String key, @NotNull final String[] command)
Creates a ProcessRunner for running the given command in its directory.
void controlClear()
Action method for clearing the log.
static final long serialVersionUID
Serial Version.
Class for reading data from a stream and appending it to a JTextArea.
final File dir
The working directory for the command.
Class to run an external process.
final Object lock
The lock object for thread synchronization.