001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.chain.web.jakarta.internal; 018 019import java.util.Arrays; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.HashSet; 023import java.util.Map; 024import java.util.Set; 025import java.util.function.Supplier; 026 027import org.apache.commons.chain.web.MapEntry; 028import org.apache.commons.chain.web.ParameterMap; 029 030import jakarta.servlet.http.Cookie; 031 032/** 033 * Implementation of {@code Map} for cookies with 034 * a parameter-provider. 035 * 036 * @param <P> the type of the parameter-provider 037 * 038 * @author Graff Stefan 039 * @since Chain 1.3 040 */ 041public class CookieMap<P> extends ParameterMap<P, Cookie> { 042 043 /** 044 * Supplier to return the {@link Cookie}-Array in this object. 045 */ 046 private final Supplier<Cookie[]> cookiesSupplier; 047 048 /** 049 * The constructor for the {@code Map} for cookies. 050 * 051 * @param request the request with the cookies 052 * @param cookiesSupplier Supplier to return the {@link Cookie}-Array in this 053 * object 054 */ 055 public CookieMap(final P request, final Supplier<Cookie[]> cookiesSupplier) { 056 super(request, null, null); 057 this.cookiesSupplier = cookiesSupplier; 058 } 059 060 /** 061 * Returns {@code true} if this cookie-map contains a mapping 062 * for the specified cookie-name. 063 * 064 * @param key The key whose presence in this cookie-map is to 065 * be tested 066 * 067 * @return {@code true} if this cookie-map contains a mapping 068 * for the specified cookie-name. 069 */ 070 @Override 071 public boolean containsKey(Object key) { 072 return get(key) != null; 073 } 074 075 /** 076 * Returns {@code true} if this cookie-map maps one or more keys 077 * to the specified cookie. 078 * 079 * @param value cookie whose presence in this cookie-map is to be 080 * tested 081 * 082 * @return {@code true} if this cookie-map maps one or more keys 083 * to the specified cookie 084 */ 085 @Override 086 public boolean containsValue(Object value) { 087 for (Cookie cookie : values()) { 088 if (cookie.equals(value)) { 089 return true; 090 } 091 } 092 return false; 093 } 094 095 /** 096 * Returns a {@link Set} view of the mappings contained in this 097 * cookie-map. The set is not backed by the cookie-map, so 098 * changes to the cookie-map are not reflected in the set, 099 * 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}