Sunday, March 30, 2014

Spring-boot and Scala

There is actually nothing very special about writing a Spring-boot web application purely using Scala, it just works!

In this blog entry, I will slowly transform a Java based Spring-boot application completely to Scala - the Java based sample is available at this github location - https://github.com/bijukunjummen/spring-boot-mvc-test

To start with, I had the option of going with either a maven based build or gradle based build - I opted to go with a gradle based build as gradle has a great scala plugin, so for scala support the only changes to a build.gradle build script is the following:


...
apply plugin: 'scala'
...
jar {
    baseName = 'spring-boot-scala-web'
    version =  '0.1.0'
}


dependencies {
    ... 
    compile 'org.scala-lang:scala-library:2.10.2'
    ...
}

Essentially adding in the scala plugin and specifying the version of the scala-library.

Now, I have one entity, a Hotel class, it transforms to the following with Scala:

package mvctest.domain

....

@Entity
class Hotel {
  
  @Id 
  @GeneratedValue 
  @BeanProperty
  var id: Long = _
  
  @BeanProperty
  var name: String = _
  
  @BeanProperty
  var address: String = _
  
  @BeanProperty
  var zip: String = _
}

Every property is annotated with @BeanProperty annotation to instruct scala to generate the Java bean based getter and setter on the variables.

With the entity in place a Spring-data repository for CRUD operations on this entity transforms from:

import mvctest.domain.Hotel;

import org.springframework.data.repository.CrudRepository;

public interface HotelRepository extends CrudRepository<Hotel, Long> {

}

to the following in Scala:

import org.springframework.data.repository.CrudRepository
import mvctest.domain.Hotel
import java.lang.Long

trait HotelRepository extends CrudRepository[Hotel, Long]

And the Scala based controller which uses this repository to list the Hotels -

...
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.stereotype.Controller
import mvctest.service.HotelRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.ui.Model

@Controller
@RequestMapping(Array("/hotels"))
class HotelController @Autowired() (private val hotelRepository: HotelRepository) {
 
  @RequestMapping(Array("/list"))
  def list(model: Model) = {
    val hotels = hotelRepository.findAll()
    model.addAttribute("hotels", hotels)
    "hotels/list"
  }
}

Here the constructor autowiring of the HotelRepository just works!. Do note the slightly awkward way of specifying the @Autowired annotation for constructor based injection.

Finally, Spring-boot based application requires a main class to bootstrap the entire application, where this bootstrap class looks like this with Java:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class SampleWebApplication {
 
 public static void main(String[] args) {
  SpringApplication.run(SampleWebApplication.class, args);
 }
}

In scala, though I needed to provide two classes, one to specify the annotation and other to bootstrap the application, there may be better way to do this(blame it on my lack of Scala depth!) -

package mvctest

import org.springframework.context.annotation.Configuration
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.context.annotation.ComponentScan
import org.springframework.boot.SpringApplication

@Configuration
@EnableAutoConfiguration
@ComponentScan
class SampleConfig


object SampleWebApplication extends App {
  SpringApplication.run(classOf[SampleConfig]);
}

and that's it, with this set-up the entire application just works, the application can be started up with the following:

./gradlew build && java -jar build/libs/spring-boot-scala-web-0.1.0.jar

and the sample endpoint listing the hotels accessed at this url: http://localhost:8080/hotels/list

I have the entire git project available at this github location: https://github.com/bijukunjummen/spring-boot-scala-web

In conclusion, Scala can be considered a first class citizen for a Spring-boot based application and there is no special configuration required to get a Scala based Spring-boot application to work. It just works!

Wednesday, March 26, 2014

Servlet 3.0 ServletContainerInitializer and Spring WebApplicationInitializer

Spring WebApplicationInitializer provides a programatic way to configure the Spring DispatcherServlet and ContextLoaderListener in Servlet 3.0+ compliant servlet containers , rather than adding this configuration through a web.xml file.

This is a quick note to show how implementation through WebApplicationInitializer interface internally works, given that this interface does not derive from any Servlet related interface!

