import java.io.*;
import java.lang.reflect.*;
import java.util.*;

/**
 * Constructs servlets appropriate based on 
 * the file-type in the request.
 *
 * Note that the Singleton pattern is used to construct
 * the factory itself.
 *
 * This version uses reflection to create servlets
 *
 * @version 0.4
 * @author  Prof. David Bernstein, James Madison University
 */
public class HttpServletFactory
{
    // For the Singleton pattern
    private static boolean             exists = false;
    private static HttpServletFactory  instance;

    // Actual attributes
    private File                file;
    private long                lastModified;
    private Properties          associations;

    private static final String     FILE_NAME            = "associations.dat";
    private static final Properties DEFAULT_ASSOCIATIONS = new Properties();

    /**
     * Default Constructor
     */
    private HttpServletFactory()
    {
       exists   = true;

       file = new File(FILE_NAME);
       lastModified = -1;
       associations = new Properties();
       loadAssociations();
    }


    /**
     * Create an HttpServletFactory
     */
    public static HttpServletFactory createFactory()
    {
       if (!exists) instance = new HttpServletFactory();
       return instance;
    }


//[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;
    }
//]createServlet



    /**
     * Load the associations between file types and
     * servlets (if they have changed on disk)
     */
    private void loadAssociations()
    {
       FileInputStream    fis;
       long               modified;
	

       modified = file.lastModified();
       if (modified > lastModified) 
       {
          try 
          {
             fis = new FileInputStream(FILE_NAME);
             associations.clear();
             associations.load(fis);
             lastModified = modified;
          } 
          catch (Exception e) 
          {
             associations = DEFAULT_ASSOCIATIONS;
          }
       }
    }
}
