[erlang-questions] Reliable way to handle Java node crashs?

Robert Raschke <>
Fri Jun 18 11:06:44 CEST 2010

On Thu, Jun 17, 2010 at 3:59 PM, zabrane Mikael <> wrote:

> Thanks guys for the advices.
> 2010/6/17 Robert Raschke <>
>  I kick off the Java node as a monitored port from within Erlang. That
>> way I am in control of starting, noticing crashes, and restarting. I
>> also have the port set up so that messages written to stdout in the
>> Java node feed into the logging in Erlang.
>> If you want I can dig out some example code when I'm back in the
>> office next week.
> Robert, I'll be more than happy to read some code!
> Thanks
> --
> Regards
> Zabrane

In Erlang I have a gen_server that interfaces to my Java Node with messages.
This kicks off the port manager and then does a handshake to transmit some
data the Java program needs to do its thing. Please note that I have not
actually compiled or run the example code below, this has been adapted from
some production code.

The port manager is a process that starts the Java node as a port program:


-export([start_link/1, init/3]).

start_link(Node_Name) ->
    spawn_link(?MODULE, init, [Node_Name]).

init(Node_Name) ->
    process_flag(trap_exit, true),
    Cmd = mk_java_cmdline(os:type(), Node_Name),
    error_logger:info_report([{module, ?MODULE}, {java_port, Node_Name},
{'START', Cmd}]),
    P = open_port({spawn, Cmd}, [stream, {line, 100}, exit_status]),
    loop(P, Node_Name, [], []).

loop(Port, Name, Response, Line) ->
        % These three messages mean that the Java program is no longer
        % So we stop looping.
        % The first is normal termination, the other two are abnormal.
        {Port, {exit_status, 0}} ->
            error_logger:info_report([{module, ?MODULE}, {java_port, Name},
                    {'EXIT', {status, 0}}]);

        {Port, {exit_status, N}} ->
            error_logger:error_report([{module, ?MODULE}, {java_port, Name},
                    {'EXIT', {status, N}}]),
            erlang:error({port_status, N});
        {'EXIT', Port, Reason} ->
            error_logger:error_report([{module, ?MODULE}, {java_port, Name},
                    {'EXIT', Reason}]),
            erlang:error({port_exit, Reason});

        % The data messages come from the standard output of the Java
        % We accumulate the output line by line; potentially having to
        % each line from pieces. Everything is accumulated through list
        % Thus all results have to be reversed before use.

        % Unfinished output lines are tagged with noeol.
        % We accumulate the line.
        {Port, {data, {noeol, S}}} ->
            loop(Port, Name, Response, [S | Line]);

        % Finished lines are tagged with eol.
        {Port, {data, {eol, S}}} ->
            case {S, Line} of
                % The convention in the Java program is to send a solitary
"." to signal
                % that this particular bit of output is complete.
                {".", []} ->
                    process_port_data(Name, lists:reverse(Response)),
                    loop(Port, Name, [], []);
                {S, Line} ->
                    Full_Line = lists:flatten(lists:reverse([S | Line])),
                    loop(Port, Name, [Full_Line | Response], [])

% Messages from the Java program are logged as info messages.
process_port_data(Name, Text) ->
    error_logger:info_report([{module, ?MODULE}, {java_port, Name},
            {'STDOUT', string:join(Text, "\n")}]).

mk_java_cmdline({Ostype, _}, Node_Name) ->
    mk_java_cmdline(Ostype, Node_Name);
mk_java_cmdline(Ostype, Node_Name) ->
            " -Xrs -classpath myPackage ",
            " myPackage.myJavaNode ",
                quote(Ostype, Node_Name), " ",
                quote(Ostype, my_cookie())

my_cookie() ->

quote(win32, S) ->
    ["\"", S, "\""];
quote(unix, S) ->
    ["'", S, "'"].

And the Java node looks something like this:

package myPackage;

import com.ericsson.otp.erlang.*;

public class myJavaNode {

    private static void print(String s)

    public static void main(String[] args)
        // System.setProperty("OtpConnection.trace", "4");

        if (args.length != 2) {
            print("Invalid arguments.");

        String node_name = args[0];
        String cookie = args[1];

        OtpNode node = null;
        try {
            node = new OtpNode(node_name, cookie);
        } catch(java.io.IOException ioe) {
            String msg = ioe.getMessage();
            if (msg != null) {
                print("OtpNode creation error: " + msg);

        try {
            OtpMbox mbox = node.createMbox("myBox");

            // go into your message loop

        } catch (Exception e) {
            System.out.println("."); System.out.flush();


    private static void shake_hands(OtpMbox mbox)
        throws Exception
        OtpErlangTuple msg = (OtpErlangTuple) mbox.receive(5000);
        if (msg == null) {
            print("Handshake timed out.");

        OtpErlangPid from = (OtpErlangPid) msg.elementAt(0);
        OtpErlangAtom hand = (OtpErlangAtom) msg.elementAt(1);

        if ("ok".equals(hand.atomValue())) {
            mbox.send(from, new OtpErlangTuple(new OtpErlangObject[] {
                new OtpErlangAtom("ok"),
        } else {
            mbox.send(from, new OtpErlangAtom("who are you?"));
            print("Not received ok: " + msg);


I hope this'll give you a few ideas.


More information about the erlang-questions mailing list