Java Class

Java is designed to be an object oriented language for deploying secure, multithreaded network applications (both clients and servers). Prolog is ideal for building intelligent components, expert systems and logic-bases. In combination, Java and Prolog are an ideal pair for delivering useful intelligent applications on the Internet. The Java Class encapsulates the Amzi! Logic Server for use by Java applications and applets. It includes: In addition, you can extend the Java Class to allow Prolog to call methods in your Java code.

Where to Learn About Java

If you want to learn more about Java and Java Applets and Servlets, see java.sun.com. You can also download Sun's Java Development Kit (JDK) from there.

Installation

The Java Class and its samples are distributed for JDK 2.0 (1.2).

To use the Java Class, you must make these files accessible to the calling environment:

Do not put any other files in your amzi/ls directory as they will be included when you import amzi.ls.*; and may cause naming conflicts.

Hello Prolog

To make sure the Amzi! Java interface is ready to use, run the Amzi! Hello sample for Java. It is in the directory amzi5\samples\java\hello. To build the Hello program from Java, first open a 'DOS' window and change to the sample directory containing Hello.java. To compile it, type: This will produce Hello.class which is simply run by typing:

Overview

The Java Class is implemented using the Java Native Interface (JNI). This allows methods used in a Java class to be implemented in C/C++. In the case of Amzi!, the JNI is used to build a bridge to the Logic Server API, which is the external interface on the Amzi! Prolog engine. The bridge is necessary because many of the Logic Server API functions have to be changed slightly to conform to Java parameter passing and return conventions (such as accommodating the lack of pointer support in Java).

So, the Amzi! Java interface defines a Java class, LogicServer, whose methods are implemented by calls to C++ functions in a dynamic/shared libary that, in turn, calls the main Amzi! engine dynamic/shared library. This is illustrated in Figure 1.

Figure 1

Working right to left in the diagram, amzi.dll is the Amzi! Logic Server (Prolog engine). amzijni.dll/libamzijni.so is the interface library that implements the Java versions of Logic Server API functions. Those, in turn are wrapped in the Java classes, LogicServer and LSException.

There are a number of features of the Java class that were dictated by the distinct characteristics of Java. These are detailed in the following sections.

Object Oriented

The Amzi! Logic Server is implemented as an object oriented program, so that each Logic Server is an object and the Logic Server API functions are methods of that object. It is natural, therefor, to provide object oriented interfaces to the Logic Server for object oriented languages such as Java. (Amzi! is also available in a C++ and Delphi class.) The Logic Server class can then be used as any other class in an object oriented application, supporting, for example, subclassing, embedding and multiple instances. This makes for an elegant approach to encapsulating Prolog services in applications. (see "Objects and Logic-C++ Meets Prolog", PC AI May/Jun 95)

Figure 2 is an expanded architecture diagram that illustrates the package and its classes.

Figure 2

Pointerless Methods

The biggest challenge in the design of the Amzi! Java class was the requirement for pointerless methods. The creators of Java wanted to keep their language simple, so they did not include support for pointers, specifically in function parameter lists. For this reason the Java methods had to be implemented so they return a single value.

A fundamental data type for the Prolog interface is a Prolog term. Internally, a Prolog term is a pointer, but, since that pointer is not manipulated by the application, it can be stored as an integer. For Java, it is stored in a 64-bit integer so Java can support both 64- and 32-bit versions of the Amzi! Prolog engine.

Many Logic Server API (LSAPI) functions return error codes, and use argument pointers to pass values back and forth. The Java class, like other Amzi! lsapis, is designed to use exception handling for errors, with return values passed directly as return values, without using pointers.

There are a number of Java LSAPI functions that differ from the corresponding base LSAPI because of lack of pointers. These are discussed in the following sections.

Issuing Prolog Queries

The base LSAPI functions that issue Prolog queries return TRUE or FALSE, corresponding to Prolog success or failure, and use a pointer to the calling Prolog term to pass back the term resulting from the query. For example a function issuing the query 'available(com, Port)' will return true or false plus the term representing the query with the Port variable unified with the result.

For Java, the query LSAPI functions (Exec, ExecStr, Call, CallStr) return the term (a long) directly, instead of a true false. If the query fails, that is indicated by a zero (0) value returned. (Errors are indicated by LSExceptions.)

String Conversion

The Java LSAPI automatically converts the internal Unicode Java representation of character strings to and from the Amzi! internal Unicode representation.

Exceptions

Instead of returning error codes, all the LogicServer methods use Java's exception mechanism. The LSException class is thrown when an error occurs. LSException contains a number of methods for learning details about the exceptions.

Multi-Threaded

Java allows you to start multiple threads in the same program, and Amzi! supports multiple simultaneous Prolog engines. So each instance of the Java Logic Server class will contain its own Prolog runtime environment.

Using the Java Class

To use the LogicServer class you import the amzi.ls package into your Java program: From there you can either instantiate a new LogicServer object and invoke its methods, or you can define a new class that extends the LogicServer class adding new methods and variables.

LogicServer and LSException Methods

The LogicServer class includes all the methods that give the developer full control over the Prolog engine. These include methods for: The LSException class has no methods and is simply used to signal and catch errors as described in the section on 'Exceptions.'

Logic Server Set-Up

These methods provide the basic API services. They are used to initialize and close down the Prolog environment. Most are similar to their base LSAPI equivalents, with the exception of AddPred, which is used to defined extended predicates.

For AddPred, the Java method that implements the predicate is defined with two string parameters, giving the class and method names, and one Object reference for the particular instance of the object that will be used for the functions. (AddPred does not allow the use of static methods for extended predicates.) See the samples for an example of its use.

Calling Prolog

These are the methods that actually call predicate in a Prolog module. The query term can be represented as a string or a Prolog term. The methods return the term representing the result, or the value 0 if the query fails.

Dynamic Database

These methods make it easy to assert and retract terms to and from Prolog's dynamic database.

Converting Strings/Terms

These methods convert strings to terms and terms to strings. The 'Q' version create quoted strings when necessary for atoms and strings that require delimiter symbols. They are necessary for those cases when you want to use the resulting string in another query.

TermToStr is especially useful during development to display the results of a Prolog query.

Making/Getting Prolog Types

These methods map Prolog types to Java types.

Manipulating Structures

These methods let you create and take apart terms that represent structures. This is especially useful for retrieving arguments in a query. For example, for the query 'sibling(mary, X)' GetStrArg can be used to retrieve the second argument of the strucutre.

Manipulating Parameters for Extended Predicates

These methods let you get and set (unify) the parameters that are passed with a Prolog extended predicate. The term parameter is used to distinguish them from functor arguments, although in pure Prolog terminology the parameters are simply the arguments of the functor of the extended predicate. For example, if you implemented an extended predicate call get_url/1 in Java, these predicates would let you unify a URL with the first parameter of that predicate.

Manipulating Lists

These methods let you create Prolog lists, add items to lists and retrieve items from lists. The Get__Head family of functions can be used in loops to get all the items in a list (in conjunction with GetTail).

Error Handling

These methods are all implemented as part of the LSException class, and let you get details about the exception.

Miscellaneous Methods

This method lets you get the current version number.

Copyright ©1987-2000 Amzi! inc. All Rights Reserved.