    // RelocateFrame.java
    // $Id: RelocateFrame.html,v 1.2 1998/03/26 09:52:41 benoit Exp $
    // (c) COPYRIGHT MIT and INRIA, 1996.
    // Please first read the full copyright statement in file COPYRIGHT.html

    package org.w3c.jigsaw.frames;

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

    import org.w3c.tools.resources.*;
    import org.w3c.jigsaw.http.*;
    import org.w3c.www.http.*;

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

    /**
     * Emit a HTTP redirect.
     */
    public class RelocateFrame extends HTTPFrame {

        /**
         * Name of the state to hold the PATH_INFO in the request.
         */
        public final static
    	String PATH_INFO =
    	"org.w3c.jigsaw.resources.RelocateResource.PathInfo";

        /**
         * Attribute index - The relocation location.
         */
        protected static int ATTR_LOCATION = -1 ;
        /**
         * Attribute index - Should we also handle extra path infos ?
         */
        protected static int ATTR_HANDLE_PATHINFO = -1;

        static {
    	Attribute a = null ;
    	Class     c = null ;

    	try {
    	    c = Class.forName("org.w3c.jigsaw.frames.RelocateFrame");
    	} catch (Exception ex) {
    	    ex.printStackTrace() ;
    	    System.exit(1) ;
    	}
    	// The location attribute
    	a = new StringAttribute("location"
    				, null
    				, Attribute.EDITABLE|Attribute.MANDATORY) ;
    	ATTR_LOCATION = AttributeRegistry.registerAttribute(c, a) ;
    	// The handle path info attribute
    	a = new BooleanAttribute("handle-pathinfo"
    				 , Boolean.TRUE
    				 , Attribute.EDITABLE);
    	ATTR_HANDLE_PATHINFO = AttributeRegistry.registerAttribute(c, a);
        }

        /**
         * Get the location for the relocation
         */

        public String getLocation() {
    	return (String) getValue(ATTR_LOCATION, null) ;
        }

        public boolean checkHandlePathInfo() {
    	return getBoolean(ATTR_HANDLE_PATHINFO, true);
        }

        public void registerResource(FramedResource resource) {
    	super.registerOtherResource(resource);
        }

        protected boolean lookupOther(LookupState ls, LookupResult lr)
    	throws ProtocolException
        {
    	// Perform our super-class lookup strategy:
    	if ( super.lookupOther(ls, lr) ) {
    	    return true;
    	} else if ( ! checkHandlePathInfo() ) {
    	    return false;
    	}
    	// Compute PATH INFO, store it as a piece of state in the request:
    	StringBuffer pathinfo = new StringBuffer();
    	while ( ls.hasMoreComponents() ) {
    	    pathinfo.append('/');
    	    pathinfo.append(ls.getNextComponent());
    	}
    	if (ls.hasRequest() ) {
    	    Request request = (Request) ls.getRequest();
    	    request.setState(PATH_INFO, pathinfo.toString());
    	}
    	lr.setTarget(resource.getResourceReference());
    	return true;
        }

        /**
         * Emit a redirect.
         * All GET requests are redirected toward the target location.
         * @param client The client issuing the request.
         * @param request The request to handle.
         * @exception ProtocolException If the request couldn't be handled.
         */

        protected Reply getOtherResource (Request request)
    	throws ProtocolException
        {
    	String location = getLocation() ;
    	if ( location == null ) {
    	    Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR) ;
    	    error.setContent("The target RelocateResource doesn't define the"
    			     + " relocation location. The server is "
    			     + " misconfigured.") ;
    	    throw new HTTPException(error) ;
    	} else {
    	    Reply  reply    = request.makeReply(HTTP.MOVED_TEMPORARILY) ;
    	    URL    loc      = null;
    	    try {
    		loc = new URL(getURL(request), location);
    		if (checkHandlePathInfo()) {
    		    String pathinfo = (String) request.getState(PATH_INFO);
    		    // Given the way pathinfo is computed, it starts with a /
    		    try {
    			if (pathinfo != null)
    			    loc = new URL(loc.toExternalForm()+pathinfo);
    			else
    			    resource.getServer().errlog(resource,
    					"This resource handle Pathinfo "+
    					"but the request has no "+
    					"PATH_INFO state.");
    		    } catch (MalformedURLException ex) {
    			resource.getServer().errlog(resource,
    					"This resource handle Pathinfo "+
    					"but the request has an invalid "+
    					"PATH_INFO state.");
    		    }
    		}
    	    } catch (Exception ex) {
    		ex.printStackTrace();
    	    }
    	    reply.setLocation(loc);
    	    return reply ;
    	}
        }

    }