Hazelcast Integration With SpringBoot

Target Audience

Developers who are familiar with Java and Spring Boot [with maven]

We all are building various applications in Spring Boot. Spring boot is a simple lightweight spring application with the integrated server. We can run java[spring] application without any hassle, with most of the things are driven by application properties.  We run single Spring Boot application in the single JVM. Many times we have to run more than one instance of the same application, to manage a large number of requests. We put these instances behind the load balancer, and load balancer will decide which instance should handle the current request.

Simple Pictorial Design

Screen Shot 2018-04-09 at 4.20.39 PM

So our request comes to the load balancer. The load balancer is the entry point of the request. Here we have App 1, which have 3 instances.

Instance: Same Application running in the different server [or in there scope].

So, whenever request goes to any of the instances of App 1, it should behave in the same manner. We create multiple instances so that we can handle more requests. Consider these 3 green regions as separate JVM [seperate tomcat sever].

As we all know two JVMs does not tall to each other, We can consider JVM as an isolated boundary to run a Java application.

Problem Statement

Now suppose you want to somehow share data between these 3 different instances running on different JVM. Assume you need to count of the total number of request server by App 1. If we create a single variable in App1, which will be auto incremented each time request comes to application, it will not solve our problem. Lets name variable requestCounter. Now suppose the total number of request come to load balancer be 3.

Flow Of Request

  • Request 1 goes to instance 1
  • Request 2 goes to instance 2
  • Request 3 goes to instance 1

If We request for the total number of requests server by App 1

  • Instance 1 will return 2
  • Instance 2 will return 1
  • Instance 3 will return 0

Though App 1 serves total number 3 request, all instance provide the wrong result. This is because  we are saving the requestCounter variable at an individual instance, thus every instance is giving the response of its state. We can either get the count from all the instance and sum it, but assume if you have hundred of instance of the same application, how you will do that.Even if we are ready to call each instance, we need to maintain the IP address of all the instances which can be very difficult.

For the same, we will you Hazelcast. What Hazelcast  will do, it will share the state of variable among different instances [JVM].  So in this blog, we will create a simple Spring Boot Application with HazelCast support. And try to share a single long variable among the different instances of Application.

Spring-boot  Setup With Hazelcast

Create Spring Boot Application[Sample Application on Git]

Go to Start Spring IO to create a vanilla Spring-boot Application with Java, Maven and Spring Web as the dependency.

Add HazelCast dependency in the pom.xml


 com.hazelcast
 hazelcast-spring 

Create a class HazelcastConfig inside config package [create package also]

@Configuration
public class HazelcastConfig {

@Bean
public Config hazelConfig(){

Config config = new Config();
config.setInstanceName("hazel-test");
config.getGroupConfig().setName("dev").setPassword("pass");
return config;
}
}

 

  • Line 8 represents the instance name, it should  be different for each instance, in our case Instance 1, Instance 2 and Instance 3
  • Line 9 represents the group. in our case it will be App 1, Since there can be much application you are running, you want to share hazelcast cluster among instances of the same app. In the code above we have used dev [App1]. On the same line, we have set the password also, as to avoid adding the cluster of different instance among the same group.

Now add the TestController, which will use the shared variable.

@RestController
@RequestMapping(value = "/api")
public class TestController {

@Autowired
private HazelcastInstance instance;

@RequestMapping(value = "test")
public String appName(){

return "App1" + instance.getAtomicLong("long-test").incrementAndGet();
}


}
  • Line 6, we have bound the hazelcast instance.
  • Line 11, we are taking Atomic long [“long-test”] variable and simultaneously increasing its value.

Now your code is ready, start this spring boot application twice on the different port. Let’s assume we have started two instances on port 8080, 8081.

 

This is a very simple POC for haze-cast integration with spring boot, it has enormous usecase, We will see some the use cases.

Other Use Cases

  • To maintain the session amoung distributed application.
  • Have distributed cache, [If we maintain cache at the instance level, then cache created at instance 1 will not benefit the instance 2]
  • Distributed in-memory data storage.[Hazelcast contain replica also in case some instance goes down]

 

 

 

 

Advertisements

SpringBoot With Angular 4 Integration and Social Authentication

