/* Copyright (c) 2003, Oracle Corporation, All Rights Reserved.*/
package oracle.portal.provider.v2.render.http;

import oracle.portal.provider.v2.render.http.ResourceRenderer;
import oracle.portal.provider.v2.render.http.BaseManagedRenderer;
import oracle.portal.provider.v2.render.PortletRenderRequest;
import oracle.portal.provider.v2.render.RenderManager;
import oracle.portal.provider.v2.render.PortletRendererUtil;
import oracle.portal.provider.v2.PortletDefinition;
import oracle.portal.provider.v2.ProviderSession;
import oracle.portal.provider.v2.PortletException;
import oracle.portal.provider.v2.utils.ValidationError;
import oracle.portal.utils.xml.v2.NodeHandlerException;
import oracle.portal.log.LogManager;
import oracle.webdb.utils.SimpleStringBuffer;

/**
 * This class is used as an adapter to a Struts servlet application.
 * <p>
 * Requests to this renderer contain the Struts action to be called as a 
 * parameter. The only time that this is not the case is the first time the
 * portlet is called. In this case the action set using 
 * <code>setDefaultAction</code> is used instead.
 */
public class StrutsRenderer extends AbstractResourceRenderer
{
    private String mDefaultAction;

    /**
     * The Struts action parameter name
     */
    public static final String STRUTS_ACTION = "strutsAction";

    /**
     * This constructor is called by a <code>RenderManager</code> object. Pre-
     * initialisation checks are carried out by the framework in
     * {@link BaseManagedRenderer#preInitialize}.
     */
    public StrutsRenderer()
    {
        super();
    }

    /**
     * Called by the framework when the provider definition is loaded or
     * refreshed in response to a Portal message or when the test page is
     * called.
     * 
     * @param context The context of the calling instance.
     * @param errors The current list of errors.
     */
    public void validate(String context, ValidationError errors)
    {
        String ctx = ValidationError.newContext(context,
                                                "StrutsRenderer",
                                                null);
        // Do supertype validation
        super.validate(ctx, errors);

        // Check that there is a default action
        if (mDefaultAction == null)
        {
            errors.addError(ctx, "default action must be set", null);
        }
    }
    
    /**
     * Sets the default Struts servlet action to be used if none is present in
     * the portlet request.
     * <p>
     * Most likely to be called when the provider definition is loaded.
     * 
     * @param action the default action name. The code uses an action name
     *        starting with the '/' character but will add one if none is
     *        present.
     */
    public void setDefaultAction(String action)
    {
        if (!action.startsWith("/"))
        {
            action = "/" + action;
        }  
        mDefaultAction = action;
    }

    /**
     * Returns the default Struts servlet action.
     * 
     * @return the default action
     */
    public String getDefaultAction()
    {
        return mDefaultAction;
    }

    /**
     * Gets a path pointing to the resource to be rendered, in this case it is
     * a Struts action.
     * <p>
     * The first time the renderer is called the default action will be
     * returned. Subsequent calls should contain the Struts action as a
     * parameter.
     * 
     * @param prr the portlet request
     */
    public String getRequestResourcePath(PortletRenderRequest prr)
      throws PortletException
    {
        // ResourceRenderer.renderBody must call this.
        String strutsAction = null;

        // Create a user session attribute to store the last action value
        // parameter sent. This is to get around a BUG in persistent parameters
        // where they are lost after a full-page call.
        // The session attribute uses the user name and instance name so that 
        // portlets using the same provider session do not interfere with each 
        // other.
        String userStrutsAction = PortletRendererUtil.portletParameter
            (prr, STRUTS_ACTION);

        if (LogManager.isDebugEnabled())
        {
            SimpleStringBuffer msg = new SimpleStringBuffer(100)
                .append("Session attribute: ")
                .append(userStrutsAction);
            LogManager.debug(msg.toString());
        }

        ProviderSession sess = prr.getSession();
        if (sess == null)
        {
            // No session - once public parameters are fixed this code will be
            // redundant.
            throw new PortletException("No provider session.");
        }

        if (!(prr.getPortletDefinition().getPassAllUrlParams()))
        {
            // passAllUrlParams must be set to true for the time being.
            throw new PortletException("The passAllUrlParams flag must be set "
                                       + "to true for portlets using the "
                                       + "Struts renderer.");
        }

        strutsAction =prr.getQualifiedParameter(STRUTS_ACTION);

        if (strutsAction != null)
        {
            // The Struts action has been found.
            LogManager.debug("Struts action found in the request..");

            // Set the user action as a session attribute in case the portlet
            // parameter which should contain it is lost.
            sess.setAttribute(userStrutsAction, strutsAction);
        }
        else
        {
            LogManager.debug("No Struts action in the request..");

            // No struts action in the request so try and get the last action 
            // performed by that user for that portlet instance, the action 
            // parameter may have  been 'lost' due to a full-page action
            // being performed on the portlet page.
            strutsAction = (String)sess.getAttribute(userStrutsAction);
        
            if (strutsAction == null)
            {
                LogManager.debug("No Struts action in the session, either..");
                // Still no struts action. This must be the first request for 
                // this portlet by this user in this session so use the default
                // action.
                strutsAction = getDefaultAction();
                sess.setAttribute(userStrutsAction, strutsAction);
                LogManager.debug("Using default Struts action value.");
            }
            else
            {
                LogManager.debug("Struts action found in the session.");            
            }
        }

        if (!strutsAction.startsWith("/"))
        {
          strutsAction = "/" + strutsAction;
        }

        if (LogManager.isDebugEnabled())
        {
            SimpleStringBuffer msg = new SimpleStringBuffer(50)
                .append("Struts action is: ")
                .append(strutsAction);
        }
        return strutsAction;
    }  
}
