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.*;
020
021import java.util.*;
022import java.util.function.*;
023
024import org.apache.juneau.commons.collections.*;
025import org.apache.juneau.commons.lang.*;
026import org.apache.juneau.http.*;
027import org.apache.juneau.bct.assertions.*;
028
029/**
030 * Represents a parsed <l>Client-Version</l> HTTP request header.
031 *
032 * <p>
033 * Specifies a client-side version number.
034 *
035 * <h5 class='figure'>Example</h5>
036 * <p class='bcode'>
037 *    Client-Version: 2.0.1
038 * </p>
039 *
040 * <p>
041 * Not part of the RFC2616 specification, but provided to allow for HTTP responses to be tailored to specified
042 * known client versions.
043 *
044 * <h5 class='section'>See Also:</h5><ul>
045 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommon">juneau-rest-common</a>
046 * </ul>
047 *
048 * @serial exclude
049 */
050@Header("Client-Version")
051@SuppressWarnings({
052   "java:S2160" // equals() inherited from BasicHeader compares name+value; no additional equality-relevant fields
053})
054public class ClientVersion extends BasicStringHeader {
055   private static final long serialVersionUID = 1L;
056   private static final String NAME = "Client-Version";
057
058   private static final Cache<String,ClientVersion> CACHE = Cache.of(String.class, ClientVersion.class).build();
059
060   /**
061    * Static creator.
062    *
063    * @param value
064    *    The header value.
065    *    <br>Must be parsable by {@link Version#of(String)}
066    *    <br>Can be <jk>null</jk>.
067    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
068    */
069   public static ClientVersion of(String value) {
070      return value == null ? null : CACHE.get(value, () -> new ClientVersion(value));
071   }
072
073   /**
074    * Static creator with delayed value.
075    *
076    * <p>
077    * Header value is re-evaluated on each call to {@link #getValue()}.
078    *
079    * @param value
080    *    The supplier of the header value.
081    *    <br>Can be <jk>null</jk>.
082    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
083    */
084   public static ClientVersion of(Supplier<Version> value) {
085      return value == null ? null : new ClientVersion(value);
086   }
087
088   /**
089    * Static creator.
090    *
091    * @param value
092    *    The header value.
093    *    <br>Can be <jk>null</jk>.
094    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
095    */
096   public static ClientVersion of(Version value) {
097      return value == null ? null : new ClientVersion(value);
098   }
099
100   private final transient Version value;
101   private final transient Supplier<Version> supplier;
102
103   /**
104    * Constructor.
105    *
106    * @param value
107    *    The header value.
108    *    <br>Must be parsable by {@link Version#of(String)}
109    *    <br>Can be <jk>null</jk> to create a header with no value.
110    */
111   public ClientVersion(String value) {
112      super(NAME, value);
113      this.value = Version.of(value);
114      this.supplier = null;
115   }
116
117   /**
118    * Constructor with delayed value.
119    *
120    * <p>
121    * Header value is re-evaluated on each call to {@link #getValue()}.
122    *
123    * @param value
124    *    The supplier of the header value.
125    *    <br>Can be <jk>null</jk> to create a header with no value.
126    */
127   public ClientVersion(Supplier<Version> value) {
128      super(NAME, (String)null);
129      this.value = null;
130      supplier = value;
131   }
132
133   /**
134    * Constructor.
135    *
136    * @param value
137    *    The header value.
138    *    <br>Can be <jk>null</jk> to create a header with no value.
139    */
140   public ClientVersion(Version value) {
141      super(NAME, s(value));
142      this.value = value;
143      this.supplier = null;
144   }
145
146   /**
147    * Provides the ability to perform fluent-style assertions on this header.
148    *
149    * <h5 class='section'>Examples:</h5>
150    * <p class='bjava'>
151    *    <jc>// Validates the response content is older than 1.</jc>
152    *    <jv>client</jv>
153    *       .get(<jsf>URL</jsf>)
154    *       .run()
155    *       .getHeader(ClientVersion.<jk>class</jk>).assertVersion().major().isGreaterThan(1);
156    * </p>
157    *
158    * @return A new fluent assertion object.
159    * @throws AssertionError If assertion failed.
160    */
161   public FluentVersionAssertion<ClientVersion> assertVersion() {
162      return new FluentVersionAssertion<>(asVersion().orElse(null), this);
163   }
164
165   /**
166    * Returns the header value as a {@link Version} object.
167    *
168    * @return The header value as a {@link Version} object, or {@link Optional#empty()} if the value is <jk>null</jk>.
169    */
170   public Optional<Version> asVersion() {
171      return o(value);
172   }
173
174   @Override /* Overridden from Header */
175   public String getValue() {
176      if (nn(supplier))
177         return s(supplier.get());
178      return super.getValue();
179   }
180}