/* Copyright (c) 1999, 2001 Oracle Corporation. All Rights Reserved */
package oracle.portal.provider.v1.http;

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

import javax.servlet.http.*;

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

/**
 * <code>ServletPortletRenderRequest</code> is the JPDK's base implementation
 * of the {@link oracle.portal.provider.v1.PortletRenderRequest} interface. It
 * represents a {@link oracle.portal.provider.v1.PortletRenderRequest} running
 * in a servlet environment.
 * <p>The interfaces {@link oracle.portal.provider.v1.PortletExecutionTracker}
 * and {@link PerformanceLoggerAccessor} are used for
 * tracking the execution time of a portlet, and for logging performance stats
 * about it.
 */
public class ServletPortletRenderRequest 
  implements PortletRenderRequest, 
             PortletExecutionTracker, 
             PerformanceLoggerAccessor
{
    private PortletReference mRef;
    private ServletProviderRequest mProviderRequest;
    private Servlet20RequestWrapper mServletRequest;

    private Hashtable attributes;
    private String mContentType = null;
    private String mCharacterEncoding = null;
    private PrintWriter mWriter = null;

    /**
     * Constructs a <code>ServletPortletRenderRequest</code>.
     *
     * @param ref a {@link oracle.portal.provider.v1.PortletReference}.
     * @param request a {@link
     * oracle.portal.provider.v1.http.ServletProviderRequest}.
     */
    public ServletPortletRenderRequest(PortletReference ref,
                                       ServletProviderRequest request)
    {
        mRef = ref;
        mProviderRequest = request;
        mServletRequest = (Servlet20RequestWrapper)request.getRequest();

        /* running in a Servlet 2.0 environment -- otherwise just use the
           ServletRequest */
        attributes = new Hashtable();

        setAttribute(HttpProvider.SERVLET_CONFIG,
                     mProviderRequest.getServletConfig());
        setAttribute(HttpProvider.SERVLET_CONTEXT,
                     mProviderRequest.getServletContext());
        setAttribute(HttpProvider.SERVLET_REQUEST, mServletRequest);
        setAttribute(HttpProvider.SERVLET_RESPONSE,
                     mProviderRequest.getResponse());

        // Write self as attribute in case we get forwarded to a servlet and
        // they need to get back to us.
        setAttribute(HttpProvider.PORTLET_RENDER_REQUEST, this);
    }

    /**
     * @return a URL that returns one to the portal page that invoked this
     * portlet.Note: Query string is included if applicable.
     */
    public String getDesignURL() throws java.lang.IllegalStateException
    {
        return mProviderRequest.getDesignURL();
    }

    /**
     * @return the URL of the page that invoked this portlet.  Portlets use
     * this to (re)write URLs in their response that should redisplay the
     * portlet in this page. Note: Query string is included if applicable.
     */
    public String getPageURL() throws java.lang.IllegalStateException
    {
        return mProviderRequest.getPageURL();
    }

    /**
     * @return the URL of the page that caused this page to display.
     */
    public String getBackURL() throws java.lang.IllegalStateException
    {
        return mProviderRequest.getBackURL();
    }

    /**
     * @return the URL that invoked this portlet.  Portlets use this to
     * (re)write HREFs in their response as these references must be absolute
     * paths since the client browser considers the current target the
     * portal. Note: request parameters are always returned as part of the URLs
     * querystring regardless of whether the request was received via an HTTP
     * GET or POST.
     */
    public String getRequestURL() throws java.lang.IllegalStateException
    {
        String request = getScheme() + "://" + getServerName()+ ":" +
            getServerPort() + mServletRequest.getRequestURI();
        if (mServletRequest.getMethod().equalsIgnoreCase("GET"))
        {
            String qs = mServletRequest.getQueryString();
            if (qs != null && qs.length()>0)
            {
                request += "?" + qs;
            }
        }
        else
        {
            // assume POST
            boolean start = true;
            Enumeration e = mServletRequest.getParameterNames();
            while (e != null && e.hasMoreElements())
            {
                String name = (String) e.nextElement();
                String[] values = mServletRequest.getParameterValues(name);
                for (int i = 0; i < values.length; i++)
                {
                    if (start)
                    {
                        request += "?";
                        start = false;
                    }
                    else
                    {
                        request += "&";
                    }
                    request += URLEncoder.encode(name) + "=" +
                        URLEncoder.encode(values[i]);
                }
            }
        }
        return request;
    }

    /**
     * @return the URL ....
     */
    public String getLoginServerURL() throws java.lang.IllegalStateException
    {
        return mProviderRequest.getLoginServerURL();
    }

    /**
     * @return an array of mime-types in preference order being requested.
     * I.e.  the portal may pass a list of valid mime-types it accepts for the
     * target device.  The Portlet must emit its response in one of these
     * mime-types.  The list is ordered by reference with the first being the
     * highest preference.
     */
    public String[] getAcceptContentTypes()
        throws java.lang.IllegalStateException
    {
        return mProviderRequest.getAcceptContentTypes();
    }

    /**
     * @return the most preferred mime-type beign requested.
     */
    public String getPreferredContentType()
        throws java.lang.IllegalStateException
    {
        return mProviderRequest.getPreferredContentType();
    }

    /**
     *  @return an indicator of whether this portlet should draw a title or not.
     */
    public boolean hasTitle() throws java.lang.IllegalStateException
    {
        return mProviderRequest.hasTitle();
    }

    /**
     * @return an indicator of whether this portlet should draw its border or
     * not.
     */
    public boolean hasBorder() throws java.lang.IllegalStateException
    {
        return mProviderRequest.hasBorder();
    }

    /**
     * The Portal supports an edit mode that allows a page developer to create
     * multiple language versions of a page including the default
     * customizations.  The <code>boolean</code> return value from this call
     * indicates whether or not the Portlet is in this mode.  If
     * <code>false</code> the Portlet should save all edit_default
     * customizations in the default (language) customization.  If
     * <code>true</code> the Portlet should save all edit_default
     * customizations in the current language customization.
     */
    public boolean translateDefaultCustomizations()
    {
        return mProviderRequest.getTranslateMode();
    }

    /**
     * @return the rendering mode.  The mode is defined in the various
     * constants in PortletRenderingMode.
     */
    public int getMode() throws java.lang.IllegalStateException
    {
        return mProviderRequest.getMode();
    }

    /**
     * Gets the portlet reference for the instance we are intended to render.
     */
    public PortletReference getPortletReference()
    {
        return mRef;
    }

    /**
     * Gets the user making this request.
     */
    public ProviderUser getUser()
    {
        return mProviderRequest.getProviderUser();
    }

    /**
     *  @return the device information for this request.
     */
    public DeviceInfo getDeviceInfo()
    {
        return mProviderRequest.getDeviceInfo();
    }

    /**
     *  @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()
    {
        return mProviderRequest.getPortalConfig();
    }

    /**
     *  If this is a mobile request iAS Wireless will have overwritten some
     *  of the client's original HTTP headers: specifically the Accept and the
     *  UserAgent header.  These routines give you access to the original values.
     *  Note: if the values haven't been overwritten then its assumed that the
     *  standard headers contain the original values.  In this situation these
     *  methods return the values for the standard headers.  In this way these
     *  methods always give you access to the header values as they originated
     *  from the client whether or not they have been overwritten.
     *
     *  @param name the header name you want the original value for.  I.e. if
     *  you pass "Accept" you will receive the original value of "Accept"
     *  whether its been overwritten or not.
     */
    public String getOriginalHeader(String name) {
        String h = null;
        if (name.equalsIgnoreCase("Accept"))
        {
            h = mServletRequest.getHeader(
                HttpProviderConstants.IASWIRELESS_ORIGINAL_ACCEPT_HEADER);
            if (h == null)
                h = mServletRequest.getHeader("Accept");
            return h;
        }
        else if (name.equalsIgnoreCase("User-Agent"))
        {
            h = mServletRequest.getHeader(
                HttpProviderConstants.IASWIRELESS_ORIGINAL_USERAGENT_HEADER);
            if (h == null)
                h = mServletRequest.getHeader("User-Agent");
            return h;
        }
        else
            return mServletRequest.getHeader(name);
    }

    /* convenience routines -- each can be accessed indirectly via the
       PortletReference */

    /**
     * Gets the Provider associated with this request.  This is equivalent to
     * calling getPortletReference().getPortlet().getProvider().
     */
    public Provider getProvider()
    {
        return getPortlet().getProvider();
    }

    /**
     * Gets the Portlet associated with this request.  This is equivalent to
     * calling getPortletReference().getPortlet().
     */
    public Portlet getPortlet()
    {
        return mRef.getPortlet();
    }


    /**
     * Gets the PortletSecurityManager controlling this request.  This is
     * equivalent to getPortletReference().getPortlet().getSecurityManager();
     */
    public PortletSecurityManager getSecurityManager()
    {
        return getPortlet().getSecurityManager();
    }

    /**
     * Gets the PortletPersonalizationManager controlling this request.  This
     * is equivalent to
     * getPortletReference().getPortlet().getPortletPersonalizationManager();
     */
    public PortletPersonalizationManager getPersonalizationManager()
    {
        return getPortlet().getPersonalizationManager();
    }


    /**
     * The scheme we are running in.  Most commonly this will return
     * <b>http</b>.  Return value will be <i>null</i> if not running in any
     * scheme.  This can occur if running outside the context of a request as
     * in a batch program filling a cache on the server.
     */
    public String getScheme()
    {
        return mServletRequest.getScheme();
    }

    /**
     * The user agent that originated this request.  May be null if user-agent
     * is local.
     */
    public String getUserAgent()
    {
        return mServletRequest.getHeader("User-Agent");
    }

    /**
     * Server name.  Used to reconstruct absolute paths back to server.
     */
    public String getServerName()
    {
        return mServletRequest.getServerName();
    }

    /**
     * Port used by this server. Used to reconstruct absolute paths back to
     * server.
     */
    public int getServerPort()
    {
        return mServletRequest.getServerPort();
    }

    /**
     * Returns the request parameter of the given name.  If there are
     * duplicates the first value is returned.  Returned Parameter values are
     * encoded using the RequestContext's encoding.  By default this is
     * ISO-8859-1.
     *
     * @param name the name of the parameter whose value is requested.
     */
    public String getParameter(String name)
    {
        return mServletRequest.getParameter(name);
    }

    /**
     * Returns the qualified request parameter of the given non-qualified name.
     * Because all portlets on a page share the same query string, portlets
     * will often fully qualify their parameter names to the portlet instance
     * to ensure the instance can distinguish its parameters from the others.
     * This qualification is of the form
     * providerId.portletId.instanceName.paramName.  Utility methods are
     * provided in PortletRendererUtil and HttpPortletRendererUtil to construct
     * these fully qualified names.<p> Fully-qualified parameter names are
     * somewhat inconvenient to use because they are dynamic.  I.e. they are
     * isntance-based.  This method helps to overcome this inconvenience by
     * allowing you to retrieve the fully qualified parameter name value
     * passing only the non-qualified name.  E.g. calling
     * request.getQualifiedParameter("symbol") will return the value for the
     * parameter named
     * "<i>curProviderId.curPortletId.curInstanceName</i>.symbol".<p>
     *
     * As with getParameter(), if there are duplicates the first value is
     * returned.  Returned Parameter values are encoded using the
     * RequestContext's encoding.  By default this is ISO-8859-1.
     *
     * @param name the unqualfied name of the parameter whose value is
     * requested.
     * @return the value corresponding to the fully qualified name constructed
     * by prepending the portlet reference information to the passed parameter
     * name.
     */
    public String getQualifiedParameter(String name)
    {
        return getParameter(PortletRendererUtil.portletParameter(mRef, name));
    }

    /**
     * Returns the values for the named request parameter.  Returned Parameter
     * values are encoded using the RequestContext's encoding.  By default this
     * is ISO-8859-1.
     *
     * @param name the name of the parameter whose value is requested.
     * @return an array of Strings; one element per value associated with this
     * parameter name.
     */
    public String[] getParameterValues(String name)
    {
        return mServletRequest.getParameterValues(name);
    }

    /**
     * Returns the qualified request parameter values of the given
     * non-qualified name.  Because all portlets on a page share the same query
     * string, portlets will often fully qualify their parameter names to the
     * portlet instance to ensure the instance can distinguish its parameters
     * from the others.  This qualification is of the form
     * providerId.portletId.instanceName.paramName.  Utility methods are
     * provided in PortletRendererUtil and HttpPortletRendererUtil to construct
     * these fully qualified names.<p> Fully-qualified parameter names are
     * somewhat inconvenient to use because they are dynamic.  I.e. they are
     * isntance-based.  This method helps to overcome this inconvenience by
     * allowing you to retrieve the fully qualified parameter name value
     * passing only the non-qualified name.  E.g. calling
     * request.getQualifiedParameterValues("symbol") will return the values for
     * the parameter named
     * "<i>curProviderId.curPortletId.curInstanceName</i>.symbol".<p>
     *
     * Returned Parameter values are encoded using the RequestContext's
     * encoding.  By default this is ISO-8859-1.
     *
     * @param name the unqualfied name of the parameter whose value is
     * requested.
     * @return the values corresponding to the fully qualified name constructed
     * by prepending the portlet reference information to the passed parameter
     * name.
     */
    public String[] getQualifiedParameterValues(String name)
    {
        return getParameterValues(PortletRendererUtil.portletParameter(mRef,
                                                                       name));
    }

    /**
     * Returns an enumeration containing the parameter names passed in this
     * request.
     */
    public Enumeration getParameterNames()
    {
        return mServletRequest.getParameterNames();
    }

    /**
     * Returns an enumeration containing only those parameter names that match
     * this portlets fully qualified name.  I.e. only those parameters that are
     * prefixed by this portlet's curProviderId.curPortletId.curInstanceName.
     * The return values remain fully qualified.  I.e. the names in the
     * enumeration remain fully qualified -- hence you use the regular methods
     * to access (getParameter() vs. getQualifiedParameter())
     */
    public Enumeration getQualifiedParameterNames()
    {
        Enumeration e = getParameterNames();
        Vector v = new Vector(20);
        String fqn = mRef.getProviderId() + "." + mRef.getPortletId() + "." +
            mRef.getName() + ".";

        while (e.hasMoreElements())
        {
            String s = (String) e.nextElement();
            if (s.startsWith(fqn))
            {
                v.addElement(s);
            }
        }
        return v.elements();
    }

    /**
     * Sets the contentType for this request's response.  After the first call
     * to any of the getWriter() methods the content type and character
     * encoding cannot be changed.
     */
    public void setContentType(String contentType)
    {
        if (contentType == null)
            return;
        
        // save only the content type - not the character set
        mContentType = removeCharsetFromContentType(contentType);

        // store the character set as the character encoding
        String charset = getCharsetFromContentType(contentType);
        if (charset != null)
        {
            setCharacterEncoding(charset);
        }
        writeResponseContentType();
    }

    /**
     * Gets the current contentType for this request's response.  After the
     * first call to any of the getWriter() methods the content type and
     * character encoding cannot be changed.
     */
    public String getContentType()
    {
        if (mContentType == null || mContentType.equals(""))
            mContentType = PortletRenderer.TYPE_HTML;

        return mContentType;
    }


    /**
     * Sets the IANA character encoding to be used for this request's response.
     * After the first call to any of the getWriter() methods the content type
     * and character encoding cannot be changed.
     */
    public void setCharacterEncoding(String encoding)
    {
        if (encoding == null)
            mCharacterEncoding = getCharacterEncoding();

        mCharacterEncoding = encoding;
        writeResponseContentType();
    }

    /**
     * The default IANA character encoding to be used for this request's
     * response.  After the first call to any of the getWriter() methods the
     * content type and character encoding cannot be changed.
     */
    public String getCharacterEncoding()
    {
        // if a character set has not been specified, get the first
        // acceptable charset from the request. If that is null,
        // use the default character encoding.
        if (mCharacterEncoding == null || mCharacterEncoding.equals(""))
        {
            mCharacterEncoding = mProviderRequest.getAcceptCharset();
            if (mCharacterEncoding == null || mCharacterEncoding.equals(""))
            {
                mCharacterEncoding = PortletRenderer.DEFAULT_CHARACTER_ENCODING;
            }
        }

        return mCharacterEncoding;
    }


    /**
     * Returns a PrintWriter used to emit this request's response. If
     * applicable the passed contentType and character encoding are used to
     * prepare the response (header).  <p>Note: <p>if <b>null</b> is passed for
     * the content type of the response is defaulted to "text/html".  <p>if
     * <b>null</b> is passed for the character encoding and the encoding has
     * not previously been set by calling setCharacterEncoding() it will be
     * defaulted using the default encoding of the request.  <p> After the
     * first call to any of the getWriter() methods the content type and
     * character encoding cannot be changed.
     */
    public PrintWriter getWriter(String contentType, String encoding)
           throws java.io.IOException
    {
        if (mWriter != null)
            return mWriter;

        setContentType(contentType);
        setCharacterEncoding(encoding);
        return getWriter();
    }


    /**
     * Returns a PrintWriter used to emit this request's response. If
     * applicable the passed contentType is used to prepare the response
     * (header).  <p>Note: <p>if <b>null</b> is passed the content type of the
     * response is set to "text/html".  Also, if the contentType doesn't
     * contain character set information (or is null), this routine sets the
     * character set information based on the default encoding of the request.
     * <p> After the first call to any of the getWriter() methods the content
     * type and character encoding cannot be changed.
     */
    public PrintWriter getWriter(String contentType) throws java.io.IOException
    {
        if (mWriter != null)
            return mWriter;

        setContentType(contentType);
        return getWriter();
    }

    /**
     * Returns a PrintWriter used to emit this request's response. If
     * applicable the passed contentType is used to prepare the response
     * (header).  <p>Note: <p>Uses the content type specified by calling
     * setContentType() or defaults the content type of the response to
     * "text/html".  Uses the character encoding set by calling
     * setCharacterEncoding() or the default character encoding from the
     * request <p> After the first call to any of the getWriter() methods the
     * content type and character encoding cannot be changed.
     */
    public PrintWriter getWriter() throws java.io.IOException
    {
        if (mWriter != null)
        {
            return mWriter;
        }
        writeResponseContentType();
        HttpServletResponse response = mProviderRequest.getResponse();
        mWriter = response.getWriter();
        return mWriter;
    }

    /**
     * The preferred Java Locale to be used for this response.
     */
    public Locale getLocale()
    {
        return mProviderRequest.getAcceptLanguage();
    }

    /**
     * Returns an Enumeration of Locale objects indicating, in decreasing order
     * starting with the preferred locale, the locales that are acceptable to
     * the client based on the Accept-Language header.
     */
    public Enumeration getLocales()
    {
        Vector v = mProviderRequest.getAcceptLanguages();

        if (v != null)
        {
            return v.elements();
        }
        else
        {
            return null;
        }
    }

    /**
     * Returns the Portal's default Locale.  Used by portlets/personalization
     * managers to properly default to the correct language when preferred
     * languages aren't supported.  This value may be <code>null</code>.  When
     * <code>null</code> or when the portlet doesn't support this locale the
     * Portlet's default Locale should be used.  This is accessible via the
     * Portlet interface (<code>getDefaultLocale()</code>).<p> Alternatively,
     * you might consider using the <code>getDefaultLocale()</code> method in
     * the <code>PortletReference</code> interface.  This method is defined to
     * return the Portlet's default locale if the Portal hasn't passed one.
     */
    public Locale getDefaultLocale()
    {
        return mProviderRequest.getDefaultLanguage();
    }

    /**
     * The IANA character encoding of the parameters passed with this request.
     */
    public String getParameterCharacterEncoding()
    {
        // get the contentType header
        return mProviderRequest.getContentCharset();
    }

    /**
     * The Java Locale of the parameters passed with this request.
     */
    public Locale getParameterLocale()
    {
        return mProviderRequest.getContentLanguage();
    }

    /**
     * Returns the Provider resource associated with the Locale of this
     * request.  This resource contains locale specific strings for the title
     * bar.
     */
    public ResourceBundle getProviderResource()
    {
        return mProviderRequest.getProviderResource();
    }


    /**
     * A session is an object that maintains state across requests. We use the
     * Servlet Session abstraction as it really is Http independent and is the
     * most commonly used session object in this model anyway.
     *
     */
    public ProviderSession getSession()
    {
        return getUser().getSession();
    }

    /**
     * A session is an object that maintains state across requests. We use the
     * Servlet Session abstraction as it really is Http independent and is the
     * most commonly used session object in this model anyway.
     *
     */
    public Object[] getCookies()
    {
        return mServletRequest.getCookies();
    }


    /**
     * Data can be passed between object in a request via attr/value pairs hung
     * off the RequestContext.  Clients are encouraged to prefix attribute
     * names with fully qualified class names to avoid collisions.  E.g.
     * setAttribute("oracle.jdeveloper.chart.color", chartColor);
     *
     * @param name the name of the attribute.
     * @param value the value for the attribute.
     */
    public void setAttribute(String name, Object value)
    {
        attributes.put(name, value);
    }


    /**
     * Data can be passed between object in a request via attr/value pairs hung
     * off the RequestContext.  Clients are encouraged to prefix attribute
     * names with fully qualified class names to avoid collisions.  E.g.
     * setAttribute("oracle.jdeveloper.chart.color", chartColor);
     *
     * @param name the name of the attribute.
     * @return value the value for the attribute.
     */
    public Object getAttribute(String name)
    {
        if (attributes == null) 
        {
            return mServletRequest.getAttribute(name);
        }
        else
        {
            Object o = attributes.get(name);
            if (o == null)
            {
                return mServletRequest.getAttribute(name);
            }
            else
            {
                return o;
            }
        }
    }

    public java.util.Enumeration getAttributeNames()
    {
        return attributes.keys();
    }

    /**
     * Removes an existing attribute.
     *
     * @param name the name of the attribute.
     */
    public void removeAttribute(String name)
    {
        // only implemented in servlet 2.2????
        if (attributes != null) attributes.remove(name);
    }

    /**
     * Returns the character set that was used when the parameters of the
     * request were encoded.  Used when encoding parameters for inclusion in a
     * URL
     */
    public String getURLCharSet()
    {
        return mServletRequest.getURLCharSet();
    }

    /**
     * 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 mProviderRequest.getPortletStartTime();
    }

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

    /**
     * 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 mProviderRequest.hasPortletTimeoutElapsed();
    }

    /**
     * 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 mProviderRequest.getPortletKillTimeout();
    }

    /**
     * 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 mProviderRequest.hasPortletTimeoutElapsed();
    }

    /**
     * Returns a performance logger object.
     *
     * @return a reference to a <code>PerformanceLogger</code> object.
     */
    public PerformanceLogger getPerformanceLogger()
    {
        return mProviderRequest.getPerformanceLogger();
    }

    private void writeResponseContentType()
    {
        SimpleStringBuffer contentType = new SimpleStringBuffer();
        contentType.append(getContentType());
        contentType.append(";charset=");
        contentType.append(getCharacterEncoding());

        HttpServletResponse response = mProviderRequest.getResponse();
        response.setContentType(contentType.toString());
    }

    private String getCharsetFromContentType(String contentType)
    {
        int pos;
        String csName = null;

        if ((pos = contentType.toLowerCase().indexOf("charset=")) > 0)
        {
            csName = contentType.substring(pos + 8);
            if ((pos = csName.indexOf(" ")) > 0)
            {
                csName = csName.substring(0, pos-1);
            }
        }
        return csName;
    }

    private String removeCharsetFromContentType(String contentType)
    {
        int pos;
        String ctype = null;

        if ((pos = contentType.toLowerCase().indexOf(";")) > 0)
        {
            ctype = contentType.substring(0, pos);
            if ((pos = ctype.indexOf(" ")) > 0)
            {
                ctype = ctype.substring(0, pos);
            }
        }
        else
        {
            ctype = contentType;
        }
        return ctype;
    }

}
