Powered by SmartDoc
ENGLISHJAPANESE

Integrating prolog and Java on Servlet

JPL: a Java interface to prolog

We learn in this chapter how to call prolog programs from Servlet and return the result on Servlet. The mechanism allows you to build in your Web page various AI technologies implemented in prolog.

We employ JPL, the Java interface to prolog, to call prolog programs from Java. JPL is developed by Fred Dushin and detailed explanation is given in the distribution, under doc directory. We will not therefore repeat the explanation of the interface below. We illustrate how the interface is used on Servlet. The sample programs are taken from the distribution, under 'demo/getting-started' directory. It is good idea to test-run Test.java under the directory before proceeding to check if JPL was installed correctly as shown in 図[Testing JPL]. You may have to run it within Meadow if the result is not visible in Bash Window.

Testing JPL
/tmp/jpl/demo/getting-started> java Test
% test.pl compiled 0.02 sec, 1,084 bytes
child_of(joe, ralf) = true
descendent_of(steve, ralf) = true
querying descendent_of( X, ralf )
X = joe
querying descendent_of( X, ralf )
X = joe
X = mary
X = steve
/tmp/jpl/demo/getting-started> 

A note on Windows95: I have tested the samples below on Windows95 and Windows98 and found that calling prolog program from Servlet does not work on Windows95. I am not sure if it is generally so. Please tell me what happened if you run the samples on Windows95.

Sample prolog program

We assume that you have an elementary level of knowledge about prolog programming. Below (リスト[test.pl]) is a sample prolog program, 'test.pl', taken from 'demo/getting-started'. The program says that 'joe' is a child of 'ralf', and 'mary' and 'steve' are children of 'joe'. It defines descendent_of relation, too, such that X is descendent of Y if X is a child of Y or if there is a person Z who is child of Y and a parent of X.

test.pl
child_of( joe, ralf ).
child_of( mary, joe ).
child_of( steve, joe ).

descendent_of( X, Y ) :-
	child_of( X, Y ).
descendent_of( X, Y ) :-
	child_of( Z, Y ),
	descendent_of( X, Z ).

