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.juneau.rest.httppart; 018 019import static org.apache.juneau.commons.utils.AssertionUtils.*; 020import static org.apache.juneau.commons.utils.CollectionUtils.*; 021import static org.apache.juneau.commons.utils.Utils.*; 022 023import java.util.*; 024 025import org.apache.juneau.collections.*; 026import org.apache.juneau.commons.collections.*; 027import org.apache.juneau.rest.*; 028import org.apache.juneau.svl.*; 029 030import jakarta.servlet.http.*; 031 032/** 033 * Represents the attributes in an HTTP request. 034 * 035 * <p> 036 * The {@link RequestAttributes} object is the API for accessing the standard servlet attributes on an HTTP request 037 * (i.e. {@link jakarta.servlet.ServletRequest#getAttribute(String)}). 038 * </p> 039 * 040 * <p class='bjava'> 041 * <ja>@RestPost</ja>(...) 042 * <jk>public</jk> Object myMethod(RequestAttributes <jv>attributes</jv>) {...} 043 * </p> 044 * 045 * <h5 class='figure'>Example:</h5> 046 * <p class='bjava'> 047 * <ja>@RestPost</ja>(...) 048 * <jk>public</jk> Object myMethod(RequestAttributes <jv>attributes</jv>) { 049 * 050 * <jc>// Add a default value.</jc> 051 * <jv>attributes</jv>.addDefault(<js>"Foo"</js>, 123); 052 * 053 * <jc>// Get an attribute value as a POJO.</jc> 054 * UUID <jv>etag</jv> = <jv>attributes</jv>.get(<js>"ETag"</js>).as(UUID.<jk>class</jk>).orElse(<jk>null</jk>); 055 * } 056 * </p> 057 * 058 * <p> 059 * Some important methods on this class are: 060 * </p> 061 * <ul class='javatree'> 062 * <li class='jc'>{@link RequestHeaders} 063 * <ul class='spaced-list'> 064 * <li>Methods for retrieving request attributes: 065 * <ul class='javatreec'> 066 * <li class='jm'>{@link RequestAttributes#contains(String...) contains(String...)} 067 * <li class='jm'>{@link RequestAttributes#containsAny(String...) containsAny(String...)} 068 * <li class='jm'>{@link RequestAttributes#get(String) get(String)} 069 * <li class='jm'>{@link RequestAttributes#getAll() getAll()} 070 * </ul> 071 * <li>Methods for overriding request attributes: 072 * <ul class='javatreec'> 073 * <li class='jm'>{@link RequestAttributes#addDefault(List) addDefault(List)} 074 * <li class='jm'>{@link RequestAttributes#addDefault(NamedAttribute...) addDefault(NamedAttribute...)} 075 * <li class='jm'>{@link RequestAttributes#addDefault(NamedAttributeMap) addDefault(NamedAttributeMap)} 076 * <li class='jm'>{@link RequestAttributes#addDefault(String,Object) addDefault(String,Object)} 077 * <li class='jm'>{@link RequestAttributes#remove(NamedAttribute...) remove(NamedAttribute...)} 078 * <li class='jm'>{@link RequestAttributes#remove(String...) remove(String...)} 079 * <li class='jm'>{@link RequestAttributes#set(NamedAttribute...) set(NamedAttribute...)} 080 * <li class='jm'>{@link RequestAttributes#set(String,Object) set(String,Object)} 081 * </ul> 082 * <li>Other methods: 083 * <ul class='javatreec'> 084 * <li class='jm'>{@link RequestAttributes#asMap() asMap()} 085 * </ul> 086 * </ul> 087 * </ul> 088 * 089 * <p> 090 * Modifications made to request attributes through the <c>RequestAttributes</c> bean are automatically reflected in 091 * the underlying servlet request attributes making it possible to mix the usage of both APIs. 092 * </p> 093 * 094 * <h5 class='section'>See Also:</h5><ul> 095 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HttpParts">HTTP Parts</a> 096 * </ul> 097 */ 098public class RequestAttributes { 099 100 final RestRequest req; 101 final HttpServletRequest sreq; 102 final VarResolverSession vs; 103 104 /** 105 * Constructor. 106 * 107 * @param req The request creating this bean. 108 */ 109 public RequestAttributes(RestRequest req) { 110 this.req = req; 111 this.sreq = req.getHttpServletRequest(); 112 this.vs = req.getVarResolverSession(); 113 } 114 115 /** 116 * Adds default entries to the request attributes. 117 * 118 * @param pairs 119 * The default entries. 120 * <br>Can be <jk>null</jk>. 121 * @return This object. 122 */ 123 public RequestAttributes addDefault(List<NamedAttribute> pairs) { 124 for (var p : pairs) 125 if (sreq.getAttribute(p.getName()) == null) { 126 Object o = p.getValue(); 127 sreq.setAttribute(p.getName(), o instanceof String ? vs.resolve(o) : o); 128 } 129 return this; 130 } 131 132 /** 133 * Adds default entries to the request attributes. 134 * 135 * @param pairs 136 * The default entries. 137 * <br>Can be <jk>null</jk>. 138 * @return This object. 139 */ 140 public RequestAttributes addDefault(NamedAttribute...pairs) { 141 return addDefault(l(pairs)); 142 } 143 144 /** 145 * Adds default entries to the request attributes. 146 * 147 * @param pairs 148 * The default entries. 149 * <br>Can be <jk>null</jk>. 150 * @return This object. 151 */ 152 public RequestAttributes addDefault(NamedAttributeMap pairs) { 153 for (var p : pairs.values()) 154 if (sreq.getAttribute(p.getName()) == null) { 155 Object o = p.getValue(); 156 sreq.setAttribute(p.getName(), o instanceof String ? vs.resolve(o) : o); 157 } 158 return this; 159 } 160 161 /** 162 * Adds a default entry to the request attributes. 163 * 164 * @param name The name. 165 * @param value The value. 166 * @return This object. 167 */ 168 public RequestAttributes addDefault(String name, Object value) { 169 return addDefault(BasicNamedAttribute.of(name, value)); 170 } 171 172 /** 173 * Returns the request attributes as a map. 174 * 175 * @return The request attributes as a map. Never <jk>null</jk>. 176 */ 177 public Map<String,Object> asMap() { 178 var m = new JsonMap(); 179 Enumeration<String> e = sreq.getAttributeNames(); 180 while (e.hasMoreElements()) { 181 var n = e.nextElement(); 182 m.put(n, sreq.getAttribute(n)); 183 } 184 return m; 185 } 186 187 /** 188 * Returns <jk>true</jk> if the attributes with the specified names are present. 189 * 190 * @param names The attribute names. Must not be <jk>null</jk>. 191 * @return <jk>true</jk> if the parameters with the specified names are present. 192 */ 193 public boolean contains(String...names) { 194 assertArgNotNull("names", names); 195 for (var n : names) 196 if (sreq.getAttribute(n) == null) 197 return false; 198 return true; 199 } 200 201 /** 202 * Returns <jk>true</jk> if the attribute with any of the specified names are present. 203 * 204 * @param names The attribute names. Must not be <jk>null</jk>. 205 * @return <jk>true</jk> if the attribute with any of the specified names are present. 206 */ 207 public boolean containsAny(String...names) { 208 assertArgNotNull("names", names); 209 for (var n : names) 210 if (nn(sreq.getAttribute(n))) 211 return true; 212 return false; 213 } 214 215 /** 216 * Returns the request attribute with the specified name. 217 * 218 * @param name The attribute name. 219 * @return The parameter value, or {@link Optional#empty()} if it doesn't exist. 220 */ 221 public RequestAttribute get(String name) { 222 return new RequestAttribute(req, name, sreq.getAttribute(name)); 223 } 224 225 /** 226 * Returns all the attribute on this request. 227 * 228 * @return All the attribute on this request. 229 */ 230 public List<RequestAttribute> getAll() { 231 List<RequestAttribute> l = list(); 232 Enumeration<String> e = sreq.getAttributeNames(); 233 while (e.hasMoreElements()) { 234 var n = e.nextElement(); 235 l.add(new RequestAttribute(req, n, sreq.getAttribute(n))); 236 } 237 return l; 238 } 239 240 /** 241 * Remove request attributes. 242 * 243 * @param attributes The attributes to remove. Must not be <jk>null</jk>. 244 * @return This object. 245 */ 246 public RequestAttributes remove(NamedAttribute...attributes) { 247 for (var p : attributes) 248 remove(p.getName()); 249 return this; 250 } 251 252 /** 253 * Remove request attributes. 254 * 255 * @param name The attribute names. Must not be <jk>null</jk>. 256 * @return This object. 257 */ 258 public RequestAttributes remove(String...name) { 259 assertArgNotNull("name", name); 260 for (var n : name) { 261 sreq.removeAttribute(n); 262 } 263 return this; 264 } 265 266 /** 267 * Sets request attributes. 268 * 269 * @param attributes The parameters to set. Must not be <jk>null</jk> or contain <jk>null</jk>. 270 * @return This object. 271 */ 272 public RequestAttributes set(NamedAttribute...attributes) { 273 assertArgNotNull("attributes", attributes); 274 for (var p : attributes) 275 set(p); 276 return this; 277 } 278 279 /** 280 * Sets a request attribute. 281 * 282 * @param name The attribute name. Must not be <jk>null</jk>. 283 * @param value 284 * The attribute value. 285 * <br>Can be <jk>null</jk>. 286 * @return This object. 287 */ 288 public RequestAttributes set(String name, Object value) { 289 assertArgNotNull("name", name); 290 sreq.setAttribute(name, value); 291 return this; 292 } 293 294 protected FluentMap<String,Object> properties() { 295 // @formatter:off 296 return filteredBeanPropertyMap() 297 .a("attributes", asMap()); 298 // @formatter:on 299 } 300 301 @Override /* Overridden from Object */ 302 public String toString() { 303 return r(properties()); 304 } 305}