Saturday 13 November 2010

Rules-based Validation using Drools, JSR303 and Spring

Validation and business rules are closely linked. Indeed validation logic could be thought of as being part of the implicit business rules for an application.

It seems natural that integrating a business rules solution with a validation technology might be a natural step. In this post, I explore the possibility of integrating JSR303 and Drools to provide business rule driven validation within a Spring application. JSR303 is the standard Java method for data validation using annotations and Drools is a business rules engine that is a JBoss project and an implementation of JSR94, the standard Java rule engine API.

When to use (and when not to)

I don't think that this is a natural choice for all data validation needs. For a start, if the validation in your application is simple, the standard JSR303 annotations mixed with a few custom annotations might be enough. Integrating Drools comes at a cost in terms of architectural complexity and additional dependencies for you application. And although Drools is highly performance-optimised, a set of business rules in Drools will probably be slower than a set of custom Java statements.

However, there are significant benefits to complex applications - particularly if you are using Drools already. In that case, the complexity and dependency arguments are not valid.

The big benefit is the ability to externalise the business rules from the application and enable them to be edited without redeploying the application.

Drools overview

In a Drools application, business rules can be written in a powerful expression language called mvel (although XML can be used as well). In the Drools Expert documentation, the following basic example is given.

 
    public class Applicant {

        private String name;

        private int age;

        private boolean valid;

        // getter and setter methods here

    }
 
    package com.company.license;

    rule "Is of valid age" 
        when 
            $a : Applicant( age < 18 ) 
        then 
            $a.setValid( false ); 
        end

The rule consists of conditions (when) and consequences (then). In this rule, when the Applicant age property is less than 18, the valid property is set to false.

Often, business rules will need to access collaborators such as services or DAOs. These can be injected as "globals" in the rule definition. For example, the scenario above could be modified so that the applicant needs to be loaded from a DAO in order to check the age. The applicant identifier is a property in an ApplicationForm, submitted from a GUI or web application.

We'll also introduce a new class to hold the validation result, rather than setting the validity on the model object itself, which is somewhat artificial. This object could be returned to the presentation tier to tell the user what went wrong.

Error object to hold validation result:


    package com.acme.app.validation;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Collections;

    public class Errors {
 
        private final List<Error> errors = Collections.synchronizedList(new ArrayList<Error>());

        public Collection<Error> getErrors() {
            return Collections.unmodifiableCollection(errors);
        }
 
        public void addError(Object target, String field, String message) {
            this.errors.add(new Error(target, field, message));
        }
 
        public boolean hasErrors() {
            if (this.errors.size() > 0) {
                return true;
            }
            return false;
        }
    }

    class Error {
        private final Object target;
        private final String field;
        private final String message;
 
        public Error(Object target, String field, String message) {
            super();
            this.target = target;
            this.field = field;
            this.message = message;
        }

        public Object getTarget() {
            return target;
        }

        public String getField() {
            return field;
        }

        public String getMessage() {
            return message;
        }
    }

Modified Applicant (with identity)

 
    public class Applicant {

        private int id;

        private String name;

        private int age;

        private boolean valid;

        // getter and setter methods here

    }

ApplicationForm from the GUI/web:

 
    public class ApplicationForm {
 
        private int applicantId;
 
        private Date date;

        // getter and setter methods here

    }

Here is a slightly silly test DAO:

    
    public class ApplicantDaoImpl implements ApplicantDao {
 
        private final Map<Integer, Applicant> applicants = new HashMap<Integer, Applicant>();
 
        public ApplicantDaoImpl() {
            Applicant app1 = new Applicant(1, "Mr John Smith", 16);
            applicants.put(app1.getId(), app1);
            Applicant app2 = new Applicant(2, "Mr Joe Bloggs", 21);
            applicants.put(app2.getId(), app2);
        }
 
        @Override
        public Applicant findApplicant(Integer identifier) {
            return applicants.get(identifier);
        }

    }

Finally, a rule with a global representing the ApplicantDao and using our new Errors object could look like:

 
    package com.acme.app.rules

        import com.acme.app.form.ApplicationForm
        import com.acme.app.model.Applicant
        import com.acme.app.validation.Errors
        import com.acme.app.dao.ApplicantDao

        global ApplicantDao applicantDao

        rule "Check applicant age"
            when
                $a : ApplicationForm()
                $errors : Errors() 
                $applicant:Applicant( age < 18 ) from applicantDao.findApplicant($a.getApplicantId())
            then
                $errors.addError( $a, "applicantId", "Applicant age < 18" );
            end

In this version of the rule, the applicant is loaded from a DAO based on their identity. If the age of the applicant is less than 18, an error is inserted into the Errors object specifying the target object, field and message to return to the GUI. Obviously, this could be internationalized by putting a message code instead of the actual message.

That's an extremely brief overview of rules. Next, I'll quickly discuss the main API that Java programmers use when interacting with Drools. These will be used by the JSR303 validator when validating a bean using business rules.

