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