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.Shorts.*; 020import static org.apache.juneau.commons.utils.StringUtils.*; 021 022import java.util.*; 023import java.util.function.*; 024 025/** 026 * An {@link org.apache.juneau.http.HttpPart} whose value is a comma-delimited list of strings. 027 * 028 * <p> 029 * Mirrors the semantics of {@code BasicCsvArrayPart} from {@code juneau-rest-common-classic} without 030 * the Apache HttpCore dependency. 031 * 032 * @since 10.0.0 033 */ 034@SuppressWarnings({ 035 "java:S2160" // Equality is fully determined by name + getValue() in HttpPartBean; the typed fields are derived from the wire value and add no state to compare 036}) 037public class HttpCsvArrayPart extends HttpPartBean { 038 039 private static final String[] EMPTY = {}; 040 041 /** 042 * Creates an {@link HttpCsvArrayPart} with the given name and array value. 043 * 044 * @param name The part name. Must not be <jk>null</jk>. 045 * @param value The array of values. May be <jk>null</jk>. 046 * @return A new instance. Never <jk>null</jk>. 047 */ 048 public static HttpCsvArrayPart of(String name, String...value) { 049 return new HttpCsvArrayPart(name, value); 050 } 051 052 /** 053 * Creates an {@link HttpCsvArrayPart} by parsing the given comma-delimited wire value. 054 * 055 * @param name The part name. Must not be <jk>null</jk>. 056 * @param value The wire value. May be <jk>null</jk> or empty. 057 * @return A new instance. Never <jk>null</jk>. 058 */ 059 public static HttpCsvArrayPart ofString(String name, String value) { 060 return new HttpCsvArrayPart(name, value); 061 } 062 063 /** 064 * Creates an {@link HttpCsvArrayPart} with a lazy array supplier. 065 * 066 * @param name The part name. Must not be <jk>null</jk>. 067 * @param supplier Supplier for the array value. Must not be <jk>null</jk>. 068 * @return A new instance. Never <jk>null</jk>. 069 */ 070 public static HttpCsvArrayPart ofLazy(String name, Supplier<String[]> supplier) { 071 return new HttpCsvArrayPart(name, supplier); 072 } 073 074 private final String[] typedValue; 075 private final Supplier<String[]> typedSupplier; 076 077 /** 078 * Constructor accepting an array of values. 079 * 080 * @param name The part name. Must not be <jk>null</jk>. 081 * @param value The array of values. May be <jk>null</jk>. 082 */ 083 public HttpCsvArrayPart(String name, String...value) { 084 super(name, value == null ? null : join(value, ',')); 085 this.typedValue = cp(value); 086 this.typedSupplier = null; 087 } 088 089 /** 090 * Constructor accepting a comma-delimited wire string. 091 * 092 * @param name The part name. Must not be <jk>null</jk>. 093 * @param value The wire value. May be <jk>null</jk> or empty. 094 */ 095 public HttpCsvArrayPart(String name, String value) { 096 super(name, value); 097 this.typedValue = splita(value); 098 this.typedSupplier = null; 099 } 100 101 /** 102 * Constructor accepting a lazy supplier of array values. 103 * 104 * @param name The part name. Must not be <jk>null</jk>. 105 * @param supplier Supplier for the array value. Must not be <jk>null</jk>. 106 */ 107 public HttpCsvArrayPart(String name, Supplier<String[]> supplier) { 108 super(name, () -> { 109 var v = supplier.get(); 110 return v == null ? null : join(v, ','); 111 }); 112 this.typedValue = null; 113 this.typedSupplier = supplier; 114 } 115 116 /** 117 * Returns the value as a copy of the underlying array, wrapped in an {@link Optional}. 118 * 119 * @return The array value, wrapped in an {@link Optional}. Never <jk>null</jk>. 120 */ 121 public Optional<String[]> asArray() { 122 return o(toArray()); 123 } 124 125 /** 126 * Returns the value as an unmodifiable {@link List}, wrapped in an {@link Optional}. 127 * 128 * @return The list value, wrapped in an {@link Optional}. Never <jk>null</jk>. 129 */ 130 public Optional<List<String>> asList() { 131 return o(toList()); 132 } 133 134 /** 135 * Returns {@code true} if this part contains the given value (case-sensitive). 136 * 137 * @param val The value to check for. 138 * @return {@code true} if the value is present. 139 */ 140 public boolean contains(String val) { 141 if (val == null) 142 return false; 143 var arr = value(); 144 if (arr == null) 145 return false; 146 for (var v : arr) 147 if (eq(v, val)) 148 return true; 149 return false; 150 } 151 152 /** 153 * Returns {@code true} if this part contains the given value (case-insensitive). 154 * 155 * @param val The value to check for. 156 * @return {@code true} if the value is present. 157 */ 158 public boolean containsIgnoreCase(String val) { 159 if (val == null) 160 return false; 161 var arr = value(); 162 if (arr == null) 163 return false; 164 for (var v : arr) 165 if (eqic(v, val)) 166 return true; 167 return false; 168 } 169 170 /** 171 * Returns a copy of the underlying array, or {@code null} if not set. 172 * 173 * @return The array, possibly {@code null}. 174 */ 175 public String[] toArray() { 176 return cp(value()); 177 } 178 179 /** 180 * Returns the value as an unmodifiable {@link List}, or {@code null} if not set. 181 * 182 * @return The list, possibly {@code null}. 183 */ 184 public List<String> toList() { 185 return u(l(value())); 186 } 187 188 /** 189 * Returns the value if present, otherwise returns {@code other}. 190 * 191 * @param other The default value. 192 * @return The value or {@code other}. 193 */ 194 public String[] orElse(String[] other) { 195 var x = value(); 196 return nn(x) ? cp(x) : other; 197 } 198 199 private String[] value() { 200 if (typedSupplier != null) { 201 var v = typedSupplier.get(); 202 return v == null ? EMPTY : v; 203 } 204 return typedValue; 205 } 206}