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