ServletCTL.java

This abstract class is the basis for the creation of any other controller classes that are used in the MVC architecture for building web applications. Classes that extend the ServletCTL class are greaty simplified. An example of this is the StateToVendorPaymentCTL.java. This controller class was used before I started using other MVC framworks like Struts.
package cpa.app.vip;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.lang.reflect.*;
import java.util.StringTokenizer;


/*************************************************************************
 * This servlet controller (CLT) class handles HTTP requests and
 * uses the extra path information in a URL to call an object
 * and/or method.  If both object and method are provided the servlet
 * calls the the method in the target object residing
 * in session.  If only one element is in the extra path information
 * is provided only the method defined within the servlet is called.
 *
 * This class was created based on the article in the December 2000
 * JavaWorld "Servlet Reflection - Untagle your servlet code with
 * reflection."  The servlet uses relflection to call the the designated
 * method based on paramaters in the "extra path" information in the
 * passed URL.  The benefit of this approach is to help simplify
 * servlet code, ability to centralize repeated methods in the abstract
 * class, and a better ability to use an object-oriented style in
 * servlet programming.
 *
 * Example in: /ecpa/vip/StateToVendorPaymentCTL/handleStateAgencyMaint/
 *
 * The handleStateAgencyMaint method will be called from the
 * StateToVendorPaymentCTL controller servlet.  
 *
 * @author Paul McKinney
 *************************************************************************/
abstract public class ServletCTL extends HttpServlet
{


   /************************************************************************
    * Handles HTTP POST resquest.
    *
    * @param request  object used to provide the servlet information about
    *                 the request
    * @param response response that the servlet provides back to the
    *                 client
    ************************************************************************/
   public void doPost(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException
   {
      doGetOrPost(request, response);
   }


   /************************************************************************
    * Handles HTTP GET resquest.
    *
    * @param request  object used to provide the servlet information about
    *                 the request
    * @param response response that the servlet provides back to the
    *                 client
    ************************************************************************/
   public void doGet(HttpServletRequest request, HttpServletResponse response) 
                      throws ServletException, IOException
   {
      doGetOrPost(request, response);
   }


   /************************************************************************
    * Takes the request from the POST or GET, parses out the object name
    * and method name (if any) and calls the dispatch method.
    *
    * @param request  object used to provide the servlet information about
    *                 the request
    * @param response response that the servlet provides back to the
    *                 client
    ************************************************************************/
   private void doGetOrPost(HttpServletRequest request, 
                            HttpServletResponse response)
   {
      try
      {
         ParsedPathInfo ppi = new ParsedPathInfo(request);
         dispatch(getController(ppi.object,ppi.methodName),
                  ppi.object,
                  request,
                  response);
      }
      catch (ControllerNotFoundException e)
      {
         handleControllerNotFound(request, response);
      }
   }


   /************************************************************************
    * Called if a problem with calling the method.
    *
    * @param request  object used to provide the servlet information about
    *                 the request
    * @param response response that the servlet provides back to the
    *                 client
    ************************************************************************/
   abstract protected void handleControllerNotFound(HttpServletRequest request, 
                                                 HttpServletResponse response);


   /************************************************************************
    * Called if the method is not found.
    *
    * @param request  object used to provide the servlet information about
    *                 the request
    * @param response response that the servlet provides back to the
    *                 client
    ************************************************************************/
   abstract protected void handleRequest(HttpServletRequest request, 
                                         HttpServletResponse response);


   /***********************************************************************
    * Invokes a method against a target object using the request and
    * response objects as paramaters.
    *
    * @param method   method to dispatch
    * @param target   object in which the method is run against
    * @param request  object used to provide the servlet information about
    *                 the request
    * @param response response that the servlet provides back to the
    *                 client
    ***********************************************************************/
   protected void dispatch(Method method, Object target, 
                           HttpServletRequest request, 
                           HttpServletResponse response) 
                throws ControllerNotFoundException
   {
      try
      {
         method.invoke(target, new Object[] {request, response});
      }
      catch (IllegalAccessException ex)
      {
         throw new ControllerNotFoundException("Error:ServletCTL:IAE:" +
             "couldn't access method");
      }
      catch (InvocationTargetException ex)
      {
         ex.printStackTrace();
         throw new ControllerNotFoundException("Error:ServletCTL:ITE:" +
             "object doesn't have method");
      }
   }


   //gets classes of Class for HttpServletRequest and HttpServletResponse 
   //using class literals
   static final Class[] sFormalArgs = {HttpServletRequest.class, 
                                       HttpServletResponse.class};


   protected Method getController(Object target, String methodName)
                                    throws ControllerNotFoundException
   {
      try
      {
         return target.getClass().getMethod(methodName,sFormalArgs);
      }
      catch (NoSuchMethodException e)
      {
         throw new ControllerNotFoundException("Error:ServletCTL:" +
             "getController:couldn't get method");
      }
   }


   class ControllerNotFoundException extends ServletException
   {
      ControllerNotFoundException(String reason)
      {
         super(reason);
      }
   }


   protected Object getDefaultObject()
   {
      return this;
   }


   /*************************************************************
    * Encapsulates the methods and properties used to parse out
    * the object and method in the extra path information
    * in a URL.
    *************************************************************/
   public class ParsedPathInfo
   {
      String methodName;
      Object object;
      private String firstPart;
      private String secondPart;

      /************************************************************************
       * Takes the extra path info in a URL and returns an object or
       * default object if none specified and method or default method
       * if none specified.
       *
       * @param request  object used to provide the servlet information about
       *                 the request
       * @param response response that the servlet provides back to the
       *                 client
       ************************************************************************/
      public ParsedPathInfo(HttpServletRequest request) 
                   throws ServletCTL.ControllerNotFoundException
      {
         String pathInfo = normalize(request.getPathInfo());
         parsePath(pathInfo);
         if (secondPart == null && firstPart == null)
         {
            object = getDefaultObject();
            methodName = "handleRequest";
         }
         else if (secondPart == null)
         {
            object = getDefaultObject();
            methodName = firstPart;
         }
         else
         {
            object = request.getSession().getValue(firstPart);
            methodName = secondPart;
            if (object == null) 
            {
               throw new ControllerNotFoundException(
                         "Error:ServletCTL:ParsedPathInfo:ParsedPathInfo:" + 
                         "missing object");
            }
         }
      }


      private String normalize(String pathInfo)
      {
         return (pathInfo != null) ? pathInfo : "/";
      }


      private void parsePath(String pathInfo)
      {
         StringTokenizer tokens = new StringTokenizer(pathInfo,"/");
         if (tokens.hasMoreTokens())
         {
            firstPart = tokens.nextToken();
         }
         if (tokens.hasMoreTokens())
         {
            secondPart = tokens.nextToken();
         }
      }
   } //class ParsedInfoPath

}