Sunday, March 29, 2009

Bookmark and Share

When working with the Bean Validation API (JSR 303) it can be very practical to have the API sources at hand (e.g. as "Java Source Attachment" in Eclipse).

While the API binary can be retrieved from the JBoss Maven repository, no source JAR is deployed there as of March 2009.

But as the API sources are hosted at JBoss' public subversion repository, you can either read them online or check them out with any SVN client.

Using a SVN command line client the current release of the API – 1.0.CR1 – can be fetched by

1
svn co http://anonsvn.jboss.org/repos/hibernate/beanvalidation/tags/v1_0_CR1/

Monday, March 23, 2009

Bookmark and Share

JAX-WS is the standard API of the Java platform not only for the creation of web service providers but also for building web service clients. In the following I will show how to build and test a web service client using the JAX-WS reference implementation (RI) in conjunction with the Spring framework.

The example: A client for a simple shop web service

As example a simple client for an exemplary shop web service shall be built, that allows to search for products by their id. The WSDL looks as follows (this is a slightly simplified version of the WSDL from the shop service example which is part of the maven-instant-ws project):

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
<?xml version="1.0" encoding="UTF-8"?>
<definitions 
    name="Products" 
    targetNamespace="http://www.gmorling.de/jaxwsonspring/products"
    xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:tns="http://www.gmorling.de/jaxwsonspring/products"
    xmlns:products="http://www.gmorling.de/jaxwsonspring/products/types"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">

    <types>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <xsd:import namespace="http://www.gmorling.de/jaxwsonspring/products/types"
                schemaLocation="products.xsd" />
        </xsd:schema>
    </types>

    <message name="GetProductByIdRequestMessage">
        <part name="body" element="products:GetProductByIdRequest" />
    </message>
    <message name="GetProductByIdResponseMessage">
        <part name="body" element="products:GetProductByIdResponse" />
    </message>

    <portType name="ProductsPortType">
        <operation name="GetProductById">
            <input message="tns:GetProductByIdRequestMessage" />
            <output message="tns:GetProductByIdResponseMessage" />
        </operation>
    </portType>

    <binding name="ProductsSoapBinding" type="tns:ProductsPortType">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
        <operation name="GetProductById">
            <soap:operation soapAction="GetProductById" />
            <input>
                <soap:body use="literal" />
            </input>
            <output>
                <soap:body use="literal" />
            </output>
        </operation>
    </binding>

    <service name="ProductsService">
        <port name="ProductsPort" binding="tns:ProductsSoapBinding">
            <soap:address location="TODO" />
        </port>
    </service>
</definitions>

The WSDL basically defines a single operation, GetProductById, that takes a GetProductByIdRequest object and returns a GetProductByIdResponse object. These types are specified in a separate XML schema:

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
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://www.gmorling.de/jaxwsonspring/products/types"
    xmlns="http://www.w3.org/2001/XMLSchema" xmlns:products="http://www.gmorling.de/jaxwsonspring/products/types">

    <!-- GetProductById -->
    <element name="GetProductByIdRequest">
        <complexType>
            <sequence>
                <element name="Id" type="int" />
            </sequence>
        </complexType>
    </element>
    <element name="GetProductByIdResponse">
        <complexType>
            <sequence>
                <element type="products:Product" name="Product" minOccurs="0" />
            </sequence>
        </complexType>
    </element>

    <!-- General-purpose types -->
    <complexType name="Product">
        <sequence>
            <element name="Id" type="int" />
            <element name="Name" type="string" />
            <element name="Price" type="decimal" />
            <element name="Size" type="string" minOccurs="0" />
        </sequence>
    </complexType>
</schema>

The request type is just a wrapper for an int parameter representing a product id, while the response type contains a Product element, which itself has a name, price etc.

Generating proxy classes

JAX-WS provides a tool called wsimport which takes the WSDL of a web service and generates proxy classes for the WSDL's service and port definitions. These can then be used to access the web service endpoint.

With the help of the JAX-WS Maven plugin the wsimport tool can easily be used in Maven based projects. Just configure the wsimport goal of the plugin in your project's pom.xml 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
...
<build>
    ...
    <plugins>
        ...
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>jaxws-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>wsimport</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <wsdlDirectory>${basedir}/src/main/resources/wsdl</wsdlDirectory>
            </configuration>
        </plugin>
        ...     
    </plugins>
    ...
