Coverage Report - org.mule.transport.http.CookieHelper
 
Classes in this File Line Coverage Branch Coverage Complexity
CookieHelper
0%
0/67
0%
0/30
0
CookieStorageType
0%
0/9
0%
0/6
0
CookieStorageType$1
0%
0/60
0%
0/34
0
CookieStorageType$2
0%
0/40
0%
0/14
0
 
 1  
 /*
 2  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 3  
  * The software in this package is published under the terms of the CPAL v1.0
 4  
  * license, a copy of which has been included with this distribution in the
 5  
  * LICENSE.txt file.
 6  
  */
 7  
 package org.mule.transport.http;
 8  
 
 9  
 import org.mule.api.MuleEvent;
 10  
 import org.mule.api.MuleMessage;
 11  
 import org.mule.api.expression.ExpressionManager;
 12  
 
 13  
 import java.net.URI;
 14  
 import java.net.URISyntaxException;
 15  
 import java.text.SimpleDateFormat;
 16  
 import java.util.ArrayList;
 17  
 import java.util.Collection;
 18  
 import java.util.Date;
 19  
 import java.util.Iterator;
 20  
 import java.util.List;
 21  
 import java.util.Locale;
 22  
 import java.util.Map;
 23  
 import java.util.Map.Entry;
 24  
 import java.util.TimeZone;
 25  
 
 26  
 import org.apache.commons.httpclient.Cookie;
 27  
 import org.apache.commons.httpclient.Header;
 28  
 import org.apache.commons.httpclient.HttpClient;
 29  
 import org.apache.commons.httpclient.cookie.CookiePolicy;
 30  
 import org.apache.commons.httpclient.cookie.CookieSpec;
 31  
 import org.apache.commons.httpclient.cookie.MalformedCookieException;
 32  
 import org.apache.commons.httpclient.cookie.NetscapeDraftSpec;
 33  
 import org.apache.commons.httpclient.cookie.RFC2109Spec;
 34  
 import org.apache.commons.logging.Log;
 35  
 import org.apache.commons.logging.LogFactory;
 36  
 import org.apache.tomcat.util.http.Cookies;
 37  
 import org.apache.tomcat.util.http.MimeHeaders;
 38  
 import org.apache.tomcat.util.http.ServerCookie;
 39  
 
 40  
 /**
 41  
  * <p>
 42  
  * Helper functions for parsing, formatting, storing and retrieving cookie headers.
 43  
  * </p>
 44  
  * <p>
 45  
  * It is important that all access to Cookie data is done using this class. This will
 46  
  * help to prevent ClassCastExceptions and data corruption.
 47  
  * </p>
 48  
  * <p>
 49  
  * The reasons for such a very complex CookieHelper class are historical and are
 50  
  * related to the fact that cookies are a multivalued property and we store them as a
 51  
  * single message property under the name
 52  
  * {@linkplain HttpConnector#HTTP_COOKIES_PROPERTY "cookies"}.
 53  
  * </p>
 54  
  * <p>
 55  
  * In an HTTP message going from client to server the cookies come on their own
 56  
  * {@linkplain HttpConstants#HEADER_COOKIE "Cookie"} header. The HTTP message can
 57  
  * have several of these Cookie headers and each of them can store 1 or more cookies.
 58  
  * One problem with this is that in Mule we use {@link Map} instances to store the
 59  
  * HTTP headers and this means that we can only have one object with the key
 60  
  * {@linkplain HttpConnector#HTTP_COOKIES_PROPERTY "cookies"} (yes, we use that
 61  
  * constant instead of {@linkplain HttpConstants#HEADER_COOKIE "Cookie"} when we
 62  
  * store the cookies inside a {@link MuleMessage}).
 63  
  * </p>
 64  
  * <p>
 65  
  * In an HTTP message going from server to client the Cookies go in their own
 66  
  * {@linkplain HttpConstants#HEADER_COOKIE_SET "Set-Cookie"} header. But, again,
 67  
  * internally we store all the HTTP headers inside a {@link Map} that maps each HTTP
 68  
  * header with a single value. For Cookies it is a special case so have to be able to
 69  
  * store many cookies in the value from that map.
 70  
  * </p>
 71  
  * <p>
 72  
  * With all these layed out one could say that we could just have a
 73  
  * {@link Collection} of {@link Cookie} instances. But this is not that simple. In
 74  
  * some parts of the code the cookies are stored as an array of Cookies and in some
 75  
  * others it is stored as a {@link Map} where each entry corresponds to a cookie's
 76  
  * name/value pair (which is not strictly a cookie). Specifically, when parsing
 77  
  * cookies from the client (ie, acting as a server), the code stores it as an array
 78  
  * of cookies. When the cookies are specified as a property in the endpoint (like <a
 79  
  * href=
 80  
  * "http://www.mulesoft.org/documentation/display/MULE3USER/HTTP+Transport#HTTPTransport-Cookies"
 81  
  * >explained in the docs</a>), they are stored as a {@link Map}.
 82  
  * </p>
 83  
  * <p>
 84  
  * This class has helper methods that helps making code that is independent of the
 85  
  * way the cookies are stored and still keep backward compatibility. It is very
 86  
  * hacky, but I think it is better than what we had before.
 87  
  * </p>
 88  
  * <p>
 89  
  * <b>Know Limitation:</b> because of how cookies are handled in Mule, we don't
 90  
  * handle well the host, port and path of a Cookie. We just handle Cookies as if they
 91  
  * were only name/value pairs. This means that, for example, if a message with
 92  
  * cookies is received on an endpoint called http://localhost:4020/hello (1) and that
 93  
  * message goes to http://www.mulesoft.org/jira/ (2), then service (2) will receive
 94  
  * all the cookies that were sent to service (1) as if they were their own.
 95  
  * Furthermore, the same thing will happend on the response: all the returned cookies
 96  
  * from service (2) will reach service (1) and then the client will receive them as
 97  
  * if they were from service (1).
 98  
  * </p>
 99  
  */
 100  
 public class CookieHelper
 101  
 {
 102  
     /**
 103  
      * This is used as the default {@link URI} for
 104  
      * {@link #parseCookiesAsAClient(String, String, URI)} and overloading methods
 105  
      * for when the {@link URI} supplied is null.
 106  
      */
 107  
     private static final String DEFAULT_URI_STRING = "http://localhost:80/";
 108  
 
 109  
     /**
 110  
      * logger used by this class
 111  
      */
 112  0
     protected static final Log logger = LogFactory.getLog(CookieHelper.class);
 113  
 
 114  
         private static final String EXPIRE_PATTERN = "EEE, d-MMM-yyyy HH:mm:ss z";
 115  
     private static final SimpleDateFormat EXPIRE_FORMATTER;
 116  
 
 117  
     static
 118  
     {
 119  0
         EXPIRE_FORMATTER = new SimpleDateFormat(EXPIRE_PATTERN, Locale.US);
 120  0
         EXPIRE_FORMATTER.setTimeZone(TimeZone.getTimeZone("GMT"));
 121  0
     }
 122  
 
 123  
     /**
 124  
      * Do not instantiate.
 125  
      */
 126  
     private CookieHelper()
 127  0
     {
 128  
         // no op
 129  0
     }
 130  
 
 131  
     /**
 132  
      * @return the {@link CookieSpec} (defaults to {@link RFC2109Spec} when spec is
 133  
      *         null)
 134  
      */
 135  
     public static CookieSpec getCookieSpec(String spec)
 136  
     {
 137  0
         if (spec != null && spec.equalsIgnoreCase(HttpConnector.COOKIE_SPEC_NETSCAPE))
 138  
         {
 139  0
             return new NetscapeDraftSpec();
 140  
         }
 141  
         else
 142  
         {
 143  0
             return new RFC2109Spec();
 144  
         }
 145  
     }
 146  
 
 147  
     /**
 148  
      * @return the cookie policy (defaults to {@link CookiePolicy#RFC_2109} when spec
 149  
      *         is null).
 150  
      */
 151  
     public static String getCookiePolicy(String spec)
 152  
     {
 153  0
         if (spec != null && spec.equalsIgnoreCase(HttpConnector.COOKIE_SPEC_NETSCAPE))
 154  
         {
 155  0
             return CookiePolicy.NETSCAPE;
 156  
         }
 157  
         else
 158  
         {
 159  0
             return CookiePolicy.RFC_2109;
 160  
         }
 161  
     }
 162  
 
 163  
     /**
 164  
      * @see #parseCookiesAsAClient(String, String, URI)
 165  
      */
 166  
     public static Cookie[] parseCookiesAsAClient(Header cookieHeader, String spec)
 167  
         throws MalformedCookieException
 168  
     {
 169  0
         return parseCookiesAsAClient(cookieHeader.getValue(), spec, null);
 170  
     }
 171  
 
 172  
     /**
 173  
      * @see #parseCookiesAsAClient(String, String, URI)
 174  
      */
 175  
     public static Cookie[] parseCookiesAsAClient(String cookieHeaderValue, String spec)
 176  
         throws MalformedCookieException
 177  
     {
 178  0
         return parseCookiesAsAClient(cookieHeaderValue, spec, null);
 179  
     }
 180  
 
 181  
     /**
 182  
      * @see #parseCookiesAsAClient(String, String, URI)
 183  
      */
 184  
     public static Cookie[] parseCookiesAsAClient(Header cookieHeader, String spec, URI uri)
 185  
         throws MalformedCookieException
 186  
     {
 187  0
         return parseCookiesAsAClient(cookieHeader.getValue(), spec, uri);
 188  
     }
 189  
 
 190  
     /**
 191  
      * This method parses the value of {@linkplain HttpConstants#HEADER_COOKIE_SET
 192  
      * "Set-Cookie"} HTTP header, returning an array with all the {@link Cookie}s
 193  
      * found. This method is intended to be used from the client side of the HTTP
 194  
      * connection.
 195  
      *
 196  
      * @param cookieHeaderValue the value with the cookie/s to parse.
 197  
      * @param spec the spec according to {@link #getCookieSpec(String)} (can be null)
 198  
      * @param uri the uri information that will be use to complete Cookie information
 199  
      *            (host, port and path). If null then the
 200  
      *            <code>DEFAULT_URI_STRING</code> will be used.
 201  
      */
 202  
     public static Cookie[] parseCookiesAsAClient(String cookieHeaderValue, String spec, URI uri)
 203  
         throws MalformedCookieException
 204  
     {
 205  0
         if (uri == null)
 206  
         {
 207  
             try
 208  
             {
 209  0
                 uri = new URI(DEFAULT_URI_STRING);
 210  
             }
 211  0
             catch (URISyntaxException e)
 212  
             {
 213  0
                 throw new RuntimeException("This should have not happened", e);
 214  0
             }
 215  
         }
 216  0
         CookieSpec cookieSpec = getCookieSpec(spec);
 217  0
         boolean secure = uri.getScheme() != null && uri.getScheme().equalsIgnoreCase("https");
 218  0
         String host = uri.getHost();
 219  0
         int port = getPortFromURI(uri);
 220  0
         String path = uri.getPath();
 221  
 
 222  0
         return cookieSpec.parse(host, port, path, secure, cookieHeaderValue);
 223  
     }
 224  
 
 225  
     private static int getPortFromURI(URI uri) throws MalformedCookieException
 226  
     {
 227  0
         int port = uri.getPort();
 228  0
         if (port < 0)
 229  
         {
 230  0
             String scheme = uri.getScheme();
 231  0
             if (scheme.equalsIgnoreCase("https"))
 232  
             {
 233  0
                 port = 443;
 234  
             }
 235  0
             else if (scheme.equalsIgnoreCase("http"))
 236  
             {
 237  0
                 port = 80;
 238  
             }
 239  
             else
 240  
             {
 241  0
                 String message = String.format(
 242  
                     "The uri (%1s) does not specify a port and no default is available for its scheme (%2s).",
 243  
                     uri, scheme);
 244  0
                 throw new MalformedCookieException(message);
 245  
             }
 246  
         }
 247  0
         return port;
 248  
     }
 249  
 
 250  
     /**
 251  
      * This method parses the value of an HTTP
 252  
      * {@linkplain HttpConstants#HEADER_COOKIE "Cookie"} header that comes from a
 253  
      * client to a server. It returns all the Cookies present in the header.
 254  
      *
 255  
      * @param header the header from which the cookie will be parsed. Please not that
 256  
      *            only the {@link Header#getValue() value} of this header will be
 257  
      *            used. No validation will be made to make sure that the
 258  
      *            {@linkplain Header#getName() headerName} is actually a
 259  
      *            {@link HttpConstants#HEADER_COOKIE}.
 260  
      */
 261  
     public static Cookie[] parseCookiesAsAServer(Header header, URI uri)
 262  
     {
 263  0
         return parseCookiesAsAServer(header.getValue(), uri);
 264  
     }
 265  
 
 266  
     /**
 267  
      * This method parses the value of an HTTP {@linkplain HttpConstants#HEADER_COOKIE
 268  
      * "Cookie"} header that comes from a client to a server. It returns all the
 269  
      * Cookies present in the header.
 270  
      *
 271  
      * @param headerValue the value of the header from which the cookie will be
 272  
      *            parsed.
 273  
      */
 274  
     public static Cookie[] parseCookiesAsAServer(String headerValue, URI uri)
 275  
     {
 276  0
         MimeHeaders mimeHeaders = new MimeHeaders();
 277  0
         mimeHeaders.addValue(HttpConstants.HEADER_COOKIE).setBytes(headerValue.getBytes(), 0,
 278  
             headerValue.length());
 279  
 
 280  0
         Cookies cs = new Cookies(mimeHeaders);
 281  0
         Cookie[] cookies = new Cookie[cs.getCookieCount()];
 282  0
         for (int i = 0; i < cs.getCookieCount(); i++)
 283  
         {
 284  0
             ServerCookie serverCookie = cs.getCookie(i);
 285  0
             cookies[i] = transformServerCookieToClientCookie(serverCookie);
 286  0
             if (uri != null)
 287  
             {
 288  0
                 cookies[i].setSecure(uri.getScheme() != null && uri.getScheme().equalsIgnoreCase("https"));
 289  0
                 cookies[i].setDomain(uri.getHost());
 290  0
                 cookies[i].setPath(uri.getPath());
 291  
             }
 292  
         }
 293  0
         return cookies;
 294  
     }
 295  
 
 296  
     /**
 297  
      * Transforms a {@link ServerCookie} (from Apache Tomcat) into a {@link Cookie}
 298  
      * (from commons httpclient). Both types of Cookie hold the same data but the
 299  
      * {@link ServerCookie} is the type that you get when parsing cookies as a
 300  
      * Server.
 301  
      */
 302  
     protected static Cookie transformServerCookieToClientCookie(ServerCookie serverCookie)
 303  
     {
 304  0
         Cookie clientCookie = new Cookie(serverCookie.getDomain().toString(), serverCookie.getName()
 305  
             .toString(), serverCookie.getValue().toString(), serverCookie.getPath().toString(),
 306  
             serverCookie.getMaxAge(), serverCookie.getSecure());
 307  0
         clientCookie.setComment(serverCookie.getComment().toString());
 308  0
         clientCookie.setVersion(serverCookie.getVersion());
 309  0
         return clientCookie;
 310  
     }
 311  
 
 312  
     /**
 313  
      * This method formats the cookie so it can be send from server to client in a
 314  
      * {@linkplain HttpConstants#HEADER_COOKIE_SET "Set-Cookie"} header.
 315  
      */
 316  
     public static String formatCookieForASetCookieHeader(Cookie cookie)
 317  
     {
 318  0
         StringBuffer sb = new StringBuffer();
 319  0
         ServerCookie.appendCookieValue(sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
 320  
             cookie.getPath(), cookie.getDomain(), cookie.getComment(), -1, cookie.getSecure());
 321  
 
 322  0
         Date expiryDate = cookie.getExpiryDate();
 323  0
         if (expiryDate != null)
 324  
         {
 325  0
             sb.append("; Expires=");
 326  0
             sb.append(EXPIRE_FORMATTER.format(expiryDate));
 327  
         }
 328  
 
 329  0
         return sb.toString();
 330  
     }
 331  
 
 332  
     /**
 333  
      * Adds to the client all the cookies present in the cookiesObject.
 334  
      *
 335  
      * @param cookiesObject this must be either a {@link Map Map&lt;String,
 336  
      *            String&gt;} or a {@link Cookie Cookie[]}. It can be null.
 337  
      * @param event this one is used only if the cookies are stored in a {@link Map}
 338  
      *            in order to resolve expressions with the {@link ExpressionManager}.
 339  
      * @param destinationUri the host, port and path of this {@link URI} will be used
 340  
      *            as the data of the cookies that are added.
 341  
      */
 342  
     public static void addCookiesToClient(HttpClient client,
 343  
                                           Object cookiesObject,
 344  
                                              String policy,
 345  
                                              MuleEvent event,
 346  
                                              URI destinationUri)
 347  
     {
 348  0
         CookieStorageType.resolveCookieStorageType(cookiesObject).addCookiesToClient(client, cookiesObject,
 349  
             policy, event, destinationUri);
 350  0
     }
 351  
 
 352  
     /**
 353  
      * <p>
 354  
      * This method merges a new Cookie (or override the previous one if it exists) to
 355  
      * the preExistentCookies. The result (the old cookies with the new one added) is
 356  
      * returned. If a cookie with the same name already exists, then it will be
 357  
      * overridden.
 358  
      * </p>
 359  
      * <p>
 360  
      * It is <b>important</b> that you use the returned value of this method because
 361  
      * for some implementations of preExistentCookies it is not possible to add new
 362  
      * Cookies (for example, on Cookie[]).
 363  
      * </p>
 364  
      *
 365  
      * @param preExistentCookies this must be either a
 366  
      *            <code>java.util.Map&lt;String, String&gt;</code> or a
 367  
      *            <code>Cookie[]</code>. It can be null.
 368  
      * @param cookieName the new cookie name to be added.
 369  
      * @param cookieValue the new cookie value to be added.
 370  
      */
 371  
     public static Object putAndMergeCookie(Object preExistentCookies, String cookieName, String cookieValue)
 372  
     {
 373  0
         return CookieStorageType.resolveCookieStorageType(preExistentCookies).putAndMergeCookie(
 374  
             preExistentCookies, cookieName, cookieValue);
 375  
     }
 376  
 
 377  
     /**
 378  
      * <p>
 379  
      * Merges all the Cookies in newCookiesArray with the preExistentCookies, adding
 380  
      * the new ones and overwriting the existing ones (existing means same cookie
 381  
      * name).
 382  
      * </p>
 383  
      * <p>
 384  
      * It is <b>important</b> that you use the returned value of this method because
 385  
      * for some implementations of preExistentCookies it is not possible to add new
 386  
      * Cookies (for example, on Cookie[]).
 387  
      * </p>
 388  
      */
 389  
     public static Object putAndMergeCookie(Object preExistentCookies, Cookie[] newCookiesArray)
 390  
     {
 391  0
         return CookieStorageType.resolveCookieStorageType(preExistentCookies).putAndMergeCookie(
 392  
             preExistentCookies, newCookiesArray);
 393  
     }
 394  
 
 395  
     /**
 396  
      * <p>
 397  
      * Merges all the Cookies in newCookiesMap with the preExistentCookies, adding
 398  
      * the new ones and overwriting the existing ones (existing means same cookie
 399  
      * name).
 400  
      * </p>
 401  
      * <p>
 402  
      * It is <b>important</b> that you use the returned value of this method because
 403  
      * for some implementations of preExistentCookies it is not possible to add new
 404  
      * Cookies (for example, on Cookie[]).
 405  
      * </p>
 406  
      */
 407  
     public static Object putAndMergeCookie(Object preExistentCookies, Map<String, String> newCookiesMap)
 408  
     {
 409  0
         return CookieStorageType.resolveCookieStorageType(preExistentCookies).putAndMergeCookie(
 410  
             preExistentCookies, newCookiesMap);
 411  
     }
 412  
 
 413  
     /**
 414  
      * Searches and return the cookie with the cookieName in the cookiesObject. It
 415  
      * returns <code>null</code> if the cookie is not present.
 416  
      */
 417  
     public static String getCookieValueFromCookies(Object cookiesObject, String cookieName)
 418  
     {
 419  0
         return CookieStorageType.resolveCookieStorageType(cookiesObject).getCookieValueFromCookies(
 420  
             cookiesObject, cookieName);
 421  
     }
 422  
 
 423  
     /**
 424  
      * Returns an array view of the cookiesObject.
 425  
      */
 426  
     public static Cookie[] asArrayOfCookies(Object cookiesObject)
 427  
     {
 428  0
         return CookieStorageType.resolveCookieStorageType(cookiesObject).asArrayOfCookies(cookiesObject);
 429  
     }
 430  
 
 431  
 }
 432  
 
 433  
 /**
 434  
  * This enum type is here to distinguish and handle the two type of cookie storage
 435  
  * that we have. The method
 436  
  * {@link CookieStorageType#resolveCookieStorageType(Object)} allows you to select
 437  
  * the appropriate {@link CookieStorageType} for the cookiesObject that you have.
 438  
  */
 439  0
 enum CookieStorageType
 440  
 {
 441  
     /**
 442  
      * <p>
 443  
      * This corresponds to the storage of cookies as a Cookie[].
 444  
      * </p>
 445  
      * <p>
 446  
      * All the parameters of type {@link Object} in the method of this object are
 447  
      * assumed to be of type Cookie[] and won't be checked. They will be cast to
 448  
      * Cookie[].
 449  
      * </p>
 450  
      */
 451  0
     ARRAY_OF_COOKIES
 452  
     {
 453  
         @Override
 454  
         public Object putAndMergeCookie(Object preExistentCookies, String cookieName, String cookieValue)
 455  
         {
 456  0
             final Cookie[] preExistentCookiesArray = (Cookie[]) preExistentCookies;
 457  
 
 458  0
             final int sessionIndex = getCookieIndexFromCookiesArray(cookieName, preExistentCookiesArray);
 459  
 
 460  
             // domain, path, secure (https) and expiry are handled in method
 461  
             // CookieHelper.addCookiesToClient()
 462  0
             final Cookie newSessionCookie = new Cookie(null, cookieName, cookieValue);
 463  
             final Cookie[] mergedCookiesArray;
 464  0
             if (sessionIndex >= 0)
 465  
             {
 466  0
                 preExistentCookiesArray[sessionIndex] = newSessionCookie;
 467  0
                 mergedCookiesArray = preExistentCookiesArray;
 468  
             }
 469  
             else
 470  
             {
 471  0
                 Cookie[] newSessionCookieArray = new Cookie[]{newSessionCookie};
 472  0
                 mergedCookiesArray = concatenateCookies(preExistentCookiesArray, newSessionCookieArray);
 473  
             }
 474  0
             return mergedCookiesArray;
 475  
         }
 476  
 
 477  
         protected Cookie[] concatenateCookies(Cookie[] cookies1, Cookie[] cookies2)
 478  
         {
 479  0
             if (cookies1 == null)
 480  
             {
 481  0
                 return cookies2;
 482  
             }
 483  0
             else if (cookies2 == null)
 484  
             {
 485  0
                 return null;
 486  
             }
 487  
             else
 488  
             {
 489  0
                 Cookie[] mergedCookies = new Cookie[cookies1.length + cookies2.length];
 490  0
                 System.arraycopy(cookies1, 0, mergedCookies, 0, cookies1.length);
 491  0
                 System.arraycopy(cookies2, 0, mergedCookies, cookies1.length, cookies2.length);
 492  0
                 return mergedCookies;
 493  
             }
 494  
         }
 495  
 
 496  
         protected int getCookieIndexFromCookiesArray(String cookieName, Cookie[] preExistentCookies)
 497  
         {
 498  0
             if (preExistentCookies != null && cookieName != null)
 499  
             {
 500  0
                 for (int i = 0; i < preExistentCookies.length; i++)
 501  
                 {
 502  0
                     if (cookieName.equals(preExistentCookies[i].getName()))
 503  
                     {
 504  0
                         return i;
 505  
                     }
 506  
                 }
 507  
             }
 508  0
             return -1;
 509  
         }
 510  
 
 511  
         @Override
 512  
         public String getCookieValueFromCookies(Object cookiesObject, String cookieName)
 513  
         {
 514  0
             Cookie[] cookies = (Cookie[]) cookiesObject;
 515  
 
 516  0
             int sessionIndex = getCookieIndexFromCookiesArray(cookieName, cookies);
 517  0
             if (sessionIndex >= 0)
 518  
             {
 519  0
                 return cookies[sessionIndex].getValue();
 520  
             }
 521  
             else
 522  
             {
 523  0
                 return null;
 524  
             }
 525  
         }
 526  
 
 527  
         @Override
 528  
         public void addCookiesToClient(HttpClient client,
 529  
                                        Object cookiesObject,
 530  
                                        String policy,
 531  
                                        MuleEvent event,
 532  
                                        URI destinationUri)
 533  
         {
 534  0
             Cookie[] cookies = (Cookie[]) cookiesObject;
 535  
 
 536  0
             if (cookies != null && cookies.length > 0)
 537  
             {
 538  0
                 String host = destinationUri.getHost();
 539  0
                 String path = destinationUri.getPath();
 540  0
                 for (Cookie cookie : cookies)
 541  
                 {
 542  0
                     client.getState().addCookie(
 543  
                         new Cookie(host, cookie.getName(), cookie.getValue(), path, cookie.getExpiryDate(),
 544  
                             cookie.getSecure()));
 545  
                 }
 546  0
                 client.getParams().setCookiePolicy(CookieHelper.getCookiePolicy(policy));
 547  
             }
 548  0
         }
 549  
 
 550  
         @Override
 551  
         public Object putAndMergeCookie(Object preExistentCookies, Cookie[] newCookiesArray)
 552  
         {
 553  0
             if (newCookiesArray == null)
 554  
             {
 555  0
                 return preExistentCookies;
 556  
             }
 557  0
             final List<Cookie> cookiesThatAreReallyNew = new ArrayList<Cookie>(newCookiesArray.length);
 558  0
             final Cookie[] preExistentCookiesArray = (Cookie[]) preExistentCookies;
 559  0
             for (Cookie newCookie : newCookiesArray)
 560  
             {
 561  0
                 int newCookieInPreExistentArrayIndex = getCookieIndexFromCookiesArray(newCookie.getName(),
 562  
                     preExistentCookiesArray);
 563  0
                 if (newCookieInPreExistentArrayIndex >= 0)
 564  
                 {
 565  
                     // overwrite the old one
 566  0
                     preExistentCookiesArray[newCookieInPreExistentArrayIndex] = newCookie;
 567  
                 }
 568  
                 else
 569  
                 {
 570  
                     // needs to add it at the end
 571  0
                     cookiesThatAreReallyNew.add(newCookie);
 572  
                 }
 573  
             }
 574  
 
 575  0
             return concatenateCookies(preExistentCookiesArray,
 576  
                 cookiesThatAreReallyNew.toArray(new Cookie[cookiesThatAreReallyNew.size()]));
 577  
         }
 578  
 
 579  
         @Override
 580  
         public Object putAndMergeCookie(Object preExistentCookies, Map<String, String> newCookiesMap)
 581  
         {
 582  0
             if (newCookiesMap == null)
 583  
             {
 584  0
                 return putAndMergeCookie(preExistentCookies, (Cookie[]) null);
 585  
             }
 586  
             else
 587  
             {
 588  0
                 Cookie[] cookiesArray = new Cookie[newCookiesMap.size()];
 589  0
                 int i = 0;
 590  0
                 for (Entry<String, String> cookieEntry : newCookiesMap.entrySet())
 591  
                 {
 592  0
                     Cookie cookie = new Cookie();
 593  0
                     cookie.setName(cookieEntry.getKey());
 594  0
                     cookie.setValue(cookieEntry.getValue());
 595  0
                     cookiesArray[i++] = cookie;
 596  0
                 }
 597  0
                 return putAndMergeCookie(preExistentCookies, cookiesArray);
 598  
             }
 599  
         }
 600  
 
 601  
         @Override
 602  
         public Cookie[] asArrayOfCookies(Object cookiesObject)
 603  
         {
 604  0
             if (cookiesObject == null)
 605  
             {
 606  0
                 return ZERO_COOKIES;
 607  
             }
 608  
             else
 609  
             {
 610  0
                 return (Cookie[]) cookiesObject;
 611  
             }
 612  
         }
 613  
 
 614  
     },
 615  
 
 616  
     /**
 617  
      * <p>
 618  
      * This corresponds to the storage of cookies as {@link Map<String, String>},
 619  
      * where the keys are the cookie names and the values are the cookie values.
 620  
      * </p>
 621  
      * <p>
 622  
      * All the parameters of type {@link Object} in the method of this object are
 623  
      * assumed to be of type {@link Map<String, String>} and won't be checked. They
 624  
      * will be cast to {@link Map} and used as if all the keys and values are of type
 625  
      * {@link String}.
 626  
      */
 627  0
     MAP_STRING_STRING
 628  
     {
 629  
         @Override
 630  
         @SuppressWarnings("unchecked")
 631  
         public Object putAndMergeCookie(Object preExistentCookies, String cookieName, String cookieValue)
 632  
         {
 633  0
             final Map<String, String> cookieMap = (Map<String, String>) preExistentCookies;
 634  
 
 635  0
             cookieMap.put(cookieName, cookieValue);
 636  0
             return cookieMap;
 637  
         }
 638  
 
 639  
         @Override
 640  
         @SuppressWarnings("unchecked")
 641  
         public String getCookieValueFromCookies(Object cookiesObject, String cookieName)
 642  
         {
 643  0
             return ((Map<String, String>) cookiesObject).get(cookieName);
 644  
         }
 645  
 
 646  
         @Override
 647  
         @SuppressWarnings("unchecked")
 648  
         public void addCookiesToClient(HttpClient client,
 649  
                                        Object cookiesObject,
 650  
                                        String policy,
 651  
                                        MuleEvent event,
 652  
                                        URI destinationUri)
 653  
         {
 654  0
             Map<String, String> cookieMap = (Map<String, String>) cookiesObject;
 655  
 
 656  0
             client.getParams().setCookiePolicy(CookieHelper.getCookiePolicy(policy));
 657  
 
 658  0
             String host = destinationUri.getHost();
 659  0
             String path = destinationUri.getPath();
 660  0
             Iterator<String> keyIter = cookieMap.keySet().iterator();
 661  0
             while (keyIter.hasNext())
 662  
             {
 663  0
                 String key = keyIter.next();
 664  0
                 String cookieValue = cookieMap.get(key);
 665  
 
 666  
                 final String value;
 667  0
                 if (event != null)
 668  
                 {
 669  0
                     value = event.getMuleContext()
 670  
                         .getExpressionManager()
 671  
                         .parse(cookieValue, event.getMessage());
 672  
                 }
 673  
                 else
 674  
                 {
 675  0
                     value = cookieValue;
 676  
                 }
 677  
 
 678  0
                 Cookie cookie = new Cookie(host, key, value, path, null, false);
 679  0
                 client.getState().addCookie(cookie);
 680  0
             }
 681  
 
 682  0
         }
 683  
 
 684  
         @Override
 685  
         public Object putAndMergeCookie(Object preExistentCookies, Cookie[] newCookiesArray)
 686  
         {
 687  0
             if (newCookiesArray == null)
 688  
             {
 689  0
                 return preExistentCookies;
 690  
             }
 691  0
             for (Cookie cookie : newCookiesArray)
 692  
             {
 693  0
                 preExistentCookies = putAndMergeCookie(preExistentCookies, cookie.getName(),
 694  
                     cookie.getValue());
 695  
             }
 696  0
             return preExistentCookies;
 697  
         }
 698  
 
 699  
         @Override
 700  
         public Object putAndMergeCookie(Object preExistentCookies, Map<String, String> newCookiesMap)
 701  
         {
 702  0
             if (newCookiesMap == null)
 703  
             {
 704  0
                 return preExistentCookies;
 705  
             }
 706  0
             for (Entry<String, String> cookieEntry : newCookiesMap.entrySet())
 707  
             {
 708  0
                 preExistentCookies = putAndMergeCookie(preExistentCookies, cookieEntry.getKey(),
 709  
                     cookieEntry.getValue());
 710  
             }
 711  0
             return preExistentCookies;
 712  
         }
 713  
 
 714  
         @Override
 715  
         @SuppressWarnings("unchecked")
 716  
         public Cookie[] asArrayOfCookies(Object cookiesObject)
 717  
         {
 718  0
             Map<String, String> cookieMap = (Map<String, String>) cookiesObject;
 719  0
             Cookie[] arrayOfCookies = new Cookie[cookieMap.size()];
 720  0
             int i = 0;
 721  0
             for (Entry<String, String> cookieEntry : cookieMap.entrySet())
 722  
             {
 723  0
                 Cookie cookie = new Cookie();
 724  0
                 cookie.setName(cookieEntry.getKey());
 725  0
                 cookie.setValue(cookieEntry.getValue());
 726  0
                 arrayOfCookies[i++] = cookie;
 727  0
             }
 728  0
             return arrayOfCookies;
 729  
         }
 730  
 
 731  
     };
 732  
 
 733  0
     private static final Cookie[] ZERO_COOKIES = new Cookie[0];
 734  
 
 735  
     /**
 736  
      * Resolves the cookiesObject to the appropriate {@link CookieStorageType}.
 737  
      *
 738  
      * @param cookiesObject
 739  
      * @return
 740  
      */
 741  
     public static CookieStorageType resolveCookieStorageType(Object cookiesObject)
 742  
     {
 743  0
         if (cookiesObject == null || cookiesObject instanceof Cookie[])
 744  
         {
 745  0
             return CookieStorageType.ARRAY_OF_COOKIES;
 746  
         }
 747  0
         else if (cookiesObject instanceof Map)
 748  
         {
 749  0
             return CookieStorageType.MAP_STRING_STRING;
 750  
         }
 751  
         else
 752  
         {
 753  0
             throw new IllegalArgumentException("Invalid cookiesObject. Only " + Cookie.class + "[] and "
 754  
                                                + Map.class + " are supported: " + cookiesObject);
 755  
         }
 756  
     }
 757  
 
 758  
     /**
 759  
      * @see CookieHelper#putAndMergeCookie(Object, String, String)
 760  
      */
 761  
     public abstract Object putAndMergeCookie(Object preExistentCookies, String cookieName, String cookieValue);
 762  
 
 763  
     /**
 764  
      * @see CookieHelper#putAndMergeCookie(Object, Cookie[])
 765  
      */
 766  
     public abstract Object putAndMergeCookie(Object preExistentCookies, Cookie[] newCookiesArray);
 767  
 
 768  
     /**
 769  
      * @see CookieHelper#putAndMergeCookie(Object, Map)
 770  
      */
 771  
     public abstract Object putAndMergeCookie(Object preExistentCookies, Map<String, String> newCookiesMap);
 772  
 
 773  
     /**
 774  
      * @see CookieHelper#getCookieValueFromCookies(Object, String)
 775  
      */
 776  
     public abstract String getCookieValueFromCookies(Object cookiesObject, String cookieName);
 777  
 
 778  
     /**
 779  
      * @see CookieHelper#addCookiesToClient(HttpClient, Object, String, MuleEvent,
 780  
      *      URI)
 781  
      */
 782  
     public abstract void addCookiesToClient(HttpClient client,
 783  
                                             Object cookiesObject,
 784  
                                             String policy,
 785  
                                             MuleEvent event,
 786  
                                             URI destinationUri);
 787  
 
 788  
     /**
 789  
      * @see CookieHelper#asArrayOfCookies(Object)
 790  
      */
 791  
     public abstract Cookie[] asArrayOfCookies(Object cookiesObject);
 792  
 }