Tuesday, January 27, 2009

Bookmark and Share

Update (february 17, 2009): With the first alpha release of Hibernate Validator 4.0 – the JSR 303 reference implementation – some of the steps described here are not neccessary any more. In particular you can retrieve the project from the Maven repo at JBoss now. This post is also the basis for the "Getting started" section of the reference guide which is part of the Hibernate Validator distribution.

Validating objects against different criteria is a requirement in basically every software development project. Examples are countless:

  • a given object might never be allowed to be null
  • a number could be required to be always in the interval [1 ... 100]
  • a String might be expected to match some regular expression or to represent a valid e-mail address, credit card number, license plate etc.

Where Java is concerned, a couple of dedicated validation frameworks have been around for quite a long time. The probably best-known ones are Commons Validator from the Apache Commons project and Hibernate Validator. Other options are iScreen and OVal, and the ubiquitous Spring framework comes with its own validation package, too.

With JSR 303: "Bean Validation" efforts are under-way, to establish a standard validation API. The JSR tries to combine the best features of the different validation frameworks, while making you independent from any concrete implementation.

Try it out yourself

Though the JSR 303 specification is not yet completed, you can already get a first impression, what it will feel like to use the standardized validation API. At the time of writing I am aware of two projects that aim for an implementation of the JSR 303 spec (I'd be happy to learn on any other implementations):

In the following I will describe the first steps using the reference implementation. Help on using agimatec-validation can be found here.

Download and build the JSR 303 RI

The reference implementation comes in form of a Maven project. As I didn't find it in any public Maven repository, I checked it out from SVN at JBoss:

1
svn co http://anonsvn.jboss.org/repos/hibernate/validator/trunk/

The checked-out project has now to be built using Maven. As of January, 27th (repo revision #15824), unfortunately one of the four contained sub-projects – hibernate-validator – doesn't build properly, as the version of one of its dependencies is not specified in the project's pom.xml.

So I added the version of the tck-utils dependency in hibernate-validator/pom.xml. Furthermore, I specified the versions of two other dependencies – slf4j-api and slf4j-log4j12 – in the same file. Failure to do so gave me NoClassDefFoundErrors within my own project, since these libraries weren't added as transitive dependencies to my classpath. The three modified dependencies in hibernate-validator/pom.xml should look like that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
...
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.5.6</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.5.6</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>tck-utils</artifactId>
    <version>0.9-SNAPSHOT</version>
    <scope>test</scope>
</dependency>
...

Use Bean Validation in your own project

Having built the JSR 303 API and the RI, it's time to make use of it in a litte sample project. First create a new Maven project using the Maven archetype plugin:

1
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart -DgroupId= -DartifactId=beansvalidation-test -Dversion=1.0-SNAPSHOT

Now add the dependencies to the Bean Validation API and the reference implementation to your project's pom.xml. Also make sure – since JSR 303 is all about annotations – that you are using at least Java 5 as source/target compliance level. Having done so, your POM should look as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<project 
    xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.gm</groupId>
    <artifactId>beans-validation-test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>RELEASE</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Open the project in the IDE of your choice and create the following class as an exemplary domain object:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package org.gm.beansvalidation;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class Car {

    @NotNull
    private String manufacturer;

    @NotNull
    @Size(min = 2, max = 14)
    private String licensePlate;

    public Car(String manufacturer, String licencePlate) {

        super();
        this.manufacturer = manufacturer;
        this.licensePlate = licencePlate;
    }

    //getters and setters ...

}

@NotNull and @Size are so-called constraint-annotions, that we use to declare certain constraints, which shall be applied to the fields manufacturer (shall never be null) and licensePlate (shall never be null and must be between 2 and 14 characters long).

To perform a validation of these constraints, we use the Validator interface defined by the specification. Let's try it in a test for our Car class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package org.gm.beansvalidation;

import static org.junit.Assert.*;

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.junit.BeforeClass;
import org.junit.Test;

public class CarTest {

    private static Validator validator;

    @BeforeClass
    public static void setUp() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
    }

    @Test
    public void testManufacturerIsNull() {

        Car car = new Car(null, "DD-AB-123");

        Set<ConstraintViolation<Car>> constraintViolations =
            validator.validate(car);

        assertEquals(1, constraintViolations.size());
        assertEquals(
            "may not be null", constraintViolations.iterator().next().getInterpolatedMessage());

    }

    @Test
    public void testLicensePlateTooShort() {

        Car car = new Car("Audi", "D");

        Set<ConstraintViolation<Car>> constraintViolations = 
            validator.validate(car);

        assertEquals(1, constraintViolations.size());
        assertEquals(
            "size must be between 2 and 14", constraintViolations.iterator().next().getInterpolatedMessage());
    }

    @Test
    public void testCarIsValid() {

        Car car = new Car("Audi", "DD-AB-123");

        Set<ConstraintViolation<Car>> constraintViolations =
            validator.validate(car);

        assertEquals(0, constraintViolations.size());
    }
}

On line 22 we get a Validator object from the ValidatorFactory. Then, we use this validator to validate the car object. The validate() method returns a set of ConstraintViolation objects, which we can iterate through in order to see which validation errors occured.

The first two validate() calls return a violation of the @NotNull constraint on manufacturer (line 31) and of the @Size constraint on licensePlate (line 46). If the object could be validated successfully (as in line 59), validate() returns an empty set.

Note that we only use classes from the package javax.validation, which stems from the Bean Validation standard API. The concrete implementations, e.g. for ValidatorFactory and Validator, are hidden from us. Therefore it would be no problem to switch to another implementation of the API, should that need arise.

What's next?

This post showed the very first steps using the Bean Validation API and its reference implementation. As the specification is not yet completed, it wouldn't be wise to make use of it already in a real-world application. The API still experiences frequent changes, things that work today, might end up in a compiler error tomorrow due to a renamed interface for instance.

The JSR is right now in "Public Review" status, meaning that everyone is invited to have a look on the specification and comment on it in the JSR 303 feedback forum.

Though the reference implementation doesn't implement the spec completely (e.g. specified annotations as @Min, @Max or @AssertTrue are not yet supported, using them will result in a NullPointerException), it still allows us to get a practical impression where the path of bean validation will lead one day.

In a subsequent post I will show how to make use of some more advanced features of the JSR 303 API, such as custom constraint annotations and validation groups.

Monday, January 19, 2009

Bookmark and Share

Every once in a while I find myself in a situation, where the visitor design pattern comes in handy to perform a set of different operations on the elements of an object hierarchy. Normally I would start then designing a Visitor and Visitable interface, dedicated to the problem right at my hands.

Having done this for a couple of times, I asked myself, whether there might be some essence in all those visitor pattern implementations, which might be worth being extracted into a basic Visitor resp. Visitable interface, allowing for further reuse. The challenge when creating such interfaces is to design them in a generic, but still type-safe manner.

Optimally, the elements of a concrete object hierarchy should only be visitable by an associated hierachy of visitors, while these visitors should only be able to visit the elements of exactly this hierarchy. This requirement is met by the following design:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.gm.visitorpattern;

public interface Visitor<V extends Visitor<V, T>, T extends Visitable<V, T>> {

    void dispatchVisit(T visitable);

}

...

public interface Visitable<V extends Visitor<V, T>, T extends Visitable<V, T>> {

    public void accept(V visitor);

}

Through the use of type parameters the interfaces are generic, independent of any concrete application of the pattern. Despite this genericity, the design fulfills our requirement, that elements of a concrete visitable hierarchy only accept visitors of an associated visitor hierarchy and vice versa. This coupling between a concrete visitable hierarchy and an associated hierarchy of visitor classes is ensured by leveraging so-called "self-bound" or "self-referential generics" (Visitor<V extends Visitor<V, T>, ...).

To make things a bit clearer, let's use those interfaces to apply the visitor pattern to a hierarchy of file system objects (files and directories), that can be visited by file system visitors. The interface to represent file system objects is derived from Visitable:

1
2
3
4
5
6
7
8
9
10
package org.gm.visitorpattern.sample;

import org.gm.visitorpattern.Visitable;

public interface FileSystemObject extends
    Visitable<FileSystemVisitor, FileSystemObject> {

    String getName();

}

As implementation of this interface let's first create a file class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package org.gm.visitorpattern.sample;

public class File implements FileSystemObject {

    private long size;
    protected String name;

    public File(String name, long size) {
        this.name = name;
        this.size = size;
    }

    public long getSize() {
        return size;
    }

    @Override
    public void accept(FileSystemVisitor visitor) {
        visitor.visit(this);
    }

    @Override
    public String getName() {
        return name;
    }

}

Of course we need a class to represent directories as well:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package org.gm.visitorpattern.sample;

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

public class Directory implements FileSystemObject {

    private List<FileSystemObject> children = new ArrayList<FileSystemObject>();
    protected String name;

    public Directory(String name, FileSystemObject... children) {
        this.name = name;

        for (FileSystemObject fso : children) {
            this.children.add(fso);
        }
    }

    public List<FileSystemObject> getChildren() {
        return children;
    }

    @Override
    public void accept(FileSystemVisitor visitor) {
        visitor.visit(this);
    }

    @Override
    public String getName() {
        return name;
    }

}

One might create an abstract base class for both implementations (which could hold the name property and other common logic), but we will skip this for the sake of simplicity.

Now its time to create a derivation of the Visitor interface, that has to be implemented by all concrete file system visitors. According to the visitor pattern we specify an overloaded version of the visit method for each class of the visited object hierarchy:

1
2
3
4
5
6
7
8
9
10
11
12
package org.gm.visitorpattern.sample;

import org.gm.visitorpattern.Visitor;

public interface FileSystemVisitor extends
        Visitor<FileSystemVisitor, FileSystemObject> {

    void visit(File file);

    void visit(Directory directory);

}

By specifying the concrete values for the type parameters of the Visitor and Visitable interfaces as shown in the FileSystemObject resp. FileSystemVisitor interfaces, we ensure that file system objects can only be visited by file system vistors, while those only can visit file system objects. Actually, there wouldn't have been any way around this (welcome) restriction due to the self-bound type parameters in the super interfaces.

To conclude the example, let's develop a file system visitor, that calculates the size of a directory with all its files and sub directories:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package org.gm.visitorpattern.sample;

public class SizeCalculationVisitor implements FileSystemVisitor {

    private long totalSize = 0;

    @Override
    public void dispatchVisit(FileSystemObject visitable) {
        visitable.accept(this);
    }

    @Override
    public void visit(File file) {
        totalSize += file.getSize();
    }

    @Override
    public void visit(Directory directory) {
        for (FileSystemObject oneChild : directory.getChildren()) {
            oneChild.accept(this);
        }

    }

    public long getTotalSize() {
        return totalSize;
    }

}

Finally let's test our new visitor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package org.gm.visitorpattern.sample;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;

public class VisitorPatternTest {

    private FileSystemObject root;

    @Before
    public void setup() {
        root = 
            new Directory("root", 
                new File("file1.txt", 100),
                new Directory("dir1",
                    new File("dir1_file1.txt", 200),
                    new File("dir1_file2.txt", 200)),
                new File("file2.txt", 400));
    }

    @Test
    public void testGetOperations() {

        SizeCalculationVisitor visitor = new SizeCalculationVisitor();
        visitor.dispatchVisit(root);

        assertEquals(900, visitor.getTotalSize());

    }

}

What is it worth for?

So, what's the use of the generic Visitor and Visitable interfaces? First, they help implementing the visitor design pattern properly. For my part, I am always forgetting about the implementation details – by deriving from the interfaces, there isn't much left that I could do wrong.

At second, visitor and visitors are recognizable as such not only by some naming convention or similar but inherently by their types. So if an application needs to perform operations on all visitables or visitors – across the bounds of hierarchies – it can do so by inspecting their types.

Sunday, January 18, 2009

Bookmark and Share

With the advent of generics in Java 5, also generic methods were introduced. Generic methods have one ore more type parameters, which can be used to specify the parameters or return type of a method. For example the JDK's collection utility class java.util.Collections declares a wide range of generic methods.

When using those methods, the concrete types to be used as parameters or return value are derived from the invocation context using type inference (Angelika Langer goes into detail on this topic in her great Generics FAQ here).

So for instance you can use the method emptyMap() of the mentioned class Collections as follows to initialize an empty Map<String, Long>:

1
2
3
4
5
6
7
8
9
public class GenericMethodsTest {

    @Test
    public void testTypeInference() {

        Map<String, Long> map = Collections.emptyMap();
        assertTrue(map.isEmpty());
    }
}

Unfortunately, this doesn't work, if the return value of the generic method isn't assigned to a variable, but rather is used as parameter for another method invocation. So the following code fails with a compiler error at line 6 saying "The method doSomething(Map<String,Long>) in the type GenericMethodsTest is not applicable for the arguments (Map<Object,Object>)":

1
2
3
4
5
6
7
8
9
10
11
12
public class GenericMethodsTest {

    @Test
    public void testTypeInference() {

        doSomething(Collections.emptyMap()); //compiler error
    }

    private void doSomething(Map<String, Long> map) {
        assertTrue(map.isEmpty());
    }
}

What I did till today in such a case was to assign the result of the generic method to a local variable and using this variable as parameter. This is somewhat ugly and actually not neccessary at all, as it is possible to specify the type parameters explicitely as follows:

1
2
3
4
5
6
7
8
9
10
11
12
public class GenericMethodsTest {

    @Test
    public void testTypeInference() {

        doSomething(Collections.<String, Long> emptyMap());
    }

    private void doSomething(Map<String, Long> map) {
        assertTrue(map.isEmpty());
    }
}

Actually a practical but rather unknown feature of the Java language, which makes the code shorter while more readable at the same time. More information on explicitely specifying type parameters when calling generic methods can again be found at Angelika Langer's FAQ here.

Wednesday, January 7, 2009

Bookmark and Share

In my previous posting, I gave a short overview on the very basic features of Google's dependency injection container Guice. Today, I want to delve a bit more into Guice's means of aspect oriented programming (AOP) by musing on its abilities for method interception.

AOP is a common way for implementing cross-cutting concerns of an application, such as logging/tracing, transaction handling or permission checking.

As opposed to fully-fledged AOP solutions such as AspectJ, Guice's AOP facilities are limited to simple method interceptors. But to be fair, this should do the trick for most scenarios, while at the same time keeping the mechanism very easy to understand and use.

Create a new project

As in the first part of this tutorial, Maven shall be used as build tool. Unfortunately, one required 3rd party library – the AOP alliance API – is not declared as dependency in Guice's Maven POM. Therefore, we have to declare this dependency in our own pom.xml, which should look as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<project 
    xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.gm</groupId>
    <artifactId>guice-aop</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>guice-aop</name>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.google.code.guice</groupId>
            <artifactId>guice</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>RELEASE</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

As exemplary business service for this tutorial let's now create a little video rental shop, where videos from the stock can be rented and new videos can be registered:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.gm.guicetutorial;

public class VideoRental {

    public boolean rentMovie(long movieId) {

        System.out.println(
            String.format("Movie %s rented.", movieId));

        return true;
    }

    public boolean registerNewMovie(String name) {

        System.out.println(
            String.format("New movie \"%s\" registered.", name));

        return true;
    }
}

Create a simple interceptor

Now it's time to create our first method interceptor. Since Guice uses AOP alliance conform method interceptors, we have to implement the interface MethodInterceptor to do so. The following snippet shows the canonical example, a simple tracing interceptor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package org.gm.guicetutorial.interceptors;

import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class TracingInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

        long start = System.nanoTime();

        try {
            return invocation.proceed();
        } 
        finally {
            System.out.println(
                String.format(
                    "Invocation of method %s() with parameters %s took %.1f ms.",
                    invocation.getMethod().getName(),
                    Arrays.toString(invocation.getArguments()),
                    (System.nanoTime() - start) / 1000000.0));
        }
    }

}

