Java receives an error executing Ruby script; Terminal doesn't - java

This is a forked problem off of this question: flac: "ERROR: input file has an ID3v2 tag" (it doesn't). I've solved the initial issue there but that didn't resolve one problem I was having, so I'm going to introduce it separately here.
I'm using a Ruby gem called speech2text to convert an audio file into (approximated) text. Calling it on the command line works fine (Mac Terminal). However, the following Java code:
String[] cmd = {"speech2text", "tmp/audio/pop-test-audio.wav"};
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.redirectErrorStream(true);
Process process = builder.start();
Only receives this back from the process streams:
/Library/Ruby/Gems/1.8/gems/speech2text-0.3.4/lib/speech/audio_inspector.rb:50:in `initialize': undefined method `first' for nil:NilClass (NoMethodError)
from /Library/Ruby/Gems/1.8/gems/speech2text-0.3.4/lib/speech/audio_splitter.rb:77:in `new'
from /Library/Ruby/Gems/1.8/gems/speech2text-0.3.4/lib/speech/audio_splitter.rb:77:in `initialize'
from /Library/Ruby/Gems/1.8/gems/speech2text-0.3.4/lib/speech/audio_to_text.rb:15:in `new'
from /Library/Ruby/Gems/1.8/gems/speech2text-0.3.4/lib/speech/audio_to_text.rb:15:in `to_text'
from /Library/Ruby/Gems/1.8/gems/speech2text-0.3.4/bin/speech2text:11
from /usr/bin/speech2text:19:in `load'
from /usr/bin/speech2text:19
I don't know anything about Ruby, hence my lightweight use of the library through Java. I really can't tell what's going on here, but I know that it works when executed in exactly the same way from the Terminal. Has anyone got any idea what might be causing this?

You could also ditch the terminal and try JRuby. It's just as fast as the normal Ruby VM and is easier to integrate with Java.

I have had similar issues trying to run jslint.js (for node.js). I actually did better running bash first, then print writing in my commands that way, but even that had problems as I recall.
Basically the problem is that executing things with Java can fail when environment settings that would otherwise be available are not loaded. This can be a tough one to solve.

Related

Java/python using processBuilder

Good evening all,
am running a python script inside java using processBuilder.
the python script returns a list and i dont know how to get it java and use it since all i can do for the moment with process builder is print errors or outputs.
is it possible to get the list in java as well.
Many thanks
From your scenario, you are looking for inter process communication.
You can achieve this using shared file. Your python script will write the output in text file, and your java program will read the same file.

Trying to run octave through Runtime.exec in a JSF application

Ok, so my situation is as follows: I NEED to run a .mod file (a mathematical model) in Octave (a mathematical program used for advanced calculations), get its result and return for the user THROUGH a webapp.
Not that much really, I have a application that run as smoothly as one would need on my windows enviro (development enviro, I developed it using Glassfish 4.0 and Eclipse) with the following code:
...
Process p = rt.exec("C:\\Octave\\Octave3.6.4_gcc4.6.2\\bin\\octave.exe --eval \"cd "
+ actingFolder + "; dynare code.mod; save -text saida.txt; exit\"");
InputStream in = p.getInputStream();
while(in.read != -1);
...
However, when I migrate it to the linux envior (Debian GNU/Linux 7, using a Glassfish 4.0 as the AppServer) and adjust the code to run in the said system it stopped working! Follows the code which I'm currently trying to run:
...
p = rt.exec("/bin/bash -c /root/octave --eval \"cd "
+ actingFolder + "; dynare code.mod; save -text saida.txt; exit\" --silent");
InputStream in = p.getInputStream();
while(in.read() != -1);
...
When this code runs it never ends: in.read() never returns -1 (InputStream code for the end of execution) so it never stops... Also, when octave is run it generates several exit files and none of them has been created, to what I assume that either the program wasn't able to be started or, for some reason, it was denied for the webApp to create the files as an output of the Octave application... I don't really know...
could you guys give me a hand?
and
P.S.:
I'm running this application through runtime because I know no better way in order to make Octave interpret the .mod. If there's another sollution I would really aprecciate it too.
UPDATE
I tested througly and I can 100% guarantee that the application has the rights to create files in the server and Octave has full rights on my system... I should be able to run it correctly, right?
I also was able to verify that no: the program generates no errors on running the String on shell. In fact, even seems that it ignores the call on shell and goes on with the application, this imply 2 things: InputStream is returning -1 (ending correctly) and for some reason Octave isn't starting...
Any thoughs on why could this be?
And yes, Octave and all it's dependencys are installed correctly and I, myself, can manually call it from shell.
UPDATE2
Now I'm getting what is happening!
Still trying to grasp everything at http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html?page=2 however I was able to understand some things by running the "TestExec" program in that guide.
First of all, at least in my situation, Runtime.Exec() WILL ALWAYS run the program at the beggning of the String. He them proceeds to try to feed the said program with the suplyied String, taking each space as if it was a line-break and feeding the program with it 'till an error or termination.
In my case he received "--eval", which is a Octave command, and as it was without any arguments it was ignored. Then it received "cd\"" and it caused and error, as it's not a Octave command without any address and caused the input to stop.
So this explains why it didn't caus any error in the execution (the error was handled by octave, thus not raising any Exception) and why nothing happened after the end of the proccess.
I'm working now on finding out how to input commands to Octave during execution.

Java runtime.exec causes program crash

I am trying to run an external program Decoder.exe using a java:
Runtime.getRuntime().exec("C:\fullpath-and-so-on\Decoder.exe -h"); like so:
try{
Process p = Runtime.getRuntime().exec("C:\\fullpath-and-so-on\\Decoder.exe -h");
}
catch(Exception e){
e.printStackTrace();
}
This works for all other programs I've tried. But whenever I execute it from java the Decoder.exe crashes. The java executes fine and does not generate any exceptions but the called program Decodes.exe stops working. The program Decoder.exe executes perfectly when run in a separate cmd window.
Have anyone had any experience with a similar problem? What differs when java runs exec and when a program is run in cmd.exe? Is there a known workaround or am I just making a mistake somewhere?
Very thankful for any help!
BR,
Fredrik
Stops working you say?
Is the decoder.exe writing output to stderr or stdout? You must in that case read those streams, since the buffers for the streams are very small, and the execution will halt if those buffers get full.
This is a great article, it's old, but it still holds:
When Runtime.exec() won't
this tutorial can help you with that http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=1
and
ProcessBuilder
and
Oracle API
maybe my question Pass String as params from one Java App to another

Permission error while trying to access an (server) program started by a Java program

I am starting a server application (normally to be started from the Unix command line) by using Runtime.getRuntime().exec("path/mmserver"). My problem is now that as long as my Java program, which started that server runs, the server is correctly accessible (from command line and other programs). But when my Java program exits the sever is not accessible anymore (the process of the server is still running). I just get such a error message when trying to access the server: "Error: permission_error(flush_output(user_output),write,stream,user_output,errno(32))".
The server is a blackbox for me.
I am just looking for other ways to start a new process. And maybe someone has a hint why I get that permission error (even if one doesn't know what that server exactly is ... you rather won't know it).
I'm guessing your server program is trying to write to standard output or perhaps standard error (System.out / System.err in Java terms) which it implicitly inherited from your Java program but which turn into pumpkins when your Java program goes away.
A simple solution might be for your Java program to exec a shell script which starts your server as a background process (using START (Windows) or & (Unix)) with explicitly redirected I/O streams.
The Java library has recently gotten some nice updates to the Process class (I think) that allow you to do a lot of fiddling with the streams, but I don't have much experience there so I can't offer a detailed suggestion.
EDIT: My suggestion from the middle paragraph. Untested, sorry!
File server-runner.sh:
#!/bin/bash
/path/mmserver >/dev/null &
You'll need to chmod +x server-runner.sh, of course.
Then, from your Java program, you exec the script server-runner.sh rather than your mmserver.
If you want to kill mmserver, you'll have to find it in ps -ux and use kill on the process number.

Can I find the console width with Java?

Is there a way to find the width of the console in which my Java program is running?
I would like this to be cross platform if possible...
I have no desire to change the width of the buffer or the window, I just want to know its width so I can properly format text that is being printed to screen.
There are no reliable cross-platform solutions to this problem. Indeed, there are situations where it is not possible to know what the real console width is.
(See other answers for approaches that work some of the time and/or on some platforms. But beware of the limitations ...)
For example, on a Linux system you can typically find out the notional terminal dimensions from the LINES and COLUMNS environment variables. While these variables are automatically updated when you resize some "terminal emulator" windows, this is not always the case. Indeed, in the case of a remote console connected via telnet protocol, there is no way to get the actual terminal dimensions to the user's shell.
EDIT: Just to add that if the user changes the dimensions of his/her xterm on Linux after launching a Java app, the Java app won't be notified, and it won't see the new dimensions reflected in its copy of the LINES and COLUMNS environment variables!
EDIT 2: My mistake: LINES and COLUMNS are bash shell variables, and they are not exported to the environment by default. You can "fix" this by running export COLUMNS LINES before you run your Java application.
Actually, a Java library already exists to do this in Java: JLine 2. (There's an old version on SourceForce, but that link to GitHub seems to be the latest.)
This worked for me under Linux (Mint 14) and Windows (I don't know what version), using JLine 2.11:
terminalWidth = jline.TerminalFactory.get().getWidth();
JLine promises to work on Mac, too.
I've found that it returns bad widths (like 1!) under the Eclipse console (but even Java's native Console doesn't work under Eclipse!), and, unfortunately, under Cygwin. But I've worked around this with code that checks for unreasonable values (< 10) and just uses 80 in those cases.
Update for JLine 3 (per Mark—thanks, mate!):
terminalWidth = org.jline.terminal.TerminalBuilder.terminal().getWidth()
There's a trick that you can use based on ANSI Escape Codes. They don't provide a direct way to query the console size, but they do have a command for requesting the current cursor position. By moving the cursor to a really high row and column and then requesting the cursor position you can get an accurate measurement.
Combine this with commands to store/restore the cursor position, as in the following example:
Send the following sequences to the terminal (stdout)
"\u001b[s" // save cursor position
"\u001b[5000;5000H" // move to col 5000 row 5000
"\u001b[6n" // request cursor position
"\u001b[u" // restore cursor position
Now watch stdin, you should receive a sequece that looks like \u001b[25;80R", where 25 is the row count, and 80 the columns.
I first saw this used in the Lanterna library.
Update:
There are really four different ways that I know of to achieve this, but they all make certain assumptions about the environment the program is running in, or the terminal device/emulator it is talking to.
Using the VT100 protocol. This is what this solution does, it assumes you are talking over stdin/stdout to a terminal emulator that honors these escape codes. This seems like a relatively safe assumption for a CLI program, but e.g. if someone is using cmd.exe this likely won't work.
terminfo/termcap. These are databases with terminal information, which you can query for instance with tput. Operating system dependent, and assumes you are connected to a TTY device. Won't work over ssh for instance.
Using the telnet protocol. Telnet has its own affordances for querying the screen size, but of course this only works if people connect to your application via the telnet client, not really an option in most cases.
Rely on the shell (e.g. bash), this is what solutions that use COLUMNS/ROWS variables do. Far from universal, but could work quite well if you provide a wrapper script for your app that makes sure the necessary env vars are exported.
Edit: See #dave_thompson_085's comment about ProcessBuilder, as that's almost certainly a better approach.
Another answer mentioned running tput cols in a script before you start your command. But if you want to run that after Java has already started, using Runtime.getRuntime().exec(), you'll find that tput can't talk to your terminal, because Java has redirected stdout and stderr. As a not-at-all-portable workaround, you can use the magical /dev/tty device, which refers to the terminal of the current process. That lets you run something like this:
Process p = Runtime.getRuntime().exec(new String[] {
"bash", "-c", "tput cols 2> /dev/tty" });
// Read the output of this process to get your terminal width
This works for me on Linux, but I wouldn't expect it to work everywhere. It will hopefully work on Mac. It definitely won't work on Windows, though it might with Cygwin.
Java 6 has a class java.io.Console, but it unfortunately lacks the functionality you're asking for. Getting the console window width is not possible with the standard Java library and pure, cross-platform Java.
Here is an alternative Java console library which allows you to get the screen size, but it includes a Windows-specific DLL. You might be able to take the source code and compile the C part into a Linux or Mac OS X shared library, so that it will work on those platforms as well.
I have been working on this problem before. I use a couple of different techniques. However it is difficult to have a truly cross platform solution.
I tried doing try something like this:
String os = System.getProperty("os.name").toLowerCase();
//Windows
if(os.contains("win")){
System.out.append("Windows Detected");
//set Windows Dos Terminal width 80, height 25
Process p = Runtime.getRuntime().exec("mode 80, 25");
}
//Mac
if(os.contains("mac")){
System.out.println("Macintosh Detected");
//... I dont know...try Google
}
//Linux
if(os.contains("linux")){
System.out.println("Linux Detected");
You can read/test and append "export COLUMNS" to the .bashrc file in every Linux users home directory with the String.contains("export COLUMNS") method and the user.dir property.
That would allow you to get the columns to load up every time the java app starts up.
Then I would pass it to a temp file. Like this:
try {
ProcessBuilder pb = new ProcessBuilder("bash","-c","echo $COLUMNS >/home/$USER/bin/temp.txt" );
pb.start();
}catch (Exception e) {
System.out.println("exception happened - here's what I know: ");
e.printStackTrace();
System.exit(-1);
}
}
Another option you have is to execute yor Java.jar with a bash script at startup. Inside the script you can use "tput cols" to get the width. Then pass that value to your Java app as a String[] arg.
Like so:
//#!/bin/bash
//#clear the screen
clear
//#get the console width and height
c=$[$(tput cols)]
l=$[$(tput lines)]
//#pass the columns, lines and an optional third value as String[] args.
java -jar ~/bin/Plus.jar $c $l $1
why is this such a difficult task with Java? Obviously a good place to write a good API. I guess we could try Apache.commons.exec as well?
For me, the only way to get an idea of the terminal window (still not correct when the window resizes) is to use a command like
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", "mode con");
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
When run without the cmd.exe part, it shows that the command could not be found. Also note the redirectError part. If not used then the Java output size will be used, not the actual one. Only with this combination it was possible to grab the actual size.
Python seems to have a good solution: 11.9.3. Querying the size of the output terminal. I wouldn't hold my breath waiting for this to be available in core Java, but you might be able to use Jython to make the Python functionality available.

Categories

Resources