001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.http.header; 014 015import static org.apache.juneau.common.internal.StringUtils.*; 016 017import java.util.function.*; 018 019import org.apache.juneau.*; 020import org.apache.juneau.httppart.*; 021import org.apache.juneau.oapi.*; 022import org.apache.juneau.serializer.*; 023 024/** 025 * TODO 026 * 027 * <h5 class='section'>See Also:</h5><ul> 028 * <li class='link'><a class="doclink" href="../../../../../index.html#juneau-rest-common">juneau-rest-common</a> 029 * </ul> 030 * 031 * @serial exclude 032 */ 033public class SerializedHeader extends BasicHeader { 034 035 //----------------------------------------------------------------------------------------------------------------- 036 // Static 037 //----------------------------------------------------------------------------------------------------------------- 038 039 private static final long serialVersionUID = 1L; 040 041 /** 042 * Static creator. 043 * 044 * @param name The header name. 045 * @param value 046 * The POJO to serialize as the header value. 047 * <br>Can be <jk>null</jk>. 048 * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>. 049 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 050 */ 051 public static SerializedHeader of(String name, Object value) { 052 return new SerializedHeader(name, value, null, null, false); 053 } 054 055 /** 056 * Static creator with delayed value. 057 * 058 * <p> 059 * Header value is re-evaluated on each call to {@link #getValue()}. 060 * 061 * @param name The header name. 062 * @param value 063 * The supplier of the POJO to serialize as the header value. 064 * <br>Can be <jk>null</jk>. 065 * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>. 066 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 067 */ 068 public static SerializedHeader of(String name, Supplier<?> value) { 069 return new SerializedHeader(name, value, null, null, false); 070 } 071 072 /** 073 * Static creator. 074 * 075 * @param name The HTTP header name name. 076 * @param value 077 * The POJO to serialize as the header value. 078 * @param serializer 079 * The serializer to use for serializing the value to a string value. 080 * @param schema 081 * The schema object that defines the format of the output. 082 * <br>If <jk>null</jk>, defaults to the schema defined on the serializer. 083 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 084 * <br>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). 085 * <br>Can also be a {@link Supplier}. 086 * @param skipIfEmpty If value is a blank string, the value should return as <jk>null</jk>. 087 * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>. 088 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 089 */ 090 public static SerializedHeader of(String name, Object value, HttpPartSerializerSession serializer, HttpPartSchema schema, boolean skipIfEmpty) { 091 return new SerializedHeader(name, value, serializer, schema, skipIfEmpty); 092 } 093 094 /** 095 * Static creator with delayed value. 096 * 097 * <p> 098 * Header value is re-evaluated on each call to {@link #getValue()}. 099 * 100 * @param name The HTTP header name name. 101 * @param value 102 * The supplier of the POJO to serialize as the header value. 103 * @param serializer 104 * The serializer to use for serializing the value to a string value. 105 * @param schema 106 * The schema object that defines the format of the output. 107 * <br>If <jk>null</jk>, defaults to the schema defined on the serializer. 108 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 109 * <br>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). 110 * <br>Can also be a {@link Supplier}. 111 * @param skipIfEmpty If value is a blank string, the value should return as <jk>null</jk>. 112 * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>. 113 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 114 */ 115 public static SerializedHeader of(String name, Supplier<?> value, HttpPartSerializerSession serializer, HttpPartSchema schema, boolean skipIfEmpty) { 116 return new SerializedHeader(name, value, serializer, schema, skipIfEmpty); 117 } 118 119 //----------------------------------------------------------------------------------------------------------------- 120 // Instance 121 //----------------------------------------------------------------------------------------------------------------- 122 123 private final Object value; 124 private final Supplier<Object> supplier; 125 private HttpPartSerializerSession serializer; 126 private HttpPartSchema schema = HttpPartSchema.DEFAULT; 127 private boolean skipIfEmpty; 128 129 /** 130 * Constructor. 131 * 132 * @param name The HTTP header name name. 133 * @param value The POJO to serialize to the parameter value. 134 * @param serializer 135 * The serializer to use for serializing the value to a string value. 136 * @param schema 137 * The schema object that defines the format of the output. 138 * <br>If <jk>null</jk>, defaults to the schema defined on the serializer. 139 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 140 * <br>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). 141 * <br>Can also be a {@link Supplier}. 142 * @param skipIfEmpty If value is a blank string, the value should return as <jk>null</jk>. 143 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 144 */ 145 @SuppressWarnings("unchecked") 146 public SerializedHeader(String name, Object value, HttpPartSerializerSession serializer, HttpPartSchema schema, boolean skipIfEmpty) { 147 super(name, null); 148 this.value = value instanceof Supplier ? null : value; 149 this.supplier = value instanceof Supplier ? (Supplier<Object>)value : null; 150 this.serializer = serializer; 151 this.schema = schema; 152 this.skipIfEmpty = skipIfEmpty; 153 } 154 155 /** 156 * Constructor with delayed value. 157 * 158 * <p> 159 * Header value is re-evaluated on each call to {@link #getValue()}. 160 * 161 * @param name The HTTP header name name. 162 * @param value The supplier of the POJO to serialize to the parameter value. 163 * @param serializer 164 * The serializer to use for serializing the value to a string value. 165 * @param schema 166 * The schema object that defines the format of the output. 167 * <br>If <jk>null</jk>, defaults to the schema defined on the serializer. 168 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 169 * <br>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). 170 * <br>Can also be a {@link Supplier}. 171 * @param skipIfEmpty If value is a blank string, the value should return as <jk>null</jk>. 172 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 173 */ 174 public SerializedHeader(String name, Supplier<Object> value, HttpPartSerializerSession serializer, HttpPartSchema schema, boolean skipIfEmpty) { 175 super(name, null); 176 this.value = null; 177 this.supplier = value; 178 this.serializer = serializer; 179 this.schema = schema; 180 this.skipIfEmpty = skipIfEmpty; 181 } 182 183 /** 184 * Copy constructor. 185 * 186 * @param copyFrom The object to copy. 187 */ 188 protected SerializedHeader(SerializedHeader copyFrom) { 189 super(copyFrom); 190 this.value = copyFrom.value; 191 this.supplier = copyFrom.supplier; 192 this.serializer = copyFrom.serializer == null ? serializer : copyFrom.serializer; 193 this.schema = copyFrom.schema == null ? schema : copyFrom.schema; 194 this.skipIfEmpty = copyFrom.skipIfEmpty; 195 } 196 197 /** 198 * Creates a copy of this object. 199 * 200 * @return A new copy of this object. 201 */ 202 public SerializedHeader copy() { 203 return new SerializedHeader(this); 204 } 205 206 /** 207 * Sets the serializer to use for serializing the value to a string value. 208 * 209 * @param value The new value for this property. 210 * @return This object. 211 */ 212 public SerializedHeader serializer(HttpPartSerializer value) { 213 if (value != null) 214 return serializer(value.getPartSession()); 215 return this; 216 } 217 218 /** 219 * Sets the serializer to use for serializing the value to a string value. 220 * 221 * @param value The new value for this property. 222 * @return This object. 223 */ 224 public SerializedHeader serializer(HttpPartSerializerSession value) { 225 serializer = value; 226 return this; 227 } 228 229 /** 230 * Sets the schema object that defines the format of the output. 231 * 232 * @param value The new value for this property. 233 * @return This object. 234 */ 235 public SerializedHeader schema(HttpPartSchema value) { 236 this.schema = value; 237 return this; 238 } 239 240 /** 241 * Copies this bean and sets the serializer and schema on it. 242 * 243 * @param serializer The new serializer for the bean. Can be <jk>null</jk>. 244 * @param schema The new schema for the bean. Can be <jk>null</jk>. 245 * @return Either a new bean with the serializer set, or this bean if 246 * both values are <jk>null</jk> or the serializer and schema were already set. 247 */ 248 public SerializedHeader copyWith(HttpPartSerializerSession serializer, HttpPartSchema schema) { 249 if ((this.serializer == null && serializer != null) || (this.schema == null && schema != null)) { 250 SerializedHeader h = copy(); 251 if (serializer != null) 252 h.serializer(serializer); 253 if (schema != null) 254 h.schema(schema); 255 return h; 256 } 257 return this; 258 } 259 260 /** 261 * Don't serialize this header if the value is <jk>null</jk> or an empty string. 262 * 263 * @return This object. 264 */ 265 public SerializedHeader skipIfEmpty() { 266 return skipIfEmpty(true); 267 } 268 269 /** 270 * Don't serialize this header if the value is <jk>null</jk> or an empty string. 271 * 272 * @param value The new value of this setting. 273 * @return This object. 274 */ 275 public SerializedHeader skipIfEmpty(boolean value) { 276 this.skipIfEmpty = value; 277 return this; 278 } 279 280 @Override /* NameValuePair */ 281 public String getValue() { 282 try { 283 Object v = value; 284 if (supplier != null) 285 v = supplier.get(); 286 HttpPartSchema schema = this.schema == null ? HttpPartSchema.DEFAULT : this.schema; 287 String def = schema.getDefault(); 288 if (v == null) { 289 if ((def == null && ! schema.isRequired()) || (def == null && schema.isAllowEmptyValue())) 290 return null; 291 } 292 if (isEmpty(stringify(v)) && skipIfEmpty && def == null) 293 return null; 294 return serializer == null ? stringify(v) : serializer.serialize(HttpPartType.HEADER, schema, v); 295 } catch (SchemaValidationException e) { 296 throw new BasicRuntimeException(e, "Validation error on request {0} parameter ''{1}''=''{2}''", HttpPartType.HEADER, getName(), value); 297 } catch (SerializeException e) { 298 throw new BasicRuntimeException(e, "Serialization error on request {0} parameter ''{1}''", HttpPartType.HEADER, getName()); 299 } 300 } 301}