At the most basic level, Drools stores business rules in a KnowledgeBase, from which can be created "sessions" which enable users to execute the rules based on facts, which are usually model objects inserted into the session.

There are two types of session: StatefulKnowldegeSession and StatelessKnowledgeSession. A StatelessKnowledgeSession is considered appropriate for use cases such as validation, because they are intended as a "one-shot" function call: pass in the facts, execute the rules, get a result. That's therefore the interface I will use for the integration with a JSR303 validation.

Here is a simple example of creating a StatelessKnowledgeSession and executing the rules based on a collection of facts, each of which is inserted in turn before the rules are fired.


    KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( ResourceFactory.newFileSystemResource( fileName ), ResourceType.DRL );
        assertFalse( kbuilder.hasErrors() );     
        if (kbuilder.hasErrors() ) {
            System.out.println( kbuilder.getErrors() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
 
        StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
        ksession.execute( collection );

Spring integration

Conveniently, in Drools 5.1 some additional Spring integration was added that enables you to create KnowledgeBases and sessions declaratively in the application context, using a purpose-built namespace.

In this example, Spring is the "glue" bringing together the Drools and JSR303 parts. Here's the configuration.


    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:drools="http://drools.org/schema/drools-spring"       
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd 
                           http://drools.org/schema/drools-spring http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-container/drools-spring/src/main/resources/org/drools/container/spring/drools-spring-1.0.0.xsd">
  
        <drools:kbase id="kbase">
            <drools:resources>
                <drools:resource type="DRL" source="classpath:testSpring.drl"></drools:resource>
            </drools:resources>
        </drools:kbase>
    
        <drools:ksession id="statelessKSession" type="stateless" name="statelessKSession" kbase="kbase">
        </drools:ksession>
  
    </beans>

I'm keeping things very simple - there is a lot more that the namespace can do in terms of configuring knowledge bases, agents, sessions etc.

JSR 303 Overview

JSR303 is a standard Java mechanism for validating JavaBeans using convenient annotations. Creating custom annotations is a matter of creating the annotation and an accompanying ConstraintValidator implementation, which will be automatically used by the Validator when it encounters the annotation on a bean getting validated.

The annotation itself is simple.


    package com.acme.app.validation;

    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
 
    import javax.validation.Constraint;
    import javax.validation.Payload;
 
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Constraint(validatedBy=BusinessRulesConstraintValidator.class)
 
    public @interface BusinessRulesConstraint {
        String message() default "Business rules validation failed.";
        Class<?>[] groups() default {};
        Class<? extends Payload>[] payload() default {};
    }

The validator is also reasonably simple. A StatelessKnowledgeSession and a simple bean carrying a Map of the needed collaborators (to be set as globals) are injected into the constructor.

When the isValid() method is called, an Errors object and the target of the validation are inserted into the session and the validation rules are fired. If the Errors object comes back with errors, validation has failed and a ConstraintViolation is built using the data in the Errors object.


    package com.acme.app.validation;

    import java.util.Arrays;
    import java.util.Map;

    import javax.validation.ConstraintValidator;    
    import javax.validation.ConstraintValidatorContext;

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.drools.runtime.StatefulKnowledgeSession;
    import org.drools.runtime.StatelessKnowledgeSession;
    import org.springframework.beans.factory.annotation.Autowired;

    /**
     * Custom JSR303 {@link ConstraintValidator} that
     * uses a Drools {@link StatelessKnowledgeSession} to
     * implement rules-based validation of objects
     * decorated with a @BusinessRulesConstraint annotation
     */
    public class BusinessRulesConstraintValidator implements ConstraintValidator<BusinessRulesConstraint, Object> {

        private final Log logger = LogFactory.getLog(BusinessRulesConstraintValidator.class);
 
        private final StatelessKnowledgeSession session;
 
        @Autowired
        public BusinessRulesConstraintValidator(StatelessKnowledgeSession session, Collaborators collaborators) {
            this.session = session;
            if (collaborators != null) {
                Map<String, Object> map = collaborators.getCollaborators();
                for (String key : map.keySet()) {
                    session.setGlobal(key, map.get(key));
                }
            }
        }

        @Override
        public void initialize(BusinessRulesConstraint constraint) {}

        @Override
        public boolean isValid(Object target, ConstraintValidatorContext context) {
  
            // Create Errors
            Errors errors = new Errors();
  
            try {
   
                // Fire rules
                session.execute(Arrays.asList(new Object[]{errors, target}));
   
                // Check for errors
                if (errors.hasErrors()) {
                    // Build constraint violations
                    context.disableDefaultConstraintViolation();
                    for (Error error : errors.getErrors()) {
    context.buildConstraintViolationWithTemplate(error.getMessage()).addNode(error.getField()).addConstraintViolation();
                    }
                    return false;
                }
            } 
            catch (Exception e) {
                logger.error(e);
                return false;
            }
  
            return true;
        }

    }

The Collaborators object is extremely simple:


package com.acme.app.validation;

import java.util.Collections;
import java.util.Map;

public class Collaborators {
 
    private final Map<String, Object> collaborators;

    public Collaborators(Map<String, Object> collaborators) {
        super();
        this.collaborators = collaborators;
    }

    public Map<String, Object> getCollaborators() {
        return Collections.unmodifiableMap(collaborators);
    }
}

It's simply a container holding a map into which collaborators such as DAO or Service facades could be injected using Spring.

The full Spring configuration gluing the whole thing together is below:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:drools="http://drools.org/schema/drools-spring"       
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd 
                           http://drools.org/schema/drools-spring http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-container/drools-spring/src/main/resources/org/drools/container/spring/drools-spring-1.0.0.xsd">
  
  <drools:kbase id="kbase">
    <drools:resources>
      <drools:resource type="DRL" source="classpath:testSpring.drl"></drools:resource>
    </drools:resources>
  </drools:kbase>
    
  <drools:ksession id="statelessKSession" type="stateless" name="statelessKSession" kbase="kbase"></drools:ksession>

  <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"></bean>
  
  <bean id="collaborators" class="com.acme.app.validation.Collaborators">
      <constructor-arg><map>
              <entry key="applicantDao" value-ref="applicantDao"></entry>
          </map>
      </constructor-arg></bean>

<bean id="applicantDao" class="com.acme.app.dao.impl.ApplicantDaoImpl"></bean>
</beans>

Using the validator is very simple. First, the ApplicantForm object needs to be decorated with the @BusinessRulesConstraint annotation at class level so that the JSR303 validator will be triggered to use the BusienssRulesConstraintValidator.


package com.acme.app.form;

import java.util.Date;

import com.acme.app.validation.BusinessRulesConstraint;

@BusinessRulesConstraint
public class ApplicationForm {
 
    private Integer applicantId;
 
    private Date date;

    // getters/setters
}

Then it is a matter of invoking the validator with a bean instance like this:


package com.acme.app.validation.tests;

import java.util.Date;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;

import junit.framework.Assert;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.acme.app.form.ApplicationForm;

public class ValidationTestCase {
 
    private static ApplicationContext ctx;
 
    private static Validator validator;
 
    @BeforeClass
    public static void beforeClass() {
  
        // Create the Spring application context
        String[] paths = { "application-context.xml" };
        ctx = new ClassPathXmlApplicationContext(paths);
  
    }
 
    @Before
    public void before() {
        validator = (Validator)ctx.getBean("validator");
    }
 
    @Test
    public void testInvalidAge() {
        ApplicationForm applicationForm = new ApplicationForm(1, new Date());
        Set<ConstraintViolation<ApplicationForm>> violations = validator.validate(applicationForm);
        Assert.assertNotNull(violations);
        Assert.assertEquals(Integer.valueOf(2), Integer.valueOf(violations.size()));
    }
 
}

Summary

This post shows you an approach for integrating JSR303 and Drools in a Spring application, something you might want to do if you were using these technologies already in your application and it was sufficiently complex to warrant it. The steps involved are:

  • Create your domain objects and decorate them withe @BusinessRulesConstraint where business rule validation is to be used.
  • Create the .drl file with your validation logic in it.
  • Configure Spring as above with a KnowledgeBase containing your drl file as a resource, a StatelessKnowledgeSession derived from that KnowledgeBase, your collaborators for the rules and the JSR303 validator.

That's it!

Postscript: Maven configuration

For Maven users, this should be useful in getting all the dependencies for this example to work.



<dependencies>
  
    <!-- Spring bits -->
    <dependency>
        <groupid>org.springframework</groupId>
        <artifactid>spring-core</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
        <groupid>org.springframework</groupId>
        <artifactid>spring-context</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>    
  
    <dependency>
        <groupid>org.springframework</groupId>
        <artifactid>spring-beans</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>   
    
    <!-- Drools bits -->
    <dependency>
        <groupid>org.drools</groupId>
        <artifactid>drools-core</artifactId>
        <version>5.1.1</version>
    </dependency>
  
    <dependency>
        <groupid>org.drools</groupId>
        <artifactid>drools-spring</artifactId>
        <version>5.1.1</version>
    </dependency>

    <!-- JSR303 bits -->
    <dependency>
        <groupid>org.hibernate</groupId>
        <artifactid>hibernate-validator</artifactId>
        <version>4.1.0.Final</version>
    </dependency>

    <dependency>
        <groupid>org.slf4j</groupId>
        <artifactid>slf4j-api</artifactId>
        <version>1.5.6</version>
    </dependency>
  
    <!-- concrete Log4J Implementation for SLF4J API-->
    <dependency>
        <groupid>org.slf4j</groupId>
        <artifactid>slf4j-log4j12</artifactId>
        <version>1.5.6</version>
    </dependency>
 
</dependencies>

Wednesday 20 October 2010

Validating service method parameters using JSR 303, Spring AOP/AspectJ and Spring

When building an application with Spring and JSR303 you can easily validate form submissions using the built in JSR303 validators. This helps ensure that parameters passed to service methods are valid in a web application. However, there are certain cases where you might wish to invoke your service methods directly rather than from within an MVC controller, for example if you were using DWR or a REST web service. Here is an example of a service facade that might exist in a Spring application.
public interface UserService {

 public abstract void updateUser(UserForm userForm);

}

@Service
public class UserServiceImpl {

 @Override
 @Secured({"ROLE_EMPLOYEE"})
 @Transactional(readOnly=false, isolation=Isolation.READ_COMMITTED,propagation=Propagation.SUPPORTS)
 public abstract void updateUser(UserForm userForm) {
   User user = extractUserFromUserForm(userForm);
   userDao.updateUser(user);
 }

}
Here is the UserForm parameter that is passed to the updateUser method above. It is a simple Form or Command bean using JSR 303 annotations to validate input.
@FieldMatch.List({
 @FieldMatch(first = "password", second = "confirmPassword"),
})
public class UserForm {
 @NotNull
 private String username;

 @NotNull
 @Pattern(regexp = "(?=.*\\d)(?=.*[a-zA-Z]).{6,12}")
 private String password;

 @NotNull
 @Pattern(regexp = "(?=.*\\d)(?=.*[a-zA-Z]).{6,12}")
 private String confirmPassword;

}
If the only client of the facade is a Spring MVC controller, the JSR303 validator can easily be wired in to validate the UserForm before it gets anywhere near the facade. However, if you are invoking the service in another way, there is a risk that the UserForm wouldn't be valid when it is passsed to the updateUser() method. How could we prevent that? The obvious answer would be to invoke the JSR303 validator in code in the facade implementation. Something like this would do the trick:
@Service
public class UserServiceImpl {

 @Autowired
 private Validator validator;

 @Override
 @Secured({"ROLE_EMPLOYEE"})
 @Transactional(readOnly=false, isolation=Isolation.READ_COMMITTED,propagation=Propagation.SUPPORTS)
 public abstract void updateUser(UserForm userForm) {

   // Validate input
   Set> violations = validator.validate(userForm);
   if (!violations.isEmpty())
     throw new ConstraintViolationException(violations);

   // Perform update
   User user = extractUserFromUserForm(userForm);
   userDao.updateUser(user);
 }

}
Reasonably simple - but if you do that for every service method, the repeated boilerplate code will add up to a fair bit of typing and clutter. Here is my proposed alternative. Use a new annotation to decorate the parameter in the service method, and use AOP to intercept method invocations and perform parameter validation. It is effectively the same solution but with less typing. Here is what the end solution would look like.
@Service
public class UserServiceImpl {

 @Autowired
 private Validator validator;

 @Override
 @Secured({"ROLE_EMPLOYEE"})
 @Transactional(readOnly=false, isolation=Isolation.READ_COMMITTED,propagation=Propagation.SUPPORTS)
 public abstract void updateUser(@Valid UserForm userForm) {

   // Perform update
   User user = extractUserFromUserForm(userForm);
   userDao.updateUser(user);
 }

}
Note the @Valid annnotation on the UserForm parameter. This isn't the standard JSR 303, but our own custom annotation that is used to mark parameters that need validation via AOP. On reflection, I probably should have called it something else to avoid confusion.
package myapp.validators.aspects;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface Valid {
 Class[] groups() default {};
}

The aspect that performs the validation is here.
package myapp.validators.aspects;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;

@Aspect
public class ValidateAspect {
 
 @Autowired
 private Validator validator;

 public void setVaidator(Validator validator) {
   this.validator = validator;
 }
 
  
 @Before("execution(* *(@myapp.validators.aspects.Valid (*)))")
 public void valid(JoinPoint jp) throws NoSuchMethodException {

   // ConstraintViolations to return
   Set<ConstraintViolation<?>> violations = new HashSet<ConstraintViolation<?>>();

   // Get the target method
   Method interfaceMethod = ((MethodSignature)jp.getSignature()).getMethod();
   Method implementationMethod = jp.getTarget().getClass().getMethod(interfaceMethod.getName(), interfaceMethod.getParameterTypes());
  
   // Get the annotated parameters and validate those with the @Valid annotation
   Annotation[][] annotationParameters = implementationMethod.getParameterAnnotations();
   for (int i = 0; i < annotationParameters.length; i++) {
     Annotation[] annotations = annotationParameters[i];
     for (Annotation annotation : annotations) {
       if (annotation.annotationType().equals(Valid.class)) {
         Valid valid = (Valid)annotation;
         Object arg = jp.getArgs()[i];
         violations.addAll(validator.validate(arg, valid.groups()));
       }
     }
   }
        
   // Throw an exception if ConstraintViolations are found
   if (!violations.isEmpty()) {
     throw new ConstraintViolationException(violations);
   }
  }
}

The final bit of glue in Spring to make it all work is to declare the custom annotation aspect in the application context.


 

Hope this is useful to someone. I found the following blogs and forum threads helpful in coming up with this post and related code. References http://forum.springsource.org/showthread.php?t=77390 http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html http://blog.newsplore.com/2010/02/23/spring-mvc-3-0-rest-rebuttal

Tuesday 25 May 2010

Creating a custom JSR 303 constraint annotation with Spring 3

Spring 3.0 has support for JSR303 annotation-driven validation, which makes it easy to build declarative validation into Java Beans in Spring applications. Out of the box, JSR303 supports annotations such as @NotNull and @Size etc which allow you to perform basic validation checks. However, most applications will need to do more sophisticated "business-logic" validation such as checking whether an email already exists in a database. I recently needed to do just that in a Spring MVC application that needed a "Forgot Password" function to let users receive an email with their password. The Spring MVC command object was very simple:
public class SendPasswordReminderCommand implements Serializable {
 
 private static final long serialVersionUID = 42L;

 private String email;

 public String getEmail() {
  return email;
 }

 public void setEmail(String email) {
  this.email = email;
 }

      // equals, hashcode, toString, constructors omitted
}
Annotating this class with JSR 303 annotations to check the format of the email or ensure that the email is not null is easy enough (using @NotNull, @Length from the core javax.validation.constraints standard package and @Email from the org.hibernate.validator.constraints package). Ideally, you would also be able to check the database and ensure that the email exists in the database and inform the user if not as part of the validation. To do this, having a custom annotation called @EmailExistsConstraint would be ideal - but you need to make your own!
public class SendPasswordReminderCommand implements Serializable {
 
 private static final long serialVersionUID = 42L;
 
 @NotNull
 @Length(min=1)
 @Email
 @EmailExistsConstraint
 private String email;

 public String getEmail() {
  return email;
 }

 public void setEmail(String email) {
  this.email = email;
 }
}
Creating the custom constraint requires you to create two classes - an annotation interface and associated constraint validator. The annotation is straightforward.

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy=EmailExistsConstraintValidator.class)

public @interface EmailExistsConstraint {
 String message() default "Email doesn't exists";
 Class[] groups() default {};
 Class[] payload() default {};
}

The constraint validator is where you perform the database check. As this is a Spring and Hibernate application, the constraint validator uses a Hibernate DAO as a "collaborator" to perform the check.
public class EmailExistsConstraintValidator implements ConstraintValidator {

 private Log log = LogFactory.getLog(EmailExistsConstraintValidator.class);
 
 @Autowired
 private EmployeeFinder employeeFinder;
 
 @Override
 public void initialize(EmailExistsConstraint constraint) {
  
 }

 @Override
 public boolean isValid(Object target, ConstraintValidatorContext context) {
  
  try {
   Collection employees = employeeFinder.findEmployeeByEmail((String) target);
   if (employees.size() > 0) {
    return true;
   }
  } catch (Exception e) {
   log.error(e);
  }
  return false;
 }

 public void setEmployeeFinder(EmployeeFinder employeeFinder) {
  this.employeeFinder = employeeFinder;
 }
}

This is a fairly straightforward constraint validator implementation. If the database contains a record matching the email address, the isValid() method returns true and false if not. All that Spring needs to use JSR303 is to register the Spring validator implementation in the application context. It then automatically detects any custom constraints and will validate classes using your annotations without any further configuration.

However, there is still one problem with this. As it stands, the Validator will validate all of the annotations in one pass. This is a problem, because the database check will occur even if the email fails all of the other checks which is wasteful and potentially confusing to the user, who would see multiple validation messages. Thankfully, the JSR303 specification contains the concept of groups, which can be used to lump annotations together and process them in a specified order. The example below illustrates how groups can be used to split the basic format checks from the database check.
@GroupSequence(value={SendPasswordReminderCommand.class, FormatChecks.class,BusinessLogicChecks.class})
public class SendPasswordReminderCommand implements Serializable {
 
 private static final long serialVersionUID = 42L;
 
 @NotNull(groups=FormatChecks.class)
 @Length(min=1, groups=FormatChecks.class)
 @Email(groups=FormatChecks.class)
 @EmailExistsConstraint(groups=BusinessLogicChecks.class)
 private String email;

 public String getEmail() {
  return email;
 }

 public void setEmail(String email) {
  this.email = email;
 }
}
Firstly, each annotation has a group parameter that specifies a class (in this example, FormatChecks.class and BusinessLogicChecks.class). These classes are marker interfaces that are simply used to identify groups. To specify the sequence in which annotation groups are processed, the @GroupSequence annotation is used. An array of classes is passed to the values parameter that starts by convention with the class being validated, followed by the group marker interfaces in the order that you wish to process them. The marker interfaces are very straightforward. One of the interfaces must extend the javax.validation.groups.Default marker interface, which as you may guess is the default group if no group is specified.
public interface FormatChecks extends Default {

}

public interface BusinessLogicChecks {

}
You can define as many groups as you want. As you can see, creating custom constraint annotations is pretty straightforward with Spring 3.0. JSR 303 is well thought out and the ability to group constraints is very useful for ensuring that expensive business logic checks are not performed without reason, when validation has already failed for basic data format reasons.

Thursday 22 April 2010

Thread safety, Java Beans and Hibernate

I just read "Java Concurrency in Practice" by Brian Goetz et al and found it to be a fantastic educational experience. The main thing I learned is that I am a total novice when it comes to multi-threaded programming! My excuse is that I learned programming by building websites and applications, where it is popularly imagined that multi-threading is not really an issue. Also, I'm no computer scientist, just an ex-physicist who found out that pretending to know about the internet and programming pays better than doing a real job like physics. I digress.

I started to think about the standard patterns and practices used by web programmers when building web applications, especially using my favourite frameworks (Spring and Hibernate, of course) and wondered whether I should be more worried about threads than I usually am (i.e. not at all). After some serious head-scratching and blog-reading I have come to the following conclusions.

  1. There is evidence that Java Bean based frameworks could potentially be vulnerable to multi-threading issues due to the mutability of Java Beans
  2. I wouldn't worry about it too much (as long as they are thread-confined).

I better make it clear that I am not talking about the thread-safety of Hibernate or Spring themselves. By and large, as developers we accept these frameworks and given and while we should be aware of the thread-safety issues that they may have there is not much that we can do to change them in our applications. I'm talking about the standard components that we build on top of these frameworks. The thread-safety or otherwise of these frameworks is probably a worthy topic in itself, but it's not what I'm looking at here.

Let's start with Hibernate itself. Typically, persistent classes follow the Java Beans "pattern" of a no-args constructor with accessor and mutator objects for the private fields of the class (getters and setters). Java Beans are intrinsically "mutable" objects (they have mutators, after all!). Mutability on its own is not necessarily a thread-safety hazard, but the first recommendation for building thread-safe classes is to make them immutable - so Java Beans immediately seem to be a thread-safety hazard.

There are plenty of great resources explaining why mutable classes pose thread-safety hazard, including the "Java Concurrency In Practice" book, so I'll just summarise. The Java memory model makes no particular guarantees about the visibilty of changes in state between two threads, and in fact makes no guarantees about the order in which changes in state may seem to occur in two threads. This means that if thread 1 changes the state of a Java Bean field, thread 2 may not see this change immediately, or indeed at all. A further risk is that fields that are involved in invariants (i.e. are constrained by validation rules) could be modified so as to violate the invariants by different threads, even if the mutator methods contain logic to enforce the invariants.

So if Hibernate persistent classes are usually Java Beans, and Java Beans are mutable, and mutability is bad this surely seems to point to a potential thread-safety issue. So why am I sanguine about this risk?

The reason is that in general the risks posed by mutability are reduced when the objects in questions can be "thread-confined". In other words, they are only ever used by a single thread at a time. A mutable class will not pose thread-safety hazards if it is confined in this way. So, are Hibernate Java Beans thread-confined in a web application? The answer is potentially yes, depending on whether you store them somewhere that another thread can access them (like the HttpSession).

If your web application loads a Hibernate entity from a DAO or a service object that uses JPA (for instance) and then places this entity in a request for rendering in a view, it's pretty clear that this is thread-confined up to the point where the entity is placed in the request. Up to this point, it is only ever a local variable in a series of methods and is hence thread-confined (Actually, I don't know whether Hibernate is returning a unique instance for each call to Session.load() but I believe it does).

