[erlang-questions] Best way to interface Erlang with Java code

Jayson Vantuyl kagato@REDACTED
Mon Dec 7 05:51:18 CET 2009


I've been watching this thread and something's been nagging at me but I couldn't remember what it was.  I remembered.  I almost never use os:cmd, but use erlang:open_port/2 instead.

It turns out you can do something like this:

> Command = "my command executable",
> Args = ["arg1","arg2","arg3"],
> Cwd = "/some/directory",
> Env = [ {"some_var","some_val"}, {"other_var","other_val"} ],
> Port = open_port( {spawn_executable, Command}, [ {args,Args}, {cd, Cwd}, {env,Env}, exit_status ] ).

This is pretty handy because:

* It doesn't go through the shell unless you explicitly make it do so.
* Commands or paths containing spaces are not a problem.
* Args with spaces are not a problem.
* Full control over the environment and cwd.
* All data comes in as Erlang messages that can be "received".

There are also a number of other options I didn't use which are quite handy:

* Packet-mode: If you control the program being run, you can prepend chunks of data with their length and you don't have to worry about framing or partial reads.
* Line-mode: Data is sent a line at a time.
* EOF detection: You can receive a message when the file is closed.
* You can set arg0, which is handy for some programs (busybox comes to mind).
* nouse_stdio: Allows you to use file descriptors other than 0 and 1 to communicate with Erlang.
* stderr__to_stdout: Easily captures stderr without any shell trickery.
* binary: Get all data as binaries, this is exceptionally nice with packet mode.
* hide: hides console window when using Windows

Depending on your willingness to modify the Java program, you might be able to greatly simplify what you're doing.  I suspect that it won't even require any regexps.

Of the top of my head, I'd be inclined to use line mode, and take each line at a time.  Then you just receive a bunch of {eol,Line} messages, with a {Port,{exit_status,Status}} message at the end.  If you want to make it a bit more sophisticated, you could use packet mode with similar results.

Also, have you looked at jinterface?  It can be a Java program appear as an Erlang node.

On Dec 6, 2009, at 8:00 PM, Michael McDaniel wrote:

> and another using extra re features  ...
> 
> 
> 1> Cmd = "java transform animals.txt ; echo $?" .
> "java transform animals.txt ; echo $?" .
> 2> {match, [Val,Ret]} = 
>             re:run( os:cmd(Cmd),
>                     "(?<VAL>.*)(?<RETCODE>[0-9])\\n$", 
>                     [dotall,ungreedy,{capture,['VAL','RETCODE'],list}]).
> {match, ["Cat\nShark\n...", "1"]}
> 3> Ret.
> "1"
> 4> Val.
> "Cat\nShark\n..."
> 5> re:split(Val, "\n", [{return,list}]).
> ["Cat", "Shark", ...]
> 
> 
> the above presumes single digit return codes
> 
> os:cmd/1 is not the only tool to get other program output; e.g. running
> via a port, or using jinterface.  Or maybe the new NIF experimental
> feature in R13B03.
> 
> 
> ~M
> 
> 
> On Sun, Dec 06, 2009 at 07:13:52PM -0800, Michael McDaniel wrote:
>> one way ...
>> 
>> 
>> 1> L = re:split (os:cmd ("java transform animals.txt ; echo $?"), "\n").
>> [<<"Cat">>,
>> <<"Shark">>,
>> ........                  % a lot of animal names here (more than 1000)
>> <<"Wolf">>,
>>  <<"1">>,<<>>]
>> 
>> 2> Ret = lists:nth( 2, lists:reverse( L ) ) .
>> <<"1">>
>> 3> case Ret
>> 3> of <<"0">> -> do_something ;
>> 3> _          -> do_something_else
>> 3> end.
>> failure
>> 
>> 
>> read up on lists and re modules for different ways of playing with
>> the output
>> 
>> ~Michael
>> 
>> 
>> On Mon, Dec 07, 2009 at 03:37:25AM +0100, zabrane Mikael wrote:
>>> Hi Michael !
>>> 
>>> I found a subtle problem when trying your solution when my program returns a
>>> text with one or more "\n".
>>> 
>>> Eg:
>>> 1> re:split (os:cmd ("java transform animals.txt ; echo $?"), "\n").
>>> [<<"Cat">>,
>>> <<"Shark">>,
>>> ........                  % a lot of animal names here (more than 1000)
>>> <<"Wolf">>,
>>> <<"1">>,<<>>]
>>> 2>
>>> 
>>> How then can I distinguish between my program output and the error code
>>> (which is at the end of the list) ?
>>> 
>>> Thanks
>>> Zabrane
>>> 
>>> 2009/12/5 Michael <erlangy@REDACTED>
>>> 
>>>> on my Linux box ...
>>>> 
>>>> $ erl
>>>> Erlang R13B03 (erts-5.7.4) [rq:1] [async-threads:0] [hipe]
>>>> [kernel-poll:false]
>>>> 
>>>> Eshell V5.7.4  (abort with ^G)
>>>> 1> re:split(os:cmd("java x ; echo $?"),"\n").
>>>> [<<"Exception in thread \"main\" java.lang.NoClassDefFoundError: x">>,
>>>> <<"1">>,<<>>]
>>>> 2>
>>>> 
>>>> 
>>>> On Sat, Dec 05, 2009 at 06:27:24PM +0100, zabrane Mikael wrote:
>>>>> Hi Sean !
>>>>> 
>>>>> Ok I see. But how then cal I handle error code in Erlang if my Java
>>>> program
>>>>> crash or returns something different from error code 0?
>>>>> 
>>>>> Thanks
>>>>> Zabrane
>>>>> 
>>>>> 2009/12/5 Sean Cribbs <seancribbs@REDACTED>
>>>>> 
>>>>>> zabrane Mikael wrote:
>>>>>> 
>>>>>>> Hi List !
>>>>>>> 
>>>>>>> I've a small program written in "Java" which take a filename (input),
>>>>>>> proceed it, and print out
>>>>>>> a text (output).
>>>>>>> 
>>>>>>> What's the best way to be able to access to that program from Erlang?
>>>>>>> My whish is get back the "output" as an Erlang binary.
>>>>>>> 
>>>>>>> Thanks
>>>>>>> Zabrane
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>> Use os:cmd/1, which returns a string/list -
>>>>>> http://erldocs.com/R13B03/kernel/os.html?search=os&i=5
>>>>>> 
>>>>>> Sean
>>>>>> 
>>>> 
>>>> ________________________________________________________________
>>>> erlang-questions mailing list. See http://www.erlang.org/faq.html
>>>> erlang-questions (at) erlang.org
>>>> 
>> 
>> ________________________________________________________________
>> erlang-questions mailing list. See http://www.erlang.org/faq.html
>> erlang-questions (at) erlang.org
>> 
> 
> 
> ________________________________________________________________
> erlang-questions mailing list. See http://www.erlang.org/faq.html
> erlang-questions (at) erlang.org
> 



-- 
Jayson Vantuyl
kagato@REDACTED







More information about the erlang-questions mailing list