1 /*
2  * ====================================================================
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  * ====================================================================
20  *
21  * This software consists of voluntary contributions made by many
22  * individuals on behalf of the Apache Software Foundation.  For more
23  * information on the Apache Software Foundation, please see
24  * <http://www.apache.org/>.
25  *
26  */

27 package org.apache.http.impl.client;
28
29 import java.io.IOException;
30 import java.io.ObjectInputStream;
31 import java.io.Serializable;
32 import java.util.ArrayList;
33 import java.util.Date;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.TreeSet;
37 import java.util.concurrent.locks.ReadWriteLock;
38 import java.util.concurrent.locks.ReentrantReadWriteLock;
39
40 import org.apache.http.annotation.Contract;
41 import org.apache.http.annotation.ThreadingBehavior;
42 import org.apache.http.client.CookieStore;
43 import org.apache.http.cookie.Cookie;
44 import org.apache.http.cookie.CookieIdentityComparator;
45
46 /**
47  * Default implementation of {@link CookieStore}
48  *
49  *
50  * @since 4.0
51  */

52 @Contract(threading = ThreadingBehavior.SAFE)
53 public class BasicCookieStore implements CookieStore, Serializable {
54
55     private static final long serialVersionUID = -7581093305228232025L;
56
57     private final TreeSet<Cookie> cookies;
58     private transient ReadWriteLock lock;
59
60     public BasicCookieStore() {
61         super();
62         this.cookies = new TreeSet<Cookie>(new CookieIdentityComparator());
63         this.lock = new ReentrantReadWriteLock();
64     }
65
66     private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException {
67         stream.defaultReadObject();
68
69         /* Reinstantiate transient fields. */
70         this.lock = new ReentrantReadWriteLock();
71     }
72
73     /**
74      * Adds an {@link Cookie HTTP cookie}, replacing any existing equivalent cookies.
75      * If the given cookie has already expired it will not be added, but existing
76      * values will still be removed.
77      *
78      * @param cookie the {@link Cookie cookie} to be added
79      *
80      * @see #addCookies(Cookie[])
81      *
82      */

83     @Override
84     public void addCookie(final Cookie cookie) {
85         if (cookie != null) {
86             lock.writeLock().lock();
87             try {
88                 // first remove any old cookie that is equivalent
89                 cookies.remove(cookie);
90                 if (!cookie.isExpired(new Date())) {
91                     cookies.add(cookie);
92                 }
93             } finally {
94                 lock.writeLock().unlock();
95             }
96         }
97     }
98
99     /**
100      * Adds an array of {@link Cookie HTTP cookies}. Cookies are added individually and
101      * in the given array order. If any of the given cookies has already expired it will
102      * not be added, but existing values will still be removed.
103      *
104      * @param cookies the {@link Cookie cookies} to be added
105      *
106      * @see #addCookie(Cookie)
107      *
108      */

109     public void addCookies(final Cookie[] cookies) {
110         if (cookies != null) {
111             for (final Cookie cookie : cookies) {
112                 this.addCookie(cookie);
113             }
114         }
115     }
116
117     /**
118      * Returns an immutable array of {@link Cookie cookies} that this HTTP
119      * state currently contains.
120      *
121      * @return an array of {@link Cookie cookies}.
122      */

123     @Override
124     public List<Cookie> getCookies() {
125         lock.readLock().lock();
126         try {
127             //create defensive copy so it won't be concurrently modified
128             return new ArrayList<Cookie>(cookies);
129         } finally {
130             lock.readLock().unlock();
131         }
132     }
133
134     /**
135      * Removes all of {@link Cookie cookies} in this HTTP state
136      * that have expired by the specified {@link java.util.Date date}.
137      *
138      * @return true if any cookies were purged.
139      *
140      * @see Cookie#isExpired(Date)
141      */

142     @Override
143     public boolean clearExpired(final Date date) {
144         if (date == null) {
145             return false;
146         }
147         lock.writeLock().lock();
148         try {
149             boolean removed = false;
150             for (final Iterator<Cookie> it = cookies.iterator(); it.hasNext(); ) {
151                 if (it.next().isExpired(date)) {
152                     it.remove();
153                     removed = true;
154                 }
155             }
156             return removed;
157         } finally {
158             lock.writeLock().unlock();
159         }
160     }
161
162     /**
163      * Clears all cookies.
164      */

165     @Override
166     public void clear() {
167         lock.writeLock().lock();
168         try {
169             cookies.clear();
170         } finally {
171             lock.writeLock().unlock();
172         }
173     }
174
175     @Override
176     public String toString() {
177         lock.readLock().lock();
178         try {
179             return cookies.toString();
180         } finally {
181             lock.readLock().unlock();
182         }
183     }
184
185 }
186