org.mule.transport.http.CookieHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.mule.transport.http.CookieHelper.java

Source

/*
 * $Id$
 * --------------------------------------------------------------------------------------
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 *
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */

package org.mule.transport.http;

import org.mule.api.MuleEvent;
import org.mule.api.MuleMessage;
import org.mule.api.expression.ExpressionManager;

import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TimeZone;

import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.cookie.CookieSpec;
import org.apache.commons.httpclient.cookie.MalformedCookieException;
import org.apache.commons.httpclient.cookie.NetscapeDraftSpec;
import org.apache.commons.httpclient.cookie.RFC2109Spec;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tomcat.util.http.Cookies;
import org.apache.tomcat.util.http.MimeHeaders;
import org.apache.tomcat.util.http.ServerCookie;

/**
 * <p>
 * Helper functions for parsing, formatting, storing and retrieving cookie headers.
 * </p>
 * <p>
 * It is important that all access to Cookie data is done using this class. This will
 * help to prevent ClassCastExceptions and data corruption.
 * </p>
 * <p>
 * The reasons for such a very complex CookieHelper class are historical and are
 * related to the fact that cookies are a multivalued property and we store them as a
 * single message property under the name
 * {@linkplain HttpConnector#HTTP_COOKIES_PROPERTY "cookies"}.
 * </p>
 * <p>
 * In an HTTP message going from client to server the cookies come on their own
 * {@linkplain HttpConstants#HEADER_COOKIE "Cookie"} header. The HTTP message can
 * have several of these Cookie headers and each of them can store 1 or more cookies.
 * One problem with this is that in Mule we use {@link Map} instances to store the
 * HTTP headers and this means that we can only have one object with the key
 * {@linkplain HttpConnector#HTTP_COOKIES_PROPERTY "cookies"} (yes, we use that
 * constant instead of {@linkplain HttpConstants#HEADER_COOKIE "Cookie"} when we
 * store the cookies inside a {@link MuleMessage}).
 * </p>
 * <p>
 * In an HTTP message going from server to client the Cookies go in their own
 * {@linkplain HttpConstants#HEADER_COOKIE_SET "Set-Cookie"} header. But, again,
 * internally we store all the HTTP headers inside a {@link Map} that maps each HTTP
 * header with a single value. For Cookies it is a special case so have to be able to
 * store many cookies in the value from that map.
 * </p>
 * <p>
 * With all these layed out one could say that we could just have a
 * {@link Collection} of {@link Cookie} instances. But this is not that simple. In
 * some parts of the code the cookies are stored as an array of Cookies and in some
 * others it is stored as a {@link Map} where each entry corresponds to a cookie's
 * name/value pair (which is not strictly a cookie). Specifically, when parsing
 * cookies from the client (ie, acting as a server), the code stores it as an array
 * of cookies. When the cookies are specified as a property in the endpoint (like <a
 * href=
 * "http://www.mulesoft.org/documentation/display/MULE3USER/HTTP+Transport#HTTPTransport-Cookies"
 * >explained in the docs</a>), they are stored as a {@link Map}.
 * </p>
 * <p>
 * This class has helper methods that helps making code that is independent of the
 * way the cookies are stored and still keep backward compatibility. It is very
 * hacky, but I think it is better than what we had before.
 * </p>
 * <p>
 * <b>Know Limitation:</b> because of how cookies are handled in Mule, we don't
 * handle well the host, port and path of a Cookie. We just handle Cookies as if they
 * were only name/value pairs. This means that, for example, if a message with
 * cookies is received on an endpoint called http://localhost:4020/hello (1) and that
 * message goes to http://www.mulesoft.org/jira/ (2), then service (2) will receive
 * all the cookies that were sent to service (1) as if they were their own.
 * Furthermore, the same thing will happend on the response: all the returned cookies
 * from service (2) will reach service (1) and then the client will receive them as
 * if they were from service (1).
 * </p>
 */
public class CookieHelper {
    /**
     * This is used as the default {@link URI} for
     * {@link #parseCookiesAsAClient(String, String, URI)} and overloading methods
     * for when the {@link URI} supplied is null.
     */
    private static final String DEFAULT_URI_STRING = "http://localhost:80/";

    /**
     * logger used by this class
     */
    protected static final Log logger = LogFactory.getLog(CookieHelper.class);