As a full stack developer, we need to create an application with both frontend-end and backend.

Today we will create a simple full stack application which will have a social login using Google authentication.The area on which we want to focus is how to integrate google social authentication to spring-boot, with logout functionality. And when angular 4 is used in spring-boot application to build the UI, how we will manage the routes, as we know that both angular and have routes, so how our application will resolve which route it has to call.

Tech Stack

  • Angular 4
  • SpringBoot
  • Gradle

Prerequisites

Let’s start creating an application

  • Create a simple spring boot application using Spring.io
    • Project Type with gradle and Java
    • Add necessary description, group, and artifact
    • Add following dependencies to it.

compile 'org.springframework.cloud:spring-cloud-starter-config'
compile('org.springframework.boot:spring-boot-starter-web')
compile("org.springframework.boot:spring-boot-starter-tomcat")
compile 'org.springframework.security:spring-security-web'
compile 'org.springframework.security:spring-security-config'
compile 'org.springframework.security.oauth:spring-security-oauth2'
compile 'org.apache.httpcomponents:httpclient'
compile("io.springfox:springfox-swagger2:2.6.1")
compile("io.springfox:springfox-swagger-ui:2.6.1")

testCompile('org.springframework.boot:spring-boot-starter-test')
compile group: 'org.slf4j' , name: 'slf4j-api' , version: '1.7.22'
compile group: 'io.jsonwebtoken' , name: 'jjwt' , version: '0.7.0'
compile group: 'commons-io' , name: 'commons-io', version: '2.5'
compile group: 'org.projectlombok' , name: 'lombok' , version: '1.16.12'

These dependencies will allow us to enable the google authentication on the top of normal spring boot application.

  • Create the property file application-local.yml in the java main resources.

security:
oauth2:
client:
clientId: ******.apps.googleusercontent.com
clientSecret: ********
accessTokenUri: https://www.googleapis.com/oauth2/v4/token
userAuthorizationUri: https://accounts.google.com/o/oauth2/v2/auth
clientAuthenticationScheme: form
scope:
- openid
- email
- profile
resource:
userInfoUri: https://www.googleapis.com/oauth2/v3/userinfo
preferTokenInfo: true

user:
role: test-role

We have created a property file to enable google authentication against the particular client.Replace the * with your actual data.

  • Create bootstrap.yml with following data.
<pre>spring:
  application:
    name: frontend
  profiles:
    active: local
  cloud:
    config:
      uri: http://localhost:8888
      enabled: true</pre>

It will help us to give the name to our application and will activate “LOCAL” profile.

  • Create a Security Config java file “SpringConfig” on the same level as of the main file.

package com.test.practise;

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .antMatchers( "/login","/public/**", "/resources/**","/resources/public/**")
                    .permitAll()
                .antMatchers("/","/api/**").authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/login")
                .defaultSuccessUrl("/");
    }
}

It will apply authentication to all the path accept /login,  /public,  /resources/public/.

  • Add controller for logout “SecurityController”
<pre>package com.test.practise.controller;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller
public class SecurityController {


    @RequestMapping(value="/logout", method = RequestMethod.GET)
    public String logoutPage (HttpServletRequest request, HttpServletResponse response) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null){
            new SecurityContextLogoutHandler().logout(request, response, auth);
        }
        return "redirect:/";
    }
}
</pre>

It will enable the logout URL, which will delete the session.

  • We are not pretty much done with the spring side coding, but we have not added any view or frontend related code yet. We will create the angular project now.
  • Go to the root of the project and create the angular project angular-cli.

ng new webui

It will create a new project directory for frontend inside our current project directory.

  • Navigate to a webui directory which you have created, and make 3 testing controller using the following command.

ng g component landingComponent

ng g component homeComponent

ng g component settingComponent

These are the dummy component to show the routing.

  • Now we will mention our routes in the angular project in file app.module.ts

<pre>import {RouterModule, Routes} from "@angular/router";</pre>


const appRoutes: Routes =[

{path:'',component:LandingComponent},
{path:'welcome',component:WelcomeComponent},
{path:'setting',component:SettingComponent}

]

 

 

  • Add routing module in Imports in the same file.
