Thursday, 25 May 2017

REST Endpoint Testing With MockMvc

In this post I'm going to show you how to test a Spring MVC Rest endpoint without deploying your application to a server. In the past, full integration tests were the only meaningful way to test a Spring REST endpoint. This involved spinning up a test server like Tomcat or Jetty, deploying the application, calling the test endpoint, running some assertions and then terminating the server. While this is an effective way to test an endpoint, it isn't particularly fast. We're forced to wait while the entire application is stood up, just to test a single endpoint.
An alternative approach is to unit test by manually instantiating the Controller and mocking out any required dependencies.  While such a test will run much faster than a full integration test, its of limited value. The problem is that by manually instantiating the Controller we're bypassing Springs Dispatcher Servlet, and as a result missing out on core features like
  • request URL mapping 
  • request deserialization 
  • response serialization
  • exception translation 
What we'd really like is the best of both worlds. The ability to test a fully functional REST controller but without the overhead of deploying the entire application to a server.

Introducing MockMvc

Thankfully that's exactly what MockMvc allows us to do. It stands up the Dispatcher Servlet and all required MVC components, allowing us to test an endpoint in a proper web environment, but without the overhead of running a server.
MockMvc provides a fluent API, allowing you to write tests that are self descriptive. This is a great feature as your tests will pretty much read like English, making life easier for developers coming behind you.

Defining a Controller

Before we can put MockMvc through its paces we need a REST endpoint to test. The AccountController defined below exposes 2 endpoints, one to create an Account and one to retrieve an Account.

 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
@RestController
public class AccountController {

    private AccountService accountService;
 
    @Autowired
    public AccountController(AccountService accountService) {
        this.accountService = accountService;
    }
 
    @RequestMapping(value = { "/api/account" }, method = { RequestMethod.POST })
    public Account createAccount(@RequestBody Account account, 
     HttpServletResponse httpResponse, 
     WebRequest request) {

        Long accountId = accountService.createAccount(account);
        account.setAccountId(accountId);
  
        httpResponse.setStatus(HttpStatus.CREATED.value());
        httpResponse.setHeader("Location", String.format("%s/api/account/%s", 
                                      request.getContextPath(), accountId));  
        return account;
    }
 
    @RequestMapping(value = "/api/account/{accountId}", method = RequestMethod.GET)
    public Account getAccount(@PathVariable("accountId") Long accountId) {
  
        /* validate account Id parameter */
        if (accountId < 9999) {
            throw new InvalidAccountRequestException();
        }
  
        Account account = accountService.loadAccount(accountId);
        if(null==account){   
           throw new AccountNotFoundException();
        }
  
        return account;
    }
 
}
  • createAccount - calls an AccountService to create the Account, then returns the Account along with a HTTP header specifying its location for future retrieval. The AccountService will be mocked using Mockito so that we can keep our test focus solely on the web layer.
  • retrieveAccount - takes an account Id from the URL and performs some simple validation to ensure the value is greater than 9999. If the validation fails a custom InvalidAccountRequestExcption is thrown. This exception is caught and translated by an exception handler we'll define later. Next the mock AccountService is called to retrieve the specified Account, before returning it to the client.

Exception Handler

The custom runtime exceptions thrown in getAccount are intercepted and mapped to appropriate HTTP response codes using the exception handler defined below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Slf4j
@ControllerAdvice
public class ControllerExceptionHandler {
 
 
    @ResponseStatus(HttpStatus.NOT_FOUND) // 404
    @ExceptionHandler(AccountNotFoundException.class)
    public void handleNotFound(AccountNotFoundException ex) {
        log.error("Requested account not found");
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST) // 400
    @ExceptionHandler(InvalidAccountRequestException.class)
    public void handleBadRequest(InvalidAccountRequestException ex) {
        log.error("Invalid account supplied in request");
    }
 
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) // 500
    @ExceptionHandler(Exception.class)
    public void handleGeneralError(Exception ex) {
        log.error("An error occurred processing request" + ex);
    }
}

MockMVC Setup

The @SpringBootTest annotation is used to specify the application configuration to load prior to running the tests. We could have referenced a test specific configuration here, but given our simple project setup its fine to use the main Application config 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
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;


@RunWith(SpringRunner.class)
@SpringBootTest(classes={ Application.class })
public class AccountControllerTest {
 
    private MockMvc mockMvc;
 
    @Autowired
    private WebApplicationContext webApplicationContext;

    @MockBean 
    private AccountService accountServiceMock;
 
    @Before
    public void setUp() {
        this.mockMvc = webAppContextSetup(webApplicationContext).build();
    }

The injected WebApplicationContext is a sub component of Springs main application context and encapsulates Springs configuration for web related components such as the controller and exception handler we defined earlier.

The @MockBean annotation tells Spring to create a mock instance of AccountService and add it to the application context so that it gets injected into the AccountController. We have a handle on it in the test so that we can define its behaviour prior to running each test.

The setup method uses the statically imported webAppContextSetup method from MockMvcBuilders and the injected WebApplicationContext to build a MockMvc instance.

Create Account Test

Now that we've created the MockMvc instance, its time to put it to work with a test for the create account endpoint.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
    @Test
    public void should_CreateAccount_When_ValidRequest() throws Exception {
  
        when(accountServiceMock.createAccount(any(Account.class))).thenReturn(12345L);
  
        mockMvc.perform(post("/api/account")
               .contentType(MediaType.APPLICATION_JSON)
               .content("{ \"accountType\": \"SAVINGS\", \"balance\": 5000.0 }")      
               .accept(MediaType.APPLICATION_JSON))
               .andExpect(status().isCreated())
               .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
               .andExpect(header().string("Location", "/api/account/12345"))
               .andExpect(jsonPath("$.accountId").value("12345"))      
               .andExpect(jsonPath("$.accountType").value("SAVINGS"))
               .andExpect(jsonPath("$.balance").value(5000));  
    }

On line 4 we use mockito to define the expected behaviour of the mock AccountService which was injected into the AccountController. We tell the mock that upon receiving any Account instance it should return a 12345.  

Lines 6 to 9 uses mockMvc to define a HTTP POST request to the URI /api/account. The request content type is JSON and the request body contains a JSON definition of the Account to be created. Finally an accept header is set to tell the server that the client expects a JSON response.

Lines 10 to 15 use statically imported methods from MockMvcResultMatchers to perform assertions on the response. We begin by checking that the response code returned is HTTP 200 'Created' and that the content type is indeed JSON. We then check for the existence of a HTTP header 'Location' that contains the request URL for retrieving the created account. The final 3 lines use jsonPath to check that the JSON response is as expected. JsonPath is like an JSON equivalent to XPath that allows you to query JSON using path expressions. For more information take a look at their documentation.

Retrieve Account Test

The retrieve account test follows a similar format to that described above.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    @Test
    public void should_GetAccount_When_ValidRequest() throws Exception {
  
        /* setup mock */
        Account account = new Account(12345L, EnumAccountType.SAVINGS, 5000.0);
        when(accountServiceMock.loadAccount(12345L)).thenReturn(account);
  
        mockMvc.perform(get("/api/account/12345")    
               .accept(MediaType.APPLICATION_JSON))
               .andExpect(status().isOk())
               .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
               .andExpect(jsonPath("$.accountId").value(12345))
               .andExpect(jsonPath("$.accountType").value("SAVINGS"))
               .andExpect(jsonPath("$.balance").value(5000.0));
    }

We begin by creating an Account object and use it to define the behaviour of the mock AccountService. The MockMvc instance is used to perform a HTTP GET request that expects a JSON response. We check the response for a HTTP 200 'OK' response code, a JSON content type and a JSON response body containing the requested account.

Retrieve Account Error Test 


