The Artima Developer Community
Sponsored Link

The Cyberspace Console
By Bill Venners

Advertisement

Summary
In this document I show a Java application, which ran as a server on my laptop during the Cyberspace demo, that was responsible for launching resources.


In the Cyberspace demo, I used a server running locally on my laptop called the Cyberspace Console. The browser plug-in and the Place services themselves (via a call to launchResource() on the service context object) connected via a socket and "localhost" to the Cyberspace Console, to request that a new resource be launched for the user. If the resource was a Jini service, the Cyberspace Console exec'ed an ObjectLauncher. Here's the code for CyberspaceConsole:

/*
 * This source code (.java) file is Copyright (C) 2000 Artima Software, Inc. All rights reserved.
 * This file accompanies the Jini Place Service Draft Specification, written by Bill
 * Venners and published on the World Wide Web at:
 *
 *     http://www.artima.com/jini/cyberspace/DraftSpec.html,
 *
 * This source file may not be copied, modified, or redistributed EXCEPT as allowed
 * by the following statements: From August 11, 2000 through December 31, 2000, you may
 * copy and/or modify these files to test and experiment with the Place API,
 * described in the Jini Place Service Draft Specification. Any bug fixes must be given
 * back to Artima Software, Inc. You may not redistribute this file or any binary (such
 * as .class) files generated from this file. You may not distribute modified versions
 * this files or any binary (such as .class) files generated from modified versions of
 * this file. You may not remove this copyright notice. You may not use this file in
 * printed media without the express permission of Bill Venners. And if that weren't
 * enough, you must destroy all copies of this file, and any binary (such as
 * .class) files generated from this file, by December 31, 2000.
 *
 * ARTIMA SOFTWARE, INC. MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THIS SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
 * BILL VENNERS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY A LICENSEE AS A RESULT
 * OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*/
import java.io.IOException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.ObjectInputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.Socket;
import java.net.ServerSocket;
import java.io.StreamCorruptedException;
import java.io.OptionalDataException;

public class CyberspaceConsole {

    private static final int PORT = 7718;

    // The command sent from either the Netscape browser's Cyberspace Plug-In
    // or a Jini Place service itself. CMD_LAUNCH_URL means a URL follows
    // the command. CMD_LAUNCH_OBJECT means a serialized marshalled
    // ServiceItem follows the command. In the demo, the browser plug-in
    // passes the serialized marshalled service item that came across the
    // network as the application/x-serviceui MIME type.
    private static final int CMD_LAUNCH_URL = 0;
    private static final int CMD_LAUNCH_OBJECT = 1;

    // The command to launch a Jini service and service UI. This likely just
    // works on my computer, which was good enough for the demo. To get the demo
    // working on your computer, you'll have to tweak this variable.
    private static String[] execCmd = {

        "c:\\jdk1.3\\bin\\java",
        "-cp",
        "d:\\projects\\serviceui\\apicode;d:\\projects\\cyberspace\\apicode;       /
            c:\\jini1_0_1\\lib\\jini-core.jar;c:\\jini1_0_1\\lib\\jini-ext.jar;    /
            c:\\jini1_0_1\\lib\\sun-util.jar; d:\\projects\\cyberspace\\launcher",
        "-Djava.security.policy=c:/jini1_0_1/example/lookup/policy.all",
        "ObjectLauncher",
        ""
    };

    // The command to launch the Netscape browser. Once again, this is hard-coded for my
    // computer, which was good enough for the demo. To get this working on your own
    // system, you may need to edit this variable. You may also need to make sure that
    // the browser is in your path.
    private static String[] browserCmd = {

        //"d:\\progra~1\\Netscape\\Communicator\\Program\\netscape",
        "netscape",
        "-browser",
        ""
    };

    private static class MonitorInputStreamThread extends Thread {

        private Reader reader;
        private Writer writer;

        public MonitorInputStreamThread(InputStream in) {

            reader = new InputStreamReader(new BufferedInputStream(in));
            writer = new OutputStreamWriter(System.out);
            setDaemon(true);
        }

        public void run() {

            try {
                int c;
                while ((c = reader.read()) != -1) {

                    writer.write(c);
                    writer.flush();
                }
            }
            catch (IOException ioe) {
                ioe.printStackTrace(System.out);
            }
            System.out.println("MonitorInputStreamThread exiting...");
        }
    }

    // A thread that handles a single client request.
    private static class ServerThread extends Thread {

        private Socket sock;

        public ServerThread(Socket sock) {
            this.sock = sock;
        }

