View Javadoc

1   package pl.aislib.fm;
2   
3   import java.util.ArrayList;
4   import java.util.HashMap;
5   import java.util.Iterator;
6   import java.util.LinkedHashMap;
7   import java.util.List;
8   import java.util.Map;
9   
10  import pl.aislib.fm.forms.Field;
11  import pl.aislib.fm.forms.IEntity;
12  import pl.aislib.fm.forms.Rule;
13  import pl.aislib.fm.messages.IMessageConverter;
14  import pl.aislib.util.Pair;
15  
16  /***
17   * Class of forms.
18   *
19   * A form is a set of fields together with a set of rules.
20   * Form is said to be validated if all fields and rules are appropriately validated.
21   *
22   * @author
23   * <table>
24   *   <tr><td><a href="mailto:warlock@ais.pl">Michal Jastak</a>, AIS.PL</td></tr>
25   *   <tr><td><a href="mailto:pikus@ais.pl">Tomasz Pik</a>, AIS.PL</td></tr>
26   *   <tr><td><a href="mailto:wswiatek@ais.pl">Wojciech Swiatek</a>, AIS.PL</td></tr>
27   * </table>
28   * @version $Revision: 1.8 $
29   * @since AISLIB 0.1
30   */
31  public class Form extends FieldContainer {
32  
33    /*** */
34    public static final String MC_ENTITY_RULE = "rule";
35  
36  
37    /***
38     * Map of rules.
39     */
40    protected Map rules;
41  
42    /***
43     * Map of rule names and booleans.
44     */
45    protected Map validatedRules;
46  
47  
48    // Constructors
49  
50    /***
51     * @see pl.aislib.fm.FieldContainer#FieldContainer(String)
52     */
53    public Form(String name) {
54      super(name);
55  
56      messageGroups = new LinkedHashMap();
57      rules = new LinkedHashMap();
58    }
59  
60  
61    // Public methods
62  
63    /***
64     * @param rule <code>Rule</code> object.
65     */
66    public void addRule(Rule rule) {
67      rules.put(rule.getName(), rule);
68    }
69  
70  
71    // Protected methods
72  
73    /***
74     * @param rule <code>Rule</code> object.
75     * @return true if the rule can be validated.
76     */
77    protected boolean checkRuleForValidation(Rule rule) {
78      for (Iterator i = rule.getMapping().entrySet().iterator(); i.hasNext();) {
79        Map.Entry me = (Map.Entry) i.next();
80        String value = (String) me.getValue();
81        if (!isFieldValidated(value)) {
82          return false;
83        }
84      }
85      return true;
86    }
87  
88    /***
89     * @see java.lang.Object#clone()
90     */
91    protected Object clone() throws CloneNotSupportedException {
92      Form form = new Form(name);
93  
94      form.messages = messages;
95      form.messageGroups = messageGroups;
96      form.fields = fields;
97      form.rules = rules;
98      form.log = log;
99      form.bTreatEmptyAsNull = bTreatEmptyAsNull;
100 
101     return form;
102   }
103 
104   /***
105    * Form validates all non-complex fields first, then all complex fields.
106    * Then it tries to validate all rules.
107    *
108    * @see pl.aislib.fm.FieldContainer#doValidate(Map, Object)
109    */
110   protected boolean doValidate(Map fieldValues, Object data) {
111     boolean result = true;
112 
113     result &= validateNonComplexFields(fieldValues, data);
114     result &= validateComplexFields(fieldValues, data);
115     result &= validateRules(fieldValues);
116 
117     return result;
118   }
119 
120   /***
121    * @param rule a Rule object
122    * @param fieldValues map of string field values.
123    * @param values map of values.
124    * @return true if rule has been successfully validated.
125    */
126   protected boolean validateRule(Rule rule, Map fieldValues, Map values) {
127     String ruleName = rule.getName();
128     boolean result = true;
129 
130     List l = orderFieldValues(values, rule.getMapping(), fieldValues);
131     for (Iterator i = l.iterator(); i.hasNext();) {
132       try {
133         Pair pair = (Pair) i.next();
134         int j = ((Integer) pair.getFirst()).intValue();
135         ruleName = rule.getName() + (rule.isDynamic() ? "" + j : "");
136         Map map = (Map) pair.getSecond();
137 
138         stamp("Validating rule " + rule.getName() + " ...");
139 
140         boolean ruleValidated = rule.doValidate(this, fieldValues, map, j);
141 
142         validatedRules.put(ruleName, new Boolean(ruleValidated));
143 
144         if (!ruleValidated) {
145           if (rule.areAllFieldsValidated()) {
146             messagesMap.put(ruleName, new Integer(rule.getMsgCode()));
147             orderedMessagesMap.put(ruleName, new Integer(rule.getMsgCode()));
148             stamp("Rule '" + ruleName + "' has not been successfully validated.");
149           }
150         }
151 
152         result &= ruleValidated;
153       } catch (Exception e) {
154         messagesMap.put(ruleName, new Integer(rule.getMsgCode()));
155         orderedMessagesMap.put(ruleName, new Integer(rule.getMsgCode()));
156         validatedRules.put(ruleName, Boolean.FALSE);
157         stamp("Rule '" + ruleName + "' has not been successfully validated. Exception thrown: " + e.getMessage());
158         return false;
159       }
160     }
161 
162     return result;
163   }
164 
165   /***
166    * @param fieldValues map of string field values.
167    * @return true if all rules have been successfully validated.
168    */
169   protected boolean validateRules(Map fieldValues) {
170     boolean result = true;
171 
172     for (Iterator i = rules.entrySet().iterator(); i.hasNext();) {
173       Rule rule = (Rule) ((Map.Entry) i.next()).getValue();
174       result &= validateRule(rule, fieldValues, values);
175     }
176 
177     return result;
178   }
179 
180   /***
181    * Automatically generates all conditional fields.
182    * <p>
183    * The algorithm is as follows:
184    * <ul>
185    *   <li>take all rules for which condition should be checked</li>
186    *   <li>for each such rule, store all fields that are to be validated only when the condition has been met</li>
187    *   <li>remove from those fields all such that must be used in 'unconditional' rules, therefore
188    *       such that must be validated before rules</li>
189    *   <li>mark fields that left as 'conditional'</li>
190    * </ul>
191    */
192   public void setConditionalFields() {
193     Map conditionalFields = new HashMap();
194 
195     for (Iterator i = rules.entrySet().iterator(); i.hasNext();) {
196       Map.Entry me = (Map.Entry) i.next();
197       Rule rule = (Rule) me.getValue();
198       if (!rule.isCheckCondition()) {
199         continue;
200       }
201       Map ruleConditionalFields = rule.getFieldsValidatedConditionally();
202       if (ruleConditionalFields != null) {
203         for (Iterator j = ruleConditionalFields.entrySet().iterator(); j.hasNext();) {
204           Map.Entry me2 = (Map.Entry) j.next();
205           String fieldName = (String) me2.getValue();
206           conditionalFields.put(fieldName, Boolean.TRUE);
207           Field field = getField(fieldName);
208           if (field.isComplex()) {
209             for (Iterator k = field.getBuilder().getMapping().entrySet().iterator(); k.hasNext();) {
210               Map.Entry me3 = (Map.Entry) k.next();
211               String fieldPartName = (String) me3.getValue();
212               conditionalFields.put(fieldPartName, Boolean.TRUE);
213             }
214           }
215         }
216       }
217     }
218 
219     for (Iterator i = rules.entrySet().iterator(); i.hasNext();) {
220       Map.Entry me = (Map.Entry) i.next();
221       Rule rule = (Rule) me.getValue();
222       if (rule.isCheckCondition()) {
223         continue;
224       }
225       Map mapping = rule.getMapping();
226       if (mapping != null) {
227         for (Iterator j = mapping.entrySet().iterator(); j.hasNext();) {
228           Map.Entry me2 = (Map.Entry) j.next();
229           String fieldName = (String) me2.getValue();
230           conditionalFields.remove(fieldName);
231           Field field = getField(fieldName);
232           if (field.isComplex()) {
233             for (Iterator k = field.getBuilder().getMapping().entrySet().iterator(); k.hasNext();) {
234               Map.Entry me3 = (Map.Entry) k.next();
235               String fieldPartName = (String) me3.getValue();
236               conditionalFields.remove(fieldPartName);
237             }
238           }
239         }
240       }
241     }
242 
243     for (Iterator i = conditionalFields.keySet().iterator(); i.hasNext();) {
244       Field field = getField((String) i.next());
245       field.addType(Field.FT_CONDITIONAL);
246     }
247   }
248 
249   /***
250    * @return description of the form.
251    */
252   public String toString() {
253     StringBuffer result = new StringBuffer();
254     result.append("Form '" + name + "':");
255 
256     result.append("\n  defined fields: ");
257     for (Iterator i = fields.entrySet().iterator(); i.hasNext();) {
258       Map.Entry me = (Map.Entry) i.next();
259       Field field = (Field) me.getValue();
260       result.append(field.toString());
261     }
262 
263     result.append("\n  defined rules: ");
264     for (Iterator i = rules.entrySet().iterator(); i.hasNext();) {
265       Map.Entry me = (Map.Entry) i.next();
266       Rule rule = (Rule) me.getValue();
267       result.append(rule.toString());
268     }
269 
270     result.append("\n  parsed values: ");
271     for (Iterator i = values.entrySet().iterator(); i.hasNext();) {
272       Map.Entry me = (Map.Entry) i.next();
273       String fieldName = (String) me.getKey();
274       Object value = me.getValue();
275       result.append("\n\t" + fieldName + " = " + value);
276     }
277 
278     return result.toString();
279   }
280 
281   /***
282    * This method will not work for dynamic fields.
283    * Therefore I would like to make it deprecated - wswiatek.
284    *
285    * @see pl.aislib.fm.FieldContainer#getErrorCodes()
286    */
287   public Iterator getErrorCodes() {
288     List list = new ArrayList();
289 
290     for (Iterator i = orderedMessagesMap.entrySet().iterator(); i.hasNext();) {
291       Map.Entry me = (Map.Entry) i.next();
292       Integer msgCode = (Integer) me.getValue();
293       if (!list.contains(msgCode)) {
294         if (messages.containsKey(msgCode)) {
295           list.add(msgCode);
296         } else if (messageGroups.containsKey(msgCode)) {
297           List messageGroup = (List) messageGroups.get(msgCode);
298           for (Iterator j = messageGroup.iterator(); j.hasNext();) {
299             Integer refMsgCode = (Integer) j.next();
300             if (!list.contains(refMsgCode)) {
301               list.add(refMsgCode);
302             }
303           }
304         }
305       }
306     }
307 
308     return list.iterator();
309   }
310 
311   /***
312    * @return iterator of rule names.
313    */
314   public Iterator getRuleNames() {
315     return rules.keySet().iterator();
316   }
317 
318   /***
319    * @param ruleName name of a rule.
320    * @return the rule.
321    */
322   public Rule getRule(String ruleName) {
323     return (Rule) rules.get(ruleName);
324   }
325 
326   /***
327    * @return map of validated rules.
328    */
329   public Map getValidatedRules() {
330     return validatedRules;
331   }
332 
333   /***
334    * @param ruleName name of a rule.
335    * @return true if the rule has been validated successfully.
336    */
337   public boolean isRuleValidated(String ruleName) {
338     Boolean b = (Boolean) validatedRules.get(ruleName);
339     return (b != null ? b.booleanValue() : false);
340   }
341 
342 
343   // Protected methods
344 
345   /***
346    * @see pl.aislib.fm.FieldContainer#preValidate(Map, Object)
347    */
348   protected boolean preValidate(Map fieldValues, Object data) {
349     super.preValidate(fieldValues, data);
350 
351     validatedRules = new LinkedHashMap();
352 
353     return true;
354   }
355 
356   /***
357    * @see pl.aislib.fm.FieldContainer#getEntity(String)
358    */
359   protected IEntity getEntity(String entityName) {
360     IEntity entity = super.getEntity(entityName);
361     return entity != null ? entity : (IEntity) rules.get(entityName);
362   }
363 
364   /***
365    *
366    * @see pl.aislib.fm.FieldContainer#getDynamicEntityNamesList(String)
367    */
368   protected List getDynamicEntityNamesList(String entityName) {
369     List result = super.getDynamicEntityNamesList(entityName);
370     if (result.size() != 0) {
371       return result;
372     }
373 
374     for (Iterator i = validatedRules.keySet().iterator(); i.hasNext();) {
375       String ruleName = (String) i.next();
376       if (ruleName.startsWith(entityName)) {
377         result.add(ruleName);
378       }
379     }
380 
381     return result;
382   }
383 
384   /***
385    * @see pl.aislib.fm.FieldContainer#getErrorMessages(IMessageConverter)
386    */
387   public Map getErrorMessages(IMessageConverter messageConverter) {
388     Map formEntityProperties = getEntitiesProperties();
389 
390     Map result = super.getErrorMessages(messageConverter);
391 
392     for (Iterator i = rules.keySet().iterator(); i.hasNext();) {
393       String ruleName = (String) i.next();
394       result.putAll(getEntityMessages(ruleName, messageConverter, formEntityProperties));
395     }
396 
397     return result;
398   }
399 
400   /***
401    * @see pl.aislib.fm.FieldContainer#getEntitiesProperties()
402    */
403   protected Map getEntitiesProperties() {
404     Map result = super.getEntitiesProperties();
405 
406     for (Iterator i = rules.keySet().iterator(); i.hasNext(); ) {
407       String ruleName = (String) i.next();
408       getEntityProperties(ruleName, result);
409     }
410 
411     return result;
412   }
413 
414 
415   /***
416    * @see pl.aislib.fm.FieldContainer#addSpecificEntityProperties(pl.aislib.fm.forms.IEntity, java.lang.String, java.util.Map)
417    */
418   protected void addSpecificEntityProperties(IEntity entity, String entityName, Map entityProperties) {
419     super.addSpecificEntityProperties(entity, entityName, entityProperties);
420 
421     if (!(entity instanceof Rule)) {
422       return;
423     }
424 
425     Rule rule = (Rule) entity;
426     Map fieldNameMapping = null;
427     if (entity.isDynamic()) {
428       try {
429         int entityNumber = Integer.parseInt(entityName.substring(entityName.lastIndexOf("_") + 1));
430         fieldNameMapping = rule.getDynamicFieldNameMapping(this, entityNumber);
431       } catch (Exception ex) {
432         ;
433       }
434     } else {
435       fieldNameMapping = rule.getMapping();
436     }
437 
438     Map ruleFieldProperties = new HashMap();
439 
440     if (fieldNameMapping != null) {
441       for (Iterator iter = fieldNameMapping.entrySet().iterator(); iter.hasNext();) {
442         Map.Entry me = (Map.Entry) iter.next();
443         String key = (String) me.getKey();
444         String value = (String) me.getValue();
445         Field field = getField((String) rule.getMapping().get(key));
446         Map fieldProperties = new HashMap();
447         addSpecificEntityProperties(field, value, fieldProperties);
448         ruleFieldProperties.put(key, fieldProperties);
449       }
450     }
451 
452     entityProperties.put(MC_ENTITY_RULE, ruleFieldProperties);
453   }
454 
455 } // pl.aislib.fm.Form class