    public static final String EXPIRE_PATTERN = "EEE, d-MMM-yyyy HH:mm:ss z";
    private static final SimpleDateFormat EXPIRE_FORMATTER;

    static {
        EXPIRE_FORMATTER = new SimpleDateFormat(EXPIRE_PATTERN, Locale.US);
        EXPIRE_FORMATTER.setTimeZone(TimeZone.getTimeZone("GMT"));
    }

    /**
     * Do not instantiate.
     */
    private CookieHelper() {
        // no op
    }

    /**
     * @return the {@link CookieSpec} (defaults to {@link RFC2109Spec} when spec is
     *         null)
     */
    public static CookieSpec getCookieSpec(String spec) {
        if (spec != null && spec.equalsIgnoreCase(HttpConnector.COOKIE_SPEC_NETSCAPE)) {
            return new NetscapeDraftSpec();
        } else {
            return new RFC2109Spec();
        }
    }

    /**
     * @return the cookie policy (defaults to {@link CookiePolicy#RFC_2109} when spec
     *         is null).
     */
    public static String getCookiePolicy(String spec) {
        if (spec != null && spec.equalsIgnoreCase(HttpConnector.COOKIE_SPEC_NETSCAPE)) {
            return CookiePolicy.NETSCAPE;
        } else {
            return CookiePolicy.RFC_2109;
        }
    }

    /**
     * @see #parseCookiesAsAClient(String, String, URI)
     */
    public static Cookie[] parseCookiesAsAClient(Header cookieHeader, String spec) throws MalformedCookieException {
        return parseCookiesAsAClient(cookieHeader.getValue(), spec, null);
    }

    /**
     * @see #parseCookiesAsAClient(String, String, URI)
     */
    public static Cookie[] parseCookiesAsAClient(String cookieHeaderValue, String spec)
            throws MalformedCookieException {
        return parseCookiesAsAClient(cookieHeaderValue, spec, null);
    }

    /**
     * @see #parseCookiesAsAClient(String, String, URI)
     */
    public static Cookie[] parseCookiesAsAClient(Header cookieHeader, String spec, URI uri)
            throws MalformedCookieException {
        return parseCookiesAsAClient(cookieHeader.getValue(), spec, uri);
    }

    /**
     * This method parses the value of {@linkplain HttpConstants#HEADER_COOKIE_SET
     * "Set-Cookie"} HTTP header, returning an array with all the {@link Cookie}s
     * found. This method is intended to be used from the client side of the HTTP
     * connection.
     *
     * @param cookieHeaderValue the value with the cookie/s to parse.
     * @param spec the spec according to {@link #getCookieSpec(String)} (can be null)
     * @param uri the uri information that will be use to complete Cookie information
     *            (host, port and path). If null then the
     *            <code>DEFAULT_URI_STRING</code> will be used.
     */
    public static Cookie[] parseCookiesAsAClient(String cookieHeaderValue, String spec, URI uri)
            throws MalformedCookieException {
        if (uri == null) {
            try {
                uri = new URI(DEFAULT_URI_STRING);
            } catch (URISyntaxException e) {
                throw new RuntimeException("This should have not happened", e);
            }
        }
        CookieSpec cookieSpec = getCookieSpec(spec);
        boolean secure = uri.getScheme() != null && uri.getScheme().equalsIgnoreCase("https");
        String host = uri.getHost();
        int port = getPortFromURI(uri);
        String path = uri.getPath();

        return cookieSpec.parse(host, port, path, secure, cookieHeaderValue);
    }

    private static int getPortFromURI(URI uri) throws MalformedCookieException {
        int port = uri.getPort();
        if (port < 0) {
            String scheme = uri.getScheme();
            if (scheme.equalsIgnoreCase("https")) {
                port = 443;
            } else if (scheme.equalsIgnoreCase("http")) {
                port = 80;
            } else {
                String message = String.format(
                        "The uri (%1s) does not specify a port and no default is available for its scheme (%2s).",
                        uri, scheme);
                throw new MalformedCookieException(message);
            }
        }
        return port;
    }

    /**
     * This method parses the value of an HTTP
     * {@linkplain HttpConstants#HEADER_COOKIE "Cookie"} header that comes from a
     * client to a server. It returns all the Cookies present in the header.
     *
     * @param header the header from which the cookie will be parsed. Please not that
     *            only the {@link Header#getValue() value} of this header will be
     *            used. No validation will be made to make sure that the
     *            {@linkplain Header#getName() headerName} is actually a
     *            {@link HttpConstants#HEADER_COOKIE}.
     */
    public static Cookie[] parseCookiesAsAServer(Header header, URI uri) {
        return parseCookiesAsAServer(header.getValue(), uri);
    }