<pre>@NgModule({
  declarations: [
    AppComponent,
    WelcomeComponent,
    SettingComponent,
    LandingComponent
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot(appRoutes,{enableTracing:true})
  ],
  providers: [],
  bootstrap: [AppComponent]
})

</pre>
  • replace the code of app.component.html the main page of ui with following code.

<pre>&lt;!–The content below is only a placeholder and can be replaced.–&gt;
&lt;div style="text-align:center"&gt;
&lt;h1&gt;
Welcome to {{title}}!!
&lt;/h1&gt;
&lt;img width="300" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyNTAgMjUwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyNTAgMjUwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDojREQwMDMxO30NCgkuc3Qxe2ZpbGw6I0MzMDAyRjt9DQoJLnN0MntmaWxsOiNGRkZGRkY7fQ0KPC9zdHlsZT4NCjxnPg0KCTxwb2x5Z29uIGNsYXNzPSJzdDAiIHBvaW50cz0iMTI1LDMwIDEyNSwzMCAxMjUsMzAgMzEuOSw2My4yIDQ2LjEsMTg2LjMgMTI1LDIzMCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAJIi8+DQoJPHBvbHlnb24gY2xhc3M9InN0MSIgcG9pbnRzPSIxMjUsMzAgMTI1LDUyLjIgMTI1LDUyLjEgMTI1LDE1My40IDEyNSwxNTMuNCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAxMjUsMzAgCSIvPg0KCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0xMjUsNTIuMUw2Ni44LDE4Mi42aDBoMjEuN2gwbDExLjctMjkuMmg0OS40bDExLjcsMjkuMmgwaDIxLjdoMEwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMQ0KCQlMMTI1LDUyLjF6IE0xNDIsMTM1LjRIMTA4bDE3LTQwLjlMMTQyLDEzNS40eiIvPg0KPC9nPg0KPC9zdmc+DQo="&gt;
&lt;/div&gt;
&lt;a href="/setting"&gt;Direct Setting&lt;/a&gt;
&lt;a href="/welcome"&gt;Direct Welcome&lt;/a&gt;
&lt;nav&gt;
&lt;a routerLink="/" routerLinkActive="active"&gt;Landing Page&lt;/a&gt;
&lt;a routerLink="/welcome" routerLinkActive="active"&gt;Welcome Page&lt;/a&gt;
&lt;a routerLink="/setting" routerLinkActive="active"&gt;Setting Page&lt;/a&gt;
&lt;/nav&gt;
&lt;router-outlet&gt;&lt;/router-outlet&gt;

</pre>

It will create the routes .First two route for setting and welcome is using href. normal HTML routes and then we have refined routes using routerLink.

  • Build the frontend application

ng build

  • Now we will make changes in spring application to consume this frontend code.First of all, we will add the  code in our build.gradle to copy the frontend code and place it in resource so that it can be consume by spring-boot.
  • Add following task to build.gradle

<pre>

task removeWebui(type: Delete) {
delete "${sourceSets.main.resources.srcDirs[0]}/webui"
}

task copyWebui(type: Copy) {
from "webui/dist"

into "${sourceSets.main.resources.srcDirs[0]}/webui"
exclude "*.gz"
//eachFile { println it.name }
}

task downloadRedoc(type: Download) {
src "https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js&quot;
dest "${sourceSets.main.resources.srcDirs[0]}/public/redoc"
overwrite true
}

task var &lt;&lt; {
sourceSets {
main {
println "java.srcDirs = ${java.srcDirs}"
println "resources.srcDirs = ${resources.srcDirs[0]}"
println "output.classesDir = ${output.classesDir}"
println "output.resourcesDir = ${output.resourcesDir}"
}
}
}

compileJava.dependsOn downloadRedoc
copyWebui.dependsOn removeWebui
compileJava.dependsOn copyWebui</pre>

  • Create controller for APIs “WebRestController

package com.test.practise.controller;

import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RefreshScope
@RestController
@RequestMapping("/api")
public class WebRestController {

@RequestMapping("test")
public String test(){
return "test api data";
}


}
  • Create a view controller for enabling angular routes
<pre>package com.test.practise.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import springfox.documentation.annotations.ApiIgnore;


