[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