JMU
Design of an HTTP Server that uses Reflection for Servlets
A Simple Network Application in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


A Shortcoming of the Current Implementation
A Shortcoming of the Current Implementation (cont.)
javaexamples/http/v3/HttpServletFactory.java
import java.io.*;


/**
 * Constructs servlets appropriate based on 
 * the file-type in the request.
 *
 * Note that the Singleton pattern is used to construct
 * the factory itself.
 *
 * @version 0.3
 * @author  Prof. David Bernstein, James Madison University
 */
public class HttpServletFactory
{
    // For the Singleton pattern
    private static HttpServletFactory  instance = new HttpServletFactory();

    // Actual attributes
    private File                file;
    private long                lastModified;
    private NameValueMap        associations;

    private static final String       FILE_NAME            
                                      = "associations.dat";
    private static final NameValueMap DEFAULT_ASSOCIATIONS 
                                      = NameValueMap.createNameValueMap();

    /**
     * Default Constructor
     */
    private HttpServletFactory()
    {
       file = new File(FILE_NAME);
       lastModified = -1;
       associations = NameValueMap.createNameValueMap();
       loadAssociations();
    }

    /**
     * Create an HttpServletFactory
     */
    public static HttpServletFactory createFactory()
    {
       return instance;
    }

    /**
     * Construct an HttpServlet
     *
     * @param req   The HTTP request
     * @param in    The HttpInputStream to read from
     * @param out   The HttpOutputStream to write to
     */
    public HttpServlet createServlet(HttpRequest req, 
                                     HttpInputStream in, HttpOutputStream out)
    {
       Class                  c;
       HttpServlet            servlet;
       String                 className, ext, fname;

       servlet   = null;

       loadAssociations();
       fname     = req.getRequestURI();
       ext       = FileTyper.getExtension(fname);
       className = associations.getValue(ext);

       if (className == null) 
       {
          servlet = new DefaultHttpServlet(in, out);
       }
       else if (className.equals("TemplatedHttpServlet"))
       {
          servlet = new TemplatedHttpServlet(in, out);
       }
        

       return servlet;
    }

    /**
     * Load the associations between file types and
     * servlets (if they have changed on disk)
     */
    private void loadAssociations()
    {
       BufferedReader     in;
       long               modified;
        

       modified = file.lastModified();
       if (modified > lastModified) 
       {
          try 
          {
             in = new BufferedReader(new FileReader(new File(FILE_NAME)));
             associations.clear();
             associations.putPairs(in, "\\s");
             lastModified = modified;
          } 
          catch (Exception e) 
          {
             associations = DEFAULT_ASSOCIATIONS;
          }
       }
    }
}
        
Improving the Implementation
Constructing Objects Using Reflection
Using Constructors
Using Constructors (cont.)
    /**
     * Construct an HttpServlet
     *
     * @param req   The HTTP request
     * @param in    The HttpInputStream to read from
     * @param out   The HttpOutputStream to write to
     */
    public HttpServlet createServlet(HttpRequest req, 
                                     HttpInputStream in, 
                                     HttpOutputStream out)
    {
       Class                  c;
       HttpServlet            servlet;
       String                 className, ext, fname;

       servlet   = null;

       loadAssociations();
       fname     = req.getRequestURI();
       ext       = FileTyper.getExtension(fname);
       className = associations.getProperty(ext);


       if (className == null)
       {
           servlet = new DefaultHttpServlet(in, out);
       }
       else // Use reflection to create an appropriate servlet
       {
         try
         {
             Class       cl = Class.forName(className);
             Constructor co = cl.getConstructor(new Class[]{HttpInputStream.class, 
                                                            HttpOutputStream.class});
             servlet = (HttpServlet)co.newInstance(in, out);
         }
         catch (Exception e)
         {
             servlet = new DefaultHttpServlet(in, out);
         }
       }
        
       return servlet;
    }
    
Using newInstance()
Using newInstance() (cont.)
javaexamples/http/v4/HttpServletFactory.java (Fragment: createServlet)
    /**
     * Construct an HttpServlet
     *
     * @param req   The HTTP request
     * @param in    The HttpInputStream to read from
     * @param out   The HttpOutputStream to write to
     */
    public HttpServlet createServlet(HttpRequest req, 
                                     HttpInputStream in, 
                                     HttpOutputStream out)
    {
       Class                  c;
       HttpServlet            servlet;
       String                 className, ext, fname;

       servlet   = null;

       loadAssociations();
       fname     = req.getRequestURI();
       ext       = FileTyper.getExtension(fname);
       className = associations.getProperty(ext);


       if (className == null)
       {
           servlet = new DefaultHttpServlet(in, out);
       }
       else // Use reflection to create an appropriate servlet
       {
          try 
          {
             c = Class.forName(className);
             servlet = (HttpServlet)c.newInstance();
             servlet.setStreams(in, out);
          } 
          catch (Exception e)
          {
             servlet = new DefaultHttpServlet(in, out);
          }
       }
        
       return servlet;
    }
        
What About A Static Factory Method?
What About a Static Factory Method? (cont.)
javaexamples/reflection/MethodExample.java
import java.lang.reflect.*;

/**
 * An example of static and non-static method invocation using
 * reflection.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class MethodExample
{
    /**
     * The entry point of the application.
     *
     * @param args  The command-line arguments (which are ignored)
     */
    public static void main(String[] args) throws Exception
    {
        Class   s_class;
        Integer i, j;        
        Method  s_method;
        String  s, zip;

        s        = new String("James Madison University");
        s_class  = s.getClass();

        // Using a non-static method
        s_method = s_class.getMethod("indexOf", new Class[]{String.class});
        i = (Integer)s_method.invoke(s, "University");
        System.out.println(i.intValue());

        // Using a static method
        s_method = s_class.getMethod("valueOf", new Class[]{Object.class});
        zip = (String)s_method.invoke(null, new Integer(22801));
        System.out.println(zip);
    }
}
        
What About A Static Factory Method?