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:
Opening and closing can be performed in a single step from either the Java or the ECLiPSe side.
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.
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.
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.
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.
This is done simply by calling the close() method on the AsyncEclipseQueue instance.
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.
See the corresponding section for synchronous queues, 8.5.2.