View Javadoc
1   /*
2    * Copyright 2002-2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.foxinmy.weixin4j.util;
18  
19  import java.util.HashMap;
20  import java.util.LinkedHashMap;
21  import java.util.Locale;
22  import java.util.Map;
23  
24  /**
25   * {@link LinkedHashMap} variant that stores String keys in a case-insensitive
26   * manner, for example for key-based access in a results table.
27   *
28   * <p>
29   * Preserves the original order as well as the original casing of keys, while
30   * allowing for contains, get and remove calls with any case of key.
31   *
32   * <p>
33   * Does <i>not</i> support {@code null} keys.
34   *
35   * @author Juergen Hoeller
36   * @since 3.0
37   */
38  @SuppressWarnings("serial")
39  public class LinkedCaseInsensitiveMap<V> extends LinkedHashMap<String, V> {
40  
41  	private final Map<String, String> caseInsensitiveKeys;
42  
43  	private final Locale locale;
44  
45  	/**
46  	 * Create a new LinkedCaseInsensitiveMap for the default Locale.
47  	 * 
48  	 * @see java.lang.String#toLowerCase()
49  	 */
50  	public LinkedCaseInsensitiveMap() {
51  		this(null);
52  	}
53  
54  	/**
55  	 * Create a new LinkedCaseInsensitiveMap that stores lower-case keys
56  	 * according to the given Locale.
57  	 * 
58  	 * @param locale
59  	 *            the Locale to use for lower-case conversion
60  	 * @see java.lang.String#toLowerCase(java.util.Locale)
61  	 */
62  	public LinkedCaseInsensitiveMap(Locale locale) {
63  		super();
64  		this.caseInsensitiveKeys = new HashMap<String, String>();
65  		this.locale = (locale != null ? locale : Locale.getDefault());
66  	}
67  
68  	/**
69  	 * Create a new LinkedCaseInsensitiveMap that wraps a {@link LinkedHashMap}
70  	 * with the given initial capacity and stores lower-case keys according to
71  	 * the default Locale.
72  	 * 
73  	 * @param initialCapacity
74  	 *            the initial capacity
75  	 * @see java.lang.String#toLowerCase()
76  	 */
77  	public LinkedCaseInsensitiveMap(int initialCapacity) {
78  		this(initialCapacity, null);
79  	}
80  
81  	/**
82  	 * Create a new LinkedCaseInsensitiveMap that wraps a {@link LinkedHashMap}
83  	 * with the given initial capacity and stores lower-case keys according to
84  	 * the given Locale.
85  	 * 
86  	 * @param initialCapacity
87  	 *            the initial capacity
88  	 * @param locale
89  	 *            the Locale to use for lower-case conversion
90  	 * @see java.lang.String#toLowerCase(java.util.Locale)
91  	 */
92  	public LinkedCaseInsensitiveMap(int initialCapacity, Locale locale) {
93  		super(initialCapacity);
94  		this.caseInsensitiveKeys = new HashMap<String, String>(initialCapacity);
95  		this.locale = (locale != null ? locale : Locale.getDefault());
96  	}
97  
98  	@Override
99  	public V put(String key, V value) {
100 		String oldKey = this.caseInsensitiveKeys.put(convertKey(key), key);
101 		if (oldKey != null && !oldKey.equals(key)) {
102 			super.remove(oldKey);
103 		}
104 		return super.put(key, value);
105 	}
106 
107 	@Override
108 	public void putAll(Map<? extends String, ? extends V> map) {
109 		if (map.isEmpty()) {
110 			return;
111 		}
112 		for (Map.Entry<? extends String, ? extends V> entry : map.entrySet()) {
113 			put(entry.getKey(), entry.getValue());
114 		}
115 	}
116 
117 	@Override
118 	public boolean containsKey(Object key) {
119 		return (key instanceof String && this.caseInsensitiveKeys
120 				.containsKey(convertKey((String) key)));
121 	}
122 
123 	@Override
124 	public V get(Object key) {
125 		if (key instanceof String) {
126 			return super.get(this.caseInsensitiveKeys
127 					.get(convertKey((String) key)));
128 		} else {
129 			return null;
130 		}
131 	}
132 
133 	@Override
134 	public V remove(Object key) {
135 		if (key instanceof String) {
136 			return super.remove(this.caseInsensitiveKeys
137 					.remove(convertKey((String) key)));
138 		} else {
139 			return null;
140 		}
141 	}
142 
143 	@Override
144 	public void clear() {
145 		this.caseInsensitiveKeys.clear();
146 		super.clear();
147 	}
148 
149 	/**
150 	 * Convert the given key to a case-insensitive key.
151 	 * <p>
152 	 * The default implementation converts the key to lower-case according to
153 	 * this Map's Locale.
154 	 * 
155 	 * @param key
156 	 *            the user-specified key
157 	 * @return the key to use for storing
158 	 * @see java.lang.String#toLowerCase(java.util.Locale)
159 	 */
160 	protected String convertKey(String key) {
161 		return key != null ? key.toLowerCase(this.locale) : null;
162 	}
163 
164 }