1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package eu.ehri.project.persistence;
21
22 import com.google.common.base.Joiner;
23 import com.google.common.collect.ArrayListMultimap;
24 import com.google.common.collect.ImmutableListMultimap;
25 import com.google.common.collect.LinkedHashMultiset;
26 import com.google.common.collect.ListMultimap;
27 import com.google.common.collect.Lists;
28 import com.google.common.collect.Maps;
29 import com.google.common.collect.Multimap;
30 import eu.ehri.project.exceptions.SerializationError;
31
32 import java.util.Collection;
33 import java.util.List;
34 import java.util.Map;
35
36 import static com.google.common.base.Preconditions.checkNotNull;
37
38
39
40
41 public final class ErrorSet implements NestableData<ErrorSet> {
42 private final Multimap<String, String> errors;
43 private final Multimap<String, ErrorSet> relations;
44
45
46
47
48 public static final String REL_KEY = "relationships";
49 public static final String ERROR_KEY = "errors";
50
51
52
53
54 public static class Builder {
55 private final ListMultimap<String, String> errors = ArrayListMultimap.create();
56 private final ListMultimap<String, ErrorSet> relations = ArrayListMultimap.create();
57
58 Builder addError(String key, String error) {
59 errors.put(key, error);
60 return this;
61 }
62
63 Builder addRelation(String relation, ErrorSet errorSet) {
64 relations.put(relation, errorSet);
65 return this;
66 }
67
68 public ErrorSet build() {
69 return new ErrorSet(errors, relations);
70 }
71 }
72
73
74
75
76 public ErrorSet() {
77 this(ArrayListMultimap.<String, String>create(),
78 ArrayListMultimap.<String, ErrorSet>create());
79 }
80
81
82
83
84
85
86
87 public static ErrorSet fromError(String key, String error) {
88 Multimap<String, String> tmp = ArrayListMultimap.create();
89 tmp.put(key, error);
90 return new ErrorSet(tmp);
91 }
92
93
94
95
96
97
98 public ErrorSet(Multimap<String, String> errors) {
99 this(errors, ArrayListMultimap.<String, ErrorSet>create());
100 }
101
102
103
104
105
106
107
108 public ErrorSet(Multimap<String, String> errors, Multimap<String, ErrorSet> relations) {
109 this.errors = ImmutableListMultimap.copyOf(errors);
110 this.relations = ImmutableListMultimap.copyOf(relations);
111 }
112
113
114
115
116
117
118
119 @SuppressWarnings("unchecked")
120 @Override
121 public Collection<String> getDataValue(String key) {
122 checkNotNull(key);
123 return errors.get(key);
124 }
125
126
127
128
129
130
131 public Multimap<String, String> getErrors() {
132 return errors;
133 }
134
135
136
137
138
139
140 @Override
141 public Multimap<String, ErrorSet> getRelations() {
142 return relations;
143 }
144
145
146
147
148
149
150
151 @Override
152 public ErrorSet withRelations(Multimap<String, ErrorSet> newRelations) {
153 Multimap<String, ErrorSet> tmp = ArrayListMultimap.create(relations);
154 tmp.putAll(newRelations);
155 return new ErrorSet(errors, tmp);
156 }
157
158
159
160
161
162
163
164 @Override
165 public List<ErrorSet> getRelations(String relation) {
166 return Lists.newArrayList(relations.get(relation));
167 }
168
169 @Override
170 public boolean hasRelations(String relation) {
171 return relations.containsKey(relation);
172 }
173
174 @Override
175 public ErrorSet replaceRelations(Multimap<String, ErrorSet> relations) {
176 return new ErrorSet(errors, relations);
177 }
178
179
180
181
182
183
184
185
186 @Override
187 public ErrorSet withDataValue(String key, Object err) {
188 if (err == null) {
189 return this;
190 } else {
191 Multimap<String, String> tmp = ArrayListMultimap.create(errors);
192 tmp.put(key, err.toString());
193 return new ErrorSet(tmp, relations);
194 }
195 }
196
197 @Override
198 public ErrorSet removeDataValue(String key) {
199 Multimap<String, String> tmp = ArrayListMultimap.create(errors);
200 tmp.removeAll(key);
201 return new ErrorSet(tmp, relations);
202 }
203
204
205
206
207
208
209
210
211 @Override
212 public ErrorSet withRelations(String relation, List<ErrorSet> others) {
213 Multimap<String, ErrorSet> tmp = ArrayListMultimap
214 .create(relations);
215 tmp.putAll(relation, others);
216 return new ErrorSet(errors, tmp);
217 }
218
219
220
221
222
223
224
225 @Override
226 public ErrorSet withRelation(String relation, ErrorSet other) {
227 Multimap<String, ErrorSet> tmp = ArrayListMultimap
228 .create(relations);
229 tmp.put(relation, other);
230 return new ErrorSet(errors, tmp);
231 }
232
233
234
235
236
237
238 public Map<String, Object> toData() {
239 return DataConverter.errorSetToData(this);
240 }
241
242 @Override
243 public String toString() {
244 return Joiner.on(", ").join(flatErrors());
245 }
246
247 private List<String> flatErrors() {
248 List<String> flatErrors = Lists.newArrayList();
249 for (Map.Entry<String, String> e : errors.entries()) {
250 flatErrors.add(String.format("%s: %s", e.getKey(), e.getValue()));
251 }
252 for (Map.Entry<String, ErrorSet> e : relations.entries()) {
253 for (String flatError : e.getValue().flatErrors()) {
254 flatErrors.add(String.format("%s.%s", e.getKey(), flatError));
255 }
256 }
257 return flatErrors;
258 }
259
260
261
262
263
264
265 public String toJson() {
266 try {
267 return DataConverter.errorSetToJson(this);
268 } catch (SerializationError e) {
269 return "Invalid Errors: " + e.getMessage();
270 }
271 }
272
273 @Override
274 public boolean equals(Object o) {
275 if (this == o) return true;
276 if (o == null || getClass() != o.getClass()) return false;
277
278 ErrorSet other = (ErrorSet) o;
279
280 return errors.equals(other.errors)
281 && unorderedRelations(relations)
282 .equals(unorderedRelations(other.relations));
283
284 }
285
286 @Override
287 public int hashCode() {
288 int result = errors.hashCode();
289 result = 31 * result + relations.hashCode();
290 return result;
291 }
292
293
294
295
296
297
298
299 public boolean isEmpty() {
300 if (!errors.isEmpty())
301 return false;
302 for (Map.Entry<String, ErrorSet> rel : relations.entries()) {
303 if (!rel.getValue().isEmpty())
304 return false;
305 }
306 return true;
307 }
308
309
310
311
312
313 private Map<String, LinkedHashMultiset<ErrorSet>> unorderedRelations(Multimap<String, ErrorSet> rels) {
314 Map<String, LinkedHashMultiset<ErrorSet>> map = Maps.newHashMap();
315 for (Map.Entry<String, Collection<ErrorSet>> entry : rels.asMap().entrySet()) {
316 map.put(entry.getKey(), LinkedHashMultiset.create(entry.getValue()));
317 }
318 return map;
319 }
320 }