# Process - Befehle senden



## spaghettiBolognese (7. Jul 2008)

Hallo Leute,

habe leider ein Problem, dass ich noch nicht lösen konnte und an dem ich fast am verzweifeln bin  ???:L .
Ich versuche an einen _Process_ mehrere Befehle zu senden. Das klappt bei mir aber nicht so ganz wie es soll.

Eine Instanz _Process p_ wird in der Klasse _ConsoleProcess_ gestartet (Singleton-Muster). In der selben Klasse kann ich über eine Methode _execProc_ individuelle Befehle - die nacheinander in dem Process ausgeführt werden sollen - senden.
Das ist die Idee, die dahinter steht. Allerdings funktioniert das nur für den ersten Befehl den ich sende. Führe ich einen weiteren Befehl aus, wird eine Exception geschmissen.

Allerdings weiß ich nicht warum???? (Meine Idee ist, dass der Process beendet wird bevor überhaupt der nachfolgende Befehl ausgeführt wird.)
Hoffentlich könnt ihr mir weiterhelfen - weiß leider nicht mehr weiter.

Anbei der komplette lauffähige Code. Bin wirklich dankbar für jede Hilfe.

Der Code:
*EDIT:* Out- und Inputstreams werden nun nicht mehr geschlossen. + Thread-sichere Methode für execProc()

Klasse *ProcessesMain*

```
import java.io.IOException;

public class ProcessesMain {
	public static void main(String[] args) throws IOException {
		// Get instance of process.
		ConsoleProcess cp = ConsoleProcess.getInstance();
		cp.execProc("include x.grs");
		cp.execProc("show graph ycomp");
		cp.execProc("debug enable");
		cp.execProc("debug disable");
	}
}
```

Klasse *ConsoleProcess*

```
import java.io.IOException;

/** This class handles one started process. */
public class ConsoleProcess {
	/** A process to run the GrShell in a command prompt (DOS console). */
	private Process p;
	/** The single instance of ConsoleProcess. */
	private static ConsoleProcess cp;

	private ConsoleProcess() { // A private constructor - a singleton pattern
		initProc();
	}

        /* Returns instance of process console. */
	public static ConsoleProcess getInstance() {
		if (cp == null) {
			cp = new ConsoleProcess();
		}
		return cp;
	}

        /* Create the process builder to start the process. */
	private void initProc() {
		if (p == null) {
			// Start a command process. Currently only Windows based
			// operating systems are supported.
			ProcessBuilder pb = new ProcessBuilder("grshell");
			try {
				p = pb.start();
			} catch (IOException e) {
				System.err
						.println("ERR: ProcessBuilder did not start the process.");
				System.err.println(e.getMessage());
			}
		}
	}

        /* Sends and executes a command. Will be executed within threads (StreamChoker + StreamGobbler). Thread-safe*/
	public synchronized void execProc(String cmd) {
		// Append an 'ENTER'-key to execute command ( \r\n = ENTER )
		String str = cmd + " \r\n";
		StreamChoker c = new StreamChoker(str, p.getOutputStream());
		c.start();
		// Print results on screen.
		StreamGobbler s1 = new StreamGobbler(p.getInputStream());
		StreamGobbler s2 = new StreamGobbler(p.getErrorStream());
		s1.start();
		s2.start();
	}
}
```

Klasse *StreamChoker*

```
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class StreamChoker implements Runnable {
	/** The output stream of a process to write to the command prompt. */
	private final OutputStream os;
	private final String cmd;
	private Thread thread;
	
	public void start() {
		thread = new Thread(this);
		thread.start();
	}
	
	public StreamChoker(String cmd, OutputStream os) {
		this.os = os;
		this.cmd = cmd;
	}

	/**
	 * Runs the thread. Emit and execute the command to the output stream into the console.
	 */
	@Override
	public void run() {
		BufferedOutputStream bos = new BufferedOutputStream(os);
		
		try {
			bos.write(cmd.getBytes());
			bos.flush();
		} catch (IOException e) {
			System.err.println("ERR: Invalid entering sequence." + " '" + cmd + "'  not be executed." );
			System.err.println(e.getMessage());
		}
	}

}
```

Klasse *StreamGobbler*

```
import java.io.BufferedReader;
import java.io.IOException;

import java.io.InputStream;
import java.io.InputStreamReader;

public class StreamGobbler implements Runnable {
	/** The input stream of a process to read the command prompt. */
	private final InputStream is;
	private Thread thread;
	
	public void start() {
		thread = new Thread(this);
		thread.start();
	}
	
	public StreamGobbler(InputStream is) {
		this.is = is;
	}

	/**
	 * Runs the thread. Prints the process's input stream on the console.
	 */
	@Override
	public void run() {
		InputStreamReader isr = new InputStreamReader(is);
		BufferedReader br = new BufferedReader(isr);
		
		String str;
		try {
			while ((str = br.readLine()) != null) {
				System.out.println(str);
			}
		} catch (IOException e) {
			System.err.println("ERR: Invalid reading sequence.");
			System.err.println(e.getMessage());
		}
	}

}
```


----------



## SlaterB (7. Jul 2008)

in Zeile 37 von StreamChoker wird der übergebene p.getOutputStream() geschlossen,
danach kannst du logischerweise nichts mehr reinschreiben


----------



## spaghettiBolognese (7. Jul 2008)