The method invoke() will be called by the container for each intercepted method. The passed MethodInvocation object contains an instance of java.lang.reflect.Method to represent the called method, a reference to the object on which the method was called as well as the parameters of the invocation.

To execute the intercepted method call, the proceed() method of the passed invocation has to be invoked. Before and afterwards, one can do whatever one wants with the invocation, including a modification of the parameters or the return value or supressing the actual call at all. For the TracingInterceptor, we just log the called method together with the duration of the call.

Now we have to tell Guice, to which method invocations the interceptor shall be attached. As with the binding in the tutorial's first installment, we do this using a configuration module:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package org.gm.guicetutorial;

import static com.google.inject.matcher.Matchers.*;
import org.gm.guicetutorial.interceptors.TracingInterceptor;
import com.google.inject.AbstractModule;

public class ExampleModule extends AbstractModule {

    public void configure() {

        bindInterceptor(
            subclassesOf(VideoRental.class),
            any(),
            new TracingInterceptor());
    }
}

By calling bindInterceptor() we specify, which interceptor (TracingInterceptor) shall be attached to which methods (any()) of which classes (subclassesOf(VideoRental.class)). The latter two are so-called matchers, which allow a type-safe and refactoring-safe way of linking interceptors and the calls to which these shall be applied. More information on the matchers, that Guice provides, can be found in the JavaDoc of com.google.inject.matcher.Matchers.

