1 | |
package org.kuali.rice.core.api.mo.common; |
2 | |
|
3 | |
import org.apache.commons.lang.builder.EqualsBuilder; |
4 | |
import org.apache.commons.lang.builder.HashCodeBuilder; |
5 | |
import org.apache.commons.lang.builder.ToStringBuilder; |
6 | |
import org.kuali.rice.core.util.KeyValue; |
7 | |
import org.kuali.rice.core.util.jaxb.StringMapEntry; |
8 | |
import org.kuali.rice.core.util.jaxb.StringMapEntryList; |
9 | |
|
10 | |
import javax.xml.bind.annotation.XmlRootElement; |
11 | |
import javax.xml.bind.annotation.adapters.XmlAdapter; |
12 | |
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; |
13 | |
import java.io.Serializable; |
14 | |
import java.util.AbstractMap; |
15 | |
import java.util.ArrayList; |
16 | |
import java.util.Collection; |
17 | |
import java.util.Collections; |
18 | |
import java.util.HashMap; |
19 | |
import java.util.HashSet; |
20 | |
import java.util.List; |
21 | |
import java.util.Map; |
22 | |
import java.util.Set; |
23 | |
|
24 | |
|
25 | |
|
26 | |
|
27 | |
|
28 | |
@XmlRootElement |
29 | |
@XmlJavaTypeAdapter(Attributes.Adapter.class) |
30 | 5 | public final class Attributes implements Serializable { |
31 | |
|
32 | |
private static final long serialVersionUID = -2804341886674598357L; |
33 | |
|
34 | 1 | private static final Attributes EMPTY = new Attributes(Collections.<String, String>emptyMap()); |
35 | |
|
36 | |
private final Map<String, String> keyValues; |
37 | |
|
38 | 13 | private final Object lock = new Object(); |
39 | |
private Set<Map.Entry<String, String>> cache; |
40 | |
|
41 | |
|
42 | |
|
43 | |
|
44 | 0 | private Attributes() { |
45 | 0 | this.keyValues = null; |
46 | 0 | } |
47 | |
|
48 | 13 | private Attributes(final Map<String, String> map) { |
49 | 13 | this.keyValues = new HashMap<String, String>(map); |
50 | 13 | } |
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | |
|
56 | |
|
57 | |
public static Attributes empty() { |
58 | 4 | return EMPTY; |
59 | |
} |
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
|
67 | |
public static Attributes fromMap(Map<String, String> map) { |
68 | 12 | if (map == null) { |
69 | 1 | throw new IllegalArgumentException("map is null"); |
70 | |
} |
71 | |
|
72 | 11 | if (map.isEmpty()) { |
73 | 1 | return empty(); |
74 | |
} |
75 | |
|
76 | 10 | return new Attributes(map); |
77 | |
} |
78 | |
|
79 | |
|
80 | |
|
81 | |
|
82 | |
|
83 | |
|
84 | |
|
85 | |
public static Attributes fromMapEntry(Map.Entry<String, String> entry) { |
86 | 3 | if (entry == null) { |
87 | 1 | throw new IllegalArgumentException("entry is null"); |
88 | |
} |
89 | |
|
90 | 2 | if (entry.getKey() == null) { |
91 | 1 | throw new IllegalArgumentException("entry.key is null"); |
92 | |
} |
93 | |
|
94 | 1 | return fromMap(Collections.singletonMap(entry.getKey(), entry.getValue())); |
95 | |
} |
96 | |
|
97 | |
|
98 | |
|
99 | |
|
100 | |
|
101 | |
|
102 | |
|
103 | |
public static Attributes fromStrings(String key, String value) { |
104 | 2 | if (key == null) { |
105 | 1 | throw new IllegalArgumentException("key is null"); |
106 | |
} |
107 | |
|
108 | 1 | return fromMap(Collections.singletonMap(key, value)); |
109 | |
} |
110 | |
|
111 | |
|
112 | |
|
113 | |
|
114 | |
|
115 | |
|
116 | |
|
117 | |
public static Attributes fromKeyValue(KeyValue keyValue) { |
118 | 3 | if (keyValue == null) { |
119 | 1 | throw new IllegalArgumentException("keyValue is null"); |
120 | |
} |
121 | |
|
122 | 2 | if (keyValue.getKey() == null) { |
123 | 1 | throw new IllegalArgumentException("keyValue.key is null"); |
124 | |
} |
125 | |
|
126 | 1 | return fromMap(Collections.singletonMap(keyValue.getKey(), keyValue.getValue())); |
127 | |
} |
128 | |
|
129 | |
|
130 | |
|
131 | |
|
132 | |
|
133 | |
|
134 | |
|
135 | |
public Map<String, String> toMap() { |
136 | 2 | return new HashMap<String, String>(keyValues); |
137 | |
} |
138 | |
|
139 | |
|
140 | |
|
141 | |
|
142 | |
|
143 | |
|
144 | |
|
145 | |
|
146 | |
public int size() { |
147 | 0 | return keyValues.size(); |
148 | |
} |
149 | |
|
150 | |
|
151 | |
|
152 | |
|
153 | |
|
154 | |
|
155 | |
public boolean isEmpty() { |
156 | 0 | return keyValues.isEmpty(); |
157 | |
} |
158 | |
|
159 | |
|
160 | |
|
161 | |
|
162 | |
|
163 | |
|
164 | |
|
165 | |
|
166 | |
public boolean containsKey(String key) { |
167 | 1 | validateKey(key); |
168 | 1 | return keyValues.containsKey(key); |
169 | |
} |
170 | |
|
171 | |
|
172 | |
|
173 | |
|
174 | |
|
175 | |
|
176 | |
|
177 | |
public boolean containsValue(String value) { |
178 | 0 | return keyValues.containsValue(value); |
179 | |
} |
180 | |
|
181 | |
|
182 | |
|
183 | |
|
184 | |
|
185 | |
|
186 | |
|
187 | |
public String get(String key) { |
188 | 0 | validateKey(key); |
189 | 0 | return keyValues.get(key); |
190 | |
} |
191 | |
|
192 | |
|
193 | |
|
194 | |
|
195 | |
|
196 | |
|
197 | |
public Set<String> keySet() { |
198 | 0 | return keyValues.keySet(); |
199 | |
} |
200 | |
|
201 | |
|
202 | |
|
203 | |
|
204 | |
|
205 | |
|
206 | |
public Collection<String> values() { |
207 | 0 | return keyValues.values(); |
208 | |
} |
209 | |
|
210 | |
|
211 | |
|
212 | |
|
213 | |
|
214 | |
|
215 | |
public Set<Map.Entry<String, String>> entrySet() { |
216 | |
|
217 | |
|
218 | 5 | synchronized (lock) { |
219 | 5 | if (cache == null) { |
220 | 5 | final Set<Map.Entry<String, String>> temp = new HashSet<Map.Entry<String, String>>(); |
221 | 5 | for (Map.Entry<String, String> e : keyValues.entrySet()) { |
222 | 5 | if (e != null) { |
223 | 5 | temp.add(new AbstractMap.SimpleImmutableEntry<String, String>(e.getKey(), e.getValue())); |
224 | |
} |
225 | |
} |
226 | 5 | cache = Collections.unmodifiableSet(temp); |
227 | |
} |
228 | 5 | } |
229 | 5 | return cache; |
230 | |
} |
231 | |
|
232 | |
private static void validateKey(String key) { |
233 | 1 | if (key == null) { |
234 | 0 | throw new IllegalArgumentException("key is null"); |
235 | |
} |
236 | 1 | } |
237 | |
|
238 | |
@Override |
239 | |
public int hashCode() { |
240 | 0 | return HashCodeBuilder.reflectionHashCode(this, Constants.HASH_CODE_EQUALS_EXCLUDE); |
241 | |
} |
242 | |
|
243 | |
@Override |
244 | |
public boolean equals(Object obj) { |
245 | 2 | return EqualsBuilder.reflectionEquals(obj, this, Constants.HASH_CODE_EQUALS_EXCLUDE); |
246 | |
} |
247 | |
|
248 | |
@Override |
249 | |
public String toString() { |
250 | 0 | return ToStringBuilder.reflectionToString(this); |
251 | |
} |
252 | |
|
253 | |
|
254 | |
|
255 | |
|
256 | 0 | static class Constants { |
257 | 1 | final static String[] HASH_CODE_EQUALS_EXCLUDE = {"cache", "lock"}; |
258 | |
} |
259 | |
|
260 | 5 | public static class Adapter extends XmlAdapter<StringMapEntryList, Attributes> { |
261 | |
|
262 | |
@Override |
263 | |
public StringMapEntryList marshal(Attributes attributes) throws Exception { |
264 | 1 | if (attributes == null || attributes.keyValues == null) { |
265 | 0 | return null; |
266 | |
} |
267 | 1 | List<StringMapEntry> entries = new ArrayList<StringMapEntry>(attributes.keyValues.size()); |
268 | 1 | for (Map.Entry<String, String> entry : attributes.keyValues.entrySet()) { |
269 | 1 | entries.add(new StringMapEntry(entry)); |
270 | |
} |
271 | 1 | return new StringMapEntryList(entries); |
272 | |
} |
273 | |
|
274 | |
@Override |
275 | |
public Attributes unmarshal(StringMapEntryList entries) throws Exception { |
276 | 2 | if (entries == null || entries.getEntries() == null) { |
277 | 0 | return null; |
278 | |
} |
279 | 2 | Map<String, String> resultMap = new HashMap<String, String>(); |
280 | 2 | for (StringMapEntry entry : entries.getEntries()) { |
281 | 2 | resultMap.put(entry.getKey(), entry.getValue()); |
282 | |
} |
283 | 2 | return new Attributes(resultMap); |
284 | |
} |
285 | |
|
286 | |
} |
287 | |
|
288 | |
} |