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