</build>
...

The WSDL to be processed can either be fetched directly from the actual web service endpoint or from a local directory (by specifying the wsdlDirectory property as shown in the example). I recommend to stick with the latter approach. That way your project can be built even if the service to be accessed is not available from your development environment.

During the "generate-sources" build lifecycle phase the plugin will generate

  • proxy classes for all service and port type declarations contained within the WSDL files in the specified directory
  • JAXB binding classes for all schema types used in the operations of that services

Using the proxy classes generated from the shop service WSDL it is not too hard to build a simple shop client:

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
package de.gmorling.jaxwsonspring;

import javax.xml.ws.BindingProvider;

import de.gmorling.jaxwsonspring.shop.products.ProductsPortType;
import de.gmorling.jaxwsonspring.shop.products.ProductsService;
import de.gmorling.jaxwsonspring.shop.products.types.GetProductByIdRequest;

public class ShopClient {

    private final static String END_POINT_URL = "http://localhost:8080/shopserver/Products";

    public String getProductNameByid(int productId) {

        GetProductByIdRequest request = new GetProductByIdRequest();
        request.setId(productId);

        ProductsService productsService = new ProductsService();
        ProductsPortType productsPort = productsService.getProductsPort();
        ((BindingProvider) productsPort).getRequestContext().put(
            BindingProvider.ENDPOINT_ADDRESS_PROPERTY, END_POINT_URL);

        return productsPort.getProductById(request).getProduct().getName();
    }
}

All you have to to do is to instantiate the ProductsService, retrieve the ProductsPort from it, set the endpoint address and call any of the port's operations.

Portability issues

This works basically pretty well, but I ran into a problem, as I tried to execute my project's binary on a different machine – suddenly the WSDL of the service couldn't be found. Searching the web a little bit I found out, that JAX-WS RI parses the WSDL each time a Service instance is created.

The WSDL's location is taken from an annotation of the generated Service class (ProductsService in this case), where it is unfortunately specified as an absolute path. That causes the Service initialization to fail if the project is moved to another directory or to another system, where the WSDL doesn't exist at the expected location.

This problem can be solved by specifying the WSDL location relatively when instantiating the Service class. This complicates the process of obtaining web service port references a little bit, therefore I thought it might be a good idea to make use of dependency injection (DI). That way the rather ugly API for setting the endpoint address can be hidden from the caller as well and DI finally allows to inject mock port implementations in unit tests.

Spring's JaxWsPortProxyFactoryBean

At first I considered building a custom solution using the Spring DI container, but then I stumbled upon Spring's JaxWsPortProxyFactoryBean that already provides DI services for JAX-WS client ports.

Using that bean a JAX-WS port can be configured within a Spring application context as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<beans 
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="productsPort" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
        <property name="serviceInterface" value="de.gmorling.jaxwsonspring.shop.products.ProductsPortType" />
        <property name="wsdlDocumentUrl" value="wsdl/products.wsdl" />
        <property name="namespaceUri" value="http://www.gmorling.de/jaxwsonspring/shop/products" />
        <property name="serviceName" value="ProductsService" />
        <property name="endpointAddress" value="http://localhost:8080/jaxws-on-spring-server/Products" />
    </bean>
</beans>

So basically you have to configure the type of the port to be injected (the attribute name "serviceInterface" seams a bit irritating to me), the URL of the WSDL (e.g. identifying a classpath resource), namespaceUri and serviceName as specified in the WSDL file and finally the address of the endpoint to be used.

A word on thread safety

When configured as shown above Spring will use the singleton scope for the productsPort bean. That means the bean will exist only once and potentially be accessed from multiple threads at the same time.

Unfortunately the JAX-WS specification doesn't clearly say whether the generated service and port classes are thread-safe or not. Therefore one generally should assume that they aren't.

But after some searching, I found a comment by one of the JAX-WS RI developers stating, that the proxy classes of JAX-WS RI are thread-safe, as long as the request context of a port instance isn't modified. Assuming that no user of the bean modifies its request context (e.g. by re-setting the endpoint address) we are fine with the singleton scope for now.

Injecting JAX-WS client ports

Now let's rewrite the ShopClient class by having the productsPort bean injected into it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package de.gmorling.jaxwsonspring;

import javax.annotation.Resource;

