// ServletWrapperFrame.java
// $Id: ServletWrapperFrame.java,v 1.12 1999/03/29 12:45:18 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.jigsaw.servlet;

import java.io.* ;
import java.util.*;

import javax.servlet.*;

import org.w3c.tools.resources.store.*;
import org.w3c.util.*;
import org.w3c.www.mime.*;
import org.w3c.www.http.*;
import org.w3c.jigsaw.http.*;
import org.w3c.jigsaw.frames.*;
import org.w3c.tools.resources.*;

import org.w3c.tools.resources.ProtocolException;
import org.w3c.tools.resources.ResourceException;

/**
 * @author Alexandre Rafalovitch <alex@access.com.au>
 * @author Anselm Baird-Smith <abaird@w3.org>
 * @author Benoit Mahe <bmahe@w3.org>
 */

public class ServletWrapperFrame extends HTTPFrame {

    public static final 
    String STATE_EXTRA_PATH = "org.w3c.jigsaw.servlet.extraPath";

    protected ServletWrapper wrapper = null;

    /**
     * Register our resource. Must be an instance of ServletWrapper.
     */
    public void registerResource(FramedResource resource) {
	super.registerOtherResource(resource);
	if (resource instanceof ServletWrapper)
	    wrapper = (ServletWrapper) resource;
    }

    /**
     * Create a reply to answer to request on this file.
     * This method will create a suitable reply (matching the given request)
     * and will set all its default header values to the appropriate 
     * values. The reply will not have LastModified field setted.
     * @param request The request to make a reply for.
     * @return An instance of Reply, suited to answer this request.
     */

    public Reply createDefaultReply(Request request, int status) {
	Reply reply = super.createDefaultReply(request, status);
	reply.setLastModified( -1 );
	return reply;
    }

    /**
     * Dispatch the give request to our servlet.
     * <p>If the servlet cannot be inititalized, we just throw an error message
     * otherwise, we just delegate that request processing to the underlying 
     * servlet instance.
     * @param request The request to be processed.
     * @exception ProtocolException If the wrapped servlet is not initialized.
     * @exception ResourceException If the resource got a fatal error.
     */

    public ReplyInterface perform(RequestInterface req)
	throws ProtocolException, ResourceException
    {
	ReplyInterface repi = performFrames(req);
	if (repi != null)
	    return repi;

	if (! checkRequest(req))
	    return null;

	Request request = (Request) req;

	if (wrapper == null) {
	    Reply reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
	    reply.setContent("Servlet Wrapper Frame not configured properly: "+
			     "must be attached to a ServletWrapper.");
	    throw new HTTPException(reply);
	}

	try {
	    wrapper.checkServlet();
	} catch (ClassNotFoundException ex) {
	    Reply reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
	    reply.setContent("The server was unable to find the "+
			     "servlet class : "+ex.getMessage());
	    if ( wrapper.debug )
		ex.printStackTrace();
	    throw new HTTPException(reply);
	} catch (ServletException ex) {
	    Reply reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
	    reply.setContent("The server was unable to initialize the "+
			     "servlet : "+ex.getMessage());
	    if ( wrapper.debug )
		ex.printStackTrace();
	    throw new HTTPException(reply);
	}

	// Check that the servlet has been initialized properly:
	if ( ! wrapper.isInited() ) {
	    Reply reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
	    reply.setContent("Servlet not configured properly");
	    throw new HTTPException(reply);
	} 
	// Dispatch the request:
	Reply reply = createDefaultReply(request, HTTP.OK);
	reply.setContentType(MimeType.TEXT_HTML);
	try {
	    wrapper.service(request, reply);
	} catch (UnavailableException uex) {
	     reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
	     if (uex.isPermanent()) {
		 reply.setContent("<h2>The servlet is permanently "+
				  "unavailable :</h2>"+
				  "Details: <b>"+uex.getMessage()+"</b>");
	     } else {
		 int delay = uex.getUnavailableSeconds();
		 if (delay > 0)
		     reply.setContent("<h2>The servlet is temporarily "+
				      "unavailable :</h2>"+
				      "Delay : "+delay+
				      " seconds<br><br>Details: <b>"+
				      uex.getMessage()+"</b>");
		 else
		     reply.setContent("<h2>The servlet is temporarily "+
				      "unavailable :</h2>"+
				      "Details: <b>"+uex.getMessage()+"</b>");
	     }
	} catch (Exception ex) {
	    if ( wrapper.debug )
		ex.printStackTrace();
	    reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
	    reply.setContent("Servlet has thrown exception:" + ex.toString());
	}
	return reply;
    }
    
    /**
     * Jigsaw's lookup on servlets.
     * Once here, we have reached a leaf servlet (or at least the remaining
     * lookup is to be done at the servlet itself). We keep track of the
     * <em>path info</em> and mark that servlet as the target of request.
     * @param ls The lookup state.
     * @param lr The lookup result.
     * @exception ProtocolException If some error occurs.
     */

    protected boolean lookupOther(LookupState ls, LookupResult lr)
	throws ProtocolException
    {
	// Get the extra path information:
	String extraPath = ls.getRemainingPath(true);
	if ((extraPath == null) || extraPath.equals(""))
	    extraPath = "/";
	// Keep this path info into the request, if possible:
	Request request = (Request) ls.getRequest();
	if ( request != null ) {
	    if (request.getState(STATE_EXTRA_PATH) == null)
		request.setState(STATE_EXTRA_PATH, extraPath);
	}
	lr.setTarget(resource.getResourceReference());
	return super.lookupOther(ls, lr);
    }

}
