Tuesday, November 11, 2014

Spring boot war packaging

Spring boot recommends creating an executable jar with an embedded container(tomcat or jetty) during build time and using this executable jar as a standalone process at runtime. It is common however to deploy applications to an external container instead and Spring boot provides packaging the applications as a war specifically for this kind of a need.

My focus here is not to repeat the already detailed Spring Boot instructions on creating the war artifact, but on testing the created file to see if it would reliably work on a standalone container. I recently had an issue when creating a war from a Spring Boot project and deploying it on Jetty and this is essentially a learning from that experience.

The best way to test if the war will work reliably will be to simply use the jetty-maven and/or the tomcat maven plugin, with the following entries to the pom.xml file:

<plugin>
 <groupId>org.apache.tomcat.maven</groupId>
 <artifactId>tomcat7-maven-plugin</artifactId>
 <version>2.2</version>
</plugin>
<plugin>
 <groupId>org.eclipse.jetty</groupId>
 <artifactId>jetty-maven-plugin</artifactId>
 <version>9.2.3.v20140905</version>
</plugin>

With the plugins in place, starting up the war with the tomcat plugin:
mvn tomcat7:run

and with the jetty plugin:
mvn jetty:run

If there any issues with the way the war has been created, it should come out at start-up time with these containers. For eg, if I were to leave in the embedded tomcat dependencies:

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

then when starting up the maven tomcat plugin, an error along these lines will show up:
java.lang.ClassCastException: org.springframework.web.SpringServletContainerInitializer cannot be cast to javax.servlet.ServletContainerInitializer

an indication of a servlet jar being packaged with the war file, fixed by specifying the scope as provided in the maven dependencies:
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-tomcat</artifactId>
 <scope>provided</scope>
</dependency> 

why both jetty and tomcat plugins, the reason is I saw a difference in behavior specifically with websocket support with jetty as the runtime and not in tomcat. So consider the websocket dependencies which are pulled in the following way:
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-websocket</artifactId>
</dependency> 

This gave me an error when started up using the jetty runtime, and the fix again is to mark the underlying tomcat dependencies as provided, replace above with the following:

<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-websocket</artifactId>
</dependency>
<dependency>
 <groupId>org.apache.tomcat.embed</groupId>
 <artifactId>tomcat-embed-websocket</artifactId>
 <scope>provided</scope>
</dependency>
<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-messaging</artifactId>
</dependency>

So to conclude, a quick way to verify if the war file produced for a Spring-boot application will cleanly deploy to a container(atleast tomcat and jetty) is to add the tomcat and jetty maven plugins and use these plugins to start the application up. Here is a sample project demonstrating this - https://github.com/bijukunjummen/spring-websocket-chat-sample.git

Wednesday, November 5, 2014

Spring boot based websocket application and capturing http session id

I was involved in a project recently where we needed to capture the http session id for a websocket request - the reason was to determine the number of websocket sessions utilizing the same underlying http session

The way to do this is based on a sample utilizing the new spring-session module and is described here.

The trick to capturing the http session id is in understanding that before a websocket connection is established between the browser and the server, there is a handshake phase negotiated over http and the session id is passed to the server during this handshake phase.

Spring Websocket support provides a nice way to register a HandShakeInterceptor, which can be used to capture the http session id and set this in the sub-protocol(typically STOMP) headers. First, this is the way to capture the session id and set it to a header:

public class HttpSessionIdHandshakeInterceptor implements HandshakeInterceptor {

 @Override
 public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
  if (request instanceof ServletServerHttpRequest) {
   ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
   HttpSession session = servletRequest.getServletRequest().getSession(false);
   if (session != null) {
    attributes.put("HTTPSESSIONID", session.getId());
   }
  }
  return true;
 }

 public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
 }
}

And to register this HandshakeInterceptor with Spring Websocket support:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketDefaultConfig extends AbstractWebSocketMessageBrokerConfigurer {

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

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

 @Bean
 public HttpSessionIdHandshakeInterceptor httpSessionIdHandshakeInterceptor() {
  return new HttpSessionIdHandshakeInterceptor();
 }

}

Now that the session id is a part of the STOMP headers, this can be grabbed as a STOMP header, the following is a sample where it is being grabbed when subscriptions are registered to the server:

@Component
public class StompSubscribeEventListener implements ApplicationListener<SessionSubscribeEvent> {

 private static final Logger logger = LoggerFactory.getLogger(StompSubscribeEventListener.class);

