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 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/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 = "int64")
047public class BasicLongHeader 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>Must be parsable by {@link Long#parseLong(String)}.
057    *    <br>Can be <jk>null</jk>.
058    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
059    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
060    */
061   public static BasicLongHeader of(String name, Long value) {
062      return value == null ? null : new BasicLongHeader(name, value);
063   }
064
065   /**
066    * Static creator.
067    *
068    * @param name The header name.
069    * @param value
070    *    The header value.
071    *    <br>Must be parsable by {@link Long#parseLong(String)}.
072    *    <br>Can be <jk>null</jk>.
073    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
074    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
075    */
076   public static BasicLongHeader of(String name, String value) {
077      return value == null ? null : new BasicLongHeader(name, value);
078   }
079
080   /**
081    * Static creator with delayed value.
082    *
083    * <p>
084    * Header value is re-evaluated on each call to {@link #getValue()}.
085    *
086    * @param name The header name.
087    * @param value
088    *    The supplier of the header value.
089    *    <br>Can be <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 BasicLongHeader of(String name, Supplier<Long> value) {
094      return value == null ? null : new BasicLongHeader(name, value);
095   }
096
097   private final Long value;
098   private final Supplier<Long> supplier;
099
100   /**
101    * Constructor.
102    *
103    * @param name The header name.
104    * @param value
105    *    The header value.
106    *    <br>Can be <jk>null</jk>.
107    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
108    */
109   public BasicLongHeader(String name, Long value) {
110      super(name, value);
111      this.value = value;
112      this.supplier = null;
113   }
114
115   /**
116    * Constructor.
117    *
118    * @param name The header name.
119    * @param value
120    *    The header value.
121    *    <br>Must be parsable by {@link Long#parseLong(String)}.
122    *    <br>Can be <jk>null</jk>.
123    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
124    */
125   public BasicLongHeader(String name, String value) {
126      super(name, value);
127      this.value = parse(value);
128      this.supplier = null;
129   }
130
131   /**
132    * Constructor with delayed value.
133    *
134    * <p>
135    * Header value is re-evaluated on each call to {@link #getValue()}.
136    *
137    * @param name The header name.
138    * @param value
139    *    The supplier of the header value.
140    *    <br>Can be <jk>null</jk>.
141    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
142    */
143   public BasicLongHeader(String name, Supplier<Long> value) {
144      super(name, null);
145      this.value = null;
146      supplier = value;
147   }
148
149   /**
150    * Returns the header value as a {@link Long} wrapped in an {@link Optional}.
151    *
152    * @return The header value as a {@link Long} wrapped in an {@link Optional}.  Never <jk>null</jk>.
153    */
154   public Optional<Long> asLong() {
155      return opt(value());
156   }
157
158   /**
159    * Provides the ability to perform fluent-style assertions on this header.
160    *
161    * <h5 class='section'>Examples:</h5>
162    * <p class='bjava'>
163    *    <jc>// Validates the response body is not too large.</jc>
164    *    <jv>client</jv>
165    *       .get(<jsf>URL</jsf>)
166    *       .run()
167    *       .getHeader(<js>"Length"</js>).asLongHeader().assertLong().isLessThan(100000);
168    * </p>
169    *
170    * @return A new fluent assertion object.
171    * @throws AssertionError If assertion failed.
172    */
173   public FluentLongAssertion<BasicLongHeader> assertLong() {
174      return new FluentLongAssertion<>(value(), this);
175   }
176
177   @Override /* Overridden from Header */
178   public String getValue() { return s(value()); }
179
180   /**
181    * Return the value if present, otherwise return <c>other</c>.
182    *
183    * <p>
184    * This is a shortened form for calling <c>asLong().orElse(<jv>other</jv>)</c>.
185    *
186    * @param other The value to be returned if there is no value present, can be <jk>null</jk>.
187    * @return The value, if present, otherwise <c>other</c>.
188    */
189   public Long orElse(Long other) {
190      Long x = value();
191      return nn(x) ? x : other;
192   }
193
194   /**
195    * Returns the header value as a {@link Long}.
196    *
197    * @return The header value as a {@link Long}.  Can be <jk>null</jk>.
198    */
199   public Long toLong() {
200      return value();
201   }
202
203   private static Long parse(String value) {
204      try {
205         return value == null ? null : Long.parseLong(value);
206      } catch (NumberFormatException e) {
207         throw rex(e, "Value ''{0}'' could not be parsed as a long.", value);
208      }
209   }
210
211   private Long value() {
212      if (nn(supplier))
213         return supplier.get();
214      return value;
215   }
216}