Thursday, August 20, 2020

How to use Redis caching server with Spring Boot.

Firstly, I would like to explain about the advantage about cacheing.


When we use RESTFull applicatoin, most of the time, we are using token (Ex: JWT) base authentication/authorization. Since we are using token base authentication/authorization, we don't cross check the user infomation with the database. Therefore, if somebody copy the token and logout from the system, still, if he/she knows the API details, they can invoke the APIs (Using Postman, curl or similer tools). It is very unsecure, so, better to keep the token information somewhere, we can access the inforation very quickly and easily, then we can validate service invokation whether is it valid or not.

In this article I'm going to describe, how to conect and use Redis server in Spring Boot application.

Steps:

1. Start the Redis server. For this explanation I'm going to use the docker.

 docker run -p 6379:6379 --name redis -v redis.conf:/usr/local/etc/redis/redis.conf -d --memory 100m redis


2. Then we need to add below dependency for the project

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
</dependency>


Here I'm going to use jedis client.

3. Enable caching

import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class TestApplication {
    ....
}


4. Redis cache repository

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;

import java.util.concurrent.TimeUnit;

@Repository
public class RedisCacheRepository {
    private HashOperations hashOperations;
    private RedisTemplate redisTemplate;

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

    private long tokenValidity = 180000;

    public RedisCacheRepository(RedisTemplate redisTemplate){
        this.redisTemplate = redisTemplate;
        this.hashOperations = this.redisTemplate.opsForHash();
    }

    public void save(String tokenId) {
        try {
            hashOperations.put("USERS", tokenId, tokenId);
            redisTemplate.expire("USERS", tokenValidity, TimeUnit.MILLISECONDS);
        } catch (Exception ex) {
            logger.error(ex.getMessage());
        }
    }
    
    public boolean findById(String tokenId) {
        boolean activeUser = false;
        try {
            activeUser = hashOperations.get("USERS", tokenId) != null;
        } catch (Exception ex) {
            logger.error(ex.getMessage());
        }
        return activeUser;
    }

    public void delete(String tokenId) {
        try {
            hashOperations.delete("USERS", tokenId);
        } catch (Exception ex) {
            logger.error(ex.getMessage());
        }
    }
}


Above data is just for explain purpose only.
I have added token validity period (tokenValidity), because, if user ideal and/or doesn't logout properly, we cannot delete the login info from the cache. Therefore, we can add a expire time as above.

Wednesday, February 12, 2020

Feign Client - Spring Boot (Microservice) inter service call

In this article I'm planing to explain the way we can implement Feign Client to invoke inter service call.

We have eurekaServer, zuulServer, clientServer, serverServer. Initially, we need to register our all servers with the eurekaServer.
zuulServer register as proxyService
clientServer register as oneService
serverServer register as twoService
twoService has a end-point as below:
 http method: POST

 url: /api/person/{personId}/bank

1st of all, we need to add dependency to the application. In this example I'm going to use maven dependency as below.
<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-feign</artifactId>
      <version>#{feign.version}</version>
</dependency>

According to the above end-point, we need to implement the feign-client as below
 @FeignClient(name = "twoservice", path = "/api",
        fallback = TwoServiceFallBack.class,
        configuration = DefaultFeignConfig.class)
public interface TwoServiceClient {

    @RequestMapping(path = "/person/{personId}/bank", method = RequestMethod.POST)
    CustomResponseMessage addBankInfo(@PathVariable("personId") String personId, @RequestBody BankDTO bankDTO);

}

And also fall-back class below (when calling the service, if something happen, you can handle the situation here).
@Component
public class TwoServiceClientFallBack implements TwoServiceClient {

    @Override
    public CustomResponseMessage addBankInfo(String personId, BankDTO bankDTO) {
     //
        return null;
    }
}

CustomResponseMessage -> response payload.
BankDTO -> request body

Hope this will helpful.

Thursday, April 18, 2019

Java 8 method reference

Java 8 provides a new feature call method reference. Method reference is used to refer method of functional interface.

There are 3 types of method reference as listed below.
  1. Reference to a static method
  2. Reference to an instance method
  3. Reference to a constructor
I'm going to use same sample to explain the way can use method reference.

1. Reference to a static method

Syntax:
ClassName::staticMethodName

Sample code:
public class MyPrinter { public static void print(String name) { System.out.println(name); } }


public class PrinterApp { public static void main(String[] args) { List<String> names = Arrays.asList("Tharanga", "Wijeweera"); names.forEach(MyPrinter::print); } }


2. Reference to an instance method

Syntax:
object::instanceMethodName

Sample code:
    public class MyPrinter {
     public void print(String name) {
         System.out.println(name);
     }
   }


public class PrinterApp {
public static void main(String[] args) { MyPrinter myPrinter = new MyPrinter(); List<String> names = Arrays.asList("Tharanga", "Wijeweera"); names.forEach(myPrinter::print); } }

3. Reference to a constructor

Syntax:
ClassName::new

Sample code:
    public class MyPrinter {

     private String name;

     public MyPrinter(String name) {
         this.name = name;
         print();
     }

     public void print() {
         System.out.println(this.name);
     }
    }