For example, here is a very brief illustration of retrieving a Hibernate entity for display on a page.

In the service object:
public Customer getCustomer(Integer customerId) {
return em.find(Customer.class, customerId);
}
in the controller:
@ModelAttribute("customer")
public Customer getCustomer() {
return customerService.getCustomer(customerId);
}

In the above example, the Customer entity instance is always thread confined. As a @ModelAttribute is stored in the HttpServletRequest it should be thread-confined as each request runs in its own thread which ends when the request is finished.

However, if the model is stored in the HttpSession, ServletContext or in a cache, then multiple threads might access the JavaBean. You are at the mercy of the thread safety of the HttpSession, ServletContext or cache provider.

In fact, it is recommended to synchronize access to attributes stored in the HttpSession unless contained in an immutable object, because multiple threads may access it simultaneously. The same is true of the SerlvetContext. A well-designed cache should be designed with concurrency in mind and have appropriate synchronization - but you should make sure of this.

So in conclusion, if you want to avoid thread-safety problems with Java Beans, confine them to a single thread and avoid storing them in places where multiple threads could access them such as the HttpSession, ServletContext or a cache (unless you are sure that the cache is thread-safe).

Wednesday 21 April 2010

Using JSR 303 with "classic" Spring Validators (enter the SpringValidatorAdapter)