The answer is the ServletContainerInitializer interface introduced with Servlet 3.0 specification, implementors of this interface are notified during the context startup phase and can perform any programatic registration through the provided ServletContext.

Spring implements the ServletContainerInitializer through SpringServletContainerInitializer class. Per the Servlet specs, this implementation must be declared in a META-INF/services/javax.servlet.ServletContainerInitializer file of the libraries jar file - Spring declares this in spring-web*.jar jar file and has an entry `org.springframework.web.SpringServletContainerInitializer`

SpringServletContainerInitializer class has a @HandlerTypes annotation with a value of WebApplicationInitializer, this means that the Servlet container will scan for classes implementing the WebApplicationInitializer implementation and call the onStartUp method with these classes and that is where the WebApplicationInitializer fits in.

A little convoluted, but the good thing is all these details are totally abstracted away within the spring-web framework and the developer only has to configure an implementation of WebApplicationInitializer and live in a web.xml free world.

Sunday, March 16, 2014

Java 8 functional interfaces - random musings implementing a Scala type

In one of the assignments of the Functional programming with Scala course a type called Terrain is introduced - Terrain represents a region, parts of which are accessible and parts which are not. So in a very clever way Terrain is defined the following way in the assignment:

case class Pos(x:Int, y: Int)

type Terrain = Pos => Boolean

Essentially Terrain is a function which takes a position and for that position returns a boolean based on whether the position is accessible or not!

Given this definition of Terrain, a way to define an "infinite" terrain where every position is accessible is done this way:

val infiniteTerrain = (pos: Pos) => true

or another terrain, where certain coordinates are accessible can be defined this way:

def terrainFunction(vector: Vector[Vector[Char]]) : Terrain = {
 (pos: Pos) => {
  if (pos.x > vector.size - 1 || pos.y > vector(0).size - 1 || pos.x < 0 || pos.y < 0) {
   false
  } else {
   val ch = vector(pos.x)(pos.y)
   ch == 'o';
  }
 }
}  

val terrain1 = terrainFunction(Vector(
     Vector('-','-','-'),
     Vector('-','o','-'),
     Vector('-','o','-'),
     Vector('-','o','-'),
     Vector('-','-','-')
     )
    )


All extremely clever.

Now, given that Java 8 release is imminent, an equally(almost :-) ) clever code can be attempted using Java 8 constructs:

whereas the Terrain could be defined as a function signature in Scala, it has to be defined as a functional interface with Java 8:

interface Terrain {
 public boolean isAccessible(Pos pos);
}

Given this interface, an infinite terrain looks like this using Lambdas in Java 8:

Terrain infiniteTerrain = (pos) -> true;

The terrainFunction equivalent in Java 8 can be defined along these lines:

public Terrain terrainFunction(char[][] arr) {
 return (pos) -> {
  if (pos.x > arr.length - 1 || pos.y > arr[0].length - 1 || pos.x < 0 || pos.y < 0) {
   return false;
  } else {
   char ch = arr[pos.x][pos.y];
   return ch == 'o';
  }
 };
}
 
char[][] arr = {
 {'-','-','-'},
 {'-','o','-'},
 {'-','o','-'},
 {'-','o','-'},
 {'-','-','-'}
};
Terrain terrain = terrainFunction(arr); 

assertTrue(terrain.isAccessible(new Pos(1, 1)));

Close enough!

Saturday, March 8, 2014

Websockets with Spring 4

I am throwing the entire kitchen sink into a small web application that I am developing as part of this post - Spring Boot, Spring Integration, RabbitMQ and finally the topic of the post, the Websocket support in Spring MVC with Spring 4.

Real-time quake listing application

The final app will list the earthquake occurrences around the world and is updated in realtime(if a minute can be considered realtime enough), along these lines:



Storing the Quake Information

