I'm trying to write a little application that would automate the use of an external application which is cisco any connect mobility client. It provides a command line tools that you can use to connect to your VPN.
I want to run this command line tools from my java application using apache commons-exec library and be able to read his output to send needed information.
I already searched on the net to find "how to communicate" with an external application but the only post I found was this article : Trouble providing multiple input to a Command using Apache Commons Exec and extracting output where it just says "hey I found the solutions", but I don't understand how he did it.
When I start the process, I run a function that read the input like this :
Thread T = new Thread() {
public void run() {
String line;
try {
line = processOutput.readLine();
while (line != null) {
System.out.println(line);
if(line.contains("VPN-Password")){
sendMessage(processInput, "1");
}
if(line.contains("Please enter your username and password")){
sendMessage(processInput, "username");
}
line = processOutput.readLine();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
T.start();
the function send message just run a thread to write in the process inputstream then flush it.
Thread T = new Thread() {
public void run() {
try {
os.write((message+"\n").getBytes());
os.flush();
System.out.println("SENT : "+message);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
T.start();
As you can see I check the output to send a message to the process depending on it (basicly to answer questions). However, when it comes to the "Please enter...", I got this exception
java.io.IOException: Read end dead
My issue is that I can't find how to "communicate" with the process by reading his output and sending it messages depending on what it tells me.
Can you help me ?
Thanks for reading.
Related
I'm trying to find a way to establish a stdout-based communication between my java program (chess engine) and an external program (chess gui). It's important to notice that the external program is starting my java-app with a little bash script executing the .jar file. The java-app should be able to send commands to the external program through stdout. At the moment, only the communication from external program to java is working.
This is what I tried:
try {
log = new FileWriter("log.txt");
} catch (IOException e) {
System.out.println("IOException on initializing FileWriter 'log'.");
}
while (true) {
try {
stringInput = input.readLine();
} catch (IOException ex) {
System.out.println("IOException on reading Buffered Reader 'input'.");
}
if (stringInput != null){
try {
log.write(stringInput + "\n");
} catch (IOException ex){
System.out.println("IOException on writing to FileWriter 'log'.");
}
switch (stringInput){
case "uci\n":
System.out.println("uciok");
break;
}
} else {
break;
}
}
I expect the java program to store incoming commands in the log.txt file, while I should be able to see commands coming from the java-app in the debugging console of the external program.
log.txt indeed is storing incoming commands.
There's no trace of output from the java-app being received by the external program though.
If someone have an actual solution to this problem i would much appreciate it. So far all implementation that I have used close the session as soon as one of the channel is "connected" what ever that means. Like most i need to be able to script ssh interaction meaning that i need the result of my operation with a still alive channel I'm not looking for a command with "cmd1;cmd2;cmd3" type ..
The best example I can think of is if you were trying to browse trough a file system.
If each command is a new session you would be going going no where since at each new session you go back to square one.
In command line the ssh session remain open when you type an operation why all java implementation differ so much from this approach is beyond me. My next step if i cant find an answer is actually to use command shell from java and interacting from there instead of using java ssh libraries..
public void connect() {
Session session;
try {
session = createConnectedSession();
java.util.logging.Logger.getLogger("test").log(Level.INFO,"isConnected "+session.isConnected());
ByteArrayOutputStream output = new ByteArrayOutputStream();
Channel channel = session.openChannel("shell");
channel.setOutputStream(output);
PrintStream ps = new PrintStream(channel.getOutputStream(), true);
// InputStream is = new InputStream(channel.getInputStream());
channel.connect();
sleep();
java.util.logging.Logger.getLogger("test").log(Level.INFO,"isConnected "+session.isConnected());
Stack<String> mstack = getCommandStack();
//readChannel(channel);
while (!mstack.isEmpty()) {
String cmd = mstack.pop();
java.util.logging.Logger.getLogger("test").log(Level.INFO,"sending command "+cmd);
ps.println(cmd);
sleep();
System.out.println(output.toString());
java.util.logging.Logger.getLogger("test").log(Level.INFO,"command result"+output.toString());
sleep();
// System.out.println(output.toString());
ps.flush();
}
channel.disconnect();
session.disconnect();
} catch (JSchException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I just started using RCP to write Java-based applications. I am trying to add a console view in my app, and output info of log4j to the console. Now it works. But there is a problem, it cannot perform as eclipse witch output once per line, but output all info after the method finish.
Object[] elements = tableViewer.getCheckedElements();
if(elements.length > 0){
for(Object ele : elements){
File file = (File) ele;
logger.info("log4j处理目录" + file.getAbsolutePath());
MessageConsoleStream stream = ConsoleFactory.getConsole().newMessageStream();
stream.println("println处理目录" + file.getAbsolutePath());
try {
stream.flush();
stream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I tried use stream.println() stream.flush(), but it does not work.
It is my first time questing on stackoverflow. Sorry for my english.
Calling Thread.sleep(1000) in the User Interface Thread will block the entire UI and nothing will happen. Never do this.
If you want to do something once a second use the timerExec method of Display to run code.
Something like:
Display.getDefault().timerExec(1000, new Runnable() {
#Override
public void run()
{
// TODO output one item to the log
// TODO if need to run again call
Display.getDefault().timerExec(1000, this);
}
});
The JavaDoc for MessageConsoleStream says:
Clients should avoid writing large amounts of output to this stream in
the UI thread. The console needs to process the output in the UI
thread and if the client hogs the UI thread writing output to the
console, the console will not be able to process the output.
So you must not loop constantly outputting to the stream without letting other code in the UI thread run.
i wanted to read the output-stream of a c-Application in my Java program. iremoted (available here: Link) is a C-Application that puts out seperate lines like "0x19 pressed" if a button on my Apple Remote is pressed. If i start the iremoted program everything is doing well and these separate lines are shown on my screen everytime I pressed a button.
Now I wanted to read the output-stream of the c-application in my Java application to process inputs of the Apple Remote in Java projects.
Unfortunately i don't know why no input is regocnized?
I tried it with a simple HelloWorld.c program and my program responded as intended in this case (prints out HelloWorld).
Why doensn't it work with the iremoted program?
public class RemoteListener {
public void listen(String command) throws IOException {
String line;
Process process = null;
try {
process = Runtime.getRuntime().exec(command);
} catch (Exception e) {
System.err.println("Could not execute program. Shut down now.");
System.exit(-1);
}
Reader inStreamReader = new InputStreamReader(process.getInputStream());
BufferedReader in = new BufferedReader(inStreamReader);
System.out.println("Stream started");
while((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
System.out.println("Stream Closed");
}
public static void main(String args[]) {
RemoteListener r = new RemoteListener();
try {
r.listen("./iremoted"); /* not working... why?*/
// r.listen("./HelloWorld"); /* working fine */
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
stdout is buffered and it's not automatically flushed if you are not writing to screen. Add:
fflush(stdout);
after:
printf("%#lx %s\n", (UInt32)event.elementCookie,
(event.value == 0) ? "depressed" : "pressed");
iremoted is likely writing to stderr if a hello world program works. You would want the error stream in that case. I'm not sure how this works for your hello world case - I think you're doing the wrong thing here:
new InputStreamReader(process.getInputStream());
should be
new InputStreamReader(process.getOutputStream());
or
new InputStreamReader(process.getErrorStream());
I want to run an interactive command with apache commons exec. Everything works except that when my command is executed and waits for user input I don't see my input in the console until I press enter which makes it effectively unusable.
This is an example of an interactive program:
public static void main(String[] args) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while (true) {
System.out.print("=> ");
try {
line = in.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(line);
}
}
Now I want to execute that with apache commons exec like this:
public static void main(String[] args) {
Executor ex = new DefaultExecutor();
ex.setStreamHandler(new PumpStreamHandler(System.out, System.err, System.in));
CommandLine cl = new CommandLine("java");
cl.addArguments("-cp target\\classes foo.bar.Main");
try {
ex.execute(cl);
} catch (ExecuteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
As I said, it basically works, I get the "=>" prompt but when I type something I don't see it until I hit enter. I'm doing this on windows 7 with a cmd prompt.
I'd appreciate any hint on how to achieve the desired behaviour.
Edit: It works as expected on linux. I guess this is an issue with the windows cmd prompt. I'd still like to make this work if at all possible, so I would appreciate any insight into this behaviour on windows.
Edit2: I also tested with msys shell and powershell, both exhibit the same problem.
Edit3: I worked around the issue by launching a seperate cmd prompt. This works, but I still like to understand why.
CommandLine cl = new CommandLine("cmd");
cl.addArguments("/C java -cp target\\classes foo.bar.Main");
thanks
Raoul
I'm not sure exactly what you were expecting to happen here; if the spawned process is designed to wait to read from its input, then it shouldn't be surprising when it does exactly that?
If that's the issue, and your question is "How can I make my program automatically send a newline character to the spawned process' input?", then you'll need to define an OutputStream to write the input to, and get hold of the ExecuteStreamHandler to attach it to the process. Something like the following:
Executor ex = new DefaultExecutor();
// Create an output stream and set it as the process' input
OutputStream out = new ByteArrayOutputStream();
ex.getStreamHandler().setProcessInputStream(out);
...
try
{
ex.execute(cl);
out.write("\n".getBytes()); // TODO use appropriate charset explicitly
...
Using Apache exec org.apache.commons.exec.DefaultExecuteResultHandler you can launch a non-blocking command. And then you can follow the steps #Andrzej mentioned.