Reactive RESTful service with Spring 5, Spring Boot 2 and MongoDB (part 2)

In this second post of the series “Reactive RESTful service with Spring 5, Spring Boot 2 and MongoDB” we will see how to useSpring Security OAuth2 and SSL to secure the service created in part1

The project is available on github.

Overview

ssauth2-archi

  1. The client requests a new token from the Authorization Server by sending a POST to /oauth/token
  2. The server authenticates the client and returns a payload containing the token.
  3. The Resource Server intercepts calls to the REST api and checks if the client has provided a token in the HTTP header
  4. The token is validated with the Authorization server.
  5. If the token is valid then the resource is returned.

Tokens have an expiry time so it’s the responsibility of the client to request a new one whenever the current token expires.

Project dependencies

We start by adding spring-boot-starter-security starter module to enable Spring Security, then we add the dependency spring-security-oauth2 to enable OAuth2 and finally we add spring-security-test dependency for tests.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.security.oauth</groupId>
	<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-test</artifactId>
	<scope>test</scope>
</dependency>

Authorization Server

Spring provides @EnableAuthorizationServer annotation along with AuthorizationServerConfigurerAdapter class that can be extended to create an Authorization Server

@EnableAuthorizationServer
@Configuration
public class OAuth2AuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
....
}

The class can be customized by overriding AuthorizationServerConfigurerAdapter’s methods which is what we will do to add an in-memory client (for ease of use)

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
	clients.inMemory()
		.withClient("clientId")
		.secret("clientSecret")
		.scopes("read","write","read-write")
		.and().build();
}

The code can be made cleaner by externalizing client’s credentials to application.properties file located under src/main/resources

# OAuth2 credentials
oauth2.clientId=clientId
oauth2.secret=clientSecret
oauth2.scopes=read,write,read-write

Then injecting them with @Value annotation

package customerservice.oauth2;

public class OAuth2AuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {

	@Value("${oauth2.clientId}")
	private String clientId;

	@Value("${oauth2.secret}")
	private String secret;

	@Value("${oauth2.scopes}")
	private String[] scopes;

	/* OAuth2 in memory credentials */
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		clients.inMemory()
			.withClient(clientId)
			.secret(secret)
			.scopes(scopes)
			.and().build();
	}
}

The client we just created has three scopes: read, write and read-write, which means it can access resources restricted to read-only operations, to write-only operation and to read-write operations.
Scopes in OAuth2 can be seen as equivalent to Spring Security roles.

Resource Server

The Resource server is created by extending ResourceServerConfigurerAdapter and annotating the class with @EnableResourceServer

package customerservice.oauth2;

@EnableResourceServer
@Configuration
public class OAuth2ResourceServerConfigurer extends ResourceServerConfigurerAdapter {

}

We don’t need to customize OAuth2ResourceServerConfigurer, but if needed this can be done by overriding ResourceServerConfigurerAdapter‘s methods.

Enable oauth2 SpEL variable

Regular Spring Security annotations support OAuth2 but this support is not enabled by default, to enable it an extra step is needed which consists in extending GlobalMethodSecurityConfiguration and annotating the new class with @EnableGlobalMethodSecurity(prePostEnabled = true)

We also need to customize the behavior of the new class by overriding the method createExpressionHandler() to return an OAuth2MethodSecurityExpressionHandler instead of the default MethodSecurityExpressionHandler, this will enable the SpEL variable oauth2 that will use with the Spring Security annotation @PreAuthorize

package customerservice.oauth2;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class OAuth2GlobalMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {

	@Override
	protected MethodSecurityExpressionHandler createExpressionHandler() {
		return new OAuth2MethodSecurityExpressionHandler();
	}
}

Securing resources

Spring offers different strategies to define access controls, one of them is the Method Security Expression which offers a set of @Pre and @Post annotations that can be applied at method level.

More details can be found in the reference documentation.

For this example we will use @PreAuthorize annotation.

package customerservice.restapi;

public class CustomerController {

	@PreAuthorize("#oauth2.hasAnyScope('read','write','read-write')")
	@RequestMapping(method = GET)
	public Mono<ResponseEntity<List<Customer>>> allCustomers() {
	}

	@PreAuthorize("#oauth2.hasAnyScope('read','write','read-write')")
	@RequestMapping(method = GET, value = "/{id}")
	public Mono<ResponseEntity<Customer>> oneCustomer(@PathVariable @NotNull ObjectId id) {
	}