public class PrinterApp {
public static void main(String[] args) { List<String> names = Arrays.asList("Tharanga", "Wijeweera"); names.forEach(MyPrinter::new); } }

Hope this will help you to get an idea about the method reference in Java 8.

Thursday, November 22, 2018

Spring Boot (Microservice) - Inter service call

Generally, inter service call more common, when we develop a microservice application. So in this artical, I'm going to explain, how to use RestTemplate to call another service.

We have eurekaServer, zuulServer, clientServer, serverServer. Initially, we need to register our all servers with the eurekaServer.
zuulServer register as proxyService
clientServer register as oneService
serverServer register as twoService

twoService has a end-point as below:
http method: PUT
url: /api/person/{personId}/bank

this end-point is going to update the bank information in particulate person and we need to pass the bank details in the body. As below, you can call above end-point in twoService from oneService.

    @Autowired 
    private final RestTemplate restTemplate;
    @Autowired 
    private final EurekaClient eurekaClient;
   .....
   .....
    public CustomResponseMessageDTO method() {
     ....
        String endPoint = "/api/person/{personId}/bank"
        HttpEntity<BankDTO> requestEntity = new HttpEntity<>(bank_information_BankDTO_object);
        Map<String, String> param = new HashMap<>();
param.put("personId", "person_id_should_pass");
        Application application = eurekaClient.getApplication(twoService);
        InstanceInfo instanceInfo = application.getInstances().get(0);
        String url = "http://" + instanceInfo.getIPAddr() + ":" + instanceInfo.getPort() + endPoint;
        ResponseEntity<CustomResponseMessageDTO> exchange = restTemplate.exchange(url, HttpMethod.PUT, requestEntity, CustomResponseMessageDTO.class, param);
        return exchange.getBody(); // this return the CustomResponseMessageDTO object.
    }
....
As above, you can pass the message body using HttpEntity and url paramerter using HashMap.

If you need to pass the header you can add the header to the HttpEntity as below
HttpEntity<BankDTO> requestEntity = new HttpEntity<>(bank_information_BankDTO_object, HttpHeaders_object);

Enjoy..!!!

Spring Boot - Read yml file

When developing a Spring Boot application, we are using yml (properties) file to store the data. Due to this without we don't want to re-build the source code after change the property values.

Even thought this a very basic thing, in this article, I'm going to explain the way we can get the data from yml file.

For this explanation, I'm going to take application.yml file and we have a property as below
company:
  name: Company ABC

Then we can get this value in java code as below
public class TestApplication {
...
@Value("${company.name}")
        private String companyName;
...
}

This value will cast to the variable type.

Enjoy.....!!!

Thursday, June 21, 2018

No 'Access-Control-Allow-Origin' header is present on the requested resource.

In this blog I'm try to explain the way we can solve above issue from the "SpringBoot" side.

I faced the below issue with calling my service through the React.
Failed to load http://xx.xx.xx.xx:8080/api/yy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://xx.xx.xx.xx:3000' is therefore not allowed access.

Default, it didn't set the "Access-Control-Allow-Origin" header. So, you can solve this as below.

1. Create a filter as below
 
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CORSFilter extends GenericFilterBean implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
        //httpResponse.setHeader("Access-Control-Allow-Methods", "*");
        //httpResponse.setHeader("Access-Control-Allow-Headers", "*");
        //httpResponse.setHeader("Access-Control-Allow-Credentials", "false");
        //httpResponse.setHeader("Access-Control-Max-Age", "3600");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

Add if you need add more headers you can add as above.

2. In the main application you have to set the @Bean as below
@SpringBootApplication
@EnableMongoRepositories(basePackages= {"com.home"})
@EntityScan(basePackages = {"com.home"})
@EnableEurekaClient
public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class);
    }
    public FilterRegistrationBean corsFilterRegistration() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(new CORSFilter());
        registrationBean.setName("CORS Filter");
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(1);
        return registrationBean;
    }
}


After this, when you execute the service you can see the 'Access-Control-Allow-Origin' in the header.

Enjoy...!!!

Friday, March 2, 2018

The way we can use 'intellij community edition' to debug tomcat application:

 Environment configurations use for this explanation:

        #  apache-tomcat-7.0.85
        #  IntelliJ IDEA 2017.3.2 (Community Edition)

Steps:

1. Build the project and put the war file into the webapps folder(<tomcat_home>/webapps/).

2. Intellij IDEA
    a) Run -> Edit Configurations
    b) Press the green + and select 'Remote'
    c) Give a proper name (Ex: debug-demo)
    d) Set the host and port(not the tomcat running port number. better to keep the default 5005)
    f) Select the 'Search sources using module's classpath (better to select root)
    g) Copy the 'Command line arguments for running remove JVM'
    Ex: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

3. Tomcat
    a) Open the 'setclasspath.sh'
    b) Set the above copied 'Command line arguments for running remove JVM' value to the  'JAVA_OPTS'. To do that, paste the below line at the end of the file:
JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
    c) Start the tomcat
        Ex: sh startup.sh

4. Intellij IDEA
    a) Select the 'debug-demo' according to our example
    b) Press 'Debug' icon (Shift+9)

Then you can see the connected message in the console as below:
Connected to the target VM, address: 'localhost:5005', transport: 'socket'

Enjoy...!!!