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:

The Java Logic Server methods are documented in the LSAPI Reference.

In addition, you can extend the Java Class to allow Prolog to call methods in your Java code.

The sections of this document are:

Where to Learn About Java

If you want to learn more about Java and Java Applets and JSP/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.

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 amzi\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/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.

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 .NET, 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

Representing Prolog Terms

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.

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.

Implementing Extended Predicates

Java, like C/C++, Delphi and VB 5.0 (and later), can be used to implement custom extended predicates to the Prolog language. These custom extensions give the Prolog code the ability to directly access anything Java can access.

The Java methods that implement extended predicates, must be declared as returning type boolean, and as public. They can be added one at a time using the API function AddPred, which adds a single predicate at a time. If your extended predicate is in a package, then the package name must be included in the class name, delimited by forward slashes, to AddPred as follows:

ls.AddPred("extpred", 1, "javapkg/jprolog", "extpred", this);

The parameters are:

Note: Extended predicate definitions must always be added after calling InitLS and before calling LoadXPL.

The sample in directory /samples/java/pets_callback is an example of how to implement an extended predicate in Java.

Using Static Methods as Extended Predicates

You can use static methods as extended predicates by specifying null for the pointer to the instance of the class. Static methods are a good choice when pooling Logic Servers in a Web application.

Controlling the JNI Environment Pointer for Extended Predicates

More complex applications may require finer control over the JNI environment pointer that is used to locate and call extended predicates. AddPred can be called with an additional parameter that specifies this, for example:

ls.AddPred("extpred", 1, "javapkg/jprolog", "extpred", this, LogicServer.ADD_PRED);

There are three options:

Note: Extended predicates will fail (return false) if you use CURRENT_THREAD and the current thread is not attached to the Java virtual machine.

Converting Prolog Lists to Java Types

Here are some useful Java methods that convert Prolog lists. The first takes each item in a Prolog list, converts it to a string and saves it in a String array.

   	public static String[] prologListToStringArray(LogicServer ls, long list, int size) throws LSException
   	{
		List array = new ArrayList();

      	// Check for the empty list or an atom
      	long type = ls.GetTermType(list);

      	if (type != LogicServer.pLIST) return new String[0];

      	while (list != 0) {
         	array.add(ls.TermToStr(ls.GetHead(list), size));

         	list = ls.GetTail(list);
      	}

		String[] result= new String[array.size()];
		array.toArray(result);
		return result;
   }

This method takes a Prolog list of the form [name1 : value1, name2 : value2... nameN: valueN] or [item(name1, value1), item(name2, value2)...item(nameN, valueN)] and converts it to a Java Properties list where the property name and value.

   public static Properties prologListToProperties(LogicServer ls, long list, int size) throws LSException
   {
      Properties p = new Properties();
      long element, name, value;

      // Check for the empty list or an atom
      long type = ls.GetTermType(list);
      if (type != LogicServer.pLIST) return p;

      while (list != 0) {
         element = ls.GetHead(list);
         name = ls.GetArg(element, 1);
         value = ls.GetArg(element, 2);
         if (ls.GetTermType(value) == LogicServer.pLIST)
            p.setProperty(ls.TermToStr(name, size), ls.TermToStrQ(value, size));
         else {
			p.setProperty(ls.TermToStr(name, size), ls.TermToStr(value, size));
         }

         list = ls.GetTail(list);
      }
      return p;
   }

Examples

Samples for .NET can be found in samples\java and in samples\internet\jsp and samples\internet\servlets.

Copyright ©1987-2011 Amzi! inc. All Rights Reserved. Amzi! is a registered trademark and Logic Server is a trademark of Amzi! inc.