1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package java.net;
18
19import java.util.ArrayList;
20import java.util.Collections;
21import java.util.HashMap;
22import java.util.Iterator;
23import java.util.List;
24import java.util.Map;
25
26/**
27 * An in-memory cookie store.
28 */
29final class CookieStoreImpl implements CookieStore {
30
31    /** this map may have null keys! */
32    private final Map<URI, List<HttpCookie>> map = new HashMap<URI, List<HttpCookie>>();
33
34    public synchronized void add(URI uri, HttpCookie cookie) {
35        if (cookie == null) {
36            throw new NullPointerException("cookie == null");
37        }
38
39        uri = cookiesUri(uri);
40        List<HttpCookie> cookies = map.get(uri);
41        if (cookies == null) {
42            cookies = new ArrayList<HttpCookie>();
43            map.put(uri, cookies);
44        } else {
45            cookies.remove(cookie);
46        }
47        cookies.add(cookie);
48    }
49
50    private URI cookiesUri(URI uri) {
51        if (uri == null) {
52            return null;
53        }
54        try {
55            return new URI("http", uri.getHost(), null, null);
56        } catch (URISyntaxException e) {
57            return uri; // probably a URI with no host
58        }
59    }
60
61    public synchronized List<HttpCookie> get(URI uri) {
62        if (uri == null) {
63            throw new NullPointerException("uri == null");
64        }
65
66        List<HttpCookie> result = new ArrayList<HttpCookie>();
67
68        // get cookies associated with given URI. If none, returns an empty list
69        List<HttpCookie> cookiesForUri = map.get(uri);
70        if (cookiesForUri != null) {
71            for (Iterator<HttpCookie> i = cookiesForUri.iterator(); i.hasNext(); ) {
72                HttpCookie cookie = i.next();
73                if (cookie.hasExpired()) {
74                    i.remove(); // remove expired cookies
75                } else {
76                    result.add(cookie);
77                }
78            }
79        }
80
81        // get all cookies that domain matches the URI
82        for (Map.Entry<URI, List<HttpCookie>> entry : map.entrySet()) {
83            if (uri.equals(entry.getKey())) {
84                continue; // skip the given URI; we've already handled it
85            }
86
87            List<HttpCookie> entryCookies = entry.getValue();
88            for (Iterator<HttpCookie> i = entryCookies.iterator(); i.hasNext(); ) {
89                HttpCookie cookie = i.next();
90                if (!HttpCookie.domainMatches(cookie.getDomain(), uri.getHost())) {
91                    continue;
92                }
93                if (cookie.hasExpired()) {
94                    i.remove(); // remove expired cookies
95                } else if (!result.contains(cookie)) {
96                    result.add(cookie);
97                }
98            }
99        }
100
101        return Collections.unmodifiableList(result);
102    }
103
104    public synchronized List<HttpCookie> getCookies() {
105        List<HttpCookie> result = new ArrayList<HttpCookie>();
106        for (List<HttpCookie> list : map.values()) {
107            for (Iterator<HttpCookie> i = list.iterator(); i.hasNext(); ) {
108                HttpCookie cookie = i.next();
109                if (cookie.hasExpired()) {
110                    i.remove(); // remove expired cookies
111                } else if (!result.contains(cookie)) {
112                    result.add(cookie);
113                }
114            }
115        }
116        return Collections.unmodifiableList(result);
117    }
118
119    public synchronized List<URI> getURIs() {
120        List<URI> result = new ArrayList<URI>(map.keySet());
121        result.remove(null); // sigh
122        return Collections.unmodifiableList(result);
123    }
124
125    public synchronized boolean remove(URI uri, HttpCookie cookie) {
126        if (cookie == null) {
127            throw new NullPointerException("cookie == null");
128        }
129
130        List<HttpCookie> cookies = map.get(cookiesUri(uri));
131        if (cookies != null) {
132            return cookies.remove(cookie);
133        } else {
134            return false;
135        }
136    }
137
138    public synchronized boolean removeAll() {
139        boolean result = !map.isEmpty();
140        map.clear();
141        return result;
142    }
143}
144