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