import de.gmorling.jaxwsonspring.shop.products.ProductsPortType;
import de.gmorling.jaxwsonspring.shop.products.types.GetProductByIdRequest;

public class ShopClient {

    @Resource
    private ProductsPortType productsPort;

    public String getProductNameByid(int productId) {

        GetProductByIdRequest request = new GetProductByIdRequest();
        request.setId(productId);

        return productsPort.getProductById(request).getProduct().getName();
    }

}

Of course we need to configure ShopClient as Spring bean as well:

1
2
3
...
<bean id="shopClient" class="de.gmorling.jaxwsonspring.ShopClient" />
...

When creating the shopClient bean Spring will process the @Resource annotation (which stems from JSR 250: "Common Annotations for the JavaTM Platform") by populating the productsPort field with the bean of the same name.

Mocking web service requests in unit tests

Leveraging dependency the ShopClient class is greatly simplified now. As last step let's create a unit test for it.

To do so we should work with a mock implementation of the ProductsPortType interface. Working with a mock instead of accessing the real shop web service does not only increase the performance of the unit test. It also ensures, that the test result isn't dependent on the service's availability or its proper functioning.

For creating the mock we will use the freely available Mockito framework in the following (alternatively we could work with EasyMock or JMockit).

In the Spring application context for the unit test we specify that the productsPort bean shall be created by calling the method org.mockito.Mockito#mock(), which expects the class object of the object to be mocked as parameter:

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<beans 
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="productsPort" class="org.mockito.Mockito" factory-method="mock" >
        <constructor-arg index="0" value="de.gmorling.jaxwsonspring.shop.products.ProductsPortType" />
    </bean>

    <bean id="shopClient" class="de.gmorling.jaxwsonspring.ShopClient" />
</beans>

Next we have to define, how the mock shall behave, when it is called by the code under test. For doing so we inject the productsPort bean into our test 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
package de.gmorling.jaxwsonspring;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import java.math.BigDecimal;

import javax.annotation.Resource;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import de.gmorling.jaxwsonspring.shop.products.ProductsPortType;
import de.gmorling.jaxwsonspring.shop.products.types.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ShopClientTest {

    @Resource
    private ProductsPortType productsPort;

    @Resource
    private ShopClient shopClient;

    @Before
    public void instructMock() {
        GetProductByIdResponse response = new GetProductByIdResponse();
        Product product = new Product();
        product.setId(1);
        product.setName("Jeans-Hose");
        product.setPrice(new BigDecimal("89.99"));
        product.setSize("L");
        response.setProduct(product);

        when(productsPort.getProductById(
            any(GetProductByIdRequest.class))).thenReturn(response);
    }

    @Test
    public void getProductName() {
        assertEquals("Jeans-Hose", shopClient.getProductNameByid(1));
    }

}

In the instructMock() method we first create a sample response object. Then we specify, that whenever the getProductById() of the mock is called, this response object shall be returned.

As the productsPort bean has singleton scope, the same instance of the bean will be injected into the shopClient bean. That way the shopClient bean will finally return the expected product name within the actual test method.

Conclusion

JAX-WS is a powerful API not only for the creation of web service providers but also for building web service clients. Unfortunately the devil is in the details – when not handled properly, JAX-WS will try to read WSDL files using absolute file pathes and setting end point addresses is not very intuitive as well.

Luckily the Spring framework comes to the rescue by enabling the creation of web service ports using dependency injection. That way obtaining port references is not only greatly simplified, it also allows mocking actual web service requests within unit tests.

The complete source code from this post can be downloaded here. As always I'd be happy about any comments and ideas for improvement.

Sunday, March 8, 2009

Bookmark and Share

This is the third – and for now last – part of my series on Google's dependency injection (DI) framework Guice. The first part showed how to get started with Guice in 15 minutes, while the second installment explained Guice's concept of method interception.

Today I want to show how to integrate Guice with EJB. One might ask, whether that makes sense at all, as EJB 3 provides a DI container and an interceptor framework itself. But these services are only available for beans, which are managed by the container. You can't use DI and method interception for non-managed objects, and even within managed beans only certain objects (such as other session beans or JPA EntityManagers) can be injected.

But luckily Guice comes to the rescue and allows to use DI and method interception in and with arbitrary objects.

The example: Retrieving online weather information