Finally we create a test. Note the use of Injector.injectMembers() which allows for injection of dependencies into objects, which are not instantiated under the reign of Guice, as it is the case with JUnit test classes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package org.gm.guicetutorial;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

public class VideoRentalTest {

    @Inject
    private VideoRental videoRental;

    @Before
    public void setup() {

        Injector injector = Guice.createInjector(new ExampleModule());
        injector.injectMembers(this);
    }

    @Test
    public void testRentMovie() throws Exception {

        assertTrue(videoRental.rentMovie(1));
    }

    @Test
    public void testRegisterNewMovie() throws Exception {

        assertTrue(videoRental.registerNewMovie("The Fugitive"));
    }

}

Executing the test should yield in an output similar to the following:

1
2
3
4
Movie 1 rented.
Invocation of method rentMovie([1]) took 10.5 ms.
New movie "The Fugitive" registered.
Invocation of method registerNewMovie([The Fugitive]) took 0.4 ms.

A security checking interceptor

As a more advanced use of a method interceptor, let us now create an interceptor, that checks, if a given user is allowed to execute a certain action. The actions that a user is allowed to execute, shall be specified using a role based approach. Which role is required to perform a certain method call, shall be expressed using a custom annotation. The task of the interceptor will be to check, whether the current user has this role.

