/*  Copyright (c) 2000 by Oracle Corporation. All Rights Reserved. */

package oracle.portal.provider.v1.http;

import java.util.*;
import java.io.*;
import java.text.*;
import javax.servlet.*;
import javax.servlet.http.*;

import oracle.portal.provider.v1.*;
import oracle.webdb.utils.SimpleStringBuffer;

import org.w3c.dom.*;
import oracle.xml.parser.v2.*;

public class ServletProviderRequest 
    implements PortletExecutionTracker, PerformanceLoggerAccessor
{
    static final String SOAP_BODY = "Body";
    static final String NULL_ATTRIBUTE = "xsi:null";

    static final int ID_UNKNOWN = -1;
    static final long DEFAULT_PORTLET_TIMEOUT = 30000;   // 30 seconds
    static final long DEFAULT_PORTLET_KILL_TIMEOUT = 300000;  // 5 minutes

    // default session timeout - used if "sessiontimeout" initArg is not
    // specified. Value is in milliseconds.
    private static final int DEFAULT_SESSION_TIMEOUT = 1800000;

    private long mProviderId = ID_UNKNOWN;
    private long mPortletId = ID_UNKNOWN;
    private String mPortletName;
    private int mAction = HttpProviderConstants.ACTION_UNKNOWN;

    /* Holds portlet information for a copy */
    private long mFromPortletId = ID_UNKNOWN;
    private String mFromPortletName;
    private long mToPortletId = ID_UNKNOWN;
    private String mToPortletName;

    private String mSubscriberId;
    private String mCompanyName;
    private String mPortalVersion;

    private String mUser308; // used by Portal release 3.0.8 and earlier
    private String mUser309; // used by Portal release 3.0.9 and later
    private String mMappedUserName;
    private String mLoginTime;
    private String mSessionId;

    private int mAuthenticationLevel = ProviderUser.AUTH_NOT_DETERMINED;
    private ProviderUser mProviderUser;

    private ExternalPrincipal mExternalApp;

    private boolean mIsByUser;
    private int mStart;
    private int mCount;
    private Locale mLanguage;

    private String mDesignURL;
    private String mPageURL;
    private String mBackURL;
    private String mLoginURL;
    private String[] mAcceptContentTypes;
    private Boolean mHasTitle; // object so I can determine if initialized
    private Boolean mHasBorder; // object so I can determine if initialized
    private int mMode = ID_UNKNOWN;

    private int mDebugLevel = 0;
    private boolean mUrlDebug = false;

    private ServletConfig mServletConfig;
    private ServletContext mServletContext;
    private HttpServletRequest mRequest;
    private HttpServletResponse mResponse;

    private Vector mAcceptCharset;
    private Vector mAcceptLanguage;
    private String mContentCharset;
    private Locale mContentLanguage;
    private Locale mDefaultLanguage;  // Portal's default locale
    private boolean mTranslateMode;  // if true indicates default customizations are saved using the current language rather than the default

    private ResourceBundle mProviderResource;
    private ResourceBundle mHttpProviderExceptionResource;
    private ResourceBundle mProviderExceptionResource;

    private int mServletSessionTimeout = ID_UNKNOWN;

    private boolean mIsTest;
    private boolean mIsFromParameters;

    private DeviceInfo mDeviceInfo;

    private PortalConfig mPortalConfig;

    // Time at which the service method started
    private long mStartTime = 0;

    // Timeout used to indicate that a portlet is taking its time to render
    private long mTimeout = DEFAULT_PORTLET_TIMEOUT;

    // Actual time in ms after which the portlet is taking its time
    private long mWarningTime = 0;

    // Timeout indicating that the portlet has hung and should be stopped.
    private long mKillTimeout = DEFAULT_PORTLET_KILL_TIMEOUT;

    // Actual time after which the portlet should be killed
    private long mKillTime = 0;

    // Performance logger object
    private PerformanceLogger mPerformanceLogger;

    /**
     * Constructs <code>ServletProviderRequest</code>.
     * @param sc configuration object from which initialisation parameters are 
     * extracted
     * @param request incoming request object from which the request parameters
     * extracted
     * @param response the response object to which content will be written
     */
    public ServletProviderRequest(ServletConfig sc, 
                                  HttpServletRequest request, 
                                  HttpServletResponse response) 
        throws ServletException, IOException 
    {
        mServletConfig = sc;
        mServletContext = sc.getServletContext();
        mRequest = request;
        mResponse = response;


        // Ugh! in Servlet 2.0 there is no way to get the sessionTimeout from the session
        // It must be passed in the initArgs.
        String arg = sc.getInitParameter(HttpProviderConstants.SERVLET_SESSION_TIMEOUT);
        if (arg != null)
        {
            try
            {
                mServletSessionTimeout = Integer.parseInt(arg);
            }
            catch(Exception e)
            {
                SimpleStringBuffer buf = new SimpleStringBuffer(150);
                buf.append("CONFIG ERROR: sessiontimeout must be ");
                buf.append("a numeric value (in milliseconds). "); 
                buf.append("Defaulting to ");
                buf.append(DEFAULT_SESSION_TIMEOUT);
                mServletContext.log(e, buf.toString());

                mServletSessionTimeout = DEFAULT_SESSION_TIMEOUT;
            }
            mServletSessionTimeout = mServletSessionTimeout/1000;
        }
        else
        {
            mServletSessionTimeout = DEFAULT_SESSION_TIMEOUT/1000;
        }

        // Check initParameters to see if debugMode is on
        arg = sc.getInitParameter(HttpProviderConstants.PROVIDER_DEBUG_LEVEL);
        if (arg != null) 
        {
            try
            {
                mDebugLevel = Integer.parseInt(arg);
            }
            catch(Exception e)
            {
                SimpleStringBuffer buf = new SimpleStringBuffer(100);
                buf.append("CONFIG ERROR: debuglevel must be a numeric value.");
                buf.append("Defaulting to 0 (debug off)");
                mServletContext.log(e, buf.toString());
                mDebugLevel = 0;
            }
        }

        // detetmine whether this is an HTTP/Form request or an HTTP/Soap request
        String ct = request.getContentType();
        if (ct != null && (ct.equals("text/xml") || ct.startsWith("text/xml;"))) 
        {
            setFromSOAP(request);
        } 
        else 
        {
            setFromParameters(request);
        }

        // Fill in additional request information from request Headers
        setFromHeaders(request);

        // Set the dubug parameter flag, false by default.
        String debug = request.getParameter(HttpProviderConstants.DEBUG_PARAMETER);
        if (debug != null)
        {
            try
            {
                int debugInt = Integer.parseInt(debug);
                mUrlDebug = (debugInt >= 1);
            }
            catch (NumberFormatException nfe)
            {
                // Note the exception and carry on. Debug switch set to false
                // by default.
                mServletContext.log(nfe, "Invalid value for parameter '_debug'.");
            }
        }
    }

    /**
     * This version of the constructor includes the time at which the incoming 
     * request started being processed.
     * @param sc configuration object from which initialisation parameters are 
     * extracted
     * @param request incoming request object from which the request parameters
     * are extracted
     * @param response the response object to which content will be written
     * @param startTime time at which the incoming request started being
     * processed.
     */
    public ServletProviderRequest(ServletConfig sc, 
                                  HttpServletRequest request, 
                                  HttpServletResponse response,
                                  long startTime) 
        throws ServletException, IOException
    {
        this(sc, request, response);

        // Check for portlet timeout parameter from an init
        // parameter.  If not specified the default is used.
        mStartTime = startTime;
        String timeout = null;       
        timeout = sc.getInitParameter(HttpProviderConstants.INIT_PORTLET_TIMEOUT);
        
        if (timeout != null)
        {
            // Unchecked NumberFormatException thrown if an invalid parameter
            // has been passed.
            mTimeout = Long.parseLong(timeout);
        }
        mWarningTime = mStartTime + mTimeout;

        // Check for portlet kill timeout parameter from an init parameter. If
        // none is found,  a default is used.
        String killTimeout = null;
        killTimeout = sc.getInitParameter(HttpProviderConstants.INIT_PORTLET_KILL_TIMEOUT);
        if (killTimeout != null)
        {
            // Unchecked NumberFormatException thrown if an invalid parameter
            // has been passed.
            mKillTimeout = Long.parseLong(killTimeout);
        }
        mKillTime = mStartTime + mKillTimeout;
    }

    /**
     * This version of the constructor includes the a performance logger
     * object which may be used to record performance stats.
     * @param sc configuration object from which initialisation parameters are 
     * extracted
     * @param request incoming request object from which the request parameters
     * are extracted
     * @param response the response object to which content will be written
     * @param startTime time at which the incoming request started being
     * processed.
     * @parame logger the <code>PerformanceLogger</code> object associated with
     * this request.
     */
    public ServletProviderRequest(ServletConfig sc, 
                                  HttpServletRequest request, 
                                  HttpServletResponse response,
                                  long startTime,
                                  PerformanceLogger logger) 
        throws ServletException, IOException
    {
        this(sc, request, response, startTime);
        mPerformanceLogger = logger;

        // Set the request id in the logger if present
        String reqId = request.getHeader(HttpProvider.REQUEST_ID_HEADER);
        if(reqId != null)
        {
            logger.setRequestId(reqId);
        }

    }

    /**
     * Returns the time at which the request started. Time is defined in number
     * of milliseconds since January 1, 1970 UTC.
     *
     * return start time of the request
     */
    public long getPortletStartTime()
    {
        return mStartTime;
    }

    /**
     * Returns the maximum time that the portlet should take to be rendered.
     *
     * @return the portlet timeout in milliseconds
     */
    public long getPortletTimeout()
    {
        return mTimeout;
    }


    /**
     * Indicates whether this request has exceeded an execution timeout.
     * The execution timeout is picked up from an initialisation argument
     * or from a system default (in that order of preference.
     *
     * @return true if the portlet has timed out, false otherwise
     */
    public boolean hasPortletTimeoutElapsed()
    {
        return (System.currentTimeMillis() > mWarningTime);
    }

    /**
     * Returns the maximum time that a portlet may take to execute, after which
     * it should be forcefully terminated.
     *
     * @return the portlet maximum execution time in milliseconds
     */
    public long getPortletKillTimeout()
    {
        return mKillTimeout;
    }

    /**
     * Indicates whether this request has exceeded its 'kill time', i.e, the
     * time after which the thread should be forcefully stopped.
     *
     * @return true if the kill time has been exceeded, false otherwise.
     */
    public boolean hasPortletKillTimeoutElapsed()
    {
        return (System.currentTimeMillis() > mKillTime);
    }

    /**
     *  Returns the performance logger object for this request
     *
     *  @return a reference to the <code>PerformanceLogger</code> for this
     *  request.
     */
    public PerformanceLogger getPerformanceLogger()
    {
        return mPerformanceLogger;
    }
    
    /**
     *  Gets the servletConfig this request is contained within.
     */
    protected ServletConfig getServletConfig() {
        return mServletConfig;
    }

    /**
     *  Gets the servletContext this request is contained within.
     */
    protected ServletContext getServletContext() {
        return mServletContext;
    }


    /**
     *  Gets the HttpServletRequest that instantiated this request.
     */
    protected HttpServletRequest getRequest() {
        return mRequest;
    }


    /**
     *  Gets the HttpServletResponse in use by this request.
     */
    protected HttpServletResponse getResponse() {
        return mResponse;
    }

    protected Locale getDefaultLanguage() {
        // Note -- currently always null as Portal doesn't yet pass this information
        return mDefaultLanguage;
    }

    protected boolean getTranslateMode() {
        // Note -- currently always false as Portal doesn't yet pass this information
        return mTranslateMode;
    }

    protected Locale getAcceptLanguage() 
    {
        if (mAcceptLanguage == null)
        {
            // initialize mAcceptLanguage using a default value
            getAcceptLanguages();
        }
        return (Locale) mAcceptLanguage.elementAt(0);
    }

    protected Vector getAcceptLanguages() 
    {
        if (mAcceptLanguage == null)
        {
            // initialize mAcceptLanguage using a default value
            getAcceptLanguage("en");
        }
        return mAcceptLanguage;
    }

    protected String getAcceptCharset() 
    {
        if (mAcceptCharset == null)
        {
            // initialize mAcceptCharset using a default value
            getAcceptCharset(null);
        }
        return (String) mAcceptCharset.elementAt(0);
    }

    protected Vector getAcceptCharsets() 
    {
        if (mAcceptCharset == null)
        {
            // initialize mAcceptCharset using a default value
            getAcceptCharset(null);
        }
        return mAcceptCharset;
    }

    protected Locale getContentLanguage() {
        return mContentLanguage;
    }

    protected String getContentCharset() {
        return mContentCharset;
    }

    protected ResourceBundle getProviderResource() {
        if (mProviderResource == null) {
            Locale l = getAcceptLanguage();
            if (l != null) {
                mProviderResource = ResourceBundle.getBundle("oracle.portal.provider.v1.resource.ProviderBundle", l);
            } else {
                mProviderResource = ResourceBundle.getBundle("oracle.portal.provider.v1.resource.ProviderBundle");
            }
        }
        return mProviderResource;
    }

    protected ResourceBundle getProviderExceptionResource() {
        if (mProviderExceptionResource == null) {
            Locale l = getAcceptLanguage();
            if (l != null) {
                mProviderExceptionResource = ResourceBundle.getBundle("oracle.portal.provider.v1.resource.mProviderExceptionResource", l);
            } else {
                mProviderExceptionResource = ResourceBundle.getBundle("oracle.portal.provider.v1.resource.mProviderExceptionResource");
            }        }
        return mProviderExceptionResource;
    }

    protected ResourceBundle getHttpProviderExceptionResource()
    {
        if (mHttpProviderExceptionResource == null) {
            Locale l = getAcceptLanguage();
            if (l != null) {
                mHttpProviderExceptionResource = ResourceBundle.getBundle("oracle.portal.provider.v1.http.resource.mHttpProviderExceptionResource", l);
            } else {
                mHttpProviderExceptionResource = ResourceBundle.getBundle("oracle.portal.provider.v1.http.resource.mHttpProviderExceptionResource");
            }        }
        return mHttpProviderExceptionResource;
    }

    protected ExternalPrincipal getExternalPrincipal()
    {
        return mExternalApp;
    }

    protected ProviderUser getProviderUser()
        throws java.lang.IllegalStateException
    {
        if (mProviderUser != null)
            return mProviderUser;

        // if request was from SOAP, the ProviderUser object is created when the
        // SOAP is processed. Creation is only deferred for the Http request case
        if (mIsFromParameters)
        {
            // create a new User Object using request parameters as source of
            // data
            mProviderUser = new ServletProviderUser(this, mServletSessionTimeout);
            return mProviderUser;
        }
        return null;
    }


    protected long getProviderId() throws IllegalStateException
    {
        if (mProviderId != ID_UNKNOWN)
            return mProviderId;

        if (mIsFromParameters)
        {
            mProviderId = translateLong(mRequest.getParameter(HttpProviderConstants.PROVIDER_PARAMETER));

            if (mProviderId == ID_UNKNOWN)
                throw new IllegalStateException("ProviderId not passed in request.");
        }
        return mProviderId;
    }

    protected long getPortletId() throws IllegalStateException
    {
        if (mPortletId != ID_UNKNOWN)
            return mPortletId;

        if (mIsFromParameters)
        {
            mPortletId = translateLong(mRequest.getParameter(HttpProviderConstants.PORTLET_PARAMETER));

            if (mPortletId != ID_UNKNOWN)
                return mPortletId;
        }

        throw new IllegalStateException("PortletId not passed in request.");
    }

    protected String getPortletName() throws IllegalStateException
    {
        if (mPortletName != null)
            return mPortletName;

        if (mIsFromParameters)
        {
            mPortletName = mRequest.getParameter(HttpProviderConstants.PORTLET_INSTANCE_PARAMETER);
            if (mPortletName != null)
                return mPortletName;
        }
        throw new IllegalStateException("Portlet Instance Name not passed in request.");
    }

    protected String getSubscriberId() throws java.lang.IllegalStateException {
        if (mSubscriberId != null)
            return mSubscriberId;

        if (mIsFromParameters)
            mSubscriberId = mRequest.getParameter(HttpProviderConstants.SUBSCRIBER_ID_PARAMETER);
        return mSubscriberId;
    }

    protected String getCompanyName() throws IllegalStateException
    {
        if (mCompanyName != null)
            return mCompanyName;

        if (mIsFromParameters)
            mCompanyName = mRequest.getParameter(HttpProviderConstants.COMPANY_NAME_PARAMETER);
        return mCompanyName;
    }

    protected int getAuthenticationLevel() throws IllegalStateException
    {
        if (mAuthenticationLevel != ProviderUser.AUTH_NOT_DETERMINED)
            return mAuthenticationLevel;

        if (mIsFromParameters)
        {
            // Try and find the authentication level in the request header if 
            // it is not one of the request parameters.  Part of middle-tier 
            // caching changes to be introduced in 9.0.3.
            String authParameter = mRequest.getParameter(HttpProviderConstants.AUTHENTICATION_LEVEL_PARAMETER);
            if (authParameter == null)
            {
                authParameter = mRequest.getHeader(HttpProviderConstants.AUTH_LEVEL_HEADER);
            }

            mAuthenticationLevel = translateInt(authParameter);
        }
        return mAuthenticationLevel;
    }

    protected String getPortalVersion()
    {
        if (mPortalVersion != null)
            return mPortalVersion;

        if (mIsFromParameters)
        {
            mPortalVersion = mRequest.getParameter(HttpProviderConstants.PORTAL_VERSION_PARAMETER);
        }
        return mPortalVersion;
    }

    protected int getAction() throws java.lang.IllegalStateException
    {
        if (mAction != HttpProviderConstants.ACTION_UNKNOWN)
            return mAction;

        if (mIsFromParameters)
        {
            mAction = translateAction(mRequest.getParameter(HttpProviderConstants.ACTION_PARAMETER));
            if (mAction != HttpProviderConstants.ACTION_UNKNOWN)
                return mAction;
        }
        throw new java.lang.IllegalStateException("Action unrecognized or not passed in request.");
    }

    protected String getUser() throws IllegalStateException
    {
        String user = getUser309();
        if (user != null)
        {
            return user;
        }
        else
        {
            user = getUser308();
            if (user != null)
            {
                return user;
            }
        }
        
        // Later versions of portal will send user specific info in 
        // headers. Look for user info in the headers if not in the request 
        // parameters.
        String userHeader = mRequest.getHeader
                                         (HttpProviderConstants.USER_HEADER);
        if (userHeader != null)
        {
            return userHeader;
        }
        throw new java.lang.IllegalStateException("User not passed in request.");
    }


    protected String getUser308() throws IllegalStateException
    {
        if (mUser308 != null)
            return mUser308;

        if (mIsFromParameters)
            mUser308 = mRequest.getParameter(HttpProviderConstants.USER_PARAMETER);
        return mUser308;
    }

    protected String getUser309() throws IllegalStateException
    {
        if (mUser309 != null)
            return mUser309;

        if (mIsFromParameters)
            mUser309 = mRequest.getParameter(HttpProviderConstants.USERNAME_PARAMETER);
        return mUser309;
    }

    protected String getMappedUser() throws IllegalStateException
    {
        if (mMappedUserName != null)
            return mMappedUserName;

        if (mIsFromParameters)
        {
            mMappedUserName = mRequest.getParameter(HttpProviderConstants.MAPPED_USER_PARAMETER);
            if (mMappedUserName == null)
            {
                mMappedUserName = mRequest.getHeader
                                   (HttpProviderConstants.MAPPED_USER_HEADER);
            }
        }
        
        return mMappedUserName;
    }

    protected String getLoginTime() throws java.lang.IllegalStateException
    {
        if (mLoginTime != null)
            return mLoginTime;

        if (mIsFromParameters)
            mLoginTime = mRequest.getParameter(HttpProviderConstants.LOGINTIME_PARAMETER);
        return mLoginTime;
    }

    protected String getSessionId() throws java.lang.IllegalStateException
    {
        if (mSessionId != null)
            return mSessionId;

        if (mIsFromParameters)
            mSessionId = mRequest.getParameter(HttpProviderConstants.SESSIONID_PARAMETER);
        return mSessionId;
    }

    /**
     *  @return the device information for this request.
     */
    public DeviceInfo getDeviceInfo()
    {
        if (mDeviceInfo != null)
            return mDeviceInfo;

        String sDeviceClass = mRequest.getHeader(HttpProviderConstants.DEVICE_CLASS_HEADER);
        if (sDeviceClass == null)
            // no device information
            return mDeviceInfo = null;
        DeviceInfo.DeviceClass deviceClass =
            DeviceInfo.DeviceClass.getDeviceClass(sDeviceClass);

        // else get the other values
        DeviceInfo.DeviceOrientation orientation =
             DeviceInfo.DeviceOrientation.getDeviceOrientation(
                mRequest.getHeader(HttpProviderConstants.DEVICE_ORIENTATION_HEADER));

        String sDocSize = mRequest.getHeader(HttpProviderConstants.DEVICE_MAXDOCSIZE_HEADER);
        long maxDocSize = 0;
        if (sDocSize != null)
        {
            try
            {
                maxDocSize = Long.parseLong(sDocSize);
            } catch (NumberFormatException nfe){/*already defaulted*/};
        }

        // get the information about the connection
        boolean isSecure = Boolean.valueOf(
            mRequest.getHeader(HttpProviderConstants.DEVICE_SECURE_HEADER)).booleanValue();

        mDeviceInfo = new DeviceInfo(deviceClass, orientation, maxDocSize, isSecure);

        return mDeviceInfo;
    }

    /**
     *  @return an object containing information pertinent to the portlet
     *  about how the portal is currently configured.  Currently, only a single
     *  state is defined: mobileEnabled.  Portlets may
     *  use this information to add customization fields to its screens or
     *  help information that pertain to mobile.
     */
    public PortalConfig getPortalConfig()
    {
        if (mPortalConfig != null)
            return mPortalConfig;

        String stringFlag = mRequest.getParameter(
            HttpProviderConstants.PORTALCFG_FLAG_PARAMETER);
        if (stringFlag != null)
        {
            try
            {
                mPortalConfig =  new PortalConfig(Long.parseLong(stringFlag));
            } catch (NumberFormatException nfe) {} // fall through to create default

        }

        if (mPortalConfig == null)
        {
            mPortalConfig = new PortalConfig (0);
        }

        return mPortalConfig;
    }

    /* Following are only pertinent for action = copyPortlet */
    protected long getCopyFromPortletId() throws java.lang.IllegalStateException {
        if (mFromPortletId == ID_UNKNOWN) throw new java.lang.IllegalStateException("fromPortletId not passed in request.");

        return mFromPortletId;
    }

    protected String getCopyFromPortletName() throws java.lang.IllegalStateException {
        if (mFromPortletName == null) throw new java.lang.IllegalStateException("fromPortletName not passed in request.");

        return mFromPortletName;
    }

    protected long getCopyToPortletId() throws java.lang.IllegalStateException {
        if (mToPortletId == ID_UNKNOWN) throw new java.lang.IllegalStateException("toPortletId not passed in request.");

        return mToPortletId;
    }

    protected String getCopyToPortletName() throws java.lang.IllegalStateException {
        if (mToPortletName == null) throw new java.lang.IllegalStateException("toPortletName not passed in request.");

        return mToPortletName;
    }

    /* Following are only pertinent for action = do_login */

    protected boolean isByUser() {
        return mIsByUser;
    }

    protected int getStart() throws java.lang.IllegalStateException {
        if (mStart <= 0) throw new java.lang.IllegalStateException("Invalid starting element: " + mStart);

        return mStart;
    }

    protected int getCount() {
        return mCount;
    }

    protected Locale getLanguage() throws java.lang.IllegalStateException 
    {
        if (mLanguage == null) 
        {
            mLanguage = new Locale(Locale.ENGLISH.getLanguage(), "");
        }

        return mLanguage;
    }


    /* Following are only pertinent for action = show_portlet */

    protected String getDesignURL() throws IllegalStateException
    {
        if (mDesignURL != null)
            return mDesignURL;

        mDesignURL = mRequest.getParameter(HttpProviderConstants.DESIGNURL_PARAMETER);
        if (mDesignURL == null)
            throw new IllegalStateException("DesignURL not passed in request.");

        return mDesignURL;
    }

    protected String getPageURL() throws IllegalStateException
    {
        if (mPageURL != null)
            return mPageURL;

        mPageURL = mRequest.getParameter(HttpProviderConstants.PAGEURL_PARAMETER);
        if (mPageURL == null)
            throw new IllegalStateException("PageURL not passed in request.");

        return mPageURL;
    }

    protected String getBackURL() throws IllegalStateException
    {
        if (mBackURL != null)
            return mBackURL;

        mBackURL = mRequest.getParameter(HttpProviderConstants.BACKURL_PARAMETER);
        return mBackURL;
    }

    protected String getLoginServerURL() throws IllegalStateException
    {
        if (mLoginURL != null)
            return mLoginURL;

        mLoginURL = mRequest.getParameter(HttpProviderConstants.LOGINURL_PARAMETER);
        if (mLoginURL == null)
            throw new IllegalStateException("PageURL not passed in request.");

        return mLoginURL;
    }

    protected String[] getAcceptContentTypes() 
        throws java.lang.IllegalStateException 
    {
        if (mAcceptContentTypes == null || mAcceptContentTypes.length == 0)
        {
            // if the portal does not send a list of accept content types with
            // the request, generate a list of supported content types.
            // This is a rare situation most likely related to misconfiguration
            // of the portal mid-tier. Sequence of types is based on checkin
            // report for a mobile bug for a similar issue elsewhere in the 
            // product
            mAcceptContentTypes = new String[3];
            mAcceptContentTypes[0] = PortletRenderer.TYPE_HTML;
            mAcceptContentTypes[1] = PortletRenderer.TYPE_MOBILE;
            mAcceptContentTypes[2] = PortletRenderer.TYPE_XML;
        }
        return mAcceptContentTypes;
    }

    protected String getPreferredContentType() 
        throws java.lang.IllegalStateException 
    {
        // getAcceptContentTypes will always return something - just return
        // the first element.
        String[] types = getAcceptContentTypes();
        return types[0];
    }

    protected boolean hasTitle() throws IllegalStateException
    {
        // using Boolean object so I can determine if the value
        // has been set or not.
        if (mHasTitle != null)
            return mHasTitle.booleanValue();

        boolean b = translateBoolean(mRequest.getParameter(HttpProviderConstants.HAS_TITLE_PARAMETER));
        mHasTitle = new Boolean(b);
        return mHasTitle.booleanValue();
    }

    protected boolean hasBorder() throws IllegalStateException
    {
        // using Boolean object so I can determine if the value
        // has been set or not.
        if (mHasBorder != null)
            return mHasBorder.booleanValue();

        boolean b = translateBoolean(mRequest.getParameter(HttpProviderConstants.HAS_BORDER_PARAMETER));
        mHasBorder = new Boolean(b);
        return mHasBorder.booleanValue();
    }

    protected int getMode() throws IllegalStateException
    {
        if (mMode != ID_UNKNOWN)
            return mMode;

        // always from parameters...
        // In process of changing from passing mode as a name to a value. Try name first then value.
        // remove once we have made the transition.
        String renderMode = mRequest.getParameter(HttpProviderConstants.RENDER_MODE_PARAMETER);
        try {
            mMode = PortletRendererUtil.getModeValue(renderMode);
        } catch (Exception e) {
            try {
                mMode = Integer.valueOf(renderMode).intValue();
            } catch (Exception ae) {}
        }
        return mMode;
    }

    protected int getDebugLevel() {
        return mDebugLevel;
    }

    protected boolean isTest() {
        return mIsTest;
    }

    /**
     *  Returns true if the incoming request has the _debug parameter set to 1
     */
    protected boolean isHtmlDebugOn()
    {
        return mUrlDebug;
    }

    private void setFromHeaders(HttpServletRequest request) {
        mAcceptCharset = getAcceptCharset(request.getHeader(HttpProviderConstants.HTTP_ACCEPT_CHARSET));
        mAcceptLanguage = getAcceptLanguage(request.getHeader(HttpProviderConstants.HTTP_ACCEPT_LANGUAGE));
        mContentCharset = charsetFromContentType(request.getHeader(HttpProviderConstants.HTTP_CONTENT_TYPE));
        mContentLanguage = translateLanguage(request.getHeader(HttpProviderConstants.HTTP_CONTENT_LANGUAGE));
    }

    private Vector getAcceptLanguage(String languages) 
    {
        if (languages == null)
        {
            languages = "en";
        }

        StringTokenizer t = new StringTokenizer(languages, ",");
        Vector v = new Vector(t.countTokens());

        while (t.hasMoreTokens()) 
        {
            v.addElement(translateLanguage(t.nextToken()));
        }
        return v;
    }

    private Vector getAcceptCharset(String charsets) 
    {
        if (charsets == null);
        {
            // use UTF-8 as the default "Accept" charset for content since this 
            // can be converted to most other charsets by the PPE
            charsets = "utf-8";
        }

        StringTokenizer t = new StringTokenizer(charsets, ",");
        Vector v = new Vector(t.countTokens());

        while (t.hasMoreTokens()) 
        {
            String charset = t.nextToken();

            // ignore the "quality" setting
            int i = charset.indexOf(";");
            if (i != -1) 
            {
                charset = charset.substring(0, i);
            }

            v.addElement(charset);
        }

        return v;
    }



    private Locale translateLanguage(String l) {
       String language = Locale.ENGLISH.getLanguage(), country = "";

        if (l != null) {
            int i = l.indexOf("-");
            if (i != -1) {
                language = l.substring(0, i).toLowerCase();
                country = l.substring(i+1).toUpperCase();
            } else {
                language = l;
            }
        }

        return new Locale(language, country);

    }

    private String charsetFromContentType(String ct) {
        if (ct != null) {
            int i = ct.indexOf(';');
            if (i != -1) {
                i = ct.indexOf("charset", i);
            }
            if (i != -1) {
                i = ct.indexOf('=', i);
            }
            if (i != -1) {
                ct = ct.substring(i + 1).trim();
                i = ct.indexOf(';');
                if (i != -1) {
                    return ct.substring(0, i);
                } else {
                    return ct;
                }
            }
        }

        return HttpProviderConstants.HTTP_DEFAULT_CHARSET;

    }



    /*******************************************************************
     *       Section that contains the methods for processing
     *       a Form/URL request.
     *
     *******************************************************************/



    private void setFromParameters(HttpServletRequest request)
    {
        mIsFromParameters = true;
        try
        {
            if ( getAction() == HttpProviderConstants.ACTION_SHOW_PORTLET)
            {
                // all other parameters are now fetched lazily when requested
                // in their get<> methods
                setAcceptContentTypes(request);
            }
        }
        catch (IllegalStateException e)
        {
            // getAction threw IllegalStateException because the parameter
            // did not exist. In this situation, this means that we are in
            // test mode.
            mIsTest = true;
        }
    }

    private void setAcceptContentTypes(HttpServletRequest request) {
        String ac = request.getHeader(HttpProviderConstants.HTTP_ACCEPT_CONTENT_TYPE);

        if (ac == null) {
            mAcceptContentTypes = null;
            return;
        }

        StringTokenizer st = new StringTokenizer(ac, ",");

        mAcceptContentTypes = new String[st.countTokens()];
        for (int i = 0; st.hasMoreElements(); i++) {
            mAcceptContentTypes[i] = st.nextToken();
        }
    }



    /*******************************************************************
     *       Section that contains the methods for processing
     *       a SOAP request.
     *
     *******************************************************************/

    private void setFromSOAP(HttpServletRequest request) throws ServletException, IOException {
        mIsFromParameters = false;
        Document doc = getDocument(request);
        Element aE = getMethodElement(doc);

        mAction = translateAction(aE.getNodeName());

        switch (mAction) {
        case HttpProviderConstants.ACTION_REGISTER_PROVIDER:
            unmarshalRegisterProvider(aE);
            break;
        case HttpProviderConstants.ACTION_DEREGISTER_PROVIDER:
            unmarshalDeregisterProvider(aE);
            break;
        case HttpProviderConstants.ACTION_GET_PORTLETS:
            unmarshalGetPortlets(aE);
            break;
        case HttpProviderConstants.ACTION_GET_PORTLET:
            unmarshalGetPortlet(aE);
            break;
        case HttpProviderConstants.ACTION_IS_PORTLET_RUNNABLE:
            unmarshalIsPortletRunnable(aE);
            break;
        case HttpProviderConstants.ACTION_GET_API_VERSION:
            unmarshalGetApiVersion(aE);
            break;
        case HttpProviderConstants.ACTION_REGISTER_PORTLET:
            unmarshalRegisterPortlet(aE);
            break;
        case HttpProviderConstants.ACTION_COPY_PORTLET:
            unmarshalCopyPortlet(aE);
            break;
        case HttpProviderConstants.ACTION_DEREGISTER_PORTLET:
            unmarshalDeregisterPortlet(aE);
            break;
        case HttpProviderConstants.ACTION_INIT_SESSION:
            unmarshalInitSession(aE);
            break;
        default:

        }
        return;
    }

    private Document getDocument(HttpServletRequest request) throws ServletException, IOException
    {
        Reader r = request.getReader();

        // Get an instance of the parser
        DOMParser parser = new DOMParser();

        // Set various parser options: validation on,
        // warnings shown, error stream set to stderr.
        CharArrayWriter errOut = new CharArrayWriter();
        parser.setErrorStream(new PrintWriter(errOut));
        parser.setValidationMode(false);
        parser.showWarnings(true);

      // Parse the document.
        try
        {
            parser.parse(r);
        }
        catch (Exception e)
        {
            String msg = e.getMessage() + Character.LINE_SEPARATOR + errOut.toString();
            this.getServletContext().log(msg);
            throw new ServletException(msg);
        }

        if (mDebugLevel >= 2)
        {
            Document d = parser.getDocument();
            dumpDocument(d);
            return d;
        }
        else
        {
            return parser.getDocument();
        }
    }

    private Element getMethodElement(Document d) {
        // the method should be the only element of the SOAP BODY
        NodeList nl = d.getElementsByTagName(SOAP_BODY);

        nl = nl.item(0).getChildNodes();

        return (Element) nl.item(0);

    }

    private void unmarshalRegisterProvider(Element aE) {
        mProviderId = unmarshalLong(aE, HttpProviderConstants.PROVIDER_ID_ELEMENT);
        mSubscriberId = unmarshalString(aE, HttpProviderConstants.SUBSCRIBER_ID_ELEMENT);
        mPortalVersion = unmarshalString(aE, HttpProviderConstants.PORTAL_VERSION_ELEMENT);
        mCompanyName = unmarshalString(aE,HttpProviderConstants.COMPANY_NAME_ELEMENT);
    }

    private void unmarshalDeregisterProvider(Element aE) {
        mProviderId = unmarshalLong(aE, HttpProviderConstants.PROVIDER_ID_ELEMENT);
        mSubscriberId = unmarshalString(aE, HttpProviderConstants.SUBSCRIBER_ID_ELEMENT);
        mCompanyName = unmarshalString(aE,HttpProviderConstants.COMPANY_NAME_ELEMENT);
    }

    private void unmarshalGetPortlets(Element aE) {
        mProviderId = unmarshalLong(aE, HttpProviderConstants.PROVIDER_ID_ELEMENT);
        unmarshalRange(aE);
        unmarshalUser(aE);
        mIsByUser = unmarshalBoolean(aE, HttpProviderConstants.PORTLET_BY_USER_ELEMENT);
        mLanguage = unmarshalLanguage(aE);
    }

    private void unmarshalGetPortlet(Element aE) {
        mProviderId = unmarshalLong(aE, HttpProviderConstants.PROVIDER_ID_ELEMENT);
        mPortletId = unmarshalLong(aE, HttpProviderConstants.PORTLET_ID_ELEMENT);
        unmarshalUser(aE);
        mLanguage = unmarshalLanguage(aE);
    }

    private void unmarshalIsPortletRunnable(Element aE) {
        mProviderId = unmarshalLong(aE, HttpProviderConstants.PROVIDER_ID_ELEMENT);
        unmarshalPortlet(aE);
        unmarshalUser(aE);
    }

    private void unmarshalGetApiVersion(Element aE) {
        mProviderId = unmarshalLong(aE, HttpProviderConstants.PROVIDER_ID_ELEMENT);
    }

    private void unmarshalRegisterPortlet(Element aE) {
        mProviderId = unmarshalLong(aE, HttpProviderConstants.PROVIDER_ID_ELEMENT);
        unmarshalPortlet(aE);
        unmarshalUser(aE);
    }

    private void unmarshalCopyPortlet(Element aE) {
        mProviderId = unmarshalLong(aE, HttpProviderConstants.PROVIDER_ID_ELEMENT);
        unmarshalCopyFromPortlet(aE);
        unmarshalCopyToPortlet(aE);
        unmarshalUser(aE);
    }

    private void unmarshalDeregisterPortlet(Element aE) {
        mProviderId = unmarshalLong(aE, HttpProviderConstants.PROVIDER_ID_ELEMENT);
        unmarshalPortlet(aE);
        unmarshalUser(aE);
    }

    private void unmarshalInitSession(Element aE) {
        mProviderId = unmarshalLong(aE, HttpProviderConstants.PROVIDER_ID_ELEMENT);
        unmarshalUser(aE);
        unmarshalExternalApp(aE);
    }

    private void dumpDocument(Document d)
    {
        mServletContext.log("Traverse WebDB request tree: ");
        printTree(d.getDocumentElement(), 0, mServletContext);
    }

    private void printTree(Node n, int level, ServletContext sc)
    {
        String ident = "";

        int i, len;

        if (level > 0) {
            for (i = 0; i < level; i++) {
                ident += "\t";
            }
        }

        String name = n.getNodeName();
        if (name == "#text") {
            sc.log(ident + n.getNodeValue());
        } else {
            sc.log(ident + name + ": ");
            if (n instanceof Element) {
                Element el = (Element) n;
                String nullStr = el.getAttribute("xsi:null");
                if (nullStr != null && (nullStr.equals("true") || nullStr.equals("1"))) {
                    sc.log(ident + "null");
                }
            }
        }

        NodeList nl = n.getChildNodes();
        len = nl.getLength();

        if (len == 0) {
            return;
        }

        for (int j=0; j < len; j++) {
            printTree(nl.item(j), level + 1, sc);
        }
    }




    private int translateAction(String mAction)
    {
        if (mAction == null) return HttpProviderConstants.ACTION_UNKNOWN;

        int j = mAction.indexOf(":");
        if (j != -1 && j < mAction.length() - 1)
        {
            mAction = mAction.substring(j+1);
        }

        return actionFromName(mAction);
    }

    private boolean translateBoolean(String param)
    {
        if (param == null)
            return false;

        try
        {
            return (Integer.parseInt(param) == 1);
        }
        catch (NumberFormatException nfe)
        {
            return param.equalsIgnoreCase("true");
        }
    }

    private long translateLong(String param)
    {
        if (param == null)
            return ID_UNKNOWN;

        try
        {
            return Long.parseLong(param);
        }
        catch (NumberFormatException e)
        {
            return ID_UNKNOWN;
        }
    }

    private int translateInt(String param)
    {
        if (param == null)
            return ID_UNKNOWN;

        try
        {
            return Integer.parseInt(param);
        }
        catch (NumberFormatException e)
        {
            return ID_UNKNOWN;
        }
    }


    private int actionFromName(String actionName)
    {
        if (actionName.equalsIgnoreCase(HttpProviderConstants.ACTIONNAME_INIT_SESSION)) {
            return HttpProviderConstants.ACTION_INIT_SESSION;
        } else if (actionName.equalsIgnoreCase(HttpProviderConstants.ACTIONNAME_IS_PORTLET_RUNNABLE)) {
            return HttpProviderConstants.ACTION_IS_PORTLET_RUNNABLE;
        } else if (actionName.equalsIgnoreCase(HttpProviderConstants.ACTIONNAME_GET_PORTLETS)) {
            return HttpProviderConstants.ACTION_GET_PORTLETS;
        } else if (actionName.equalsIgnoreCase(HttpProviderConstants.ACTIONNAME_GET_PORTLET)) {
            return HttpProviderConstants.ACTION_GET_PORTLET;
        } else if (actionName.equalsIgnoreCase(HttpProviderConstants.ACTIONNAME_REGISTER_PORTLET)) {
            return HttpProviderConstants.ACTION_REGISTER_PORTLET;
        } else if (actionName.equalsIgnoreCase(HttpProviderConstants.ACTIONNAME_REGISTER_PROVIDER)) {
            return HttpProviderConstants.ACTION_REGISTER_PROVIDER;
        } else if (actionName.equalsIgnoreCase(HttpProviderConstants.ACTIONNAME_COPY_PORTLET)) {
            return HttpProviderConstants.ACTION_COPY_PORTLET;
        } else if (actionName.equalsIgnoreCase(HttpProviderConstants.ACTIONNAME_DEREGISTER_PORTLET)) {
            return HttpProviderConstants.ACTION_DEREGISTER_PORTLET;
        } else if (actionName.equalsIgnoreCase(HttpProviderConstants.ACTIONNAME_DEREGISTER_PROVIDER)) {
            return HttpProviderConstants.ACTION_DEREGISTER_PROVIDER;
        } else if (actionName.equalsIgnoreCase(HttpProviderConstants.ACTIONNAME_GET_API_VERSION)) {
            return HttpProviderConstants.ACTION_GET_API_VERSION;
        } else if (actionName.equalsIgnoreCase(HttpProviderConstants.ACTIONNAME_SHOW_PORTLET)) {
            return HttpProviderConstants.ACTION_SHOW_PORTLET;
        } else {
            mServletContext.log("Unrecognized action: " + actionName);
            return HttpProviderConstants.ACTION_UNKNOWN;
        }
    }

    private void unmarshalUser(Element aE)
    {
        NodeList nl = aE.getElementsByTagName(HttpProviderConstants.PROVIDER_USER_ELEMENT);

        if (nl.getLength() > 0)
        {
            Element e;

            if (nl.item(0) instanceof Element)
            {
                e = (Element) nl.item(0);
            }
            else
            {
                return;
            }

            if (isNull(e))
                return;

            mUser308 = unmarshalString(e, HttpProviderConstants.PROVIDER_USER_NAME_ELEMENT);
            mUser309 = unmarshalString(e, HttpProviderConstants.PROVIDER_USERID_ELEMENT);
            mMappedUserName = unmarshalString(e, HttpProviderConstants.PROVIDER_USER_MAPPED_NAME_ELEMENT);
            mLoginTime = unmarshalString(e, HttpProviderConstants.PROVIDER_LOGIN_TIME_ELEMENT);
            mSessionId = unmarshalString(e, HttpProviderConstants.PROVIDER_SESSION_ID_ELEMENT);
            mSubscriberId = unmarshalString(e, HttpProviderConstants.SUBSCRIBER_ID_ELEMENT);
            mCompanyName = unmarshalString(e,HttpProviderConstants.COMPANY_NAME_ELEMENT);
            mAuthenticationLevel = unmarshalInt(e, HttpProviderConstants.PROVIDER_AUTHENTICATION_LEVEL_ELEMENT);

            mProviderUser = new ServletProviderUser(this,
                                                    mUser308,
                                                    mUser309,
                                                    mSubscriberId,
                                                    mCompanyName,
                                                    mAuthenticationLevel,
                                                    mMappedUserName,
                                                    mLoginTime,
                                                    mSessionId,
                                                    mServletSessionTimeout);
        }
    }

    private void unmarshalExternalApp(Element aE)
    {
        NodeList nl = aE.getElementsByTagName(HttpProviderConstants.PROVIDER_EXTERNAL_APP_ELEMENT);

        if (nl.getLength() > 0)
        {
            Element e;

            if (nl.item(0) instanceof Element)
            {
                e = (Element) nl.item(0);
            }
            else
            {
                return;
            }

            if (isNull(e))
                return;

            String mappedUser = unmarshalString(e, HttpProviderConstants.PROVIDER_EXTERNAL_APP_USERNAME_ELEMENT);
            String password = unmarshalString(e, HttpProviderConstants.PROVIDER_EXTERNAL_APP_PASSWORD_ELEMENT);
            String userField = unmarshalString(e, HttpProviderConstants.PROVIDER_EXTERNAL_APP_USER_FIELD);
            String passField = unmarshalString(e, HttpProviderConstants.PROVIDER_EXTERNAL_APP_PASS_FIELD);
            String authMethod = unmarshalString(e, HttpProviderConstants.PROVIDER_EXTERNAL_APP_AUTH_METHOD);
            String authUrl = unmarshalString(e, HttpProviderConstants.PROVIDER_EXTERNAL_APP_AUTH_URL);
            Hashtable fieldMap = unmarshalExternalAppFieldArray(e);

            mExternalApp = new ExternalPrincipal(mappedUser,
                                                password,
                                                userField,
                                                passField,
                                                authMethod,
                                                authUrl,
                                                fieldMap);
        }
    }


    private Hashtable unmarshalExternalAppFieldArray(Element aE)
    {
        // get the <applicationFields> element
        NodeList nl = aE.getElementsByTagName(HttpProviderConstants.PROVIDER_EXTERNAL_APP_FIELD_ARRAY_ELEMENT);

        Hashtable appFieldMap = null;
        if (nl.getLength() > 0)
        {
            Element e;

            if (nl.item(0) instanceof Element)
            {
                e = (Element) nl.item(0);
            }
            else
            {
                return null;
            }

            if (isNull(e))
                return null;

            NodeList fieldNodes = e.getElementsByTagName(HttpProviderConstants.PROVIDER_EXTERNAL_APP_FIELD_ELEMENT);
            int numFields = fieldNodes.getLength();
            if (numFields > 0)
            {
                // loop through the list of <applicationField> elements
                appFieldMap = new Hashtable(numFields);
                Node node = null;
                for (int i=0; i < numFields; i++)
                {
                    node = fieldNodes.item(i);
                    if (node instanceof Element)
                    {
                        // get the field name and value from the current
                        // element
                        Element fieldElement = (Element)node;
                        String name = unmarshalString(fieldElement,
                                                      HttpProviderConstants.PROVIDER_EXTERNAL_APP_FIELD_NAME_ELEMENT);
                        String value = unmarshalString(fieldElement,
                                                       HttpProviderConstants.PROVIDER_EXTERNAL_APP_FIELD_VALUE_ELEMENT);
                        if (name != null && !name.equals(""))
                        {
                            if (value == null)
                            {
                                // if the field does not have a value, put an
                                // empty string in the hashtable
                                value = new String("");
                            }
                            appFieldMap.put(name, value);
                        }
                    }
                }
            }
        }
        return appFieldMap;
    }

    private void unmarshalPortlet(Element aE)
    {
        NodeList nl = aE.getElementsByTagName(HttpProviderConstants.PORTLET_INSTANCE_ELEMENT);

        if (nl.getLength() > 0) {
            Element e;

            if (nl.item(0) instanceof Element)
            {
                e = (Element) nl.item(0);
            }
            else
            {
                return;
            }

            if (isNull(e))
                return;

            mPortletId = unmarshalLong(e, HttpProviderConstants.PORTLET_ID_ELEMENT);
            mPortletName = unmarshalString(e, HttpProviderConstants.PORTLET_INSTANCE_NAME_ELEMENT);
        }
    }

    private void unmarshalCopyFromPortlet(Element aE)
    {
        NodeList nl = aE.getElementsByTagName(HttpProviderConstants.PORTLET_COPYFROM_INSTANCE_ELEMENT);

        if (nl.getLength() > 0)
        {
            Element e;

            if (nl.item(0) instanceof Element)
            {
                e = (Element) nl.item(0);
            }
            else
            {
                return;
            }

            if (isNull(e))
                return;

            mFromPortletId = unmarshalLong(e, HttpProviderConstants.PORTLET_ID_ELEMENT);
            mFromPortletName = unmarshalString(e, HttpProviderConstants.PORTLET_INSTANCE_NAME_ELEMENT);
        }
    }

    private void unmarshalCopyToPortlet(Element aE)
    {
        NodeList nl = aE.getElementsByTagName(HttpProviderConstants.PORTLET_COPYTO_INSTANCE_ELEMENT);

        if (nl.getLength() > 0)
        {
            Element e;

            if (nl.item(0) instanceof Element)
            {
                e = (Element) nl.item(0);
            }
            else
            {
                return;
            }

            if (isNull(e))
                return;

            mToPortletId = unmarshalLong(e, HttpProviderConstants.PORTLET_ID_ELEMENT);
            mToPortletName = unmarshalString(e, HttpProviderConstants.PORTLET_INSTANCE_NAME_ELEMENT);
        }
    }

    private void unmarshalRange(Element aE)
    {
        NodeList nl = aE.getElementsByTagName(HttpProviderConstants.PORTLET_RANGE_ELEMENT);

        if (nl.getLength() > 0)
        {
            Element e;

            if (nl.item(0) instanceof Element)
            {
                e = (Element) nl.item(0);
            }
            else
            {
                return;
            }

            if (isNull(e))
                return;

            mStart = unmarshalInt(e, HttpProviderConstants.PORTLET_RANGE_START_ELEMENT);
            mCount = unmarshalInt(e, HttpProviderConstants.PORTLET_RANGE_COUNT_ELEMENT);
        }
    }

    private Locale unmarshalLanguage(Element aE)
    {
        NodeList nl = aE.getElementsByTagName(HttpProviderConstants.PORTLET_LANGUAGE_ELEMENT);

        if (nl.getLength() > 0)
        {
            return translateLanguage(unmarshalString(nl.item(0)));
        }
        return translateLanguage(null);
    }

    private String unmarshalString(Element aE, String elementName)
    {
        if (elementName == null || (elementName != null && elementName.equals("")))
            return null;

        NodeList nl = aE.getElementsByTagName(elementName);

        if (nl.getLength() > 0)
        {
            return unmarshalString(nl.item(0));
        }
        return null;
    }

    private long unmarshalLong(Element containingElement, String elementName)
    {
        if (elementName == null || (elementName != null && elementName.equals("")))
            return ID_UNKNOWN;

        NodeList nl = containingElement.getElementsByTagName(elementName);

        if (nl.getLength() > 0)
        {
            return unmarshalLong(nl.item(0));
        }
        return ID_UNKNOWN;
    }

    private int unmarshalInt(Element containingElement, String elementName)
    {
        if (elementName == null || (elementName != null && elementName.equals("")))
            return ID_UNKNOWN;

        NodeList nl = containingElement.getElementsByTagName(elementName);

        if (nl.getLength() > 0)
        {
            return unmarshalInt(nl.item(0));
        }
        return ID_UNKNOWN;
    }

    private boolean unmarshalBoolean(Element containingElement,
                                     String elementName)
    {
        if (elementName == null || (elementName != null && elementName.equals("")))
            return false;

        NodeList nl = containingElement.getElementsByTagName(elementName);

        if (nl.getLength() > 0)
        {
            return unmarshalBoolean(nl.item(0));
        }
        return false;
    }

    private long unmarshalLong(Node n)
    {
        if (isNull(n)) return ID_UNKNOWN;

        // get the text node for this Element and convert its value to a long
        NodeList nl = n.getChildNodes();
        if (nl.getLength() > 0)
        {
            try
            {
                return Long.parseLong(nl.item(0).getNodeValue());
            }
            catch (Exception e)
            {
                return ID_UNKNOWN;
            }
        }
        return ID_UNKNOWN;
    }

    private int unmarshalInt(Node n)
    {
        if (isNull(n))
            return ID_UNKNOWN;

        // get the text node for this Element and convert its value to a long
        NodeList nl = n.getChildNodes();
        if (nl.getLength() > 0)
        {
            try
            {
                return Integer.parseInt(nl.item(0).getNodeValue());
            }
            catch (Exception e)
            {
                return ID_UNKNOWN;
            }
        }
        return ID_UNKNOWN;
    }

    private String unmarshalString(Node n)
    {
        if (isNull(n))
            return null;

        // get the text node for this Element and convert its value to a long
        NodeList nl = n.getChildNodes();
        if (nl.getLength() > 0)
        {
            try
            {
                return nl.item(0).getNodeValue();
            }
            catch (Exception e)
            {
                return null;
            }
        }
        return null;
    }

    private boolean unmarshalBoolean(Node n)
    {
        if (isNull(n))
            return false;

        // get the text node for this Element and convert its value to a long
        NodeList nl = n.getChildNodes();
        if (nl.getLength() > 0)
        {
            try
            {
                return Boolean.valueOf(nl.item(0).getNodeValue()).booleanValue();
            }
            catch (Exception e)
            {
                return false;
            }
        }
        return false;
    }

    private boolean isNull(Node n)
    {
        if (! (n instanceof Element))
            return false;

        Element el = (Element) n;
        String nullStr = el.getAttribute(NULL_ATTRIBUTE);
        if (nullStr != null && (nullStr.equals("true") || nullStr.equals("1")))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    private void dumpPost()
    {
        char[] buf = new char[1024];
        BufferedInputStream bis = null;
        InputStreamReader isr = null;
        try
        {
            bis = new BufferedInputStream(mRequest.getInputStream());
            isr = new InputStreamReader(bis);
            SimpleStringBuffer stringBuf = new SimpleStringBuffer();
            int charsRead = 0;
            while ((charsRead = isr.read(buf)) != -1)
            {
                stringBuf.append(buf, 0, charsRead);
            }
            mServletContext.log(stringBuf.toString());
        }
        catch (Exception e)
        {
            try
            {
                if (isr != null)
                    isr.close();
                if (bis != null)
                    bis.close();
            }
            catch (Exception e2)
            {
                // do nothing
            }
        }
    }

}

