ENGLISH | JAPANESE |
We will conclude this part by showing how to combine prolog and relational databases in Java. One may ask why we should use both prolog and relational databases. We would reply to the question, for example, as follows:
The combination of prolog, RDB, and Java, may develop into an intelligent system with huge supply of data both from RDB and through Internet. We do not know yet how we can exploit the possibility, but the goal sounds attractive, especially to the ear of retired prolog programmers.
We demonstrate how prolog works with RDB with an example. Recall the prolog program we examined to test the connection between prolog and Servlet. The program is reproduced below for readers' convenience:
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 ).
Of the definitions, the first three lines defining the child_of relation will vary, depending on the domain to which you apply the 'descendent_of' program. The relation is therefore a good candidate to encode in RDB. We remove the lines to slim down 'test.pl' program as follows:
descendent_of( X, Y ) :- child_of( X, Y ). descendent_of( X, Y ) :- child_of( Z, Y ), descendent_of( X, Z ).
The items of information we have removed from the prolog program, test.pl, is obtainable from the database, mysqltest, we built in the previous section to teach you the very basics of MySQL:
mysql> use mysqltest; Database changed mysql> select * from child_of; +-------+--------+ | child | parent | +-------+--------+ | joe | ralf | | mary | joe | | steve | joe | +-------+--------+ 3 rows in set (0.00 sec)
We will modify the demo system we presented in the beginning of this part, the system that calls prolog to return the name of parent given name of a person. We replace a database connection module for the prolog predicate specifying child_of relation.
To allow prolog to handle facts dynamically, we have to declare the predicate, child_of, to be dynamic. The program, test2.pl, must be therefore inserted the first line as below:
:- dynamic child_of/2. descendent_of( X, Y ) :- child_of( X, Y ). descendent_of( X, Y ) :- child_of( Z, Y ), descendent_of( X, Z ).
When you load the program, the definition of child_of is of course missing:
programs/proServ2/src> 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 ?- [test2]. % test2 compiled 0.02 sec, 860 bytes Yes 2 ?- listing. descendent_of(A, B) :- child_of(A, B). descendent_of(A, B) :- child_of(C, B), descendent_of(A, C). Yes
With the declaration, you can insert the set of facts about child_of relation as follows:
3 ?- assert( child_of( joe, ralf ) ). Yes 4 ?- assert( child_of( mary, joe ) ). Yes 5 ?- assert( child_of( steve, joe ) ). Yes 6 ?- listing. child_of(joe, ralf). child_of(mary, joe). child_of(steve, joe). descendent_of(A, B) :- child_of(A, B). descendent_of(A, B) :- child_of(C, B), descendent_of(A, C). Yes
With the facts of child_of, one can correctly calculate who is descendent of Ralf:
7 ?- descendent_of( X, ralf ). X = joe ; X = mary ; X = steve ; No
After getting the result, you should not forget to clean up the data by executing abolish:
8 ?- abolish( child_of/2 ). Yes 9 ?- listing. descendent_of(A, B) :- child_of(A, B). descendent_of(A, B) :- child_of(C, B), descendent_of(A, C). Yes
What we need to do to realize the demo story, is to do the same operation as presented in the previous section using Java. Basic idea is to combine the Java program to call prolog, e.g., Test.java presented in the first chapter of this part, and the other to get access to RDB, JDBCSample.java shown above. The whole program, which we call Test2.java, is shown below:
//*****************************************************************************/ // // This program is drived from Test.java included in the JPL package under // 'demo/getting_started'. The original was implemented by Fred Dushin, // who developed JPL package. // //*****************************************************************************/ import java.util.Hashtable; import jpl.Atom; import jpl.Variable; import jpl.Term; import jpl.Query; import jpl.JPL; import jpl.Compound; import jpl.Util; import jpl.Integer; import java.io.*; import java.sql.*; public class Test2 { public static void main( String argv[] ) { load_prog(); assert_facts(); test_4(); abolish_facts(); } static void abolish_facts() { Term pred = new Atom( "child_of" ); Term num = new Integer( 2 ); Term rem = new Compound( "/", Util.toTermArray( pred, num ) ); Query query = new Query( "abolish", rem ); query.oneSolution(); } static void assert_facts() { try { Class.forName( "org.gjt.mm.mysql.Driver" ); String url = "jdbc:mysql://ks15e0f00/mysqltest?user=YourID&password=YourPassword"; Connection con = DriverManager.getConnection( url ); Statement select = con.createStatement(); String sql = "select * from child_of"; ResultSet res = select.executeQuery( sql ); while( res.next() ) { Term child = new Atom( res.getString( "child" ) ); Term parent = new Atom( res.getString( "parent" ) ); Term pair = new Compound( "child_of", Util.toTermArray( child, parent ) ); Query assert_query = new Query( "assert", pair ); assert_query.oneSolution(); } select.close(); con.close(); } catch ( Exception e ) { e.printStackTrace(); } } static void load_prog() { JPL.init(); Term consult_arg[] = { new Atom( "test2.pl" ) }; Query consult_query = new Query( "consult", consult_arg ); boolean consulted = consult_query.query(); if ( !consulted ){ System.err.println( "Consult failed" ); System.exit( 1 ); } } static void test_4() { 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 )" ); while ( query.hasMoreSolutions() ){ java.util.Hashtable solution = query.nextSolution(); System.out.println( "X = " + solution.get( X ) ); } } }The explanation is in order.
We import 'java.util.Hashtable' to recieve the result from prolog. The packages under 'jpl' are part of JPL, the java interface to prolog. The last, 'java.sql.*', is to get access to the RDB.
import java.util.Hashtable; import jpl.Atom; import jpl.Variable; import jpl.Term; import jpl.Query; import jpl.JPL; import jpl.Compound; import jpl.Util; import jpl.Integer; import java.io.*; import java.sql.*;
The top level defines the control flow. The method, 'load_prog()', first loads the prolog program, 'test2.pl'. Another method, 'assert_facts()', establishes the connection to RDB and retrieves data. The method asserts each datum into prolog every time it retrieves a line of data. The method, 'test_4()', prints out the result in prolog. This method is as implemented by Fred Dushin, the author of JPL. We finally clean up the facts of prolog interpreter.
load_prog(); assert_facts(); test_4(); abolish_facts();
We first laod the prolog program, 'test2.pl'. Nothing new to the method as we have already explained about the procedure.
static void load_prog() { JPL.init(); Term consult_arg[] = { new Atom( "test2.pl" ) }; Query consult_query = new Query( "consult", consult_arg ); boolean consulted = consult_query.query(); if ( !consulted ){ System.err.println( "Consult failed" ); System.exit( 1 ); } }
The next thing we have to do is to establish the connection to MySQL. We have already gave an explanation on the procedure. There is nothing new in retrieving data, too. In 'while' loop, however, we insert the data into prolog through JPL. The actoin occurs each time the method reads out a line from RDB.
static void assert_facts() { try { Class.forName( "org.gjt.mm.mysql.Driver" ); String url = "jdbc:mysql://ks15e0f00/mysqltest?user='YourID'&password='YourPassword"; Connection con = DriverManager.getConnection( url ); Statement select = con.createStatement(); String sql = "select * from child_of"; ResultSet res = select.executeQuery( sql ); while( res.next() ) { Term child = new Atom( res.getString( "child" ) ); Term parent = new Atom( res.getString( "parent" ) ); Term pair = new Compound( "child_of", Util.toTermArray( child, parent ) ); Query assert_query = new Query( "assert", pair ); assert_query.oneSolution(); } select.close(); con.close(); } catch ( Exception e ) { e.printStackTrace(); } }
The method, 'test_4()', executes the query, descendent_of(X, ralf), in prolog and receives the result through JPL.
static void test_4() { 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 )" ); while ( query.hasMoreSolutions() ){ java.util.Hashtable solution = query.nextSolution(); System.out.println( "X = " + solution.get( X ) ); } }
The last thing to do is to clean up the prolog facts, i.e., child_of/2, we inserted for the query. The point to note is that the expression, child_of/2, is in fact a compound term such as /(child_of, 2). No mystery, otherwise. You can skip the execution of this method because the inserted facts disappear anyway when Tomcat terminates.(1)
static void abolish_facts() { Term pred = new Atom( "child_of" ); Term num = new Integer( 2 ); Term rem = new Compound( "/", Util.toTermArray( pred, num ) ); Query query = new Query( "abolish", rem ); query.oneSolution(); }
The program, Test2.class, works as follows when compiled. Do not forget to replace your userID and password for 'YourID' and 'YourPassword' in Test2.java.
programs/proServ2/src> java Test2 % test2.pl compiled 0.02 sec, 784 bytes querying descendent_of( X, ralf ) X = joe X = mary X = steve
We have now everything at our hand to combine prolog and MySQL on Servlet. We will extend the sample Servlet, proServ, which we developed in the first chapter of this part. The Servlet was to return the name of a parent given a person name by calling prolog program. The modified version of the Servlet will return all the names of parents of the person.
We show you above all the source code. The reader who have read through the text in every corer should understand it without difficulties. The explanation comes in order.
// // for Servlet // 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; import java.util.Hashtable; import jpl.Compound; import jpl.Util; import jpl.Integer; // // for SQL // import java.sql.*; public class prologServ2 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 SWI-prolog and MySQL<br>" ); load_prog(); // Loading test2.pl assert_facts(); // Asserting facts into prolog Enumeration enum = req.getParameterNames(); while( enum.hasMoreElements() ) { String name = (String)enum.nextElement(); String value = req.getParameter( name ); out.println( name + "=" + value + "<br>" ); test4( value, out ); } // JPL.halt(); this causes Tomcat shutdown abolish_facts(); out.println( "</body></html>" ); out.close(); } public void doPost ( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException { doGet( req, res ); } static void load_prog() { JPL.init(); Term consult_arg[] = { new Atom( "/WinApps/jakarta-tomcat/webapps/proServ2/WEB-INF/classes/test2.pl" ) }; Query consult_query = new Query( "consult", consult_arg ); boolean consulted = consult_query.query(); if ( !consulted ){ System.err.println( "Consult failed" ); System.exit( 1 ); } } static void assert_facts() { try { Class.forName( "org.gjt.mm.mysql.Driver" ); String url = "jdbc:mysql://ks15e0f00/mysqltest?user=YourID&password=YourPassword"; Connection con = DriverManager.getConnection( url ); Statement select = con.createStatement(); String sql = "select * from child_of"; ResultSet res = select.executeQuery( sql ); while( res.next() ) { Term child = new Atom( res.getString( "child" ) ); Term parent = new Atom( res.getString( "parent" ) ); Term pair = new Compound( "child_of", Util.toTermArray( child, parent ) ); Query assert_query = new Query( "assert", pair ); assert_query.oneSolution(); } select.close(); con.close(); } catch ( Exception e ) { e.printStackTrace(); } } static void test4( String person, PrintWriter out ) { Variable X = new Variable(); Term args[] = { X, new Atom( person ) }; Query query = new Query( "descendent_of", args ); out.println( "querying descendent_of( X, " + person + " ) <br>" ); while ( query.hasMoreSolutions() ){ java.util.Hashtable solution = query.nextSolution(); out.println( "X = " + solution.get( X ) + "<br>" ); } } static void abolish_facts() { Term pred = new Atom( "child_of" ); Term num = new Integer( 2 ); Term rem = new Compound( "/", Util.toTermArray( pred, num ) ); Query query = new Query( "abolish", rem ); query.oneSolution(); } }
We import the packages for Servlet, JPL, and SQL.
// // for Servlet // 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; import java.util.Hashtable; import jpl.Compound; import jpl.Util; import jpl.Integer; // // for SQL // import java.sql.*;
We firstly send back the browser the header and the line to be printed out in the top.
public class prologServ2 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 SWI-prolog and MySQL<br>" );
The program, test2.pl, is then loaded, and the facts of child_of relation is imported from RDB to prolog. The methods, load_prog() and assert_facts(), are identical with the ones presented above.
load_prog(); // Loading test2.pl assert_facts(); // Asserting facts into prolog
In the next step, the program receives the person's name to hand it to the method, test4. The method, test4, will evoke prolog to infer who are parents of the person and display the result.
Enumeration enum = req.getParameterNames(); while( enum.hasMoreElements() ) { String name = (String)enum.nextElement(); String value = req.getParameter( name ); out.println( name + "=" + value + "<br>" ); test4( value, out ); }
When finished with displaying the names of parents, the program terminates by abolishing the inserted facts and closing the connection to the browser.
abolish_facts(); out.println( "</body></html>" ); out.close(); }
The first half is to construct the query, descendent_of(X, 'ralf'). The last part is to print out each name of parent to the browser by executing the query in prolog.
static void test4( String person, PrintWriter out ) { Variable X = new Variable(); Term args[] = { X, new Atom( person ) }; Query query = new Query( "descendent_of", args ); out.println( "querying descendent_of( X, " + person + " ) <br>" ); while ( query.hasMoreSolutions() ){ java.util.Hashtable solution = query.nextSolution(); out.println( "X = " + solution.get( X ) + "<br>" ); } }
We build the web application as 'proServ2'. The files are appended in appendix. Do not forget to add the following lines to 'conf/server.xml', before restarting Tomcat.
<Context path="/proServ2" docBase="webapps/proServ2" debug="0" reloadable="true" > </Context>
You start Tomcat by executing 'startup.bat' under jakarta-tomcat/bin. Open the page, 'http://127.0.0.1:8080/proServ2/index.html' and enter 'ralf' as before in the place of Name. (図[Opening the input window]) Then click 'SUBMIT' button.
You will then see the result displayed on the window as (図[Getting the result])