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 (the 006 * "License"); you may not use this file except in compliance with the 007 * 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 019 020import static org.apache.juneau.commons.utils.Shorts.*; 021import static org.apache.juneau.commons.utils.StringUtils.*; 022 023import java.util.*; 024import java.util.function.*; 025 026/** 027 * Base for simple comma-separated token lists. 028 * 029 * @since 9.2.1 030 */ 031@SuppressWarnings({ 032 "java:S2160", // equals() on HttpHeaderBean uses name + getValue(); typed state is reflected in getValue() 033 "java:S9149", // Public Juneau DSL factory; hiding parent of()/create() is intentional. 034 "unchecked" // Supplier<?> branches cast to typed suppliers after lazy-mode check 035}) 036public class HttpCsvHeader extends HttpHeaderBean { 037 038 public static final int LAZY_WIRE_STRING = 0; 039 public static final int LAZY_TOKENS = 1; 040 041 private final String[] eagerTokens; 042 private final Supplier<?> lazySupplier; 043 private final int lazyMode; 044 045 /** 046 * Creates an {@link HttpCsvHeader} by parsing the given comma-delimited wire value. 047 * 048 * @param name Header name. Must not be {@code null}. 049 * @param wireValue Wire value. May be {@code null} or empty. 050 * @return A new instance. Never {@code null}. 051 */ 052 public static HttpCsvHeader of(String name, String wireValue) { 053 return new HttpCsvHeader(name, wireValue); 054 } 055 056 /** 057 * Creates an {@link HttpCsvHeader} with the given typed values. 058 * 059 * @param name Header name. Must not be {@code null}. 060 * @param typedValues The token values. May be {@code null}. 061 * @return A new instance. Never {@code null}. 062 */ 063 public static HttpCsvHeader of(String name, String...typedValues) { 064 return new HttpCsvHeader(name, typedValues); 065 } 066 067 /** 068 * Constructor. 069 * 070 * @param name Header name. Must not be <jk>null</jk>. 071 * @param value Wire value. Can be <jk>null</jk> or empty, in which case the parsed tokens are <jk>null</jk>. 072 */ 073 protected HttpCsvHeader(String name, String value) { 074 super(name, value); 075 this.eagerTokens = null; 076 this.lazySupplier = null; 077 this.lazyMode = -1; 078 } 079 080 /** 081 * Constructor. 082 * 083 * @param name Header name. Must not be <jk>null</jk>. 084 * @param values The token values. Can be <jk>null</jk>, in which case the parsed tokens are <jk>null</jk>. 085 */ 086 protected HttpCsvHeader(String name, String... values) { 087 super(name, values == null || values.length == 0 ? null : join(values, ", ")); 088 this.eagerTokens = values == null ? null : cp(values); 089 this.lazySupplier = null; 090 this.lazyMode = -1; 091 } 092 093 /** 094 * Constructor with lazy value supplier. 095 * 096 * @param name Header name. Must not be <jk>null</jk>. 097 * @param supplier The lazy value supplier. Must not be <jk>null</jk>. 098 * @param lazyMode Either {@link #LAZY_WIRE_STRING} or {@link #LAZY_TOKENS}. 099 */ 100 protected HttpCsvHeader(String name, Supplier<?> supplier, int lazyMode) { 101 super(name, lazyMode == LAZY_WIRE_STRING 102 ? ((Supplier<String>) supplier)::get 103 : () -> { 104 var t = ((Supplier<String[]>) supplier).get(); 105 if (t == null) 106 return null; 107 return join(t, ", "); 108 }); 109 this.eagerTokens = null; 110 this.lazySupplier = supplier; 111 this.lazyMode = lazyMode; 112 } 113 114 public Optional<String[]> asArray() { 115 return o(cp(csvTokens())); 116 } 117 118 public Optional<List<String>> asList() { 119 return o(u(l(csvTokens()))); 120 } 121 122 public boolean contains(String val) { 123 var t = csvTokens(); 124 if (t == null) 125 return false; 126 for (var v : t) 127 if (eq(v, val)) 128 return true; 129 return false; 130 } 131 132 public boolean containsIgnoreCase(String val) { 133 var t = csvTokens(); 134 if (t == null) 135 return false; 136 for (var v : t) 137 if (eqic(v, val)) 138 return true; 139 return false; 140 } 141 142 /** 143 * Returns the comma-delimited wire-format value of this header. 144 * 145 * @return The wire value, or <jk>null</jk> if the value is unset. 146 */ 147 @Override 148 public String getValue() { 149 var t = csvTokens(); 150 return t == null ? null : join(t, ", "); 151 } 152 153 /** 154 * Returns the parsed tokens of this header, or the specified default if unset. 155 * 156 * @param other The default value. Can be <jk>null</jk> to allow a <jk>null</jk> result when the header is unset. 157 * @return The parsed tokens, or <c>other</c> if the value is unset. Can be <jk>null</jk> if <c>other</c> is <jk>null</jk>. 158 */ 159 public String[] orElse(String[] other) { 160 var x = csvTokens(); 161 return nn(x) ? cp(x) : other; 162 } 163 164 /** 165 * Returns the parsed tokens of this header. 166 * 167 * @return The parsed tokens, or <jk>null</jk> if the value is unset. 168 */ 169 public String[] toArray() { 170 return cp(csvTokens()); 171 } 172 173 public List<String> toList() { 174 return u(l(csvTokens())); 175 } 176 177 private String[] csvTokens() { 178 if (lazyMode == LAZY_TOKENS) 179 return ((Supplier<String[]>) lazySupplier).get(); 180 if (eagerTokens != null) 181 return eagerTokens; 182 return splita(super.getValue()); 183 } 184}