From p.singleton@keele.ac.uk  Fri Nov 17 15:38:56 2000
Received: from mail4.svr.pol.co.uk (mail4.svr.pol.co.uk [195.92.193.211])
	by swi.psy.uva.nl (8.9.3/8.9.3) with ESMTP id PAA09463
	for <prolog@swi.psy.uva.nl>; Fri, 17 Nov 2000 15:38:56 +0100 (MET)
Received: from modem4294967187.people.dialup.pol.co.uk ([195.92.3.109] helo=keele.ac.uk)
	by mail4.svr.pol.co.uk with esmtp (Exim 3.13 #0)
	id 13wmfR-0004tR-00
	for prolog@swi.psy.uva.nl; Fri, 17 Nov 2000 14:39:05 +0000
Message-ID: <3A1542D2.CC0B6ABA@keele.ac.uk>
Date: Fri, 17 Nov 2000 14:38:10 +0000
From: Paul Singleton <p.singleton@keele.ac.uk>
Organization: SmartArts Computing Consultancy
X-Mailer: Mozilla 4.74 [en] (WinNT; U)
X-Accept-Language: en
MIME-Version: 1.0
To: prolog@swi.psy.uva.nl
Subject: Re: Launching Prolog from Java
References: <007801c05075$e1659320$c6655dc0@greyc.ismra.fr>
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Pierre Nugues wrote:

> I would like to launch SWI-Prolog from Java. I just need to redirect socket
> streams to Prolog's standard input and output before launching it. It's
> fairly easy to do that with Unix and C with dup() and execv().
> 
> There is an exec() method in Java but apparently it doesn't enable stream
> passing.
> Is there a workaround?

As a Java newbie concerned only to exploit Java (via my Prolog-calls-Java
interface) to provide my (Standard) Prolog apps with portable access to
their environment, I wrote this code (which I no longer understand :-)

    import java.lang.*;
    import java.io.*;

    public class Xfer extends Thread
        {
        private InputStream in;
        private OutputStream out;

        public Xfer( InputStream s1, OutputStream s2)
            {
            in = s1;
            out = s2;
            }

        public void run()
            {
            int c;

            try    {
                while ( (c=in.read()) != -1 )
                    {
                    out.write(c);
                    }
                in.close();
                out.close();
                }
            catch ( IOException e )
                {
                }
            }
        }

I believe that constructing a new Xfer(InputStream,OutputStream)
starts a thread which copies InputStream to OutputStream.

I use this in a gadget which runs an external application to completion,
providing its stdin as a String, and catching and returning its stdout
and stderr in new Strings:

    public static int
    spawn_in_out_err( String command, String infile, String outfile, String
errfile)
        {
        Process p;

        try    {
            p = Runtime.getRuntime().exec(command);
            }
        catch ( IOException e)
            {
            return -1;
            }

        try    {
            if ( infile != null )
                {
                ( new Xfer(
                        new FileInputStream(infile),
                        p.getOutputStream()
                    )).start();
                }
            if ( outfile != null )
                {
                ( new Xfer(
                        p.getInputStream(),
                        new FileOutputStream(outfile)
                    )).start();
                }
            if ( errfile != null )
                {
                ( new Xfer(
                        p.getErrorStream(),
                        new FileOutputStream(errfile)
                    )).start();
                }
            return p.waitFor();
            }
        catch ( FileNotFoundException e )
            {
            return -2;
            }
        catch ( IOException e )
            {
            return -3;
            }
        catch ( InterruptedException e )
            {
            return -4;
            }
        }

I believe this could be adapted to connect the in, out and err streams of the
new Process to three existing Java streams.

> Pierre
> 
> PS I know of JPL. I would like to know whether there is something simpler

As co-guardian of JPL (with Fred Dushin its author), I'd like to be able to
map SWI-Prolog streams into Java within JPL too, but I don't know how.
Suggestions very welcome, especially if they only involve the published
FLI (rather than delving into the sources).

NB JPL starts SWI-Prolog "in-process", by dynamically linking the libpl.dll
(or .so) shared library to the JVM, and provides a tight coupling at the
Prolog "API" level (build terms, call non-determinate goals, fetch bindings
etc.) rather than at the "teletype interface" level.

This makes the JVM vulnerable to memory faults in Prolog or (more likely :-)
in foreign libraries loaded by Prolog.

With a suitable socket protocol, we could run Prolog in a separate process,
yet support (effectively) the same tight coupling.

(the traditional teletype interface is not a suitable protocol :-)

This would allow Java to recover from Prolog crashes, and would allow a
"pure Java" interface to Prolog, which would in turn allow Prolog-generated
dynamic Web pages to be published via a Java Servlet web server without
endangering the server.

NB the Servlet interface would allow (sequential) reuse of the Prolog process
(managing this sort of thing is what the Servlet interface is all about), so
we would't necessarily start a new Prolog process for each HTTP request.  And
I guess it could exploit multi-threading in Prolog too...

Paul Singleton