Spring 3.0 has a number of new features, one of which is support for JSR303. JSR303 adds annotation-driven validation for Java Beans which is intended to replace hand-coded validation code. This has obvious ramifications for Spring MVC as a key part of this framework includes support for validation of web forms using hand-coded Validator implementations. I'm gradually upgrading a Spring 2.x MVC application to Spring 3.0 at the moment, with the emphasis on gradual. So while I'd like to use JSR 303, I'm not ready yet to re-code the 50 odd Controller implementations to use the new annotation-driven style (even though I hate seeing warnings in Eclipse). Luckily, Spring makes it really easy to have the best of both worlds using the SpringValidatorAdapter. Put simply, this class wraps the JSR303 adapter and provides convenience methods to enable you to easily support the old style Validator interface methods. You can then use the annotations in your command/form objects and the old-school Validators in your Controller classes. Here is a simple example command object using the JSR 303 annotations. They are pretty self-evident and there are loads of blogs that explain what they do.
public class MyCommand implements Serializable {

private static final long serialVersionUID = 42L;

@NotNull
@Min(value=1L)
private Integer projectId;

@NotNull
@Min(value=1L)
private Integer employeeId;

@NotNull
@Min(value=1L)
@Max(value=999L)
private BigDecimal hoursToComplete;

     // Constructors, accessors, mutators, equals, hashcode omitted :-)
}
The Validator for this class is then very simple. Create a Validator implementation as per usual, and then inject the SpringValidatorAdapter class into it. I've done this through the constructor, as I am trying to appear clever and multi-threaded by marking the SpringValidatorAdapter instance as final. Oh yeah, feel my muscles.
public class MyCommandCommandValidator implements Validator {

private final SpringValidatorAdapter validator;

public MyCommandCommandValidator(SpringValidatorAdapter validator) {
 super();
 this.validator = validator;
}

@SuppressWarnings("unchecked")
@Override
public boolean supports(Class givenClass) {
 return validator.supports(givenClass);
}

@Override
public void validate(Object target, Errors errors) {
 validator.validate(target, errors);
 
 // More custom validation here

}
}
Note that you could just use the SpringValidationAdapter directly (without wrapping it in your own Validator implementation) if you are only doing JSR303 validation. It's also possible to write your own JSR303 custom validation routines, which might be a better long term architecture than the mixed approach above. The Spring LocalValidatorFactoryBean implements the main JSR303 Validator interface as well as SpringValidatorAdapter. So the Spring configuration is simple. You do need to have the Hibernate Validator reference implementation available on the classpath or an alternative.



   

