View Javadoc

1   package net.sourceforge.argval.impl;
2   
3   
4   import java.io.File;
5   import java.net.MalformedURLException;
6   import java.net.URI;
7   import java.net.URISyntaxException;
8   import java.net.URL;
9   import java.text.DateFormat;
10  import java.text.ParseException;
11  import java.text.SimpleDateFormat;
12  import java.util.ArrayList;
13  import java.util.Collection;
14  import java.util.HashMap;
15  import java.util.Iterator;
16  import java.util.List;
17  import java.util.Map;
18  import java.util.Properties;
19  import java.util.Set;
20  
21  import net.sourceforge.argval.ArgumentValidation;
22  import net.sourceforge.argval.lang.SystemConstants;
23  import net.sourceforge.argval.utils.StringUtil;
24  
25  import org.apache.oro.text.regex.MalformedPatternException;
26  import org.apache.oro.text.regex.Pattern;
27  import org.apache.oro.text.regex.PatternCompiler;
28  import org.apache.oro.text.regex.PatternMatcher;
29  import org.apache.oro.text.regex.Perl5Compiler;
30  import org.apache.oro.text.regex.Perl5Matcher;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  
35  /**
36   * The class for validating arguments of (public) methods and constructors (precondition checking).
37   * For each argument that does not fulfill the required 
38   * conditions, a message is added. These messages are used to create an <code>IllegalArgumentException</code> 
39   * before the real work of the method / constructor should be started.
40   *
41   * <a  name="exampleSimple">
42   * <h4>A simple example without pattern matching</h4>
43   * </a>
44   * <p>
45   * First the incoming Strings are polished, which in fact means that they are trimmed (str.trim()) and when only a 
46   * empty string remains it's changed into <code>null</code>.
47   * 
48   * <iframe  src="{@docRoot}/example/net/sourceforge/argval/example/ValidationDataSourceVersion.html" 
49   *   width="100%"  height="400">
50   * 
51   * <pre>
52   *   public ValidationDataSourceVersion(DataSource dataSource, String sqlQuery, String columnName, String version) {
53   *       // First polish the incoming String instances.
54   *       sqlQuery = ArgumentValidation.polish(sqlQuery);
55   *       version = ArgumentValidation.polish(version);
56   *       columnName = ArgumentValidation.polish(columnName);
57  
58   *       // Create the ArgumentValidation instance. 
59   *       ArgumentValidation argVal = new ArgumentValidation();
60   *       
61   *       // Check the conditions.
62   *       argVal.isValidWhenNotNull("dataSource", dataSource);
63   *       argVal.isValidWhenNotNull("sqlQuery", sqlQuery);
64   *       argVal.isValidWhenNotNull("version", version);
65   *       argVal.isValidWhenNotNull("columnName", columnName);
66   *       
67   *       // Create an IllegalArgumentException if not all argument conditions are met.
68   *       if (argVal.containsIllegalArgument()) throw argVal.createIllegalArgumentException();
69   *   
70   *       // Doing the real work for this method
71   *       .....
72   *   }
73   * </pre>
74   * </iframe>
75   * 
76   * There are several methods <code>isValidXxxx</code>, which can be used to validate all kinds of conditions. 
77   * </p>
78   *
79   * 
80   * <a  name="examplePatternSet">
81   * <h4>An example with pattern matching and set matching</h4>
82   * </a>
83   * <pre>
84   * public class Address {
85   *     private final static String PATTERN_DUTCH_POSTALCODE = "dutch_postalcode";
86   *     
87   *     private static Map patternMap;
88   *     private static Set countrySet;
89   *     
90   *     static {
91   *         patternMap = new HashMap();
92   *         patternMap.put(PATTERN_DUTCH_POSTALCODE, "^[0-9]{4}[ ]?[A-Z]{2}$");
93   *     
94   *         countrySet = new HashSet();
95   *         countrySet.add("The Netherlands");
96   *     }
97   *     
98   * public Address(String street, Integer houseNumber, String postbox, String postalCode, String city, String country) {
99   *     street = ArgumentValidation.polish(street);
100  *     postalCode = ArgumentValidation.polish(postalCode);
101  *     city = ArgumentValidation.polish(city);
102  *     country = ArgumentValidation.polish(country);
103  *     
104  *     ArgumentValidation argVal = new ArgumentValidation(patternMap);
105  *         if (argVal.isValidWhenNotNull("street", street)) {
106  *             argVal.isValidWhenGreaterThen("houseNumber", houseNumber.intValue(), 0);
107  *     	
108  *         if (postalCode != null) {
109  *             argVal.addError("When argument 'street' is given, no value for argument 'postbox' is expected.");
110  *         }
111  *     }
112  *     else if (argVal.isValidWhenNotNull("postbox", postbox)) {
113  *         if (argVal.isValidWhenNotNull("street", street)
114  *                 || argVal.isValidWhenGreaterThen("houseNumber", houseNumber.intValue(), 0)) {
115  *             argVal.addError("When argument 'postbox' is given, no values for argument 'street' and 'houseNumber' are expected.");
116  *         }
117  *     }
118  *     argVal.isValidMatchingPattern("postalCode", postalCode, PATTERN_DUTCH_POSTALCODE);
119  *     argVal.isValidWhenNotNull("city", city);
120  *     argVal.isValidWhenInSet("country", country, countrySet);
121  *     if (argVal.containsIllegalArgument()) throw argVal.createIllegalArgumentException();
122  *     
123  *     }
124  *     
125  * }
126  * </pre>
127  * 
128  * 
129  * <a  name="examplePattern">
130  * <h4>An example with pattern matching, patterns added through a Properties instance</h4>
131  * </a>
132  * <p>
133  * <pre>
134  *   private final static String PATTERN_NUMBER = "number";
135  *   private final static String PATTERN_DUTCH_POSTALCODE = "dutch_postalcode";
136  * 
137  *   private static Properties properties;
138  *   
139  *   // Inside the constructor (or static initialization) create a (static) Properties instance, or inject it!
140  *   public Constructor() {
141  *       // Creating a Properties instance, with two pattern names {'number', postalcode'}.
142  *       // Add for each pattern name a regular expression. As property file it should look like:
143  *       // argument_validation.patterns = number postalcode 
144  *       // argument_validation.number.regexp = ^[0-9]+$
145  *       // argument_validation.postalcode.regexp = ^[0-9]{4}[ ]?[A-Z]{2}$
146  *       properties = new Properties();
147  *       properties.setProperty(ConfigurationManager.PROP_ARG_VAL_PATTERNS, PATTERN_NUMBER + " " + PATTERN_DUTCH_POSTALCODE);
148  *       properties.setProperty(PropertiesUtil.createKey(
149  *    		   ConfigurationManager.PROP_ARG_VAL, PATTERN_NUMBER, ConfigurationManager.PROP_POSTFIX_REG_EXP), "^[0-9]+$");
150  *       properties.setProperty(PropertiesUtil.createKey(
151  *    		   ConfigurationManager.PROP_ARG_VAL, PATTERN_DUTCH_POSTALCODE, ConfigurationManager.PROP_POSTFIX_REG_EXP), "^[0-9]{4}[ ]?[A-Z]{2}$");
152  *   }
153  *   
154  *   
155  *   public void doSomething(String number, String postalcode) {
156  *       postalcode = ArgumentValidation.polishToUpper(postalcode);     
157  *       ArgumentValidation argVal = new ArgumentValidation(properties);
158  *       
159  *       // Check the conditions by using regular expressions
160  *       argVal.isValidMatchingPattern("number", number, PATTERN_NUMBER);
161  *       argVal.isValidMatchingPattern("postalcode", postalcode, PATTERN_DUTCH_POSTALCODE);
162  *       
163  *       // Create an IllegalArgumentException if not all argument conditions are met.
164  *       if (argVal.containsIllegalArgument()) throw argVal.createIllegalArgumentException();
165  *       
166  *       // Doing the real work for this method
167  *       .....
168  *   }
169  * </pre>
170  * </p>
171  * <p>
172  * The patterns can also be added through a properties file. Each pattern must have a name, through which the 
173  * method <code>isValidMatchingPattern(&lt;arg as string&gt;, &lt;arg&gt;, &lt;pattern name&gt;)</code> will 
174  * access the regular expression. Each pattern name has to be named under the key 
175  * <code>argument_validation.patterns</code>. To assign each pattern name a regular expression, the key
176  * combination of <code>argument_validation.&lt;pattern name&gt;.regexp</code> is used. 
177  * <pre>
178  * argument_validation.patterns = number postalcode 
179  * argument_validation.number.regexp = ^[0-9]+$
180  * argument_validation.postalcode.regexp = ^[0-9]{4}[ ]?[A-Z]{2}$
181  * </pre>
182  * </p>
183  * 
184  * @author T. Verhagen
185  */
186 public class ArgumentValidationImpl implements ArgumentValidation {
187     /** The logging instance. */
188     transient static Logger logger = LoggerFactory.getLogger(ArgumentValidationImpl.class);
189 
190     /** The line separator. */
191     private final static String SEPARATOR = System.getProperty(SystemConstants.LINE_SEPARATOR);
192     /** This list contains the messages about the conditions that are not satisfied. */
193     private List<String> errorList;
194     
195     private Map<String, DateFormat> dateFormatMap;
196     /** This map contains the pattern names and their related regular expressions, which are 
197      * used by the validations with regularExpressions. */
198     private Map<String, Pattern> patternMap;
199     ///** The regular expression pattern compiler. */
200     //private PatternCompiler compiler;
201     /** The regular expression pattern matcher. */
202     private PatternMatcher matcher;
203     
204     private String validationTypeName = ArgumentValidation.VALIDATION_TYPE_NAME_ARGUMENT;
205 
206     /** The default constructor. */
207     public ArgumentValidationImpl() {
208     	this((String)null);
209     }
210     /** The default constructor. */
211     public ArgumentValidationImpl(String validationTypeName) {
212         super();
213     	validationTypeName = polish(validationTypeName);
214     	
215     	if (validationTypeName != null) {
216     		this.validationTypeName = validationTypeName;
217     	}
218     	else {
219     		this.validationTypeName = ArgumentValidation.VALIDATION_TYPE_NAME_ARGUMENT; 
220     	}
221         errorList = new ArrayList<String>();
222         dateFormatMap = new HashMap<String, DateFormat>();
223         patternMap = new HashMap<String, Pattern>();
224     }
225     /**
226      * Construct an <code>ArgumentValidation</code> instance, which can also validate 
227      * against regular expressions. It will use the <code>org.apache.oro.text.regex.Perl5Compiler</code> 
228      * and <code>org.apache.oro.text.regex.Perl5Matcher</code>. See for detailed information on 
229      * <a  href="http://jakarta.apache.org/oro/api/org/apache/oro/text/regex/package-summary.html#package_description}">
230      * creating regular expressions</a> the package description.
231      * 
232      * @param  patternMap  A <code>Map</code> instance, containing pattern names and their regular expressions.
233      */
234     public ArgumentValidationImpl(Map<String, String> patternMap) {
235         this(patternMap, new Perl5Compiler(), new Perl5Matcher());
236     }
237     public ArgumentValidationImpl(Map<String, String> patternMap, String validationTypeName) {
238         this(patternMap, new Perl5Compiler(), new Perl5Matcher(), validationTypeName);
239     }
240     // TODO
241     public ArgumentValidationImpl(Map<String, String> patternMap, Map<String, String> dateFormatMap) {
242         this(patternMap, new Perl5Compiler(), new Perl5Matcher(), dateFormatMap);
243     }
244     public ArgumentValidationImpl(Map<String, String> patternMap, Map<String, String> dateFormatMap, String validationTypeName) {
245         this(patternMap, new Perl5Compiler(), new Perl5Matcher(), dateFormatMap, validationTypeName);
246     }
247     /**
248      * Construct an <code>ArgumentValidation</code> instance, which can also validate 
249      * against regular expressions. It will use the <code>org.apache.oro.text.regex.Perl5Compiler</code> 
250      * and <code>org.apache.oro.text.regex.Perl5Matcher</code>. See for detailed information on 
251      * <a  href="http://jakarta.apache.org/oro/api/org/apache/oro/text/regex/package-summary.html#package_description}">
252      * creating regular expressions</a> the package description.
253      * 
254      * @param  properties  A properties instance, containing pattern names and their regular expressions.
255      * /
256     public ArgumentValidation(Properties properties) {
257         this(properties, new Perl5Compiler(), new Perl5Matcher());
258     }//*/
259     /**
260      * Construct an <code>ArgumentValidation</code> instance, which can also validate 
261      * against regular expressions. See for detailed information on 
262      * <a  href="http://jakarta.apache.org/oro/api/org/apache/oro/text/regex/package-summary.html#package_description}">
263      * creating regular expressions</a> the package description.  
264      *  
265      * @param  patternMap  A <code>Map</code> instance, containing pattern names and their regular expressions.
266      * @param  compiler  A <code>org.apache.oro.text.regex.PatternCompiler</code> compiler.
267      * @param  matcher  A <code>org.apache.oro.text.regex.PatternMatcher</code> matcher.
268      */
269     public ArgumentValidationImpl(Map<String, String> patternMap, PatternCompiler compiler, PatternMatcher matcher) {
270         this(patternMap, compiler, matcher, new HashMap<String, String>());
271     }
272     public ArgumentValidationImpl(Map<String, String> patternMap, PatternCompiler compiler, PatternMatcher matcher,
273     		String validationTypeName) {
274         this(patternMap, compiler, matcher, new HashMap<String, String>(), validationTypeName);
275     }
276     // TODO [2007.07.18 tv] Add javadoc.
277     public ArgumentValidationImpl(Map<String, String> patternMap, 
278             PatternCompiler compiler, PatternMatcher matcher, Map<String, String> dateFormatMap) {
279     	this(patternMap, compiler, matcher, dateFormatMap, null);
280     }
281     /**
282      * 
283      * @param patternMap
284      * @param compiler
285      * @param matcher
286      * @param dateFormatMap
287      * @param validationTypeName - The type of validation (default 'Argument'), but use this
288      *                             for checking other type of things like 'Property-key's.
289      */
290     public ArgumentValidationImpl(Map<String, String> patternMap, 
291             PatternCompiler compiler, PatternMatcher matcher, Map<String, String> dateFormatMap,
292             String validationTypeName) {
293         this();
294         if (patternMap == null) {
295             throw new IllegalArgumentException("Argument 'patternMap' should not be null.");
296         }
297         if (compiler == null) {
298             throw new IllegalArgumentException("Argument 'compiler' should not be null.");
299         }
300         if (matcher == null) {
301             throw new IllegalArgumentException("Argument 'matcher' should not be null.");
302         }
303         if (dateFormatMap == null) {
304             throw new IllegalArgumentException("Argument 'dateFormatMap' should not be null.");
305         }
306         
307         validationTypeName = polish(validationTypeName);
308         if (validationTypeName == null) {
309         	validationTypeName = ArgumentValidation.VALIDATION_TYPE_NAME_ARGUMENT;
310         }
311         
312         //this.compiler = compiler;
313         this.matcher = matcher;
314 
315         for (Iterator<String> iter = patternMap.keySet().iterator(); iter.hasNext();) {
316             String patternName = (String)iter.next();
317             String regExpStr = (String)patternMap.get(patternName);
318             try {
319                 Pattern pattern = compiler.compile(regExpStr);
320                 this.patternMap.put(patternName, pattern);
321                 logger.debug("Created Pattern instance '" + patternName + "' with reg exp '" + regExpStr + "'.");
322             }
323             catch (MalformedPatternException mpe) {
324                 logger.error("The pattern '" + patternName + "' with regular expression '" + regExpStr + "' is not correct.", mpe);
325             }
326         }
327         
328         for (Iterator<String> iter = dateFormatMap.keySet().iterator(); iter.hasNext();) {
329             String dateFormatName = (String)iter.next();
330             String datePattern = (String)dateFormatMap.get(dateFormatName);
331             try {
332                 DateFormat dateFormat = new SimpleDateFormat(datePattern);
333                 this.dateFormatMap.put(dateFormatName, dateFormat);
334                 logger.debug("Created DateFormat instance '" + dateFormatName + "' with simple date pattern '" + datePattern + "'.");
335             }
336             catch (NullPointerException npe) {
337                 logger.error("The date format name '" + dateFormatName + "' with simple date pattern '" + datePattern + "' is not correct.", npe);
338             }
339             catch (IllegalArgumentException iae) {
340                 logger.error("The date format name '" + dateFormatName + "' with simple date pattern '" + datePattern + "' is not correct.", iae);
341             }
342         }
343     }
344     /**
345      * TODO [2007.07.18 tv] update with date pattern
346      * Construct an <code>ArgumentValidation</code> instance, which can also validate 
347      * against regular expressions. See for detailed information on 
348      * <a  href="http://jakarta.apache.org/oro/api/org/apache/oro/text/regex/package-summary.html#package_description}">
349      * creating regular expressions</a> the package description.  
350      *  
351      * @param  properties  A properties instance, containing pattern names and their regular expressions.
352      * @param  compiler  A <code>org.apache.oro.text.regex.PatternCompiler</code> compiler.
353      * @param  matcher  A <code>org.apache.oro.text.regex.PatternMatcher</code> matcher.
354      */
355     public ArgumentValidationImpl(Properties properties, PatternCompiler compiler, PatternMatcher matcher) {
356         this(new PropertiesConfigurationManager().createPatternMap(properties), compiler, matcher, new PropertiesConfigurationManager().createDateFormatMap(properties));
357     }
358     
359     
360     /* (non-Javadoc)
361      * @see net.sourceforge.argval.ArgumentValidation#getMessage()
362      */
363     public String getMessage() {
364         if (errorList.size() == 0) {
365             return null;
366         }
367         StringBuffer strBuf = new StringBuffer();
368         boolean isFirst = true;
369         Iterator<String> iter = errorList.iterator();
370         while (iter.hasNext()) {
371             strBuf.append(isFirst ? "" : SEPARATOR ).append(iter.next());
372             isFirst = false;
373         }
374         
375         return strBuf.toString();
376     }
377 
378     
379     /* (non-Javadoc)
380      * @see net.sourceforge.argval.ArgumentValidation#containsIllegalArgument()
381      */
382     public boolean containsIllegalArgument() {
383         return errorList.size() > 0;
384     }
385 
386 
387     /* (non-Javadoc)
388      * @see net.sourceforge.argval.ArgumentValidation#createIllegalArgumentException()
389      */
390     public IllegalArgumentException createIllegalArgumentException() {
391         return new IllegalArgumentException(getMessage());
392     }
393 
394 
395     /* (non-Javadoc)
396      * @see net.sourceforge.argval.ArgumentValidation#isValidWhenNotNull(java.lang.String, java.lang.Object)
397      */
398     public boolean isValidWhenNotNull(String argumentName, Object argumentValue) {
399         if (argumentValue == null) {
400             addError(argumentName, "should not be null.");
401             return false;
402         }
403         return true;
404     }
405 
406     public boolean isValidWhenNotNullInCollection(String argumentName, Collection<?> argumentValue) {
407         if (isValidWhenNotNull(argumentName, argumentValue)) {
408             Object[] argValueArray = argumentValue.toArray(new Object[argumentValue.size()]);
409             for (int index = 0; index < argValueArray.length; index++) {
410                 if (argValueArray[index] == null) {
411                     return false;
412                 }
413             }
414             return true;
415         }
416         return false;
417     }
418 
419     /**
420      * Add an error message, for the given argumentName, to the list of error messages.
421      * @param argumentName - the argument (or property-key) in which the problem is found. 
422      * @param message - the message that describes the problem.
423      */
424     public void addError(String argumentName, String message) {
425     	errorList.add(validationTypeName + " '" + argumentName + "' " + message);
426 	}
427 
428     public void addError(String argumentName, String key, String message) {
429         errorList.add(validationTypeName + " '" + argumentName + "[" + key + "]' " + message);
430     }
431     
432 	/* (non-Javadoc)
433      * @see net.sourceforge.argval.ArgumentValidation#isValidWhenBoolean(java.lang.String, java.lang.String)
434      */
435     public boolean isValidWhenBoolean(String argumentName, String argumentValue) {
436         if (isValidWhenNotNull(argumentName, argumentValue)) {
437             if (Boolean.FALSE.toString().toLowerCase().equals(argumentValue.toLowerCase())
438                     || Boolean.TRUE.toString().toLowerCase().equals(argumentValue.toLowerCase())) {
439                 return true;
440             }
441             else {
442             	addError(argumentName, "should be a boolean.");
443             }
444         }
445         return false;
446     }
447 
448     
449     /* (non-Javadoc)
450      * @see net.sourceforge.argval.ArgumentValidation#isValidWhenInteger(java.lang.String, java.lang.String)
451      */
452     public boolean isValidWhenInteger(String argumentName, String argumentValue) {
453         try {
454             Integer.parseInt(argumentValue);
455         }
456         catch (NumberFormatException nfe) {
457         	addError(argumentName, "should be a number which can be parsed into an Integer.");
458             return false;
459         }
460         return true;
461     }
462 
463     
464     /* (non-Javadoc)
465      * @see net.sourceforge.argval.ArgumentValidation#isValidWhenLong(java.lang.String, java.lang.String)
466      */
467     public boolean isValidWhenLong(String argumentName, String argumentValue) {
468         try {
469             Long.parseLong(argumentValue);
470         }
471         catch (NumberFormatException nfe) {
472         	addError(argumentName, "should be a number which can be parsed into a Long.");
473             return false;
474         }
475         return true;
476     }
477 
478 
479     /* (non-Javadoc)
480      * @see net.sourceforge.argval.ArgumentValidation#isValidWhenDirectory(java.lang.String, java.lang.String)
481      */
482     public boolean isValidWhenDirectory(String argumentName, String argumentValue) {
483         if (! isValidWhenNotNull(argumentName, argumentValue)) {
484         	return false;
485         }
486         return isValidWhenDirectory(argumentName, new File(argumentValue));
487     }
488     public boolean isValidWhenDirectory(String argumentName, File argumentValue) {
489         if (! isValidWhenNotNull(argumentName, argumentValue)) {
490         	return false;
491         }
492         if (! argumentValue.isDirectory() || ! argumentValue.exists()) {
493         	addError(argumentName, "with value '" + argumentValue + "' should be an existing path.");
494             return false;
495         }
496         return true;
497     }
498     
499     
500     /* (non-Javadoc)
501      * @see net.sourceforge.argval.ArgumentValidation#isValidWhenFile(java.lang.String, java.lang.String)
502      */
503     public boolean isValidWhenFile(String argumentName, String argumentValue) {
504         if (! isValidWhenNotNull(argumentName, argumentValue)) {
505         	return false;
506         }
507         return isValidWhenFile(argumentName, new File(argumentValue));
508     }
509     public boolean isValidWhenFile(String argumentName, File argumentValue) {
510         if (! isValidWhenNotNull(argumentName, argumentValue)) {
511         	return false;
512         }
513         if (! argumentValue.isFile() || ! argumentValue.exists()) {
514         	addError(argumentName, "with value '" + argumentValue + "' should be an existing file.");
515             return false;
516         }
517         return true;
518     }
519 
520     
521     /* (non-Javadoc)
522      * @see net.sourceforge.argval.ArgumentValidation#isValidWhenUrl(java.lang.String, java.lang.String)
523      */
524     public boolean isValidWhenUrl(String argumentName, String argumentValue) {
525         try {
526             new URL(argumentValue);
527         } 
528         catch (MalformedURLException murle) {
529         	addError(argumentName, "with value '" + argumentValue + "' is not a valid url.");
530             return false;
531         }
532         return true;
533     }
534     
535     
536     public boolean isValidWhenUri(String argumentName, String argumentValue) {
537         try {
538             new URI(argumentValue);
539         } 
540         catch (URISyntaxException urise) {
541         	addError(argumentName, "with value '" + argumentValue + "' is not a valid uri.");
542             return false;
543 		}
544         return true;
545     }
546     
547     
548     /* (non-Javadoc)
549      * @see net.sourceforge.argval.ArgumentValidation#isValidWhenInSet(java.lang.String, java.lang.String, java.util.Set)
550      */
551     public boolean isValidWhenInSet(String argumentName, String argumentValue, Set<String> argumentSet) {
552         if (isValidWhenNotNull(argumentName, argumentValue)) {
553             if (! argumentSet.contains(argumentValue)) {
554                 StringBuffer strBuf = new StringBuffer();
555                 strBuf.append(validationTypeName).append(" '").append(argumentName).append("' with value '").append(argumentValue);
556                 strBuf.append("' should contain one of the following values { ");
557                 boolean isFirst = true;
558                 Iterator<String> iter = argumentSet.iterator();
559                 while (iter.hasNext()) {
560                     strBuf.append((isFirst) ? "'" : "', '");
561                     strBuf.append(iter.next().toString());
562                     isFirst = false;
563                 }
564                 if (!isFirst) {
565                     strBuf.append("'");
566                 }
567                 strBuf.append(" }.");
568                 errorList.add(strBuf.toString());
569                 return false;
570             }
571             return true;
572         }
573         return false;
574     }
575     /* (non-Javadoc)
576      * @see net.sourceforge.argval.ArgumentValidation#isValidWhenNotInSet(java.lang.String, java.lang.String, java.util.Set)
577      */
578     public boolean isValidWhenNotInSet(String argumentName, String argumentValue, Set<String> argumentSet) {
579         if (isValidWhenNotNull(argumentName, argumentValue)) {
580             if (argumentSet.contains(argumentValue)) {
581                 StringBuffer strBuf = new StringBuffer();
582                 strBuf.append(validationTypeName).append(" '").append(argumentName).append("' with value '").append(argumentValue);
583                 strBuf.append("' should not be contained by the given set.");
584                 errorList.add(strBuf.toString());
585                 return false;
586             }
587             return true;
588         }
589         return false;
590     }
591     
592     
593     public boolean isValidCollectionWhenNoNulls(String argumentName, Collection<?> argumentValue) {
594         if (isValidWhenNotNull(argumentName, argumentValue)) {
595         	if (argumentValue.size() > 0) {
596         		Object[] argumentValueArray = argumentValue.toArray();
597         		StringBuilder builder = new StringBuilder();
598         		for (int index = 0; index < argumentValueArray.length; index++) {
599         			Object element = argumentValueArray[index];
600 					if (element instanceof String) {
601 						String elementStr = polish((String)element);
602 						if (elementStr == null) {
603 	        				if (builder.length() > 0) {
604 	        					builder.append(", ");
605 	        				}
606 	        				builder.append(index);
607 						}
608 					}
609 					else if (element == null) {
610         				if (builder.length() > 0) {
611         					builder.append(", ");
612         				}
613         				builder.append(index);
614         			}
615 				}
616 				if (builder.length() > 0) {
617 					addError(argumentName , "is expected to have no null elements. Found null on following elements '"
618 							+ builder + "'.");
619 					return false;
620 				}
621         	}
622         	return true;
623         }
624         return false;
625     }
626     
627 
628     public boolean isValidCollectionWhenMinElements(String argumentName, Collection<?> argumentValue, int minElements) {
629         if (isValidWhenNotNull(argumentName, argumentValue)) {
630         	if (argumentValue.size() < minElements) {
631         		addError(argumentName, "is expected to have at least " + minElements + " element(s).");
632 				return false;
633         	}
634         	return true;
635         }
636         return false;
637     }
638 
639     
640     /* (non-Javadoc)
641      * @see net.sourceforge.argval.ArgumentValidation#isValidWhenGreaterThen(java.lang.String, int, int)
642      */
643     public boolean isValidWhenGreaterThen(String argumentName, int argumentValue, int value) {
644         if (argumentValue > value) {
645             return true;
646         }
647         StringBuffer strBuf = new StringBuffer();
648         strBuf.append(validationTypeName).append(" '").append(argumentName).append("' should have at least a value of '")
649                 .append(argumentValue).append("'. The given value is '")
650                 .append(argumentValue).append("'.");
651         errorList.add(strBuf.toString());
652         return false;
653     }
654 
655 
656     /* (non-Javadoc)
657      * @see net.sourceforge.argval.ArgumentValidation#isValidStringMinLength(java.lang.String, java.lang.String, int)
658      */
659     public boolean isValidStringMinLength(String argumentName, String argumentValue, int minLength) {
660         if (isValidWhenNotNull(argumentName, argumentValue)) {
661             if (argumentValue.length() < minLength) {
662                 createErrorInLength(argumentName, argumentValue, minLength, "a minimal");
663                 return false;
664             }
665         }
666         return true;
667     }
668 
669     
670     /* (non-Javadoc)
671      * @see net.sourceforge.argval.ArgumentValidation#isValidStringMaxLength(java.lang.String, java.lang.String, int)
672      */
673     public boolean isValidStringMaxLength(String argumentName, String argumentValue, int maxLength) {
674         if (isValidWhenNotNull(argumentName, argumentValue)) {
675             if (argumentValue.length() > maxLength) {
676                 createErrorInLength(argumentName, argumentValue, maxLength, "a maximal");
677                 return false;
678             }
679         }
680         return true;
681     }
682 
683     
684     /* (non-Javadoc)
685      * @see net.sourceforge.argval.ArgumentValidation#isValidStringLength(java.lang.String, java.lang.String, int)
686      */
687     public boolean isValidStringLength(String argumentName, String argumentValue, int length) {
688         if (isValidWhenNotNull(argumentName, argumentValue)) {
689             if (argumentValue.length() != length) {
690                 createErrorInLength(argumentName, argumentValue, length, "an exact");
691                 return false;
692             }
693         }
694         return true;
695     }
696     
697 
698     /* (non-Javadoc)
699      * @see net.sourceforge.argval.ArgumentValidation#isValidStringMinAndMaxLength(java.lang.String, java.lang.String, int, int)
700      */
701     public boolean isValidStringMinAndMaxLength(String argumentName, String argumentValue, int minLength, int maxLength) {
702         if (isValidWhenNotNull(argumentName, argumentValue)) {
703             if (argumentValue.length() < minLength) {
704                 createErrorInLength(argumentName, argumentValue, minLength, "a minimal");
705                 return false;
706             }
707             else if (argumentValue.length() > maxLength) {
708                 createErrorInLength(argumentName, argumentValue, maxLength, "a maximal");
709                 return false;
710             }
711         }
712         return true;
713     }
714     
715     
716     /* (non-Javadoc)
717      * @see net.sourceforge.argval.ArgumentValidation#isValidMatchingDateFormat(java.lang.String, java.lang.String, java.text.DateFormat)
718      */
719     public boolean isValidMatchingDateFormat(String argumentName, String argumentValue, DateFormat dateFormat) {
720         if (! isValidWhenNotNull(argumentName, argumentValue)) {
721             return false;
722         }
723         try {
724             dateFormat.parse(argumentValue);
725         } 
726         catch (ParseException e) {
727             //e.printStackTrace();
728         	addError(argumentName, "with value '" + argumentValue 
729                     + "' does not match the given date format pattern '" 
730                     + ((dateFormat instanceof SimpleDateFormat) 
731                             ? ((SimpleDateFormat)dateFormat).toPattern() : dateFormat.toString())
732                     + "'.");
733             return false;
734         }
735         
736         return true;
737     }
738     
739 
740     /* (non-Javadoc)
741      * @see net.sourceforge.argval.ArgumentValidation#isValidMatchingDateFormat(java.lang.String, java.lang.String, java.lang.String)
742      */
743     public boolean isValidMatchingDateFormat(String argumentName, String argumentValue, String dateFormatName) {
744         if (dateFormatName != null && ! dateFormatMap.keySet().contains(dateFormatName)) {
745             throw new IllegalArgumentException("There is no date format known with the name '" + dateFormatName + "'.");
746         }
747         DateFormat dateFormat = (DateFormat)dateFormatMap.get(dateFormatName);
748         
749         logger.debug((dateFormat != null) ? "Date format '" + dateFormatName + "' is available as '" 
750                 + ((dateFormat instanceof SimpleDateFormat) 
751                         ? ((SimpleDateFormat)dateFormat).toPattern() : dateFormat.toString()) 
752                 + "'" : "No date format available.");
753 
754         return isValidMatchingDateFormat(argumentName, argumentValue, dateFormat);
755 //        if (! isValidWhenNotNull(argumentName, argumentValue)) {
756 //            return false;
757 //        }
758 //        try {
759 //            dateFormat.parse(argumentValue);
760 //        } 
761 //        catch (ParseException e) {
762 //            //e.printStackTrace();
763 //            errorList.add("Argument '" + argumentName + "' with value '" + argumentValue 
764 //                    + "' does not match the given date format pattern '" 
765 //                    + ((dateFormat instanceof SimpleDateFormat) 
766 //                            ? ((SimpleDateFormat)dateFormat).toPattern() : dateFormat.toString())
767 //                    + "'.");
768 //            return false;
769 //        }
770 //
771 //        return true;
772     }
773 
774 
775     /* (non-Javadoc)
776      * @see net.sourceforge.argval.ArgumentValidation#isValidMatchingPattern(java.lang.String, java.lang.String, java.lang.String)
777      */
778     public boolean isValidMatchingPattern(String argumentName, String argumentValue, String patternName) {
779         if (patternName != null && ! patternMap.keySet().contains(patternName)) {
780             throw new IllegalArgumentException("There is no pattern known with the name '" + patternName + "'.");
781         }
782         Pattern pattern = (Pattern)patternMap.get(patternName);
783         logger.debug((pattern != null) ? "Pattern '" + patternName + "' is available as '" + pattern.getPattern() + "'" : "No pattern available.");
784 
785         if (! isValidWhenNotNull(argumentName, argumentValue)) {
786             return false;
787         }
788         if (! matcher.matches(argumentValue, pattern)) {
789             errorList.add("Argument '" + argumentName + "' with value '" + argumentValue 
790                     + "' does not match the given regular expression pattern '" 
791                     + pattern.getPattern() + "'.");
792             return false;
793         }
794         
795         return true;
796     }
797     
798     
799     /**
800      * Helper method for creating an error message about the length conditions for a String argument.
801      *  
802      * @param  argumentName  The name of the argument as it is named in the method.
803      * @param  argumentValue
804      * @param  theLength
805      * @param  lengthConditionStr
806      */
807     private void createErrorInLength(String argumentName, String argumentValue, int theLength, String lengthConditionStr) {
808         StringBuffer strBuf = new StringBuffer();
809         strBuf.append(validationTypeName).append(" '").append(argumentName).append("' should have ").append(lengthConditionStr);
810         strBuf.append(" length of '").append(theLength).append("'. The given value has a length of '");
811         strBuf.append(argumentValue.length()).append("'.");
812         errorList.add(strBuf.toString());
813     }
814     
815     
816     /* (non-Javadoc)
817      * @see net.sourceforge.argval.ArgumentValidation#addError(java.lang.String)
818      */
819     public void addError(String error) {
820         error = ArgumentValidationImpl.polish(error);
821         if (error == null) {
822             return;
823         }
824         errorList.add(error);
825     }
826 
827 
828     /* (non-Javadoc)
829      * @see net.sourceforge.argval.ArgumentValidation#getPatternNames()
830      */
831     public Set<String> getPatternNames() {
832         return patternMap.keySet();
833     }
834     
835 
836     /* (non-Javadoc)
837      * @see net.sourceforge.argval.ArgumentValidation#getPattern()
838      */
839     public Map<String, String> getPattern() {
840         Map<String, String> patternMap = new HashMap<String, String>();
841         for (Iterator<String> iter = this.patternMap.keySet().iterator(); iter.hasNext(); ) {
842             String patternName = (String)iter.next();
843             patternMap.put(patternName, ((Pattern)this.patternMap.get(patternName)).getPattern());
844         }
845         return patternMap;
846     }
847     
848     
849     /* (non-Javadoc)
850      * @see net.sourceforge.argval.ArgumentValidation#getPattern(java.lang.String)
851      */
852     public Pattern getPattern(String patternName) {
853         if (! patternMap.containsKey(patternName)) {
854             throw new IllegalArgumentException("Argument 'patternName' with the value '" 
855                     + patternName + "' is not known.");
856         }
857         return (Pattern)patternMap.get(patternName);
858     }
859     
860     
861     /* (non-Javadoc)
862      * @see net.sourceforge.argval.ArgumentValidation#getRegularExpression(java.lang.String)
863      */
864     public String getRegularExpression(String patternName) {
865         if (! patternMap.containsKey(patternName)) {
866             throw new IllegalArgumentException("Argument 'patternName' with the value '" 
867                     + patternName + "' is not known.");
868         }
869         return ((Pattern)patternMap.get(patternName)).getPattern();
870     }
871     
872     
873     /**
874      * Returns the incoming text, but stripes leading and trailing spaces and returns <code>null</code> 
875      * when the (remaining) text is an empty String instance.
876      * 
877      * @param  text  The text to polish.
878      * @return  The text without leading and trailing spaces that remains or 
879      *          <code>null</code>, when no characters are left.
880      */
881     public static String polish(String text) {
882         if (text == null) {
883             return null;
884         }
885         text = text.trim();
886         
887         if (text.length() == 0) {
888             return null;
889         }
890         return text;
891     }
892     /**
893      * Returns the incoming text polished (see {@link #polish(String)} and converted into lower case.
894      * 
895      * @param  text  The text to polish and convert.
896      * @return  The polished and to lower case converted text. 
897      * 
898      * @see #polish(String)
899      */
900     public static String polishToLower(String text) {
901         text = ArgumentValidationImpl.polish(text);
902         return text == null ? null : text.toLowerCase();
903     }
904     /**
905      * Returns the incoming text polished (see {@link #polish(String)} and converted into upper case.
906      * 
907      * @param  text  The text to polish and convert.
908      * @return  The polished and to upper case converted text. 
909      * 
910      * @see #polish(String)
911      */
912     public static String polishToUpper(String text) {
913         text = ArgumentValidationImpl.polish(text);
914         return text == null ? null : text.toUpperCase();
915     }
916     
917     public boolean isValidNotNullForKey(String argumentName, Map<String, String> argumentValueMap, String key) {
918         String value = StringUtil.polish(argumentValueMap.get(key));
919         if (value == null) {
920             addError(argumentName, key, "should not be null.");
921             return false;
922         }
923         return true;
924     }
925 
926 }