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 }