As example for the integration of Guice and EJB in the following an application shall be built, that is able to retrieve the weather information (that is temperature and a textual description of the weather conditions) for a given location, using the freely available Yahoo! Weather RSS Feed.

We will encapsulate the access to the Yahoo! service in a dedicated client class. To allow for mocking the online requests in unit tests, we introduce an interface WeatherService that for now will be implementated by the actual Yahoo! client. The service interface just provides one method, getWeatherCondition():

1
2
3
4
5
6
@ImplementedBy(WeatherServiceYahooImpl.class)
public interface WeatherService {

    WeatherCondition getWeatherCondition(String locationCode);

}

WeatherCondition is a simple model class, that contains the weather information for one location:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package de.gmorling.guiceonejb.demo;

public class WeatherCondition {

    final String text;

    final int temperature;

    final String location;

    public WeatherCondition(String location, String text, int temperature) {
        this.location = location;
        this.text = text;
        this.temperature = temperature;
    }

    //getters and setters, equals() and hashCode() ...
}

Now let's build the implementation of the WeatherService, based on the Yahoo! feed:

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
package de.gmorling.guiceonejb.demo;

import java.io.InputStream;
import java.net.URL;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;

public class WeatherServiceYahooImpl implements WeatherService {

    private final static String address = "http://weather.yahooapis.com/forecastrss?u=c&p=";

    @Override
    public WeatherCondition getWeatherCondition(String locationCode) {

        InputStream inputStream = null;

        try {
            inputStream = new URL(address + locationCode).openStream();
            Document doc = new SAXBuilder().build(inputStream);

            Namespace namespace = 
                Namespace.getNamespace("http://xml.weather.yahoo.com/ns/rss/1.0");

            Element channelElement = doc.getRootElement().getChild("channel");
            Element locationElement = channelElement.getChild("location", namespace);
            Element conditionElement = channelElement.getChild("item").getChild("condition", namespace);

            return new WeatherCondition(
                locationElement.getAttributeValue("city") + ", " + locationElement.getAttributeValue("country"),
                conditionElement.getAttributeValue("text"),
                Integer.parseInt(conditionElement.getAttributeValue("temp")));
        } 
        catch (Exception e) {
            throw new RuntimeException(e);
        }
        finally {
            if (inputStream != null) {
                try { inputStream.close(); } catch (Exception e) {}
            }
        }
    }

}

The implementation is pretty straight-forward. First we retrieve the weather information from the Yahoo! feed by opening an InputStream to the feed URL. Using the JDOM API we then create a Document object representing the returned RSS structure. From the child elements of that document we can retrieve all the information required to create a new WeatherCondition instance.

Writing a session bean

Having implemented the weather service, let's now create a stateless session bean, that uses this service. The bean in the following example just delegates all calls to the actual service, but of course one could imagine a more complex bean with its own logic etc. First we have to create the local interface for the session bean. Thanks to EJB 3 this is just a POJI (plain old java interface) annotated with @Local:

1
2
3
4
5
6
7
8
9
10
11
12
package de.gmorling.guiceonejb.demo.ejb;

import javax.ejb.Local;

import de.gmorling.guiceonejb.demo.WeatherCondition;

@Local
public interface WeatherInformationLocal {

    WeatherCondition getWeatherCondition(String locationCode);

}

Next we create the session bean by implementing the local interface:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package de.gmorling.guiceonejb.demo.ejb;

import javax.ejb.Stateless;

import com.google.inject.Inject;

import de.gmorling.guiceonejb.UsesGuice;
import de.gmorling.guiceonejb.demo.WeatherCondition;
import de.gmorling.guiceonejb.demo.WeatherService;

@Stateless
@UsesGuice
public class WeatherInformationBean implements WeatherInformationLocal {

    @Inject
    private WeatherService weatherService;

    @Override
    public WeatherCondition getWeatherCondition(String locationCode) {
        return weatherService.getWeatherCondition(locationCode);
    }

}

To create a stateless session bean, we just annotate the class with the @Stateless annotation. Besides that, two things here are remarkable:

  • The injection of a WeatherService instance using Guice's @Inject annotation
  • The session bean being annotated with a new annotation, @UsesGuice

Bringing together Guice and EJB