Note, that in a real-world scenario, one would probably have one level of indirection more by checking on a role's permissions instead of on the role itself, but let's keep things simple for now.

First of all, we need some sort of user manager, which holds the currently logged in user:

1
2
3
4
5
6
7
8
9
package org.gm.guicetutorial;

public interface UserManager {

    void setCurrentUser(User user);

    User getCurrentUser();

}

Our very simple implementation of the user manager looks as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package org.gm.guicetutorial;

public class UserManagerImpl implements UserManager {

    private User currentUser;

    @Override
    public void setCurrentUser(User currentUser) {
        this.currentUser = currentUser;
    }

    @Override
    public User getCurrentUser() {
        return currentUser;
    }

}

Within a multi-user server application, the user manager typically would use some sort of session mechanism to manage multiple users logged in at the same time. On the contrary, within a client application, the user manager might be a singleton object with application scope. For the sake of simplicity, we stick with the latter scenario, which we will realize leveraging Guice's SINGLETON scope as will be shown.

The User entity is a simple model class, which contains a user's name and his/her role(s) in form of a set of roles:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package org.gm.guicetutorial;

import java.util.Set;

public class User {

    private String name;

    private Set<Role> roles;

    public User(String name, Set<Role> roles) {

        super();
        this.name = name;
        this.roles = roles;
    }

