You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fm...@apache.org on 2011/07/18 23:20:52 UTC

svn commit: r1148054 - in /chemistry/opencmis/trunk: chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/impl/ chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/ja...

Author: fmui
Date: Mon Jul 18 21:20:50 2011
New Revision: 1148054

URL: http://svn.apache.org/viewvc?rev=1148054&view=rev
Log:
CMIS-366: added cookie support
standard authentication provider clean up

Added:
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisCookieManager.java   (with props)
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisCookieStoreImpl.java   (with props)
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisHttpCookie.java   (with props)
Removed:
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/CookieAwareStandardAuthenticationProvider.java-6
Modified:
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/impl/CmisBindingImpl.java
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/StandardAuthenticationProvider.java
    chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java
    chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/LoginDialog.java
    chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/model/ClientSession.java

Modified: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/impl/CmisBindingImpl.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/impl/CmisBindingImpl.java?rev=1148054&r1=1148053&r2=1148054&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/impl/CmisBindingImpl.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/impl/CmisBindingImpl.java Mon Jul 18 21:20:50 2011
@@ -85,12 +85,12 @@ public class CmisBindingImpl implements 
 
         if (authenticationProvider == null) {
             // create authentication provider and add it session
-            String authProvider = sessionParameters.get(SessionParameter.AUTHENTICATION_PROVIDER_CLASS);
-            if (authProvider != null) {
+            String authProviderClassName = sessionParameters.get(SessionParameter.AUTHENTICATION_PROVIDER_CLASS);
+            if (authProviderClassName != null) {
                 Object authProviderObj = null;
 
                 try {
-                    authProviderObj = Class.forName(authProvider).newInstance();
+                    authProviderObj = Class.forName(authProviderClassName).newInstance();
                 } catch (Exception e) {
                     throw new IllegalArgumentException("Could not load authentication provider: " + e, e);
                 }
@@ -99,20 +99,8 @@ public class CmisBindingImpl implements 
                     throw new IllegalArgumentException(
                             "Authentication provider does not implement AuthenticationProvider!");
                 }
-
-                session.put(CmisBindingsHelper.AUTHENTICATION_PROVIDER_OBJECT, (AuthenticationProvider) authProviderObj);
-
-                if (authProviderObj instanceof SessionAwareAuthenticationProvider) {
-                    ((SessionAwareAuthenticationProvider) authProviderObj).setSession(session);
-                }
-            }
-        } else {
-            session.put(CmisBindingsHelper.AUTHENTICATION_PROVIDER_OBJECT, authenticationProvider);
-
-            if (authenticationProvider instanceof SessionAwareAuthenticationProvider) {
-                ((SessionAwareAuthenticationProvider) authenticationProvider).setSession(session);
+                authenticationProvider = (AuthenticationProvider) authProviderObj;
             }
-
         }
 
         // locale
@@ -148,6 +136,14 @@ public class CmisBindingImpl implements 
 
         // set up repository service
         repositoryServiceWrapper = new RepositoryServiceImpl(session);
