001// Copyright (C) 1998-2001 by Jason Hunter <jhunter_AT_acm_DOT_org>.
002// All rights reserved.  Use of this class is limited.
003// Please see the LICENSE for more information.
004
005package com.oreilly.servlet;
006
007import java.io.*;
008import java.net.*;
009import java.rmi.*;
010import java.rmi.server.*;
011import java.rmi.registry.*;
012import java.util.*;
013import javax.servlet.*;
014import javax.servlet.http.*;
015
016/** 
017 * A superclass for any HTTP servlet that wishes to act as an RMI server
018 * and, additionally, accept raw socket connections.  Includes the 
019 * functionality from both RemoteHttpServlet and DaemonHttpServlet, by
020 * extending DaemonHttpServlet and re-implementing RemoteHttpServlet.
021 *
022 * @see com.oreilly.servlet.RemoteHttpServlet
023 * @see com.oreilly.servlet.DaemonHttpServlet
024 *
025 * @author <b>Jason Hunter</b>, Copyright &#169; 1998
026 * @version 1.0, 98/09/18
027 */
028public abstract class RemoteDaemonHttpServlet extends DaemonHttpServlet
029                                              implements Remote {
030  /**
031   * The registry for the servlet
032   */
033  protected Registry registry;
034
035  /**
036   * Begins the servlet's RMI operations and begins a thread listening for
037   * socket connections.
038   * Subclasses that override this method must be sure to first call 
039   * <tt>super.init(config)</tt>.
040   * 
041   * @param config the servlet config
042   * @exception ServletException if a servlet exception occurs
043   */
044  public void init(ServletConfig config) throws ServletException {
045    super.init(config);
046    try {
047      UnicastRemoteObject.exportObject(this);
048      bind();
049    }
050    catch (RemoteException e) {
051      log("Problem binding to RMI registry: " + e.getMessage());
052    }
053  }
054
055  /**
056   * Halts the servlet's RMI operations and halts the thread listening for
057   * socket connections.  Subclasses that 
058   * override this method must be sure to first call <tt>super.destroy()</tt>.
059   */
060  public void destroy() {
061    super.destroy();
062    unbind();
063  }
064
065  /**
066   * Returns the name under which the servlet should be bound in the
067   * registry.  By default the name is the servlet's class name.  This
068   * can be overridden with the <tt>registryName</tt> init parameter.
069   *
070   * @return the name under which the servlet should be bound in the registry
071   */
072  protected String getRegistryName() {
073    // First name choice is the "registryName" init parameter
074    String name = getInitParameter("registryName");
075    if (name != null) return name;
076
077    // Fallback choice is the name of this class
078    return this.getClass().getName();
079  }
080
081  /**
082   * Returns the port where the registry should be running.  By default 
083   * the port is the default registry port (1099).  This can be 
084   * overridden with the <tt>registryPort</tt> init parameter.
085   *
086   * @return the port for the registry
087   */
088  protected int getRegistryPort() {
089    // First port choice is the "registryPort" init parameter
090    try { return Integer.parseInt(getInitParameter("registryPort")); }
091
092    // Fallback choice is the default registry port (1099)
093    catch (NumberFormatException e) { return Registry.REGISTRY_PORT; }
094  }
095
096  /**
097   * Binds the servlet to the registry.  Creates the registry if necessary.
098   * Logs any errors.
099   */
100  protected void bind() {
101    // Try to find the appropriate registry already running
102    try {
103      registry = LocateRegistry.getRegistry(getRegistryPort());
104      registry.list();  // Verify it's alive and well
105    }
106    catch (Exception e) {
107      // Couldn't get a valid registry
108      registry = null;
109    }
110
111    // If we couldn't find it, we need to create it.
112    // (Equivalent to running "rmiregistry")
113    if (registry == null) {
114      try {
115        registry = LocateRegistry.createRegistry(getRegistryPort());
116      }
117      catch (Exception e) { 
118        log("Could not get or create RMI registry on port " +
119            getRegistryPort() + ": " + e.getMessage());
120        return;
121      }
122    }
123
124    // If we get here, we must have a valid registry.
125    // Now register this servlet instance with that registry.
126    try {
127      registry.rebind(getRegistryName(), this);
128    }
129    catch (Exception e) {
130      log("humbug Could not bind to RMI registry: " + e.getMessage());
131      return;
132    }
133  }
134
135  /**
136   * Unbinds the servlet from the registry.
137   * Logs any errors.
138   */
139  protected void unbind() {
140    try {
141      if (registry != null) registry.unbind(getRegistryName());
142    }
143    catch (Exception e) {
144      log("Problem unbinding from RMI registry: " + e.getMessage());
145    }
146  }
147
148}