	@PreAuthorize("#oauth2.hasAnyScope('write','read-write')")
	@RequestMapping(method = POST, consumes = { APPLICATION_JSON_UTF8_VALUE })
	public Mono<ResponseEntity<?>> addCustomer(@RequestBody @Valid Customer newCustomer) {
	}
}

As mentioned previously, the SpEL variable oauth2 is used to restrict access to clients with certain scopes listed in hasAnyScope()

For example allCustomers() method is restricted to clients with at least one of the three scopes: ‘read’, ‘write’, ‘read-write’

Testing

All tests except CustomerServiceTest continue to run successfully, that’s because they are either unit tests or integration tests in mocked web environments where Spring Security is not active.

CustomerServiceTest on the other hand runs in a real web environment where Spring Security is active.

To make the test class run successfully we need to send a valid token every time we contact the Resource server, let’s add a method that will request a token and return it.

private String requestToken(WebClient webClient) {

	// 1
	WebClient webClientAuth = webClient.filter(basicAuthentication("clientId", "clientSecret"));

	// 2
	JsonNode tokenResp = webClientAuth.post().uri("/oauth/token")
		.contentType(APPLICATION_FORM_URLENCODED)
		.accept(APPLICATION_JSON_UTF8)
		.body(fromObject("grant_type=client_credentials"))
		.exchange()
		.flatMap(resp -> resp.bodyToMono(JsonNode.class))
		.block();

	// 3
	return tokenResp.get("access_token").asText();
}

// 1 We useclient’s credentials to do Basic Authentication

// 2 The webClient sends a POST to the Authorization Server’s URL /oauth/token and blocks until the server replies, the body of the POST specifies the grant type that is used to obtain the access token, available types are: “Authorization Code”, “Implicit”, “Password credentials” and “Client credentials”. More details are available in Section 1.3 of the OAuth2 specification.

// 3 The token is extracted from the JSON payload and returned

@Test
public void testCRUDOperationsAllTogether() throws IOException {

	final WebClient webClient = createSSLWebClient();

	final HttpHeaders headers = new HttpHeaders();
	headers.add(ACCEPT, APPLICATION_JSON_UTF8_VALUE);
	headers.add(CONTENT_TYPE, APPLICATION_JSON_UTF8_VALUE);
	// 1
	headers.add(AUTHORIZATION, String.format("Bearer %s", requestToken(webClient)));
	...
}

//1 Now that we have a token we can send it in the HTTP header every time a resource is requested.

Testing with curl

The procedure described below has been tested on Ubuntu linux only, it may need adjustments on Windows.

First we get a token from the Authorization Server

curl -v -u clientId:clientSecret http://localhost:8080/oauth/token -d grant_type=client_credentials

The Authorization server replies with a JSON payload similar to this one
{
"access_token" : "7c28125d-49e0-46b2-8bf6-4981eaf2943a",
"token_type" : "bearer",
"expires_in" : 42921,
"scope" : "read write read-write"
}

We put the token in a shell variable

Linux:
export TOKEN=7c28125d-49e0-46b2-8bf6-4981eaf2943a

Windows:
set TOKEN=7c28125d-49e0-46b2-8bf6-4981eaf2943a

Every time a resource is requested the token must be sent in the HTTP header “Authorization”

curl -i -X GET -H "Content-Type:application/json" -H "Authorization: Bearer $TOKEN" http://localhost:8080/customers

SSL

Now that authentication and authorization are managed with OAuth2 let’s secure the communication channel with SSL

For ease of use a self-signed certificate will be used which is acceptable for this example, but in real life scenarios a trusted Signed Certificate provided from a Certification Authority should be used.

All files will be generated under src/main/resources

Generate the self-signed certificate

  • cd to src/main/resources
  • keytool -genkey -alias customerservice -keyalg RSA -keysize 2048 -keystore servicestore.jks -validity 3650

The creation wizard will ask a few questions, most of them can be left to Unknown except the password field that has the value qwerty in this example and "First and last name" field that must be localhost,  or the name of the machine where the server will be deployed.

This command will create a keystore named servicestore.jks containing the self-signed certificate

SSL activation

Add the section below to application.properties located under src/main/resources and the service will be available on https://localhost:8443 instead of http://localhost:8080

# SSL configuration
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:servicestore.jks
server.ssl.key-store-password=qwerty
server.ssl.key-password=qwerty

Tests

All class tests will succeed except CustomerServiceTest, that’s because they are either unit tests or integration tests that run in mocked environments where Spring Security is not active.

