Thursday, 13 March 2014

Redis Publish Subscribe and Long Polling with Spring's DeferredResult

As well as being key value store, Redis offers a publish subscribe messaging implementation. This post will describe a simple scenario, using Spring Data Redis, of adding a message domain object to a repository via a REST call, publishing that message to a channel, subscribers to that channel receiving that message who as a result set any long polling deferred results with the message.

The two key classes in the Redis publish subscribe mechanism are the RedisTemplate class and the RedisMessageListenerContainer class.

The RedisTemplate contains the JedisConnectionFactory which holds the Redis connection details and as well as the methods to manipulate the key value stores, there’s a publish method called convertAndSend. This method takes two arguments. The first being the channel name of where the messages need to be published to and the second being the object to be sent. 

In this example, the publishing of the message is done after the Message is persisted via an aspect.

@Aspect
@Component
public class MessageAspect extends AbstractRedisAspect {

    private static final Logger LOGGER = LoggerFactory
            .getLogger(MessageAspect.class);

    @Value("${messaging.redis.channel.messages}")
    private String channelName;

    @After("execution(* com.city81.redisPubSub.repository.MessageDao.save(..))")
    public void interceptMessage(JoinPoint joinPoint) {
            
        Message message = (Message) joinPoint.getArgs()[0];
    
        // this publishes the message
        this.redisTemplate.convertAndSend(channelName, message);

    }

}

The RedisMessageListenerContainer, as well as holding the JedisConnectionFactory, holds a map of message listeners where the key is a message listener instance and the value the channel. The message listener instance references a class which implements the onMessage method of the MessageListener interface.

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd" >

    <!-- for the redis pub sub aop beans -->
    <aop:aspectj-autoproxy />

    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
          p:host-name="${messaging.redis.hostname}" p:port="${messaging.redis.port}"/>

    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
          p:connection-factory-ref="jedisConnectionFactory">
    </bean>

    <bean id="messageListener" class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
        <constructor-arg>
            <ref bean="messageManager"/>
        </constructor-arg>
    </bean>

    <bean id="redisContainer" class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
        <property name="connectionFactory" ref="jedisConnectionFactory"/>
        <property name="messageListeners">
            <map>
                <entry key-ref="messageListener">
                    <bean class="org.springframework.data.redis.listener.ChannelTopic">
                        <constructor-arg value="${messaging.redis.channel.messages}" />
                    </bean>
                </entry>
            </map>
        </property>
    </bean>

</beans>

When a message is published, those subscribers who are listening to that channel will then receive the published message via the onMessage method. The published message contains the serialised object that was sent in the body of the Redis Message and needs to be deserialised and cast to the original object.

    public void onMessage(
            org.springframework.data.redis.connection.Message redisMessage,
            byte[] pattern) {

        Message message = (Message) SerializationUtils.deserialize(redisMessage.getBody());
        
        // set the deferred results for the user
        for (DeferredResult<Message> deferredResult : this.messageDeferredResultList) {
                deferredResult.setResult(message);
        }

    }

The DeferredResult list is populated by calls to the REST service's getNewMessage method. This will in turn, in the MessageManager, create a DeferredResult object, add it to the list and return the object to the client.


    public DeferredResult<Message> getNewMessage() throws Exception {

        final DeferredResult<Message> deferredResult =
                new DeferredResult<Message>(deferredResultTimeout);

        deferredResult.onCompletion(new Runnable() {
            public void run() {
                messageDeferredResultList.remove(deferredResult);
            }
        });

        deferredResult.onTimeout(new Runnable() {
            public void run() {
                messageDeferredResultList.remove(deferredResult);
            }
        });

        messageDeferredResultList.add(deferredResult);

        return deferredResult;
    }


The GitHub repo for this example contains two simple HTML pages, one which starts a long poll request and another which adds a message. These will call the below REST web service.

@Controller
@RequestMapping("/messages")
public class MessageAPIController {

    @Inject
    private MessageManager messageManager;

    //
    // ADD A MESSAGE
    //
    @RequestMapping(value = "/add", method = RequestMethod.POST,
            produces = "application/json")
    @ResponseBody
    public Message addMessage(
            @RequestParam(required = true) String text) throws Exception {
        return messageManager.addMessage(text);
    }
    
    //
    // LONG POLLING
    //
    @RequestMapping(value = "/watch", method = RequestMethod.GET,
            produces = "application/json")
    @ResponseBody
    public DeferredResult<Message> getNewMessage() throws Exception {
        return messageManager.getNewMessage();
    }
    
    
}


A further enhancement to the above to ensure messages aren't missed in between long polling requests would be to store the messages in Redis in a sorted set with the score being the message's creation timestamp. The Redis publish mechanism could then be used to tell the subscriber that there are new messages in Redis and it could then retrieve them based on the time of the last request, and return a collection of messages back to the client in the DeferredResult object.






Friday, 6 December 2013

Spring and Caching JMS Connections

As follow up to previous posts covering JMS, this post will delve into more depth on Spring's CachingConnectionFactory.

Spring provides two implementations of the javax.jms.ConnectionFactory interface, namely, the SingleConnectionFactory and the CachingConnectionFactory. The SingleConnectionFactory returns as you might expect the same single connection upon all calls to the createConnection() method. This is fine for certain scenarios and applications but the CachingConnectionFactory provides a more performant and scalable solution.

By default, a single session is cached so for a multi threaded application you would set the sessionCacheSize to be a more suitable number although this number wouldn't reflect the true number of sessions cached as this figure refers to the size of cache per session acknowledgement type eg AUTO_ACKNOWLEDGE, CLIENT_ACKNOWLEDGE, DUPS_OK_ACKNOWLEDGE and SESSION_TRANSACTED.

By default, the CachingConnectionFactory will cache the Message Producers and Message Consumers for every session. As an aside the Message Consumers are cached using keys which include the JMS selector so the more fine grained the message filter the more Message Consumers there would be, and Message Consumers aren't closed until the session is closed and removed from the pool. An alternative is to use a Listener Container for consuming messages.

Also to be noted is that on creating a CachingConnectionFactory instance, the reconnect on exception flag is set to be true. This should mean that the onException method on the default ExceptionListener class gets called which will reset the connections. You can also override the default exception listener with your own implementation.

The below snippet of XML shows a simple configuration of a CachingConnectionFactory:

<bean id="jmsQueueConnectionFactory"
    class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
    <property name="targetConnectionFactory" ref="mqConnectionFactory" />
    <property name="username" value="${mq.username}" />
</bean>

<bean id="jmsConnectionFactory" 
    class="org.springframework.jms.connection.CachingConnectionFactory">
    <property name="targetConnectionFactory" ref="jmsQueueConnectionFactory" />
    <property name="sessionCacheSize" value="50" />
    <property name="exceptionListener" ref="jmsExceptionListener" />
</bean>

<bean id="jmsExceptionListener"
    class="com.city81.messaging.MessageMQExceptionListener"">
    <property name="cachingConnectionFactory" ref="jmsConnectionFactory" /">
</bean>

Monday, 3 June 2013

Exposing and Managing Links with Spring HATEOAS

As a follow up to the previous Spring HATEOAS post, this post will cover how to use the @ExposesResourceFor annotation as an alternative to using the resource's Controller to obtain links.

It'll also cover how to find links based on a particular relation type in a hypermedia enabled representation.

In addition to the classes in the previous post, the SettlementController class is responsible for settling bets and exposes one method, settleBet, in order to do this. To return a link to the settled bet, the SettlementController uses the linkTo method on the ControllerLinkBuilder class:

@RequestMapping(method = RequestMethod.PUT, value = "/{betId}")
ResponseEntity<SettlementResource> settleBet(@PathVariable Long betId) {

    Settlement settlement = this.settlementService.settleBet(betId);  
    SettlementResource resource = 
        settlementResourceAssembler.toResource(settlement);
    resource.add(
        linkTo(BetController.class).slash(betId).withSelfRel());
    return new ResponseEntity<SettlementResource>(resource, HttpStatus.CREATED);
}  

An alternative approach to this is to enable EntityLinks. By adding the @ExposesResourcesFor annotation to the BetController, the SettlementController need only know about the resource and not it's Controller class.

@Controller
@ExposesResourceFor(Bet.class)
@RequestMapping("/bets")
public class BetController {
...
}

The SettlementController by way of the EntityLinks interface can now obtain the link to a single resource or a link to a resource collection. It can either get the Link or a LinkBuilder. With the latter approach, the relation types can be overwritten:


@Controller
@RequestMapping("/settlements")
public class SettlementController {

    private SettlementService settlementService;
    private SettlementResourceAssembler settlementResourceAssembler;
    private EntityLinks entityLinks;

    @Autowired
    public SettlementController(SettlementService settlementService,
        SettlementResourceAssembler settlementResourceAssembler, EntityLinks entityLinks) {
        this.settlementService = settlementService;
        this.settlementResourceAssembler = settlementResourceAssembler;
        this.entityLinks = entityLinks;
    }