You can load the program on SWI-prolog to test it as shown in (図[Test run].

Test run
/tmp/jpl/demo/getting-started> pl
Welcome to SWI-Prolog (Version 3.3.6)
Copyright (c) 1990-2000 University of Amsterdam. 
Copy policy: GPL-2 (see www.gnu.org)

For help, use ?- help(Topic). or ?- apropos(Word).

1 ?- [test].
% test compiled 0.02 sec, 1,156 bytes
Yes

2 ?- child_of(joe, ralf).
Yes

3 ?- descendent_of( X, ralf ).
X = joe ;
X = mary ;
X = steve ;

No
4 ?- 

Handing prolog variables and atoms

The program, demo/getting-started/Test.java, and the documentation illustrate well how to hand SWI-prolog variables and atoms. Let us examine the method, test_3, in Test.java (リスト[Test.java])

Test.java
	static void
	test_3()
	{
		Variable X = new Variable();
		Term args[] = { 
			X,
			new Atom( "ralf" )
		};
		Query query = 
			new Query( 
				"descendent_of", 
				args );

		System.out.println( "querying descendent_of( X, ralf )" );
		java.util.Hashtable solution =
			query.oneSolution();
		System.out.println( "X = " + solution.get( X ) );
	}

The method prepares an inquiry, descendent_of( X, ralf ), to emit it to SWI-prolog and receives back an atom instantiating X. We modify the method slightly so that it returns an Atom bound to the variable, X. Let us call the method 'test3'. The method is defined as below (リスト[Method test3]). The type of the method is changed from 'void' to 'Atom' and the line, 'return (Atom)solution.get( X );' replaces for 'System.out.println( "X = " + solution.get( X ) );'

Method test3
	//
	//  This is test3 method. 
	//  The type of the return value is Atom.
	//
	static Atom
	test3( String person )
	{
		//
		// We construct the query, descendent_of( X, Person )
		// where Person is instantiated already when called
		Variable X = new Variable();
		Term args[] = { 
			X,
			new Atom( person )
		};
		Query query = 
			new Query( 
				"descendent_of", 
				args );

		//
		// Obtain the first solution to return
		//
		java.util.Hashtable solution =	query.oneSolution();
		return (Atom)solution.get( X );
	}

Getting back atoms from prolog

Executing 'query.oneSolution()' calls SWI-prolog, emitting the variable and name. By executing 'solution.get( X )', the Java method receives back some atom bound to X. We have to cast the return value to Atom type because the returned value is of 'Object' type.

Calling prolog from Servlet

We show the part of the program up to test3 method (リスト[prologServ.java]). The sample is almost identical with the one shown to illustrate basic usage of Servlet. Points to note are:

  1. The location of 'test.pl' must be specified in full, as 'new Atom( "/usr/local/jakarta-tomcat/webapps/proServ/WEB-INF/classes/test.pl" )' because Tomcat does not know how to relate 'test.pl' to the file itself. (test.pl is not a class file.)
  2. We use the method, name(), to retrieve the name of Atom, i.e., 'String descendent = test3( value ).name();' Consult the chapter, 'High-Level Interface' (doc/high-level_interface.html), for more detai.
prologServ.java
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
// 
//   JPL package
//
import jpl.Atom;
import jpl.Variable;
import jpl.Term;
import jpl.Query;
import jpl.JPL;

public class prologServ extends HttpServlet {
	public void doGet (
		HttpServletRequest req,
		HttpServletResponse res
		) throws ServletException, IOException
	{
		res.setContentType( "text/html" );
		PrintWriter out = res.getWriter();
		out.println( "<html><head><title>Finding decendents of the person</title></head>" );
		out.println( "<body>Using getParameter() method<br>" );

		JPL.init(); // We initialize JPL
		Term consult_arg[] = { 
			//
			// We have to specify the location of prolog program in full
			//
			new Atom( "/usr/local/jakarta-tomcat/webapps/proServ/WEB-INF/classes/test.pl" ) 
		};
		//
		// We consult 'test.pl'
		//
		Query consult_query = 
			new Query( 
				"consult", 
				consult_arg );

		boolean consulted = consult_query.query();

		if ( !consulted ){
			out.println( "Consult failed" );
			System.exit( 1 );
		}

		Enumeration enum = req.getParameterNames();
		while( enum.hasMoreElements() ) {
			String name = (String)enum.nextElement();
			String value = req.getParameter( name );
			out.println( name + "=" + value + "<br>" );
			// 
			//   We pass the task to test3 below
			//
			String descendent = test3( value ).name();
			out.println( "descendent = " +  descendent + "<br>" );
		}
		out.println( "</body></html>" );
		out.close();
	}
	
	static Atom
	test3( String person )
	{
	    ( ... Suppressed ... )
	}

	public void doPost
	    ( ... Suppressed ... )
}

Running the sample

We create the application named 'proServ' under some working directory and build it as explained above. Upon entering the address, 'http://127.0.0.1:8080/proServ/index.html', you are prompted to enter a name of person, whose descendent we like to know of (図[Query window]). We type in 'ralf' for this example.

Query window

Upon cliking 'SUBMIT', you are shown the result that 'joe' is a descendent of 'ralf', which was inferred by prolog (図[Result]).

Result

You can check that the prolog program is loaded on the starting window of Tomcat (Monitoring invocation of prolog_ja.html)

Monitoring invocation of prolog
( ... Suppressed ... )
Context log: path="/admin" Automatic context load 
             docBase="C:\cygnus\usr\local\jakarta-tomcat\webapps\admin"
Context log: path="/admin" Adding context path="/admin"  
             docBase="C:\cygnus\usr\local\jakarta-tomcat\webapps\admin"
% /usr/local/jakarta-tomcat/webapps/proServ/WEB-INF/classes/test.pl 
compiled 0.09 sec, 1,344 bytes

Source code

All the files comprising proServ application are found in Appendix.

unkonwn(ja)

Calling prolog program from Servlet did not work on Windows95 for my case. Please share your experience if you tried to do the same on Windows95.