Job done! The only other thing to note is that the message codes are set by the JSR303 Validator, so you may have less control over them. For example:

public void testValidateNotNullFields() throws Exception {

 // Perform validation
 validator.validate(command, errors);

 // Check error count
 assertEquals(Integer.valueOf(3), Integer.valueOf(errors.getErrorCount()));
 
 // Test employeeId field
 FieldError employeeIdError = errors.getFieldError("employeeId");
 assertNotNull(employeeIdError);
 assertEquals("NotNull", employeeIdError.getCode());

}

In this test, the employeeId field was not set in the command. The Validator created a field error under key "employeeId" with the error code "NotNull" as it was the @NotNull constraint that was violated (and not in a good way). In summary - using JSR303 with "classic" validators is really easy thanks to the SpringValidatorAdapter class. Woot.

Tuesday 20 April 2010

Spring Security 3.0 and Spring EL

Among the many improvements in Spring Security 3.0 is the ability to use the Spring Expression Language (SPEL) to secure methods and URLs. This immediately opens up the possibility of more sophisticated "domain object security" on service methods and URLs. To secure service methods, a number of additional attributes have been added that support the SPEL. The most immediately useful is the @PreAuthorize attribute which is similar to the old @Secured attribute in intent but with a bit of SPEL processing thrown in as well. The documentation gives the following example:
@PreAuthorize("#contact.name == principal.name)")
public void doSomething(Contact contact);
The #contact refers to the contact parameter in the method. The tag causes all of the method parameters to be injected as variables into the expression language evaluation context. Variables are referenced using the # prefix. This script basically checks that the #contact variable has a name field that matches the name field in the current principal object (principal is an implicit object that is the current Spring Security Principal implementation). There are3 other attributes that have been added for filtering and post-authorisation. You can also use SPEL to restrict access to URLs.
<http expressions="true>
<intercept-url pattern="/admin*" access="hasRole('admin') and hasIpAddress('192.168.1.0/24')">
...
</intercept-url>
</http>
A great feature of this is that the EL has access to the HttpServletRequest in the EvaluationContext for the web request, meaning that you can peek at request parameters in the EL to grant access based on their values. Another useful feature is being able to check access to a specific URL in the Spring Security taglibs before rendering content.
<sec:authorize url="/admin">