 @Override
 public void onApplicationEvent(SessionSubscribeEvent sessionSubscribeEvent) {
  StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(sessionSubscribeEvent.getMessage());
  logger.info(headerAccessor.getSessionAttributes().get("HTTPSESSIONID").toString());
 }
}

or it can be grabbed from a controller method handling websocket messages as a MessageHeaders parameter:

@MessageMapping("/chats/{chatRoomId}")
 public void handleChat(@Payload ChatMessage message, @DestinationVariable("chatRoomId") String chatRoomId, MessageHeaders messageHeaders, Principal user) {
  logger.info(messageHeaders.toString());
  this.simpMessagingTemplate.convertAndSend("/topic/chats." + chatRoomId, "[" + getTimestamp() + "]:" + user.getName() + ":" + message.getMessage());
 }

Here is a complete working sample which implements this pattern.

Friday, October 31, 2014

Spring Caching abstraction and Google Guava Cache

Spring provides a great out of the box support for caching expensive method calls. The caching abstraction is covered in a great detail here.

My objective here is to cover one of the newer cache implementations that Spring now provides with 4.0+ version of the framework - using Google Guava Cache

In brief, consider a service which has a few slow methods:

public class DummyBookService implements BookService {

 @Override
 public Book loadBook(String isbn) {
  // Slow method 1.

 }

 @Override
 public List<Book> loadBookByAuthor(String author) {
  // Slow method 2
 }

}

With Spring Caching abstraction, repeated calls with the same parameter can be sped up by an annotation on the method along these lines - here the result of loadBook is being cached in to a "book" cache and listing of books cached into another "books" cache:

public class DummyBookService implements BookService {

 @Override
 @Cacheable("book")
 public Book loadBook(String isbn) {
  // slow response time..

 }

 @Override
 @Cacheable("books")
 public List<Book> loadBookByAuthor(String author) {
  // Slow listing
 }
}

Now, Caching abstraction support requires a CacheManager to be available which is responsible for managing the underlying caches to store the cached results, with the new Guava Cache support the CacheManager is along these lines:

@Bean
public CacheManager cacheManager() {
 return new GuavaCacheManager("books", "book");
}

Google Guava Cache provides a rich API to be able to pre-load the cache, set eviction duration based on last access or created time, set the size of the cache etc, if the cache is to be customized then a guava CacheBuilder can be passed to the CacheManager for this customization:

@Bean
public CacheManager cacheManager() {
 GuavaCacheManager guavaCacheManager =  new GuavaCacheManager();
 guavaCacheManager.setCacheBuilder(CacheBuilder.newBuilder().expireAfterAccess(30, TimeUnit.MINUTES));
 return guavaCacheManager;
}

This works well if all the caches have a similar configuration, what if the caches need to be configured differently - for eg. in the sample above, I may want the "book" cache to never expire but the "books" cache to have an expiration of 30 mins, then the GuavaCacheManager abstraction does not work well, instead a better solution is actually to use a SimpleCacheManager which provides a more direct way to get to the cache and can be configured this way:

@Bean
public CacheManager cacheManager() {
 SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
 GuavaCache cache1 = new GuavaCache("book", CacheBuilder.newBuilder().build());
 GuavaCache cache2 = new GuavaCache("books", CacheBuilder.newBuilder()
             .expireAfterAccess(30, TimeUnit.MINUTES)
             .build());
 simpleCacheManager.setCaches(Arrays.asList(cache1, cache2));
 return simpleCacheManager;
}

This approach works very nicely, if required certain caches can be configured to be backed by a different caching engines itself, say a simple hashmap, some by Guava or EhCache some by distributed caches like Gemfire.


Wednesday, October 22, 2014

Docker RabbitMQ cluster

I have been trying to create a Docker based RabbitMQ cluster on and off for sometime and got it working today - fairly basic and flaky but could be a good starting point for others to improve on.

This is how the sample cluster looks on my machine, this is a typical cluster described in the RabbitMQ clustering guide available here - https://www.rabbitmq.com/clustering.html. As recommended at the site, there are 2 disk based nodes and 1 RAM based node here.



To quickly replicate this, you only need to have fig in your machine, just create a fig.yml file with the following entry:

rabbit1:
  image: bijukunjummen/rabbitmq-server
  hostname: rabbit1
  ports:
    - "5672:5672"
    - "15672:15672"

rabbit2:
  image: bijukunjummen/rabbitmq-server
  hostname: rabbit2
  links:
    - rabbit1
  environment: 
   - CLUSTERED=true
   - CLUSTER_WITH=rabbit1
   - RAM_NODE=true