CustomerServiceTest fails because it’s executed in a real environment, so let’s fix it.

First we need to export the certificate to pem (Privacy-enhanced Electronic Mail) format

  • cd to src/main/resources
  • keytool -exportcert -rfc -keystore servicestore.jks -storepass qwerty -alias customerservice > servicestore.pem

Then we update CustomerServiceTest class to make it use the certificate.

package customerservice;

public class CustomerServiceTest {

	@LocalServerPort
	private int port;

	//1
	@Value("classpath:servicestore.pem")
	private Resource pemResource;

	private WebClient createSSLWebClient() throws IOException {

	//2
	final File pemFile = pemResource.getFile();
	final ClientHttpConnector clientConnector = new ReactorClientHttpConnector(options -> options.sslSupport(builder -> builder.trustManager(pemFile)));

	//3
	return WebClient.builder()
		.baseUrl(String.format("https://127.0.0.1:%d", port))
		.clientConnector(clientConnector)
		.build();
}

// 1
The pem file is injected as a resource

// 2
A reactive ClientHttpConnector is created, this connector uses the self-signed certificate as a trusted certificate.

// 3
The connector is passed to the builder of WebClient and a new instance of the client is returned.

That’s all we need, for the rest of the test SSL management is transparent.

curl

To test with curl we need to export the certificate to p12 format first, to do so we will use the command line tool openssl

  •  cd to src/main/resources
  • keytool -importkeystore -srckeystore servicestore.jks -destkeystore servicestore.pfx -deststoretype PKCS12 -srcalias customerservice -deststorepass qwerty -destkeypass qwerty
  • openssl pkcs12 -in servicestore.pfx -out servicestore.p12 -nodes

To run correctly, curl needs both pem and p12 files:

curl --cacert src/main/resoures/servicestore.pem --cert src/main/resources/servicestore.p12 -v -u clientId:clientSecret https://localhost:8443/oauth/token -d grant_type=client_credentials

The rest is similar to what has been explained previously; a token is first requested, then put into a shell variable and passed in the requests to the Resource Server.

For example, to list all customers:

curl -i -X GET -H "Accept:application/json" -H "Authorization: Bearer $TOKEN" https://localhost:8443/customers --cacert src/main/resources/servicestore.pem --cert src/main/resources/servicestore.p12

That concludes this series on creating a Reactive RESTful service with Spring 5, the source code will be updated with the beta releases of Spring 5 and Boot 2 until the GA is released.

Finally, I would like to thank Station Kaffe for their support and the “darn good” coffee 🙂

Advertisements

Smallest Reactive RESTful service with Spring 5

Spring 5 is around the corner and with it comes a new reactive web framework called WebFlux and a new functional programming model.
Let’s use these features to write the smallest possible Hello world reactive RESTful service.

If you want to see how a more complete Reactive service looks like you can read the series Reactive RESTful service with Spring 5, Spring Boot 2 and MongoDB

public static void main(String[] args) {
	Undertow.builder().addHttpListener(8080, "localhost")
		.setHandler(new UndertowHttpHandlerAdapter(
			toHttpHandler(route(GET("/greetings"), request -> ok().body(fromObject("Hello World"))))))
		.build().start();
}
  1. route() method creates a RouterFunction that maps an HTTP verb to a HandlerFunction. Several mappings can be created by chaining calls to route() like this: route(…).and().route(…).and().route(…)
  2. toHttpHandler() passes the RouterFunction to a generic HTTP Handler
  3. The generic handler is then passed to an HTTP Handler specific to the runtime environment, here we use Undertow hence the specific class UndertowHttpHandlerAdapter
  4. Finally the Undertow server is created and started with build().start()

More on creating routes and using WefFlex in the reference documentation.

The service can be started with mvn spring-boot:run at the root directory of the project and tested in a web browser, with curl or any other client.

test-nano-rest

The full code of the project is available on github.

Reactive RESTful service with Spring 5, Spring Boot 2 and MongoDB (part 1)

In this series I will share my experience on writing a reactive RESTful service with Spring 5 and Spring Boot 2, the goal is to build a simple yet fully functional service: from the entity persistence layer with MongoDB up to the REST layer with WebFlux and security with OAuth2 and SSL

If you are not familiar with Reactive programming and Spring 5’s implementation you can find interesting material here, here and here.

At the time of the writing, the available version of Spring Boot is 2.0.0.BUILD-SNAPSHOT. It brings with it Spring Framework 5.0.0.BUILD-SNAPSHOT which is also the latest version.

Part1 will focus on the core of the service: entities, repositories, REST api and testing. In part2 we will see how to secure the service.

The entire code of the project is available on github

The service

We will develop a very basic reactive service that allows us to manage customers through a REST api.

Used technologies

