View Javadoc

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 }