        public void run() {

            try {

                BufferedInputStream in =
                    new BufferedInputStream(
                        sock.getInputStream()
                    );

                try {

                    // The first byte is a command that indicates what
                    // type of data follows.
                    int command = in.read();

                    if (command == CMD_LAUNCH_URL) {
                        launchURL(in);
                    }
                    else if (command == CMD_LAUNCH_OBJECT) {

                        launchObject(in);
                    }
                    else {
                        System.out.println("Unkown command, ignoring.");
                    }
                }
                finally {
                    in.close();
                }
            }
            catch (IOException ioe) {
                ioe.printStackTrace(System.out);
            }
            finally {
                try {
                    sock.close();
                }
                catch (IOException e) {
                }
            }
        }
    }

    public static void main(String[] args)
        throws IOException {

        // Listen on port 7777 for incoming commands
        ServerSocket listener = new ServerSocket(PORT);

        try {

            for (;;) {

                Socket sock = listener.accept();

                // Start a new ServerThread to handle each
                // incoming request.
                ServerThread ss = new ServerThread(sock);
                ss.start();
            }
        }
        finally {
            listener.close();
        }
    }

    private static void launchURL(InputStream in) {

        ObjectInputStream ois;

        try {
            // Client passes the URL as a String object, so wrap
            // the InputStream in an ObjectInputStream.
            ois = new ObjectInputStream(in);
        }
        catch (StreamCorruptedException sce) {
            System.out.println("URL String object input stream corrupted. Aborting.");
            return;
        }
        catch (IOException ioe) {
            System.out.println("IOException while deserializing URL String. Aborting.");
            return;
        }

        String url;
        try {
            // Deserialize the URL String object
            url = (String) ois.readObject();
        }
        catch (OptionalDataException ode) {
            System.out.println("OptionalDataException while attempting to deserialize a URL String. Aborting.");
            return;
        }
        catch (IOException ioe) {
            System.out.println("IOException while deserializing URL String. Aborting.");
            return;
        }
        catch (ClassNotFoundException cnfe) {
            System.out.println("ClassNotFoundException while deserializing URL String. Aborting.");
            return;
        }

        System.out.println("runResourceWithUI(" + url + ")");

        String[] cmd;

        // If its a .serviceui file, pass the URL to the ObjectLauncher.
        // Otherwise, just pass the URL to the browser.
        if (url.endsWith(".serviceui")) {
            execCmd[5] = url;
            cmd = execCmd;
        }
        else {
            browserCmd[2] = url;
            cmd = browserCmd;
        }

        try {
            Process process = Runtime.getRuntime().exec(cmd);

            // Start threads to suck the bytes out of the stderr
            // and stdout. If you don't do this, Windows will hang.
            // Besides, it's sometimes nice to see what those Jini
            // services are printing to the stdout and stderr. That's
            // what makes this the Cyberspace *Console*.
            InputStream processOut = process.getInputStream();
            InputStream processErr = process.getErrorStream();

            Thread thread = new MonitorInputStreamThread(processOut);
            thread.start();

            thread = new MonitorInputStreamThread(processErr);
            thread.start();
        }
        catch (IOException ioe) {
            ioe.printStackTrace(System.out);
        }
    }

    private static void launchObject(InputStream in) {

        BufferedInputStream buffin = new BufferedInputStream(in);

        execCmd[5] = "";

        try {
            Process process = Runtime.getRuntime().exec(execCmd);

            // Start threads to suck the bytes out of the stderr
            // and stdout. If you don't do this, Windows will hang.
            // Besides, it's sometimes nice to see what those Jini
            // services are printing to the stdout and stderr. That's
            // what makes this the Cyberspace *Console*.
            InputStream processOut = process.getInputStream();
            InputStream processErr = process.getErrorStream();

            Thread thread = new MonitorInputStreamThread(processOut);
            thread.start();

            thread = new MonitorInputStreamThread(processErr);
            thread.start();

            // Feed the bytes of the serialized object to the process's stdin
            BufferedOutputStream buffout = new BufferedOutputStream(process.getOutputStream());
            try {

                int c;
                while ((c = buffin.read()) != -1) {
                    buffout.write(c);
                }
            }
            finally {
                buffout.flush();
                buffout.close();
            }
        }
        catch (IOException ioe) {
            ioe.printStackTrace(System.out);
        }
    }
}

Discussion Forum

To discuss the ideas presented in this article please post to the cyberspace@jini.org mailing list, or visit:

http://www.artima.com/jini/jf/cyberspace/index.html

For a more in-depth explanation of the cyberspace project, please see the A Walk Through Cyberspace article.

ServiceUI is a trademark of Artima Software, Inc.

Sponsored Links



Google
  Web Artima.com   
Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us