    @RequestMapping(method = RequestMethod.PUT, value = "/{betId}")
    ResponseEntity<SettlementResource> settleBet(@PathVariable Long betId) {

        Settlement settlement = this.settlementService.settleBet(betId);
        SettlementResource resource = 
            settlementResourceAssembler.toResource(settlement);
        resource.add(this.entityLinks.linkToSingleResource(Bet.class, betId));
        return new ResponseEntity<SettlementResource>(
            resource, HttpStatus.CREATED);
    } 
 
}

For a collection link, the call would be:

resource.add(this.entityLinks.linkToCollectionResource(Bet.class)); 

To obtain the builders:

LinkBuilder linkFor = this.entityLinks.linkFor(Bet.class);
LinkBuilder linkForSingleResource = 
    this.entityLinks.linkForSingleResource(Bet.class, betId);

To enable all this functionality, the @EnableEntityLinks annotation must be in your Spring configuration.

Another useful feature that comes with Spring HATEOAS, is the ability to discover links. For a given hypermedia enabled representation, the Link Discoverer API can find a link or links for a particular relation type. For example, from the previous post, to find the cancelBet relation type link of a ResourceSupport object would be:

LinkDiscoverer discoverer = new DefaultLinkDiscoverer();
Link link = discoverer.findLinkWithRel("cancelBet", resource.toString());

The DefaultLinkDiscoverer will expect JSON but since 0.5 of Spring HATEOAS, the HAL variant has been supported via the HalLinkDiscoverer class.

Although still evolving, the Spring HATEOAS project provides a good foundation for implementing a HATEOAS compliant REST service. But if all you require is to expose and manage domain objects via a REST web service then the Spring Data REST project which applies the HATEOAS constraint to persisted entities is worth considering and the Restbucks example an ideal tutorial.


Thursday, 9 May 2013

Spring MVC and the HATEOAS constraint

HATEOAS is a REST architecture principle where hypermedia is used to change application state. To change state, the returned resource representation contains links thereby 'constraining' the client on what steps to take next.

The Spring-HATEOAS project aims to assist those writing Spring MVC code in the creation of such links and the assembly of resources returned to the clients.

The example below will cover a simple scenario showing how links are created and returned for the resource, Bet. Each operation on the resource is described below:

  • createBet - this POST operation will create a Bet.
  • updateBet - this PUT operation will update the Bet.
  • getBet - this GET operation will retrieve a Bet.
  • cancelBet - this DELETE operation will cancel the Bet.

@Controller
@RequestMapping("/bets")
public class BetController {

 private BetService betService;
 private BetResourceAssembler betResourceAssembler;

 public BetController(BetService betService,
   BetResourceAssembler betResourceAssembler) {
  this.betService = betService;
  this.betResourceAssembler = betResourceAssembler;
 }

 @RequestMapping(method = RequestMethod.POST)
 ResponseEntity<BetResource> createBet(@RequestBody Bet body) {
  Bet bet = betService.createBet(body.getMarketId(),
    body.getSelectionId(), body.getPrice(), body.getStake(),
    body.getType());
  BetResource resource = betResourceAssembler.toResource(bet);
  return new ResponseEntity<BetResource>(resource, HttpStatus.CREATED);
 }

 @RequestMapping(method = RequestMethod.PUT, value = "/{betId}")
 ResponseEntity<BetResource> updateBet(@PathVariable Long betId,
   @RequestBody Bet body) throws BetNotFoundException, BetNotUnmatchedException {
  Bet bet = betService.updateBet(betId, body);
  BetResource resource = betResourceAssembler.toResource(bet);
  return new ResponseEntity<BetResource>(resource, HttpStatus.OK);
 }

 @RequestMapping(method = RequestMethod.GET, value = "/{betId}")
 ResponseEntity<BetResource> getBet(@PathVariable Long betId) throws BetNotFoundException {
  Bet bet = betService.getBet(betId);
  BetResource resource = betResourceAssembler.toResource(bet);
  if (bet.getStatus() == BetStatus.UNMATCHED) {
   resource.add(linkTo(BetController.class).slash(bet.getId()).withRel("cancel"));
  }
  return new ResponseEntity<BetResource>(resource, HttpStatus.OK);
 }

 @RequestMapping(method = RequestMethod.GET)
 ResponseEntity<List<BetResource>> getBets() {
  List<Bet> betList = betService.getAllBets();
  List<BetResource> resourceList = betResourceAssembler.toResources(betList);
  return new ResponseEntity<List<BetResource>>(resourceList, HttpStatus.OK);
 }

 @RequestMapping(method = RequestMethod.DELETE, value = "/{betId}")
 ResponseEntity<BetResource> cancelBet(@PathVariable Long betId) {
  Bet bet = betService.cancelBet(betId);
  BetResource resource = betResourceAssembler.toResource(bet);
  return new ResponseEntity<BetResource>(resource, HttpStatus.OK);
 }

 @ExceptionHandler
 ResponseEntity handleExceptions(Exception ex) {
  ResponseEntity responseEntity = null;
  if (ex instanceof BetNotFoundException) {
   responseEntity = new ResponseEntity(HttpStatus.NOT_FOUND);
  } else if (ex instanceof BetNotUnmatchedException) {
   responseEntity = new ResponseEntity(HttpStatus.CONFLICT);
  } else {
   responseEntity = new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
  }
  return responseEntity;
 }
 
}

 
All the operations will create a BetResource for returning to the client. This is done by calling toResource on the BetResourceAssembler class:

public class BetResourceAssembler extends ResourceAssemblerSupport<Bet, BetResource> {

 public BetResourceAssembler() {
  super(BetController.class, BetResource.class);
 }

 public BetResource toResource(Bet bet) {
  BetResource resource = instantiateResource(bet);
  resource.bet = bet;
        resource.add(linkTo(BetController.class).slash(bet.getId()).withSelfRel());
  return resource;
 }

}


This class extends ResourceAssemblerSupport which requires the implementation of a toResource method as it implements the ResourceAssembler interface. This is where the mapping between Bet and BetResource is done. In this case, BetResource is just a wrapper for Bet so it is simply a case of setting the bet attribute. The instantiateResource method will return a BetResource without any links so links can be added at this point if required. In this example a link to self is added. An alternative approach would be to use createResourceWithId which will return a BetResource with the self link. 
 
public class BetResource extends ResourceSupport {
 
 public Bet bet;
 
}

 
Also in this example, links are added to the BetResource within the BetController class to ensure the application of the HATEOAS constraint. If the REST service receives a GET request then a check is made on the status of the Bet. If the Bet is UNMATCHED, then a link to cancel the Bet can be added to the BetResource. This is done in similar fashion to the self link but with the relationship attribute name of cancel.
 
An alternative approach to this is to build a link to a method as opposed to constructing a URI. 
 
resource.add(linkTo(methodOn(BetController.class).cancelBet(betId))
.withRel("cancel")); 
 
The methodOn would create a proxy of the BetController class and as a result the return type of the cancelBet method would have to be capable of proxying. Therefore in this example the return type of cancelBet method would be HttpEntity<Bet> and not ResponseEntity<Bet>. If the latter, then the likely exception from the server would be:
 
[org.springframework.http.ResponseEntitycom.city81.hateoas.rest.BetResource> com.city81.hateoas.controller.BetController.getBet(java.lang.Long) throws com.city81.hateoas.BetNotFoundException]:org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class org.springframework.http.ResponseEntity]: common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
 
Back to the GET request, and the returned JSON for requesting a Bet resource which has a status of UNMATCHED is shown below:

