Go to the first, previous, next, last section, table of contents.


Low-level Prolog to Java interface

Author(s): Jesús Correas.

This module defines the low level Prolog to Java interface. This interface allows a Prolog program to start a Java process, and create Java objects, invoke methods, set/get attributes (fields), and handle Java events.

Although the Java side interface is explained in Javadoc format, the general interface structure is detailed here.

Low-Level Prolog to Java Interface Structure

This low-level prolog to java interface is made up of two parts: a Prolog part and a Java part. The Prolog part receives requests from a Prolog program and sends them to the Java part through a socket. The Java part receives requests from the socket and performs the actions included in the requests.

If an event is thrown in the java side, an asynchronous message must be sent away to the prolog side, in order to launch a prolog goal to handle the event. This asynchronous communication is made by the means of a second socket. The nature of this communication needs the use of threads both in java and prolog: one thread to deal with the 'sequential program flow,' and other thread (may be several) to do the job of event handling.

In the java side the threads are automatically created by the context of the objects we use: adding an event listener implies automatically that there will be a thread ready to launch it when the event raises. The prolog side is different: there must be a thread in the low-level interface that listens to the asynchronous socket to launch the goals requested.

Prolog side

The prolog side receives the actions to do in the java side from the user program, and sends them to the java side through the socket connection. When the action is done in the java side, the result is returned to the user program, or the action fails if any problem in the java side is found.

In order to send and receive prolog terms and java object references using a socket, this layer must transform this elements in a serialized representation, just like the java serialization package does. This transformation is done in our implementation using the fast_read/1 and fast_write/1 predicates included in Ciao, so any prolog element can be translated to and from a list of bytes.

Prolog data representation of java elements is very simple in this low-level interface. Java primitive types such as integers and characters are translated into Prolog terms, and even some Java objects are translated that way (e. g. Java strings). Java objects are represented in Prolog as compound terms with a reference to identify the corresponding Java object. Data conversion is made automatically when the interface is used, so the Prolog user programs do not have to deal with the complexity of this tasks.

Java side

The java side of this layer is more complex than the prolog side. The tasks this part have to deal to are the following:

In the implementation of the java side, two items must be carefully designed: the handling of java objects, and the representation of prolog data structures. The last item is specially important because all the interactions between prolog and java are made using prolog structures, an easy way to standardize the different data management of both languages. Even the requests themselves are encapsulated using prolog structures. The overload of this encapsulation is not significant in terms of socket traffic, due to the optimal implementation of the prolog serialized term.

The java side must handle the objects created from the prolog side dinamically, and these objects must be accessed as fast as possible from the set of objects. The java API provides a powerful implementation of Hash tables that achieves all the requirements of our implementation.

On the other hand, the java representation of prolog terms is made using the inheritance of java classes. In the java side exists a representation of a generic prolog term, implemented as an abstract class in java. Variables, atoms, compound terms, lists, and numeric terms are classes in the java side which inherit from the term class. Java objects can be seen also under the prolog representation as compound terms, where the single argument corresponds to the Hash key of the actual java object in the Hash table referred to before. This behaviour makes the handling of mixed java and prolog elements easy. Prolog goals are represented in the java side as objects which contain a prolog compound term with the term representing the goal. This case will be seen more in depth next, when the java to prolog is explained.

Java event handling from Prolog

Java event handling is based on a delegation model since version 1.1.x. This approach to event handling is very powerful and elegant, but a user program cannot handle all the events that can raise on a given object: for each kind of event, a listener must be implemented and added specifically. However, the Java 2 API includes a special listener (AWTEventListener) that can manage the internal java event queue.

The prolog to java interface has been designed to emulate the java event handler, and is also based on event objects and listeners. The low level prolog to java interface implements its own event manager, to handle those events that have prolog listeners associated to the object that raises the event. From the prolog side can be added listeners to objects for specific events. The java side includes a list of goals to launch from the object and event type.

Due to the events nature, the event handler must work in a separate thread to manage the events asynchronously. The java side has its own mechanisms to work this way. The prolog side must be implemented specially for event handling using threads. The communication between java and prolog is also asynchronous, and a additional socket stream is used to avoid interferences with the main socket stream. The event stream will work in this implementation only in one way: from java to prolog. If an event handler needs to send back requests to java, it will use the main socket stream, just like the requests sent directly from a prolog program.

The internal process of register a Prolog event handler to a Java event is shown in the next figure:

Image:autofigip2jbn-events-pl-reg.jpg

When an event raises, the low-level Prolog to Java interface have to send to the Prolog user program the goal to evaluate. Graphically, the complete process takes the tasks involved in the following figure:

Image:autofigip2jbn-events-pl-fire.jpg

Java exception handling from Prolog

Java exception handling is very similar to the peer prolog handling: it includes some specific statements to trap exceptions from user code. In the java side, the exceptions can be originated from an incorrect request, or can be originated in the code called from the request. Both exception types will be sent to prolog using the main socket stream, leaving the prolog program manage the exception. However, the first kind of exceptions are prefixed, so the user program can distinguish from the second type of exceptions.

In order to handle exceptions properly using the prolog to java and java to prolog interfaces simultaneously, in both sides of the interface will be filtered those exceptions coming from their own side: this avoids an endless loop of exceptions bouncing from one side to another.

Usage and interface (javart)

Documentation on exports (javart)

PREDICATE: java_create_object/2:

Usage: java_create_object(+java_constructor,-(java_object))

REGTYPE: machine_name/1:

Usage: machine_name(X)

REGTYPE: java_constructor/1:

Usage: java_constructor(X)

REGTYPE: java_object/1:

Usage: java_object(X)

PREDICATE: java_delete_object/1:

Usage: java_delete_object(+java_object)

PREDICATE: java_invoke_method/2:

Usage: java_invoke_method(+java_object,+java_method)

REGTYPE: java_method/1:

Usage: java_method(X)

PREDICATE: java_get_value/2:

Usage: java_get_value(+java_object,+java_field)

PREDICATE: java_set_value/2:

Usage: java_set_value(+java_object,+java_field)

REGTYPE: java_field/1:

Usage: java_field(X)

PREDICATE: java_connection/0:

Usage:

PREDICATE: java_remote_connection/1:

Usage: java_remote_connection(+machine_name)

PREDICATE: java_disconnection/0:

Usage:

PREDICATE: java_add_listener/3:

Meta-predicate with arguments: java_add_listener(?,?,goal).

Usage: java_add_listener(+java_object,+java_event,+prolog_goal)

REGTYPE: java_event/1:

Usage: java_event(X)

REGTYPE: prolog_goal/1:

Usage: prolog_goal(X)

PREDICATE: java_remove_listener/3:

Usage: java_remove_listener(+java_object,+java_event,+prolog_goal)


Go to the first, previous, next, last section, table of contents.