Next: , Previous: , Up: The Prolog Library   [Contents][Index]


10.22 JSON mediated process communication—library(jsonrpc/jsonrpc_server)

This is not a library module proper, but a collection of examples of using JSON to communicate between a non-Prolog parent process and a SICStus sub-process. There are examples of writing the parent process using Python, C#, Java, C, Prolog etc.. These examples provide functionality that is similar to what is available in the language-specific libraries, e.g. library(jasper) and library(prologbeans), but do so in a language-agnostic way. The collection has been part of SICStus Prolog since release 4.5.0, but was made more visible in release 4.7.0. The code is meant to demonstrate possibilities of this process communication method. It is not intended for production use.

The collection can be found in library/jsonrpc and consists of a server written in Prolog, library/jsonrpc/jsonrpc_server.pl, and clients written in C, C#, Java, Prolog, Go, and Python, library/jsonrpc/clients/*.

Following is a number of sessions. Each session has the same structure. The client process first creates a server subprocess, then issues a number of requests to the server and reads the replies, finally shuts down the server. The interactions illustrate functionality like state updates, determinate and nondeterminate Prolog queries, backtracking, failures, and exceptions:

  1. Read the initial state.
  2. Set state to 4.
  3. Read current state.
  4. Increment current state.
  5. Increment current state again.
  6. Call member/2 and ask for the first solution.
  7. Ask for the next solution.
  8. Commit to the last solution.
  9. Call member/2 again and ask for the first solution.
  10. Ask for the next solution.
  11. Ask for the next solution.
  12. Ask for the next solution, which fails.
  13. Make a call that throws an error exception.
  14. Shut down the server.

These sessions are using Linux or macOS, the % is the shell prompt. On Windows starting the programs will be different but program outputs will be very similar. Recall that $SP_APP_PATH denotes the absolute path to the SICStus development system.

The clients are intentionally written to be very similar in structure, and to have almost identical outputs, regardless of implementation language.

The first session is with the Python client:

% python3 "$SP_LIBRARY_DIR/jsonrpc/clients/jsonrpc_client.py" "$SP_APP_PATH"
state ==> State is None
state:=4 ==> State was None
state ==> State is 4

once(Result is StateIn+1, StateOut=Result). ==> Result=5
once(Result is StateIn+1, StateOut=Result). ==> Result=6

Increment=5, once(Result is StateIn+Increment, StateOut=Result). ==> Result=11

Multiplier=10, call(member(E,[10,20,30]), Inc is Multiplier*E, Result is StateIn+Inc). ==> First Result=111
retry ==> (next) Result=211
cut ==> Result=None

Multiplier=10, call(member(E,[10,20,30]), Inc is Multiplier*E, Result is StateIn+Inc). ==> First Result=111
retry ==> (next) Result=211
retry ==> (next) Result=311
retry ==> Prolog failed (this is expected)

once(foo is bar). ==> Prolog threw an exception (this is expected): msg=Exception, data=type_error(evaluable,bar/0)

quit ==> Result=Bye

The next session is with the Prolog client:

% sicstus --nologo --noinfo \
  -l "$SP_LIBRARY_DIR/jsonrpc/clients/jsonrpc_client.pl"
state ==> State is @(null)
state:=4 ==> State was @(null)
state ==> State is 4

once('Result is StateIn+1, StateOut=Result.'). ==> Result=5
once('Result is StateIn+1, StateOut=Result.'). ==> Result=6

Increment=5, once('Result is StateIn+Increment, StateOut=Result.'). ==> Result=11

Multiplier=10, call('member(E,[10,20,30]), Inc is Multiplier*E, Result is StateIn+Inc.'). ==> First Result=111
retry ==> (next) Result=211
cut ==> Result=@(null)

Multiplier=10, call('member(E,[10,20,30]), Inc is Multiplier*E, Result is StateIn+Inc.'). ==> First Result=111
retry ==> (next) Result=211
retry ==> (next) Result=311
retry ==> Prolog failed (this is expected)

once('foo is bar.'). ==> Prolog threw an exception (this is expected): Exception 'type_error(evaluable,bar/0)'

quit ==> Result='Bye'

The next session is with the Java client:

% javac -d . "$SP_LIBRARY_DIR/jsonrpc/clients/JSONRPCClient.java"
% jar cf JSONRPCClient.jar JSONRPCClient*.class
% java -Dlogging=false -cp JSONRPCClient.jar \
  JSONRPCClient "$SP_APP_PATH"
state ==> State is null
state:=4 ==> State was null
state ==> State is 4

once(Result is StateIn+1, StateOut=Result). ==> Result=5
once(Result is StateIn+1, StateOut=Result). ==> Result=6

Increment=5, once(Result is StateIn+Increment, StateOut=Result). ==> Result=11

Multiplier=10, call(member(E,[10,20,30]), Inc is Multiplier*E, Result is StateIn+Inc). ==> First Result=111
retry ==> (next) Result=211
cut ==> Result=null

Multiplier=10, call(member(E,[10,20,30]), Inc is Multiplier*E, Result is StateIn+Inc). ==> First Result=111
retry ==> (next) Result=211
retry ==> (next) Result=311
retry ==> Prolog failed (this is expected)

once(foo is bar). ==> Prolog threw an exception (this is expected): "type_error(evaluable,bar/0)"

quit ==> Result="Bye"

The next session is with the C client:

% cc "$SP_LIBRARY_DIR/jsonrpc/clients/jsonrpc_client.c" -o jsonrpc_client
% ./jsonrpc_client "$SP_APP_PATH"

state ==> State is null
state:=4 ==> State was null
state ==> State is 4

once(Result is StateIn+1, StateOut=Result). ==> Result=5
once(Result is StateIn+1, StateOut=Result). ==> Result=6

Increment=5, once(Result is StateIn+Increment, StateOut=Result). ==> Result=11

Multiplier=10, call(member(E,[10,20,30]), Inc is Multiplier*E, Result is StateIn+Inc). ==> First Result=111
retry ==> (next) Result=211
cut ==> Result=null

Multiplier=10, call(member(E,[10,20,30]), Inc is Multiplier*E, Result is StateIn+Inc). ==> First Result=111
retry ==> (next) Result=211
retry ==> (next) Result=311
retry ==> Prolog failed (this is expected)

once(foo is bar). ==> Prolog threw an exception (this is expected)

quit ==> Result="Bye"

As mentioned above, there are sample clients in other languages as well.



Send feedback on this subject.