// ********************************************************************** // // <copyright> // // BBN Technologies // 10 Moulton Street // Cambridge, MA 02138 // (617) 873-8000 // // Copyright (C) BBNT Solutions LLC. All rights reserved. // // </copyright> // ********************************************************************** // // $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/layer/util/http/HttpServer.java,v $ // $RCSfile: HttpServer.java,v $ // $Revision: 1.5 $ // $Date: 2005/08/09 18:57:51 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.util.http; import java.io.IOException; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Enumeration; import java.util.Vector; /** * A simple HTTP Server implementing HTTP/0.9 protocols. * * Cobbled together from a server originally written by David Flanagan * for the book <b>Java in a Nutshell </b>, Copyright(c) 1996 * O'Reilly & Associates. * * Modified to use JDK 1.1 Readers, and Writers. Further modified to * use the JDK 1.1 Event model. * * @author Tom Mitchell * @version 1.0, 06/13/97 */ public class HttpServer extends Thread { /** * The default port. A port of 0 (zero) causes the system to * allocate any unused port. With any other number the system will * attempt to open that port, and throw an exception if it is in * use. */ public final static int DEFAULT_PORT = 0; protected int port; protected ServerSocket listen_socket; protected Vector listeners; /** * Creates an Http Server on the indicated port, and then starts a * thread that listens to that port. The thread will not be a * daemon thread. * * @param port the port to open * @see java.net.ServerSocket */ public HttpServer(int port) throws IOException { this(port, false); } /** * Creates an Http Server on the indicated port, and then starts a * thread that listens to that port. The thread will be a daemon * thread of asDaemon is true. * * @param port the port to open * @param asDaemon whether to make thread a daemon * @see java.net.ServerSocket */ public HttpServer(int port, boolean asDaemon) throws IOException { this.port = port; listeners = new Vector(); listen_socket = new ServerSocket(port); this.setDaemon(asDaemon); } /** * Creates an Http Server on any free port, and then starts a * thread that listens to that port. * * @see java.net.ServerSocket */ public HttpServer() throws IOException { this(DEFAULT_PORT); } /** * The body of the server thread. Loop forever, listening for and * accepting connections from clients. For each connection, create * a HttpConnection object to handle communication through the new * Socket. * * @see HttpConnection * @see java.net.Socket */ public void run() { try { while (true) { Socket client_socket = listen_socket.accept(); HttpConnection httpConnection = new HttpConnection(client_socket, this); httpConnection.start(); } } catch (IOException e) { System.err.println("Exception while listening for connections"); e.printStackTrace(); } } /** * Gets the port associate with this server. * * @return the server's port */ public int getPort() { return listen_socket.getLocalPort(); } /** * Creates a HttpRequestEvent and sends it to all registered * listeners. * * @param request the parsed http request * @param output OutputStream associated with the request's client * connection. * @see java.io.DataOutputStream * @see HttpRequestListener * @see HttpRequestEvent */ public HttpRequestEvent fireHttpRequestEvent(String request, OutputStream output) throws IOException { HttpRequestEvent event = new HttpRequestEvent(this, request, output); HttpRequestListener listener; // Make a copy of the list and fire the events using that // copy. // This means that listeners can be added or removed from the // original list in response to this event. Vector list = (Vector) listeners.clone(); Enumeration e = list.elements(); while (e.hasMoreElements()) { listener = (HttpRequestListener) e.nextElement(); listener.httpRequest(event); } return event; } /** * Adds a new http request listener. Don't add multiple listeners * when binary content responses are required! One Listener should * handle binary responses, because the result length needs to be * calculated. You can add multiple Listeners that use the Writer * inside the HttpRequestEvent to concatenate a complete text * response. * * @param l the listener * @see HttpRequestListener */ public void addHttpRequestListener(HttpRequestListener l) { listeners.addElement(l); } /** * Removes an http request listener. * * @param l a listener * @see HttpRequestListener */ public void removeHttpRequestListener(HttpRequestListener l) { listeners.removeElement(l); } /** * A main routine for unit testing. Starts a HttpServer, adds * several HttpRequestListeners, and waits for connections. * <p> * Usage: java com.bbn.openmap.layer.util.http.HttpServer [port] * <p> * If no port is specified, the default port is used. * <p> * If port zero is specified, the system chooses the port. * <p> * If a port other than zero is specified, the http server will * attempt to open that port, or fail if it is in use. * <p> * Examples: * <p> * java com.bbn.openmap.layer.util.http.HttpServer * <p> * java com.bbn.openmap.layer.util.http.HttpServer 8000 * <p> * java com.bbn.openmap.layer.util.http.HttpServer 0 * <p> * * @param args command line args */ public static void main(String[] args) { int port = 0; if (args.length == 1) { try { port = Integer.parseInt(args[0]); } catch (NumberFormatException e) { port = 0; } } try { HttpServer server = new HttpServer(port); server.addHttpRequestListener(new SeparatorListener()); server.addHttpRequestListener(new SieveListener()); server.addHttpRequestListener(new SeparatorListener()); server.addHttpRequestListener(new ReverseListener()); server.addHttpRequestListener(new SeparatorListener()); server.start(); System.out.println("Server listening on port " + server.getPort()); } catch (IOException e) { System.err.println("Unable to start http server:"); e.printStackTrace(); } } }