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