    /**
     * This method parses the value of an HTTP {@linkplain HttpConstants#HEADER_COOKIE
     * "Cookie"} header that comes from a client to a server. It returns all the
     * Cookies present in the header.
     *
     * @param headerValue the value of the header from which the cookie will be
     *            parsed.
     */
    public static Cookie[] parseCookiesAsAServer(String headerValue, URI uri) {
        MimeHeaders mimeHeaders = new MimeHeaders();
        mimeHeaders.addValue(HttpConstants.HEADER_COOKIE).setBytes(headerValue.getBytes(), 0, headerValue.length());

        Cookies cs = new Cookies(mimeHeaders);
        Cookie[] cookies = new Cookie[cs.getCookieCount()];
        for (int i = 0; i < cs.getCookieCount(); i++) {
            ServerCookie serverCookie = cs.getCookie(i);
            cookies[i] = transformServerCookieToClientCookie(serverCookie);
            if (uri != null) {
                cookies[i].setSecure(uri.getScheme() != null && uri.getScheme().equalsIgnoreCase("https"));
                cookies[i].setDomain(uri.getHost());
                cookies[i].setPath(uri.getPath());
            }
        }
        return cookies;
    }

    /**
     * Transforms a {@link ServerCookie} (from Apache Tomcat) into a {@link Cookie}
     * (from commons httpclient). Both types of Cookie hold the same data but the
     * {@link ServerCookie} is the type that you get when parsing cookies as a
     * Server.
     */
    protected static Cookie transformServerCookieToClientCookie(ServerCookie serverCookie) {
        Cookie clientCookie = new Cookie(serverCookie.getDomain().toString(), serverCookie.getName().toString(),
                serverCookie.getValue().toString(), serverCookie.getPath().toString(), serverCookie.getMaxAge(),
                serverCookie.getSecure());
        clientCookie.setComment(serverCookie.getComment().toString());
        clientCookie.setVersion(serverCookie.getVersion());
        return clientCookie;
    }

    /**
     * This method formats the cookie so it can be send from server to client in a
     * {@linkplain HttpConstants#HEADER_COOKIE_SET "Set-Cookie"} header.
     */
    public static String formatCookieForASetCookieHeader(Cookie cookie) {
        StringBuffer sb = new StringBuffer();
        ServerCookie.appendCookieValue(sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
                cookie.getPath(), cookie.getDomain(), cookie.getComment(), -1, cookie.getSecure());

        Date expiryDate = cookie.getExpiryDate();
        if (expiryDate != null) {
            sb.append("; Expires=");
            sb.append(EXPIRE_FORMATTER.format(expiryDate));
        }

        return sb.toString();
    }

    /**
     * Adds to the client all the cookies present in the cookiesObject.
     *
     * @param cookiesObject this must be either a {@link Map Map&lt;String,
     *            String&gt;} or a {@link Cookie Cookie[]}. It can be null.
     * @param event this one is used only if the cookies are stored in a {@link Map}
     *            in order to resolve expressions with the {@link ExpressionManager}.
     * @param destinationUri the host, port and path of this {@link URI} will be used
     *            as the data of the cookies that are added.
     */
    public static void addCookiesToClient(HttpClient client, Object cookiesObject, String policy, MuleEvent event,
            URI destinationUri) {
        CookieStorageType.resolveCookieStorageType(cookiesObject).addCookiesToClient(client, cookiesObject, policy,
                event, destinationUri);
    }

    /**
     * <p>
     * This method merges a new Cookie (or override the previous one if it exists) to
     * the preExistentCookies. The result (the old cookies with the new one added) is
     * returned. If a cookie with the same name already exists, then it will be
     * overridden.
     * </p>
     * <p>
     * It is <b>important</b> that you use the returned value of this method because
     * for some implementations of preExistentCookies it is not possible to add new
     * Cookies (for example, on Cookie[]).
     * </p>
     *
     * @param preExistentCookies this must be either a
     *            <code>java.util.Map&lt;String, String&gt;</code> or a
     *            <code>Cookie[]</code>. It can be null.
     * @param cookieName the new cookie name to be added.
     * @param cookieValue the new cookie value to be added.
     */
    public static Object putAndMergeCookie(Object preExistentCookies, String cookieName, String cookieValue) {
        return CookieStorageType.resolveCookieStorageType(preExistentCookies).putAndMergeCookie(preExistentCookies,
                cookieName, cookieValue);
    }