    public String getName() {
        return name;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    @Override
    public String toString() {
        return name;
    }

}

To allow for specifying roles in a simple and still safe manner, we model the Role entity as enum:

1
2
3
4
5
6
7
package org.gm.guicetutorial;

public enum Role {

    CUSTOMER, EMPLOYEE;

}

As mentioned above, it would be nice, to have a custom annotation, that can be used to specify, which role is required for the execution of a certain method.

The next snippet shows a simple blueprint, how such an annotation could look like. For now, the annotation has just one attribute – the standard attribute "value", which holds the name of the required role. By the use of meta annotations we specify further details of the annotation: it shall be usable at methods (@Target(ElementType.METHOD)) and accessible at runtime (@Retention(RetentionPolicy.RUNTIME)).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package org.gm.guicetutorial;

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresRole {

    Role value();

}

Using our new annotation it's real fun to define, which roles are required to execute the methods of the VideoRental class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package org.gm.guicetutorial;

import com.google.inject.Inject;

public class VideoRental {

    @Inject
    UserManager userManager;

    @RequiresRole(Role.CUSTOMER)
    public boolean rentMovie(long movieId) {

        System.out.println(String.format(
            "Movie %s rented by user %s.",
            movieId,
            userManager.getCurrentUser()));

        return true;
    }

