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