    /**
     * <p>
     * Merges all the Cookies in newCookiesArray with the preExistentCookies, adding
     * the new ones and overwriting the existing ones (existing means same cookie
     * name).
     * </p>
     * <p>
     * It is <b>important</b> that you use the returned value of this method because
     * for some implementations of preExistentCookies it is not possible to add new
     * Cookies (for example, on Cookie[]).
     * </p>
     */
    public static Object putAndMergeCookie(Object preExistentCookies, Cookie[] newCookiesArray) {
        return CookieStorageType.resolveCookieStorageType(preExistentCookies).putAndMergeCookie(preExistentCookies,
                newCookiesArray);
    }

    /**
     * <p>
     * Merges all the Cookies in newCookiesMap with the preExistentCookies, adding
     * the new ones and overwriting the existing ones (existing means same cookie
     * name).
     * </p>
     * <p>
     * It is <b>important</b> that you use the returned value of this method because
     * for some implementations of preExistentCookies it is not possible to add new
     * Cookies (for example, on Cookie[]).
     * </p>
     */
    public static Object putAndMergeCookie(Object preExistentCookies, Map<String, String> newCookiesMap) {
        return CookieStorageType.resolveCookieStorageType(preExistentCookies).putAndMergeCookie(preExistentCookies,
                newCookiesMap);
    }

    /**
     * Searches and return the cookie with the cookieName in the cookiesObject. It
     * returns <code>null</code> if the cookie is not present.
     */
    public static String getCookieValueFromCookies(Object cookiesObject, String cookieName) {
        return CookieStorageType.resolveCookieStorageType(cookiesObject).getCookieValueFromCookies(cookiesObject,
                cookieName);
    }

    /**
     * Returns an array view of the cookiesObject.
     */
    public static Cookie[] asArrayOfCookies(Object cookiesObject) {
        return CookieStorageType.resolveCookieStorageType(cookiesObject).asArrayOfCookies(cookiesObject);
    }

}

/**
 * This enum type is here to distinguish and handle the two type of cookie storage
 * that we have. The method
 * {@link CookieStorageType#resolveCookieStorageType(Object)} allows you to select
 * the appropriate {@link CookieStorageType} for the cookiesObject that you have.
 */
