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:
-
A Java Class Package the encapsulates a Logic Server Engine
-
Methods that correspond to the Logic Server API Functions
-
Use of Java's exception handling for API errors, and
-
Java-like method interfaces.
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:
- Amzi! Dynamic/Shared Library - The Amzi! Logic Server, amzi.dll
or libamzi.so, and the Amzi! Java interface, amzijni.dll, must be in your
PATH or otherwise accessible to the calling environment. These files are in
the amzi/\bin directory. You can load these libraries (and LSXs) explicitly
in Java with Runtime.getRuntime().load(libraryPath) or loadLibrary(libraryName).
- Amzi! Java Classes - The amzi/ls directory structure, containing
the amzi.ls.* package must be accessible via your CLASSPATH. You can do this
by adding amzi/lsapis/java20 to your CLASSPATH or copying the amzi/ls subdirectory
structure to a directory already in your CLASSPATH.
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:
javac Hello.java
This will produce Hello.class which is simply run by typing:
java Hello
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:
import amzi.ls.*;
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:
- Predicate Name
- Predicate Arity
- Java Class Name (fully qualified including packages)
- Java Method Name
- Pointer to the Instance of the Class Object that contains the Method
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:
- ADD_PRED — This uses the JNI environment pointer when AddPred is called. For this to work, the thread that called AddPred() needs to be the same thread that is calling the extended predicate.
- CURRENT_THREAD — This uses the JNI environment pointer for the currently executing thread.
- EXEC_OR_CALL — Not recommend. This option is available for backwards compatibility. It will not work in a multi-threaded environment. It uses the JNI environment pointer from the last Exec(), Call() or Redo(). This pointer is saved in a global variable for all threads using the Amzi! JNI Interface.
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.