    @RequiresRole(Role.EMPLOYEE)
    public boolean registerNewMovie(String name) {

        System.out.println(String.format(
            "New movie \"%s\" registered by user %s.",
            name, 
            userManager.getCurrentUser()));

        return true;
    }
}

Now let's have a look at the interceptor, that checks, wether the current user has the role required to invoke a certain method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package org.gm.guicetutorial.interceptors;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.gm.guicetutorial.RequiresRole;
import org.gm.guicetutorial.Role;
import org.gm.guicetutorial.UserManager;

import com.google.inject.Inject;

public class RoleValidationInterceptor implements MethodInterceptor {

    @Inject
    private UserManager userManager;

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

        Role requiredRole = 
            invocation.getMethod().getAnnotation(RequiresRole.class).value();

        if( userManager.getCurrentUser() == null ||
            !userManager.getCurrentUser().getRoles().contains(requiredRole)) {

            throw new IllegalStateException("User requires role " + requiredRole);
        }

        return invocation.proceed();
    }
}

We get the required role for a method invocation by evaluating the value attribute of the RequiresRole annotation. If this role is not contained within the current user's set of roles, an IllegalStateException is thrown. Otherwise, the intercepted method call is resumed.

As before, some plumbing has to be done now in the binding module:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package org.gm.guicetutorial;

import static com.google.inject.matcher.Matchers.*;

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

import org.gm.guicetutorial.interceptors.RoleValidationInterceptor;

import com.google.inject.AbstractModule;
import com.google.inject.Scopes;

public class ExampleModule extends AbstractModule {

    private List<Object> injectees = new ArrayList<Object>();

    public void configure() {

        bind(UserManager.class).to(UserManagerImpl.class).in(Scopes.SINGLETON);

        RoleValidationInterceptor roleValidationInterceptor = new RoleValidationInterceptor();

        bindInterceptor(
            any(),
            annotatedWith(RequiresRole.class),
            roleValidationInterceptor);

        injectees.add(roleValidationInterceptor);
    }

    public List<Object> getInjectees() {
        return injectees;
    }

}

First, we bind UserManagerImpl to the interface UserManager. By using the SINGLETON scope we ensure, that the same UserManager instance will be returned by the injector each time, so that the UserManger injected into VideoRental as well as into the interceptor is the same.

Secondly, the RoleValidationInterceptor has to be configured. As method matcher we specify annotatedWith(RequiresRole.class), thereby attaching the interceptor only to those methods, which are tagged with our new shiny annotation.

Unfortunately, Guice currently can not inject dependencies into interceptors within a module's configure() method. To circumvent this issue, we let the module return a collection of injectees, that we will process manually, once the injector is created. A more sophisticated way to tackle that problem is shown by Tim Peierl in his blog.