@Slf4j
@ApiIgnore
@Controller
public class ViewController {

    @RequestMapping({ "/","/welcome" })
    public String views() {
        return "forward:/index.html";
    }

}</pre>

This view controller will enable the spring to resolve these URL as angular URL.

 

Now we are good to go.Run the spring boot application using gradle bootRun.it will start the application.Once you will try to react the application from the browser, it will navigate you to google login first.

On Successful login, you will see the angular page.So till now we are pretty much done with authentication part. Now comes the routing part.

Now try to navigate to welcome page and setting page using above router.In this case, the welcome route will be successful but setting URL will fail, as we have not mentioned it in ViewController.

But when we try the routes which are below one, every route will work fine, as it is using angular routes.

For reference, you can check the GIT REPO with sample working code.

 

Some Use cases of Annotations

In our previous post, we understand what annotation is, and how to create our custom annotations. Now we will try to understand how and when we can use annotation.

This is more sort of the suggestion rather than any rule of using experience.All this will be from my experience, it can change from person to person.

The common examples where I love to use annotations are:

Separating and Categorization
Every one of us loves to code and to protect our code we write test cases. We all are familiar with unit test cases and integration test cases. To reduce the build in time we always want to run these test cases in parallel.But to run them in parallel we first have to categorize these in two different buckets. we need some mechanism to identify what test cases are unit test cases and what are integration test cases.
For this, we will try very simple use case. We will try to use annotation to identify our type of test cases.We will create a simple spring application with Gradle, which have few unit test cases and integration test cases.
You can access the code base directly from GIT Repo.
  • First, create a simple spring-boot application with Gradle.
  • Create two interfaces “UnitTest” and “IntegrationTest

 

package com.application
public interface UnitTest{}

 

package com.application
public interface IntegrationTests{}

  • Create Gradle task to run different type of test cases

Gradle tasks

test {
    useJUnit {
        includeCategories 'com.application.UnitTest'
    }
}

task integrationTest(type: Test) {
    useJUnit {
        includeCategories 'com.application.IntegrationTest'
    }
}

 

All you need to do is put the annotation on your test case now.


@Category(IntegrationTest.class)
public class IntegrationTestCaseExample {
}

 


@Category(value = UnitTest.class)
public class UnitTestCaseExample {
}

Now all you need to do is run the gradle test if running unit test cases and gradle integrationTest if have to run integration test.

 

Sample code for the same can be seen at this link

For further usage of Annotation,  will try to write few more blogs

Dockerize Spring Boot Application

This blog will help the audience to enable them to create docker image from a Spring boot Application.We have created a Spring Boot with maven.

We have already created the code repository. This repository contain 3 branches

1.Master: – Vanilla Spring Boot with Web Module

2.Controller-Test: – Master with test Rest repository.

3.Docker-Support :- Added docker support to Controller-Test branch

Prerequisite

  • Spring Boot Knowledge
  • How to create simple DockerFile

Here we will see what changes are required to add docker support to Spring Boot Application. It is the changes required to create Docker-Support branch from Controller-Test branch.

Changes Required in Pom

We need to add below mention plugin in the pom.

<plugin>
   <groupId>com.spotify</groupId>
   <artifactId>docker-maven-plugin</artifactId>
   <version>0.2.3</version>
   <configuration>
      <imageName>horizon/${project.artifactId}</imageName>
      <dockerDirectory>/</dockerDirectory>
      <resources>
         <resource>
            <targetPath>/</targetPath>
            <directory>/</directory>
            <include>${project.build.finalName}.jar</include>
         </resource>
      </resources>
   </configuration>
</plugin>

Add DockerFile in the project path

FROM frolvlad/alpine-oraclejdk8:slim
VOLUME /tmp
ADD target/docker-0.0.1.jar app.jar
RUN sh -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
EXPOSE 8080

There are two ways to create a docker image from the current source now.

1.Create docker image using maven plugin [can also be used using Jenkin worklow]

Run the command from project directory:- mvn clean package docker:build

2.Create docker image using docker build command

Run mvn install:- mvn clean install

Create docker image by executing the following command from project directory:

docker build  -t  docker.demo:latest  .