--- /dev/null
+package com.itmill.toolkit.data.validator;\r
+\r
+/**\r
+ * Validator base class for validating strings. See\r
+ * {@link com.itmill.toolkit.data.validator.AbstractValidator} for more\r
+ * information.\r
+ * \r
+ * <p>\r
+ * If the validation fails, the exception thrown contains the error message with\r
+ * its argument 0 replaced with the string being validated.\r
+ * </p>\r
+ * \r
+ * @author IT Mill Ltd.\r
+ * @version\r
+ * @VERSION@\r
+ * @since 5.4\r
+ */\r
+public abstract class AbstractStringValidator extends AbstractValidator {\r
+\r
+ /**\r
+ * Constructs a validator for strings.\r
+ * <p>\r
+ * Null and empty string values are always accepted. To disallow empty\r
+ * values, set the field being validated as required.\r
+ * </p>\r
+ * \r
+ * @param errorMessage\r
+ * the message included in the exception (with its parameter {0}\r
+ * replaced by the string to be validated) in case the validation\r
+ * fails\r
+ */\r
+ public AbstractStringValidator(String errorMessage) {\r
+ super(errorMessage);\r
+ }\r
+\r
+ public boolean isValid(Object value) {\r
+ if (value == null) {\r
+ return true;\r
+ }\r
+ if (!(value instanceof String)) {\r
+ return false;\r
+ }\r
+ return isValidString((String) value);\r
+ }\r
+\r
+ /**\r
+ * Checks if the given string is valid.\r
+ * \r
+ * @param value\r
+ * String to check. Can never be null.\r
+ * @return true if the string is valid, false otherwise\r
+ */\r
+ protected abstract boolean isValidString(String value);\r
+}\r
--- /dev/null
+package com.itmill.toolkit.data.validator;\r
+\r
+import com.itmill.toolkit.data.Validator;\r
+\r
+/**\r
+ * Default Validator base class. See\r
+ * {@link com.itmill.toolkit.data.validator.Validator} for more information.\r
+ * <p>\r
+ * If the validation fails, the exception thrown contains the error message with\r
+ * its argument 0 replaced with the toString() of the object being validated.\r
+ * </p>\r
+ * \r
+ * @author IT Mill Ltd.\r
+ * @version\r
+ * @VERSION@\r
+ * @since 5.4\r
+ */\r
+public abstract class AbstractValidator implements Validator {\r
+\r
+ /**\r
+ * Error message.\r
+ */\r
+ private String errorMessage;\r
+\r
+ /**\r
+ * Constructs a validator with an error message.\r
+ * \r
+ * @param errorMessage\r
+ * the message included in the exception (with its parameter {0}\r
+ * replaced by toString() of the object to be validated) in case\r
+ * the validation fails\r
+ */\r
+ public AbstractValidator(String errorMessage) {\r
+ this.errorMessage = errorMessage;\r
+ }\r
+\r
+ public void validate(Object value) throws InvalidValueException {\r
+ if (!isValid(value)) {\r
+ String message;\r
+ if (value == null) {\r
+ message = errorMessage.replace("{0}", "null");\r
+ } else {\r
+ message = errorMessage.replace("{0}", value.toString());\r
+ }\r
+ throw new InvalidValueException(message);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Gets the message to be displayed in case the value does not validate.\r
+ * \r
+ * @return the Error Message.\r
+ */\r
+ public String getErrorMessage() {\r
+ return errorMessage;\r
+ }\r
+\r
+ /**\r
+ * Sets the message to be displayed in case the value does not validate.\r
+ * \r
+ * @param errorMessage\r
+ * the Error Message to set.\r
+ */\r
+ public void setErrorMessage(String errorMessage) {\r
+ this.errorMessage = errorMessage;\r
+ }\r
+}\r
import java.util.Collection;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.LinkedList;
+import java.util.List;
import com.itmill.toolkit.data.Validator;
* @VERSION@
* @since 3.0
*/
-public class CompositeValidator implements Validator {
+public class CompositeValidator extends AbstractValidator {
/**
* The validators are combined with <code>AND</code> clause: validity of the
/**
* List of contained validators.
*/
- private final LinkedList validators = new LinkedList();
-
- /**
- * Error message.
- */
- private String errorMessage;
+ private final List<Validator> validators = new LinkedList<Validator>();
/**
* Construct a composite validator in <code>AND</code> mode without error
* message.
*/
public CompositeValidator() {
+ super("");
}
/**
* Constructs a composite validator in given mode.
*/
public CompositeValidator(int mode, String errorMessage) {
+ super(errorMessage);
setMode(mode);
- setErrorMessage(errorMessage);
}
/**
* @throws Validator.InvalidValueException
* if the value is not valid.
*/
+ @Override
public void validate(Object value) throws Validator.InvalidValueException {
switch (mode) {
case MODE_AND:
- for (final Iterator i = validators.iterator(); i.hasNext();) {
- ((Validator) i.next()).validate(value);
+ for (Validator validator : validators) {
+ validator.validate(value);
}
return;
case MODE_OR:
Validator.InvalidValueException first = null;
- for (final Iterator i = validators.iterator(); i.hasNext();) {
+ for (Validator v : validators) {
try {
- ((Validator) i.next()).validate(value);
+ v.validate(value);
return;
} catch (final Validator.InvalidValueException e) {
if (first == null) {
public boolean isValid(Object value) {
switch (mode) {
case MODE_AND:
- for (final Iterator i = validators.iterator(); i.hasNext();) {
- final Validator v = (Validator) i.next();
+ for (Validator v : validators) {
if (!v.isValid(value)) {
return false;
}
return true;
case MODE_OR:
- for (final Iterator i = validators.iterator(); i.hasNext();) {
- final Validator v = (Validator) i.next();
+ for (Validator v : validators) {
if (v.isValid(value)) {
return true;
}
* Gets the error message for the composite validator. If the error message
* is null, original error messages of the sub-validators are used instead.
*/
+ @Override
public String getErrorMessage() {
- if (errorMessage != null) {
- return errorMessage;
+ if (getErrorMessage() != null) {
+ return getErrorMessage();
}
// TODO Return composite error message
return null;
}
- /**
- * Sets the error message for the composite validator. If the error message
- * is null, original error messages of the sub-validators are used instead.
- *
- * @param errorMessage
- * the Error Message to set.
- */
- public void setErrorMessage(String errorMessage) {
- this.errorMessage = errorMessage;
- }
-
/**
* Adds validator to the interface.
*
* validators of given type null is returned.
* </p>
*
- * @return Collection of validators compatible with given type that must
- * apply or null if none fould.
+ * @return Collection<Validator> of validators compatible with given type
+ * that must apply or null if none fould.
*/
- public Collection getSubValidators(Class validatorType) {
+ public Collection<Validator> getSubValidators(Class validatorType) {
if (mode != MODE_AND) {
return null;
}
- final HashSet found = new HashSet();
- for (final Iterator i = validators.iterator(); i.hasNext();) {
- final Validator v = (Validator) i.next();
+ final HashSet<Validator> found = new HashSet<Validator>();
+ for (Validator v : validators) {
if (validatorType.isAssignableFrom(v.getClass())) {
found.add(v);
}
if (v instanceof CompositeValidator
&& ((CompositeValidator) v).getMode() == MODE_AND) {
- final Collection c = ((CompositeValidator) v)
+ final Collection<Validator> c = ((CompositeValidator) v)
.getSubValidators(validatorType);
if (c != null) {
found.addAll(c);
--- /dev/null
+package com.itmill.toolkit.data.validator;\r
+\r
+/**\r
+ * String validator for a double precision floating point number. See\r
+ * {@link com.itmill.toolkit.data.validator.AbstractStringValidator} for more\r
+ * information.\r
+ * \r
+ * @author IT Mill Ltd.\r
+ * @version\r
+ * @VERSION@\r
+ * @since 5.4\r
+ */\r
+public class DoubleValidator extends AbstractStringValidator {\r
+\r
+ /**\r
+ * Creates a validator for checking that a string can be parsed as an\r
+ * double.\r
+ * \r
+ * @param errorMessage\r
+ * the message to display in case the value does not validate.\r
+ */\r
+ public DoubleValidator(String errorMessage) {\r
+ super(errorMessage);\r
+ }\r
+\r
+ @Override\r
+ protected boolean isValidString(String value) {\r
+ try {\r
+ Double.parseDouble(value);\r
+ return true;\r
+ } catch (Exception e) {\r
+ return false;\r
+ }\r
+ }\r
+\r
+}\r
--- /dev/null
+package com.itmill.toolkit.data.validator;\r
+\r
+/**\r
+ * String validator for e-mail addresses. The e-mail address syntax is not\r
+ * complete according to RFC 822 but handles the vast majority of valid e-mail\r
+ * addresses correctly.\r
+ * \r
+ * See {@link com.itmill.toolkit.data.validator.AbstractStringValidator} for\r
+ * more information.\r
+ * \r
+ * @author IT Mill Ltd.\r
+ * @version\r
+ * @VERSION@\r
+ * @since 5.4\r
+ */\r
+public class EmailValidator extends RegexpValidator {\r
+\r
+ /**\r
+ * Creates a validator for checking that a string is a syntactically valid\r
+ * e-mail address.\r
+ * \r
+ * @param errorMessage\r
+ * the message to display in case the value does not validate.\r
+ */\r
+ public EmailValidator(String errorMessage) {\r
+ super(\r
+ "^([a-zA-Z0-9_\\.\\-+])+@(([a-zA-Z0-9-])+\\.)+([a-zA-Z0-9]{2,4})+$",\r
+ true, errorMessage);\r
+ }\r
+\r
+}\r
--- /dev/null
+package com.itmill.toolkit.data.validator;\r
+\r
+/**\r
+ * String validator for integers. See\r
+ * {@link com.itmill.toolkit.data.validator.AbstractStringValidator} for more\r
+ * information.\r
+ * \r
+ * @author IT Mill Ltd.\r
+ * @version\r
+ * @VERSION@\r
+ * @since 5.4\r
+ */\r
+public class IntegerValidator extends AbstractStringValidator {\r
+\r
+ /**\r
+ * Creates a validator for checking that a string can be parsed as an\r
+ * integer.\r
+ * \r
+ * @param errorMessage\r
+ * the message to display in case the value does not validate.\r
+ */\r
+ public IntegerValidator(String errorMessage) {\r
+ super(errorMessage);\r
+\r
+ }\r
+\r
+ @Override\r
+ protected boolean isValidString(String value) {\r
+ try {\r
+ Integer.parseInt(value);\r
+ return true;\r
+ } catch (Exception e) {\r
+ return false;\r
+ }\r
+ }\r
+\r
+}\r
--- /dev/null
+package com.itmill.toolkit.data.validator;\r
+\r
+import java.util.regex.Matcher;\r
+import java.util.regex.Pattern;\r
+\r
+/**\r
+ * String validator comparing the string against a Java regular expression. Both\r
+ * complete matches and substring matches are supported.\r
+ * \r
+ * <p>\r
+ * For the Java regular expression syntax, see\r
+ * {@link java.util.regex.Pattern#sum}\r
+ * </p>\r
+ * <p>\r
+ * See {@link com.itmill.toolkit.data.validator.AbstractStringValidator} for\r
+ * more information.\r
+ * </p>\r
+ * \r
+ * @author IT Mill Ltd.\r
+ * @version\r
+ * @VERSION@\r
+ * @since 5.4\r
+ */\r
+public class RegexpValidator extends AbstractStringValidator {\r
+\r
+ private Pattern pattern;\r
+ private boolean complete;\r
+ private Matcher matcher = null;\r
+\r
+ /**\r
+ * Creates a validator for checking that the regular expression matches the\r
+ * complete string to validate.\r
+ * \r
+ * @param regexp\r
+ * a Java regular expression\r
+ * @param errorMessage\r
+ * the message to display in case the value does not validate.\r
+ */\r
+ public RegexpValidator(String regexp, String errorMessage) {\r
+ this(regexp, true, errorMessage);\r
+ }\r
+\r
+ /**\r
+ * Creates a validator for checking that the regular expression matches the\r
+ * string to validate.\r
+ * \r
+ * @param regexp\r
+ * a Java regular expression\r
+ * @param complete\r
+ * true to use check for a complete match, false to look for a\r
+ * matching substring\r
+ * @param errorMessage\r
+ * the message to display in case the value does not validate.\r
+ */\r
+ public RegexpValidator(String regexp, boolean complete, String errorMessage) {\r
+ super(errorMessage);\r
+ pattern = Pattern.compile(regexp);\r
+ this.complete = complete;\r
+ }\r
+\r
+ @Override\r
+ protected boolean isValidString(String value) {\r
+ if (complete) {\r
+ return getMatcher(value).matches();\r
+ } else {\r
+ return getMatcher(value).find();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get a new or reused matcher for the pattern\r
+ * \r
+ * @param value\r
+ * the string to find matches in\r
+ * @return Matcher for the string\r
+ */\r
+ private Matcher getMatcher(String value) {\r
+ if (matcher == null) {\r
+ matcher = pattern.matcher(value);\r
+ } else {\r
+ matcher.reset(value);\r
+ }\r
+ return matcher;\r
+ }\r
+\r
+}\r
package com.itmill.toolkit.data.validator;
-import com.itmill.toolkit.data.Validator;
-
/**
* This <code>StringLengthValidator</code> is used to validate the length of
* strings.
* @VERSION@
* @since 3.0
*/
-public class StringLengthValidator implements Validator {
+public class StringLengthValidator extends AbstractValidator {
private int minLength = -1;
private boolean allowNull = true;
- private String errorMessage;
-
/**
* Creates a new StringLengthValidator with a given error message.
*
* the message to display in case the value does not validate.
*/
public StringLengthValidator(String errorMessage) {
- setErrorMessage(errorMessage);
+ super(errorMessage);
}
/**
* @param errorMessage
* the message to display in case the value does not validate.
* @param minLength
- * the minimum permissable length of the string.
+ * the minimum permissible length of the string.
* @param maxLength
- * the maximum permissable length of the string.
+ * the maximum permissible length of the string.
* @param allowNull
- * Are null strings permissable?
+ * Are null strings permissible? This can be handled better by
+ * setting a field as required or not.
*/
public StringLengthValidator(String errorMessage, int minLength,
int maxLength, boolean allowNull) {
setNullAllowed(allowNull);
}
- /**
- * Validates the value.
- *
- * @param value
- * the value to validate.
- * @throws Validator.InvalidValueException
- * if the value was invalid.
- */
- public void validate(Object value) throws Validator.InvalidValueException {
- if (value == null) {
- if (allowNull) {
- return;
- } else {
- throw new Validator.InvalidValueException(errorMessage);
- }
- }
- final String s = value.toString();
- if (s == null) {
- if (allowNull) {
- return;
- } else {
- throw new Validator.InvalidValueException(errorMessage);
- }
- }
- final int len = s.length();
- if ((minLength >= 0 && len < minLength)
- || (maxLength >= 0 && len > maxLength)) {
- throw new Validator.InvalidValueException(errorMessage);
- }
- }
-
/**
* Checks if the given value is valid.
*
* @return <code>true</code> if allows null string, otherwise
* <code>false</code>.
*/
+ @Deprecated
public final boolean isNullAllowed() {
return allowNull;
}
/**
- * Gets the maximum permissable length of the string.
+ * Gets the maximum permissible length of the string.
*
* @return the maximum length of the string.
*/
}
/**
- * Gets the minimum permissable length of the string.
+ * Gets the minimum permissible length of the string.
*
* @return the minimum length of the string.
*/
}
/**
- * Sets whether null-strings are to be allowed.
+ * Sets whether null-strings are to be allowed. This can be better handled
+ * by setting a field as required or not.
*/
+ @Deprecated
public void setNullAllowed(boolean allowNull) {
this.allowNull = allowNull;
}
/**
- * Sets the maximum permissable length of the string.
+ * Sets the maximum permissible length of the string.
*
* @param maxLength
* the length to set.
}
/**
- * Sets the minimum permissable length.
+ * Sets the minimum permissible length.
*
* @param minLength
* the length to set.
this.minLength = minLength;
}
- /**
- * Gets the message to be displayed in case the value does not validate.
- *
- * @return the Error Message.
- */
- public String getErrorMessage() {
- return errorMessage;
- }
-
- /**
- * Sets the message to be displayer in case the value does not validate.
- *
- * @param errorMessage
- * the Error Message to set.
- */
- public void setErrorMessage(String errorMessage) {
- this.errorMessage = errorMessage;
- }
-
}
--- /dev/null
+package com.itmill.toolkit.tests.validation;\r
+\r
+import com.itmill.toolkit.data.Validator;\r
+import com.itmill.toolkit.data.validator.AbstractStringValidator;\r
+import com.itmill.toolkit.data.validator.CompositeValidator;\r
+import com.itmill.toolkit.data.validator.DoubleValidator;\r
+import com.itmill.toolkit.data.validator.EmailValidator;\r
+import com.itmill.toolkit.data.validator.IntegerValidator;\r
+import com.itmill.toolkit.data.validator.RegexpValidator;\r
+import com.itmill.toolkit.data.validator.StringLengthValidator;\r
+import com.itmill.toolkit.tests.components.TestBase;\r
+import com.itmill.toolkit.ui.Button;\r
+import com.itmill.toolkit.ui.Form;\r
+import com.itmill.toolkit.ui.TextField;\r
+import com.itmill.toolkit.ui.VerticalLayout;\r
+import com.itmill.toolkit.ui.Button.ClickEvent;\r
+import com.itmill.toolkit.ui.Button.ClickListener;\r
+import com.itmill.toolkit.ui.Window.Notification;\r
+\r
+public class TestValidators extends TestBase {\r
+\r
+ @Override\r
+ protected Integer getTicketNumber() {\r
+ return 680;\r
+ }\r
+\r
+ @Override\r
+ protected String getDescription() {\r
+ return "This test verifies that various validators work correctly";\r
+ }\r
+\r
+ @Override\r
+ public void setup() {\r
+ final Form form = new Form(new VerticalLayout());\r
+\r
+ // simple validators\r
+\r
+ TextField tf = new TextField("A field, must contain 1-2 chars");\r
+ tf\r
+ .addValidator(new StringLengthValidator("Invalid length", 1, 2,\r
+ false));\r
+ tf.setRequired(true);\r
+ tf.setValue("ab");\r
+ form.addField("a", tf);\r
+\r
+ tf = new TextField("A field, must contain an integer");\r
+ tf.addValidator(new IntegerValidator("Invalid integer {0}"));\r
+ tf.setRequired(true);\r
+ tf.setValue("123");\r
+ form.addField("b", tf);\r
+\r
+ tf = new TextField("A field, must contain an integer or be empty");\r
+ tf.addValidator(new IntegerValidator("Invalid integer {0}"));\r
+ tf.setValue("-321");\r
+ form.addField("c", tf);\r
+\r
+ tf = new TextField(\r
+ "A field, must contain a floating point number or be empty");\r
+ tf.addValidator(new DoubleValidator("Invalid double {0}"));\r
+ tf.setValue("-123.45e6");\r
+ form.addField("d", tf);\r
+\r
+ tf = new TextField(\r
+ "A field, must contain an e-mail address or be empty");\r
+ tf.addValidator(new EmailValidator("Invalid e-mail address {0}"));\r
+ tf.setValue("a.b@example.com");\r
+ form.addField("e", tf);\r
+\r
+ // regular expressions\r
+\r
+ tf = new TextField("A field, must match the regular expression a.*b.*c");\r
+ tf.addValidator(new RegexpValidator("a.*b.*c",\r
+ "{0} does not match the regular expression"));\r
+ tf.setValue("aagsabeqgc");\r
+ form.addField("f", tf);\r
+\r
+ tf = new TextField(\r
+ "A field, must contain the regular expression a.*b.*c");\r
+ tf.addValidator(new RegexpValidator("a.*b.*c", false,\r
+ "{0} does not contain the regular expression"));\r
+ tf.setValue("aagsabeqgc");\r
+ form.addField("g", tf);\r
+\r
+ tf = new TextField(\r
+ "A field, must match the regular expression ^a.*b.*c$");\r
+ tf.addValidator(new RegexpValidator("^a.*b.*c$", false,\r
+ "{0} does not match the regular expression with ^ and $"));\r
+ tf.setValue("aagsabeqgc");\r
+ form.addField("h", tf);\r
+\r
+ tf = new TextField(\r
+ "A field, must contain the regular expression ^a.*b.*c$");\r
+ tf.addValidator(new RegexpValidator("^a.*b.*c$", false,\r
+ "{0} does not contain the regular expression with ^ and $"));\r
+ tf.setValue("aagsabeqgc");\r
+ form.addField("i", tf);\r
+\r
+ // TODO CompositeValidator\r
+ tf = new TextField(\r
+ "A field, must be a floating point number with 4-5 chars");\r
+ CompositeValidator cv = new CompositeValidator(\r
+ CompositeValidator.MODE_AND,\r
+ "The field must contain a floating point number with 4-5 characters");\r
+ cv\r
+ .addValidator(new StringLengthValidator(\r
+ "String length of '{0}' should be 4-5 characters", 4,\r
+ 5, false));\r
+ cv.addValidator(new DoubleValidator(\r
+ "{0} must be a floating point number"));\r
+ tf.addValidator(cv);\r
+ tf.setValue("12.34");\r
+ form.addField("j", tf);\r
+\r
+ // Postal code that must be 5 digits (10000-99999).\r
+ tf = new TextField("Postal Code");\r
+ tf.setColumns(5);\r
+\r
+ // Create the validator - this would be even easier with RegexpValidator\r
+ Validator postalCodeValidator = new AbstractStringValidator(\r
+ "Postal code must be a number 10000-99999.") {\r
+ @Override\r
+ protected boolean isValidString(String value) {\r
+ return value.matches("[1-9][0-9]{4}");\r
+ }\r
+ };\r
+ tf.addValidator(postalCodeValidator);\r
+ tf.setValue("12345");\r
+ form.addField("k", tf);\r
+\r
+ Button b = new Button("Commit", new ClickListener() {\r
+\r
+ public void buttonClick(ClickEvent event) {\r
+ try {\r
+ form.commit();\r
+ if (form.isValid()) {\r
+ getMainWindow().showNotification(\r
+ "OK! Form validated and no error was thrown",\r
+ Notification.TYPE_HUMANIZED_MESSAGE);\r
+ } else {\r
+ getMainWindow().showNotification(\r
+ "Form is invalid but no exception was thrown",\r
+ Notification.TYPE_ERROR_MESSAGE);\r
+ }\r
+ } catch (Exception e) {\r
+ if (form.isValid()) {\r
+ getMainWindow().showNotification(\r
+ "Form is valid but an exception was thrown",\r
+ Notification.TYPE_ERROR_MESSAGE);\r
+ } else {\r
+ getMainWindow().showNotification(\r
+ "OK! Error was thrown for an invalid input",\r
+ Notification.TYPE_HUMANIZED_MESSAGE);\r
+\r
+ }\r
+ }\r
+ }\r
+\r
+ });\r
+\r
+ addComponent(form);\r
+ addComponent(b);\r
+ }\r
+}\r