Building a Web Service

NeXtMidas makes it very easy to create a web service that responds to HTTP (Hyper Text Transfer Protocol) requests. This section will demonstrate the steps to create your own web service.

NOTE: This section assumes the user is familiar with HTTP and knows some basics about HTTP messages.

There are two key parts to the web server:

  1. The primitive to start/manage the server (this is the myserver class in the examples below).
  2. The library to act as the server (this is the MyServer class in the examples below).

The primitive used to start/manage the server is usually very simple. It provides the interface between the server and the NeXtMidas environment that is running the server.

package nxm.opt.prim; // <-- Your option tree goes in here

import nxm.sys.lib.*;
import nxm.opt.lib.*; // <-- Your option tree goes in here

public class myserver extends Primitive {
  private MyServer server; // Handle to the server
  
  public int open() {
    int   port    = 9999; // <-- Get port number from command line
    Table options = null; // <-- Get options table from command line
    
    server = MyServer.startNewServer(M, this, port, options);
    
    return NORMAL;
  }
  
  public int process() {
    int status = NORMAL;
    
    if (!server.isRunning()) {
      status = FINISH;
    } else {
      // The server is running in its own thread, so this thread
      // needs to pause to prevent it from taking up too much CPU.
      Time.sleep(1.0);
    }
    
    return status;
  }
  
  public int close() {
    return NORMAL;
  }
}
  

The library that extends HSource is where the real work gets done. The start() method starts the service, opens the socket, and starts the thread that will wait for incoming connections. The handleRequest(String,HPage) method will be called with each incoming request. The handleRequest(String,HPage) method is the one that does all of the real work. In this example handleRequest calls processRequest which does the work of writing out to the HPage (for any Java experts, the HPage class just wraps the underlying socket with a few ease-of-use methods).

package nxm.opt.lib; // <-- Your option tree goes in here

import nxm.sys.inc.*;
import nxm.sys.lib.*;
import nxm.sys.net.*;

public class MyServer extends HSource {
  /** Title of server displayed on the top-level page. */
  private static final String SERVER_TITLE = "My server";
  /** Directory this service resides in. */
  private static final String SERVER_DIR   = "myserver";
  
  private HServer hserver; // Handle to the HServer in use.
  private Midas   midas;   // Handle to the current Midas context.
  private Command command; // The command that started the server.
  private Table   options; // Command options.
  private boolean running; // Is the server running?
  
  
  /** Creates a new instance of the server, but does not start it.
      @param midas The Midas context to use.
      @param cmd   The command running this server.
   */
  private MyServer(HServer hserver, Midas midas,
                   Command cmd, Table options) {
    super(SERVER_DIR);
    this.hserver = hserver;
    this.midas   = midas;
    this.command = cmd;
    this.options = options;
    this.running = true;
  }
  
  /** Tells if the server is running. */
  public boolean isRunning() {
    return running;
  }
  
  
  /** Starts the server.
      @param midas   The Midas context to use.
      @param cmd     The command running this server.
      @param port    The port to use.
      @param options Any options for the server.
      @return The server that has been started.
   */
  public static MyServer startNewServer(Midas midas, Command cmd,
                                        int port, Table options) {
    HServer  server   = HServer.launch(SERVER_TITLE, port);
    MyServer myserver = new MyServer(server, midas, cmd, options);
    
    server.addSource(myserver); // Connects the server
    midas.info("MyServer: Server has been started");
    
    return myserver;
  }
  
  
  public void handleRequest(String uri, HPage hp) {
    midas.info("MyServer: Got request for "+uri+" from "
              +hp.getSocket().getRemoteSocketAddress());
    
    try {
      Table params = getParameters(uri); // Gets any URL parameters
      
      processRequest(hp, params);
    
    } catch(Exception e) {
      midas.warning("MyServer: Error while processing request "
                   +"for "+uri+": "+e);
      midas.printStackTrace(e);
    }
  }
  
  
  /** Processes the request.
      @param hp     The HPage to write to.
      @param params Any parameters from the HTTP request.
   */
  private void processRequest(HPage hp, Table params) {
    String name = params.getS("NAME");
    
    hp.open();
    hp.writeln("<html><body>");
    if (name == null) {
      hp.writeln("<h2>Hello World!</h2>");
    } else {
      hp.writeln("<h2>Hello "+name+"</h2>");
    }
    hp.writeln("</body></html>");
    hp.close();
  }
}
  

This example can then be tested by using the following URLs in a web browser:

http://localhost:9999/myserver
http://localhost:9999/myserver?NAME=Agent+Smith
  

Note that there is no mechanism for stopping the server in this example. It will be necessary to use Ctrl+C to kill NeXtMidas in order to stop it. This example simply omits the mechanism for stopping the server since such is usually application dependant.

While this example is a simple one it can be easilly expanded to include more complex tasks that involve processing data and returning different types of data or images. Please see the HPage documentation for more information.