Spring-Session Grails Plugin (Part 1)

| | grails java spring-session

Fork me on GitHub

This tutorial will guide you how to configure and use spring-session grails plugin in grails 2x application. This blog will also cover various datastore currently supported by this plugin along with serializers to serialize/deserialize your session to/from the store.

This blog is divided into 3 sections

  1. Introduction
  2. Installation
  3. Redis Datastore

1. Introduction

This grails plugin helps you to easily setup Spring Session project in your grails application.

What is Spring Session?

Spring Session is project of Spring community which provides an API and implementations for managing a user’s session information. It allows you to store user’s session in datastore such as Redis, MongoDB, JDBC, Hazelcast, Gemfire etc. You can easily change from one datastore to another.

How it is better than traditional way of storing user’s session? Well in Spring session you don’t need to add any kind of jar inside the Servlet Container (tomcat, jetty etc), which means, no container specific dependency. Session management related API (jar) will be inside your application itself. So one container can contain more than one applications which might be using different types of datastore to store user’s session. Which also helps in migrating from one container to another or switch to another vendor (i.e. Tomcat to Jetty).

Other features offered by spring-session:

  • Clustered Sessions - It trivial to support clustered sessions without being tied to an application container specific solution.
  • Multiple Browser Sessions - Spring Session supports managing multiple users’ sessions in a single browser instance (i.e. multiple authenticated accounts similar to Google).
  • RESTful APIs - Spring Session allows providing session ids in headers to work with RESTful APIs.
  • WebSocket Support - provides the ability to keep the HttpSession alive when receiving WebSocket messages.

By using this plugin you can achieve above features in your grails application.

Note: Spring Session project supports various datastore, which are not configured in this plugin yet. Those datastores are under development. If you wish to contribute in adding datastore support just fork me on GitHub.

2. Installation

Plugin configuration is very easy. If you’re using grails 2x then add following code in your BuildConfig.groovy inside the plugins block

plugins {
    ...
    compile "org.grails.plugins:spring-session:2.0.0-RC1"
}

Note: By Default plugin will use Redis as it’s default datastore. Currently it supports Redis, Mongo and JDBC store to persist session.

Currently, this plugin supports 3 datastore.

  1. Redis
  2. Mongo
  3. JDBC

This blog will cover Redis datastore. Other datastores will be covered in next blog.

1. Redis

Initially spring-session project supported only redis datastore. So the Redis is the default datasotre for this plugin. To change datastore you need to set below property in your Config.groovy file.

springsession.sessionStore=SessionStore.REDIS

Make sure redis server is running on your system. To verify plugin is working, just create a dummy controller in your app. Let’s say you’ve created controller called HomeController.

package demo

class HomeController {

    def index() {
        render "Hello from home controller"
    }
}

Now run your grails application and once your app is up then run the below command on terminal.

curl -c - localhost:8080/g2ss/home/index

#Output
#HttpOnly_localhost    FALSE    /g2ss/    FALSE    0    SESSION    9c3796b4-90d1-4f51-b340-4dc857f6cdd2

You will notice the response with session cookie name SESSION with it’s value 9c3796b4-90d1-4f51-b340-4dc857f6cdd2. Cheers!!! Your plugin is configured successfully.

If you wish to override plugin’s default configuration, well that is very easy. You need to change the property related to that functionality. e.g. Default cookie name is SESSION. To change cookie name you need to change following property in your Config.groovy.

springsession.strategy.cookie.name="SPRING_SESSION"

Let’s checkout some properties with their impact on plugin.