This content will only be visible to users who are authorized to send requests to the "/admin" URL.

</sec:authorize>
These are all very useful features. However, there are a number of problems with the support offered for EL base access control that I have discovered. My immediate instinct was to define EL based access control inside the security context with the <intercept-url /> and then use <sec:authorize url="/xxx" /> in JSPs to render links only when a user has access to them. This works well up to a point. Problems start to occur when you need to evaluate objects in the request in the expression and try to authorize those URLs using the tag. For example, take the following EL definition which checks that the employee id supplied in the request matches the employee id of the logged in principal.
<intercept-url pattern="/timesheetview.htm"
access="principal.employeeId ==
T(java.lang.Integer).valueOf(request.getParameter('employeeId'))" />
This on its own works well enough. If you request the URL in a browser, requests are correctly authorised (or not). However, if you then try to use the <sec:authorize url="/xxx" /> tag in a JSP to check access to this URL, things no longer work. For example, the script below seems like it should work.
<c:url value="/timesheetview.htm" var="url">
<c:param name="employeeId" value="${employeeId}>
<c:url>
<sec:authorize url="${url}">
<a href="${url}">View timesheet<a>
</sec:authorize>
The problem is that the authorize tag does not allow scripting variables in the url attribute. However, there is a further problem which means that even if it did you still can't dynamically check access based on a request parameter. My first attempt at a workaround was this:
<sec:authorize url="/timesheetview.htm?employeeId=123">
<a href="/timesheetview.htm?employeeId=123">View timesheet<a>
</sec:authorize>
This gets around the scripting issue, but fails for a more fundamental reason (above the fact that employee id must be hard-coded). The reason this doesn't work is that Spring Security issues a "dummy" request to the URL to see whether access is denied or granted. The dummy request is made using an instance of org.springframework.security.web.access.DummyRequest which is a partial implementation of HttpServletRequest. Specifically, most operations cause an OperationNotSupportedException - including HttpServletRequest.getParameter(String name). That means that when the EL expression executes, it tries to call request.getParameter() which in turns causes the OperationNotSupportedException. It is in fact impossible in Spring Security 3.0 to use an EL expression in the <intercept-url /> in combination with the <sec:authorize url="xxx"> tag in a situation where the url in question is secured with an expression that accesses the HttpServletRequest - regardless of whether the parameter is supplied in the request or not. These problems mean that this exciting feature falls quite short of expectations when used in what seems to be a fairly obvious scenario. I'd like to see the DummyRequest be able to support request parameters in a future version that are evaluated based on the contents of the url attribute. This attribute should support scripting variables to enable parameters to be passed in using <c:url> Don't get me wrong - it's still awesome. Spring Security 3.0 is a worthwhile upgrade but there is always room for improvement.