+
+        // add authentication provider to session
+        if (authenticationProvider != null) {
+            session.put(CmisBindingsHelper.AUTHENTICATION_PROVIDER_OBJECT, authenticationProvider);
+            if (authenticationProvider instanceof SessionAwareAuthenticationProvider) {
+                ((SessionAwareAuthenticationProvider) authenticationProvider).setSession(session);
+            }
+        }
     }
 
     public RepositoryService getRepositoryService() {

Modified: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/StandardAuthenticationProvider.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/StandardAuthenticationProvider.java?rev=1148054&r1=1148053&r2=1148054&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/StandardAuthenticationProvider.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/StandardAuthenticationProvider.java Mon Jul 18 21:20:50 2011
@@ -29,8 +29,9 @@ import java.util.TimeZone;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
+import org.apache.chemistry.opencmis.client.bindings.spi.cookies.CmisCookieManager;
 import org.apache.chemistry.opencmis.commons.SessionParameter;
-import org.apache.commons.codec.binary.Base64;
+import org.apache.chemistry.opencmis.commons.impl.Base64;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -47,53 +48,52 @@ public class StandardAuthenticationProvi
     private static final String WSSE_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
     private static final String WSU_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
 
+    private boolean sendBasicAuth;
+    private boolean sendUsernameToken;
+    private CmisCookieManager cookieManager;
+
     @Override
-    public Map<String, List<String>> getHTTPHeaders(String url) {
-        Map<String, List<String>> result = null;
+    public void setSession(BindingSession session) {
+        super.setSession(session);
 
-        // only send HTTP header if configured
-        if (!isTrue(SessionParameter.AUTH_HTTP_BASIC)) {
-            return null;
-        }
+        sendBasicAuth = isTrue(SessionParameter.AUTH_HTTP_BASIC);
+        sendUsernameToken = isTrue(SessionParameter.AUTH_SOAP_USERNAMETOKEN);
 
-        result = new HashMap<String, List<String>>();
+        if (isTrue(SessionParameter.COOKIES)) {
+            cookieManager = new CmisCookieManager();
+        }
+    }
 
-        // get user and password
-        String user = getUser();
-        String password = getPassword();
+    @Override
+    public Map<String, List<String>> getHTTPHeaders(String url) {
+        Map<String, List<String>> result = new HashMap<String, List<String>>();
 
-        // if no user is set, don't set HTTP header
-        if (user != null) {
-            if (password == null) {
-                password = "";
+        // authentication
+        if (sendBasicAuth) {
+            // get user and password
+            String user = getUser();
+            String password = getPassword();
+
+            // if no user is set, don't set basic auth header
+            if (user != null) {
+                result.put("Authorization", createBasicAuthHeaderValue(user, password));
             }
 
-            try {
-                String authHeader = "Basic "
-                        + new String(Base64.encodeBase64((user + ":" + password).getBytes("ISO-8859-1")), "ISO-8859-1");
-                result.put("Authorization", Collections.singletonList(authHeader));
-            } catch (UnsupportedEncodingException e) {
-                // shouldn't happen...
+            // get proxy user and password
+            String proxyUser = getProxyUser();
+            String proxyPassword = getProxyPassword();
+
+            // if no proxy user is set, don't set basic auth header
+            if (proxyUser != null) {
+                result.put("Proxy-Authorization", createBasicAuthHeaderValue(proxyUser, proxyPassword));
             }
         }
 
-        // get proxy user and password
-        String proxyUser = getProxyUser();
-        String proxyPassword = getProxyPassword();
-
-        // if no proxy user is set, don't set HTTP header
-        if (proxyUser != null) {
-            if (proxyPassword == null) {
-                proxyPassword = "";
-            }
-
-            try {
-                String authHeader = "Basic "
-                        + new String(Base64.encodeBase64((proxyUser + ":" + proxyPassword).getBytes("ISO-8859-1")),
-                                "ISO-8859-1");
-                result.put("Proxy-Authorization", Collections.singletonList(authHeader));
-            } catch (UnsupportedEncodingException e) {
-                // shouldn't happen...
+        // cookies
+        if (cookieManager != null) {
+            Map<String, List<String>> cookies = cookieManager.get(url, result);
+            if (!cookies.isEmpty()) {
+                result.putAll(cookies);
             }
         }
 
@@ -101,16 +101,23 @@ public class StandardAuthenticationProvi
     }
 
     @Override
-    public Element getSOAPHeaders(Object portObject) {
-        // get user and password
-        String user = getUser();
-        String password = getPassword();
+    public void putResponseHeaders(String url, int statusCode, Map<String, List<String>> headers) {
+        if (cookieManager != null) {
+            cookieManager.put(url, headers);
+        }
+    }
 
+    @Override
+    public Element getSOAPHeaders(Object portObject) {
         // only send SOAP header if configured
-        if (!isTrue(SessionParameter.AUTH_SOAP_USERNAMETOKEN)) {
+        if (!sendUsernameToken) {
             return null;
         }
 
+        // get user and password
+        String user = getUser();
+        String password = getPassword();
+
         // if no user is set, don't create SOAP header
         if (user == null) {
             return null;
@@ -170,10 +177,28 @@ public class StandardAuthenticationProvi
     }
 
     /**
+     * Creates a basic authentication header value from a username and a
+     * password.
+     */
+    protected List<String> createBasicAuthHeaderValue(String username, String password) {
+        if (password == null) {
+            password = "";
+        }
+
+        try {
+            return Collections.singletonList("Basic "
+                    + Base64.encodeBytes((username + ":" + password).getBytes("ISO-8859-1")));
+        } catch (UnsupportedEncodingException e) {
+            // shouldn't happen...
+            return Collections.emptyList();
+        }
+    }
+
+    /**
      * Returns <code>true</code> if the given parameter exists in the session
      * and is set to true, <code>false</code> otherwise.
      */
-    private boolean isTrue(String parameterName) {
+    protected boolean isTrue(String parameterName) {
         Object value = getSession().get(parameterName);
 
         if (value instanceof Boolean) {

Added: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisCookieManager.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisCookieManager.java?rev=1148054&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisCookieManager.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisCookieManager.java Mon Jul 18 21:20:50 2011
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * This class has been taken from Apache Harmony (http://harmony.apache.org/) 
+ * and has been modified to work with OpenCMIS.
+ */
+package org.apache.chemistry.opencmis.client.bindings.spi.cookies;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
+
+/**
+ * Cookie Manager.
+ * 
+ * This implementation conforms to RFC 2965, section 3.3.
+ */
+public class CmisCookieManager implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private static final String VERSION_ZERO_HEADER = "Set-cookie";
+    private static final String VERSION_ONE_HEADER = "Set-cookie2";
+
+    private final CmisCookieStoreImpl store;
+    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+    /**
+     * Constructs a new cookie manager.
+     */
+    public CmisCookieManager() {
+        store = new CmisCookieStoreImpl();
+    }
+
+    /**
+     * Searchs and gets all cookies in the cache by the specified uri in the
+     * request header.
+     * 
+     * @param uri
+     *            the specified uri to search for
+     * @param requestHeaders
+     *            a list of request headers
+     * @return a map that record all such cookies, the map is unchangeable
+     */
+    public Map<String, List<String>> get(String url, Map<String, List<String>> requestHeaders) {
+        if (url == null || requestHeaders == null) {
+            throw new IllegalArgumentException("URL or headers are null!");
+        }
+
+        URI uri;
+        try {
+            uri = new URI(url);
+        } catch (URISyntaxException e) {
+            throw new CmisConnectionException(e.getMessage(), e);
+        }
+
+        lock.writeLock().lock();
+        try {
+            List<CmisHttpCookie> cookies = store.get(uri);
+            for (int i = 0; i < cookies.size(); i++) {
+                CmisHttpCookie cookie = cookies.get(i);
+                String uriPath = uri.getPath();
+                String cookiePath = cookie.getPath();
+                // if the uri's path does not path-match cookie's path, remove
+                // cookies from the list
+                if (cookiePath == null || uriPath.length() == 0 || !uriPath.startsWith(cookiePath)) {
+                    cookies.remove(i);
+                }
+            }
+
+            return getCookieMap(cookies, requestHeaders);
+        } finally {
+            lock.writeLock().unlock();
+        }
+    }
+
+    private static Map<String, List<String>> getCookieMap(List<CmisHttpCookie> cookies,
+            Map<String, List<String>> requestHeaders) {
+        HashMap<String, List<String>> map = new HashMap<String, List<String>>();
+        ArrayList<String> cookieStr = new ArrayList<String>();
+        // If all cookies are version 1, add a "$Version="1"" header
+        boolean versionOne = true;
+        for (CmisHttpCookie cookie : cookies) {
+            if (cookie.getVersion() == 0) {
+                versionOne = false;
+                break;
+            }
+        }
+        if (versionOne && !cookies.isEmpty()) {
+            cookieStr.add("$Version=\"1\"");
+        }
+        // add every cookie's string representation into map
+        for (CmisHttpCookie cookie : cookies) {
+            cookieStr.add(cookie.toString());
+        }
+
+        if (cookieStr.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        map.put("Cookie", cookieStr);
+        return map;
+    }
+
+    /**
+     * Sets cookies according to uri and responseHeaders
+     * 
+     * @param uri
+     *            the specified uri
+     * @param responseHeaders
+     *            a list of request headers
+     * @throws IOException
+     *             if some error of I/O operation occurs
+     */
+    public void put(String url, Map<String, List<String>> responseHeaders) {
+        if (url == null || responseHeaders == null) {
+            throw new IllegalArgumentException("URL or headers are null!");
+        }
+
+        URI uri;
+        try {
+            uri = new URI(url);
+        } catch (URISyntaxException e) {
+            throw new CmisConnectionException(e.getMessage(), e);
+        }
+
+        lock.writeLock().lock();
+        try {
+            // parse and construct cookies according to the map
+            List<CmisHttpCookie> cookies = parseCookie(responseHeaders);
+            for (CmisHttpCookie cookie : cookies) {
+                if (cookie.getDomain() == null) {
+                    cookie.setDomain(uri.getHost());
+                }
+                if (cookie.getPath() == null) {
+                    cookie.setPath("/");
+                }
+                store.add(uri, cookie);
+            }
+        } finally {
+            lock.writeLock().unlock();
+        }
+    }
+
+    private static List<CmisHttpCookie> parseCookie(Map<String, List<String>> responseHeaders) {
+        List<CmisHttpCookie> cookies = new ArrayList<CmisHttpCookie>();
+        for (Map.Entry<String, List<String>> entry : responseHeaders.entrySet()) {
+            String key = entry.getKey();
+            // Only "Set-cookie" and "Set-cookie2" pair will be parsed
+            if (key != null && (key.equalsIgnoreCase(VERSION_ZERO_HEADER) || key.equalsIgnoreCase(VERSION_ONE_HEADER))) {
+                // parse list elements one by one
+                for (String cookieStr : entry.getValue()) {
+                    try {
+                        for (CmisHttpCookie cookie : CmisHttpCookie.parse(cookieStr)) {
+                            cookies.add(cookie);
+                        }
+                    } catch (IllegalArgumentException e) {
+                        // this string is invalid, jump to the next one.
+                    }
+                }
+            }
+        }
+
+        return cookies;
+    }
+
+    /**
+     * Gets current cookie store.
+     * 
+     * @return the cookie store currently used by cookie manager.
+     */
+    public CmisCookieStoreImpl getCookieStore() {
+        return store;
+    }
+}

Propchange: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisCookieManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisCookieStoreImpl.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisCookieStoreImpl.java?rev=1148054&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisCookieStoreImpl.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisCookieStoreImpl.java Mon Jul 18 21:20:50 2011
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * This class has been taken from Apache Harmony (http://harmony.apache.org/) 
+ * and has been modified to work with OpenCMIS.
+ */
+package org.apache.chemistry.opencmis.client.bindings.spi.cookies;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Provides an in-memory cookie store.
+ */
+class CmisCookieStoreImpl implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Map<URI, ArrayList<CmisHttpCookie>> storeMap = new HashMap<URI, ArrayList<CmisHttpCookie>>();
+
+    public void add(URI uri, CmisHttpCookie cookie) {
+        if (uri == null || cookie == null) {
+            throw new NullPointerException();
+        }
+
+        ArrayList<CmisHttpCookie> cookies;
+        if (storeMap.containsKey(uri)) {
+            cookies = storeMap.get(uri);
+            cookies.remove(cookie);
+            cookies.add(cookie);
+        } else {
+            cookies = new ArrayList<CmisHttpCookie>();
+            cookies.add(cookie);
+            storeMap.put(uri, cookies);
+        }
+    }
+
+    public List<CmisHttpCookie> get(URI uri) {
+        if (uri == null) {
+            throw new NullPointerException("URI is null!");
+        }
+
+        // get cookies associated with given URI. If none, returns an empty list
+        List<CmisHttpCookie> cookies = storeMap.get(uri);
+        if (cookies == null) {
+            cookies = new ArrayList<CmisHttpCookie>();
+        } else {
+            // eliminate expired cookies
+            for (CmisHttpCookie cookie : cookies) {
+                if (cookie.hasExpired()) {
+                    cookies.remove(cookie);
+                }
+            }
+        }
+
+        // get cookies whose domain matches the given URI
+        Set<URI> uris = storeMap.keySet();
+        for (URI u : uris) {
+            // exclude the given URI
+            if (!u.equals(uri)) {
+                List<CmisHttpCookie> listCookie = storeMap.get(u);
+                for (CmisHttpCookie cookie : listCookie) {
+                    if (CmisHttpCookie.domainMatches(cookie.getDomain(), uri.getHost())) {
+                        if (cookie.hasExpired()) {
+                            listCookie.remove(cookie);
+                        } else if (!(cookie.hasExpired() || cookies.contains(cookie))) {
+                            cookies.add(cookie);
+                        }
+                    }
+                }
+            }
+        }
+
+        return cookies;
+    }
+
+    public List<CmisHttpCookie> getCookies() {
+        List<CmisHttpCookie> cookies = new ArrayList<CmisHttpCookie>();
+        Collection<ArrayList<CmisHttpCookie>> values = storeMap.values();
+        for (ArrayList<CmisHttpCookie> list : values) {
+            for (CmisHttpCookie cookie : list) {
+                if (cookie.hasExpired()) {
+                    list.remove(cookie); // eliminate expired cookies
+                } else if (!cookies.contains(cookie)) {
+                    cookies.add(cookie);
+                }
+            }
+        }
+
+        return Collections.unmodifiableList(cookies);
+    }
+
+    public List<URI> getURIs() {
+        return new ArrayList<URI>(storeMap.keySet());
+    }
+
+    public boolean remove(URI uri, CmisHttpCookie cookie) {
+        if (cookie == null) {
+            throw new NullPointerException("Cookie is null!");
+        }
+
+        boolean success = false;
+        Collection<ArrayList<CmisHttpCookie>> values = storeMap.values();
+        for (ArrayList<CmisHttpCookie> list : values) {
+            if (list.remove(cookie)) {
+                success = true;
+            }
+        }
+
+        return success;
+    }
+
+    public boolean removeAll() {
+        if (!storeMap.isEmpty()) {
+            storeMap.clear();
+        }
+
+        return true;
+    }
+}

Propchange: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisCookieStoreImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisHttpCookie.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisHttpCookie.java?rev=1148054&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisHttpCookie.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisHttpCookie.java Mon Jul 18 21:20:50 2011
@@ -0,0 +1,790 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * This class has been taken from Apache Harmony (http://harmony.apache.org/) 
+ * and has been modified to work with OpenCMIS.
+ */
+package org.apache.chemistry.opencmis.client.bindings.spi.cookies;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class represents a http cookie, which indicates the status information
+ * between the client agent side and the server side. According to RFC, there
+ * are 3 http cookie specifications. This class is compatible with all the three
+ * forms. HttpCookie class can accept all these 3 forms of syntax.
+ */
+public final class CmisHttpCookie implements Cloneable, Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String DOT_STR = ".";
+    private static final String LOCAL_STR = ".local";
+    private static final String QUOTE_STR = "\"";
+    private static final String COMMA_STR = ",";
+    private static Pattern HEAD_PATTERN = Pattern.compile("Set-Cookie2?:", Pattern.CASE_INSENSITIVE);
+    private static Pattern NAME_PATTERN = Pattern.compile(
+            "([^$=,\u0085\u2028\u2029][^,\n\t\r\r\n\u0085\u2028\u2029]*?)=([^;]*)(;)?", Pattern.DOTALL
+                    | Pattern.CASE_INSENSITIVE);
+    private static Pattern ATTR_PATTERN0 = Pattern.compile("([^;=]*)(?:=([^;]*))?");
+    private static Pattern ATTR_PATTERN1 = Pattern.compile("(,?[^;=]*)(?:=([^;,]*))?((?=.))?");
+
+    private abstract static class Setter {
+        boolean set;
+
+        Setter() {
+            set = false;
+        }
+
+        boolean isSet() {
+            return set;
+        }
+
+        void set(boolean isSet) {
+            set = isSet;
+        }
+
+        abstract void setValue(String value, CmisHttpCookie cookie);
+
+        void validate(String value, CmisHttpCookie cookie) {
+            if (cookie.getVersion() == 1 && value != null && value.contains(COMMA_STR)) {
+                throw new IllegalArgumentException();
+            }
+        }
+    }
+
+    private HashMap<String, Setter> attributeSet = new HashMap<String, Setter>();
+
+    /**
+     * A utility method used to check whether the host name is in a domain or
+     * not.
+     * 
+     * @param domain
+     *            the domain to be checked against
+     * @param host
+     *            the host to be checked
+     * @return true if the host is in the domain, false otherwise
+     */
+    public static boolean domainMatches(String domain, String host) {
+        if (domain == null || host == null) {
+            return false;
+        }
+        String newDomain = domain.toLowerCase();
+        String newHost = host.toLowerCase();
+        return isValidDomain(newDomain) && effDomainMatches(newDomain, newHost) && isValidHost(newDomain, newHost);
+    }
+
+    private static boolean effDomainMatches(String domain, String host) {
+        // calculate effective host name
+        String effHost = host.indexOf(DOT_STR) != -1 ? host : (host + LOCAL_STR);
+
+        // Rule 2: domain and host are string-compare equal, or A = NB, B = .B'
+        // and N is a non-empty name string
+        boolean inDomain = domain.equals(effHost);
+        inDomain = inDomain
+                || (effHost.endsWith(domain) && effHost.length() > domain.length() && domain.startsWith(DOT_STR));
+
+        return inDomain;
+    }
+
+    private static boolean isCommaDelim(CmisHttpCookie cookie) {
+        String value = cookie.getValue();
+        if (value.startsWith(QUOTE_STR) && value.endsWith(QUOTE_STR)) {
+            cookie.setValue(value.substring(1, value.length() - 1));
+            return false;
+        }
+
+        if (cookie.getVersion() == 1 && value.contains(COMMA_STR)) {
+            cookie.setValue(value.substring(0, value.indexOf(COMMA_STR)));
+            return true;
+        }
+
+        return false;
+    }
+
+    private static boolean isValidDomain(String domain) {
+        // Rule 1: The value for Domain contains embedded dots, or is .local
+        if (domain.length() <= 2) {
+            return false;
+        }
+
+        return domain.substring(1, domain.length() - 1).indexOf(DOT_STR) != -1 || domain.equals(LOCAL_STR);
+    }
+
+    private static boolean isValidHost(String domain, String host) {
+        // Rule 3: host does not end with domain, or the remainder does not
+        // contain "."
+        boolean matches = !host.endsWith(domain);
+        if (!matches) {
+            String hostSub = host.substring(0, host.length() - domain.length());
+            matches = hostSub.indexOf(DOT_STR) == -1;
+        }
+
+        return matches;
+    }
+
+    /**
+     * Constructs a cookie from a string. The string should comply with
+     * set-cookie or set-cookie2 header format as specified in RFC 2965. Since
+     * set-cookies2 syntax allows more than one cookie definitions in one
+     * header, the returned object is a list.
+     * 
+     * @param header
+     *            a set-cookie or set-cookie2 header.
+     * @return a list of constructed cookies
+     * @throws IllegalArgumentException
+     *             if the string does not comply with cookie specification, or
+     *             the cookie name contains illegal characters, or reserved
+     *             tokens of cookie specification appears
+     * @throws NullPointerException
+     *             if header is null
+     */
+    public static List<CmisHttpCookie> parse(String header) {
+        Matcher matcher = HEAD_PATTERN.matcher(header);
+        // Parse cookie name & value
+        List<CmisHttpCookie> list = null;
+        CmisHttpCookie cookie = null;
+        String headerString = header;
+        int version = 0;
+        // process set-cookie | set-cookie2 head
+        if (matcher.find()) {
+            String cookieHead = matcher.group();
+            if ("set-cookie2:".equalsIgnoreCase(cookieHead)) {
+                version = 1;
+            }
+            headerString = header.substring(cookieHead.length());
+        }
+
+        // parse cookie name/value pair
+        matcher = NAME_PATTERN.matcher(headerString);
+        if (matcher.lookingAt()) {
+            list = new ArrayList<CmisHttpCookie>();
+            cookie = new CmisHttpCookie(matcher.group(1), matcher.group(2));
+            cookie.setVersion(version);
+
+            /*
+             * Comma is a delimiter in cookie spec 1.1. If find comma in version
+             * 1 cookie header, part of matched string need to be spitted out.
+             */
+            String nameGroup = matcher.group();
+            if (isCommaDelim(cookie)) {
+                headerString = headerString.substring(nameGroup.indexOf(COMMA_STR));
+            } else {
+                headerString = headerString.substring(nameGroup.length());
+            }
+            list.add(cookie);
+        } else {
+            throw new IllegalArgumentException();
+        }
+
+        // parse cookie headerString
+        while (!(headerString.length() == 0)) {
+            matcher = cookie.getVersion() == 1 ? ATTR_PATTERN1.matcher(headerString) : ATTR_PATTERN0
+                    .matcher(headerString);
+
+            if (matcher.lookingAt()) {
+                String attrName = matcher.group(1).trim();
+
+                // handle special situation like: <..>;;<..>
+                if (attrName.length() == 0) {
+                    headerString = headerString.substring(1);
+                    continue;
+                }
+
+                // If port is the attribute, then comma will not be used as a
+                // delimiter
+                if (attrName.equalsIgnoreCase("port") || attrName.equalsIgnoreCase("expires")) {
+                    int start = matcher.regionStart();
+                    matcher = ATTR_PATTERN0.matcher(headerString);
+                    matcher.region(start, headerString.length());
+                    matcher.lookingAt();
+                } else if (cookie.getVersion() == 1 && attrName.startsWith(COMMA_STR)) {
+                    // If the last encountered token is comma, and the parsed
+                    // attribute is not port, then this attribute/value pair
+                    // ends.
+                    headerString = headerString.substring(1);
+                    matcher = NAME_PATTERN.matcher(headerString);
+                    if (matcher.lookingAt()) {
+                        cookie = new CmisHttpCookie(matcher.group(1), matcher.group(2));
+                        list.add(cookie);
+                        headerString = headerString.substring(matcher.group().length());
+                        continue;
+                    }
+                }
+
+                Setter setter = cookie.attributeSet.get(attrName.toLowerCase());
+                if (null == setter) {
+                    throw new IllegalArgumentException();
+                }
+                if (!setter.isSet()) {
+                    String attrValue = matcher.group(2);
+                    setter.validate(attrValue, cookie);
+                    setter.setValue(matcher.group(2), cookie);
+                }
+                headerString = headerString.substring(matcher.end());
+            }
+        }
+
+        return list;
+    }
+
+    private String comment;
+    private String commentURL;
+    private boolean discard;
+    private String domain;
+    private long maxAge = -1l;
+    private String name;
+    private String path;
+    private String portList;
+    private boolean secure;
+    private String value;
+    private int version = 1;
+
+    {
+        attributeSet.put("comment", new Setter() {
+            @Override
+            void setValue(String value, CmisHttpCookie cookie) {
+                cookie.setComment(value);
+                if (cookie.getComment() != null) {
+                    set(true);
+                }
+            }
+        });
+        attributeSet.put("commenturl", new Setter() {
+            @Override
+            void setValue(String value, CmisHttpCookie cookie) {
+                cookie.setCommentURL(value);
+                if (cookie.getCommentURL() != null) {
+                    set(true);
+                }
+            }
+        });
+        attributeSet.put("discard", new Setter() {
+            @Override
+            void setValue(String value, CmisHttpCookie cookie) {
+                cookie.setDiscard(true);
+                set(true);
+            }
+        });
+        attributeSet.put("domain", new Setter() {
+            @Override
+            void setValue(String value, CmisHttpCookie cookie) {
+                cookie.setDomain(value);
+                if (cookie.getDomain() != null) {
+                    set(true);
+                }
+            }
+        });
+        attributeSet.put("max-age", new Setter() {
+            @Override
+            void setValue(String value, CmisHttpCookie cookie) {
+                try {
+                    cookie.setMaxAge(Long.parseLong(value));
+                } catch (NumberFormatException e) {
+                    throw new IllegalArgumentException("Invalid max-age!");
+                }
+                set(true);
+
+                if (!attributeSet.get("version").isSet()) {
+                    cookie.setVersion(1);
+                }
+            }
+        });
+
+        attributeSet.put("path", new Setter() {
+            @Override
+            void setValue(String value, CmisHttpCookie cookie) {
+                cookie.setPath(value);
+                if (cookie.getPath() != null) {
+                    set(true);
+                }
+            }
+        });
+        attributeSet.put("port", new Setter() {
+            @Override
+            void setValue(String value, CmisHttpCookie cookie) {
+                cookie.setPortlist(value);
+                if (cookie.getPortlist() != null) {
+                    set(true);
+                }
+            }
+
+            @Override
+            void validate(String v, CmisHttpCookie cookie) {
+                return;
+            }
+        });
+        attributeSet.put("secure", new Setter() {
+            @Override
+            void setValue(String value, CmisHttpCookie cookie) {
+                cookie.setSecure(true);
+                set(true);
+            }
+        });
+        attributeSet.put("version", new Setter() {
+            @Override
+            void setValue(String value, CmisHttpCookie cookie) {
+                try {
+                    int v = Integer.parseInt(value);
+                    if (v > cookie.getVersion()) {
+                        cookie.setVersion(v);
+                    }
+                } catch (NumberFormatException e) {
+                    throw new IllegalArgumentException("Invalid version!");
+                }
+                if (cookie.getVersion() != 0) {
+                    set(true);
+                }
+            }
+        });
+
+        attributeSet.put("expires", new Setter() {
+            @Override
+            void setValue(String value, CmisHttpCookie cookie) {
+                cookie.setVersion(0);
+                attributeSet.get("version").set(true);
+                if (!attributeSet.get("max-age").isSet()) {
+                    attributeSet.get("max-age").set(true);
+                    if (!"en".equalsIgnoreCase(Locale.getDefault().getLanguage())) {
+                        cookie.setMaxAge(0);
+                        return;
+                    }
+                    try {
+                        cookie.setMaxAge((Date.parse(value) - System.currentTimeMillis()) / 1000);
+                    } catch (IllegalArgumentException e) {
+                        cookie.setMaxAge(0);
+                    }
+                }
+            }
+
+            @Override
+            void validate(String v, CmisHttpCookie cookie) {
+                return;
+            }
+        });
+    }
+
+    /**
+     * Initializes a cookie with the specified name and value.
+     * 
+     * The name attribute can just contain ASCII characters, which is immutable
+     * after creation. Commas, white space and semicolons are not allowed. The $
+     * character is also not allowed to be the beginning of the name.
+     * 
+     * The value attribute depends on what the server side is interested. The
+     * setValue method can be used to change it.
+     * 
+     * RFC 2965 is the default cookie specification of this class. If one wants
+     * to change the version of the cookie, the setVersion method is available.
+     * 
+     * @param name
+     *            - the specific name of the cookie
+     * @param value
+     *            - the specific value of the cookie
+     * 
+     * @throws IllegalArgumentException
+     *             - if the name contains not-allowed or reserved characters
+     * 
+     * @throws NullPointerException
+     *             if the value of name is null
+     */
+    public CmisHttpCookie(String name, String value) {
+        String ntrim = name.trim(); // erase leading and trailing whitespaces
+        if (!isValidName(ntrim)) {
+            throw new IllegalArgumentException("Invalid name!");
+        }
+
+        this.name = ntrim;
+        this.value = value;
+    }
+
+    private void attrToString(StringBuilder builder, String attrName, String attrValue) {
+        if (attrValue != null && builder != null) {
+            builder.append(";");
+            builder.append("$");
+            builder.append(attrName);
+            builder.append("=\"");
+            builder.append(attrValue);
+            builder.append(QUOTE_STR);
+        }
+    }
+
+    /**
+     * Answers a copy of this object.
+     * 
+     * @return a copy of this cookie
+     */
+    @Override
+    public Object clone() {
+        try {
+            CmisHttpCookie obj = (CmisHttpCookie) super.clone();
+            return obj;
+        } catch (CloneNotSupportedException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Answers whether two cookies are equal. Two cookies are equal if they have
+     * the same domain and name in a case-insensitive mode and path in a
+     * case-sensitive mode.
+     * 
+     * @param obj
+     *            the object to be compared.
+     * @return true if two cookies equals, false otherwise
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof CmisHttpCookie) {
+            CmisHttpCookie anotherCookie = (CmisHttpCookie) obj;
+            if (name.equalsIgnoreCase(anotherCookie.getName())) {
+                String anotherDomain = anotherCookie.getDomain();
+                boolean equals = domain == null ? anotherDomain == null : domain.equalsIgnoreCase(anotherDomain);
+                if (equals) {
+                    String anotherPath = anotherCookie.getPath();
+                    return path == null ? anotherPath == null : path.equals(anotherPath);
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Answers the value of comment attribute(specified in RFC 2965) of this
+     * cookie.
+     * 
+     * @return the value of comment attribute
+     */
+    public String getComment() {
+        return comment;
+    }
+
+    /**
+     * Answers the value of commentURL attribute(specified in RFC 2965) of this
+     * cookie.
+     * 
+     * @return the value of commentURL attribute
+     */
+    public String getCommentURL() {
+        return commentURL;
+    }
+
+    /**
+     * Answers the value of discard attribute(specified in RFC 2965) of this
+     * cookie.
+     * 
+     * @return discard value of this cookie
+     */
+    public boolean getDiscard() {
+        return discard;
+    }
+
+    /**
+     * Answers the domain name for this cookie in the format specified in RFC
+     * 2965
+     * 
+     * @return the domain value of this cookie
+     */
+    public String getDomain() {
+        return domain;
+    }
+
+    /**
+     * Returns the Max-Age value as specified in RFC 2965 of this cookie.
+     * 
+     * @return the Max-Age value
+     */
+    public long getMaxAge() {
+        return maxAge;
+    }
+
+    /**
+     * Answers the name for this cookie.
+     * 
+     * @return the name for this cookie
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Answers the path part of a request URL to which this cookie is returned.
+     * This cookie is visible to all subpaths.
+     * 
+     * @return the path used to return the cookie
+     */
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * Answers the value of port attribute(specified in RFC 2965) of this
+     * cookie.
+     * 
+     * @return port list of this cookie
+     */
+    public String getPortlist() {
+        return portList;
+    }
+
+    /**
+     * Answers true if the browser only sends cookies over a secure protocol.
+     * False if can send cookies through any protocols.
+     * 
+     * @return true if sends cookies only through secure protocol, false
+     *         otherwise
+     */
+    public boolean getSecure() {
+        return secure;
+    }
+
+    /**
+     * Answers the value of this cookie.
+     * 
+     * @return the value of this cookie
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * Get the version of this cookie
+     * 
+     * @return 0 indicates the original Netscape cookie specification, while 1
+     *         indicates RFC 2965/2109 specification.
+     */
+    public int getVersion() {
+        return version;
+    }
+
+    /**
+     * Answers whether the cookie has expired.
+     * 
+     * @return true is the cookie has expired, false otherwise
+     */
+    public boolean hasExpired() {
+        // -1 indicates the cookie will persist until browser shutdown
+        // so the cookie is not expired.
+        if (maxAge == -1l) {
+            return false;
+        }
+
+        boolean expired = false;
+        if (maxAge <= 0l) {
+            expired = true;
+        }
+        return expired;
+    }
+
+    /**
+     * Answers hash code of this http cookie. The result is calculated as below:
+     * 
+     * getName().toLowerCase().hashCode() + getDomain().toLowerCase().hashCode()
+     * + getPath().hashCode()
+     * 
+     * @return the hash code of this cookie
+     */
+    @Override
+    public int hashCode() {
+        int hashCode = name.toLowerCase().hashCode();
+        hashCode += domain == null ? 0 : domain.toLowerCase().hashCode();
+        hashCode += path == null ? 0 : path.hashCode();
+        return hashCode;
+    }
+
+    private boolean isValidName(String n) {
+        // name cannot be empty or begin with '$' or equals the reserved
+        // attributes (case-insensitive)
+        boolean isValid = !(n.length() == 0 || n.startsWith("$") || attributeSet.containsKey(n.toLowerCase()));
+        if (isValid) {
+            for (int i = 0; i < n.length(); i++) {
+                char nameChar = n.charAt(i);
+                // name must be ASCII characters and cannot contain ';', ',' and
+                // whitespace
+                if (nameChar < 0 || nameChar >= 127 || nameChar == ';' || nameChar == ','
+                        || (Character.isWhitespace(nameChar) && nameChar != ' ')) {
+                    isValid = false;
+                    break;
+                }
+            }
+        }
+
+        return isValid;
+    }
+
+    /**
+     * Set the value of comment attribute(specified in RFC 2965) of this cookie.
+     * 
+     * @param purpose
+     *            the comment value to be set
+     */
+    public void setComment(String purpose) {
+        comment = purpose;
+    }
+
+    /**
+     * Set the value of commentURL attribute(specified in RFC 2965) of this
+     * cookie.
+     * 
+     * @param purpose
+     *            the value of commentURL attribute to be set
+     */
+    public void setCommentURL(String purpose) {
+        commentURL = purpose;
+    }
+
+    /**
+     * Set the value of discard attribute(specified in RFC 2965) of this cookie.
+     * 
+     * @param discard
+     *            the value for discard attribute
+     */
+    public void setDiscard(boolean discard) {
+        this.discard = discard;
+    }
+
+    /**
+     * Set the domain value for this cookie. Browsers send the cookie to the
+     * domain specified by this value. The form of the domain is specified in
+     * RFC 2965.
+     * 
+     * @param pattern
+     *            the domain pattern
+     */
+    public void setDomain(String pattern) {
+        domain = pattern == null ? null : pattern.toLowerCase();
+    }
+
+    /**
+     * Sets the Max-Age value as specified in RFC 2965 of this cookie to expire.
+     * 
+     * @param expiry
+     *            the value used to set the Max-Age value of this cookie
+     */
+    public void setMaxAge(long expiry) {
+        maxAge = expiry;
+    }
+
+    /**
+     * Set the path to which this cookie is returned. This cookie is visible to
+     * all the pages under the path and all subpaths.
+     * 
+     * @param path
+     *            the path to which this cookie is returned
+     */
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    /**
+     * Set the value of port attribute(specified in RFC 2965) of this cookie.
+     * 
+     * @param ports
+     *            the value for port attribute
+     */
+    public void setPortlist(String ports) {
+        portList = ports;
+    }
+
+    /*
+     * Handle 2 special cases: 1. value is wrapped by a quotation 2. value
+     * contains comma
+     */
+
+    /**
+     * Tells the browser whether the cookies should be sent to server through
+     * secure protocols.
+     * 
+     * @param flag
+     *            tells browser to send cookie to server only through secure
+     *            protocol if flag is true
+     */
+    public void setSecure(boolean flag) {
+        secure = flag;
+    }
+
+    /**
+     * Sets the value for this cookie after it has been instantiated. String
+     * newValue can be in BASE64 form. If the version of the cookie is 0,
+     * special value as: white space, brackets, parentheses, equals signs,
+     * commas, double quotes, slashes, question marks, at signs, colons, and
+     * semicolons are not recommended. Empty values may lead to different
+     * behavior on different browsers.
+     * 
+     * @param newValue
+     *            the value for this cookie
+     */
+    public void setValue(String newValue) {
+        // FIXME: According to spec, version 0 cookie value does not allow many
+        // symbols. But RI does not implement it. Follow RI temporarily.
+        value = newValue;
+    }
+
+    /**
+     * Sets the version of the cookie. 0 indicates the original Netscape cookie
+     * specification, while 1 indicates RFC 2965/2109 specification.
+     * 
+     * @param v
+     *            0 or 1 as stated above
+     * @throws IllegalArgumentException
+     *             if v is neither 0 nor 1
+     */
+    public void setVersion(int v) {
+        if (v != 0 && v != 1) {
+            throw new IllegalArgumentException("Unknown version!");
+        }
+        version = v;
+    }
+
+    /**
+     * Returns a string to represent the cookie. The format of string follows
+     * the cookie specification. The leading token "Cookie" is not included
+     * 
+     * @return the string format of the cookie object
+     */
+    @Override
+    public String toString() {
+        StringBuilder cookieStr = new StringBuilder();
+        cookieStr.append(name);
+        cookieStr.append("=");
+        if (version == 0) {
+            cookieStr.append(value);
+        } else if (version == 1) {
+            cookieStr.append(QUOTE_STR);
+            cookieStr.append(value);
+            cookieStr.append(QUOTE_STR);
+
+            attrToString(cookieStr, "Path", path);
+            attrToString(cookieStr, "Domain", domain);
+            attrToString(cookieStr, "Port", portList);
+        }
+
+        return cookieStr.toString();
+    }
+}

Propchange: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisHttpCookie.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java?rev=1148054&r1=1148053&r2=1148054&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java Mon Jul 18 21:20:50 2011
@@ -75,7 +75,9 @@ public final class SessionParameter {
 
     public static final String COMPRESSION = "org.apache.chemistry.opencmis.binding.compression";
     public static final String CLIENT_COMPRESSION = "org.apache.chemistry.opencmis.binding.clientcompression";
-    
+
+    public static final String COOKIES = "org.apache.chemistry.opencmis.binding.cookies";
+
     public static final String CONNECT_TIMEOUT = "org.apache.chemistry.opencmis.binding.connecttimeout";
     public static final String READ_TIMEOUT = "org.apache.chemistry.opencmis.binding.readtimeout";
 

Modified: chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/LoginDialog.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/LoginDialog.java?rev=1148054&r1=1148053&r2=1148054&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/LoginDialog.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/LoginDialog.java Mon Jul 18 21:20:50 2011
@@ -68,6 +68,8 @@ public class LoginDialog extends JDialog
     public static final String SYSPROP_BINDING = ClientSession.WORKBENCH_PREFIX + "binding";
     public static final String SYSPROP_AUTHENTICATION = ClientSession.WORKBENCH_PREFIX + "authentication";
     public static final String SYSPROP_COMPRESSION = ClientSession.WORKBENCH_PREFIX + "compression";
+    public static final String SYSPROP_CLIENTCOMPRESSION = ClientSession.WORKBENCH_PREFIX + "clientcompression";
+    public static final String SYSPROP_COOKIES = ClientSession.WORKBENCH_PREFIX + "cookies";
     public static final String SYSPROP_USER = ClientSession.WORKBENCH_PREFIX + "user";
     public static final String SYSPROP_PASSWORD = ClientSession.WORKBENCH_PREFIX + "password";
 
@@ -89,6 +91,8 @@ public class LoginDialog extends JDialog
     private JRadioButton compressionOffButton;
     private JRadioButton clientCompressionOnButton;
     private JRadioButton clientCompressionOffButton;
+    private JRadioButton cookiesOnButton;
+    private JRadioButton cookiesOffButton;
     private JTextArea sessionParameterTextArea;
     private JButton loadRepositoryButton;
     private JButton loginButton;
@@ -137,7 +141,9 @@ public class LoginDialog extends JDialog
 
         createClientCompressionButtons(basicPanel);
 
-        makeCompactGrid(basicPanel, 7, 2, 5, 10, 5, 5);
+        createCookieButtons(basicPanel);
+
+        makeCompactGrid(basicPanel, 8, 2, 5, 10, 5, 5);
 
         loginTabs.addTab("Basic", basicPanel);
 
@@ -334,7 +340,7 @@ public class LoginDialog extends JDialog
     private void createCompressionButtons(Container pane) {
         JPanel compressionContainer = new JPanel();
         compressionContainer.setLayout(new BoxLayout(compressionContainer, BoxLayout.LINE_AXIS));
-        boolean compression = !(System.getProperty(SYSPROP_BINDING, "compression").equalsIgnoreCase("off"));
+        boolean compression = !(System.getProperty(SYSPROP_COMPRESSION, "on").equalsIgnoreCase("off"));
         compressionOnButton = new JRadioButton("On", compression);
         compressionOffButton = new JRadioButton("Off", !compression);
         ButtonGroup compressionGroup = new ButtonGroup();
@@ -352,7 +358,7 @@ public class LoginDialog extends JDialog
     private void createClientCompressionButtons(Container pane) {
         JPanel clientCompressionContainer = new JPanel();
         clientCompressionContainer.setLayout(new BoxLayout(clientCompressionContainer, BoxLayout.LINE_AXIS));
-        boolean clientCompression = (System.getProperty(SYSPROP_BINDING, "clientcompression").equalsIgnoreCase("on"));
+        boolean clientCompression = (System.getProperty(SYSPROP_CLIENTCOMPRESSION, "off").equalsIgnoreCase("on"));
         clientCompressionOnButton = new JRadioButton("On", clientCompression);
         clientCompressionOffButton = new JRadioButton("Off", !clientCompression);
         ButtonGroup clientCompressionGroup = new ButtonGroup();
@@ -367,6 +373,24 @@ public class LoginDialog extends JDialog
         pane.add(clientCompressionContainer);
     }
 
+    private void createCookieButtons(Container pane) {
+        JPanel cookiesContainer = new JPanel();
+        cookiesContainer.setLayout(new BoxLayout(cookiesContainer, BoxLayout.LINE_AXIS));
+        boolean cookies = (System.getProperty(SYSPROP_COOKIES, "off").equalsIgnoreCase("on"));
+        cookiesOnButton = new JRadioButton("On", cookies);
+        cookiesOffButton = new JRadioButton("Off", !cookies);
+        ButtonGroup cookiesGroup = new ButtonGroup();
+        cookiesGroup.add(cookiesOnButton);
+        cookiesGroup.add(cookiesOffButton);
+        cookiesContainer.add(cookiesOnButton);
+        cookiesContainer.add(Box.createRigidArea(new Dimension(10, 0)));
+        cookiesContainer.add(cookiesOffButton);
+        JLabel cookiesLabel = new JLabel("Cookies:", JLabel.TRAILING);
+
+        pane.add(cookiesLabel);
+        pane.add(cookiesContainer);
+    }
+
     private JButton createButton(String title) {
         JButton button = new JButton(title);
         button.setPreferredSize(new Dimension(Short.MAX_VALUE, 30));
@@ -440,7 +464,7 @@ public class LoginDialog extends JDialog
         }
 
         return ClientSession.createSessionParameters(url, binding, username, password, authentication,
-                compressionOnButton.isSelected(), clientCompressionOnButton.isSelected());
+                compressionOnButton.isSelected(), clientCompressionOnButton.isSelected(), cookiesOnButton.isSelected());
     }
 
     private Map<String, String> createExpertSessionParameters() {

Modified: chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/model/ClientSession.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/model/ClientSession.java?rev=1148054&r1=1148053&r2=1148054&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/model/ClientSession.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/model/ClientSession.java Mon Jul 18 21:20:50 2011
@@ -102,7 +102,8 @@ public class ClientSession {
     }
 
     public static Map<String, String> createSessionParameters(String url, BindingType binding, String username,
-            String password, Authentication authentication, boolean compression, boolean clientCompression) {
+            String password, Authentication authentication, boolean compression, boolean clientCompression,
+            boolean cookies) {
         Map<String, String> parameters = new LinkedHashMap<String, String>();
 
         if (binding == BindingType.WEBSERVICES) {
@@ -142,6 +143,10 @@ public class ClientSession {
             parameters.put(SessionParameter.CLIENT_COMPRESSION, "true");
         }
 
+        if (cookies) {
+            parameters.put(SessionParameter.COOKIES, "true");
+        }
+
         // get additional workbench properties from system properties
         Properties sysProps = System.getProperties();
         for (String key : sysProps.stringPropertyNames()) {