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