 1    
 2
 3
 4
 5
 6
 7
 8
 9
10
@Test
public void should_Return404_When_AccountNotFound() throws Exception {
  
    /* setup mock */
    when(accountServiceMock.loadAccount(12345L)).thenReturn(null);
  
    mockMvc.perform(get("/api/account/12345")    
           .accept(MediaType.APPLICATION_JSON))
           .andExpect(status().isNotFound());
}

This test  configures the mock AccountService to return null when called. This demonstrates the power of @MockBean and its ability to register a mock object with the application context, and in turn have that mock injected into the AccountController. We're able to easily test non happy path logic in our controller and ensure that throwing an AccountNotFoundException results in a HTTP 404 response to the client.   

Wrapping Up

In this post you saw how MockMvc allows you to thoroughly test spring web controllers. MockMvc strikes a great balance between full integration tests and relatively low value unit tests. You get the benefit of testing a fully functional web layer without the overhead of deploying to a server.
I'm not suggesting MockMvc as an alternative to full integration tests, but rather something to compliment them. I usually write a low number of pure integration tests that focus on the happy path. MockMvc tests are faster than integration tests so are ideal when you want more granular web layer tests that will run quickly.

The sample code for this post is available on Github so feel free to pull it and have a play around. If you have any comments or questions please leave a note below.

Tuesday, 11 April 2017

Java Concurrency - Synchronization

In my last post we looked at running tasks across multiple threads, asynchronously using the ExecutorService. Accessing and manipulating an object from multiple threads simultaneously can pose a problem when the object in question holds state. If multiple threads attempt to modify shared state, behaviour can become unpredictable and result in data being left in an inconsistent state.

Unsynchronized Code

Take the simple BankAccount class below. It holds state in the form of a balance, which can be increased and decreased using the credit and debit methods respectively. When used in a single threaded context this object will behave as expected, crediting and debiting the amounts specified.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class BankAccount {
 
    private double balance;
 
    public void credit(double amount){
        balance = balance +amount;         
    }
 
    public void debit(double amount){    
        balance = balance - amount;     
    }
  
    public double getBalance(){
        return balance;
    }
}

However, when multiple threads call the credit and debit methods simultaneously, we can end up with unpredictable behaviour and an incorrect balance. To see this in action the test method below uses an ExecutorService to submit 100 account debits and 100 account credits, each for £100.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Test
public void testBankAccountWithoutSynchronization1(){
  
    BankAccount bankAccount = new BankAccount();
  
    ExecutorService executorService = Executors.newFixedThreadPool(10);
  
    IntStream.rangeClosed(1, 100).forEach(i->{   
        executorService.submit(()-> {   
            bankAccount.debit(100);    
        });
   
        executorService.submit(()-> {    
            bankAccount.credit(100);    
        });
    });
  
    executorService.shutdown();    
    System.out.println("Final Balance: " + bankAccount.getBalance());  
}

After all debits and credits have run we'd expect the account to have a balance of zero. However, what we end up with is a balance of -100 as shown below.

1
Final Balance: -100.0

So what's the problem?

The credit method takes the current balance, adds a specified amount to it and then assigns the new value back to balance. The problem is that adding a value to balance and then assigning that result back to balance is not an atomic operation. This means that it does not happen as one distinct unit of work. Instead a thread may add the specified amount to the current balance and before it has a chance to assign the new value back to balance, the balance variable is updated by another thread. At this point the balance value held by the first thread is stale and the resulting variable assignment is incorrect.

1
2
3
public void credit(double amount){ 
    balance = balance + amount;       
}

To resolve the issue we need to ensure that balance = balance + amount becomes an atomic operation, performed in isolation by one thread at a time.

Synchronized Methods

The simplest way to achieve this is by marking a method as synchronised.  A synchronized method uses an implicit lock to ensure that only 1 thread at a time can enter the method.  As a result, any shared state referenced inside the method is no longer vulnerable to being manipulated by multiple threads at the same time. In this instance the shared state we're protecting is of course the account balance.

1
2
3
public synchronized void credit(double amount){
    balance = balance + amount;         
}

Side Note: Using synchronized on an instance method will use the current objects intrinsic lock for controlling access to the method. Using synchronized on a static method however, uses the intrinsic lock associated with the class, not the object. This is an important distinction, as it is possible for one thread to hold an objects intrinsic lock, while another thread at the same time holds of the class.

Synchronized Blocks

While synchronizing an entire method can be useful, it is sometimes preferable to only synchronize a portion of a method instead. If you think about it, synchronizing a method creates a bottleneck by allowing only 1 thread into the method at a time. This bottle neck, known as contention, is a result of multiple threads competing to acquire a single lock. Contention can have an adverse affect on performance, so it can be preferable to synchronize only vulnerable code rather than an entire method. Thankfully the synchronized block shown below allows us to do exactly that.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public void debit(double amount){ 
  
    // execute some non vulnerable code here...  
  
    //vulnerable code is executed inside synchronized block
    synchronized (this) {
        balance = balance - amount; 
    }
  
    // execute some more non vulnerable code here...
}

When defining a synchronized block you must specify an object on which to lock . The intrinsic lock of the specified object is used to control access to the synchronized block. A typical approach is to use the current object by specifying this (shown above)

A final thread safe version of the original BankAccount class is shown below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class SynchronizedBankAccount {
 
    private double balance;
 
    public synchronized void credit(double amount){
        balance = balance + amount;         
    }
 
    public void debit(double amount){  
        synchronized (this) {
            balance = balance - amount; 
        }  
    }
 
    public double getBalance(){
        return balance;
    }
}


Granular Control with the Lock Interface

While synchronized methods and blocks are sufficient in most instances, there are times when greater control is required. The Lock interface defines a set of locking operations that provide developers with more granular control when writing thread safe code. ReentrantLock is a common implementation of the Lock interface and one we're going to discuss in next few sections.

ReentrantLock - what is reentrance?

The term reentrant refers to a locks ability to be acquired multiple times by the same thread. Implicit locking implemented via a synchronized method or block is reentrant. This means that a thread in a syncronized method may call into another synchronized method without blocking itself. While a reentrant lock may be acquired many times by the same thread, it must also be released the same number of times before the lock can be acquired by another thread.

Creating a ReentrantLock

The code snippet below creates a ReentrantLock using its no argument constructor.

1
private Lock lock = new ReentrantLock();

A second constructor takes a boolean to indicate whether or not the lock should apply a fairness policy. If set to true, a fairness policy is implemented that ensures that the longest waiting thread will acquire the lock when it becomes available. This avoids high priority threads monopolising CPU time, while lower priority threads are left to wait for long periods.

1
private Lock lock = new ReentrantLock(true);


Locking and Unlocking

The code snippet below is an updated version of the BankAccount credit method we looked at earlier. Instead of using the synchronized keyword I've used a ReentrantLock to control access to the vulnerable code. When a thread enters the method it will call lock in an attempt to acquire mutually exclusive access to the ReentrantLock. If the lock hasn't already been acquired by another thread, it will be acquired by the current thread, which will then be allowed to proceed.
If the lock has already been acquired by another thread when lock is called, the current thread will block until the lock becomes available again.

1
2
3
4
5
6
7
8
9
public void credit(double amount){
    try{   
        lock.lock();
        balance = balance + amount;    
    }
    finally{
        lock.unlock(); 
    }  
}

After the balance has been updated the unlock method is called to signal that the current thread is finished and the lock is released. At this point the lock can be acquired by a waiting thread.
Note that unlock should always be called inside a finally block. This ensures that the lock is always released, even if an exception is thrown after the lock is acquired. Its imperative that the lock is released, as failing to do so will result in other threads being blocked indefinitely.

More Flexible Locking and Unlocking

The lock method we looked at above attempts to acquire a lock, waiting indefinitely if it is not available. This is the same behaviour as a synchronized method or block. There are however, times when we may want to limit the amount of time we're willing to wait for a lock, especially if we have a large number of threads competing for the same lock.  Rather than have many threads blocked waiting for access, we could take some other course of action when a lock isn't available.  Luckily ReentrantLock provides this flexibility via two flavours of the tryLock method.

Acquiring a lock with tryLock()

The tryLock method checks for the availability of the lock, returning true if the lock is available. When tryLock returns true the current thread acquires the lock and is free to execute whatever vulnerable code is being protected.  If the lock is held by another thread and not immediately available tryLock will return false, allowing the application to immediately take some other course of action.

Acquiring a lock with tryLock(long time, TimeUnit unit)

An overloaded version of tryLock takes a time and time unit that determines how long the current thread should wait for the lock to become available. If the lock is available when tryLock is called, the current thread will acquire the lock and the method will return true immediately. At this point the current thread is free to execute whatever vulnerable code is being protected.
If on the other hand the lock has already been acquired by another thread, the current thread will wait for the lock to be released. If the lock is released within the specified period of time, the current thread will acquire the lock and tryLock will return true. If the time period elapsed and the lock still hasn't been released, tryLock will return false. At this point the current thread has not acquired the lock and an alternative course of action can be taken.

The debit method below shows tryLock in action. On line 3 the current thread waits up to two seconds for the lock to become available. If the lock is available or becomes available within two seconds, the current thread is free to execute whatever vulnerable code is being protected. If the lock doesn't become available after two seconds the debit amount is added to a queue for processing later.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public void debit(double amount) throws InterruptedException{  
  
