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