/*
 * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the
 * License at http://www.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.dispatcher;

import java.io.File;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;

/**
 * Basic dispatcher class for dispatching URLs to JSP or
 * other file-based assets (images, CSS, HTML, etc.) in the file
 * system in the context of a single package's URL space.
 * <p>
 * Given an application context that contains a SiteNode, and a
 * remaining URL, tries to resolve the remaining URL into a concrete file:<br>
 * $root/packages/$key/$remaining-url<br>
 *
 * where<br>
 *  $root is the ACS webapp root<br>
 *  $key is siteNode.getPackageKey()<br>
 *  $remaining-url is given by appContext.getRemainingURLPart()
 *
 * <p> To make the URL mapping in JSPApplicationDispatcher work, you
 * must map the "jsp" servlet in web.xml to whatever your entry-point
 * dispatcher is (whatever servlet is mapped to the URL pattern "/").
 * Otherwise, requests for *.jsp will get picked up by the JSP
 * container before any ACS dispatchers have a shot at URL mapping.
 *
 * <p>
 * Example: if the application sample-app is mounted on the site nodes
 * /sample1 and /sample2 then URLs will be dispatched as follows:
 * <table>
 * <tr><th>Request URL <th>File served</tr>
 * <tr><td> /sample1/page.jsp</td> <td> /packages/sample-app/www/page.jsp</td>
 * </tr>
 * <tr><td> /sample2/image.gif</td> <td> /packages/sample-app/www/image.gif</td>
 * </tr>
 * <tr><td> /sample2/script.jsp</td> <td> /packages/sample-app/www/script.jsp</td>
 * </tr>
 * </table>
 * @author Bill Schneider 
 * @version $Version$, $Date: 2004/04/07 $ 
 */
public class JSPApplicationDispatcher extends BaseDispatcherServlet
        implements Dispatcher  {
    public static final String versionId = 
        "$Id: //core-platform/dev/src/com/arsdigita/dispatcher/JSPApplicationDispatcher.java#10 $" +
        "$Author: dennis $" +
        "$DateTime: 2004/04/07 16:07:11 $";

    private static final Logger s_log = Logger.getLogger
        (JSPApplicationDispatcher.class);

    private static JSPApplicationDispatcher s_instance = newInstance();

    /**
     * Returns a new instance of a JSPApplicationDispatcher.
     * @return a new JSPApplicationDispatcher.
     */
    public static JSPApplicationDispatcher newInstance() {
        return new JSPApplicationDispatcher();
    }

    /**
     * Returns a new instance of JSPApplicationDispatcher.
     * @return a JSPApplicationDispatcher object.
     * @deprecated No longer returns a singleton instance.  Remains
     * in place for API stability.
     */
    public static JSPApplicationDispatcher getInstance() {
        return s_instance;
    }

    // No Authentication is performed here.
    protected RequestContext authenticateUser(HttpServletRequest req,
                                              HttpServletResponse resp,
                                              RequestContext ctx)
        throws RedirectException {
        return ctx;
    }

    public void dispatch(HttpServletRequest req,
                         HttpServletResponse resp,
                         RequestContext actx)
        throws IOException, ServletException {

        // Set the request context as a request attribute because a
        // JSP page might need it, which doesn't get passed the
        // request context as a parameter.
        DispatcherHelper.setRequestContext(req, actx);

        ServletContext sctx = actx.getServletContext();
        String remainingURL = actx.getRemainingURLPart();

        if (s_log.isDebugEnabled()) {
            s_log.debug("I think the remaining URL is '" + remainingURL + "'");
        }

        // This is where we forward a request from /foo1/bar.ext or
        // /foo2/bar.ext to /packages/foo/www/bar.ext the concrete
        // file should then get picked up by BaseDispatcherServlet.

        String concreteURL =
            actx.getPageBase() +
            actx.getRemainingURLPart();

        if (s_log.isDebugEnabled()) {
            s_log.debug("Looking for a concrete resource under the web app " +
                        "context at '" + concreteURL + "'");
        }

        File concreteFile = new File(sctx.getRealPath(concreteURL));

        if (concreteFile.exists()) {
            s_log.debug("Resource was found; forwarding");
            DispatcherHelper.setRequestContext(req, actx);
            DispatcherHelper.forwardRequestByPath(concreteURL, req, resp);
        } else {
            s_log.debug("Resource not found");
            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }
}
