1 /*
2 * Copyright 2006-2016 The JGUIraffe Team.
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 package net.sf.jguiraffe.gui.forms;
17
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.LinkedHashMap;
22 import java.util.LinkedHashSet;
23 import java.util.Map;
24 import java.util.Set;
25
26 import net.sf.jguiraffe.transform.DefaultValidationResult;
27 import net.sf.jguiraffe.transform.ValidationMessage;
28 import net.sf.jguiraffe.transform.ValidationResult;
29
30 /**
31 * <p>
32 * Default implementation of the {@code FormValidatorResults} interface.
33 * </p>
34 * <p>
35 * This class provides a fully functional implementation of the {@code
36 * FormValidatorResults} interface. Instances are initialized with a map that
37 * contains the names of the validated fields and their corresponding
38 * {@link ValidationResult} objects. They are immutable and thus can be shared
39 * between multiple threads.
40 * </p>
41 *
42 * @author Oliver Heger
43 * @version $Id: DefaultFormValidatorResults.java 205 2012-01-29 18:29:57Z oheger $
44 */
45 public class DefaultFormValidatorResults implements FormValidatorResults
46 {
47 /** Stores the fields and their validation results. */
48 private final Map<String, ValidationResult> fields;
49
50 /** A set with the names of all fields. */
51 private final Set<String> fieldNames;
52
53 /** A list with the names of the error fields. */
54 private final Set<String> errorFieldNames;
55
56 /**
57 * Creates a new instance of {@code DefaultFormValidatorResults} and
58 * initializes it with a map holding information about fields and their
59 * validation status.
60 *
61 * @param fieldData the map with the field data (must not be <b>null</b>
62 * @throws IllegalArgumentException if the map is <b>null</b> or contains
63 * <b>null</b> values
64 */
65 public DefaultFormValidatorResults(
66 Map<String, ? extends ValidationResult> fieldData)
67 {
68 if (fieldData == null)
69 {
70 throw new IllegalArgumentException(
71 "Map with field data must not be null!");
72 }
73
74 fields = new LinkedHashMap<String, ValidationResult>(fieldData);
75 Set<String> errFlds = new LinkedHashSet<String>();
76 for (Map.Entry<String, ValidationResult> e : fields.entrySet())
77 {
78 if (e.getValue() == null)
79 {
80 throw new IllegalArgumentException(
81 "Map with field data contains a null value!");
82 }
83 if (!e.getValue().isValid())
84 {
85 errFlds.add(e.getKey());
86 }
87 }
88
89 fieldNames = Collections.unmodifiableSet(fields.keySet());
90 errorFieldNames = Collections.unmodifiableSet(errFlds);
91 }
92
93 /**
94 * Creates a {@code java.util.Map} with validation information for all
95 * fields of the specified {@code Form}. Each field is assigned a valid
96 * {@link ValidationResult} object. This method can be used by custom
97 * {@code FormValidator} implementations to initialize a map with data about
98 * all form fields. Then, during validation, fields that were detected to be
99 * invalid can be updated in this map. Finally, a {@code
100 * DefaultFormValidatorResults} object can be created based on this map.
101 *
102 * @param form the {@code Form} (must not be <b>null</b>)
103 * @return a map with valid validation data for all fields of the form
104 * @throws IllegalArgumentException if the {@code Form} is <b>null</b>
105 */
106 public static Map<String, ValidationResult> validResultMapForForm(Form form)
107 {
108 if (form == null)
109 {
110 throw new IllegalArgumentException("Form must not be null!");
111 }
112
113 Map<String, ValidationResult> map = new LinkedHashMap<String, ValidationResult>();
114 for (String field : form.getFieldNames())
115 {
116 map.put(field, DefaultValidationResult.VALID);
117 }
118
119 return map;
120 }
121
122 /**
123 * Creates a valid {@code DefaultFormValidatorResults} for the fields of the
124 * specified {@code Form}. The resulting object stores a valid
125 * {@link ValidationResult} object for all fields that belong to the form.
126 *
127 * @param form the {@code Form} (must not be <b>null</b>)
128 * @return a valid {@code DefaultFormValidatorResults} object for this form
129 * @throws IllegalArgumentException if the {@code Form} is <b>null</b>
130 */
131 public static DefaultFormValidatorResults validResultsForForm(Form form)
132 {
133 return new DefaultFormValidatorResults(validResultMapForForm(form));
134 }
135
136 /**
137 * Obtains a {@code ValidationMessage} object for the specified key. The
138 * message is obtained from the current
139 * {@link net.sf.jguiraffe.transform.ValidationMessageHandler
140 * ValidationMessageHandler} (which can be retrieved from the form's
141 * {@code TransformerContext}).
142 *
143 * @param form the {@code Form} (must not be <b>null</b>)
144 * @param key the key of the validation error message
145 * @param params additional parameters for the validation error message
146 * @return a {@code ValidationMessage} object for the specified error
147 * message
148 * @throws IllegalArgumentException if the {@code Form} is <b>null</b>
149 */
150 public static ValidationMessage createValidationMessage(Form form,
151 String key, Object... params)
152 {
153 if (form == null)
154 {
155 throw new IllegalArgumentException("Form must not be null!");
156 }
157
158 return DefaultValidationResult.createValidationMessage(form
159 .getTransformerContext(), key, params);
160 }
161
162 /**
163 * Creates a {@code ValidationResult} object with an error message for a
164 * validation message. This is a convenience method that obtains the
165 * validation error message from the current
166 * {@link net.sf.jguiraffe.transform.ValidationMessageHandler
167 * ValidationMessageHandler} and creates the corresponding
168 * {@code ValidationResult} object. It can be used for instance by a
169 * {@code FormValidator} that determines an incorrect field.
170 *
171 * @param form the {@code Form} (must not be <b>null</b>)
172 * @param key the key of the validation error message
173 * @param params additional parameters for the validation error message
174 * @return a {@code ValidationResult} object initialized with this error
175 * message
176 * @throws IllegalArgumentException if the {@code Form} is <b>null</b>
177 */
178 public static ValidationResult createValidationErrorResult(Form form,
179 String key, Object... params)
180 {
181 if (form == null)
182 {
183 throw new IllegalArgumentException("Form must not be null!");
184 }
185
186 return DefaultValidationResult.createValidationErrorResult(form
187 .getTransformerContext(), key, params);
188 }
189
190 /**
191 * Returns a {@code FormValidatorResults} object with the combined
192 * information of the specified {@code FormValidatorResults} objects. If one
193 * of the passed in objects is <b>null</b>, the other one is returned.
194 * Otherwise a new {@code FormValidatorResults} instance is created and
195 * populated with the {@code ValidationResult} objects contained in both
196 * parameter objects. If necessary, the {@code ValidationResult} objects are
197 * also merged, so that the resulting object actually contains a union of
198 * all validation messages.
199 *
200 * @param res1 the first {@code FormValidatorResults} object
201 * @param res2 the second {@code FormValidatorResults} object
202 * @return the merged results
203 */
204 public static FormValidatorResults merge(FormValidatorResults res1,
205 FormValidatorResults res2)
206 {
207 if (res1 == null)
208 {
209 return res2;
210 }
211 if (res2 == null)
212 {
213 return res1;
214 }
215
216 Set<String> names = new HashSet<String>(res1.getFieldNames());
217 names.addAll(res2.getFieldNames());
218 Map<String, ValidationResult> map = new HashMap<String, ValidationResult>();
219 for (String field : names)
220 {
221 map.put(field, DefaultValidationResult.merge(res1
222 .getResultsFor(field), res2.getResultsFor(field)));
223 }
224
225 return new DefaultFormValidatorResults(map);
226 }
227
228 /**
229 * Checks whether form validation was successful.
230 *
231 * @return a flag if all fields are valid
232 */
233 public boolean isValid()
234 {
235 return errorFieldNames.isEmpty();
236 }
237
238 /**
239 * Returns a set with all defined field names.
240 *
241 * @return a set with the field names
242 */
243 public Set<String> getFieldNames()
244 {
245 return fieldNames;
246 }
247
248 /**
249 * Returns a set with the names of those fields that are invalid.
250 *
251 * @return a set with the names of the invalid fields
252 */
253 public Set<String> getErrorFieldNames()
254 {
255 return errorFieldNames;
256 }
257
258 /**
259 * Returns the validation results for the specified field or <b>null</b> if
260 * this field does not exist.
261 *
262 * @param field the name of the desired field
263 * @return the validation result for this field
264 */
265 public ValidationResult getResultsFor(String field)
266 {
267 return fields.get(field);
268 }
269
270 /**
271 * Compares this object with another one. Two form validator result objects
272 * are considered equal if and only if they contain the same set of fields
273 * with corresponding result objects.
274 *
275 * @param obj the object to compare to
276 * @return a flag whether the objects are equal
277 */
278 @Override
279 public boolean equals(Object obj)
280 {
281 if (this == obj)
282 {
283 return true;
284 }
285 if (!(obj instanceof DefaultFormValidatorResults))
286 {
287 return false;
288 }
289 return fields.equals(((DefaultFormValidatorResults) obj).fields);
290 }
291
292 /**
293 * Determines a hash code for this object.
294 *
295 * @return a hash code
296 */
297 @Override
298 public int hashCode()
299 {
300 return fields.hashCode();
301 }
302
303 /**
304 * Returns a string representation for this object. This string contains the
305 * string representation for the internal map with the fields and their
306 * validation result objects. Provided that the {@code ValidationResult}
307 * objects have proper {@code toString()} implementations, the string
308 * generated by the map is exactly what is needed to see which field has
309 * which validation status.
310 *
311 * @return a string for this object
312 */
313 @Override
314 public String toString()
315 {
316 StringBuilder buf = new StringBuilder();
317 buf.append(getClass().getName()).append('@');
318 buf.append(System.identityHashCode(this));
319 buf.append("[ ");
320 buf.append(fields.toString());
321 buf.append(" ]");
322 return buf.toString();
323 }
324 }