Save This Page
Home » Open-JDK-6.b17-src » sun.net.www.protocol » http » [javadoc | source]
    1   /*
    2    * Copyright 2005 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package sun.net.www.protocol.http;
   27   
   28   import java.net.URI;
   29   import java.net.CookieStore;
   30   import java.net.HttpCookie;
   31   import java.net.URISyntaxException;
   32   import java.util.List;
   33   import java.util.Map;
   34   import java.util.ArrayList;
   35   import java.util.HashMap;
   36   import java.util.Collections;
   37   import java.util.Iterator;
   38   import java.util.Comparator;
   39   import java.util.concurrent.locks.ReentrantLock;
   40   
   41   /**
   42    * A simple in-memory java.net.CookieStore implementation
   43    *
   44    * @author Edward Wang
   45    * @since 1.6
   46    */
   47   public class InMemoryCookieStore implements CookieStore {
   48       // the in-memory representation of cookies
   49       private List<HttpCookie> cookieJar = null;
   50   
   51       // the cookies are indexed by its domain and associated uri (if present)
   52       // CAUTION: when a cookie removed from main data structure (i.e. cookieJar),
   53       //          it won't be cleared in domainIndex & uriIndex. Double-check the
   54       //          presence of cookie when retrieve one form index store.
   55       private Map<String, List<HttpCookie>> domainIndex = null;
   56       private Map<URI, List<HttpCookie>> uriIndex = null;
   57   
   58       // use ReentrantLock instead of syncronized for scalability
   59       private ReentrantLock lock = null;
   60   
   61   
   62       /**
   63        * The default ctor
   64        */
   65       public InMemoryCookieStore() {
   66           cookieJar = new ArrayList<HttpCookie>();
   67           domainIndex = new HashMap<String, List<HttpCookie>>();
   68           uriIndex = new HashMap<URI, List<HttpCookie>>();
   69   
   70           lock = new ReentrantLock(false);
   71       }
   72   
   73       /**
   74        * Add one cookie into cookie store.
   75        */
   76       public void add(URI uri, HttpCookie cookie) {
   77           // pre-condition : argument can't be null
   78           if (cookie == null) {
   79               throw new NullPointerException("cookie is null");
   80           }
   81   
   82   
   83           lock.lock();
   84           try {
   85               // remove the ole cookie if there has had one
   86               cookieJar.remove(cookie);
   87   
   88               // add new cookie if it has a non-zero max-age
   89               if (cookie.getMaxAge() != 0) {
   90                   cookieJar.add(cookie);
   91                   // and add it to domain index
   92                   addIndex(domainIndex, cookie.getDomain(), cookie);
   93                   // add it to uri index, too
   94                   addIndex(uriIndex, getEffectiveURI(uri), cookie);
   95               }
   96           } finally {
   97               lock.unlock();
   98           }
   99       }
  100   
  101   
  102       /**
  103        * Get all cookies, which:
  104        *  1) given uri domain-matches with, or, associated with
  105        *     given uri when added to the cookie store.
  106        *  3) not expired.
  107        * See RFC 2965 sec. 3.3.4 for more detail.
  108        */
  109       public List<HttpCookie> get(URI uri) {
  110           // argument can't be null
  111           if (uri == null) {
  112               throw new NullPointerException("uri is null");
  113           }
  114   
  115           List<HttpCookie> cookies = new ArrayList<HttpCookie>();
  116           lock.lock();
  117           try {
  118               // check domainIndex first
  119               getInternal(cookies, domainIndex, new DomainComparator(uri.getHost()));
  120               // check uriIndex then
  121               getInternal(cookies, uriIndex, getEffectiveURI(uri));
  122           } finally {
  123               lock.unlock();
  124           }
  125   
  126           return cookies;
  127       }
  128   
  129       /**
  130        * Get all cookies in cookie store, except those have expired
  131        */
  132       public List<HttpCookie> getCookies() {
  133           List<HttpCookie> rt;
  134   
  135           lock.lock();
  136           try {
  137               Iterator<HttpCookie> it = cookieJar.iterator();
  138               while (it.hasNext()) {
  139                   if (it.next().hasExpired()) {
  140                       it.remove();
  141                   }
  142               }
  143           } finally {
  144               rt = Collections.unmodifiableList(cookieJar);
  145               lock.unlock();
  146           }
  147   
  148           return rt;
  149       }
  150   
  151       /**
  152        * Get all URIs, which are associated with at least one cookie
  153        * of this cookie store.
  154        */
  155       public List<URI> getURIs() {
  156           List<URI> uris = new ArrayList<URI>();
  157   
  158           lock.lock();
  159           try {
  160               Iterator<URI> it = uriIndex.keySet().iterator();
  161               while (it.hasNext()) {
  162                   URI uri = it.next();
  163                   List<HttpCookie> cookies = uriIndex.get(uri);
  164                   if (cookies == null || cookies.size() == 0) {
  165                       // no cookies list or an empty list associated with
  166                       // this uri entry, delete it
  167                       it.remove();
  168                   }
  169               }
  170           } finally {
  171               uris.addAll(uriIndex.keySet());
  172               lock.unlock();
  173           }
  174   
  175           return uris;
  176       }
  177   
  178   
  179       /**
  180        * Remove a cookie from store
  181        */
  182       public boolean remove(URI uri, HttpCookie ck) {
  183           // argument can't be null
  184           if (ck == null) {
  185               throw new NullPointerException("cookie is null");
  186           }
  187   
  188           boolean modified = false;
  189           lock.lock();
  190           try {
  191               modified = cookieJar.remove(ck);
  192           } finally {
  193               lock.unlock();
  194           }
  195   
  196           return modified;
  197       }
  198   
  199   
  200       /**
  201        * Remove all cookies in this cookie store.
  202        */
  203       public boolean removeAll() {
  204           lock.lock();
  205           try {
  206               cookieJar.clear();
  207               domainIndex.clear();
  208               uriIndex.clear();
  209           } finally {
  210               lock.unlock();
  211           }
  212   
  213           return true;
  214       }
  215   
  216   
  217       /* ---------------- Private operations -------------- */
  218   
  219   
  220       static class DomainComparator implements Comparable<String> {
  221           String host = null;
  222   
  223           public DomainComparator(String host) {
  224               this.host = host;
  225           }
  226   
  227           public int compareTo(String domain) {
  228               if (HttpCookie.domainMatches(domain, host)) {
  229                   return 0;
  230               } else {
  231                   return -1;
  232               }
  233           }
  234       }
  235   
  236       // @param cookies           [OUT] contains the found cookies
  237       // @param cookieIndex       the index
  238       // @param comparator        the prediction to decide whether or not
  239       //                          a cookie in index should be returned
  240       private <T> void getInternal(List<HttpCookie> cookies,
  241                                   Map<T, List<HttpCookie>> cookieIndex,
  242                                   Comparable<T> comparator)
  243       {
  244           for (T index : cookieIndex.keySet()) {
  245               if (comparator.compareTo(index) == 0) {
  246                   List<HttpCookie> indexedCookies = cookieIndex.get(index);
  247                   // check the list of cookies associated with this domain
  248                   if (indexedCookies != null) {
  249                       Iterator<HttpCookie> it = indexedCookies.iterator();
  250                       while (it.hasNext()) {
  251                           HttpCookie ck = it.next();
  252                           if (cookieJar.indexOf(ck) != -1) {
  253                               // the cookie still in main cookie store
  254                               if (!ck.hasExpired()) {
  255                                   // don't add twice
  256                                   if (!cookies.contains(ck))
  257                                       cookies.add(ck);
  258                               } else {
  259                                   it.remove();
  260                                   cookieJar.remove(ck);
  261                               }
  262                           } else {
  263                               // the cookie has beed removed from main store,
  264                               // so also remove it from domain indexed store
  265                               it.remove();
  266                           }
  267                       }
  268                   } // end of indexedCookies != null
  269               } // end of comparator.compareTo(index) == 0
  270           } // end of cookieIndex iteration
  271       }
  272   
  273       // add 'cookie' indexed by 'index' into 'indexStore'
  274       private <T> void addIndex(Map<T, List<HttpCookie>> indexStore,
  275                                 T index,
  276                                 HttpCookie cookie)
  277       {
  278           if (index != null) {
  279               List<HttpCookie> cookies = indexStore.get(index);
  280               if (cookies != null) {
  281                   // there may already have the same cookie, so remove it first
  282                   cookies.remove(cookie);
  283   
  284                   cookies.add(cookie);
  285               } else {
  286                   cookies = new ArrayList<HttpCookie>();
  287                   cookies.add(cookie);
  288                   indexStore.put(index, cookies);
  289               }
  290           }
  291       }
  292   
  293   
  294       //
  295       // for cookie purpose, the effective uri should only be scheme://authority
  296       // the path will be taken into account when path-match algorithm applied
  297       //
  298       private URI getEffectiveURI(URI uri) {
  299           URI effectiveURI = null;
  300           try {
  301               effectiveURI = new URI(uri.getScheme(),
  302                                      uri.getAuthority(),
  303                                      null,  // path component
  304                                      null,  // query component
  305                                      null   // fragment component
  306                                     );
  307           } catch (URISyntaxException ignored) {
  308               effectiveURI = uri;
  309           }
  310   
  311           return effectiveURI;
  312       }
  313   }

Save This Page
Home » Open-JDK-6.b17-src » sun.net.www.protocol » http » [javadoc | source]