com.oreilly.servlet.DaemonHttpServlet Maven / Gradle / Ivy
The newest version!
// Copyright (C) 1998-2001 by Jason Hunter .
// All rights reserved. Use of this class is limited.
// Please see the LICENSE for more information.
package com.oreilly.servlet;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
/**
* A superclass for HTTP servlets that wish to accept raw socket
* connections. DaemonHttpServlet
* starts listening for client requests in its init() method
* and stops listening in its destroy() method. In between,
* for every connection it receives, it calls the abstract
* handleClient(Socket client) method. This method should
* be implemented by the servlet subclassing DaemonHttpServlet.
* The port on which the servlet is to listen is determined by the
* getSocketPort() method.
*
* @see com.oreilly.servlet.RemoteDaemonHttpServlet
*
* @author Jason Hunter, Copyright © 1998
* @version 1.0, 98/09/18
*/
public abstract class DaemonHttpServlet extends HttpServlet {
/**
* The default listening port (1313)
*/
protected int DEFAULT_PORT = 1313;
private Thread daemonThread;
/**
* Begins a thread listening for socket connections. Subclasses
* that override this method must be sure to first call
* super.init(config).
*
* @param config the servlet config
* @exception ServletException if a servlet exception occurs
*/
public void init(ServletConfig config) throws ServletException {
super.init(config);
try {
daemonThread = new Daemon(this);
daemonThread.start();
}
catch (Exception e) {
log("Problem starting socket server daemon thread" +
e.getClass().getName() + ": " + e.getMessage());
}
}
/**
* Returns the socket port on which the servlet will listen.
* A servlet can change the port in three ways: by using the
* socketPort init parameter, by setting the DEFAULT_PORT
* variable before calling super.init(), or by overriding this
* method's implementation.
*
* @return the port number on which to listen
*/
protected int getSocketPort() {
try { return Integer.parseInt(getInitParameter("socketPort")); }
catch (NumberFormatException e) { return DEFAULT_PORT; }
}
/**
* Handles a new socket connection. Subclasses must define this method.
*
* @param client the client socket
*/
abstract public void handleClient(Socket client);
/**
* Halts the thread listening for socket connections. Subclasses
* that override this method must be sure to first call
* super.destroy().
*/
public void destroy() {
try {
daemonThread.stop();
daemonThread = null;
}
catch (Exception e) {
log("Problem stopping server socket daemon thread: " +
e.getClass().getName() + ": " + e.getMessage());
}
}
}
// This work is broken into a helper class so that subclasses of
// DaemonHttpServlet can define their own run() method without problems.
class Daemon extends Thread {
private ServerSocket serverSocket;
private DaemonHttpServlet servlet;
public Daemon(DaemonHttpServlet servlet) {
this.servlet = servlet;
}
public void run() {
try {
// Create a server socket to accept connections
serverSocket = new ServerSocket(servlet.getSocketPort());
}
catch (Exception e) {
servlet.log("Problem establishing server socket: " +
e.getClass().getName() + ": " + e.getMessage());
return;
}
try {
while (true) {
// As each connection comes in, call the servlet's handleClient().
// Note this method is blocking. It's the servlet's responsibility
// to spawn a handler thread for long-running connections.
try {
servlet.handleClient(serverSocket.accept());
}
catch (IOException ioe) {
servlet.log("Problem accepting client's socket connection: " +
ioe.getClass().getName() + ": " + ioe.getMessage());
}
}
}
catch (ThreadDeath e) {
// When the thread is killed, close the server socket
try {
serverSocket.close();
}
catch (IOException ioe) {
servlet.log("Problem closing server socket: " +
ioe.getClass().getName() + ": " + ioe.getMessage());
}
}
}
}