0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 package org.apache.spark.sql.util;
0019
0020 import org.apache.spark.annotation.Experimental;
0021 import org.slf4j.Logger;
0022 import org.slf4j.LoggerFactory;
0023
0024 import java.util.Collection;
0025 import java.util.Collections;
0026 import java.util.HashMap;
0027 import java.util.Locale;
0028 import java.util.Map;
0029 import java.util.Objects;
0030 import java.util.Set;
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 @Experimental
0043 public class CaseInsensitiveStringMap implements Map<String, String> {
0044 private final Logger logger = LoggerFactory.getLogger(CaseInsensitiveStringMap.class);
0045
0046 private String unsupportedOperationMsg = "CaseInsensitiveStringMap is read-only.";
0047
0048 public static CaseInsensitiveStringMap empty() {
0049 return new CaseInsensitiveStringMap(new HashMap<>(0));
0050 }
0051
0052 private final Map<String, String> original;
0053
0054 private final Map<String, String> delegate;
0055
0056 public CaseInsensitiveStringMap(Map<String, String> originalMap) {
0057 original = new HashMap<>(originalMap);
0058 delegate = new HashMap<>(originalMap.size());
0059 for (Map.Entry<String, String> entry : originalMap.entrySet()) {
0060 String key = toLowerCase(entry.getKey());
0061 if (delegate.containsKey(key)) {
0062 logger.warn("Converting duplicated key " + entry.getKey() +
0063 " into CaseInsensitiveStringMap.");
0064 }
0065 delegate.put(key, entry.getValue());
0066 }
0067 }
0068
0069 @Override
0070 public int size() {
0071 return delegate.size();
0072 }
0073
0074 @Override
0075 public boolean isEmpty() {
0076 return delegate.isEmpty();
0077 }
0078
0079 private String toLowerCase(Object key) {
0080 return key.toString().toLowerCase(Locale.ROOT);
0081 }
0082
0083 @Override
0084 public boolean containsKey(Object key) {
0085 return delegate.containsKey(toLowerCase(key));
0086 }
0087
0088 @Override
0089 public boolean containsValue(Object value) {
0090 return delegate.containsValue(value);
0091 }
0092
0093 @Override
0094 public String get(Object key) {
0095 return delegate.get(toLowerCase(key));
0096 }
0097
0098 @Override
0099 public String put(String key, String value) {
0100 throw new UnsupportedOperationException(unsupportedOperationMsg);
0101 }
0102
0103 @Override
0104 public String remove(Object key) {
0105 throw new UnsupportedOperationException(unsupportedOperationMsg);
0106 }
0107
0108 @Override
0109 public void putAll(Map<? extends String, ? extends String> m) {
0110 throw new UnsupportedOperationException(unsupportedOperationMsg);
0111 }
0112
0113 @Override
0114 public void clear() {
0115 throw new UnsupportedOperationException(unsupportedOperationMsg);
0116 }
0117
0118 @Override
0119 public Set<String> keySet() {
0120 return delegate.keySet();
0121 }
0122
0123 @Override
0124 public Collection<String> values() {
0125 return delegate.values();
0126 }
0127
0128 @Override
0129 public Set<Map.Entry<String, String>> entrySet() {
0130 return delegate.entrySet();
0131 }
0132
0133
0134
0135
0136
0137 public boolean getBoolean(String key, boolean defaultValue) {
0138 String value = get(key);
0139
0140 if (value == null) {
0141 return defaultValue;
0142 } else if (value.equalsIgnoreCase("true")) {
0143 return true;
0144 } else if (value.equalsIgnoreCase("false")) {
0145 return false;
0146 } else {
0147 throw new IllegalArgumentException(value + " is not a boolean string.");
0148 }
0149 }
0150
0151
0152
0153
0154
0155 public int getInt(String key, int defaultValue) {
0156 String value = get(key);
0157 return value == null ? defaultValue : Integer.parseInt(value);
0158 }
0159
0160
0161
0162
0163
0164 public long getLong(String key, long defaultValue) {
0165 String value = get(key);
0166 return value == null ? defaultValue : Long.parseLong(value);
0167 }
0168
0169
0170
0171
0172
0173 public double getDouble(String key, double defaultValue) {
0174 String value = get(key);
0175 return value == null ? defaultValue : Double.parseDouble(value);
0176 }
0177
0178
0179
0180
0181 public Map<String, String> asCaseSensitiveMap() {
0182 return Collections.unmodifiableMap(original);
0183 }
0184
0185 @Override
0186 public boolean equals(Object o) {
0187 if (this == o) {
0188 return true;
0189 }
0190 if (o == null || getClass() != o.getClass()) {
0191 return false;
0192 }
0193 CaseInsensitiveStringMap that = (CaseInsensitiveStringMap) o;
0194 return delegate.equals(that.delegate);
0195 }
0196
0197 @Override
0198 public int hashCode() {
0199 return Objects.hash(delegate);
0200 }
0201 }