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.classic.header;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020import static org.apache.juneau.commons.utils.StringUtils.*;
021
022import java.util.*;
023import java.util.function.*;
024
025import org.apache.juneau.commons.*;
026import org.apache.juneau.http.*;
027import org.apache.juneau.bct.assertions.*;
028
029/**
030 * Category of headers that consist of a single long value.
031 *
032 * <p>
033 * <h5 class='figure'>Example</h5>
034 * <p class='bcode'>
035 *    Content-Length: 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/JuneauRestCommon">juneau-rest-common</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 = "int64")
047@SuppressWarnings({
048   "java:S2160" // equals() inherited from BasicHeader compares name+value; typed Long field is accessed via getValue()
049})
050public class BasicLongHeader extends BasicHeader {
051   private static final long serialVersionUID = 1L;
052
053   /**
054    * Static creator.
055    *
056    * @param name The header name.
057    * @param value
058    *    The header value.
059    *    <br>Must be parsable by {@link Long#parseLong(String)}.
060    *    <br>Can be <jk>null</jk>.
061    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
062    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
063    */
064   public static BasicLongHeader of(String name, Long value) {
065      return value == null ? null : new BasicLongHeader(name, value);
066   }
067
068   /**
069    * Static creator.
070    *
071    * @param name The header name.
072    * @param value
073    *    The header value.
074    *    <br>Must be parsable by {@link Long#parseLong(String)}.
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 BasicLongHeader of(String name, String value) {
080      return value == null ? null : new BasicLongHeader(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 BasicLongHeader of(String name, Supplier<Long> value) {
097      return value == null ? null : new BasicLongHeader(name, value);
098   }
099
100   private final Long value;
101   private final transient Supplier<Long> supplier;
102
103   /**
104    * Constructor.
105    *
106    * @param name The header name.
107    * @param value
108    *    The header value.
109    *    <br>Can be <jk>null</jk> to create a header with no value.
110    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
111    */
112   public BasicLongHeader(String name, Long value) {
113      super(name, value);
114      this.value = value;
115      this.supplier = null;
116   }
117
118   /**
119    * Constructor.
120    *
121    * @param name The header name.
122    * @param value
123    *    The header value.
124    *    <br>Must be parsable by {@link Long#parseLong(String)}.
125    *    <br>Can be <jk>null</jk> to create a header with no value.
126    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
127    */
128   public BasicLongHeader(String name, String value) {
129      super(name, value);
130      this.value = parse(value);
131      this.supplier = null;
132   }
133
134   /**
135    * Constructor with delayed value.
136    *
137    * <p>
138    * Header value is re-evaluated on each call to {@link #getValue()}.
139    *
140    * @param name The header name.
141    * @param value
142    *    The supplier of the header value.
143    *    <br>Can be <jk>null</jk> to create a header with no value.
144    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
145    */
146   public BasicLongHeader(String name, Supplier<Long> value) {
147      super(name, null);
148      this.value = null;
149      supplier = value;
150   }
151
152   /**
153    * Returns the header value as a {@link Long} wrapped in an {@link Optional}.
154    *
155    * @return The header value as a {@link Long} wrapped in an {@link Optional}.  Never <jk>null</jk>.
156    */
157   public Optional<Long> asLong() {
158      return o(value());
159   }
160
161   /**
162    * Provides the ability to perform fluent-style assertions on this header.
163    *
164    * <h5 class='section'>Examples:</h5>
165    * <p class='bjava'>
166    *    <jc>// Validates the response body is not too large.</jc>
167    *    <jv>client</jv>
168    *       .get(<jsf>URL</jsf>)
169    *       .run()
170    *       .getHeader(<js>"Length"</js>).asLongHeader().assertLong().isLessThan(100000);
171    * </p>
172    *
173    * @return A new fluent assertion object.
174    * @throws AssertionError If assertion failed.
175    */
176   public FluentLongAssertion<BasicLongHeader> assertLong() {
177      return new FluentLongAssertion<>(value(), this);
178   }
179
180   @Override /* Overridden from Header */
181   public String getValue() { return s(value()); }
182
183   /**
184    * Return the value if present, otherwise return <c>other</c>.
185    *
186    * <p>
187    * This is a shortened form for calling <c>asLong().orElse(<jv>other</jv>)</c>.
188    *
189    * @param other The value to be returned if there is no value present, can be <jk>null</jk>.
190    * @return The value, if present, otherwise <c>other</c>.
191    */
192   public Long orElse(Long other) {
193      Long x = value();
194      return nn(x) ? x : other;
195   }
196
197   /**
198    * Returns the header value as a {@link Long}.
199    *
200    * @return The header value as a {@link Long}, or <jk>null</jk> if the header has no value.
201    */
202   public Long toLong() {
203      return value();
204   }
205
206   private static Long parse(String value) {
207      if (value == null)
208         return null;
209      return parseLong(value, () -> iaex("Value '%s' could not be parsed as a long.", value));
210   }
211
212   private Long value() {
213      if (nn(supplier))
214         return supplier.get();
215      return value;
216   }
217}