In the upcoming Guice release 2.0 the new method requestInjection() in AbstractModule can be used to specify any injectees, that shall be provided with dependencies upon creation of the injector.

Finally let's build a test for the new role validation mechanism:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package org.gm.guicetutorial;

import static org.junit.Assert.*;

import java.util.HashSet;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

public class VideoRentalTest {

    @Inject
    private VideoRental videoRental;

    @Inject
    private UserManager userManager;

    private static User customer;

    private static User employee;

    @BeforeClass
    public static void setupUsers() {

        customer = new User("Peter", EnumSet.of(Role.CUSTOMER));
        employee = new User("Bob", EnumSet.of(Role.EMPLOYEE));
    }

    @Before
    public void setup() {

        ExampleModule module = new ExampleModule();

        Injector injector = Guice.createInjector(module);
        for (Object oneInjectee : module.getInjectees()) {
            injector.injectMembers(oneInjectee);
        }

        injector.injectMembers(this);
    }

    @Test
    public void testRentMovieSuccessfully() throws Exception {

        userManager.setCurrentUser(customer);
        assertTrue(videoRental.rentMovie(1));
    }

    @Test(expected = IllegalStateException.class)
    public void testRentMovieFailing() throws Exception {

        userManager.setCurrentUser(employee);
        videoRental.rentMovie(1);
    }

    @Test
    public void testRegisterNewMovieSuccessfully() throws Exception {

        userManager.setCurrentUser(employee);
        assertTrue(videoRental.registerNewMovie("The Fugitive"));
    }

    @Test(expected = IllegalStateException.class)
    public void testRegisterNewMovieFailing() throws Exception {

        userManager.setCurrentUser(customer);
        assertTrue(videoRental.registerNewMovie("The Fugitive"));
    }
}

In the class setup, two users – one customer, one employee – are instantiated. In the test setup, the Guice injector is created, followed by the injection of dependencies into the injectees as returned by the binding module. Four test methods are present, one testing successful execution and one testing failure of execution due to the lack of the required role for each of VideoRental's methods.

This concludes the 2nd part of my tutorial series on Google Guice. As shown, Guice provides a simple but still powerful means of aspect oriented programming. Also advanced scenarios such as security checking using a custom annotation are not very hard to realize. The complete source code can be downloaded here.

In the next installment, I will show how to use Guice within a JEE environment, namely its use together with EJB.

Thursday, January 1, 2009

Bookmark and Share

As I recently played around a bit with the creation of MD5 hashes in Java, I stumbled across an alternative MD5 library called "Fast MD5", which claims to be faster than the classes provided by the JDK. So I downloaded this lib, added it to my class path and started using it by commenting out the references to JDK's class MessageDigest and using Fast MD5's class MD5 instead.

Everything worked out fine, but I was not very satisfied from a software architectural point of view. Instead of toggling referenced classes by commenting and uncommenting code, the proper way to go should be dependency injection (DI), and I thought it would be a great chance to get a grip on Google's award-winning DI framework Guice. There we go ...

Extract the interface

One of DIs basic principles is the separation between the interface of a service and its implementation. So lets extract an interface out of last post's class MD5Helper and make this class become an implementation of that new interface:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@ImplementedBy(MD5HelperStandardImpl.class)
public interface MD5Helper {

    String getMD5Hash(String input);

}

public class MD5HelperStandardImpl implements MD5Helper {

    @Override
    public String getMD5Hash(String input) {

        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] messageDigest = md.digest(input.getBytes());

            return new BigInteger(1, messageDigest).toString(16);
        }
        catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

}

Two things are remarkable:

  • The interface is annotated with Guice's @ImplementedBy annotation, specifying the interface's default implementation
  • The method getMD5Hash() became non-static, as static methods can't be declared within an interface.

May I introduce: The injector

