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.part;
014
015import static org.apache.juneau.common.internal.StringUtils.*;
016import static org.apache.juneau.internal.ArrayUtils.copyOf;
017import static org.apache.juneau.internal.CollectionUtils.*;
018
019import java.util.*;
020import java.util.function.*;
021
022import org.apache.http.*;
023import org.apache.juneau.assertions.*;
024
025/**
026 * A {@link NameValuePair} that consists of a comma-delimited list of string values.
027 *
028 * <h5 class='section'>See Also:</h5><ul>
029 *    <li class='link'><a class="doclink" href="../../../../../index.html#juneau-rest-common">juneau-rest-common</a>
030 * </ul>
031 */
032public class BasicCsvArrayPart extends BasicPart {
033
034   //-----------------------------------------------------------------------------------------------------------------
035   // Static
036   //-----------------------------------------------------------------------------------------------------------------
037
038   private static final String[] EMPTY = new String[0];
039
040   /**
041    * Static creator.
042    *
043    * @param name The part name.
044    * @param value The part value.
045    * @return A new {@link BasicCsvArrayPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
046    */
047   public static BasicCsvArrayPart of(String name, String...value) {
048      if (isEmpty(name) || value == null)
049         return null;
050      return new BasicCsvArrayPart(name, value);
051   }
052
053   /**
054    * Static creator with delayed value.
055    *
056    * <p>
057    * Part value is re-evaluated on each call to {@link NameValuePair#getValue()}.
058    *
059    * @param name The part name.
060    * @param value The part value supplier.
061    * @return A new {@link BasicCsvArrayPart} object, or <jk>null</jk> if the name or supplier is <jk>null</jk>.
062    */
063   public static BasicCsvArrayPart of(String name, Supplier<String[]> value) {
064      if (isEmpty(name) || value == null)
065         return null;
066      return new BasicCsvArrayPart(name, value);
067   }
068
069   //-----------------------------------------------------------------------------------------------------------------
070   // Instance
071   //-----------------------------------------------------------------------------------------------------------------
072
073   private final String[] value;
074   private final Supplier<String[]> supplier;
075   private String stringValue;
076
077   /**
078    * Constructor.
079    *
080    * @param name The part name.  Must not be <jk>null</jk>.
081    * @param value The part value.  Can be <jk>null</jk>.
082    */
083   public BasicCsvArrayPart(String name, String...value) {
084      super(name, value);
085      this.value = value;
086      this.supplier = null;
087      this.stringValue = null;
088   }
089
090   /**
091    * Constructor.
092    *
093    * @param name The part name.  Must not be <jk>null</jk>.
094    * @param value The part value supplier.  Can be <jk>null</jk> or supply <jk>null</jk>.
095    */
096   public BasicCsvArrayPart(String name, Supplier<String[]> value) {
097      super(name, value);
098      this.value = null;
099      this.supplier = value;
100      this.stringValue = null;
101   }
102
103   /**
104    * Constructor.
105    *
106    * <p>
107    * <jk>null</jk> values are treated as <jk>null</jk>.
108    * Otherwise parses as a comma-delimited list with whitespace trimmed.
109    *
110    * @param name The part name.  Must not be <jk>null</jk>.
111    * @param value The part value.  Can be <jk>null</jk>.
112    */
113   public BasicCsvArrayPart(String name, String value) {
114      super(name, value);
115      this.value = split(value);
116      this.supplier = null;
117      this.stringValue = value;
118   }
119
120   @Override /* Header */
121   public String getValue() {
122      if (supplier != null)
123         return join(supplier.get(), ',');
124      if (stringValue != null)
125         stringValue = join(value, ',');
126      return stringValue;
127   }
128
129   /**
130    * Returns <jk>true</jk> if this part contains the specified value.
131    *
132    * @param val The value to check for.
133    * @return <jk>true</jk> if this part contains the specified value.
134    */
135   public boolean contains(String val) {
136      if (val != null)
137         for (String v : value())
138            if (eq(v, val))
139               return true;
140      return false;
141   }
142
143   /**
144    * Returns <jk>true</jk> if this part contains the specified value using {@link String#equalsIgnoreCase(String)}.
145    *
146    * @param val The value to check for.
147    * @return <jk>true</jk> if this part contains the specified value.
148    */
149   public boolean containsIgnoreCase(String val) {
150      if (val != null)
151         for (String v : value())
152            if (eqic(v, val))
153               return true;
154      return false;
155   }
156
157   /**
158    * Provides the ability to perform fluent-style assertions on this part.
159    *
160    * @return A new fluent assertion object.
161    * @throws AssertionError If assertion failed.
162    */
163   public FluentListAssertion<String,BasicCsvArrayPart> assertList() {
164      return new FluentListAssertion<>(ulist(value()), this);
165   }
166
167   /**
168    * Returns The part value as a {@link List}.
169    *
170    * <p>
171    * The list is unmodifiable.
172    *
173    * @return The part value as a {@link List}, or <jk>null</jk> if the value <jk>null</jk>.
174    */
175   public List<String> toList() {
176      return ulist(value());
177   }
178
179   /**
180    * Returns The part value as a {@link List} wrapped in an {@link Optional}.
181    *
182    * <p>
183    * The list is unmodifiable.
184    *
185    * @return The part value as a {@link List} wrapped in an {@link Optional}.  Never <jk>null</jk>.
186    */
187   public Optional<List<String>> asList() {
188      return optional(toList());
189   }
190
191   /**
192    * Returns The part value as an array.
193    *
194    * <p>
195    * The array is a copy of the value of this part.
196    *
197    * @return The part value as an array, or <jk>null</jk> if the value <jk>null</jk>.
198    */
199   public String[] toArray() {
200      return copyOf(value());
201   }
202
203   /**
204    * Returns The part value as an array wrapped in an {@link Optional}.
205    *
206    * <p>
207    * Array is a copy of the value of this part.
208    *
209    * @return The part value as an array wrapped in an {@link Optional}.  Never <jk>null</jk>.
210    */
211   public Optional<String[]> asArray() {
212      return optional(copyOf(value()));
213   }
214
215   /**
216    * Return the value if present, otherwise return <c>other</c>.
217    *
218    * <p>
219    * This is a shortened form for calling <c>asArray().orElse(<jv>other</jv>)</c>.
220    *
221    * @param other The value to be returned if there is no value present, can be <jk>null</jk>.
222    * @return The value, if present, otherwise <c>other</c>.
223    */
224   public String[] orElse(String[] other) {
225      String[] x = value();
226      return x != null ? x : other;
227   }
228
229   private String[] value() {
230      if (supplier != null) {
231         String[] v = supplier.get();
232         return v != null ? v : EMPTY;
233      }
234      return value;
235   }
236}