I believe its well established that Struts would benefit from a good
validation framework (duh, right?). While there are a number of
really good ideas floating around, some seem to be introducing
unnecessary complexity (IMHO, of course)
Getting to the point, I think constrained properties from the
JavaBeans spec. provides a built in, flexible foundation for
struts invoked validation.
(http://java.sun.com/products/javabeans/docs/spec.html)
key advantages:
* support is provided by the standard java.beans package
* it doesn't require learning anything proprietary (even though
other solutions are very cool :)
* its conceptually simple; ie. before accepting a new value,
the bean/ActionForm's setter method(s) ensures its accepted by
all registered listeners before commiting the value
(java.bean.VetoableChangeListenter).
* and finally, its wide open for extension (key since we can't
predict all validation scenario's, right?)
I also believe that integration with Struts could be pretty straight
forward. In a nutshell, we could make 2 modifications ActionServlet:
1. Make it responsible for registering "change-listeners"
2. Make it handle PropertyVetoException(s) thrown by setter methods
(primarily by turning them into ActionErrors)
Prior to making a "formal" proposal for this, I thought it might be
useful to consider the attached code fragments:
Then again, maybe I'm way off and should be ignored- If I am,
let me know..
Regards,
Levi Cook
<struts-config>
<!-- etc.. -->
<form-bean name="myForm" type="MyForm">
<change-listener
property="email"
type="RequiredEmailAddressValidator"
/>
</form-bean>
<!-- etc.. -->
</struts-config>
import java.beans.*
public class RequiredEmailAddressValidator implements VetoableChangeListener {
public void vetoableChange(PropertyChangeEvent evt)
throws PropertyVetoException
{
String email= null;
boolean emptyOk= false;
try {
email= (String) evt.getNewValue();
}
finally {
if(StringValidator.checkEmail(email, emptyOk) == false)
throw new PropertyVetoException("some.msg.key", evt);
}
}
}
import org.apache.struts.action.ActionForm;
import java.beans.*;
public class MyForm extends ActionForm {
private static final String EMAIL_PROP_NAME= "email";
private String email;
public String getEmailAddress() {
return email;
}
public void setEmail(String newEmail)
throws PropertyVetoException
{
vcs.fireVetoableChange(EMAIL_PROP_NAME, email, newEmail);
email= newEmail;
}
private VetoableChangeSupport vcs=
new VetoableChangeSupport(this);
public void addEmailVetoableChangeListener(VetoableChangeListener lsnr) {
vcs.addVetoableChangeListener(EMAIL_PROP_NAME, lsnr);
}
public void removeEmailVetoableChangeListener(VetoableChangeListener lsnr) {
vcs.removeVetoableChangeListener(EMAIL_PROP_NAME, lsnr);
}
}
import java.beans.*;
public class OptionalEmailAddressValidator implements VetoableChangeListener {
public void vetoableChange(PropertyChangeEvent evt)
throws PropertyVetoException
{
String email= null;
boolean emptyOk= true;
try {
email= (String) evt.getNewValue();
}
finally {
if(StringValidator.checkEmail(email, emptyOk) == false)
throw new PropertyVetoException("some.msg.key", evt);
}
}
}
import org.apache.regexp.*;
public final class StringValidator {
/**
* Check that String email is a valid email address.
* emptyOK=true indicates that an empty String is valid
* for this test.
*/
public static boolean checkEmail(String email, boolean emptyOK) {
if ((emptyOK == true) && (KRStringValidator.isEmpty(email)))
return true;
else if (StringValidator.isValidEmail(email))
return true;
else
return false;
}
/**
* Checks to see if a String is a valid email address.
*/
public static boolean isValidEmail(String email) {
if(email == null) return false;
try {
RE reEmail = new RE("^.+\\@.+\\..+$");
if (reEmail.match(email) )
return true;
else
return false;
}
catch(RESyntaxException e) {
System.out.println(e);
return false;
}
}
/**
* Checks to see if a String is null or all spaces.
*/
public static boolean isEmpty(String s) {
return ((s == null) || (s.trim().length() == 0));
}
}