The interface org.xoe.core.IShell provides the simple service definition needed to implement a XOE Shell.
public interface IShell extends IService { public void start (); }For a better understanding of how to use the interface, let's examine the XOE startup procedure.
There is a three phases procedure the XOE Engine follows during startup:
The bootstrap file is read from disk.
The name of the file to use for bootstrap may be set in config.xml, or passed on the command line via the xoe.bootstrap property. If the name of the bootstrap file isn't specified in either place, the default is used: .xoe/bootstrap.xml
The bootstrap file is processed.
Each subsystem, service and package specified in the file (by the load tag) is installed.
Example 12-1. Excerpted listing from the default bootstrap file: bootstrap.xml
<bootstrap> <!-- load up the main configuration file --> <load subsystem="org.xoe.core.Engine" config="config.xml"/> <!-- set the default locale --> <load subsystem="org.xoe.core.LocaleSubsystem"/> <!-- install basic protocols --> <load subsystem="org.xoe.core.ProtocolSubsystem"/> <load service="org.xoe.core.protocol.StashHandler"/> ... <load package="device-linux"/> ...
The shell is started.
The first service that registered as an IShell is located and it's start method is invoked.
Looking at the above process, we can see that launching a custom shell is as simple as ensuring that the load line for the new shell appears before the default shell's load line in the bootstrap file, or by simply removing the default shell's load line from the bootstrap file altogether.
So what happens in start? Well, everything! The first step in implementing a new shell is deciding on the user interface. Will it be a command line interface for a small character display? Or browser interface using XHTML? Maybe it won't have an interface at all, but instead start up, install some services and wait for SOAP instructions to come in over the network... the possibilities are virtually limitless.
Let's compare two approaches:
Example 12-2. Excerpted listing from the default XOE Shell: org.xoe.shell.Main
public void start () { /* * Find the service which manages the devices screen. */ IScreen screen = (IScreen) ServiceLocator.findImplementor (IScreen.INTERFACE); if (screen == null) { Logger.log (this, "*** ERROR *** No screen found"); System.exit (1); } /* * Setup the AWT window so we can manage the GUI. */ Container win = screen.getScreen (); Render render = new Render (); win.add (render); /* * Get the shell's default view and put it on the screen. */ render.setDocument (getViewableDocument ()); win.validate (); win.repaint (); /* * Here's where this thread ends. When the user interacts with * default view, the shell is notified of the event by the * appropriate callback and will process it at that time. */ }
Example 12-3. Excerpted listing from a character-based debug shell: org.xoe.DebugShell
public void start () { /* * Local variable to read the user's commands into */ String command; /* * Display the welcome message. */ System.out.println ("Welcome to the XOE debug shell."); System.out.println ("Copyright 2001 Transvirtual Technologies, Inc."); System.out.println ("XOE Version is " + Engine.getVersion ()); System.out.println ("Type 'help' for a list of commands."); /* * Loop until the user quits the shell. */ while (true) { /* * Display the prompt. */ System.out.print (PROMPT); Vector args = new Vector (); try { /* * Read in the user's command. */ command = readCommand (args); } catch (IOException e) { System.err.println (e); break; } /* * Process the user's command. */ if (!doCommand (command, args)) { /* * Effectively terminate the shell. */ break; } } }