  • Spring Boot 2.0.0.BUILD-SNAPSHOT
    • Spring 5
    • Spring Data MongoDB Reactive
    • Spring WebFlux
    • Spring Security OAuth2
    • Other Spring modules
  • Embedded MongoDB (for ease of use)
  • Undertow (can be replaced with Tomcat or Jetty)
  • Java 8
  • Maven 3

The project

Let’s start with a Java 8 Maven project that we turn into a Spring Boot project by making the pom inherit from spring-boot-starter-parent. We also add the starter module spring-boot-starter-test for unit tests.
This version of Boot is not available in the public Maven Repository so we need to add a reference to spring-snapshots and spring-milestones repositories. This operation is explained here.

Domain entities

package customerservice.domain;

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(Include.NON_NULL)
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public final class Customer {

	@JsonSerialize(using = ToStringSerializer.class)
	private ObjectId id;
	private String firstName;
	private String lastName;
	private Gender gender;
	@JsonFormat(shape = Shape.STRING)
	private LocalDate birthDate;
	private MaritalStatus maritalStatus;
	private Address address;
	private Map<PhoneType, String> phones;
	private String email;
	@NotNull
	private CustomerType customerType;

	private Customer() {}
	...
}

The class Customer contains information about the customer, the address will be stored in its own class Address that has a one to one relationship with Customer

package customerservice.domain;

@JsonInclude(Include.NON_NULL)
public final class Address {

	private Integer streetNumber;
	private String streetName;
	private String city;
	private String zipcode;
	private String stateOrProvince;
	private String country;

	private Address() {}
	...
}

A few things are worth mentioning here:

  • All entities are immutable.
  • Builders (the Builder pattern) are used to create instances.
  • Jackson annotations @Json* are used to customize serialization and deserialization
    • @JsonIgnoreProperties(ignoreUnknown = true): during deserialization ignore fields that can not be mapped to a Java field
    • @JsonInclude(Include.NON_NULL): don’t serialize fields when they contain Null
    • @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class): output JSON in snake case; “first_name” instead of “firstName”
    • @JsonSerialize(using = ToStringSerializer.class): serialize the String representation of ObjectId (24 hexadecimal characters)
    • @JsonFormat(shape = Shape.STRING): serialize the String representation of Java 8’s LocalDate, if jackson-datatype-jsr310 dependency is present in the classpath then the date will be formatted in ISO-8601 format (yyyy-MM-dd)

Usage

Create a customer

Customer myCustomer = Customer.ofType(CustomerType.PERSON)
    .withFirstName("John")
    .withLastName("Doe")
    .withBirthDate(LocalDate.of(1990, Month.MARCH, 25))
    .build();

The static method ofType() takes a mandatory parameter of type CustomerType and returns a builder, each field of Customer has a corresponding with*() method in the builder to set its value. build() returns a new instance of Customer with the given values.

Create an address

Address myAddress = Address.ofCountry("myCountry")
    .withStreetNumber(110)
    .withStreetName("My street")
    .withCity("My City")
    .build();

For Address the mandatory field is country and the static method returning the builder is ofCountry(), the rest is similar to Customer.

Update a customer

Immutable objects don’t have setters and so a new instance is created every time the value of a field must change.

Customer myCustomer = Customer.ofType(CustomerType.PERSON)
    .withFirstName("John")
    .withLastName("Doe")
    .build();
// Now, myCustomer points to a new instances with updated first name
myCustomer = Customer.from(myCustomer).withFirstName("Jessica").build();

The static method from() takes a parameter of type Customer, creates a builder and initiates its fields with the values of the parameter then returns the builder, with*() methods can then be used to change any field before finally calling build() to return a new instance of Customer.

Update an address

Likewise, we update addresses

Address myAddress = Address.ofCountry("myCountry")
    .withStreetNumber(110)
    .withStreetName("My street")
    .withCity("My City")
    .build();
myAddress = Address.from(myAddress).withStreetNumber(75).build();

Persistence

Spring Data will be used to manage the persistence layer by adding the starter module spring-boot-starter-data-mongodb-reactive to the project, those of you who have already used Spring Data with MongoDB may have noticed the similarity of the name with the “non reactive” counterpart module spring-boot-starter-data-mongodb