Common properties
springsession.maxInactiveIntervalInSeconds=1800 // Session timeout. default is 1800 seconds
springsession.sessionStore=SessionStore.REDIS // Select session store. Default is REDIS
springsession.defaultSerializer=Serializer.JDK // Serialization mechanism, currently supports JDK & JSON Based. Default is JDK
springsession.strategy.defaultStrategy=SessionStrategy.COOKIE // session tracking mechanism. Default is COOKIE also suports HEADER
springsession.strategy.cookie.name="SESSION" // session cookie name. Default is SESSION
springsession.strategy.httpHeader.headerName="x-auth-token" // session header token name. Default is x-auth-token
springsession.allow.persist.mutable=false // check https://github.com/jeetmp3/spring-session/issues/5 for more detail. Default value is false.
Redis store specific properties
springsession.redis.connectionFactory.hostName="localhost" // Redis server hostname. default is localhost
springsession.redis.connectionFactory.port=6397 // Redis server port. default is 6397
springsession.redis.connectionFactory.timeout=2000 // Redis server connection timeout. default is 2000
springsession.redis.connectionFactory.usePool=true // To use connection pool. default is true
springsession.redis.connectionFactory.dbIndex=0 // Database number. Default is 0
springsession.redis.connectionFactory.password=null // Redis server password. Default is null
springsession.redis.connectionFactory.convertPipelineAndTxResults=true // Specifies if pipelined results should be converted to the expected data type. Default is true

springsession.redis.poolConfig.maxTotal=8 // Pool config maximum active connections. Default is 8
springsession.redis.poolConfig.maxIdle=8 // Pool config maximum idle connections. Default is 8
springsession.redis.poolConfig.minIdle=0 // Pool config minimum active connections. Default is 0

springsession.redis.sentinel.master=null // Redis sentinal master node name. Default is null
springsession.redis.sentinel.nodes=[] // List of Map sentinal nodes. e.g. [ [host: 'localhost', port: 6379], [host: '', port: 0] ]. Default is blank
springsession.redis.sentinel.password=null // Redis sentinal password. Default is null
springsession.redis.sentinel.timeout=2000 // Redis sentinal timeout. Default is 2000
JSON serialization specific properties
springsession.redis.jackson.modules = [] // List of Applicaiton Jackson modules. This plugin use Jackson library to Json serialization.
Json Serialization

By default this plugin use Java serialization. There is a big limitation with this type of serialization, you need to mark every class @Serializable. Now think of some library classes i.e. any class which comes with library and you don’t have source code for that. What happens when you try to serialize that class?

java.io.NotSerializableException Yes you’re right!!!!

In real world applications, you’d like to use libs as much you can because you don’t want to write classes/routines which are already written, why not reuse those.

Here comes the Json serialization. In Json serialization you don’t need to put @Serializable on classes. To use Json Serialization in plugin you need to change below property

springsession.defaultSerializer = Serializer.JSON

That’s it!!!

Json serialization will work perfectly until your class has default constructor. But if any class doesn’t have default constructor then you’ll need to add mixin classes or serializer/deserializer for that class and a Jackson module class. This is the blog which will guide you to Deserialize json with Java parameterized constructor.

Let’s take an example. I’ve my User class as mentioned below

package demo;

import java.io.Serializable;

/**
 * @author Jitendra Singh.
 */
public class User {

    private String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

As you can see there is one parameterized constructor. And I want to put this class in session. So what I’ve to do now.

1. Create Mixin for User
package demo;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
 * @author Jitendra Singh.
 */
public class UserMixin {
    private String name;

    @JsonCreator
    public UserMixin(@JsonProperty("name") String name) {

    }
}
2. Create module class to register mixin
package demo;

import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.Module;

/**
 * @author Jitendra Singh.
 */
public class SimpleModule extends Module {
    @Override
    public String getModuleName() {
        return "Simple";
    }

    @Override
    public Version version() {
        return Version.unknownVersion();
    }

    @Override
    public void setupModule(SetupContext setupContext) {
        setupContext.setMixInAnnotations(User.class, UserMixin.class);
    }
}
3. Register my module class with spring-session plugin
springsession.redis.jackson.modules = ['demo.SimpleModule']

That’s it. You’re done.

In next post I’ll explain Mongo datastore. Happy coding, Cheers !!!