View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.chain.web.javax.internal;
18  
19  import java.util.Arrays;
20  import java.util.Collection;
21  import java.util.Collections;
22  import java.util.HashSet;
23  import java.util.Map;
24  import java.util.Set;
25  import java.util.function.Supplier;
26  
27  import javax.servlet.http.Cookie;
28  
29  import org.apache.commons.chain.web.MapEntry;
30  import org.apache.commons.chain.web.ParameterMap;
31  
32  /**
33   * Implementation of {@code Map} for cookies with
34   * a parameter-provider.
35   *
36   * @param <P> the type of the parameter-provider
37   *
38   * @author Graff Stefan
39   * @since Chain 1.3
40   */
41  public class CookieMap<P> extends ParameterMap<P, Cookie> {
42  
43      /**
44       * Supplier to return the {@link Cookie}-Array in this object.
45       */
46      private final Supplier<Cookie[]> cookiesSupplier;
47  
48      /**
49       * The constructor for the {@code Map} for cookies.
50       *
51       * @param request         the request with the cookies
52       * @param cookiesSupplier Supplier to return the {@link Cookie}-Array in this
53       *                        object
54       */
55      public CookieMap(final P request, final Supplier<Cookie[]> cookiesSupplier) {
56          super(request, null, null);
57          this.cookiesSupplier = cookiesSupplier;
58      }
59  
60      /**
61       * Returns {@code true} if this cookie-map contains a mapping
62       * for the specified cookie-name.
63       *
64       * @param key The key whose presence in this cookie-map is to
65       *            be tested
66       *
67       * @return {@code true} if this cookie-map contains a mapping
68       *         for the specified cookie-name.
69       */
70      @Override
71      public boolean containsKey(Object key) {
72          return get(key) != null;
73      }
74  
75      /**
76       * Returns {@code true} if this cookie-map maps one or more keys
77       * to the specified cookie.
78       *
79       * @param value cookie whose presence in this cookie-map is to be
80       *        tested
81       *
82       * @return {@code true} if this cookie-map maps one or more keys
83       *         to the specified cookie
84       */
85      @Override
86      public boolean containsValue(Object value) {
87          for (Cookie cookie : values()) {
88              if (cookie.equals(value)) {
89                  return true;
90              }
91          }
92          return false;
93      }
94  
95      /**
96       * Returns a {@link Set} view of the mappings contained in this
97       * cookie-map. The set is not backed by the cookie-map, so
98       * changes to the cookie-map are not reflected in the set,
99       * and vice-versa.
100      *
101      * @return a set view of the mappings contained in this cookie-map
102      */
103     @Override
104     public Set<Map.Entry<String, Cookie>> entrySet() {
105         final Set<Map.Entry<String, Cookie>> set = new HashSet<>();
106         for (Cookie cookie : values()) {
107             set.add(new MapEntry<>(cookie.getName(), cookie, false));
108         }
109         return set;
110     }
111 
112     /**
113      * Returns the cookie to which the specified cookie-name is mapped,
114      * or {@code null} if this cookie-map contains no mapping for the
115      * cookie-name.
116      *
117      * @param key the cookie-name whose associated value is to be
118      *            returned
119      *
120      * @return the value to which the specified key is mapped, or
121      *         {@code null} if this cookie-map contains no mapping for
122      *         the cookie-name
123      *
124      * @see #put(Object, Object)
125      */
126     @Override
127     public Cookie get(Object key) {
128         final Collection<Cookie> cookies = values();
129         if (!cookies.isEmpty()) {
130             final String skey = key(key);
131             for (Cookie cookie : cookies) {
132                 if (cookie.getName().equals(skey)) {
133                     return cookie;
134                 }
135             }
136         }
137         return null;
138     }
139 
140     /**
141      * Returns {@code true} if this cookie-map contains no cookies.
142      *
143      * @return {@code true} if this cookie-map contains no cookies
144      */
145     @Override
146     public boolean isEmpty() {
147         final Cookie[] cookies = cookiesSupplier.get();
148         return cookies == null || cookies.length == 0;
149     }
150 
151     /**
152      * Returns a {@link Set} view of the cookies contained in this
153      * cookie-map. The set is not backed by the cookie-map, so
154      * changes to the cookie-map are not reflected in the set, and
155      * vice-versa.
156      *
157      * @return a set view of the cookies contained in this cookie-map
158      */
159     @Override
160     public Set<String> keySet() {
161         final Collection<Cookie> cookies = values();
162         final Set<String> set = new HashSet<String>(Math.max((int) (cookies.size() / .75f) + 1, 16));
163         for (Cookie cookie : cookies) {
164             set.add(cookie.getName());
165         }
166         return set;
167     }
168 
169     /**
170      * Returns the number of cookies in this cookie-map.
171      *
172      * @return the number of cookies in this cookie-map
173      */
174     @Override
175     public int size() {
176         final Cookie[] cookies = cookiesSupplier.get();
177         return cookies == null ? 0 : cookies.length;
178     }
179 
180     /**
181      * Returns a {@link Collection} view of the cookies contained in
182      * this cookie-map. The collection is not backed by the
183      * cookie-map, so changes to the cookie-map are not
184      * reflected in the collection, and vice-versa.
185      *
186      * @return a view of the cookies contained in this cookie-map
187      */
188     @Override
189     public Collection<Cookie> values() {
190         final Cookie[] cookies = cookiesSupplier.get();
191         return cookies == null ? Collections.emptyList() : Arrays.asList(cookies);
192     }
193 
194     /**
195      * Returns the hash code value for this cookie-map. The
196      * hash code of a cookie-map is defined to be the sum of
197      * the hash codes of each entry in the cookie-map's
198      * {@code entrySet()} view. This ensures that {@code m1.equals(m2)}
199      * implies that {@code m1.hashCode()==m2.hashCode()} for any two
200      * parameter-maps {@code m1} and {@code m2}, as required by the
201      * general contract of {@link Object#hashCode}.
202      *
203      * @implSpec
204      * This implementation calls the {@code hashCode()} from the
205      * parameter-map.
206      *
207      * @return the hash code value for this cookie-map
208      */
209     @Override
210     public int hashCode() {
211         return super.hashCode();
212     }
213 
214     /**
215      * Compares the specified object with this cookie-map for equality.
216      * Returns {@code true} if the given object is also a cookie-map
217      * and the two cookie-maps represent the same mappings. More formally,
218      * two cookie-maps {@code m1} and {@code m2} represent the same
219      * mappings if {@code m1.entrySet().equals(m2.entrySet())}.
220      *
221      * @param obj object to be compared for equality with this
222      *        cookie-map
223      *
224      * @return {@code true} if the specified object is equal to this
225      *         cookie-map
226      */
227     @Override
228     public boolean equals(Object obj) {
229         return super.equals(obj);
230     }
231 }