How comes, that the weatherService field is obviously populated by Guice? This is realized by using an EJB interceptor (very similar to Guice's method interceptors, as described in the second installment of this series), that hooks into each call of the session bean's methods by the container and injects all fields annotated with @Inject. Let's have a look at that 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
package de.gmorling.guiceonejb;

import javax.ejb.EJB;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

import com.google.inject.Injector;

public class GuiceInterceptor {

    @EJB
    private GuiceInjectorHolder injectorHolder;

    @AroundInvoke
    public Object injectByGuice(InvocationContext ctx) throws Exception {

        if (ctx.getTarget().getClass().isAnnotationPresent(UsesGuice.class)) {

            Injector injector = injectorHolder.getInjector();
            injector.injectMembers(ctx.getTarget());
        }

        return ctx.proceed();
    }
}

By annotating the method injectByGuice() with @AroundInvoke, we specify, that the interceptor shall be called for each method invocation on the target bean by the container. Within the method, we first check, whether the target bean is annotated with @UsesGuice. If that's the case, we obtain a Guice injector and use it to perform the dependency injection on the target bean. Finally we continue with the intercepted call by invoking the proceed() method of the passed invocation context.

Having implemented the interceptor, we must register it with the EJB container and specify, for which session beans it shall be invoked. As we want to enable Guice DI in basically any session bean, we do this by using the ejb-jar.xml deployment descriptor as follows (another option would be to annotate only selected beans with @Interceptors):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
    version="3.0">

    <interceptors>
        <interceptor>
            <interceptor-class>de.gmorling.guiceonejb.GuiceInterceptor</interceptor-class>
        </interceptor>
    </interceptors>
    <assembly-descriptor>
        <interceptor-binding>
            <ejb-name>*</ejb-name>
            <interceptor-class>de.gmorling.guiceonejb.GuiceInterceptor</interceptor-class>
        </interceptor-binding>
    </assembly-descriptor>
</ejb-jar>

One question is still unanswered: where did we retrieve the Guice injector from? We got it from another session bean, called GuiceInjectorHolder (which we get injected by the EJB container, as EJB – in contrast to Guice – allows DI also within interceptors).

The reason for this is, that we want to use the same Guice injector throughout the entire application. That's required in order to support Guice's singleton scope, that allows to specify objects to be singletons – but only within the context of one and the same injector instance.

This makes the Guice injector for our purposes actually a singleton object itself. Singletons used to be rather problematic in traditional JEE applications (mostly they are realized using static fields), but the upcoming EJB version 3.1 simplifies that matter by introducing the concept of singleton beans. That's very useful for our GuiceInjectorHolder, which looks 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
//interface
package de.gmorling.guiceonejb;

import com.google.inject.Injector;

public interface GuiceInjectorHolder {

    Injector getInjector();

    void setInjector(Injector injector);

}

//implementation
package de.gmorling.guiceonejb;

import javax.ejb.Singleton;
import javax.interceptor.ExcludeDefaultInterceptors;

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

@Singleton
@ExcludeDefaultInterceptors
public class GuiceInjectorHolderBean implements GuiceInjectorHolder {

    private Injector injector = Guice.createInjector();

    @Override
    public Injector getInjector() {
        return injector;
    }

    @Override
    public void setInjector(Injector injector) {
        this.injector = injector;
    }

}

All we have to do is to annotate the bean implementation with @Singleton. This annotation is already supported by GlassFish V3 as well as by Apache OpenEJB, which we will use for unit testing purposes later on.

Annotating the bean with @ExcludeDefaultInterceptors ensures, that the GuiceInterceptor won't be applied to that bean, as there are no dependencies to be injected here. The setInjector() method allows to set the injector to be used, by default a standard injector without any configuration modules will be used.

Writing a unit test

That completes the Guice-EJB integration layer (comprising the @UsesGuice annotation, the GuiceInterceptor and the GuiceInjectorHolder bean). So it's time to give it a try in a unit test.

For unit testing our EJB application we can use the embeddable OpenEJB container. It allows to launch a fully functional EJB container within a unit test, without the need to install an application server, to perform a deployment before the test etc. 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
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
package de.gmorling.guiceonejb;

import static org.junit.Assert.*;

import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;

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

import com.google.inject.Guice;

import de.gmorling.guiceonejb.demo.WeatherCondition;
import de.gmorling.guiceonejb.demo.ejb.WeatherInformationLocal;

public class GuiceInterceptorTest {

    private InitialContext context;

    @Before
    public void setUp() throws Exception {
        Properties properties = new Properties();

        properties.setProperty(
            Context.INITIAL_CONTEXT_FACTORY,
            "org.apache.openejb.client.LocalInitialContextFactory");
        properties.setProperty(
            "openejb.deployments.classpath.include",
            ".*guiceonejb/target/classes.*");
        properties.setProperty(
            "openejb.embedded.initialcontext.close",
            "destroy");

        context = new InitialContext(properties);
    }

    @Test
    public void getWeatherInformationFromYahoo() throws Exception {

        WeatherInformationLocal bean = 
            (WeatherInformationLocal) context.lookup("WeatherInformationBeanLocal");

        assertNotNull(bean);

        WeatherCondition weatherCondition = bean.getWeatherCondition("GMXX0025");
        assertEquals("Dresden, GM", weatherCondition.getLocation());
    }

    @After
    public void tearDown() throws Exception {
        context.close();
    }
}

All we have to do is to setup an InitialContext as shown within the setUp() method. This context can be used to retrieve an instance of the WeatherInformationBean. The call to getWeatherCondition() will be intercepted by the container, the WeatherService implementation based on the Yahoo! feed will be injected by Guice and the weather information for the specified location code will be retrieved.

Creating a mock implementation

Calling external services from within a unit test is mostly not a good idea (test success is subject to the service's availability, it will make the test running longer etc.). Therefore we will create a mock implementation of the WeatherService, that can be used in the unit test:

1
2
3
4
5
6
7
8
9
10
11
12
13
package de.gmorling.guiceonejb;

import de.gmorling.guiceonejb.demo.WeatherCondition;
import de.gmorling.guiceonejb.demo.WeatherService;

public class WeatherServiceMockImpl implements WeatherService {

    public WeatherCondition getWeatherCondition(String locationCode) {

        return new WeatherCondition("Dresden", "Rainy", 5);
    }

}

To bind the WeatherService interface to the mock implementation instead of the real one, we have to write a Guice configuration module as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
package de.gmorling.guiceonejb;

import com.google.inject.AbstractModule;

import de.gmorling.guiceonejb.demo.WeatherService;

public class TestModule extends AbstractModule {

    public void configure() {

        bind(WeatherService.class).to(WeatherServiceMockImpl.class);
    }
}

That configuration module can now be used to create a new Guice injector, that we'll set into the GuiceInjectorHolder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
@Test
public void getWeatherInformationFromMock() throws Exception {

    GuiceInjectorHolder holder = 
        (GuiceInjectorHolder) context.lookup("GuiceInjectorHolderBeanLocal");

    assertNotNull(holder);
    holder.setInjector(Guice.createInjector(new TestModule()));

    WeatherInformationLocal bean = 
        (WeatherInformationLocal) context.lookup("WeatherInformationBeanLocal");

    assertNotNull(bean);

    WeatherCondition weatherCondition = bean.getWeatherCondition("GMXX0025");
    assertEquals(new WeatherCondition("Dresden", "Rainy", 5), weatherCondition);
}
...

Guice will now inject the mock WeatherService implementation into the WeatherInformationBean, which makes the test independent from the real service at Yahoo!

Summary

That concludes the third and last part of my Guice tutorial. In this installment I showed, that is rather easy to use Guice within an EJB application (and that it is very simple to retrieve weather information from Yahoo! ;-)).

Guice is a great addition to EJB as it allows dependency injection and method interception also for objects not managed by the EJB container. The complete source code of this tutorial can be downloaded here. As usually I'd be happy on any feedback and comments.

Saturday, March 7, 2009

Bookmark and Share

My recently published article "Web Services: Auf die Plätze, fertig, los!" is now available for download as PDF file (it originally appeared in edition 3/09 of the German-speaking journal Java Magazin). I'd be happy on any comments and feedback.

Sunday, March 1, 2009

Bookmark and Share

Recently I nearly went nuts as I tried to delete a flawed file download from a project of mine at Google Code. I just couldn't find out where to do it.

So if you find yourself in the same situation and just don't manage to find the "delete" link, here is what you must do:

  • Go to the "Downloads" tab and click on the description of the download to be deleted in the "Summary + Labels" column (yes, this actually is a link)
  • Find the "Delete" link right to the search input field at the top of the page

Actually pretty simple once you know it, but it took me a while till I recognized that the download description is a hyper link ...