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.*;
016import static org.apache.juneau.internal.CollectionUtils.*;
017
018import java.util.*;
019import java.util.function.*;
020
021import org.apache.juneau.*;
022import org.apache.juneau.annotation.*;
023import org.apache.juneau.assertions.*;
024import org.apache.juneau.http.annotation.*;
025
026/**
027 * Category of headers that consist of a single integer value.
028 *
029 * <p>
030 * <h5 class='figure'>Example</h5>
031 * <p class='bcode'>
032 *    Age: 300
033 * </p>
034 *
035 * <h5 class='section'>See Also:</h5><ul>
036 *    <li class='link'><a class="doclink" href="../../../../../index.html#juneau-rest-common">juneau-rest-common</a>
037 *    <li class='extlink'><a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616.html">Hypertext Transfer Protocol -- HTTP/1.1</a>
038 * </ul>
039 *
040 * @serial exclude
041 */
042@Header
043@Schema(type="integer",format="int32")
044public class BasicIntegerHeader extends BasicHeader {
045
046   //-----------------------------------------------------------------------------------------------------------------
047   // Static
048   //-----------------------------------------------------------------------------------------------------------------
049
050   private static final long serialVersionUID = 1L;
051
052   /**
053    * Static creator.
054    *
055    * @param name The header name.
056    * @param value
057    *    The header value.
058    *    <br>Must be parsable using {@link Integer#parseInt(String)}.
059    *    <br>Can be <jk>null</jk>.
060    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
061    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
062    */
063   public static BasicIntegerHeader of(String name, String value) {
064      return value == null ? null : new BasicIntegerHeader(name, value);
065   }
066
067   /**
068    * Static creator.
069    *
070    * @param name The header name.
071    * @param value
072    *    The header value.
073    *    <br>Can be <jk>null</jk>.
074    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
075    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
076    */
077   public static BasicIntegerHeader of(String name, Integer value) {
078      return value == null ? null : new BasicIntegerHeader(name, value);
079   }
080
081   /**
082    * Static creator with delayed value.
083    *
084    * <p>
085    * Header value is re-evaluated on each call to {@link #getValue()}.
086    *
087    * @param name The header name.
088    * @param value
089    *    The supplier of the header value.
090    *    <br>Can be <jk>null</jk>.
091    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
092    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
093    */
094   public static BasicIntegerHeader of(String name, Supplier<Integer> value) {
095      return value == null ? null : new BasicIntegerHeader(name, value);
096   }
097
098   //-----------------------------------------------------------------------------------------------------------------
099   // Instance
100   //-----------------------------------------------------------------------------------------------------------------
101
102   private final Integer value;
103   private final Supplier<Integer> supplier;
104
105   /**
106    * Constructor.
107    *
108    * @param name The header name.
109    * @param value
110    *    The header value.
111    *    <br>Must be parsable using {@link Integer#parseInt(String)}.
112    *    <br>Can be <jk>null</jk>.
113    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
114    */
115   public BasicIntegerHeader(String name, String value) {
116      super(name, value);
117      this.value = parse(value);
118      this.supplier = null;
119   }
120
121   /**
122    * Constructor.
123    *
124    * @param name The header name.
125    * @param value
126    *    The header value.
127    *    <br>Can be <jk>null</jk>.
128    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
129    */
130   public BasicIntegerHeader(String name, Integer value) {
131      super(name, value);
132      this.value = value;
133      this.supplier = null;
134   }
135
136   /**
137    * Constructor with delayed value.
138    *
139    * <p>
140    * Header value is re-evaluated on each call to {@link #getValue()}.
141    *
142    * @param name The header name.
143    * @param value
144    *    The supplier of the header value.
145    *    <br>Can be <jk>null</jk>.
146    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
147    */
148   public BasicIntegerHeader(String name, Supplier<Integer> value) {
149      super(name, null);
150      this.value = null;
151      this.supplier = value;
152   }
153
154   @Override /* Header */
155   public String getValue() {
156      return stringify(value());
157   }
158
159   /**
160    * Returns the header value as an {@link Integer} wrapped in an {@link Optional}.
161    *
162    * @return The header value as an {@link Integer} wrapped in an {@link Optional}.  Never <jk>null</jk>.
163    */
164   public Optional<Integer> asInteger() {
165      return optional(value());
166   }
167
168   /**
169    * Returns the header value as an {@link Integer}.
170    *
171    * @return The header value as an {@link Integer}.  Can be <jk>null</jk>.
172    */
173   public Integer toInteger() {
174      return value();
175   }
176
177   /**
178    * Provides the ability to perform fluent-style assertions on this header.
179    *
180    * <h5 class='section'>Examples:</h5>
181    * <p class='bjava'>
182    *    <jc>// Validates the response content is older than 1.</jc>
183    *    <jv>client</jv>
184    *       .get(<jsf>URL</jsf>)
185    *       .run()
186    *       .getHeader(<js>"Age"</js>).asIntegerHeader().assertInteger().isGreaterThan(1);
187    * </p>
188    *
189    * @return A new fluent assertion object.
190    * @throws AssertionError If assertion failed.
191    */
192   public FluentIntegerAssertion<BasicIntegerHeader> assertInteger() {
193      return new FluentIntegerAssertion<>(value(), this);
194   }
195
196   /**
197    * Return the value if present, otherwise return <c>other</c>.
198    *
199    * <p>
200    * This is a shortened form for calling <c>asInteger().orElse(<jv>other</jv>)</c>.
201    *
202    * @param other The value to be returned if there is no value present, can be <jk>null</jk>.
203    * @return The value, if present, otherwise <c>other</c>.
204    */
205   public Integer orElse(Integer other) {
206      Integer x = value();
207      return x != null ? x : other;
208   }
209
210   private Integer parse(String value) {
211      try {
212         return value == null ? null : Integer.parseInt(value);
213      } catch (NumberFormatException e) {
214         throw new BasicRuntimeException("Value ''{0}'' could not be parsed as an integer.", value);
215      }
216   }
217
218   private Integer value() {
219      if (supplier != null)
220         return supplier.get();
221      return value;
222   }
223}