001: //** Copyright Statement ***************************************************
002: //The Salmon Open Framework for Internet Applications (SOFIA)
003: // Copyright (C) 1999 - 2002, Salmon LLC
004: //
005: // This program is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU General Public License version 2
007: // as published by the Free Software Foundation;
008: //
009: // This program is distributed in the hope that it will be useful,
010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: // GNU General Public License for more details.
013: //
014: // You should have received a copy of the GNU General Public License
015: // along with this program; if not, write to the Free Software
016: // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: //
018: // For more information please visit http://www.salmonllc.com
019: //** End Copyright Statement ***************************************************
020: package com.salmonllc.html;
021:
022: /////////////////////////
023: //$Archive: /SOFIA/SourceCode/com/salmonllc/html/HtmlComponentValidator.java $
024: //$Author: Dan $
025: //$Revision: 17 $
026: //$Modtime: 9/08/04 5:53p $
027: /////////////////////////
028:
029: import com.salmonllc.sql.*;
030: import com.salmonllc.util.*;
031: import java.util.*;
032: import java.sql.*;
033:
034: /**
035: * This class can be used to do basic validations against rows and columns in a DataStore. Simple Validation Rules can be added using the addValidationRule method and all the tests can be iterated through using the findFirstError and findNextError methods.
036: */
037: public class HtmlComponentValidator {
038: private DataStoreBuffer _ds;
039: private Vector _rules = new Vector();
040: private int _currentRule = -1;
041: private String _appName;
042: private String _profile = null;
043:
044: private static final String TYPE_EXP = "E";
045: private static final String TYPE_SQL = "S";
046: private static final String TYPE_REQ = "R";
047: private static final String TYPE_JS = "J";
048: private static final String TYPE_REGEXP = "X";
049: private static final String TYPE_RANGE = "N";
050:
051: private boolean _validateRequired = true;
052: private boolean _validateRegExp = true;
053: private boolean _validateRange = true;
054: private boolean _validateLookup = true;
055: private boolean _validateExpression = true;
056:
057: /**
058: * Constructs a new HtmlComponentValidator based on the DataStoreBuffer passed in.
059: */
060: public HtmlComponentValidator(String applicationName,
061: DataStoreBuffer ds) {
062: super ();
063: _ds = ds;
064: _appName = applicationName;
065: }
066:
067: /**
068: * Constructs a new HtmlComponentValidator based on the DataStoreBuffer passed in.
069: */
070: public HtmlComponentValidator(String applicationName,
071: String DBProfile, DataStoreBuffer ds) {
072: super ();
073: _ds = ds;
074: _appName = applicationName;
075: _profile = DBProfile;
076: }
077:
078: /**
079: * Use this method to add validation rules that will be checked for a required field.
080: * @param column The colum to validate
081: * @param errorMessage The error message to display if the field is not filled in.
082: * @param focusComp The HtmlComponent to set focus too if the error expression returns false.
083: */
084: public void addRequiredRule(String column, String errorMessage,
085: HtmlFormComponent focusComp) {
086: FourObjectContainer f = new FourObjectContainer(TYPE_REQ,
087: column, errorMessage, focusComp);
088: _rules.addElement(f);
089: }
090:
091: void addJavaScriptRule(String javaScript, String errorMessage,
092: HtmlFormComponent focusComp) {
093: FourObjectContainer f = new FourObjectContainer(TYPE_JS,
094: javaScript, errorMessage, focusComp);
095: _rules.addElement(f);
096: }
097:
098: /**
099: * Adds a regular expression rule to the datastore. The rule will be violated if the value in the focus component doesn't match the regular expression
100: * @param The column to validate
101: * @param regExp The regular expression to use for validation
102: * @param errorMessage The error message to display if the field is not filled in.
103: * @param focusComp The HtmlComponent to set focus too if the error expression returns false.
104: */
105: public void addRegularExpressionRule(String column, String regExp,
106: String errorMessage, HtmlFormComponent focusComp) {
107: FourObjectContainer f = new FourObjectContainer(TYPE_REGEXP,
108: new TwoObjectContainer(column,
109: new RegularExpressionMatcher(regExp)),
110: errorMessage, focusComp);
111: _rules.addElement(f);
112: }
113:
114: /**
115: * Use this method to add validation rules that will be checked by the validator.
116: * @param expression A boolean expression that will trigger an error if evaluated to false.
117: * @param errorMessage The error message to display if the error expression returns false.
118: * @param focusComp The HtmlComponent to set focus too if the error expression returns false.
119: */
120: public void addExpressionRule(String expression,
121: String errorMessage, HtmlFormComponent focusComp)
122: throws DataStoreException {
123: DataStoreEvaluator d = new DataStoreEvaluator(_ds, expression);
124: FourObjectContainer f = new FourObjectContainer(TYPE_EXP, d,
125: errorMessage, focusComp);
126: _rules.addElement(f);
127: }
128:
129: /**
130: * Use this method to add validation rules that will be checked by the validator.
131: * @param expression A DataStoreExpression class that returns a boolean value. It will trigger an error if the value returns false.
132: * @param errorMessage The error message to display if the error expression returns false.
133: * @param focusComp The HtmlComponent to set focus too if the error expression returns false.
134: */
135: public void addExpressionRule(DataStoreExpression expression,
136: String errorMessage, HtmlFormComponent focusComp)
137: throws DataStoreException {
138: DataStoreEvaluator d = new DataStoreEvaluator(_ds, expression);
139: FourObjectContainer f = new FourObjectContainer(TYPE_EXP, d,
140: errorMessage, focusComp);
141: _rules.addElement(f);
142: }
143:
144: /**
145: * Use this method to add a range validation rule that will be checked by the validator.
146: * @param minValue The minimum allowed value in the component
147: * @param maxValue The maximum allowed value in the component
148: * @param errorMessage The error message to display if the error expression returns false.
149: * @param focusComp The HtmlComponent to set focus too if the error expression returns false.
150: */
151: public void addRangeRule(String column, Object minValue,
152: Object maxValue, String errorMessage,
153: HtmlFormComponent focusComp) throws DataStoreException {
154: ThreeObjectContainer cont = new ThreeObjectContainer(column,
155: minValue, maxValue);
156: FourObjectContainer f = new FourObjectContainer(TYPE_RANGE,
157: cont, errorMessage, focusComp);
158: _rules.addElement(f);
159: }
160:
161: /**
162: * Use this method to add validation rules that will be checked via a lookup to another table.
163: * @param lookupTable The name of the table to lookup the value against.
164: * @param searchExpression A DataStoreEvaluator expression that returns a String and will be used as the where clause for the SQL that will validate the data.
165: * @param errorMessage The error message to display if the error expression returns false.
166: * @param focusComp The HtmlComponent to set focus to if the error expression returns false.
167: */
168: public void addLookupRule(String lookupTable,
169: String searchExpression, String errorMessage,
170: HtmlFormComponent focusComp) throws DataStoreException {
171: DataStoreEvaluator d = new DataStoreEvaluator(_ds,
172: searchExpression);
173: FourObjectContainer sql = new FourObjectContainer(lookupTable,
174: d, null, null);
175: FourObjectContainer f = new FourObjectContainer(TYPE_SQL, sql,
176: errorMessage, focusComp);
177: _rules.addElement(f);
178: }
179:
180: /**
181: * Use this method to add validation rules that will be checked via a lookup to another table. In addition to checking if a set of columns are valid, this type of rule will also fill in a bucket in the datastore with a description taken from the row retrieved in the lookup table.
182: * @param lookupTable The name of the table to lookup the value against.
183: * @param searchExpression A DataStoreEvaluator expression that returns a String and will be used as the where clause for the SQL that will validate the data.
184: * @param errorMessage The error message to display if the error expression returns false.
185: * @param focusComp The HtmlComponent to set focus to if the error expression returns false.
186: * @param descColumn The name of the column in the lookup table used to fill in the description.
187: * @param descBucket The name of a bucket column in the datastore to place the description.
188: */
189: public void addLookupRule(String lookupTable,
190: String searchExpression, String errorMessage,
191: HtmlFormComponent focusComp, String descColumn,
192: String descBucket) throws DataStoreException {
193: DataStoreEvaluator d = new DataStoreEvaluator(_ds,
194: searchExpression);
195: FourObjectContainer sql = new FourObjectContainer(lookupTable,
196: d, descColumn, descBucket);
197: FourObjectContainer f = new FourObjectContainer(TYPE_SQL, sql,
198: errorMessage, focusComp);
199: _rules.addElement(f);
200: }
201:
202: /**
203: * Use this method to add validation rules that will be checked via a lookup to another table.
204: * @param lookupTable The name of the table to lookup the value against.
205: * @param searchExpression A DataStoreExpression that returns a String and will be used as the where clause for the SQL that will validate the data.
206: * @param errorMessage The error message to display if the error expression returns false.
207: * @param focusComp The HtmlComponent to set focus to if the error expression returns false.
208: */
209: public void addLookupRule(String lookupTable,
210: DataStoreExpression searchExpression, String errorMessage,
211: HtmlFormComponent focusComp) throws DataStoreException {
212: DataStoreEvaluator d = new DataStoreEvaluator(_ds,
213: searchExpression);
214: FourObjectContainer sql = new FourObjectContainer(lookupTable,
215: d, null, null);
216: FourObjectContainer f = new FourObjectContainer(TYPE_SQL, sql,
217: errorMessage, focusComp);
218: _rules.addElement(f);
219: }
220:
221: /**
222: * Use this method to add validation rules that will be checked via a lookup to another table. In addition to checking if a set of columns are valid, this type of rule will also fill in a bucket in the datastore with a description taken from the row retrieved in the lookup table.
223: * @param lookupTable The name of the table to lookup the value against.
224: * @param searchExpression A DataStoreExpression that returns a String and will be used as the where clause for the SQL that will validate the data.
225: * @param errorMessage The error message to display if the error expression returns false.
226: * @param focusComp The HtmlComponent to set focus to if the error expression returns false.
227: * @param descColumn The name of the column in the lookup table used to fill in the description.
228: * @param descBucket The name of a bucket column in the datastore to place the description.
229: */
230: public void addLookupRule(String lookupTable,
231: DataStoreExpression searchExpression, String errorMessage,
232: HtmlFormComponent focusComp, String descColumn,
233: String descBucket) throws DataStoreException {
234: DataStoreEvaluator d = new DataStoreEvaluator(_ds,
235: searchExpression);
236: FourObjectContainer sql = new FourObjectContainer(lookupTable,
237: d, descColumn, descBucket);
238: FourObjectContainer f = new FourObjectContainer(TYPE_SQL, sql,
239: errorMessage, focusComp);
240: _rules.addElement(f);
241: }
242:
243: /**
244: * Use this method to find the next rule that is being violated using the current row in the DataStore.
245: * @return true if no errors are found and false if an error is found.
246: */
247: public boolean findNextError() throws Exception {
248: return findNextError(_ds.getRow());
249: }
250:
251: /**
252: * Use this method to find the next rule that is being violated.
253: * @param rowNo The row number in the DataStore to validate.
254: * @return true if no errors are found and false if an error is found.
255: */
256: public boolean findNextError(int rowNo) throws Exception {
257: DBConnection conn = null;
258: Statement st = null;
259:
260: _currentRule++;
261:
262: for (int i = _currentRule; i < _rules.size(); i++) {
263: try {
264:
265: FourObjectContainer f = (FourObjectContainer) _rules
266: .elementAt(i);
267: boolean b = true;
268:
269: if (f.getObject1().equals(TYPE_REQ))
270: b = validateRequired(f, rowNo);
271: else if (f.getObject1().equals(TYPE_EXP))
272: b = validateExpression(f, rowNo);
273: else if (f.getObject1().equals(TYPE_REGEXP))
274: b = validateRegularExpression(f, rowNo);
275: else if (f.getObject1().equals(TYPE_RANGE))
276: b = validateRange(f, rowNo);
277: else if (f.getObject1().equals(TYPE_SQL)) {
278: if (conn == null) {
279: conn = DBConnection.getConnection(_appName);
280: st = conn.createStatement();
281: }
282: b = validateLookup(f, rowNo, st);
283: }
284:
285: if (!b) {
286: _currentRule = i;
287: if (st != null)
288: st.close();
289: if (conn != null)
290: conn.freeConnection();
291: return true;
292: }
293: } catch (Exception e) {
294: if (st != null)
295: st.close();
296: if (conn != null)
297: conn.freeConnection();
298: _currentRule = i;
299: MessageLog
300: .writeErrorMessage("findNextError()", e, this );
301: return true;
302: }
303: }
304:
305: if (st != null)
306: st.close();
307:
308: if (conn != null)
309: conn.freeConnection();
310:
311: _currentRule = -1;
312:
313: return false;
314: }
315:
316: /**
317: * This method returns the DataStoreBuffer that the component will validate.
318: */
319: public DataStoreBuffer getDataStoreBuffer() {
320: return _ds;
321: }
322:
323: /**
324: * This method returns the HtmlComponent that should have the focus when it's corresponding rule is violated or null if there are no errors.
325: */
326: public HtmlFormComponent getErrorComponent() {
327: if (_currentRule == -1)
328: return null;
329: else {
330: FourObjectContainer f = (FourObjectContainer) _rules
331: .elementAt(_currentRule);
332: if (f.getObject4() == null)
333: return null;
334: else
335: return (HtmlFormComponent) f.getObject4();
336: }
337:
338: }
339:
340: /**
341: * This method returns the error message that should be displayed when the current rule is violated or null if there are no errors.
342: */
343: public String getErrorMessage() {
344: if (_currentRule == -1)
345: return null;
346: else {
347: FourObjectContainer f = (FourObjectContainer) _rules
348: .elementAt(_currentRule);
349: return (String) f.getObject3();
350: }
351:
352: }
353:
354: /**
355: * Returns the number of the rule that was violated or -1 if none was
356: */
357: public int getCurrentRule() {
358: return _currentRule;
359: }
360:
361: /**
362: * Use this method to fill in the descriptions for lookup columns for the current row in the datastore.
363: */
364: public void populateDescriptions() throws Exception {
365: populateDescriptions(_ds.getRow());
366: }
367:
368: /**
369: * Use this method to fill in the descriptions for lookup columns.
370: * @param rowNo The row number in the DataStore to fill in.
371: */
372: public void populateDescriptions(int rowNo) throws Exception {
373: DBConnection conn = null;
374: Statement st = null;
375:
376: try {
377: conn = DBConnection.getConnection(_appName, _profile);
378: st = conn.createStatement();
379:
380: for (int i = 0; i < _rules.size(); i++) {
381: FourObjectContainer f = (FourObjectContainer) _rules
382: .elementAt(i);
383:
384: if (f.getObject1().equals(TYPE_SQL))
385: validateLookup(f, rowNo, st);
386: }
387: } catch (Exception e) {
388: MessageLog.writeErrorMessage("populateDescriptions()", e,
389: this );
390: }
391:
392: if (st != null)
393: st.close();
394:
395: if (conn != null)
396: conn.freeConnection();
397:
398: }
399:
400: /**
401: * Use this method to reset the validator to the first rule in the list. Subsequent calls to findNextError will begin checking with the first rule instead of the one with the last error.
402: */
403: public void reset() {
404: _currentRule = -1;
405: }
406:
407: private boolean validateRegularExpression(FourObjectContainer f,
408: int rowNo) throws Exception {
409: if (!_validateRegExp)
410: return true;
411:
412: TwoObjectContainer cont = (TwoObjectContainer) f.getObject2();
413: String column = (String) cont.getObject1();
414: RegularExpressionMatcher matcher = (RegularExpressionMatcher) cont
415: .getObject2();
416: String s = _ds.getFormattedString(rowNo, column);
417: return matcher.match(s);
418: }
419:
420: private boolean validateRange(FourObjectContainer f, int rowNo)
421: throws Exception {
422: if (!_validateRange)
423: return true;
424:
425: ThreeObjectContainer cont = (ThreeObjectContainer) f
426: .getObject2();
427:
428: String column = (String) cont.getObject1();
429: int colNo = _ds.getColumnIndex(column);
430: Object minValue = cont.getObject2();
431: Object maxValue = cont.getObject3();
432: if (minValue != null) {
433: if (!_ds.valueEqual(rowNo, colNo, minValue))
434: if (!_ds.valueGreater(rowNo, colNo, minValue))
435: return false;
436: }
437:
438: if (maxValue != null) {
439: if (!_ds.valueEqual(rowNo, colNo, maxValue))
440: if (!_ds.valueLess(rowNo, colNo, maxValue))
441: return false;
442: }
443:
444: return true;
445: }
446:
447: private boolean validateExpression(FourObjectContainer f, int rowNo)
448: throws Exception {
449: if (!_validateExpression)
450: return true;
451:
452: DataStoreEvaluator d = (DataStoreEvaluator) f.getObject2();
453: Boolean b = (Boolean) d.evaluateRow(rowNo);
454: return b.booleanValue();
455: }
456:
457: private boolean validateRequired(FourObjectContainer f, int rowNo)
458: throws Exception {
459: if (!_validateRequired)
460: return true;
461:
462: Object o = _ds.getAny(rowNo, (String) f.getObject2());
463: if (o == null)
464: return false;
465: else if (o.toString().trim().length() == 0)
466: return false;
467: else
468: return true;
469: }
470:
471: private boolean validateLookup(FourObjectContainer f1, int rowNo,
472: Statement st) throws Exception {
473: if (!_validateLookup)
474: return false;
475:
476: boolean retVal = false;
477:
478: FourObjectContainer f = (FourObjectContainer) f1.getObject2();
479: HtmlFormComponent comp = (HtmlFormComponent) f1.getObject4();
480:
481: String lookupTable = (String) f.getObject1();
482: DataStoreEvaluator d = (DataStoreEvaluator) f.getObject2();
483: String descColumn = (String) f.getObject3();
484: String descBucket = (String) f.getObject4();
485:
486: if (comp != null) {
487: if (comp.getDataStoreValue(rowNo) == null) {
488: if (descBucket != null)
489: _ds.setString(rowNo, descBucket, null);
490: return true;
491: }
492: }
493:
494: String sql = "";
495: if (descColumn != null)
496: sql = "SELECT " + descColumn + " FROM " + lookupTable
497: + " WHERE ";
498: else
499: sql = "SELECT count(*) FROM " + lookupTable + " WHERE ";
500:
501: sql += (String) d.evaluateRow(rowNo);
502:
503: Object desc = null;
504: ResultSet r = st.executeQuery(sql);
505:
506: int descCount = 0;
507: if (r.next()) {
508: if (descColumn == null) {
509: if (r.getInt(1) > 0)
510: retVal = true;
511: } else {
512: desc = r.getObject(1);
513: descCount = 1;
514: if (r.next())
515: descCount = 2;
516: retVal = true;
517: }
518: }
519: r.close();
520:
521: if (descBucket != null) {
522: if (comp.getParent() instanceof HtmlLookUpComponent) {
523: HtmlLookUpComponent parent = (HtmlLookUpComponent) comp
524: .getParent();
525: if (parent.getEditDescription()) {
526: if (_ds.getAny(rowNo, descBucket) == null)
527: _ds.setAny(rowNo, descBucket, desc);
528: } else
529: _ds.setAny(rowNo, descBucket, desc);
530: } else
531: _ds.setAny(rowNo, descBucket, desc);
532:
533: }
534:
535: return retVal;
536: }
537:
538: /**
539: * Return the number of rules in the validator
540: */
541: public int getRuleCount() {
542: return _rules.size();
543: }
544:
545: /**
546: * Returns the type of validation rule (com.salmonllc.sql.ValidationRule TYPE_ constants)
547: */
548: public int getRuleType(int ruleNo) {
549: FourObjectContainer cont = (FourObjectContainer) _rules
550: .elementAt(ruleNo);
551: String type = (String) cont.getObject1();
552: if (type == TYPE_EXP)
553: return ValidationRule.TYPE_EXPRESSION;
554: else if (type == TYPE_SQL)
555: return ValidationRule.TYPE_LOOKUP;
556: else if (type == TYPE_REQ)
557: return ValidationRule.TYPE_REQUIRED;
558: else if (type == TYPE_JS)
559: return ValidationRule.TYPE_JAVASCRIPT;
560: else if (type == TYPE_REGEXP)
561: return ValidationRule.TYPE_REGULAR_EXPRESSION;
562: else if (type == TYPE_RANGE)
563: return ValidationRule.TYPE_RANGE;
564: else
565: return -1;
566: }
567:
568: /**
569: * Returns the form component associated with a rule
570: */
571: public HtmlFormComponent getRuleFocusComponent(int ruleNo) {
572: FourObjectContainer cont = (FourObjectContainer) _rules
573: .elementAt(ruleNo);
574: return (HtmlFormComponent) cont.getObject4();
575: }
576:
577: /**
578: * Returns the error message associated with a rule
579: */
580: public String getRuleErrorMessage(int ruleNo) {
581: FourObjectContainer cont = (FourObjectContainer) _rules
582: .elementAt(ruleNo);
583: return (String) cont.getObject3();
584:
585: }
586:
587: RegularExpressionMatcher getRuleRegExpression(int ruleNo) {
588: FourObjectContainer cont = (FourObjectContainer) _rules
589: .elementAt(ruleNo);
590: TwoObjectContainer cont2 = (TwoObjectContainer) cont
591: .getObject2();
592: return (RegularExpressionMatcher) cont2.getObject2();
593:
594: }
595:
596: String getRuleJavaScript(int ruleNo) {
597: FourObjectContainer cont = (FourObjectContainer) _rules
598: .elementAt(ruleNo);
599: return (String) cont.getObject2();
600: }
601:
602: Object getRuleMinValue(int ruleNo) {
603: FourObjectContainer cont = (FourObjectContainer) _rules
604: .elementAt(ruleNo);
605: ThreeObjectContainer cont2 = (ThreeObjectContainer) cont
606: .getObject2();
607: return cont2.getObject2();
608: }
609:
610: Object getRuleMaxValue(int ruleNo) {
611: FourObjectContainer cont = (FourObjectContainer) _rules
612: .elementAt(ruleNo);
613: ThreeObjectContainer cont2 = (ThreeObjectContainer) cont
614: .getObject2();
615: return cont2.getObject3();
616: }
617:
618: /**
619: * @return
620: */
621: public boolean getValidateExpression() {
622: return _validateExpression;
623: }
624:
625: /**
626: * @return
627: */
628: public boolean getValidateLookup() {
629: return _validateLookup;
630: }
631:
632: /**
633: * @return
634: */
635: public boolean getValidateRange() {
636: return _validateRange;
637: }
638:
639: /**
640: * @return
641: */
642: public boolean getValidateRegExp() {
643: return _validateRegExp;
644: }
645:
646: /**
647: * @return
648: */
649: public boolean getValidateRequired() {
650: return _validateRequired;
651: }
652:
653: /**
654: * @param b
655: */
656: public void setValidateExpression(boolean b) {
657: _validateExpression = b;
658: }
659:
660: /**
661: * @param b
662: */
663: public void setValidateLookup(boolean b) {
664: _validateLookup = b;
665: }
666:
667: /**
668: * @param b
669: */
670: public void setValidateRange(boolean b) {
671: _validateRange = b;
672: }
673:
674: /**
675: * @param b
676: */
677: public void setValidateRegExp(boolean b) {
678: _validateRegExp = b;
679: }
680:
681: /**
682: * @param b
683: */
684: public void setValidateRequired(boolean b) {
685: _validateRequired = b;
686: }
687:
688: }
|