We will also add a dependency on embedded MongoDB

<dependency>
 <groupId>de.flapdoodle.embed</groupId>
 <artifactId>de.flapdoodle.embed.mongo</artifactId>
</dependency>

The repository

The repository is created by extending the interface ReactiveCrudRepository

public interface CustomerRepository extends ReactiveCrudRepository<Customer, ObjectId> {}

Just like CrudRepository, the interface ReactiveCrudRepository takes 2 parameters: the type of the entity it is persisting and the type of the primary key of that entity, it also offers the same CRUD methods with a difference, if the method returns an object of type T in CrudRepository then it will return a Mono of T in ReactiveCrudRepository, and if it returns a collection of T in CrudRepository then it will return a Flux of T in ReactiveCrudRepository.

Mono and Flux are the Reactive types Spring Reactive uses, they are similar to Java’s Future and it’s implementation CompletableFuture.

If you want to know more about Reactive types you can read this post.

Also worth mentioning, there is no need to annotate the interface with @Repository, Spring already knows it’s a repository.

Testing

For this test we will bootstrap Spring with the annotation @RunWith(SpringJUnit4ClassRunner.class) because we want to use MongoDB, Spring will take care of starting it and configuring a repository for us, we can then inject the repository in the test class.

@Autowired
private CustomerRepository repo;

@DirtiesContext

Spring offers this interesting annotation that can be used at the class level, it basically resets the context with a clean DB for each test. Maybe I misused it but I noticed that it dramatically slows down tests execution, so I replaced it with a simple repo.deleteAll() in a method annotated with @Before.

@Before
public void cleanDB() {
 repo.deleteAll().block();
}

Example

@Test
public void shouldCreateAPerson() {

 // 1
 Address address = Address.ofCountry("Shadaloo").build();
 // 2
 Customer customer = Customer.ofType(PERSON).withFirstName("Ken").withAddress(address).build()
 // 3
 Customer saved = repo.save(customer).block();

 // 4
 assertThat(saved.getId()).isNotNull();
 assertThat(saved.getFirstName()).isEqualTo("Ken");
 assertThat(saved.getAddress().getCountry()).isEqualTo("Shadaloo");
}

// 1 Create the address
// 2 Create the customer
// 3 Save the customer and block until the Mono associated with repo.save() returns the saved customer, this is very important because of the asynchronous nature or Mono
// 4 Check returned values

The entire test class can be found under src/test/java/customerservice/repository/mongodb

The REST API

Spring 5 comes with a new module called WebFlux which can be seen as the reactive counterpart of Spring MVC, it uses the class DispatcherHandler as the “Central dispatcher for HTTP request handlers/controllers” just like DispatcherServlet in Spring MVC.

Let’s add it to the pom.xml

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

We also add an application server; tomcat, jetty and undertow can be used.

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

The REST api will handle the following requests:

URL HTTP METHOD DESCRIPTION
/customers GET Return all customers
/customers/{id} GET Return one customer
/customers POST Add a new customer
/customers/{id} PUT Update a customer
/customers/{id} DELETE Delete a customer

The REST controller

package customerservice.restapi;
@RestController
@RequestMapping(path = "/customers", produces = { APPLICATION_JSON_UTF8_VALUE })
public class CustomerController {

 private CustomerRepository repo;

 public CustomerController(CustomerRepository repo) {
  this.repo = repo;
 }
 .....
}

The controller handles requests with the path /customers and returns a JSON payload. There is no need to annotate the repository with @Autowired, Spring already knows that we are doing constructor injection and does the necessary injection.

The method to handle a GET on /customers looks like this

@RequestMapping(method = GET)
public Mono<ResponseEntity<List<Customer>>> allCustomers() {
return repo.findAll() //1
 .collectList() //2
 .filter(customers -> customers.size() > 0) //3
 .map(customers -> ok(customers)) //4
 .defaultIfEmpty(noContent().build()); //5
}

//1 findAll() returns a Flux of Customer
//2 The Flux is converted into a Mono of List or Customer
//3 If the list is not empty
//4 then return OK (HTTP 200) response containing the list in the body.
//5 otherwise return NO_CONTENT (HTTP 204) response.

The other methods of the controller are implemented in the same way, we start with a Mono or a Flux returned by the repository, then we pass it through a chain of methods before returning a Mono of ResponseEntity

If you want to do Reactive programming get ready to do a lot of method chaining 🙂

