Asynchronous Communicating between Java and ECLiPSe

## 8.6 Asynchronous Communicating between Java and ECLiPSe

- Opening and closing asynchronous queues
- Opening an asychronous queue using ECLiPSe predicates
- Writing and reading ECLiPSe terms on queues

Starting with release 5.9, the OutOfProcessEclipse and RemoteEclipse variants of the Java-ECLiPSe Interface also support asynchronous queues through the class AsyncEclipseQueue. These are essentially socket connections between ECLiPSe and Java, which can be used independently of which side has control.
An AsyncEclipseQueue queue is opened and closed in the same way as a FromEclipseQueue or ToEclipseQueue, but the following differences exist:

- an asynchronous queue can be read/written from the Java side even while the ECLiPSe side has control, e.g. during an RPC. This obviously has to happen from a different thread than the one that executes the RPC.
- I/O operations on asynchronous queues can block, they should therefore be done from a dedicated thread.
- the AsyncEclipseQueue class does not extend InputStream or OutputStream and can therefore not be used for I/O directly. Instead, a standard Java InputStream can be obtained from it via the getInputStream() method, and an OutputStream via the getOutputStream() method.
- on the ECLiPSe side, an event can (and should) be raised when data arrives from the Java side. If the ECLiPSe side has control at that time, it will handle the event. Otherwise, the event handling may be deferred until ECLiPSe has control back.

### 8.6.1 Opening and closing asynchronous queues

Opening and closing can be performed in a single step from either the Java or the ECLiPSe side.

#### Opening an asychronous queue using Java methods

The AsyncEclipseQueue does not have public constructors. Instead, we invoke `getAsyncEclipseQueue`. This asks the EclipseConnection object for a reference to an AsyncEclipseQueue instance which represents a new queue. To specify the stream for later reference, we supply the method with a string which will equal to the atom by which the queue is referred to as a stream in ECLiPSe. For example the following code creates such a queue:

     ...
      AsyncEclipseQueue java_eclipse_async =
        eclipse.getAsyncEclipseQueue("java_eclipse_async");
    ...

Note that this method will only work when the `eclipse` object is an OutOfProcessEclipse or RemoteEclipse. Teh method will create and return a new AsyncEclipseQueue object, and will also open a stream with the specified names on the ECLiPSe side. No stream in ECLiPSe should exist with the specified name. If a stream exists which has this name and is not a queue between the Java object and ECLiPSe, the Java method throws an exception. If the name is used by a pre-existing queue, it is returned, so the `getAsyncEclipseQueue` methods can also be used to retrieve the queue objects by name once they have already been created.

### Opening an asychronous queue using ECLiPSe predicates

You can use the ECLiPSe builtin peer_queue_create/5 to open a queue. Used correctly, these have the same effect as the Java methods explained above. For the peer name, you should use the atom returned by the `getPeerName()` method of the relevant EclipseConnection instance. The direction should be `bidirect`, and the queue type should be specified as `async`.

#### Transferring data using Java methods

Once an AsyncEclipseQueue has been created, a standard Java InputStream can be obtained from it via the getInputStream() method, and an OutputStream via the getOutputStream() method. These Java streams can be used as you would any instance of java.io.InputStream or java.io.OutputStream. Unlike the synchronous FromEclipseQueue and ToEclipseQueue, I/O on these streams can block, and should therefore be handled by dedicated threads. For this reason, the listener-feature is not supported on asynchronous queues.

#### Transferring data using ECLiPSe predicates

On the ECLiPSe side, there are built-in predicates for writing to, reading from and otherwise interacting with streams. Any of these may be used. Perhaps most useful are read_exdr/2 and write_exdr/2; these are explained in Section 8.5.2. For the stream ID, you may either use the stream name, or the stream number, obtained for example using peer_get_property/3.
Since the ECLiPSe side does not support threads, it should only write to an asynchronous queue when there is an active thread on the Java side to read the data. Otherwise, the write-operation may block, and control will never be transferred back from ECLiPSe to Java.
For reading from an asynchronous queue, the ECLiPSe side should typically set up an event handler. The handler will be invoked whenever new data arrives on a previously empty queue.

    my_async_queue_handler(Stream) :-
        ( select([Stream], 0, [_]) ->
            read_exdr(Stream, Data),
            process(Data),
            my_async_queue_handler(Stream)
        ;
            events_nodefer
        ).

    setup_async_queue_with_handler :-
        event_create(my_async_queue_handler(my_async_queue), [defers], Event),
        peer_queue_create(my_async_queue, host, async, bidirect, Event).

Note that execution of the handler is only guaranteed when the ECLiPSe side has control.
When communicating between Java and ECLiPSe using queues, you should always invoke the `flush()` method of the Java OutputStream which you have written to, whether it be a ToEclipseQueue or an EXDROutputStream. Similarly, on the ECLiPSe side, `flush/1` should always be executed after writing. Although in some cases reading of the data is possible without a flush, flushing guarantees the transfer of data.

#### Closing a queue using Java methods

This is done simply by calling the `close()` method on the AsyncEclipseQueue instance.

#### Closing a queue using ECLiPSe predicates

This is done by executing the builtin peer_queue_close/1. Note that the builtin `close/1` should not be used in this situation, as it will not terminate the Java end of the queue.

### 8.6.2 Writing and reading ECLiPSe terms on queues

See the corresponding section for synchronous queues, 8.5.2.