Prolog Agent

We will use a Prolog predicate to access the Java server page. Accessing the Java server is done via the built-in streams. The Jekejeke Prolog built-in streams are able to access any URL as long as the corresponding protocol is registered in the Java system. This means that a Prolog application can open ftp:, http: and https: conversations. For the client application we will open a http: conversation to the servlet application.

The corresponding Prolog code will first built a get URL by assembling the web context URL, the target page and the search criteria. This is done inside the Prolog agent by using atom_concat/3 and url_encode_utf8/2. The atom concatenation is a Prolog predicate already defined in the ISO core standard and available as a built-in in Jekejeke Prolog. The URL UTF-8 encoding is a Java foreign predicate that we dynamically register with the knowledge base. The corresponding code reads as follows:

:- foreign(encode_parameter/2, 'Stub', encodeParameter('String')).

act(F, N, AF, AT, SF, ST, R) :-
encode_parameter(F, F8),
atom_concat('<url>/example05/service.jsp?firstname=', F8, A1),
atom_concat(A1, '&name=', A2),
encode_parameter(N,N8), atom_concat(A2, N8, A3),
atom_concat(A3, '&agefrom=', A4),
encode_parameter(AF,AF8), atom_concat(A4, AF8, A5),
atom_concat(A5, '&ageto=', A6),
encode_parameter(AT,AT8), atom_concat(A6, AT8, A7),
atom_concat(A7, '&salaryfrom=', A8),
encode_parameter(SF,SF8), atom_concat(A8, SF8, A9),
atom_concat(A9, '&salaryto=',A10),
encode_parameter(ST, ST8), atom_concat(A10, ST8, A11),

As can be seen the static method for the Java foreign predicate is defined in the interpreter stub. We will explain it below when the interpreter stub class is discussed. The code above is incomplete. Before using the above code the <url> has to point to the servlet application. After the above steps the variable A11 will hold the assembled URL. As a next step we will open a stream, fetch the data and close the stream. To protect this sequence we use the setup_call_cleanup/3 system predicate:

    setup_call_cleanup(open(A11, read, S),
                      fetch(S, R),

fetch(S,R) :- repeat, read(S, T),
              (T = end_of_file, !, fail;
               T = exception(E), throw(error(
               T = R).

The predicate fetch/2 implements a backtracking loop via the built-in predicate repeat/1. During each redo a new Prolog term is read from the stream. The Prolog term is examined and depending on its form different actions are taken. When the server response ends with an end of file, the read/2 predicate will return the atom end_of_file. The action taken is then that the predicate fetch/2 fails. When the server response is an exception term, the action taken is that the predicate fetch/2 throws an exception. In all other cases the predicate fetch/2 succeeds when the fact returned by the server unifies with the second argument. 

We can test the Prolog agent in the development environment. Before doing some testing it is important to setup the development environment so that it includes the Stub class in the class path. After having consulted the Prolog text of the agent we can then query the act/7 predicate. The simplest query sets all the search criteria to blank. The server will then return all employee/4 facts. For each fact one solution is generated which we can explore via backtracking. The first invocation will take a little bit more time since the server will first load its table data:

?- [example05/agent].
?- act('','','','','','',X).
X = employee('Сергей', 'Иванов', 53, 18500) ;
X = employee('Сергей', 'Беляев', 53, 19000) ;
X = employee('Hans', 'Fischer', 62, 21500) ;

The setup_call_cleanup/3 system predicate will see to it that the execution of the closing of the stream is guaranteed when the search finishes or when the search is terminated. There-fore there is no harm when an exception occurs during the search or when the search is manually terminated. The stream will always be properly closed.