{
 "links":[
     {"rel":"self","href":http://localhost:8080/hateoas-1-SNAPSHOT/bets/0},
     {"rel":"cancel","href":http://localhost:8080/hateoas-1-SNAPSHOT/bets/0}
],
 "bet":{"id":0,"marketId":1,"selectionId":22,"price":4.0,"stake":2.0,"type":"BACK","status":"UNMATCHED"}
}

The client can therefore use the self link for retrieving and updating the Bet, and also the cancel link to effectively delete it.

This post describes just some of the functionality of the Spring-HATEOAS project which is evolving all the time. For an up to date and more detailed explanation, visit the GitHub pages.
 
 
 
 

Thursday, 4 April 2013

Mocking Static Methods in Groovy

Using Groovy to test not only other Groovy classes but also Java classes is an increasing popular approach given frameworks like Spock which facilitate Test Driven and Behaviour Driven Development.

A common problem when testing though is having to deal with legacy code and more often than not having to mock static methods calls. When writing tests in Groovy, the approach to mocking static calls will depend on the type of class you're testing and what type of class has the static method in.

If the Groovy class you're testing makes calls a static method on another Groovy class, then you could use the ExpandoMetaClass which allows you to dynamically add methods, constructors, properties and static methods. The below Account Groovy class has a static method called getType(). The Customer Groovy class you're trying to test calls the getType() static method within it's getAccountType() method:


class Customer {

 String getAccountType() {
  return Account.getType();
 }
 
}

class Account {

 static String getType() {
  return "Personal";
 }

}

class CustomerTest extends GroovyTestCase {
 
 void testGetAccountType() {
  
  Customer cust = new Customer()
  assert cust.getAccountType() == "Personal"

  Account.metaClass.static.getType = {return "Business"}
  
  assert cust.getAccountType() == "Business"
    
 }

}

The CustomerTest Groovy class shows how the getType static method can be overridden using the metaClass property. This isn't strictly mocking, more dynamically changing a class. An alternative approach is to use Spock's GroovyMock to achieve a similar result. (A more detailed description of Spock's mocking and stubbing features can be found here:)


import spock.lang.*

class CustomerTest extends Specification {
 
 def "get account type"() {
   
  setup: 
   GroovyMock(Account, global: true)
   Account.getType() >> "Business"
   Customer cust = new Customer()
  
  when: "obtaining a customer's account type"
   def type = cust.getAccountType()

  then: "the type will be a Business account"
   type == "Business"
    
 }

}

If the Account class is a Java not Groovy class then we can still mock it out using the above methods. The problem with mocking Java static methods though, when using Groovy for testing, is when they are called from Java classes and these calling classes are the ones you are trying to test.

For example, if we now have a Customer Java class and also an Account Java class, and a CustomerTest Groovy class, the ExpandoMetaClass and GroovyMock approaches will not work globally but will work locally. The below CustomerTest will pass.


public class Customer {

 public String getAccountType() {
  return Account.getType();
 }
 
}

public class Account {

 public static String getType() {
  return "Personal";
 }

}
class CustomerTest extends GroovyTestCase {
 
 void testGetAccountType() {
  
  Customer cust = new Customer()
  assert cust.getAccountType() == "Personal"

  Account.metaClass.static.getType = {return "Business"}
  
  assert Account.getType() == "Business"
  assert cust.getAccountType() == "Personal"
    
 }

}

The way around this is to use a mocking framework like Powermock or JMockit. The below amended CustomerTest Groovy class shows how Powermock can be integrated into a GroovyTestCase:


import groovy.mock.interceptor.*
import org.powermock.api.mockito.PowerMockito;
import static org.mockito.Mockito.*;
import org.powermock.core.classloader.annotations.PrepareForTest
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner

@RunWith( PowerMockRunner.class )
@PrepareForTest(Account.class)
class CustomerTest extends GroovyTestCase {
 
 public void testGetAccountType() { 
  
  Customer cust = new Customer()
  assert cust.getAccountType() == "Personal"

  PowerMockito.mockStatic(Account.class);
  when(Account.getType()).thenReturn("Business");
    
  assert cust.getAccountType() == "Business"
 
 }

}
Using Mockito's when to mock the return value of the static getType() call enables "Business" to be returned instead of "Personal". This example shows how when writing Groovy tests to test Java classes, using a framework like Powermock can fill the void of mocking Java static methods when called from the Java classes you are trying to test.

Wednesday, 27 February 2013

JSON, POJOs and Groovy's HTTPBuilder class


Whilst previous posts have looked at the use of RESTClient, this post will concentrate on its parent class, HTTPBuilder and also touch briefly on the JSONBuilder class. This post will cover the building and parsing of JSON, converting JSON to and from POJOs, adding authentication headers and handling response success and failures.

The HTTPBuilder class provides an API to make HTTP requests and parse the responses, and builds upon the Apache AbstractHttpClient class. The HTTPBuilder class can be instantiated with a URI to be used as default for all request methods. A default content type can also be supplied but for this example it will be the instantiated default of ContentType.ANY.

The below method takes an AccountFilter POJO, creates a JSONBuilder object and instantiates a HTTPBuilder with the default URI. It then makes a request specifying the method (POST) and contentType (JSON). The request body will be converted to a url-encoded form string. The code also shows how headers can be set, in this case, X-Application and X-Authentication using instance variables.


NOTE: The request is retrieving data and not creating or updating data, so would normally be a GET but the criteria can be complex and nested and therefore needs to be sent as JSON in the request body, hence the use of POST. (There is whole discussion on the web about GET requests containing a request body.) 


Set<Customer> listCustomers(AccountFilter accountFilter) {

    def resultList = new ArrayList<Customer>()
    def builder = new JsonBuilder(accountFilter)
    def http = new HTTPBuilder( 'https://beta-api.city81.com/json-rpc' )

 
    // POST request
    http.request (POST, JSON){req->
        body = [
            "jsonrpc" : "2.0",
            "method" : "Bank/v1.0/listCustomers",
            "params" : builder.toString(),
            "id" : 1
        ]

        headers.'X-Application' = this.applicationKey
        headers.'X-Authentication' = this.sessionToken

        // success response handler 
        response.success = { resp, json ->
            json.result.each { 
                resultList.add(new Customer(
                    it.customer.id, it.customer.name))
            }
        }

        // failure response handler 
        response.failure = { resp ->
            println "Unexpected error: ${resp.statusLine.statusCode}"
            println ${resp.statusLine.reasonPhrase}
        }
    }

    return resultList
}

The success response handler will iterate over the JSON result set and create Customer objects adding them to a collection. The failure response handler will print out the status code and reason phrase for the failure of the POST request.

As mentioned above, the code uses JSONBuilder to turn the POJO into JSON. For a Filter POJO with the field accountIds set, the JSON would appear as below:


"params":{"filter":{"accountIds":[1]}}

There is a flaw with this though in that if the filter attribute of MarketFilter is not set then the Filter tag will not be present in the JSON. If the service you are POSTing to requires this as its mandatory (albeit empty) then the req body params line would be:

"params" : [filter:[:]],

which would generate JSON:

"param": {"filter": {} }

This post covers only a small part of HTTPBuilder and one of a number of ways of POSTing a request, generating the JSON and parsing its response, many of which have been simplified with the RESTClient class.

The POJOS used in the above example:

public class Customer {

    private String id;
    private String name;

    public Customer(String id, String name) {
        this.id = id;
        this.name = name;
    }
   
    // ... getters and setters
 }


 public class AccountFilter {

    private Filter filter;
  

    public AccountFilter(Filter filter) {
        this.filter = filter;
    }
   
    // ... getters and setters
 }


public class Filter {
  

    private Set<String> accountIds;

    // ... getters and setters
}

Monday, 26 November 2012

Groovy's RESTClient with Spock Extensions

Groovy has an extension to its HTTPBuilder class called RESTClient which makes it fairly easy to test a RESTful web service. This post will describe how to use the RESTClient, how to inject it into a Groovy Spock test class via custom annotations, how to swap the injected client between a real one and a mocked one using Mockito, and how to test it.

The RESTClient class provides methods to perform the HTTP's GET, POST, PUT and DELETE methods. The RESTClient instance can be constructed with a url string and optionally a content type. The HTTP methods can then be called with a named parameter list. For example, the below code will create a RESTClient instance and call the get method passing in the path and a path parameter:

def client = new RESTClient("http://localhost:8080/testWebService/")
def resp = client.get(path : "server/status/ServerOne")

The response returned is an instance of HttpResponseDecorator. This wraps the HttpResponse to allow for easy access to the data which is parsed depending upon the content type. The below class shows it's use within a Spock framework test and how the parsed data can be extracted from the response object. The returned XML is:

<serverstatus>
  <servername>ServerOne</servername>
  <isrunning>true</isrunning>
</serverstatus>

then

<serverstatus>
  <servername>ServerTwo</servername>
  <isrunning>false</isrunning>
</serverstatus>


import groovy.util.slurpersupport.GPathResult
import groovyx.net.http.RESTClient
import spock.lang.*
import groovyx.net.http.ContentType

class InjectedRestServiceTest extends Specification {
 
 @RESTWebClient
 def client
   
 def "Test Server Statuses"() {

  when: "retrieve server status"
  def resp1 = client.get(path : "server/status/ServerOne")
  def resp2 = client.get(path : "server/status/ServerTwo")
  
  then: "test server one response"
  assert resp1.data.serverName.text() == "ServerOne"
  assert resp1.data.isRunning.text() == "true"
  
  then: "test server two response"
  assert resp2.data.serverName.text() == "ServerTwo"
  assert resp2.data.isRunning.text() == "false"
  
 }
 
}

The test asserts are purely there in this example to prove that the response from the real web service are the same as from the mocked web service. In reality, you would be testing some other functionality of which calling a RESTful web service is part of the flow. You wouldn't really assert the response from a mocked RESTClient although you may want to verify that it has been called n times.

The InjectedRestServiceTest class has the RESTClient injected using the custom made annotation @RESTWebClient. There are three classes involved which enable this functionality. First the interface, which is marked as only visible at field level, contains an @ExtensionAnnotation specifying the class which basically tells Spock what to do when it encounters the @RESTClient annotation:

import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
import org.spockframework.runtime.extension.ExtensionAnnotation

@Retention(RetentionPolicy.RUNTIME)
@Target([ ElementType.FIELD ])
@ExtensionAnnotation(RESTWebClientAnnotationDrivenExtension)

public @interface RESTWebClient{}
The RESTWebClientAnnotationDrivenExtension class in this example only needs to override the visitFieldAnnotation method of the AbstractAnnotationDrivenExtension class because of the annotation's target element type:

import org.spockframework.runtime.extension.AbstractAnnotationDrivenExtension
import org.spockframework.runtime.extension.AbstractMethodInterceptor
import org.spockframework.runtime.extension.IMethodInvocation
import org.spockframework.runtime.model.FieldInfo
import org.spockframework.runtime.model.SpecInfo

class RESTWebClientAnnotationDrivenExtension extends 
 AbstractAnnotationDrivenExtension<RESTWebClient> {

 private static final String url = 
  System.getProperties().getProperty("url")
 private static final boolean useMock = 
  Boolean.parseBoolean(System.getProperties().getProperty("useMock"))
 
 @Override
 void visitFieldAnnotation(RESTWebClient annotation, FieldInfo field) {
  def methodInterceptor = new RESTWebClientMethodInterceptor(field, url, useMock)
  methodInterceptor.install(field.parent)
 }
 
}

The above extension tells Spock that when it encounters @RESTClient, it must create an interceptor with the arguments denoting the field to which the RESTClient instance is to be set, the url of the web service and a boolean to specify if the mock is to be used or the real web service should be used. (The meaning of the two values could be combined to just have a url and if set then the real web service must be used.)

The interceptor will create either a mock RESTClient or a real one. It will do this when the client field needs to be set in the InjectedRestServiceTest class. If the real RESTClient is required then an instance using the url will be created and set using the fieldInfo.writeValue method. If a mock is required then a Mockito mock RESTClient is created and the expected behaviour mocked using instances of the class HttpResponseDecorator (although these could be mocks too.) Again, this is set using the fieldInfo.writeValue method. The mocking code should probably be in its own method or even class but for this simple example its within the setupRESTClient method:

import groovy.mock.interceptor.MockFor
import groovyx.net.http.HttpResponseDecorator
import groovyx.net.http.RESTClient
import org.spockframework.runtime.extension.AbstractMethodInterceptor;
import org.spockframework.runtime.extension.IMethodInvocation;
import org.spockframework.runtime.model.FieldInfo;
import org.spockframework.runtime.model.SpecInfo;

import static org.mockito.Mockito.*
import static org.mockito.Matchers.*

class RESTWebClientMethodInterceptor extends AbstractMethodInterceptor {

 private final FieldInfo fieldInfo
 private final String url
 private final boolean useMock

 RESTWebClientMethodInterceptor(FieldInfo fieldInfo, String url, boolean useMock) {
  this.fieldInfo = fieldInfo
  this.url = url
  this.useMock = useMock
 }

 @Override
 void interceptSetupMethod(IMethodInvocation methodInvocation) {
  setupRESTClient(methodInvocation.target)
  methodInvocation.proceed()
 }

 @Override
 void install(SpecInfo specInfo) {
  specInfo.setupMethod.addInterceptor this
 }

 private void setupRESTClient(target) {

  if (useMock) {

   def xmlServerOne =
     """
      <serverStatus>
        <serverName>ServerOne</serverName>
        <isRunning>true</isRunning>
      </serverStatus>
      """

   def xmlServerTwo =
     """
      <serverStatus>
        <serverName>ServerTwo</serverName>
        <isRunning>false</isRunning>
      </serverStatus>
      """

   def httpResponseDecoratorServerOne = new HttpResponseDecorator(
     null, new XmlParser().parseText(xmlServerOne))
   def httpResponseDecoratorServerTwo = new HttpResponseDecorator(
     null, new XmlParser().parseText(xmlServerTwo))
   def mapServerOne = [path:"server/status/ServerOne"]
   def mapServerTwo = [path:"server/status/ServerTwo"]

   RESTClient mockRESTClient = org.mockito.Mockito.mock(RESTClient)
   when(mockRESTClient.get(mapServerOne)).thenReturn(httpResponseDecoratorServerOne);
   when(mockRESTClient.get(mapServerTwo)).thenReturn(httpResponseDecoratorServerTwo);

   fieldInfo.writeValue(target, mockRESTClient)
  }
  else {
   fieldInfo.writeValue(target, new RESTClient(url))
  }
 }
 
}

Whilst there are different ways to mock and test RESTful web services, the above classes do show how easily RESTful web services can be called and their responses parsed, how annotations can be created and how objects can be mocked. Similar examples could be constructed for different aspects of a Spock test eg features, fixtures etc..

More can be found on extensions at http://code.google.com/p/spock/wiki/SpockBasics#Extensions and on RESTClient at http://groovy.codehaus.org/modules/http-builder/doc/rest.html

Friday, 14 September 2012

Using Spock to test Spring classes

As the previous post mentioned, Spock is a powerful DSL built on Groovy ideal for TDD and BDD testing and this post will describe how easy it is to use Spock to test Spring classes, in this case the CustomerService class from the post Using Spring Data to access MongoDB. It will also cover using Spock for mocking.

Spock relies heavily on the Spring's TestContext framework and does this via the @ContextConfiguration annotation. This allows the test specification class to load an application context from one or more locations.

This will then allow the test specification to access beans either via the annotation @Autowired or @Resource. The test below shows how an injected CusotmerService instance can be tested using Spock and the Spring TestContext: (This is a slightly contrived example as to properly unit test the CustomerService class as you would create a CustomerService class in the test as opposed to one created and injected by Spring.)

package com.city81.mongodb.springdata.dao

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.ContextConfiguration

import spock.lang.*

import com.city81.mongodb.springdata.entity.Account
import com.city81.mongodb.springdata.entity.Address
import com.city81.mongodb.springdata.entity.Customer

@ContextConfiguration(locations = "classpath:spring/applicationContext.xml")
class CustomerServiceTest extends Specification {

 @Autowired
 CustomerService customerService
 
 
 def setup() {
  customerService.dropCustomerCollection()
 } 
 
 def "insert customer"() {
  
  setup:
  
  // setup test class args
  Address address = new Address()
  address.setNumber("81")
  address.setStreet("Mongo Street")
  address.setTown("City")
  address.setPostcode("CT81 1DB")
 
  Account account = new Account()
  account.setAccountName("Personal Account")
  List<Account> accounts = new ArrayList<Account>()
  accounts.add(account)
  
  Customer customer = new Customer()
  customer.setAddress(address)
  customer.setName("Mr Bank Customer")
  customer.setAccounts(accounts)

  when:
  customerService.insertCustomer(customer)
  
  then:
  def customers = customerService.findAllCustomers()
  customers.size == 1
  customers.get(0).name == "Mr Bank Customer"
  customers.get(0).address.street == "Mongo Street"
  
 } 
}

The problem though with the above test is that MongoDB needs to be up and running so to remove this dependency we can Mock out the interaction the database. Spock's mocking framework provides many of the features you'd find in similar frameworks like Mockito.

The enhanced CustomerServiceTest mocks the CustomerRepository and sets the mocked object on the CustomerService.

package com.city81.mongodb.springdata.dao

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.ContextConfiguration

import spock.lang.*

import com.city81.mongodb.springdata.entity.Account
import com.city81.mongodb.springdata.entity.Address
import com.city81.mongodb.springdata.entity.Customer

@ContextConfiguration(locations = "classpath:spring/applicationContext.xml")
class CustomerServiceTest extends Specification {

 @Autowired
 CustomerService customerService
 
 CustomerRepository customerRepository = Mock()
 
 def setup() {
  customerService.customerRepository = customerRepository
  customerService.dropCustomerCollection()
 } 
 
 def "insert customer"() {
  
  setup:
    
  // setup test class args
  Address address = new Address()
  address.setNumber("81")
  address.setStreet("Mongo Street")
  address.setTown("City")
  address.setPostcode("CT81 1DB")
 
  Account account = new Account()
  account.setAccountName("Personal Account")
  List<Account> accounts = new ArrayList<Account>()
  accounts.add(account)
  
  Customer customer = new Customer()
  customer.setAddress(address)
  customer.setName("Mr Bank Customer")
  customer.setAccounts(accounts)
  
  when:
  customerService.insertCustomer(customer)
  
  then:
  1 * customerRepository.save(customer)
  
 } 
 
 def "find all customers"() {
 
  setup:
  
  // setup test class args
  Address address = new Address()
  address.setStreet("Mongo Street")
  
  Customer customer = new Customer()
  customer.setAddress(address)
  customer.setName("Mr Bank Customer")
  
  // setup mocking  
  def mockCustomers = []
  mockCustomers << customer
  customerRepository.findAll() >> mockCustomers
  
  when:
  def customers = customerService.findAllCustomers()
  
  then:
  customers.size() == 1  
  customers.get(0).name == "Mr Bank Customer"
  
 }
 
}


The CustomerRepository is by way of name and type although it could be inferred by just the name eg

def customerRepository = Mock(CustomerRepository)

The injected customerRepository is overwritten by the mocked instance and then in the test setup, functionality can be mocked.

In the then block of the insert customer feature, the number of interactions with the save method of customerRepository is tested and in the find all customers feature, the return list of customers from the findAll call is a mocked List,as opposed to one retrieved from the database.

More detail on Spock's mocking capabilities can be found on the project's home page.


Tuesday, 11 September 2012

Testing Java using the Spock Framework

The testing framework Spock is a powerful DSL built on Groovy which enables easily writable and extremely readable tests which lends itself well to software development processes like TDD and BDD.

As an example of how much clarity Spock and Groovy bring to testing I'll compare it with the tests for the ForkJoinPool example class InterpolationService.

Every Spock test (or specification) extends spock.lang.Specification. This abstract class uses Spock's JUnit runner, org.spockframework.runtime.Sputnik, and contains useful methods for writing tests eg creating mock objects

There are four main aspects to a specification: Fields, Fixtures, Features and Helpers. There is no point going into depth on each as there are well documented on the Spock Basics wiki but we'll certainly concentrate on Features with respect to the comparison with the JUnit InterpolationService tests.

Features are instance methods which must contain at least one block where a block is one of six methods: setup, when, then, expect, cleanup and where. The blocks setup and cleanup are as you might expect but others are described in more detail below.

First though and the first few lines of the InterpolationServiceTest are shown below:

package com.city81.interpolation.service

import spock.lang.*

class InterpolateServiceTest extends Specification {

    @Shared def interpolateService = new InterpolateService()

The class under test ie InterpolationService is marked as being @Shared (ie all features use the same instance).  This annotation is ideal for expensive resources like a DB connection.

Next the first feature which tests the interpolation of two numbers with an even number of steps:

def "interpolate two numbers with even no. of steps"() {
            
            expect:
            interpolateService.interpolate(a, b, c) == d
            
            where:
            a   | b    | c | d
            5.0 | 25.0 | 4 | [5.0, 10.0, 15.0, 20.0, 25.0] 
            }


The equivalent JUnit assert test method would be:

@Test
 public void testInterpolateTwoValues() {
     List<Double> interpolatedList = 
         interpolateService.interpolate(5.0, 25.0, 4);

    assertEquals(5, interpolatedList.size());
    assertEquals(5.0, interpolatedList.get(0), 0);
    assertEquals(10.0, interpolatedList.get(1), 0);
    assertEquals(15.0, interpolatedList.get(2), 0);
    assertEquals(20.0, interpolatedList.get(3), 0);
    assertEquals(25.0, interpolatedList.get(4), 0);
}


The clarity in what you are testing is easy to see and it is so easy with Spock just to add another where line to test another scenario:

def "interpolate two numbers with even no. of steps"() {

            expect:
            interpolateService.interpolate(a, b, c) == d

            where:
            a   | b    | c | d
            5.0 | 25.0 | 4 | [5.0, 10.0, 15.0, 20.0, 25.0] 
            2.0 | 14.0 | 6 | [2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0] 
            }

It is also worth noting at this point that Groovy uses BigDecimal for floating number numbers but if you want to denote doubles then numbers can be appended with a d eg 5.0d, -15.0d

Whilst the above demonstrates the expect and where blocks, the below shows how to test for exceptions using when and then blocks:

def "interpolate two numbers where first arg is null"() {
       
            when:
            interpolateService.interpolate(null, 25.0, 4)

            then:
            thrown(IllegalArgumentException)
            }

An alternative approach to using thrown(IllegalArgumentException) could be to bind a variable to access the exception:

then:
            IllegalArgumentException e = thrown()
            e.cause == InterpolateService.VALUE_ARG_NOT_NULL_EXCP_TEXT

You can also use the when and then blocks to order interactions although not if the first when throws an exception.

There is much more on Spock on it's Google code pages and the above only describes a few basics but the next post will look at Mocking and also examine it's use with Spring by testing code from a previous post. Might even get the Groovy code formatting working by then too!

Friday, 13 July 2012

Using Spring Data to access MongoDB

Spring Data is the data access Spring project for integrating with data stores. This post will cover the Spring Data sub project for accessing the document store MongoDB. It follows on from the Morphia post by showing how Spring Data for MongoDB would persist and query the same POJOs.

The four domain objects are shown below:

package com.city81.mongodb.springdata.entity;

import org.springframework.data.annotation.Id;

public abstract class BaseEntity {

 @Id
 protected String id;
 private Long version;

 public BaseEntity() {
  super();
 }

 public String getId() {
  return id;
 }

 public void setId(String id) {
  this.id = id;
 }

 public Long getVersion() {
  return version;
 }

 public void setVersion(Long version) {
  this.version = version;
 }

}


package com.city81.mongodb.springdata.entity;

import java.util.List;

import org.springframework.data.mongodb.core.mapping.Document;

@Document
public class Customer extends BaseEntity {

 private String name;
 private List<Account> accounts;
 private Address address;
 
 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 } 
  
 public List<Account> getAccounts() {
  return accounts;
 }

 public void setAccounts(List<Account> accounts) {
  this.accounts = accounts;
 }

 public Address getAddress() {
  return address;
 }

 public void setAddress(Address address) {
  this.address = address;
 }
 
}

package com.city81.mongodb.springdata.entity;


public class Address {

 private String number;
 private String street;
 private String town;
 private String postcode;
 
 public String getNumber() {
  return number;
 }
 public void setNumber(String number) {
  this.number = number;
 }
 public String getStreet() {
  return street;
 }
 public void setStreet(String street) {
  this.street = street;
 }
 public String getTown() {
  return town;
 }
 public void setTown(String town) {
  this.town = town;
 }
 public String getPostcode() {
  return postcode;
 }
 public void setPostcode(String postcode) {
  this.postcode = postcode;
 }
}

package com.city81.mongodb.springdata.entity;

import org.springframework.data.mongodb.core.mapping.Document;

@Document
public class Account extends BaseEntity {

 private String accountName;
 
 public String getAccountName() {
  return accountName;
 }

 public void setAccountName(String accountName) {
  this.accountName = accountName;
 }

}

Some classes are marked with the @Document annotation. This is optional but does allow you to provide a collection name eg

@Document(collection="personalBanking")


Also in the Customer class, the Address and Accounts attributes would be stored as embedded within the document but they can be stored separately by marking the variables with @DBRef. These objects will then be eagerly loaded when the Customer record is retrieved.

Next, using XML based metadata to register a MongoDB instance and a MongoTemplate instance.

The MongoFactoryBean is used to register an instance of com.mongodb.Mongo. Using the Bean as opposed to creating an instance of Mongo itself ensures that the calling code doesn't have to handle the checked exception UnknownHostException. It also ensures database specific exceptions are translated to be Spring exceptions of the DataAccessException hierarchy.

The MongoTemplate provides the operations (via the MongoOperations interface) to interact with MongoDB documents. This thread safe class has several constructors but for this example we only need to call the one that takes an instance of Mongo and the database name.

Whilst you could call the operations on the MongoTemplate to manage the entities, there exists a MongoRepository interface which can be extended to be 'document' specific via the use of Generics. The <mongo:repositories base-package="com.city81.mongodb.springdata.dao" />   registers beans extending this interface.



<?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:mongo="http://www.springframework.org/schema/data/mongo" 
 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://www.springframework.org/schema/data/mongo 
  http://www.springframework.org/schema/data/mongo/spring-mongo.xsd">    
  
 <context:annotation-config />
  
 <context:component-scan base-package="com.city81.mongodb.springdata" />
 
 <!-- MongoFactoryBean instance --> 
 <bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
  <property name="host" value="localhost" />
 </bean>   
 
 <!-- MongoTemplate instance --> 
 <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
  <constructor-arg name="mongo" ref="mongo" />
  <constructor-arg name="databaseName" value="bank" />
 </bean> 
 
 <mongo:repositories base-package="com.city81.mongodb.springdata.dao" />
  
</beans>

The repository class in this example is the CustomerRepository. It gets wired with the MongoTemplate so provides the same (this time implicit type safe) operations but also provides the ability to add other methods. In this example, a find method has been added to demonstrate how a query can be built from the method name itself. There is no need to implement this method as Spring Data will parse the method name and determine the criteria ie findByNameAndAddressNumberAndAccountsAccountName will return documents where the customer name is equal to the first arg (name), and where the customer address number is equal to the second arg (number) and where the customer has an account which has an account name equal to the thrid arg (accountName).


package com.city81.mongodb.springdata.dao;

import java.util.List;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

import com.city81.mongodb.springdata.entity.Customer;

@Repository
public interface CustomerRepository extends MongoRepository<Customer,String> {
 
 List<Customer> findByNameAndAddressNumberAndAccountsAccountName(
   String name, String number, String accountName);
 
}


In this example, we'll add a service layer in the form of the CustomerService class, which for this simple example just wraps the repository calls. The class has the CustomerRepository wired in and this service class is then in turn called from the Example class, which performs similar logic to the Morphia Example class.

package com.city81.mongodb.springdata.dao;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.city81.mongodb.springdata.entity.Customer;

@Service
public class CustomerService {  

 @Autowired
 CustomerRepository customerRepository;
  
 public void insertCustomer(Customer customer) {    
  customerRepository.save(customer);
 }
 
 public List<Customer> findAllCustomers() {           
  return customerRepository.findAll();
 }       
 
 public void dropCustomerCollection() {        
  customerRepository.deleteAll();   
 } 
 
 public List<Customer> findSpecificCustomers(
   String name, String number, String accountName) {           
  return customerRepository.findByNameAndAddressNumberAndAccountsAccountName(
    name, number, accountName);
 } 
 
}

package com.city81.mongodb.springdata;

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

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.city81.mongodb.springdata.dao.CustomerService;
import com.city81.mongodb.springdata.entity.Account;
import com.city81.mongodb.springdata.entity.Address;
import com.city81.mongodb.springdata.entity.Customer;

public class Example {
 
 public static void main( String[] args ) {     
  
  ConfigurableApplicationContext context
   = new ClassPathXmlApplicationContext("spring/applicationContext.xml");       
  
  CustomerService customerService = context.getBean(CustomerService.class);       
  
  // delete all Customer records
  customerService.dropCustomerCollection();  
  
     Address address = new Address();
     address.setNumber("81");
     address.setStreet("Mongo Street");
     address.setTown("City");
     address.setPostcode("CT81 1DB");
    
     Account account = new Account();
     account.setAccountName("Personal Account");
     List<Account> accounts = new ArrayList<Account>();
     accounts.add(account);
     
     Customer customer = new Customer();
     customer.setAddress(address);
     customer.setName("Mr Bank Customer");
     customer.setAccounts(accounts);
          
     // insert a Customer record into the database
  customerService.insertCustomer(customer);          
     
     address = new Address();
     address.setNumber("101");
     address.setStreet("Mongo Road");
     address.setTown("Town");
     address.setPostcode("TT10 5DB");
    
     account = new Account();
     account.setAccountName("Business Account");
     accounts = new ArrayList<Account>();
     accounts.add(account);
     
     customer = new Customer();
     customer.setAddress(address);
     customer.setName("Mr Customer");
     customer.setAccounts(accounts);  

     // insert a Customer record into the database
  customerService.insertCustomer(customer);     
      
  // find all Customer records
  System.out.println("\nALL CUSTOMERS:");
  List<Customer> allCustomers = customerService.findAllCustomers();     
  for (Customer foundCustomer : allCustomers) {
   System.out.println(foundCustomer.getId() + " " + foundCustomer.getName());   
   System.out.println(foundCustomer.getAddress().getTown());   
   System.out.println(foundCustomer.getAccounts().get(0).getAccountName() + "\n");   
  }
  
  // find by customer name, address number and account name
  System.out.println("\nSPECIFIC CUSTOMERS:");  
  List<Customer> specficCustomers = customerService.findSpecificCustomers(
    "Mr Customer","101","Business Account");     
  for (Customer foundCustomer : specficCustomers) {
   System.out.println(foundCustomer.getId() + " " + foundCustomer.getName());   
   System.out.println(foundCustomer.getAddress().getTown());   
   System.out.println(foundCustomer.getAccounts().get(0).getAccountName() + "\n");   
  }
  
 } 
 
}
The output from the above would look similiar to the below:

04-Oct-2012 13:48:48 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9: startup date [Thu Oct 04 13:48:48 BST 2012]; root of context hierarchy
04-Oct-2012 13:48:48 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring/applicationContext.xml]
04-Oct-2012 13:48:48 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1c92535: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,customerService,mongo,mongoTemplate,customerRepository,org.springframework.data.repository.core.support.RepositoryInterfaceAwareBeanPostProcessor#0]; root of factory hierarchy

ALL CUSTOMERS:
506d85b115503d4c92392c79 Mr Bank Customer
City
Personal Account

506d85b115503d4c92392c7a Mr Customer
Town
Business Account


SPECIFIC CUSTOMERS:
506d85b115503d4c92392c7a Mr Customer
Town
Business Account


This is a brief overview of Spring Data from MongoDB but there are many other facets to this project including MappingConverters, Compound Indexes and MVC support. For more info http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/

Wednesday, 11 July 2012

Using Morphia to map Java objects in MongoDB

MongoDB is an open source document-oriented NoSQL database system which stores data as JSON-like documents with dynamic schemas.  As it doesn't store data in tables as is done in the usual relational database setup, it doesn't map well to the JPA way of storing data. Morphia is an open source lightweight type-safe library designed to bridge the gap between the MongoDB Java driver and domain objects. It can be an alternative to SpringData if you're not using the Spring Framework to interact with MongoDB.

This post will cover the basics of persisting and querying entities along the lines of JPA by using Morphia and a MongoDB database instance.

There are four POJOs this example will be using. First we have BaseEntity which is an abstract class containing the Id and Version fields:

package com.city81.mongodb.morphia.entity;

import org.bson.types.ObjectId;
import com.google.code.morphia.annotations.Id;
import com.google.code.morphia.annotations.Property;
import com.google.code.morphia.annotations.Version;

public abstract class BaseEntity {

    @Id
    @Property("id")
    protected ObjectId id;

    @Version 
    @Property("version")
    private Long version;

    public BaseEntity() {
        super();
    }

    public ObjectId getId() {
        return id;
    }

    public void setId(ObjectId id) {
        this.id = id;
    }

    public Long getVersion() {
        return version;
    }

    public void setVersion(Long version) {
        this.version = version;
    }

}


Whereas JPA would use @Column to rename the attribute, Morphia uses @Property. Another difference is that @Property needs to be on the variable whereas @Column can be on the variable or the get method.

The main entity we want to persist is the Customer class:

package com.city81.mongodb.morphia.entity;

import java.util.List;
import com.google.code.morphia.annotations.Embedded;
import com.google.code.morphia.annotations.Entity;

@Entity
public class Customer extends BaseEntity {

    private String name;
    private List<Account> accounts;
    @Embedded
    private Address address;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Account> getAccounts() {
        return accounts;
    }

    public void setAccounts(List<Account> accounts) {
        this.accounts = accounts;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

}


As with JPA, the POJO is annotated with @Entity. The class also shows an example of @Embedded:

The Address class is also annotated with @Embedded as shown below:

package com.city81.mongodb.morphia.entity;

import com.google.code.morphia.annotations.Embedded;

@Embedded
public class Address {

    private String number;
    private String street;
    private String town;
    private String postcode;

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getTown() {
        return town;
    }

    public void setTown(String town) {
        this.town = town;
    }

    public String getPostcode() {
        return postcode;
    }

    public void setPostcode(String postcode) {
        this.postcode = postcode;
    }

}

Finally, we have the Account class of which the customer class has a collection of:

package com.city81.mongodb.morphia.entity;

import com.google.code.morphia.annotations.Entity;

@Entity
public class Account extends BaseEntity {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

The above show only a small subset of what annotations can be applied to domain classes. More can be found at http://code.google.com/p/morphia/wiki/AllAnnotations

The Example class shown below goes through the steps involved in connecting to the MongoDB instance, populating the entities, persisting them and then retrieving them:

package com.city81.mongodb.morphia;

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import com.city81.mongodb.morphia.entity.Account;
import com.city81.mongodb.morphia.entity.Address;
import com.city81.mongodb.morphia.entity.Customer;
import com.google.code.morphia.Datastore;
import com.google.code.morphia.Key;
import com.google.code.morphia.Morphia;
import com.mongodb.Mongo;
import com.mongodb.MongoException;

/**
 * A MongoDB and Morphia Example
 *
 */
public class Example {

    public static void main( String[] args ) throws UnknownHostException, MongoException {

     String dbName = new String("bank");
     Mongo mongo = new Mongo();
     Morphia morphia = new Morphia();
     Datastore datastore = morphia.createDatastore(mongo, dbName);       

     morphia.mapPackage("com.city81.mongodb.morphia.entity");
        
     Address address = new Address();
     address.setNumber("81");
     address.setStreet("Mongo Street");
     address.setTown("City");
     address.setPostcode("CT81 1DB");  

     Account account = new Account();
     account.setName("Personal Account");

     List<Account> accounts = new ArrayList<Account>();
     accounts.add(account);  

     Customer customer = new Customer();
     customer.setAddress(address);
     customer.setName("Mr Bank Customer");
     customer.setAccounts(accounts);
    
     Key<Customer> savedCustomer = datastore.save(customer);    
     System.out.println(savedCustomer.getId());

}


Executing the first few lines will result in the creation of a Datastore. This interface will provide the ability to get, delete and save objects in the 'bank' MongoDB instance.

The mapPackage method call on the morphia object determines what objects are mapped by that instance of Morphia. In this case all those in the package supplied. Other alternatives exist to map classes, including the method map which takes a single class (this method can be chained as the returning object is the morphia object), or passing a Set of classes to the Morphia constructor.

After creating instances of the entities, they can be saved by calling save on the datastore instance and can be found using the primary key via the get method. The output from the Example class would look something like the below:

11-Jul-2012 13:20:06 com.google.code.morphia.logging.MorphiaLoggerFactory chooseLoggerFactory
INFO: LoggerImplFactory set to com.google.code.morphia.logging.jdk.JDKLoggerFactory
4ffd6f7662109325c6eea24f
Mr Bank Customer

There are many other methods on the Datastore interface and they can be found along with the other Javadocs at http://morphia.googlecode.com/svn/site/morphia/apidocs/index.html

An alternative to using the Datastore directly is to use the built in DAO support. This can be done by extending the BasicDAO class as shown below for the Customer entity:

package com.city81.mongodb.morphia.dao;

import com.city81.mongodb.morphia.entity.Customer;
import com.google.code.morphia.Morphia;
import com.google.code.morphia.dao.BasicDAO;
import com.mongodb.Mongo;

public class CustomerDAO extends BasicDAO<Customer, String> {    

    public CustomerDAO(Morphia morphia, Mongo mongo, String dbName) {        
        super(mongo, morphia, dbName);    
    }

}

To then make use of this, the Example class can be changed (and enhanced to show a query and a delete):

...

     CustomerDAO customerDAO = new CustomerDAO(morphia, mongo, dbName);
     customerDAO.save(customer);

     Query<Customer> query = datastore.createQuery(Customer.class);
     query.and(        
       query.criteria("accounts.name").equal("Personal Account"),      
       query.criteria("address.number").equal("81"),        
       query.criteria("name").contains("Bank")
     );       

     QueryResults<Customer> retrievedCustomers =  customerDAO.find(query);   

     for (Customer retrievedCustomer : retrievedCustomers) {
         System.out.println(retrievedCustomer.getName());    
         System.out.println(retrievedCustomer.getAddress().getPostcode());    
         System.out.println(retrievedCustomer.getAccounts().get(0).getName());
         customerDAO.delete(retrievedCustomer);
     }  
    
...


With the output from running the above shown below:

11-Jul-2012 13:30:46 com.google.code.morphia.logging.MorphiaLoggerFactory chooseLoggerFactory
INFO: LoggerImplFactory set to com.google.code.morphia.logging.jdk.JDKLoggerFactory
Mr Bank Customer
CT81 1DB
Personal Account

This post only covers a few brief basics of Morphia but shows how it can help bridge the gap between JPA and NoSQL.

Thursday, 3 May 2012

Using Spring @Profile with @EnableAspectJAutoProxy

A new feature introduced in Spring 3.1 is the ability to mark components as being ready for registration if one or more 'profiles' (logical groupings) have been activated. The activation of the profiles is done at runtime either through a system property (-Dspring.profiles.active=xxx) or programmatically by calling the setActiveProfiles method on the ConfigurableEnvironment interface.

A common example of using profiles is to have different datasource beans for different environments eg a local jdbc datasource for a profile of dev but a jndi datasource for a profile of prod. This post though will describe a simple example of using @Profile to switch between different aspects when in different profiles.

Also as this example will use annotations and no XML, it will briefly cover the ability to enable AspectJ auto proxying using the new annotation @EnableAspectJAutoProxy.

The below CustomerApplication class has one simple task and that is to process a Customer object. In order to do that, the CustomerService bean needs to be obtained from the context and the context in this example is an AnnotationConfigApplicationContext.

This type of context will register annotated classes with the package prefix of com.city81. Classes marked with @Profile but not dev will be ignored. (More than one profile can be specified as setActiveProfiles takes an array of Strings.)


public class CustomerApplication {

    public static void main(String[] args) {
  
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();  
        ctx.getEnvironment().setActiveProfiles("dev");  
        ctx.scan("com.city81");
        ctx.refresh(); 

        Customer address = new Customer();
        address.setId("idOne");
        address.setName("custOne");
        address.setAge(21);
        address.setAddress("addressOne");
  
        CustomerService customerService = ctx.getBean(CustomerService.class);
        customerService.processCustomer(address);    
    }
 
}

As we're using Spring configuration programmatically, the getBean method on the context is able find the CustomerService bean as we have a CustomerServiceConfig class which is annotated with @Configuration. This allows the container to generate bean definitions at runtime.

@Configuration
@EnableAspectJAutoProxy
public class CustomerServiceConfig {

    @Bean
    public CustomerService customerService() {
        return new CustomerServiceImpl();
    }

}

This is the class that also includes @EnableAspectJAutoProxy. Prior to Spring 3.1, auto proxying AspectJ could be done using  <aop:aspectj-autoproxy>  but now @Configuration classes can include the @EnableAspectJAutoProxy annotation thereby enabling support for classes annotated with @Aspect.

In this example, there are two classes marked with @Aspect. Both extend an abstract class which defines the pointcut.

public abstract class LoggingAspect {

    @Pointcut("execution(* com.city81.service.CustomerService.processCustomer(..))")
    public void processCustomer() {
    }

}


@Configuration 
@Profile("prod")  
@Aspect
public class ConciseLoggingAspect extends LoggingAspect {

    @Before("processCustomer()")
    public void logCustomerId(JoinPoint jp) {
        Customer customer = (Customer) jp.getArgs()[0];
        System.out.println("id = " + customer.getId());
    }

}


@Configuration 
@Profile("dev")  
@Aspect
public class VerboseLoggingAspect extends LoggingAspect {

    @Before("processCustomer()")
    public void logCustomerAll(JoinPoint jp) {
        Customer customer = (Customer) jp.getArgs()[0];
        System.out.println("id = " + customer.getId());
        System.out.println("name = " + customer.getName());
        System.out.println("age = " + customer.getAge());
        System.out.println("address = " + customer.getAddress());
    }

}

In this example, there are two profiles, dev and prod, and depending on the profile activated there will be a different level of (contrived) 'logging'.

Each concrete LoggingAspect class contains an @Profile annotation. This can specify one or more profiles. Therefore in the case of using  ctx.getEnvironment().setActiveProfiles("dev") only VerboseLoggingAspect will be registered.

This post shows how easy it is to create profiles and activate them programmatically although it can be done just as easily using XML config.


Wednesday, 25 April 2012

Hibernate and Multiple Bags

Certain associations an Entity can have can be deemed 'bags' by Hibernate. A bag is an unordered collection that permits duplicate elements and when persisting these collections, the order of elements cannot be guaranteed. For these reasons, bags are an efficient way of representing a collection as you can add to a bag collection without the collection having been loaded. An example of a bag would be an ArrayList.

When designing the mapping between the objects and the database ie building entities, thought must be given to the type of associations between the entities and the fetching strategy for each association.

A common problem encountered when modelling entities using Hibernate is that of multiple bags. ie when an Entity contains two or more associations which are bags that have a fetch strategy of EAGER. This could be an Entity which has two member collections like the Company class below,  or an Entity that contains collections within its object graph, for example, the Company class may contain a collection of Buildings which in turn has a collection of MeetingRooms.

(Note: BaseEntity contains Id and Version fields.)


@Entity
public class Company extends BaseEntity {

    private List<Department> departments;
    private List<String> shareholders;

    @OneToMany(fetch=FetchType.EAGER)
    @Cascade(value ={CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
    @JoinColumn(name="CO_ID") 
    public List<Department> getDepartments() {  
        return this.departments; 
    }

    public void setDepartments(List<Department> departments) {      
        this.departments = departments; 
    }  

    @CollectionOfElements(fetch=FetchType.EAGER,targetElement=java.lang.String.class) 
    @JoinTable(name="CO_SHR",joinColumns=@JoinColumn(name="CO_ID")) 
    @Column(name="CO_SHR") 
    public List<String> getShareholders() {  
        return this.shareholders; 
    }

    public void setShareholders(List<String> shareholders) {  
        this.shareholders = shareholders; 
    }

}


The Hibernate exception when identifying more than one bag to fetch is shown below:

Caused by: org.hibernate.HibernateException: cannot simultaneously fetch multiple bags
 at org.hibernate.loader.BasicLoader.postInstantiate(BasicLoader.java:66)
 at org.hibernate.loader.entity.EntityLoader.<init>(EntityLoader.java:75)

There are a few ways to resolve this problem once the offending association(s) have been identified. One option is to make all or all but one collection have a fetch strategy of LAZY. This is the default strategy for Hibernate. This would mean that LAZY associations would not be loaded until requested but if requested outside of a session, this would raise a LazyInitializationException. One way to get around this is to load the collection when in a session. For example, if the Company -> Departments association is changed to be @OneToMany, the collection can be loaded as described below using Hibernate.initialize:


    public Company findById(String id) {
        HibernateTemplate ht = getHibernateTemplate();
        Company company = (Company) ht.get(Company.class, id);
        Hibernate.initialize(company.getDepartments());
        return company;
    }


Another option is to revise the type of collection being used. Does it have to be java.util.List? An alternative could be to use java.util.Set which isn't treated by Hibernate as a bag. An example of this would be to change the Company -> Shareholders association to be a SortedSet as shown below:


    private SortedSet<String> shareholders;

    @CollectionOfElements(fetch=FetchType.EAGER,targetElement=java.lang.String.class)
    @JoinTable(name="CO_SHR",joinColumns=@JoinColumn(name="CO_ID"))
    @Column(name="CO_SHR")
    @Sort(type=SortType.NATURAL)
    public SortedSet<String> getShareholders() {
        return this.shareholders;
    }


(Note that if you use HashSet, the retrieved collection may not be in the same order as it was persisted.)


If it must be java.util.List, then another solution is to use @IndexColumn which would mean the Collection semantic is that of List and not Bag. As well as a name, the Index can have a base number which if not specified will default to zero.


    @CollectionOfElements(fetch=FetchType.EAGER,targetElement=java.lang.String.class)
    @JoinTable(name="CO_SHR",joinColumns=@JoinColumn(name="CO_ID"))
    @Column(name="CO_SHR")
    @IndexColumn(name="IDX",base=1)
    public List<String> getShareholders() {
        return this.shareholders;
    }


This post highlights the need to think carefully about all associations and pose questions like what needs to be EAGERly loaded, what is the effect on memory usage, etc...

Thursday, 22 March 2012

RestTemplate and Spring MVC

This post is a follow up to the Spring MVC and RESTful Web Services post and shows a simple example of using Spring's RestTemplate class for client side access to, in this case, the Spring MVC RESTful web service built in the aforementioned post.

The RestTemplate class is, as it's javadoc describes, "the central class for client-side HTTP access. It simplifies communication with HTTP servers, and enforces RESTful principles. It handles HTTP connections, leaving application code to provide URLs (with possible template variables) and extract results."

In this example, we'll only be using the GET HTTP method (as that is all we have on our MVC example!) but the idea will be pretty much the same for other methods.

First, the Spring config and the XML below lists three beans. The Jaxb2Marshaller bean lists the classes that the JAXBContext needs to be aware of. This bean is then in turn injected into the MarshallingHttpMessageConverter as the marshaller and unmarshaller so Objects can be converted to and from an XML Stream. (Note that by default the MarshallingHttpMessageConverter supports text/xml and application/xml.) For this example, the message converter is the only entry in the list set on the RestTemplate bean. Finally, the RestTemplate bean is injected into the ExampleControllerClient bean.


<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.xsd">

 <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
  <property name="classesToBeBound">
   <list>
    <value>com.city81.spring.mvc.rest.domain.Message</value>
   </list>
  </property>
 </bean>

 <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">    
  <property name="messageConverters">    
   <list>      
    <bean id="messageConverter"            
     class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">        
     <property name="marshaller" ref="jaxbMarshaller" />        
     <property name="unmarshaller" ref="jaxbMarshaller" />    
    </bean>    
   </list>    
  </property>  
 </bean>

 <bean id="exampleControllerClient" class="com.city81.spring.mvc.rest.ExampleControllerClient">
  <constructor-arg ref="restTemplate" />
 </bean>

</beans> 


The ExampleControllerClient class below shows how simple it is to make a RESTful web service call:

package com.city81.spring.mvc.rest;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.client.RestTemplate;
import com.city81.spring.mvc.rest.domain.Message;

public class ExampleControllerClient {

 private RestTemplate restTemplate;

 public ExampleControllerClient(RestTemplate restTemplate) {
  this.restTemplate = restTemplate;
 }

 public void getMessage() {

  Message message = restTemplate.getForObject(
   "http://localhost:8080/spring-rest-0.0.1-SNAPSHOT/example/controller/message", 
   Message.class); 
  System.out.println(message.getMessageString());
 }

 public static void main(String[] args) {

  ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
          new String[] {"applicationContext.xml"});
  BeanFactory factory = (BeanFactory) appContext;
  ExampleControllerClient client = (ExampleControllerClient) factory
    .getBean("exampleControllerClient");
  client.getMessage();

 }

}


The getForObject method takes a URL and the type of the response object and retrieves a representation by doing a GET on the URL arg. This method is overloaded and can be used for different URLs. For example, if there are URI templates in the URL, then these can be populated by a third arg of a Map containing a collection of name value pairs or by using varargs.


public  T getForObject(String url,
                          Class responseType,
                          Object... urlVariables)
               throws RestClientException

public  T getForObject(String url,
                          Class responseType,
                          Map urlVariables)
               throws RestClientException


Back to the example and when the getForObject call is invoked, the JAXB marshaller behind the scenes will convert the XML into a Message object. An alternative to using the Jaxb2Marshaller  is the XStreamMarshaller. To swap JAXB for XStream would just be a Spring XML change as shown below:


<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">    
   <property name="aliases">    
    <props>      
     <prop key="message">com.city81.spring.mvc.rest.domain.Message</prop>    
    </props>    
   </property>  
  </bean>

...
     <property name="marshaller" ref="xstreamMarshaller" />        
     <property name="unmarshaller" ref="xstreamMarshaller" /> 
...


There are many different marshallers to achieve the same goal, and indeed many different media types with different marshallers. This post barely scratches the surface but just shows how simple it is to create client side code for calling a RESTful web service.

Tuesday, 31 January 2012

Parallel Processing with ForkJoinPool

With the release of Java 7 came the new Executor Service, ForkJoinPool. The class uses the notion of work-stealing threads which execute tasks which have been created by other tasks. Ultimately, this division of work will result in large problems becoming a series of smaller ones which will eventually result in one answer when all the tasks have completed their processing.

This post will demonstrate this new threading feature by an interpolation example. In this case, for two numbers with a given number of steps, the code will attempt to construct new points between those numbers using linear interpolation, and for simplicity using only a number of steps divisible by 2. eg for the numbers 5 and 25 with a step number of 4, the generated sequence would be:

[5.0, 10.0, 15.0, 20.0, 25.0]

The InterpolationService class below will contain an instance of the ForkJoinPool class. A ForkJoinPool instance can be created with an argument representing a target parallelism. This can either be supplied or left as the default which will be the number of processors ie  Runtime.availableProcessors()

package com.city81.forkjoin;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

public class InterpolateService {

    private final ForkJoinPool forkJoinPool;

    public InterpolateService() {
        forkJoinPool = new ForkJoinPool();
    }

    public List<Double> interpolate(double valueOne, double valueTwo, int steps) {
        
        ForkJoinTask<List<Double>> job = forkJoinPool.submit(
            new InterpolateTask(valueOne, valueTwo, steps));
        return job.join();
    }

    private static class InterpolateTask 
        extends RecursiveTask<List<Double>> {

        private final double valueOne;
        private final double valueTwo;
        private final int steps;
        private static final int LOWEST_STEP = 2;

        protected InterpolateTask(double valueOne, double valueTwo, int steps) {

            this.valueOne = valueOne;
            this.valueTwo = valueTwo;
            this.steps = steps;
        }

        @Override
        protected List<Double> compute() {
    
            List<Double> interpolatedArray = new ArrayList<Double>();
            double interpolatedValue = interpolate(valueOne, valueTwo);
    
            if (this.steps == LOWEST_STEP) {
                interpolatedArray.add(valueOne);
                interpolatedArray.add(interpolatedValue);
                interpolatedArray.add(valueTwo);
            } else {
                InterpolateTask interpolateTask1 = 
                    new InterpolateTask(valueOne, interpolatedValue, (steps/2));
                interpolateTask1.fork();
                InterpolateTask interpolateTask2 = 
                    new InterpolateTask(interpolatedValue, valueTwo, (steps/2));
                List<Double> interpolatedArrayTask2 = 
                    interpolateTask2.compute();
                List<Double> interpolatedArrayTask1 = 
                    interpolateTask1.join();
                interpolatedArray.addAll(
                    interpolatedArrayTask1.subList(0, interpolatedArrayTask1.size() - 1));
                interpolatedArray.addAll(interpolatedArrayTask2);
            }
            // System.out.println(interpolatedArray);
            return interpolatedArray;
        }

        private double interpolate(
            double valueOne, double valueTwo) {
   
            return ((valueTwo - valueOne) / 2.0) + valueOne;
        }

    }

    public static void main(String[] args) {
        InterpolateService interpolateService = new InterpolateService();
        List<Double> interpolatedArray = interpolateService.interpolate(5,25,4);
        System.out.println(interpolatedArray);
    }

}

The InterpolationService 's only public method interpolate, takes two numbers and the number of steps. These are the parameters to construct an instance of our private static class InterpolateTask. This class implements RecursiveTask which can return a result when the compute method is called on the task. An alternative implementation (but not suitable for this example) would be RecursiveAction whose compute method returns nothing.

The constructed task is submitted to the ForkJoinPool.

The compute method is where the logic for subdividing the task resides. It decides whether the work it has to process is small enough to process now or whether it needs further division. In the case of our example, the task will determine a task small enough when the step size is 2. If not, it will create two sub tasks, dividing the step size each time.

Eventually, all tasks will be of a small enough size to be completed. This will result in the arrays being added together as the recursive task tree is traversed back up to the original task.

This is not example of how to efficiently perform linear interpolation on a set of numbers but is just one example implementation of how to use the ForkJoinPool and its associated Task classes. Over time, hopefully this post can be updated to make the above code more efficient as well gathering metrics and benchmarking against other implementations.