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
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
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
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
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 }