enum CookieStorageType {
    /**
     * <p>
     * This corresponds to the storage of cookies as a Cookie[].
     * </p>
     * <p>
     * All the parameters of type {@link Object} in the method of this object are
     * assumed to be of type Cookie[] and won't be checked. They will be cast to
     * Cookie[].
     * </p>
     */
    ARRAY_OF_COOKIES {
        @Override
        public Object putAndMergeCookie(Object preExistentCookies, String cookieName, String cookieValue) {
            final Cookie[] preExistentCookiesArray = (Cookie[]) preExistentCookies;

            final int sessionIndex = getCookieIndexFromCookiesArray(cookieName, preExistentCookiesArray);

            // domain, path, secure (https) and expiry are handled in method
            // CookieHelper.addCookiesToClient()
            final Cookie newSessionCookie = new Cookie(null, cookieName, cookieValue);
            final Cookie[] mergedCookiesArray;
            if (sessionIndex >= 0) {
                preExistentCookiesArray[sessionIndex] = newSessionCookie;
                mergedCookiesArray = preExistentCookiesArray;
            } else {
                Cookie[] newSessionCookieArray = new Cookie[] { newSessionCookie };
                mergedCookiesArray = concatenateCookies(preExistentCookiesArray, newSessionCookieArray);
            }
            return mergedCookiesArray;
        }

        protected Cookie[] concatenateCookies(Cookie[] cookies1, Cookie[] cookies2) {
            if (cookies1 == null) {
                return cookies2;
            } else if (cookies2 == null) {
                return null;
            } else {
                Cookie[] mergedCookies = new Cookie[cookies1.length + cookies2.length];
                System.arraycopy(cookies1, 0, mergedCookies, 0, cookies1.length);
                System.arraycopy(cookies2, 0, mergedCookies, cookies1.length, cookies2.length);
                return mergedCookies;
            }
        }

        protected int getCookieIndexFromCookiesArray(String cookieName, Cookie[] preExistentCookies) {
            if (preExistentCookies != null && cookieName != null) {
                for (int i = 0; i < preExistentCookies.length; i++) {
                    if (cookieName.equals(preExistentCookies[i].getName())) {
                        return i;
                    }
                }
            }
            return -1;
        }

        @Override
        public String getCookieValueFromCookies(Object cookiesObject, String cookieName) {
            Cookie[] cookies = (Cookie[]) cookiesObject;

            int sessionIndex = getCookieIndexFromCookiesArray(cookieName, cookies);
            if (sessionIndex >= 0) {
                return cookies[sessionIndex].getValue();
            } else {
                return null;
            }
        }

        @Override
        public void addCookiesToClient(HttpClient client, Object cookiesObject, String policy, MuleEvent event,
                URI destinationUri) {
            Cookie[] cookies = (Cookie[]) cookiesObject;

            if (cookies != null && cookies.length > 0) {
                String host = destinationUri.getHost();
                String path = destinationUri.getPath();
                for (Cookie cookie : cookies) {
                    client.getState().addCookie(new Cookie(host, cookie.getName(), cookie.getValue(), path,
                            cookie.getExpiryDate(), cookie.getSecure()));
                }
                client.getParams().setCookiePolicy(CookieHelper.getCookiePolicy(policy));
            }
        }

        @Override
        public Object putAndMergeCookie(Object preExistentCookies, Cookie[] newCookiesArray) {
            if (newCookiesArray == null) {
                return preExistentCookies;
            }
            final List<Cookie> cookiesThatAreReallyNew = new ArrayList<Cookie>(newCookiesArray.length);
            final Cookie[] preExistentCookiesArray = (Cookie[]) preExistentCookies;
            for (Cookie newCookie : newCookiesArray) {
                int newCookieInPreExistentArrayIndex = getCookieIndexFromCookiesArray(newCookie.getName(),
                        preExistentCookiesArray);
                if (newCookieInPreExistentArrayIndex >= 0) {
                    // overwrite the old one
                    preExistentCookiesArray[newCookieInPreExistentArrayIndex] = newCookie;
                } else {
                    // needs to add it at the end
                    cookiesThatAreReallyNew.add(newCookie);
                }
            }

            return concatenateCookies(preExistentCookiesArray,
                    cookiesThatAreReallyNew.toArray(new Cookie[cookiesThatAreReallyNew.size()]));
        }

        @Override
        public Object putAndMergeCookie(Object preExistentCookies, Map<String, String> newCookiesMap) {
            if (newCookiesMap == null) {
                return putAndMergeCookie(preExistentCookies, (Cookie[]) null);
            } else {
                Cookie[] cookiesArray = new Cookie[newCookiesMap.size()];
                int i = 0;
                for (Entry<String, String> cookieEntry : newCookiesMap.entrySet()) {
                    Cookie cookie = new Cookie();
                    cookie.setName(cookieEntry.getKey());
                    cookie.setValue(cookieEntry.getValue());
                    cookiesArray[i++] = cookie;
                }
                return putAndMergeCookie(preExistentCookies, cookiesArray);
            }
        }

        @Override
        public Cookie[] asArrayOfCookies(Object cookiesObject) {
            if (cookiesObject == null) {
                return ZERO_COOKIES;
            } else {
                return (Cookie[]) cookiesObject;
            }
        }

    },