    if(lock.tryLock(2000, TimeUnit.MILLISECONDS)){
        try{   
            balance-=amount;   
        }
        finally{
            lock.unlock(); 
        }
    }
    /* lock isn't available right now so do something else */
    else{
        /* add debit amount to queue for processing later */
    }    
}

ReentrantReadWriteLock

Another lock implementation worth looking at is the ReentrantReadWriteLock. As the names suggests the ReentrantReadWriteLock encapsulates both a read and write lock inside a single lock implementation.

Why would I need a Read & Write Lock

Consider a situation where you have a resource such as a HashMap that is being read from and written to by multiple threads. To synchronize access to a HashMap you could use any of the approaches we've already looked at. You could use a synchronized method, a synchronized block or even a ReentrantLock. While these approaches will work just fine, they do not always offer the most efficient solution.

When a thread attempts to read from or write to a HashMap using any of the above approaches, it will obtain mutually exclusive access to the lock, blocking all other threads from reading or writing at the same time. While this is the desired behaviour when writing to a HashMap, there is no reason why we should stop multiple threads reading from the HashMap concurrently. Reads do not manipulate the HashMap in any way so there is no reason to limit reads to only 1 thread at a time.

Ideally we'd like a means of synchronizing access to the HashMap when its being updated, but allow multiple threads to read from the HashMap when its not being updated. Thankfully this is exactly what the ReentrantReadWriteLock does.

Creating a ReentrantReadWriteLock

Like ReentrantLock the ReentrantReadWriteLock can be instantiated with an optional boolean to indicate whether or not a fairness policy should be established. If a fairness policy is chosen, threads will acquire the lock in the order they've requested it.

1
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);


Acquiring a Write Lock

The method below demonstrates how a write lock is acquired by first calling the writeLock method, followed by an appropriate locking method. The example below chains the lock method with writeLock but both tryLock and tryLock(time, TimeUnit) are both available. As mentioned previously, the lock should be released inside a finally block.

1
2
3
4
5
6
7
8
9
public void saveTransaction(String transaction) throws InterruptedException {
    try{
        readWriteLock.writeLock().lock();
        transactionHistory.put(UUID.randomUUID().toString(), transaction); 
    }
    finally{
        readWriteLock.writeLock().unlock(); 
    }  
}