Wo du recht hast, hast du recht. Danke für die schnelle Info.
Ich war in der Annahme, dass ich nach jedem gesendeten Befehl den Outputstream neu erzeugen könnte. Ist aber nicht der Fall, steht auch in der API - hätt ich die bloß gelesen.

Danke  :applaus:


----------



## spaghettiBolognese (7. Jul 2008)

Noch ne kleine Frage?
Beim Senden von mehreren Befehlen (execProc()), geraten wohl die Threads durcheinander, siehe ProcessesMain.
Wie kann ich die Methodenaufrufe in der vorgegebenen Reihenfolge auszuführen???

Ich habe bereits die Methode execProc() in der Klasse ConsoleProcess synchronisiert.


----------



## SlaterB (7. Jul 2008)

tja, kannst du ein Anfang und Ende bei solchen Aufgaben feststellen, vor allem das Ende?

die einzelnen Aufgaben müssen vielleicht kein Thread sein sondern Aufgaben-Objekte,
die von einem bestimmten Arbeitsthread in Reihenfolge bearbeitet werden,

für die Ausgabe reichen dann vielleicht nur zwei Threads, 
die StreamGobbler haben ja eh nix direkt mit dem einzelnen Befehl zu tun


----------



## Gast2 (7. Jul 2008)

Moin,



			
				spaghettiBolognese hat gesagt.:
			
		

> Noch ne kleine Frage?
> Beim Senden von mehreren Befehlen (execProc()), geraten wohl die Threads durcheinander, siehe ProcessesMain.
> Wie kann ich die Methodenaufrufe in der vorgegebenen Reihenfolge auszuführen???



mit einer Queue ... ungefährt so 

1 ... schaue ob in der Queue was drinnen ist
2 ... hole Dir die Aufgabe vom anfang
3 ... führe sie aus
4 ... zurück zu 1

hand, mogel


----------



## diggaa1984 (7. Jul 2008)

sieht aus wie busy-waiting  :autsch:


----------



## Gast2 (7. Jul 2008)

Moin,



			
				diggaa1984 hat gesagt.:
			
		

> sieht aus wie busy-waiting  :autsch:


wo? ... bei 1 ... da fehlt noch "sonst beende" ... busy waiting sehe ich da nirgends

hand, mogel


----------



## diggaa1984 (7. Jul 2008)

mogel hat gesagt.:
			
		

> da fehlt noch "sonst beende"



naja wenn da fehlt dann siehts aber aus wie busy-waiting


----------



## Gast2 (8. Jul 2008)

Moin,



			
				diggaa1984 hat gesagt.:
			
		

> mogel hat gesagt.:
> 
> 
> 
> ...



gut ... ich ging davon aus das der OP sein Handwerk versteht und er nur einen gedanklichen Anstoß benötigte

hand, mogel


----------



## Guest (8. Jul 2008)

@*SlaterB*

Nein, der Anfang und das Ende steht nicht fest.

Habe die execProc()'s nur versuchsweise aufgestellt. Der eigentliche Sinn des ganzen Programms ist folgender:

In der IDE Eclipse habe ich eine eigene Perspektive mit verschiedenen Buttons entwickelt. Über diese Buttons sollen verschiedene Befehle an den Prozess gesendet werden.
Da der User hier interagiert wie er Lust und Laune hat ist mir kein Anfang und kein Ende bekannt. Anfang ist dann, wenn einer der Buttons geklickt wird. Das Ende ist wohl ein openEnd bis Eclipse geschlossen wird  :?: 

Aber die Frage die sich mir dabei stellte: Was passiert wenn der User ziemlich oft und ziemlich schnell innerhalb kurzer Zeit verschiedene Befehle sendet. Kommen dann die Threads durcheinander???? Das ist ja unerwünscht.

Beispiel:
10x "show graph"
 3x "delete graph"
 6x "debug enable"
 1x "show graph"


----------



## spaghettiBolognese (8. Jul 2008)

@*SlaterB*

Nein, der Anfang und das Ende steht nicht fest.

Habe die execProc()'s nur versuchsweise aufgestellt. Der eigentliche Sinn des ganzen Programms ist folgender:

In der IDE Eclipse habe ich eine eigene Perspektive mit verschiedenen Buttons entwickelt. Über diese Buttons sollen verschiedene Befehle an den Prozess gesendet werden.
Da der User hier interagiert wie er Lust und Laune hat ist mir kein Anfang und kein Ende bekannt. Anfang ist dann, wenn einer der Buttons geklickt wird. Das Ende ist wohl ein openEnd bis Eclipse geschlossen wird :?: 

Aber die Frage die sich mir dabei stellte: Was passiert wenn der User ziemlich oft und ziemlich schnell innerhalb kurzer Zeit verschiedene Befehle sendet. Kommen dann die Threads durcheinander???? Das ist ja unerwünscht.

Beispiel:
10x "show graph" - Button
3x "delete graph" - Button
6x "debug enable" - Button
1x "show graph" - Button


----------



## SlaterB (8. Jul 2008)

also ich kann nur mit Fakten arbeiten,
wie du beliebige unkontrolliert lange laufende Prozesse sortierst weiß ich nicht


----------



## Guest (8. Jul 2008)

Ich auch (noch) nicht. Aber wenns soweit ist, kann ich dich ja beraten  :wink: 

Danke auf jeden Fall für die Antworten.


----------