Thursday 4 February 2010

Unit testing Spring Controllers

I found this DevX blog by Edmon Begoli really useful for writing unit tests for Spring controllers using MockHttpRequest and MockHttpResponse. However, I think the ideas in it can be extended slightly to help those using Spring Security and Hibernate, particularly the Open Session In View pattern, perhaps aided by Spring's OpenSessionInViewFilter.

My first enhancement would be to load the Controller instances from Spring rather than assembling them by hand. The key to doing this with Maven is to move the "spring-servlet.xml" file that configures the controllers from the src/main/webapp/WEB-INF folder in to src/main/resources. This doesn't cause any problems as you can load the spring-servlet.xml from anywhere on the classpath.


  spring
    org.springframework.web.servlet.DispatcherServlet
    
       contextConfigLocation
       classpath:spring-servlet.xml  
     
  1

Having done this, you can then load the spring-servlet.xml application context in your Controller unit tests.

The setUp() method below shows how to do this, in addition to obtaining a reference to the Spring security AuthenticationManager and starting a Hibernate Session. The latter allows us to replicate the effects of the OpenSessionInViewFilter while the former gives us the means to log in to Spring Security before executing a test.

protected void setUp() throws Exception {
  super.setUp();
  
  // Set up Spring application context
  String[] paths = { "application-context-datasource-test.xml",
       "application-context-dao.xml",
       "application-context-facade.xml",
       "application-context-mail.xml",
       "spring-servlet.xml" };
  ctx = new ClassPathXmlApplicationContext(paths);
      
  // Get Spring AuthenticationManager
  am = (AuthenticationManager)ctx.getBean("authenticationManager");  
       
  // Create mock request and response
  request = new MockHttpServletRequest();
  response = new MockHttpServletResponse();
  
  // Start session (simulate open session in view)
  factory = (SessionFactory)ctx.getBean("sessionFactory");
  session = sessionFactory.openSession();
  TransactionSynchronizationManager.bindResource(factory, new SessionHolder(session));
}

A simple "log in" method can be provided for use in the tests.

protected void login(String username, String password) {
  Authentication auth = am.authenticate(new UsernamePasswordAuthenticationToken(username, password));
  SecurityContextHolder.getContext().setAuthentication(auth);
}

A sample test method might look like this.

public void testStuff() throws Exception {
  // Get the controller
  MyController ctrlr = (MyController ) ctx.getBean("myController");

  // Login as manager
  login("bill.business-manager", "secret");

  // Controller renders form on GET method
  request.setMethod(AbstractController.METHOD_GET);

  // Execute the request
  ModelAndView mav = ctrlr.handleRequest(request, response);
  
  // Test stuff
  assertNotNull(mav);
}