Unit testing

The controller can be unit tested without bootstraping Spring, all we need is to mock the repository and inject it into the controller (This example uses Mockito)

@RunWith(MockitoJUnitRunner.class)
public class CustomerControllerTest {

 @Mock
 private CustomerRepository repo;

 @InjectMocks
 private CustomerController controller;

 @Test
 public void shouldReturnAllCustomers() {

 // Given
 final List<Customer> customers = asList(Customer.ofType(PERSON).build(), Customer.ofType(COMPANY).build());
 when(repo.findAll()).thenReturn(Flux.fromIterable(customers));

 // When
 final ResponseEntity<List<Customer>> response = controller.allCustomers().block();

 // Then
 assertThat(response.getStatusCode()).isEqualTo(OK);
 assertThat((Iterable<Customer>) response.getBody()).asList().containsAll(customers);
}

Controller methods return either a Mono or a Flux, both have a .block() method that blocks until the ResponseEntity is returned. This is not reactive but I think is ok for unit tests.

We will see how to test in a reactive way in the next paragraph.

Integration testing

WebFlux comes with 2 useful classes that can be used for testing: WebClient and WebTestClient.

WebTestClient is comparable to MockMvc when used without a running server and is comparable to TestRestTemplate when used with a running server, whereas WebClient is comparable to RestTemplate.

Let’s see how it works

@RunWith(SpringRunner.class)
public class CustomerControllerIntegrationTest {

 @MockBean
 private CustomerRepository repo;

 private WebTestClient webClient;

 @Before
 public void init() {
  webClient = WebTestClient
   .bindToController(new CustomerController(repo))
   .build();
 }
 ...
}

WebTestClient.bindController() means that we are testing the controller CustomerController in a mocked environment.

Spring has a useful annotation @MockBean that is comparable to Mockito’s @Mock and can be used to mock Spring beans.

@Test
public void shouldReturnAllCustomers() {

List<Customer> mockCustomers = asList(Customer.ofType(PERSON).build(), Customer.ofType(COMPANY).build());
given(repo.findAll()).willReturn(Flux.fromIterable(mockCustomers)); //1

webClient.get().uri("/customers").accept(APPLICATION_JSON_UTF8).exchange() //2
 .expectStatus().isOk() //3
 .expectHeader().contentType(APPLICATION_JSON_UTF8)
 .expectBodyList(Customer.class).hasSize(2).consumeWith(customers -> { //
  assertThat(customers.stream().map(Customer::getCustomerType).collect(toList())
   .containsAll(asList(PERSON, COMPANY)));
 });
}

//1 Mock findAll() with expected behavior.
//2 Issue a GET on /customers
//3 Expect HTTP 200
//4 Expect the list of customers returned by findAll()

Testing with curl

curl is a command line tool that can be used to test RESTful services, it’s available for all platforms.

First we start the Spring Boot application with mvn spring-boot:run, this command must be typed in the root directory of the project where pom.xml is located .

Add a customer

curl -i -X POST -H “Content-Type:application/json” http://localhost:8443/customers -d ‘{“first_name”:”John”,”last_name”:”Doe”,”birth_date”:”1950-01-01″,”customer_type”:”PERSON”,”address”:{“street_name”:”Wellington”,”country”:”canada”}}’

If everything goes well, curl will return HTTP 201, the header Location of the response will contain the URL of the created customer, the hexadecimal numbers after /customers/ is the id of the customer.

HTTP/1.1 201 Created

Location: /customers/5904fde985cc4d1c01ed9c1a

Content-Length: 0

Retrieve a customer

curl -i -X GET -H “Accept:application/json” http://localhost:8443/customers/5904fde985cc4d1c01ed9c1a

We use the id of the customer returned by the previous POST to retrieve a single cusomer, curl will return HTTP 200 and the body will contain a JSON representation of the customer.

HTTP/1.1 200 OK
………..
{
“id” : “5904fde985cc4d1c01ed9c1a”,
“first_name” : “John”,
“last_name” : “Doe”,
“birth_date” : “1990-01-01”,
“address” : {
“country” : “canada”
},
“customer_type” : “PERSON”
}

Notice that the id we pass in the GET request is returned in the field “id” of the response.

Retrieve all customers

curl -i -X GET -H “Accept:application/json” http://localhost:8443/customers

Will return HTTP 200

HTTP/1.1 200 OK
………..
[{
“id” : “5904fde985cc4d1c01ed9c1a”,
“first_name” : “John”,
“last_name” : “Doe”,
“birth_date” : “1990-01-01”,
“address” : {
“country” : “canada”
},
“customer_type” : “PERSON”
}]

This GET always returns a list customers (inside square brackets) even if only one customer is returned.

Delete a customer

curl -i -X DELETE http://localhost:8443/customers/5904fde985cc4d1c01ed9c1a

Will respond with HTTP 204 indicating that the customer has been successfully deleted.

Coming next…

We now have a fully functional Reactive RESTful service, in part2 we will see how to secure it with Auth2 and SSL and the impact it has on tests.

Thanks for reading.

Resources

A Java 8 variation on the Producer-Consumer pattern

This post is an attempt to use Functional Interfaces/Lambdas brought to us by Java 8 with the Producer-Consumer pattern (the BlockingQueue implementation)
If you want to know more about this pattern see the Resources section

Requirements