    /**
     * <p>
     * This corresponds to the storage of cookies as {@link Map<String, String>},
     * where the keys are the cookie names and the values are the cookie values.
     * </p>
     * <p>
     * All the parameters of type {@link Object} in the method of this object are
     * assumed to be of type {@link Map<String, String>} and won't be checked. They
     * will be cast to {@link Map} and used as if all the keys and values are of type
     * {@link String}.
     */
    MAP_STRING_STRING {
        @Override
        @SuppressWarnings("unchecked")
        public Object putAndMergeCookie(Object preExistentCookies, String cookieName, String cookieValue) {
            final Map<String, String> cookieMap = (Map<String, String>) preExistentCookies;

            cookieMap.put(cookieName, cookieValue);
            return cookieMap;
        }

        @Override
        @SuppressWarnings("unchecked")
        public String getCookieValueFromCookies(Object cookiesObject, String cookieName) {
            return ((Map<String, String>) cookiesObject).get(cookieName);
        }

        @Override
        @SuppressWarnings("unchecked")
        public void addCookiesToClient(HttpClient client, Object cookiesObject, String policy, MuleEvent event,
                URI destinationUri) {
            Map<String, String> cookieMap = (Map<String, String>) cookiesObject;

            client.getParams().setCookiePolicy(CookieHelper.getCookiePolicy(policy));

            String host = destinationUri.getHost();
            String path = destinationUri.getPath();
            Iterator<String> keyIter = cookieMap.keySet().iterator();
            while (keyIter.hasNext()) {
                String key = keyIter.next();
                String cookieValue = cookieMap.get(key);

                final String value;
                if (event != null) {
                    value = event.getMuleContext().getExpressionManager().parse(cookieValue, event);
                } else {
                    value = cookieValue;
                }

                Cookie cookie = new Cookie(host, key, value, path, null, false);
                client.getState().addCookie(cookie);
            }

        }

        @Override
        public Object putAndMergeCookie(Object preExistentCookies, Cookie[] newCookiesArray) {
            if (newCookiesArray == null) {
                return preExistentCookies;
            }
            for (Cookie cookie : newCookiesArray) {
                preExistentCookies = putAndMergeCookie(preExistentCookies, cookie.getName(), cookie.getValue());
            }
            return preExistentCookies;
        }

        @Override
        public Object putAndMergeCookie(Object preExistentCookies, Map<String, String> newCookiesMap) {
            if (newCookiesMap == null) {
                return preExistentCookies;
            }
            for (Entry<String, String> cookieEntry : newCookiesMap.entrySet()) {
                preExistentCookies = putAndMergeCookie(preExistentCookies, cookieEntry.getKey(),
                        cookieEntry.getValue());
            }
            return preExistentCookies;
        }

        @Override
        @SuppressWarnings("unchecked")
        public Cookie[] asArrayOfCookies(Object cookiesObject) {
            Map<String, String> cookieMap = (Map<String, String>) cookiesObject;
            Cookie[] arrayOfCookies = new Cookie[cookieMap.size()];
            int i = 0;
            for (Entry<String, String> cookieEntry : cookieMap.entrySet()) {
                Cookie cookie = new Cookie();
                cookie.setName(cookieEntry.getKey());
                cookie.setValue(cookieEntry.getValue());
                arrayOfCookies[i++] = cookie;
            }
            return arrayOfCookies;
        }

    };

    private static final Cookie[] ZERO_COOKIES = new Cookie[0];

    /**
     * Resolves the cookiesObject to the appropriate {@link CookieStorageType}.
     *
     * @param cookiesObject
     * @return
     */
    public static CookieStorageType resolveCookieStorageType(Object cookiesObject) {
        if (cookiesObject == null || cookiesObject instanceof Cookie[]) {
            return CookieStorageType.ARRAY_OF_COOKIES;
        } else if (cookiesObject instanceof Map) {
            return CookieStorageType.MAP_STRING_STRING;
        } else {
            throw new IllegalArgumentException("Invalid cookiesObject. Only " + Cookie.class + "[] and " + Map.class
                    + " are supported: " + cookiesObject);
        }
    }

    /**
     * @see CookieHelper#putAndMergeCookie(Object, String, String)
     */
    public abstract Object putAndMergeCookie(Object preExistentCookies, String cookieName, String cookieValue);

    /**
     * @see CookieHelper#putAndMergeCookie(Object, Cookie[])
     */
    public abstract Object putAndMergeCookie(Object preExistentCookies, Cookie[] newCookiesArray);

    /**
     * @see CookieHelper#putAndMergeCookie(Object, Map)
     */
    public abstract Object putAndMergeCookie(Object preExistentCookies, Map<String, String> newCookiesMap);

    /**
     * @see CookieHelper#getCookieValueFromCookies(Object, String)
     */
    public abstract String getCookieValueFromCookies(Object cookiesObject, String cookieName);

    /**
     * @see CookieHelper#addCookiesToClient(HttpClient, Object, String, MuleEvent,
     *      URI)
     */
    public abstract void addCookiesToClient(HttpClient client, Object cookiesObject, String policy, MuleEvent event,
            URI destinationUri);

    /**
     * @see CookieHelper#asArrayOfCookies(Object)
     */
    public abstract Cookie[] asArrayOfCookies(Object cookiesObject);
}