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.CollectionUtils.*;
020import static org.apache.juneau.commons.utils.StringUtils.*;
021import static org.apache.juneau.commons.utils.Utils.*;
022
023import java.util.*;
024import java.util.function.*;
025
026import org.apache.juneau.assertions.*;
027
028/**
029 * Category of headers that consist of a comma-delimited list of string values.
030 *
031 * <p>
032 * <h5 class='figure'>Example</h5>
033 * <p class='bcode'>
034 *    Allow: GET, PUT
035 * </p>
036 *
037 * <h5 class='section'>See Also:</h5><ul>
038 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a>
039 *    <li class='extlink'><a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616.html">Hypertext Transfer Protocol -- HTTP/1.1</a>
040 * </ul>
041 *
042 * @serial exclude
043 */
044public class BasicCsvHeader extends BasicHeader {
045   private static final long serialVersionUID = 1L;
046
047   /**
048    * Static creator.
049    *
050    * @param name The header name.
051    * @param value
052    *    The header value.
053    *    <br>Must be a comma-delimited list.
054    *    <br>Can be <jk>null</jk>.
055    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
056    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
057    */
058   public static BasicCsvHeader of(String name, String value) {
059      return value == null ? null : new BasicCsvHeader(name, value);
060   }
061
062   /**
063    * Static creator.
064    *
065    * @param name The header name.
066    * @param value
067    *    The header value.
068    *    <br>Can be <jk>null</jk>.
069    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
070    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
071    */
072   public static BasicCsvHeader of(String name, String...value) {
073      return value == null ? null : new BasicCsvHeader(name, value);
074   }
075
076   /**
077    * Static creator with delayed value.
078    *
079    * <p>
080    * Header value is re-evaluated on each call to {@link #getValue()}.
081    *
082    * @param name The header name.
083    * @param value
084    *    The supplier of the header value.
085    *    <br>Can be <jk>null</jk>.
086    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
087    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
088    */
089   public static BasicCsvHeader of(String name, Supplier<String[]> value) {
090      return value == null ? null : new BasicCsvHeader(name, value);
091   }
092
093   private final String[] value;
094   private final Supplier<String[]> supplier;
095
096   /**
097    * Constructor.
098    *
099    * @param name The header name.
100    * @param value
101    *    The header value.
102    *    <br>Must be a comma-delimited list.
103    *    <br>Can be <jk>null</jk>.
104    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
105    */
106   public BasicCsvHeader(String name, String value) {
107      super(name, value);
108      this.value = splita(value);
109      this.supplier = null;
110   }
111
112   /**
113    * Constructor.
114    *
115    * @param name The header name.
116    * @param value
117    *    The header value.
118    *    <br>Can be <jk>null</jk>.
119    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
120    */
121   public BasicCsvHeader(String name, String...value) {
122      super(name, join(value, ", "));
123      this.value = copyOf(value);
124      this.supplier = null;
125   }
126
127   /**
128    * Constructor with delayed value.
129    *
130    * <p>
131    * Header value is re-evaluated on each call to {@link #getValue()}.
132    *
133    * @param name The header name.
134    * @param value
135    *    The supplier of the header value.
136    *    <br>Can be <jk>null</jk>.
137    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
138    */
139   public BasicCsvHeader(String name, Supplier<String[]> value) {
140      super(name, null);
141      this.value = null;
142      supplier = value;
143   }
144
145   /**
146    * Returns the header value as an array wrapped in an {@link Optional}.
147    *
148    * <p>
149    * The array is a copy of the value of this header.
150    *
151    * @return The header value as an array wrapped in an {@link Optional}.  Never <jk>null</jk>.
152    */
153   public Optional<String[]> asArray() {
154      return opt(copyOf(value()));
155   }
156
157   /**
158    * Returns the header value as a list wrapped in an {@link Optional}.
159    *
160    * <p>
161    * The list is unmodifiable.
162    *
163    * @return The header value as a list wrapped in an {@link Optional}.  Never <jk>null</jk>.
164    */
165   public Optional<List<String>> asList() {
166      return opt(u(l(value())));
167   }
168
169   /**
170    * Provides the ability to perform fluent-style assertions on this header.
171    *
172    * @return A new fluent assertion object.
173    * @throws AssertionError If assertion failed.
174    */
175   public FluentListAssertion<String,BasicCsvHeader> assertList() {
176      return new FluentListAssertion<>(u(l(value())), this);
177   }
178
179   /**
180    * Returns <jk>true</jk> if this header contains the specified value.
181    *
182    * @param val The value to check for.
183    * @return <jk>true</jk> if this header contains the specified value.
184    */
185   public boolean contains(String val) {
186      if (nn(value))
187         for (var v : value)
188            if (eq(v, val))
189               return true;
190      if (nn(supplier)) {
191         String[] value2 = supplier.get();
192         if (nn(value2))
193            for (var v : supplier.get())
194               if (eq(v, val))
195                  return true;
196
197      }
198      return false;
199   }
200
201   /**
202    * Returns <jk>true</jk> if this header contains the specified value using {@link String#equalsIgnoreCase(String)}.
203    *
204    * @param val The value to check for.
205    * @return <jk>true</jk> if this header contains the specified value.
206    */
207   public boolean containsIgnoreCase(String val) {
208      if (nn(value))
209         for (var v : value)
210            if (eqic(v, val))
211               return true;
212      if (nn(supplier)) {
213         String[] value2 = supplier.get();
214         if (nn(value2))
215            for (var v : supplier.get())
216               if (eqic(v, val))
217                  return true;
218      }
219      return false;
220   }
221
222   @Override /* Overridden from Header */
223   public String getValue() { return join(value(), ", "); }
224
225   /**
226    * Return the value if present, otherwise return <c>other</c>.
227    *
228    * <p>
229    * This is a shortened form for calling <c>asArray().orElse(<jv>other</jv>)</c>.
230    *
231    * @param other The value to be returned if there is no value present, can be <jk>null</jk>.
232    * @return The value, if present, otherwise <c>other</c>.
233    */
234   public String[] orElse(String[] other) {
235      String[] x = value();
236      return nn(x) ? x : other;
237   }
238
239   /**
240    * Returns the header value as an array.
241    *
242    * <p>
243    * The array is a copy of the value of this header.
244    *
245    * @return The header value as an array.  Can be <jk>null</jk>.
246    */
247   public String[] toArray() {
248      return copyOf(value());
249   }
250
251   /**
252    * Returns the header value as a list.
253    *
254    * <p>
255    * The list is unmodifiable.
256    *
257    * @return The header value as a list.  Can be <jk>null</jk>.
258    */
259   public List<String> toList() {
260      return u(l(value()));
261   }
262
263   private String[] value() {
264      if (nn(supplier))
265         return supplier.get();
266      return value;
267   }
268}