  • JavaSE 8

Using Functional interfaces

The idea is to make use of java.util.function.Supplier and java.util.function.Consumer interfaces
The former will be responsible for creating the object and passing it to the producer thread to be put in the queue and the latter for consuming that object when the consumer thread retrieves it from the queue

As a consequence of this approach the logic of creating and consuming the queue’s elements will not reside in the threads but passed to them as functions

Let’s see how all this looks like

The producer thread

	class MyProducer<T> {

		private BlockingQueue<T> queue;

		public MyProducer(BlockingQueue<T> queue) {
			this.queue = queue;
		}

		/**
		 * Insert the supplied object in the queue
		 * 
		 * @param supplier
		 *            Is responsible for supplying the object that will be put
		 *            in the queue
		 */
		public void produce(Supplier<T> supplier) {
			final T msg = supplier.get();
			try {
				queue.put(msg);
				out.println("Added message: " + msg);
				
				// Simulate a long running process
				MILLISECONDS.sleep(900);
				
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
		}
	}

Here the produce() method accepts an argument of type Supplier, this functional interface is responsible for creating and returning an object of type T with its get() method

The Consumer thread

class MyConsumer<T> {

	private BlockingQueue<T> queue;

	public MyConsumer(BlockingQueue<T> queue) {
		this.queue = queue;
	}

	/**
	 * Retrieves an object from the head of the queue and passes it to the
	 * consumer
	 * 
	 * @param consumer
	 *            Contains the logic on what to do with the retrieved object
	 */
	public void consume(Consumer<T> consumer) {
		try {
			consumer.accept(queue.take());
				
			// Simulate a long running process
			MILLISECONDS.sleep(1250);
			
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
	}
}

The consume() method receives an argument or type Consumer, this functional interface will contain the logic to consume the retrieved element

Starting the producer thread

	private void startProducer() {

		final MyProducer<String> myProducer = new MyProducer<>(queue);
		final Supplier<String> supplier = () -> "Hello World";
		new Thread(() -> {
			for (int i = 0; i < MSG_NBR; i++) {
				myProducer.produce(supplier);
			}
		}).start();
	}

A simple implementation of the Supplier functional interface, which returns a “Hello World” message is created and passed to the produce() method
The thread is created with Lambda expressions, this way the MyProducer and MyConsumer classes don’t have to implement the Runnable interface
The producer will produce a number of messages hence the loop

Starting the consumer thread

	private void startConsumer() {

		final MyConsumer<String> myConsumer = new MyConsumer<>(queue);
		final Consumer<String> consumer = (s) -> out.println("Consumed message: " + s);
		new Thread(() -> {
			for (int i = 0; i < MSG_NBR; i++)
				myConsumer.consume(consumer);
		}).start();
	}

A simple implementation of the Consumer functional interface, which displays the message is created and passed to the consume() method
The consumer will consume the produced messages inside the loop

Putting it all together

import static java.lang.System.out;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * Starts 2 threads, a producer and a consumer
 * <br>
 * Both threads share the same BlockingQueue
 * 
 * @author Djallal Serradji
 *
 */
public class ProducerConsumer {

	private static final int MSG_NBR = 10;

	private final BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);

	public static void main(String[] args) {
		new ProducerConsumer().startEngine();
	}

	public void startEngine() {
		startProducer();
		startConsumer();
	}

	// Producer thread
	private void startProducer() {

		final MyProducer<String> myProducer = new MyProducer<>(queue);
		final Supplier<String> supplier = () -> "Hello World";
		new Thread(() -> {
			for (int i = 0; i < MSG_NBR; i++) {
				myProducer.produce(supplier);
			}
		}).start();
	}