When the write lock is acquired by a thread, that thread has mutually exclusive access to the ReentrantReadWriteLock. At this point no other thread can obtain a read or write lock, meaning that the HashMap can not be read from or written to by any other thread.

Acquiring a Read Lock

The method below demonstrates how a read lock is acquired by first calling readLock followed by an appropriate locking method.  Although the example below chains the lock method with readLock, both tryLock and tryLock(time, TimeUnit) are also available.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public List<String> getTransactions(){  
  
    List<String> transactions = null;
    
    try{
        readWriteLock.readLock().lock();
        transactions =  transactionHistory.values().stream().collect(Collectors.toList());
    }
    finally{
        readWriteLock.readLock().unlock(); 
    } 
  
    return transactions;
}

Unlike the write lock, the read lock can be held by multiple threads. In our sample code this allows multiple threads to read from the Map concurrently.

Important Note

While the example above serves to demonstrate the fundamentals of ReentrantReadWriteLock, in reality we wouldn't use it to synchronize access to a HashMap. Instead we'd make use of the Collections class which has a method that takes a Map and returns a thread safe equivalent, as shown below.

1
Map<String, String> transactionHistory  = Collections.synchronizedMap(new HashMap<String, String>());


Wrapping Up

The sample code for this post is available on github, so feel free to pull it down and have a play around. If you have any comments, questions or suggestions please leave a note below.  

Monday, 27 March 2017

Java Concurrency - Multi Threading with ExecutorService

In this post I'll look how the ExeutorService can be used to perform multi threaded asynchronous tasks. I'll begin by looking at the traditional approach of creating threads directly and then move on to examine the ExecutorService and how it can be used to simplify things.

Instantiating Threads Directly

Prior to the Executor API developers were responsible for instantiating and managing threads directly. Lets look at a simple example below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
   /**
    * Call 2 expensive methods on separate threads 
    *    
    * @throws InterruptedException 
    */
    public void doMultiThreadedWork() throws InterruptedException {
  
        /* create Runnable using anonymous inner class */
        Thread t1 = new Thread(new Runnable() {   
            public void run() {
                System.out.println("starting expensive task thread t1");
                doSomethingExpensive();    
                System.out.println("finished expensive task thread t1");
            }
        });
  
        /* start processing on new threads */
        t1.start();            
  
        /* block current thread until t1 has finished */
        t1.join();
    }
Simple Thread example

We begin by creating a new Thread object t1 and passing a Runnable to its constructor. Runnable is an interface with a single abstract method public void run(). To create a Thread we need to supply an implementation of the Runnable interface and in this instance we do that with an anonymous inner class. The run method contains logic that will be executed by the Thread when it is started. Note that if the code inside run throws a checked Exception it must be caught and handled inside the run method.

On line 18 the Thread is started by calling its start method. The JVM spawns a new process and executes the run() method in the context of the newly created Thread.  Note: you should be careful not to call the run() method directly as this will cause the method to execute in the context of the current thread and will result in single threaded behaviour.

On line 21 we call the join method to block the main thread execution until Thread t1 has terminated. This is only necessary if you want the main thread to wait for the spawned thread to terminate. Often this is not necessary, but for sake of our sample code we want to allow t1 to complete before continuing.

Introducing the Executor Service

Dealing with threads directly is all well and good but Oracle have made things a little easier by providing a layer of abstraction via its Executor API.  An Executor allows you to process tasks asynchronously and in parallel without having to deal with threads directly.

Creating an Executor

The Executors factory class is used to create an instance of an Executor, either an ExecutorService or a ScheduledExecutorService. Some of the most common types of Executors are described below.
  • Executors.newCachedThreadPool() - An ExecutorService with a thread pool that creates threads as required but reuses previously created threads as they become available.
  • Executors.newFixedThreadPool(int numThreads) - An ExecutorService that has a thread pool with a fixed number of threads. This is the maximum number of threads that can be active in the ExecutorService at any one time. If the number of requests submitted to the pool exceeds the pool size, requests are queued until a thread becomes available. 
  • Executors.newScheduledThreadPool(int numThreads) - A ScheduledExecutorService with a thread pool that is used to run tasks periodically or after a specified delay.
  • Executors.newSingleThreadExecutor() - An ExecutorService that uses a single thread. Tasks submitted to this ExecutorService will be executed one at a time and in the order submitted. 
  • Executors.newSingleThreadScheduledExecutor() - An ExecutorService that uses a single thread to execute tasks periodically or after a specified delay. 

Below is an example of creating a simple fixed thread pool ExecutorService with a pool size of 2. I'll use this ExecutorService in the following sections. 

1
    ExecutorService executorService = Executors.newFixedThreadPool(2);
Creating an ExecutorService using Executor factory method

Using an Executor

In the following sections I'm going to look at the various methods available on the ExecutorService for executing tasks asynchronously.

execute(Runnable)

The execute method takes a Runnable and is very similar to the simple Thread example we looked at earlier. The execute method is useful when you want to run a task and are not concern about checking its status or obtaining a result. Think of it as a means of invoking a fire and forget asynchronous task.

