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

import java.util.*;

import java.io.IOException;
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>Servlet20Renderer</code> renders a single page's contents from a
 * servlet.<p> Note: the servlet container must be Servlet 2.0 compliant.
 *
 * The properties <code>contentType</code> and <code>pageExpires</code> may be
 * set at <code>Servlet20Renderer</code> level or defaulted at {@link
 * oracle.portal.provider.v1.RenderManager} level. However the servlet name
 * property is mandatory, and must be set via a call to <code>{@link
 * #setServletClass(String)}</code> or by use of the
 * <code>&ltservletClass&gt</code> tag in the provider XML registry.<p>
 *
 * Parameters can be assigned to this <code>Servlet20Renderer</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.
 *
 */
public class Servlet20Renderer extends BaseManagedRenderer
{

    private String mServletClass;
    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 Servlet20Renderer()
    {
    }

    /**
     * Creates and initializes a <code>Servlet20Renderer</code> owned by the
     * given {@link PortletPageLocator}, using a servlet class with the given name.
     * @param parent the <code>PortletPageLocator</code> that owns this renderer
     * @param className the fully qualified name of the servlet class
     * @exception PortletException if an error occurs while initializing the
     * object
     */
    public Servlet20Renderer(PortletPageLocator parent, String className) throws PortletException
    {
        try
        {
            preInitialize(parent);
            setServletClass(className);
            postInitialize();
        }
        catch(NodeHandlerException e)
        {
            throw new PortletException(e);
        }
    }

    /**
     * Sets the servlet class used to render a mode.
     *
     * @param name a fully qualified class name.
     */
    public void setServletClass(String name)
    {
        mServletClass = name;
    }

    /**
     * Gets the fully qualified class name used to render the mode.
     */
    public String getServletClass()
    {
        return mServletClass;
    }

    /**
     * Adds entries from a {@link oracle.portal.utils.v1.NameValuePair}
     * object to a parameter list stored by this
     * <code>Servlet20Renderer</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("Servlet20Renderer 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;
    }

    /**
     * Renders the page's contents using the <code>servletClass</code> servlet.
     * Servlet20Renderer gets an instance of the <code>sevletClass</code> and
     * calls its <code>service()</code> method. If the
     * <code>servletClass</code> does not override the <code>service()</code>,
     * method it must override <code>doPost()</code> as this is the request
     * method it will recieve from Portal.
     *
     * @param pr a PortletRenderRequest
     */
    public void renderBody(PortletRenderRequest pr)
        throws PortletException
    {
        ServletContext sc =
            (ServletContext)pr.getAttribute(HttpProvider.SERVLET_CONTEXT);
        try
        {
            HttpServlet servlet = (HttpServlet)sc.getServlet(mServletClass);
            HttpServletRequest request = (HttpServletRequest)
                pr.getAttribute(HttpProvider.SERVLET_REQUEST);
            HttpServletResponse response = (HttpServletResponse)
                pr.getAttribute(HttpProvider.SERVLET_RESPONSE);
            servlet.service(request, response);
        }
        catch(ServletException se)
        {
            throw new PortletException(se);
        }
        catch(IOException ioe)
        {
            throw new PortletException(ioe);
        }
    }

    // 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);
        Enumeration params = mParameters.elements();
        while(params.hasMoreElements())
        {
            NameValuePair nvp = (NameValuePair)params.nextElement();
            srw.addLocalParameter(nvp.getName(), nvp.getValue());
        }
    }

}
