001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.http.header;
014
015import static org.apache.juneau.common.internal.StringUtils.*;
016import static org.apache.juneau.internal.CollectionUtils.*;
017
018import java.util.*;
019import java.util.function.*;
020
021import org.apache.juneau.*;
022import org.apache.juneau.assertions.*;
023import org.apache.juneau.http.annotation.*;
024import org.apache.juneau.internal.*;
025
026/**
027 * Represents a parsed <l>Client-Version</l> HTTP request header.
028 *
029 * <p>
030 * Specifies a client-side version number.
031 *
032 * <h5 class='figure'>Example</h5>
033 * <p class='bcode'>
034 *    Client-Version: 2.0.1
035 * </p>
036 *
037 * <p>
038 * Not part of the RFC2616 specification, but provided to allow for HTTP responses to be tailored to specified
039 * known client versions.
040 *
041 * <h5 class='section'>See Also:</h5><ul>
042 *    <li class='link'><a class="doclink" href="../../../../../index.html#juneau-rest-common">juneau-rest-common</a>
043 * </ul>
044 *
045 * @serial exclude
046 */
047@Header("Client-Version")
048public class ClientVersion extends BasicStringHeader {
049
050   //-----------------------------------------------------------------------------------------------------------------
051   // Static
052   //-----------------------------------------------------------------------------------------------------------------
053
054   private static final long serialVersionUID = 1L;
055   private static final String NAME = "Client-Version";
056
057   private static final Cache<String,ClientVersion> CACHE = Cache.of(String.class, ClientVersion.class).build();
058
059   /**
060    * Static creator.
061    *
062    * @param value
063    *    The header value.
064    *    <br>Must be parsable by {@link Version#of(String)}
065    *    <br>Can be <jk>null</jk>.
066    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
067    */
068   public static ClientVersion of(String value) {
069      return value == null ? null : CACHE.get(value, ()->new ClientVersion(value));
070   }
071
072   /**
073    * Static creator.
074    *
075    * @param value
076    *    The header value.
077    *    <br>Can be <jk>null</jk>.
078    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
079    */
080   public static ClientVersion of(Version value) {
081      return value == null ? null : new ClientVersion(value);
082   }
083
084   /**
085    * Static creator with delayed value.
086    *
087    * <p>
088    * Header value is re-evaluated on each call to {@link #getValue()}.
089    *
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    */
095   public static ClientVersion of(Supplier<Version> value) {
096      return value == null ? null : new ClientVersion(value);
097   }
098
099   //-----------------------------------------------------------------------------------------------------------------
100   // Instance
101   //-----------------------------------------------------------------------------------------------------------------
102
103   private final Version value;
104   private final Supplier<Version> supplier;
105
106   /**
107    * Constructor.
108    *
109    * @param value
110    *    The header value.
111    *    <br>Must be parsable by {@link Version#of(String)}
112    *    <br>Can be <jk>null</jk>.
113    */
114   public ClientVersion(String value) {
115      super(NAME, value);
116      this.value = Version.of(value);
117      this.supplier = null;
118   }
119
120   /**
121    * Constructor.
122    *
123    * @param value
124    *    The header value.
125    *    <br>Can be <jk>null</jk>.
126    */
127   public ClientVersion(Version value) {
128      super(NAME, stringify(value));
129      this.value = value;
130      this.supplier = null;
131   }
132
133   /**
134    * Constructor with delayed value.
135    *
136    * <p>
137    * Header value is re-evaluated on each call to {@link #getValue()}.
138    *
139    * @param value
140    *    The supplier of the header value.
141    *    <br>Can be <jk>null</jk>.
142    */
143   public ClientVersion(Supplier<Version> value) {
144      super(NAME, (String)null);
145      this.value = null;
146      this.supplier = value;
147   }
148
149   @Override /* Header */
150   public String getValue() {
151      if (supplier != null)
152         return stringify(supplier.get());
153      return super.getValue();
154   }
155
156   /**
157    * Returns the header value as a {@link Version} object.
158    *
159    * @return The header value as a {@link Version} object, or {@link Optional#empty()} if the value is <jk>null</jk>.
160    */
161   public Optional<Version> asVersion() {
162      return optional(value);
163   }
164
165   /**
166    * Provides the ability to perform fluent-style assertions on this header.
167    *
168    * <h5 class='section'>Examples:</h5>
169    * <p class='bjava'>
170    *    <jc>// Validates the response content is older than 1.</jc>
171    *    <jv>client</jv>
172    *       .get(<jsf>URL</jsf>)
173    *       .run()
174    *       .getHeader(ClientVersion.<jk>class</jk>).assertVersion().major().isGreaterThan(1);
175    * </p>
176    *
177    * @return A new fluent assertion object.
178    * @throws AssertionError If assertion failed.
179    */
180   public FluentVersionAssertion<ClientVersion> assertVersion() {
181      return new FluentVersionAssertion<>(asVersion().orElse(null), this);
182   }
183}