How to use Guice now to get an instance of MD5Helper? Nothing could be easier. Just use Guice's injector as shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MD5HelperTest {

    @Test
    public void testStandardImpl() throws Exception {

        Injector injector = Guice.createInjector();
        MD5Helper helper = injector.getInstance(MD5Helper.class);

        assertEquals(
            "5d255e82ae2be1d1d54090bb20351106",
            helper.getMD5Hash("Hello guicy world!"));
    }
}

Custom bindings

Let's now create another implementation of the MD5Helper interface based upon the mentioned library "Fast MD5":

1
2
3
4
5
6
7
8
9
10
11
public class MD5HelperFastImpl implements MD5Helper {

    @Override
    public String getMD5Hash(String input) {

        MD5 md5 = new MD5();
        md5.Update(input);

        return new BigInteger(1, md5.Final()).toString(16);
    }
}

How can we make sure to get this implementation, if we request an instance of MD5Helper? Obviously there can be only one default implementation, so there has to be another way to tell Guice which implementation we want.

And indeed there is. All we have to do, is to provide the injector with a so called module, that specifies the binding between the interface and the implementation, as shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class TestModule extends AbstractModule {

    public void configure() {
        bind(MD5Helper.class).to(MD5HelperFastImpl.class);
    }
}

public class MD5HelperTest {

    ...

    @Test
    public void testFastImpl() throws Exception {

        Injector injector = Guice.createInjector(new TestModule());
        MD5Helper helper = injector.getInstance(MD5Helper.class);

        assertEquals(
            "5d255e82ae2be1d1d54090bb20351106",
            helper.getMD5Hash("Hello guicy world!"));
    }
}

Finally ... dependency injection!

Now imagine, there was another class which wants to make use of the MD5Helper. This class could make direct use of the injector itself, but actually this would degrade Guice to just some better sort of factory. Rather we can use Guice to inject dependency – actually that's what Guice is all about :-) How to do so? Have a look at the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class PasswordManager {

    @Inject
    private MD5Helper helper;

    private Map passwordHashes;

    public PasswordManager() {
        passwordHashes = new HashMap();
        passwordHashes.put("peter", "5ebe2294ecd0e0f08eab7690d2a6ee69");
    }

    public boolean passwordMatches(String userName, String enteredPassword) {
        return
            passwordHashes.containsKey(userName) &&
            helper.getMD5Hash(enteredPassword).equals(passwordHashes.get(userName));
    }
}

The example shows a simple password manager. It checks the password some user entered by comparing the MD5 hash of that entered password with the saved hash of the user's password.

Disclaimer: This code is just for demonstration purposes, a real implementation would include retrieving the existing hash from some sort of persistent storage and using some salt for hash generation. Generally it is recommendable to represent passwords with character arrays instead of strings, allowing for removing them from memory after processing, as described in JDK 6' Console class.

Back to the example. We make use of Guice's @Inject annotation to provide the PasswordManager with an MD5Helper. If we use Guice now to get an instance of PasswordManager, this dependency will be injected:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class PasswordManagerTest {

    private PasswordManager passwordManager;

    @Before
    public void setup() {

        Injector injector = Guice.createInjector();
        passwordManager = injector.getInstance(PasswordManager.class);
    }

    @Test
    public void testPasswordMatches() throws Exception {

        assertTrue(passwordManager.passwordMatches("peter", "secret"));
        assertFalse(passwordManager.passwordMatches("peter", "wrong password"));
    }
}

So actually you will very rarely make direct use of the Injector – only once at the top of your object graph. All dependencies annotated with @Inject in the root class (here PasswordManager) as well as in all classes referenced by it will be resolved by Guice automatically.

What's next?

Try it out yourself – download the source code of this tutorial and give Guice a try. The sources come in form of a Maven project. Just extract the archive and run mvn test. Maven will download Guice and run the tests of the tutorial.

That's the end of our 15 minute crash course in using Google's Guice, though that's surely not all to be said about this fantastic framework. Definitely Guice's user guide is worth reading – especially due to its refreshing brevity (approx. 20 pages).

Advanced features include custom binding annotations, scoped dependencies and a means of intercepting methods allowing for the implementation of cross-cutting concerns in an aspect oriented way of programming.