	// Consumer thread
	private void startConsumer() {

		final MyConsumer<String> myConsumer = new MyConsumer<>(queue);
		final Consumer<String> consumer = (s) -> out.println("Consumed message: " + s);
		new Thread(() -> {
			for (int i = 0; i < MSG_NBR; i++)
				myConsumer.consume(consumer);
		}).start();
	}

	static class MyProducer<T> {

		private BlockingQueue<T> queue;

		public MyProducer(BlockingQueue<T> queue) {
			this.queue = queue;
		}

		/**
		 * Insert the supplied object in the queue
		 * 
		 * @param supplier
		 *            Is responsible for supplying the object that will be put
		 *            in the queue
		 */
		public void produce(Supplier<T> supplier) {
			final T msg = supplier.get();
			try {
				queue.put(msg);
				out.println("Added message: " + msg);
				
				// Simulate a long running process
				MILLISECONDS.sleep(900);
				
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
		}
	}

	static class MyConsumer<T> {

		private BlockingQueue<T> queue;

		public MyConsumer(BlockingQueue<T> queue) {
			this.queue = queue;
		}

		/**
		 * Retrieves an object from the head of the queue and passes it to the
		 * consumer
		 * 
		 * @param consumer
		 *            Contains the logic on what to do with the retrieved object
		 */
		public void consume(Consumer<T> consumer) {
			try {
				consumer.accept(queue.take());
				
				// Simulate a long running process
				MILLISECONDS.sleep(1250);
				
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
		}
	}
}

The project can be found on github

What do you think about this implementation ?
Your comments are welcome.

Resources

Injecting external properties in Java EE 6/7 applications

My first post is about a project I started a few weeks ago after reading a good post from Markus Eisele (here) about injecting external properties into a Java EE 6/7 project with CDI enabled.
External means that the properties files are not packaged inside the war/ear file but instead deployed separately and accessible to the application’s code through its classpath, this is Application Server specific and will not be covered here.

How to generate the jar

The project is available on gitub as source code only but it’s easy to generate the jar file

Requirements

  • Java 1.7
  • Maven 3
  • Git (only needed if you want to clone the project)

Build the project

  • Clone the project (you can also download it as a zip file and import it in your IDE)
  • Type the maven command below to generate the jar file and add it to your local maven repository
    mvn clean install
  • Add the jar to your project dependencies, if you use maven add this snippet to your pom.xml
    		<dependency>
    			<groupId>com.github.djallalserradji</groupId>
    			<artifactId>inject.property</artifactId>
    			<version>${version_you_cloned}</version>
    		</dependency>
    

How it works

Let’s say we have a billing class that needs 3 web services, a Billing web service to process billing information received from customers, an email web service to notify the customer that the billing happened and a SMS web service to notify the customer on their mobile phone if they choose to.

public class BillingService {
	
	private String billingEndpoint;
	private String emailEndpoint;
	private String smsEndpoint;

	// Business logic
	// .........
}

And we want to inject the endpoint URLs stored in the external properties file billing.properties

billing.endpoint=http://billing.company.com
email.endpoint=http://email.company.com
sms.endpoint=http://sms.company.com

First annotate the class with @PropertiesFiles like this

@PropertiesFiles({"billing.properties"})
public class BillingService {

The annotation takes a list of files (coma separated)

Then annotate each field which will receive the value of a property with @Property

@PropertiesFiles({"billing.properties"})
public class BillingService {
	
	@Property("billing.endpoint")
	@Inject
	private String billingEndpoint;
	
	@Property("email.endpoint")
	@Inject
	private String emailEndpoint;
	
	@Property("sms.endpoint")
	@Inject
	private String smsEndpoint;
	
	// Business logic
	// .........
}

@Property takes a single parameter that represents the name of the property
Please note that @Inject annotation is mandatory in order for the injection to happen.

That’s it!

Alternatively, if you don’t want to use the class annotation @PropertiesFiles you can list all the properties files in a single configuration file named inject.property.xml (they will be available to all classes), this file must be available in the classpath (either packaged inside the war/ear or externally available) and has this structure:

<propertiesfiles>
	<file>file1.properties</file>
	<file>file2.properties</file>
	<file>...</file>
</propertiesfiles>

Important:

If a class is annotated with @PropertiesFiles the configuration file is ignored

The source code is available on gitub

Thank you for reading.
Your comments are welcome.