The first part of the application is polling the data from USGS Earthquake hazards program every minute and storing it. I have chosen to store it directly into a RabbitMQ topic, which will be later used for the Websockets integration. Spring Integration is a great fit for the requirements of such a feature - using just configuration I can poll the USGS service providing a json feed of this information and write it to a RabbitMQ topic.

This is how this flow looks:


and a raw complete Spring integration flow for the same is the following, the only code missing here is the configuration for rabbitmq which is part of another configuration file:

<import resource="rabbit-context.xml"/>
 <int:inbound-channel-adapter channel="quakeinfotrigger" expression="''">
  <int:poller fixed-delay="60000"></int:poller>
 </int:inbound-channel-adapter>
 
 <int:channel id="quakeinfo"/>

 <int:channel id="quakeinfotrigger"></int:channel>

 <int-http:outbound-gateway id="quakerHttpGateway"
     request-channel="quakeinfotrigger"
     url="http://earthquake.usgs.gov/earthquakes/feed/geojson/all/hour"
     http-method="GET"
     expected-response-type="java.lang.String"
     charset="UTF-8"
     reply-channel="quakeinfo">
 </int-http:outbound-gateway>

 <int-amqp:outbound-channel-adapter amqp-template="amqpTemplate" channel="quakeinfo" />


So, now that I have a flow which collects the Earthquake information and stores it into a RabbitMQ topic called "amq.topic" and internally plugs in a routing key of "quakes.all" to each of the quake information message, the next step is to figure out how to show this information dynamically on the browser application.

Presenting the Quake information

Spring Framework 4.0+ makes it easy to develop the web part of the application with the Websocket based messaging support now built into the framework. Spring 4.0 uses the STOMP as higher level protocol over raw websockets - I have included references which provide much more clarity on the details of the Websocket support.

In essence, Spring will act as a intermediary for the browser to subscribe to the RabbitMQ quakes topic and display realtime information as new quake information flows in, this diagram from the references sums this up well:


Spring 4 Websockets support with an external broker requires the broker to support STOMP protocol, which is easy to enable with RabbitMQ. With the STOMP support in RabbitMQ in place, the Spring MVC configuration looks like this:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

 @Override
 public void configureMessageBroker(MessageBrokerRegistry config) {
  config.enableStompBrokerRelay("/topic/");
  config.setApplicationDestinationPrefixes("/app");
 }

 @Override
 public void registerStompEndpoints(StompEndpointRegistry registry) {
  registry.addEndpoint("/quakesep").withSockJS();
 }
}


  • "/topic" is being registered as a endpoint where Spring acts as a gateway to the RabbitMQ STOMP support
  • "/app" is the application prefix where Spring MVC will listen for browser requests encoded within the STOMP message frame, in this specific instance I am not getting any requests from the UI and so this endpoint is not really used
  • "/quakesep" is the websocket endpoint

This is all that is required on the server side!

Now for the client to subscribe to the message in the RabbitMQ topic, I have implemented it along the lines of the sample in one of the reference articles. The sample uses sockjs client, a javascript library for websocket emulation in browsers.

This is how the javascript code to connect to the websocket endpoint "/quakesep" and subscribing to the "/topic/quakes.all" endpoint looks like. This internally registers a temporary queue with RabbitMQ for this websocket session and maps a AMQP routing key of "quakes.all" to this temporary queue, in essence sending all the quake messages to the temporary queue for the session.

function connect() {
      var socket = new SockJS('/quakesep');
      stompClient = Stomp.over(socket);
      stompClient.connect({}, function(frame) {
          console.log('Connected: ' + frame);
          stompClient.subscribe('/topic/quakes.all', function(message){
              showQuakeInfo(message.body);
          });
      });
  }

the showQuakeInfo function above simply displays fresh quake information when available from RabbitMQ.




The entire sample was put together with Spring Boot, this has ensured that the dependencies declared in the pom file is kept to a bare minimum, the amount of configuration to start up the application is surprisingly small - essentially the WebSocketConfig code that I displayed above!

I have the code available here in github

References

1. Websocket architecture in Spring Framework
2. Webinar on building Websocket based applications using Spring Framework