1
2
3
4
5
    executorService.execute(()->{
        System.out.println(String.format("starting expensive task thread %s", 
        Thread.currentThread().getName()));
        doSomethingExpensive();    
    }
Execute Runnable with ExecutorService

The example above creates a Runnable as a lambda expression and passes it to the execute method. The Runnable will be executed as soon as a thread is available from the ExecutorService threadpool.

Future<?> submit(Runnable)

The submit method also takes a Runnable but differs from the execute method in that it returns a Future. A Future is an object that represents a pending response form an asynchronous task. Think of it as a handle that can be used to check the status of the task or retrieve its result when the task completes. Futures use generics to allow the user to specify the return type of the task. However, given that a Runnables run method does not return a value (return type void), the Future holds the status of the task rather than a pending result. This is represented as Future<?> as shown in the example below.

1
2
3
4
5
    Future<?> taskStatus = executorService.execute(()->{
          System.out.println(String.format("starting expensive task thread %s", 
                                            Thread.currentThread().getName()));
          doSomethingExpensive();    
    }
                                                     Submit Runnable using lambda expression

The submit(Runnable) method is useful when you want to run a task that doesn't return a value but you'd like to check the status of the task after its been submitted to the ExecutorService.

Checking Task Status

Future provide a few methods that allow you to check the status of a task that's been submitted to the ExecutorService. The isCancelled method checks if a submitted task has already been cancelled. The isDone method allows you to check if the submitted task has completed. isDone will return true regardless of whether a task completed successfully, unsuccessfully or was cancelled. Finally, the cancel method can be used to cancel a submitted task. A boolean parameter indicates whether the task should be interrupted after its already been started.


1
2
3
4
5
6
7
    /* check if both tasks have completed - if not sleep current thread 
     * for 1 second and check again
     */
    while(!task1Future.isDone() || !task2Future.isDone()){
        System.out.println("Task 1 and Task 2 are not yet complete....sleeping");
 Thread.sleep(1000);
    }
Future isDone method used to check status of task 

Future<T> submit(Callable)

The submit method is overloaded to take a Callable as well as a Runnable. A Callable is similar to Runnable in that it represents a task that can be executed on another thread, but differs in that it returns a value and can throw a checked Exception. The Callable interface has the single abstract method public T call() throws Exception and like Runnable can be implemented with an anonymous inner class or functional interface. The return type of the call method is used to type the Future returned by the ExecutorService. There are two examples below, one submitting a Callable using an anonymous inner class and the other using a lambda expression.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    Future<Double> task1Future = executorService.submit(new Callable<Double>() {
  
        public Double call() throws Exception {     
   
            System.out.println(String.format("starting expensive task thread %s", 
                                              Thread.currentThread().getName()));
            Double returnedValue = someExpensiveRemoteCall();    
   
            return returnedValue;
        }           
    });
Submit Callable using anonymous inner class 

1
2
3
4
5
6
7
8
    Future<Double> task2Future = executorService.submit(()->{
  
        System.out.println(String.format("starting expensive task thread %s", 
                                           Thread.currentThread().getName()));
        Double returnedValue = someExpensiveRemoteCall();    
  
        return returnedValue;
    });
Submit Callable using lambda

The example above creates a Callable as a lambda and passes it to the execute method. The Callable will be executed as soon as a thread is available.

Retrieving a Result  from a Future

When we submit a Callable to the ExecutorService we receive a Future with the return type of the call method. In the example above the call method returns a Double so the Future returned is Future<Double>. One way of retrieving the result from a Future is by calling its get method. This method will block indefinitely waiting on the submitted task to complete. If the task doesn't complete or takes a long time to complete, the main application thread will remain blocked.

Waiting indefinitely for a result is often not ideal. We'd rather have more control over how we retrieve the result and take some action if a task does not complete within a acceptable period of time. Luckily there is an overloaded version of the get method that takes a time value and time unit. This method waits for the specified period of time and if the task is not complete and a result not available, throws a TimeoutException.

1
2
    Double value1 = task1Future.get();
    Double value2 = task2Future.get(4,  TimeUnit.SECONDS); // throws TimeoutException
                                                                                     Get result from Callable


Submit Multiple Callables

As well as supporting the submission of a single Callable, the ExecutorService allows you to submit a Collection of Callables using the invokeAll method. As you might expect, instead of receiving a single Future response, a Collection of Futures is returned. A Future is returned representing the pending result of each submitted task.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
    Collection<Callable<Double>> callables = new ArrayList<>();
    IntStream.rangeClosed(1, 8).forEach(i-> {
        callables.add(createCallable());
    });
   
    /* invoke all supplied Callables */ 
    List<Future<Double>> taskFutureList = executorService.invokeAll(callables);
   
    /* call get on Futures to retrieve result when it becomes available.
     * If specified period elapses before result is returned a TimeoutException
     * is thrown
     */
    for (Future<Double> future : taskFutureList) {
    
        /* get Double result from Future when it becomes available */
        Double value = future.get(4, TimeUnit.SECONDS);
        System.out.println(String.format("TaskFuture returned value %s", value)); 
    }
Invoking a Collection of Callables

The sample code above submits 8 Callables to the ExecutorService and retrieves a List containing 8 Futures. The Futures returned are in the same order as the Callables were submitted to the ExecutorService. Note that submitting a Collection of Callables will require that the size of the thread pool is tweaked if we want  most or all of the submitted tasks can be executed in parallel. For the example above we'd need a thread pool with 8 threads to run all tasks in parallel  

Shutting Down the ExecutorService

After all tasks have completed its important to shut down the ExecutorService gracefully so that resources used by the underlying thread pool are reclaimed by the JVM. There are 2 methods available, shutdown and shutdownNow. The shutDown method triggers a shutdown of the ExecutorService, allowing currently processing tasks to finish but rejecting newly submitted tasks.

shutDownNow also triggers a shutdown of the ExecutorService, but does not allow currently executing tasks to complete, attempting to terminate them immediately. shutDownNow returns a list of tasks that were queued for execution when the shutdown was initiated.  To avoid potential resource leaks its important that the ExecutorService is shut down inside a finally block.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    ExecutorService executorService = null;
  
    try{  
        executorService = Executors.newFixedThreadPool(2);
   
        executorService.execute(()->{
            System.out.println(String.format("starting expensive task thread %s", 
                                               Thread.currentThread().getName()));
            doSomethingExpensive();    
        });
      
    }
    finally{
        executorService.shutdown();    
    }
ExecutorService shut down in finally block

Source Code  

The source code used in this post is available on Github. Feel free to pull the code and have a play around with it. As always, feel free to post comments, questions or suggestions below. 

Tuesday, 4 October 2016

Apache CXF- Contract First Web Services

I wrote a post a few years ago detailing a step by step guide to building a contract first web service using Spring.  I recently started working with Apache CXF and thought it would be worth putting together a more up to date post, this time using CXF.
We'll create a fictitious Account Service that takes a single account number parameter and returns associated account information. Although the sample service will be very simple, the approach taken should provide you with a solid foundation upon which to build real world services.

Source Code

The full source code for this post is available on GitHub so feel free to have a look. You may find it useful to have the code locally as you work through this post.

Domain Model Definition

We'll begin by defining the service domain model as an XML Schema Definition (XSD). The schema will define the entities that our Account service will use. We'll begin by defining the core Account entity - the diagram below shows the XSD snippet that defines the Account as well as a visual representation taken from XML Spy.

Next we'll define the AccountDetailsRequest type that will be used as a parameter to the Account service.

Finally we'll define the AccountDetailsResponse type that will be used as the return type from the Account service.

The full schema definition is 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
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://com/blog/samples/webservices/accountservice" xmlns:account="http://webservices.samples.blog.com" targetNamespace="http://com/blog/samples/webservices/accountservice" elementFormDefault="qualified">
 <xsd:complexType name="Account">
  <xsd:sequence>
   <xsd:element name="AccountNumber" type="xsd:string"/>
   <xsd:element name="AccountName" type="xsd:string"/>
   <xsd:element name="AccountBalance" type="xsd:double"/>
   <xsd:element name="AccountStatus" type="EnumAccountStatus"/>
  </xsd:sequence>
 </xsd:complexType> 
 <xsd:simpleType name="EnumAccountStatus">
  <xsd:restriction base="xsd:string">
   <xsd:enumeration value="Active"/>
   <xsd:enumeration value="Inactive"/>
  </xsd:restriction>
 </xsd:simpleType>
 <xsd:element name="AccountDetailsRequest">
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element name="accountNumber" type="xsd:string"/>
   </xsd:sequence>
  </xsd:complexType>
 </xsd:element>
 <xsd:element name="AccountDetailsResponse">
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element name="AccountDetails" type="Account"/>
   </xsd:sequence>
  </xsd:complexType>
 </xsd:element>
</xsd:schema>

Service Contract Definition

Next we'll define the public facing service contract using a WSDL. A WSDL is an XML document that describes a SOAP Web Service and how clients can interact with it. WSDLs are a great way to describe service contracts because they are easy to interpret by developers and can be used by tooling to generate many useful artefacts, some of which we'll look at later.  The Account Service WSDL is defined as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/"
 xmlns:tns="http://www.briansjavablog.com/Accounts/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Accounts"
 targetNamespace="http://www.briansjavablog.com/Accounts/"
 xmlns:accounts="http://com/blog/samples/webservices/accountservice">
 <wsdl:types>
  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <xsd:import namespace="http://com/blog/samples/webservices/accountservice"
    schemaLocation="../schema/AccountsService.xsd">
   </xsd:import>
  </xsd:schema>
 </wsdl:types>
 <wsdl:message name="AccountDetailsRequest">
  <wsdl:part element="accounts:AccountDetailsRequest" name="parameters" />
 </wsdl:message>
 <wsdl:message name="AccountDetailsResponse">
  <wsdl:part element="accounts:AccountDetailsResponse" name="parameters" />
 </wsdl:message>
 <wsdl:portType name="Accounts">
  <wsdl:operation name="GetAccountDetails">
   <wsdl:input message="tns:AccountDetailsRequest" />
   <wsdl:output message="tns:AccountDetailsResponse" />
  </wsdl:operation>
 </wsdl:portType>
 <wsdl:binding name="AccountsServiceSoapBinding" type="tns:Accounts">
  <soap:binding style="document"
   transport="http://schemas.xmlsoap.org/soap/http" />
  <wsdl:operation name="GetAccountDetails">
   <soap:operation
    soapAction="http://www.briansjavablog.com/Accounts/GetAccountDetails" />
   <wsdl:input>
    <soap:body use="literal" />
   </wsdl:input>
   <wsdl:output>
    <soap:body use="literal" />
   </wsdl:output>
  </wsdl:operation>
 </wsdl:binding>
 <wsdl:service name="AccountsService">
  <wsdl:port binding="tns:AccountsServiceSoapBinding" name="AccountsPort">
   <soap:address
    location="http://localhost:8080/apache-cfx-demo/services/accounts" />
  </wsdl:port>
 </wsdl:service>
</wsdl:definitions>
                                                                                    
The WSDL is composed of 5 main parts
  • Types - the <wsdl:types> section defines the domain model associated with the service. The types are defined using XSD and can be defined in the WSDL itself or imported from a separate XSD. On line 9 above we import the schema definition file we created earlier.
  • Message - the <wsdl:message> is used to define the request and response messages handled by the service. The nested <wsdl:part> section defines the domain type that will be used to form the messages.
  • PortType - the <wsdl:portType> defines the service operations that are exposed to clients, parameters required to invoke the operations and response types returned. 
  • Binding - the <wsdl:binding> section defines the protocol and data format. 
    • The binding type attribute refers to the portType defined earlier in the WSDL. 
    • The soap binding style can be either RPC or document. In this instance we've chosen document. 
    • The transport attribute indicates that the service will be exposed over HTTP. Other less common options include JMS and SMTP.
    • The operation element defines each operation that we exposed through the portType.
    • Binding - the <wsdl:binding> section defines the protocol and data format. 
  • Service - the <wsd;:service> defines the exposed service using the portType and binding we defined above.  

POM Configuration

Now that we've defined the WSDL its time to configure the POM to use the Apache CXF code generation plugin. The plugin invokes a WSDL2Java process which parses the WSDL and generates a service endpoint interface and associated domain objects. The plugin configuration is shown below. Note that I've omitted the rest of the POM definition for brevity. To see the full definition pull the sample code from github.

 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
          <plugins>
      <plugin>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-codegen-plugin</artifactId>
  <version>3.1.7</version>
  <executions>
     <execution>
        <id>generate-sources</id>
   <phase>generate-sources</phase>
   <configuration>
      <sourceRoot>src/generated/java</sourceRoot>
      <wsdlOptions>
         <wsdlOption>
            <wsdl>${basedir}/src/main/resources/wsdl/Accounts.wsdl</wsdl>
         </wsdlOption>
      </wsdlOptions>
   </configuration>
   <goals>
      <goal>wsdl2java</goal>
   </goals>
     </execution>
  </executions>
      </plugin>
          </plugins>
                                                                          
The WSDL path on line 14 tells CXF what WSDL to run WSDL2Java with. The sourceRoot configuration on line 11 is the fully qualified package name that the generated class will be copied to. Its a good idea to put these in src/generated/java so that its obvious to other developers that the package contains generated code.

Code Generation

We're now ready to generate the Service Endpoint Interface and domain objects from the WSDL. To run the code generation simply open a command window and run mvn generate-sources



Refresh the IDE workspace and you will see 2 new packages. The package names are based on the namespaces specified in the WSDL. The contents of both packages is described below.
  • com.blog.samples.webservices.accountservice - contains 4 service domain objects, Account, AccountDetailsRequest, AccountDetailsResponse and EnumAccountStatus. These 4 types represent the service request and response. ObjectFactory is a helper class for creating new instances of the domain types and package-info.java applies XML namespace metadata to all domain classes in the package.
  • com.briansjavablog.accounts - contains the Service Endpoint Interface Accounts.java. This interface is a Java representation of the service operation we defined in the WSDL. The contents of this class are covered in detail below. AccountsService.java is a web service client and can be used to invoke the service.

Service Endpoint Interface

The Service endpoint interface that was generated in the previous step is defined below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/**
 * This class was generated by Apache CXF 3.1.7
 * 2016-09-29T07:57:42.236+01:00
 * Generated source version: 3.1.7
 * 
 */
@WebService(targetNamespace = "http://www.briansjavablog.com/Accounts/", name = "Accounts")
@XmlSeeAlso({com.blog.samples.webservices.accountservice.ObjectFactory.class})
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface Accounts {

    @WebMethod(operationName = "GetAccountDetails", action = "http://www.briansjavablog.com/Accounts/GetAccountDetails")
    @WebResult(name = "AccountDetailsResponse", targetNamespace = "http://com/blog/samples/webservices/accountservice", partName = "parameters")
    public com.blog.samples.webservices.accountservice.AccountDetailsResponse getAccountDetails(
        @WebParam(partName = "parameters", name = "AccountDetailsRequest", targetNamespace = "http://com/blog/samples/webservices/accountservice")
        com.blog.samples.webservices.accountservice.AccountDetailsRequest parameters
    );
} 
  • @WebService - Marks the class as defining a Web Service interface from a WSDL. The namespace should match the namespace defined in the WSDL and the name should match the WSDL PortType.
  • @XmlSeeeAlso - Lets JAXB know what other classes need to be registered with the JAXB context for serialization and deserialization. 
  • @SoapBinding - Describes mapping from web service operations to SOAP protocol
  • @WebMethod - Maps a service operation to a Java method. The operation name references the operation defined in the WSDL and the target namespace uses the namespace associated with the WSDL operation.  
  • @WebResult - Maps a service operation response message to a Java return type. The name refers to the response message name defined in the WSDL. The target namespace uses the namespace associated with the WSDL message and the partName refers to wdl:part name in the WSDL.
  • @WebParam - Maps a service operation request message to a Java parameter type. The name refers to the request message name defined in the WSDL. The target namespace uses the namespace associated with the WSDL message and the partName refers to wdl:part name in the WSDL. 

Service Endpoint Implementation

Now that we've generated the Service Endpoint Interface, its time to create an implementation. The endpoint implementation class will be called by the CXF framework after it has deserialized the incoming SOAP body and figured out which endpoint method should handle the request. Our simple service exposes a single operation, but for services with multiple operations CXF uses the request payload to determine which endpoint method to call. Creating an endpoint implementation is straight forward and simply requires a class that implements the Service Endpoint Interface as shown below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@WebService(portName = "Accounts", serviceName = "Accounts", 
            endpointInterface = "com.briansjavablog.accounts.Accounts", 
            targetNamespace = "http://www.briansjavablog.com/Accounts/")
public class AccountServiceEndpoint implements Accounts {

    private AccountService accountService;

    @Autowired
    public AccountServiceEndpoint(AccountService accountService) {
        this.accountService = accountService;
    }

    @Override
    public AccountDetailsResponse getAccountDetails(AccountDetailsRequest parameters) {

        return accountService.getAccountDetails(parameters);
    }
}

The @WebService annotation marks this class as implementing a web service endpoint. The attributes portName, serviceName and targetNamespace should all match their equivalent in the WSDL definition. The enpointInterface refers to the generated Service Endpoint Interface class we looked at earlier. The AccountServiceEndpoint constructor takes a Spring injected AccountService as an argument. The getAccountDetails method is an implementation of the interface method defined on the Service Endpoint Interface class and uses the injected service to get the required account details.

Account Service 

The Account Service injected into the endpoint implementation above is trivial and simply returns hard coded values. I've split this out into a separate service class to demonstrate that its good practice to decouple endpoint processing logic from business logic. The only thing to note in this class is that we use the JAXB generated ObjectFactory to create an instance of the response type.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@Service
public class AccountServiceImpl implements AccountService {

    @Override
    public AccountDetailsResponse getAccountDetails(AccountDetailsRequest parameters) {

        ObjectFactory factory = new ObjectFactory();
        AccountDetailsResponse response = factory.createAccountDetailsResponse();
  
        Account account = factory.createAccount();
        account.setAccountNumber("12345");
        account.setAccountStatus(EnumAccountStatus.ACTIVE);
        account.setAccountName("Joe Bloggs");
        account.setAccountBalance(3400);
  
        response.setAccountDetails(account);  
        return response;
    }
}
                                                                                      

Spring XML Configuration 

The guys at CXF have made a considerable effort to ensure that CXF integrates nicely with the Spring framework. Of course CXF can be configured programatically without Spring, but if you're already using Spring for dependency injection (or anything else for that matter), it makes sense to use CXFs Spring support. This section describes how to configure the endpoint we created earlier so that it can be published to a Servlet container like Tomcat.

 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
<?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:jaxws="http://cxf.apache.org/jaxws"
    xsi:schemaLocation="http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd
          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
          http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

   <context:component-scan base-package="com.briansjavablog.accounts" />

   <jaxws:endpoint id="accountService"
                   implementor="com.briansjavablog.accounts.service.AccountServiceEndpoint"
                   address="/services/accounts">
    <jaxws:inInterceptors>
      <ref bean="loggingInInterceptor" />
    </jaxws:inInterceptors>
    <jaxws:outInterceptors>
      <ref bean="loggingOutInterceptor" />
    </jaxws:outInterceptors>
   </jaxws:endpoint>

   <bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
   <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />

</beans>
  • Line 11 - Enable component scanning so that beans annotated as @Component and @Service are registered as Spring components. 
  • Lines 13 to 15 - Define endpoint configuration by specifying endpoint implementation class for implementor and the address of the exposed endpoint. Note that the address is relative to the application root.
  •  Lines 16 to 21 - Register endpoint interceptors for logging incoming SOAP request payload and outgoing SOAP response payload.
  • Line 24 - Create interceptor for logging inbound SOAP payloads. This interceptor is provided by CXF out of the box and is executed before the JAXB deserialization and endpoint implementation class is called. 
  • Line 24 - Create interceptor for logging outbound SOAP payloads. This interceptor is provided by CXF out of the box and is executed after endpoint service method is executed and the JAXB serialization and endpoint implementation class is called. 

Web.xml 

The final piece of configuration we need to run our service in a Servlet container is the web.xml. If you've done any kind of Java web development the web.xml definition below will look familiar.

 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
<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>WEB-INF/beans.xml</param-value>
    </context-param>

    <listener>
 <listener-class>
     org.springframework.web.context.ContextLoaderListener
 </listener-class>
    </listener>

    <servlet>
 <servlet-name>CXFServlet</servlet-name>
 <display-name>CXF Servlet</display-name>
 <servlet-class>
     org.apache.cxf.transport.servlet.CXFServlet
 </servlet-class>
 <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
 <servlet-name>CXFServlet</servlet-name>
 <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>
  • Line 8 to 11 - Provides a path to the Spring beans.xml configuration file. This file is used by the ContextLoaderListener described below.
  • Lines 13 to 17 - ContextLoaderListener creates the Spring application context on container startup. It uses the bean definitions defined in contextConfigLocation.
  • Lines 19 to 26 - Configures CXF provided Servlet to process incoming HTTP requests. 
  • Lines 28 to 31 -  Servlet mapping configures CXF Servlet to process all requests received at the application root.

Integration Test 

The next step is to add an integration test. Most projects now a days use some sort of continuous integration so its important to have integration test coverage that is run on every code push. We're going to create a simple happy path integration test that will deploy the service to a specified endpoint using Jetty, make a HTTP call to the endpoint and then perform some assertions on the response. This is a simple but effective end to end test that we can run locally or on a continuous integration environment, without having to worry about deploying to a standalone Servlet container.
We'll begin by looking at the Spring configuration that describes the dependencies we need to run our test.

 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
<?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:jaxws="http://cxf.apache.org/jaxws"
 xsi:schemaLocation="
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

 
 <context:component-scan base-package="com.briansjavablog.accounts" />

 <jaxws:server id="accountService"
        address="http://localhost:8080/apache-cxf-demo/services/accounts">
     <jaxws:serviceBean>
  <bean class="com.briansjavablog.accounts.service.AccountServiceEndpoint" />
     </jaxws:serviceBean>
     <jaxws:inInterceptors>
  <ref bean="loggingInInterceptor" />
     </jaxws:inInterceptors>
     <jaxws:outInterceptors>
                <ref bean="loggingOutInterceptor" />
     </jaxws:outInterceptors>
 </jaxws:server>

 <jaxws:client id="testAccountServiceClient"
        address="http://localhost:8080/apache-cxf-demo/services/accounts"
        serviceClass="com.briansjavablog.accounts.Accounts">
     <jaxws:inInterceptors>
         <ref bean="loggingInInterceptor" />
     </jaxws:inInterceptors>
     <jaxws:outInterceptors>
                <ref bean="loggingOutInterceptor" />
     </jaxws:outInterceptors>
 </jaxws:client>

 <bean id="abstractLoggingInterceptor" abstract="true">
     <property name="prettyLogging" value="true" />
 </bean>
 <bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" parent="abstractLoggingInterceptor" />
 <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor" parent="abstractLoggingInterceptor" />

</beans>
  • Line 12 - Configures component scanning so that beans annotated with @Component and @Service are registered with the bean factory.
  • Lines 14 to 15 - jaxws:server defines a server configuration that will launch Jetty to host the web service for the duration of the test. The address attribute specifies the local URL where the service will be deployed.
  • Lines 16 to 18 - Defines the endpoint class that will service incoming requests. This is the service endpoint implementation class we defined earlier.
  • Lines 19 to 24 - Logging interceptors are registered with the server to log inbound SOAP requests and outbound SOAP responses.
  •  Lines 27 to 29 - jaxws:client defines a web service client that we'll use to call the service. This client will be injected into our test class. The address attribute is the target URL of the service and the serviceClass is the Service Endpoint Interface that was generated earlier.
  • Lines 30 to 35 - Logging interceptors are registered with Client to log outbound SOAP requests and inbound SOAP responses.
  • Lines 38 to 42 - Defines inbound and outbound logging interceptors that are used by both the client and the server, The abstract interceptor is used to define a common property (prettyLogging) that is used by both logging interceptors.     
Finally we'll look at the test class definition. This class uses the test configuration above to create a web service client, a test server and deploy the application to the server.

 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
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration( {"classpath:beans-config-test.xml"} )
public class AccountServiceEndpointTest {

    @Autowired
    private Accounts accountsService;
    private AccountDetailsRequest accountDetailsRequest;
 
    @Before
    public void setUp() throws Exception {
  
        ObjectFactory objectFactory = new ObjectFactory();
 accountDetailsRequest = objectFactory.createAccountDetailsRequest();
 accountDetailsRequest.setAccountNumber("12345");
    }

    @Test
    public void testGetAccountDetails() throws Exception {
        AccountDetailsResponse response = accountsService.getAccountDetails(accountDetailsRequest);
        assertTrue(response.getAccountDetails()!= null);
        assertTrue(response.getAccountDetails().getAccountNumber().equals("12345"));
        assertTrue(response.getAccountDetails().getAccountName().equals("Joe Bloggs"));
        assertTrue(response.getAccountDetails().getAccountBalance() == 3400);
        assertTrue(response.getAccountDetails().getAccountStatus().equals(EnumAccountStatus.ACTIVE));
    }

}

  • Lines 1 & 2 - Define this as test that relies on Spring managed dependencies. The test application context is loaded form the beans-config-test.xml file we defined earlier. 
  • Lines 5 & 6 - Spring injects an instance of the Accounts Endpoint Service Interface that was generated from the WSDL. The injected instance is a client side proxy to the remote service and is constructed by Spring using the jaxws:client definition we defined in beans-config-test.xml. This is essentially a bridge out to the remote service deployed on Jetty.
  • Lines 9 to 15 - Setup method is called before the test method and is used to create a request object.
  • Lines 17 to 25 - Test method uses injected AccountService client side proxy to call the remote service deployed  on Jetty and performs a number of assertions on the deserialized response.

Running the Test

Running the test is straight forward. Simply fire up a command window and run the mvn test command. You should see the SOAP request and response payloads logged by both the client and the server as follows.

Running on Tomcat 

The service can be deployed to Tomcat manually or you can use the Tomcat maven plugin by running mvn tomcat:run-war from the command line. When the service is deployed we can test it on port 8080 using a SOAP client. We'll use the Eclipse Web Services Explorer to run a quick manual test to ensure the service is up and running.
  • In Eclipse launch the Web Services Explorer, enter the path to the WSDL as shown below and click Go.

  • Click the GetAccountDetails operation

  • Populate the account number parameter and click Go to call the service. In the bottom panel click the Source link to see the raw SOAP request and response payloads.

Wrapping Up

In this post we took a fairly detailed look at building and testing a contract first web service using Apache CXF. The service itself is very simple but the approach used should provide you with a solid grounding for building more complex services. The full source code is available on Github. As always, feel free to post comments, questions or suggestions below. Feedback is always welcome.