/* Copyright (c) 2001, Oracle Corporation. All rights reserved. */
package oracle.portal.provider.v1.http;

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

import javax.servlet.*;
import javax.servlet.http.*;

import oracle.portal.provider.v1.*;
import oracle.portal.utils.v1.*;
import oracle.portal.utils.xml.v1.*;


/**
 * When maintained by a {@link oracle.portal.provider.v1.RenderManager}, a
 * <code>JspRenderer</code> renders a single page's contents from a JSP.<p>
 *
 * The properties <code>appPath</code>, <code>appRoot</code>,
 * <code>contentType</code>, <code>pageExpires</code>,
 * <code>pageParameterName</code> and <code>charSet</code> may be set at page
 * level or defaulted at {@link oracle.portal.provider.v1.RenderManager} level.
 * However the page name must be set at page level via a call to <code>{@link
 * #setName(String)}</code> or by use of the <code>&ltname&gt</code>
 * <code>provider.xml</code> tag.<p>
 *
 * Parameters can be assigned to this <code>JspRenderer</code> using a {@link
 * oracle.portal.utils.v1.NameValuePair} object with a call to the {@link
 * #addParameter(Object)} method, and hence a properly configured
 * <code>provider.xml</code> (see the <code>provider.xml</code> tag reference.)
 * These parameters will then be passed to the {@link
 * oracle.portal.provider.v1.http.Servlet20RequestWrapper} object so that they
 * are available from the appropriate {@link
 * oracle.portal.provider.v1.http.Servlet20RequestWrapper} methods within the
 * JSP.<p>
 *
 * Currently, the Oracle JSP Engine is required.
 */
public class JspRenderer extends Page
{

    private Vector mParameters = new Vector();

    /**
     * Null Constructor. The {@link BaseManagedRenderer#preInitialize(Object)}
     * method should be called after creating an object with this constructor
     * and the {@link BaseManagedRenderer#postInitialize()} method should be
     * called after setting up page properties with the various accessor
     * methods. Normally a {@link DefaultNodeHandler} takes care of these
     * details.
     */
    public JspRenderer()
    {
    }

    /**
     * Creates and initializes a <code>JspRenderer</code> owned by the given
     * {@link PortletPageLocator}, describing a page with the given name.
     * @param parent the <code>PortletPageLocator</code> that owns this page
     * @param pageName the <code>appPath</code> relative name of the renderer's
     * page
     * @exception PortletException if an error occurs while initializing the
     * object
     */
    public JspRenderer(PortletPageLocator parent, String pageName) throws PortletException
    {
        try
        {
            preInitialize(parent);
            setName(pageName);
            postInitialize();
        }
        catch(NodeHandlerException e)
        {
            throw new PortletException(e);
        }
    }

    /**
     * Adds entries from a {@link oracle.portal.utils.v1.NameValuePair}
     * object to a parameter list stored by this <code>JspRenderer</code>.
     *
     * @param o Object representing the name-value pair (a {@link
     * NameValuePair}).
     * @exception PortletException if the given Object is not a valid {@link
     * NameValuePair}
     */
    public void addParameter(Object o) throws PortletException
    {
        if (!(o instanceof NameValuePair))
        {
            throw new PortletException("JspRenderer parameters should be NameValuePairs");
        }
        mParameters.addElement(o);
    }

    /**
     * Sets HTTP headers for the response.
     *
     * @param pr a {@link PortletRenderRequest}
     * @return boolean flag indicating whether or not to render the portlet's
     * contents (e.g. is the cached version still valid)
     */
    public boolean prepareResponse(PortletRenderRequest pr)
        throws PortletException, PortletNotFoundException
    {
        boolean retVal = super.prepareResponse(pr);

        // Add to the 'wrapped' Servlet Request all the parameters specific to
        // this PortletRenderRequest
        addParameters(pr);

        return retVal;
    }

    /**
     * Render the specified page's contents using the current appPath, appRoot
     * and page name. <i>Note: The JspRenderer currently requires the Oracle
     * JSP engine for its JSP support.  The Oracle JSP engine is included as
     * part of Oracle iAS. Alternatively, it can be downloaded for free from <a
     * href="http://technet.oracle.com">http://technet.oracle.com</a>.</i><p>
     *
     * @param pr a PortletRenderRequest
     */
    public void renderBody(PortletRenderRequest pr) throws PortletException
    {
        // Get a reference to the Jsp servlet.
        Servlet jspServlet = activateJspEngine(pr);

        // Call the servlet
        try
        {
            jspServlet.service((HttpServletRequest)
                               pr.getAttribute(HttpProvider.SERVLET_REQUEST),
                               (HttpServletResponse)
                               pr.getAttribute(HttpProvider.SERVLET_RESPONSE));
        }
        catch (Exception e)
        {
            throw new PortletException(e);
        }

    }

    // Add to this 'wrapped' Servlet Request all the parameters specific to the
    // given PortletRenderRequest
    protected void addParameters(PortletRenderRequest pr)
    {
        Servlet20RequestWrapper srw =
            (Servlet20RequestWrapper)pr.getAttribute(HttpProvider.SERVLET_REQUEST);
        srw.setVirtualPath(getPagePath(pr));
        srw.setRealPath(getPageRealPath(pr));
        Enumeration params = mParameters.elements();
        while(params.hasMoreElements())
        {
            NameValuePair nvp = (NameValuePair)params.nextElement();
            srw.addLocalParameter(nvp.getName(), nvp.getValue());
        }
    }

    private static Servlet activateJspEngine(PortletRenderRequest pr)
        throws PortletException
    {
        Servlet jspServlet = null;
        ServletContext sc =
            (ServletContext)pr.getAttribute(HttpProvider.SERVLET_CONTEXT);
        try
        {
            jspServlet = sc.getServlet("oracle.jsp.JspServlet");
        }
        catch (Exception e)
        {
            throw new PortletException(e);
        }
        return jspServlet;
    }

}