rabbit3:
  image: bijukunjummen/rabbitmq-server
  hostname: rabbit3
  links:
    - rabbit1
    - rabbit2
  environment: 
   - CLUSTERED=true
   - CLUSTER_WITH=rabbit1   

and in the folder holding this file, run:

  fig up

That is it!, the entire cluster should come up. If you need more nodes, just modify the fig.yml file.

The docker files for creating the dockerized rabbitmq-server is available at my github repo here: https://github.com/bijukunjummen/docker-rabbitmq-cluster and the "rabbitmq-server" image itself is here at the docker hub.

References:

Monday, October 13, 2014

Spring @Configuration - RabbitMQ connectivity

I have been playing around with converting an application that I have, to use Spring @Configuration mechanism to configure connectivity to RabbitMQ - originally I had the configuration described using an xml bean definition file.

So this was my original configuration:

<beans ...;>

 <context:property-placeholder/>
 <rabbit:connection-factory id="rabbitConnectionFactory" username="${rabbit.user}" host="localhost" password="${rabbit.pass}" port="5672"/>
 <rabbit:template id="amqpTemplate"
      connection-factory="rabbitConnectionFactory"
      exchange="rmq.rube.exchange"
      routing-key="rube.key"
      channel-transacted="true"/>

 <rabbit:queue name="rmq.rube.queue" durable="true"/>

 <rabbit:direct-exchange name="rmq.rube.exchange" durable="true">
  <rabbit:bindings>
   <rabbit:binding queue="rmq.rube.queue" key="rube.key"></rabbit:binding>
  </rabbit:bindings>
 </rabbit:direct-exchange>


</beans>

This is a fairly simple configuration that :

  • sets up a connection to a RabbitMQ server,
  • creates a durable queue(if not available)
  • creates a durable exchange
  • and configures a binding to send messages to the exchange to be routed to the queue based on a routing key called "rube.key"

This can be translated to the following @Configuration based java configuration:

@Configuration
public class RabbitConfig {

 @Autowired
 private ConnectionFactory rabbitConnectionFactory;

 @Bean
 DirectExchange rubeExchange() {
  return new DirectExchange("rmq.rube.exchange", true, false);
 }

 @Bean
 public Queue rubeQueue() {
  return new Queue("rmq.rube.queue", true);
 }

 @Bean
 Binding rubeExchangeBinding(DirectExchange rubeExchange, Queue rubeQueue) {
  return BindingBuilder.bind(rubeQueue).to(rubeExchange).with("rube.key");
 }

 @Bean
 public RabbitTemplate rubeExchangeTemplate() {
  RabbitTemplate r = new RabbitTemplate(rabbitConnectionFactory);
  r.setExchange("rmq.rube.exchange");
  r.setRoutingKey("rube.key");
  r.setConnectionFactory(rabbitConnectionFactory);
  return r;
 }
}

This configuration should look much more simpler than the xml version of the configuration. I am cheating a little here though, you should be seeing a missing connectionFactory which is just being injected into this configuration, where is that coming from..this is actually part of a Spring Boot based application and there is a Spring Boot Auto configuration for RabbitMQ connectionFactory based on whether the RabbitMQ related libraries are present in the classpath.

Here is the complete configuration if you are interested in exploring further - https://github.com/bijukunjummen/rg-si-rabbit/blob/master/src/main/java/rube/config/RabbitConfig.java

References:

  • Spring-AMQP project here
  • Spring-Boot starter project using RabbitMQ here

Saturday, October 11, 2014

Spring @Configuration and injecting bean dependencies as method parameters

One of the ways Spring recommends injecting inter-dependencies between beans is shown in the following sample copied from the Spring's reference guide here:

@Configuration
public class AppConfig {

 @Bean
 public Foo foo() {
  return new Foo(bar());
 }

 @Bean
 public Bar bar() {
  return new Bar("bar1");
 }

}
So here, bean `foo` is being injected with a `bar` dependency.

However, there is one alternate way to inject dependency that is not documented well, it is to just take the dependency as a `@Bean` method parameter this way:

@Configuration
public class AppConfig {

 @Bean
 public Foo foo(Bar bar) {
  return new Foo(bar);
 }

 @Bean
 public Bar bar() {
  return new Bar("bar1");
 }

}

There is a catch here though, the injection is now by type, the `bar` dependency would be resolved by type first and if duplicates are found, then by name:

@Configuration
public static class AppConfig {

 @Bean
 public Foo foo(Bar bar1) {
  return new Foo(bar1);
 }

 @Bean
 public Bar bar1() {
  return new Bar("bar1");
 }

 @Bean
 public Bar bar2() {
  return new Bar("bar2");
 }
}

In the above sample dependency `bar1` will be correctly injected. If you want to be more explicit about it, an @Qualifer annotation can be added in:

@Configuration
public class AppConfig {

 @Bean
 public Foo foo(@Qualifier("bar1") Bar bar1) {
  return new Foo(bar1);
 }

 @Bean
 public Bar bar1() {
  return new Bar("bar1");
 }

 @Bean
 public Bar bar2() {
  return new Bar("bar2");
 }
}


So now the question of whether this is recommended at all, I would say yes for certain cases. For eg, had the bar bean been defined in a different @Configuration class , the way to inject the dependency then is along these lines:

@Configuration
public class AppConfig {

 @Autowired
 @Qualifier("bar1")
 private Bar bar1;

 @Bean
 public Foo foo() {
  return new Foo(bar1);
 }

}

I find the method parameter approach simpler here:

@Configuration
public class AppConfig {

 @Bean
 public Foo foo(@Qualifier("bar1") Bar bar1) {
  return new Foo(bar1);
 }

}


Thoughts?

Sunday, September 28, 2014

Spring WebApplicationInitializer and ApplicationContextInitializer confusion

These are two concepts that I mix up occasionally - a WebApplicationInitializer and an ApplicationContextInitializer, and wanted to describe each of them to clarify them for myself.

I have previously blogged about WebApplicationInitializer here and here. It is relevant purely in a Servlet 3.0+ spec compliant servlet container and provides a hook to programmatically configure the servlet context. How does this help - you can have a web application without potentially any web.xml file, typically used in a Spring based web application to describe the root application context and the Spring web front controller called the DispatcherServlet. An example of using WebApplicationInitializer is the following:

public class CustomWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
 @Override
 protected Class<?>[] getRootConfigClasses() {
  return new Class<?>[]{RootConfiguration.class};
 }

 @Override
 protected Class<?>[] getServletConfigClasses() {
  return new Class<?>[]{MvcConfiguration.class};
 }

 @Override
 protected String[] getServletMappings() {
  return new String[]{"/"};
 }
}

Now, what is an ApplicationContextInitializer. It is essentially code that gets executed before the Spring application context gets completely created. A good use case for using an ApplicationContextInitializer would be to set a Spring environment profile programmatically, along these lines:

public class DemoApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

 @Override
 public void initialize(ConfigurableApplicationContext ac) {
  ConfigurableEnvironment appEnvironment = ac.getEnvironment();
  appEnvironment.addActiveProfile("demo");

 }
}

If you have a Spring-Boot based application then registering an ApplicationContextInitializer is fairly straightforward:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class SampleWebApplication {
 
 public static void main(String[] args) {
  new SpringApplicationBuilder(SampleWebApplication.class)
    .initializers(new DemoApplicationContextInitializer())
    .run(args);
 }
}

For a non Spring-Boot Spring application though, it is a little more tricky, if it is a programmatic configuration of web.xml, then the configuration is along these lines:
public class CustomWebAppInitializer implements WebApplicationInitializer {

 @Override
 public void onStartup(ServletContext container) {
  AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
  rootContext.register(RootConfiguration.class);
  ContextLoaderListener contextLoaderListener = new ContextLoaderListener(rootContext);
  container.addListener(contextLoaderListener);
  container.setInitParameter("contextInitializerClasses", "mvctest.web.DemoApplicationContextInitializer");
  AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
  webContext.register(MvcConfiguration.class);
  DispatcherServlet dispatcherServlet = new DispatcherServlet(webContext);
  ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", dispatcherServlet);
  dispatcher.addMapping("/");
 }
}

If it a normal web.xml configuration then the initializer can be specified this way:
<context-param>
    <param-name>contextInitializerClasses</param-name>
    <param-value>com.myapp.spring.SpringContextProfileInit</param-value>
</context-param>

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

So to conclude, except for the Initializer suffix, both WebApplicationInitializer and ApplicationContextInitializer serve fairly different purposes. Whereas the WebApplicationInitializer is used by a Servlet Container at startup of the web application and provides a way for programmatic creating a web application(replacement for a web.xml file), ApplicationContextInitializer provides a hook to configure the Spring application context before it gets fully created.