Spring Boot and Zuul API Gateway Integration


In this post, we will learn how to integrate zuul api gateway to the application developed in microservices architecture.

Our application consists of below components

  • customer-service
  • order-service
  • eureka-server
  • zuul-service

We have already seen how to create customer-service, order-service, eureka-server in the previous post given below

https://malliktalksjava.com/2020/05/28/spring-boot-netflix-eureka-integration/

Let us start integrating zuul api gateway service to the above application.

Firstly, Go to https://start.spring.io , Create SpringBoot Application with below configuration. 

As shown above, Spring Web, Eureka Server, Zuul as dependencies needs to be added.

Second Step, Import the project in the Eclipse, go to application.properties and add below properties

spring.application.name=zuul-service
zuul.routes.order.url=http://localhost:8080
eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka
server.port=8079

Next step is to create following filters

  • ErrorFilter
  • PreFilter
  • PostFilter
  • RouteFilter

Below diagram depicts flow of Request & Response intercepted by Zuul filters

Zuul_FlowDFilters creation step 1: Create ErrorFilter by extending ZuulFilter and override methods and shown below

package com.venkat.filters;

import com.netflix.zuul.ZuulFilter;

public class ErrorFilter extends ZuulFilter {

@Override
public String filterType() {
        return "error";
}

@Override
public int filterOrder() {
       return 0;
}

@Override
public boolean shouldFilter() {
       return true;
}

@Override
public Object run() {
        System.out.println(" ############# Using Error Filter ##################");               
return null;
}

}

Filters creation step 2: Create PreFilter by extending ZuulFilter and override methods and shown below

package com.venkat.filters;
import javax.servlet.http.HttpServletRequest;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

public class PreFilter extends ZuulFilter {

@Override
public String filterType() {
return "pre";
}

@Override
public int filterOrder() {
return 0;
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
System.out.println(" ############# In Pre Filter ################## ");
System.out.println(
"Request Method : " + request.getMethod() + " Request URL : " + request.getRequestURL().toString());

return null;
}

}

Filters creation step 3: Create PostFilter by extending ZuulFilter and override methods and shown below

package com.venkat.filters;

import java.io.IOException;
import java.io.InputStreamReader;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.common.io.CharStreams;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

public class PostFilter extends ZuulFilter {

@Override
public String filterType() {
return "post";
}

@Override
public int filterOrder() {
return 0;
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
System.out.println(" ############# In Post Filter ################## ");
try {
System.out.println(
"Response Status Code : " + ctx.getResponseStatusCode() + " Response Body : " + CharStreams.toString(new InputStreamReader(ctx.getResponseDataStream(), "UTF-8")));
} catch (IOException e) {

}

return null;
}

}

Filters creation step 4: Create RouteFilter by extending ZuulFilter and override methods and shown below

package com.venkat.filters;

import com.netflix.zuul.ZuulFilter;

public class RouteFilter extends ZuulFilter {

@Override
public String filterType() {
return "route";
}

@Override
public int filterOrder() {
return 0;
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
public Object run() {
System.out.println("Using Route Filter");

return null;
}

}

Next, Add @EnableZuulProxy to ZuulProxyApplication class in zuul-service and add bean configurations for Filters which we have created as shown below

package com.venkat;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulProxyApplication {

public static void main(String[] args) {
SpringApplication.run(ZuulProxyApplication.class, args);
}

@Bean
public PreFilter preFilter() {
return new PreFilter();
}

@Bean
public PostFilter postFilter() {
return new PostFilter();
}

@Bean
public ErrorFilter errorFilter() {
return new ErrorFilter();
}

@Bean
public RouteFilter routeFilter() {
return new RouteFilter();
}
}

Once we are done creating all the filters package structure of our
zuul-service will be as shown as shown below

Now we will see changes to done to the customer-service application to enable requests
pass via zuul-service filters.

Go to CusomerControllerClient.java in customer-service replace

List<ServiceInstance> instances = discoveryClient.getInstances("ORDER-SERVICE");

with

List<ServiceInstance> instances = discoveryClient.getInstances("ZUUL-SERVICE");

and 

String completeURL = baseURL + "/customerorder";

with 

String completeURL = baseURL + "/order/customerorder";

Upon completion of all the code changes/additons discussed above run all the services, eureka-server, order-service, customer-service, zuul-service.

Following will be output once we hit the REST endpoint /customerorderinfo

zuul-service logs on hitting the REST end point are given below, clearly we can see both Request and Response pass through Pre, Route, Post Filters 

############# In Pre Filter ################## 
Request Method : GET Request URL : http://Dell:8079/order/customerorder
Using Route Filter
############# In Post Filter ##################
Response Status Code : 200 Response Body : {"orderId":"TIF567","itemName":"Dosa","itemType":"Tiffin","cost":40.0}
2020-05-31 18:56:18.494 INFO 3892 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver : Resolving eureka endpoints via configuration
############# In Pre Filter ##################
Request Method : GET Request URL : http://Dell:8079/order/customerorder
Using Route Filter
############# In Post Filter ##################
Response Status Code : 200 Response Body : {"orderId":"TIF567","itemName":"Dosa","itemType":"Tiffin","cost":40.0}

Conclusion

In this post, we have seen how to configure Zuul-proxy and make requests from one microservice pass through customized zuul filters. These filters enable us to apply functionality to our edge service. These filters help us perform the following functions:

  • Authentication & Security – identifying authentication requirements for each resource and rejecting requests that do not satisfy them.
  • Monitoring – tracking data and statistics at the edge which gives us a view of production.
  • Dynamic Routing – dynamically routing requests to various back-end clusters.
  • Load Shedding – allocating capacity for each type of request and dropping requests that exceeds the limit set.
  • Stress Testing – increasing the traffic to a cluster to measure its performance.
  • Static Response handling – sending some responses directly at the edge instead of forwarding them to an internal cluster.

Related links:

References:

Core Java and Java 8 Concepts


In this post, you will see some important Core Java/Java 8 concepts related to Collections, Exception Handling, Multi-threading, Concurrency etc.

Comparable Vs Comparator

Comparable Comparator
Comparable provides a single sorting sequence. In other words, Sorting of  collection is based on a single property of a class such as ID, ItemName or quantity etc. The Comparator provides multiple sorting sequences. In other words, sorting of collection can based of multiple properties such as ID, ItemName, and quantity etc.
Comparable affects the original class, i.e., the actual class is modified. Comparator doesn’t affect the original class, i.e., the actual class is not modified.
Comparable provides compareTo() method to sort elements. Comparator provides compare() method to sort elements.
Comparable is from  java.lang package. A Comparator is from java.util package.
Sorting list of Objects-Comparable type can be done using Collections.sort(List) method. Sorting list of Objects-Comparator type by Collections.sort(List, Comparator) method.

JVM Architecture

Different types of Class Loaders?

  • Bootstrap class Loader
  • Extensions class Loader
  • System class Loader

Boostrap class loader loads the classes from jdk/jre/lib/rt.jar. Extension class loader loads the classes from jdk/lib/ext folder jars. System class loader loads the classes from CLASSPATH.

Difference between ClassNotFoundException and NoClassDefFoundError

  • ClassNotFoundException is an Exception, while NoClassDefFoundError is an Error.
  • ClassNotFoundException occurs when CLASSPATH does not get updated with required JAR files while NoClassDefFoundError occurs when required class definition is not present at runtime.

Example for NoClassDefFoundError :

class Shape {
  public void draw() {
     System.out.println("Drawing Shape!");
  }
}

public class DrawingApp {
  public void draw() {
     System.out.println("Drawing Shape!");
  }
  public static void main(String[] args) {
     Shape shape = new Shape();
     shape.draw();
  }
}

After compilation, Shape.class and DrawApp.class are generated, If Shape.class is deleted and DrawApp is run then NoClassDefFoundError is thrown.

Difference between ConcurrentHashMap and SynchronizedMap

  • ConcurrentHashMap is designed for concurrency and improves performance while Collections.synchronizedMap(map) which is non-synchronized by sort can be synchronized by applying a wrapper using Collections.synchronizedMap(map).
  • ConcurrentHashMap doesn’t support null keys or null values while synchronized HashMap supports one null key.
  • Locking in SynchronizedMap is at object level, so read/write operations performance is slower.
  • Locking in ConcurrentHashMap is at a much finer granularity at a hashmap bucket level.

Differences betwen equals() and hashcode() methods

equals() and hashCode() are methods present in Object class and hashCode method should not be used to check if two object references are same. Reason: hashCode just returns int value for an Object, even two different objects can have same hashCode integer. The value returned by hashCode() is the object’s hash code, which is the object’s memory address in hexadecimal. equals() checks if the two object references are same. If two objects are equal then their hashCode must be the same, but the reverse is not true.

O(1) vs O(n) vs O(log n)

These are measures of time complexity of running a piece of code.

O(1) – if execution time is constant, it requires the same amount of time regardless of the size. Example:  array – accessing any element int i = a[0];

O(n) – if execution time is directly proportional to the size.  Example: Linear search for an element has a time complexity of O(n).

O(log n) – if execution time is proportional to the logarithm of the input size. Example: Performing Binary Search on array of elements

Changes to HashMap in Java8

  • In case of Hash collision entry objects are stored as a node in a LinkedList and equals() method is used to compare keys. That comparison to find the correct key with in a linked-list is a linear operation so in a worst case scenario the complexity becomes O(n).
  • To address this issue, Java 8 hash elements use Balanced Tree instead of LinkedList after a certain threshold is reached. Which means HashMap starts with storing Entry objects in linked list but after the number of items in a hash becomes larger than a certain threshold, the hash will change from using a LinkedList to a Balanced Tree, which will improve the worst case performance from O(n) to O(log n).

Fail Fast Vs Fail Safe Iterators

Fail-Fast Iterators Fail-Safe Iterators
Fail-Fast iterators doesn’t allow  modifications of a collection while iterating over it. Fail-Safe iterators allow modifications of a collection while iterating over it.
Concurrent Modification Exception is thrown if a collection is modified while iterating over it. These iterators don’t throw any exceptions if a collection is modified while iterating over it.
They use original collection to traverse over the elements of the collection. They use copy of the original collection to traverse over the elements of the collection.
These iterators don’t require extra memory. These iterators require extra memory to clone the collection.
Ex : Iterators returned by ArrayList, Vector, HashMap. Ex : Iterator returned by CopyOnWriteArrayList, ConcurrentHashMap.

Difference between map() and flatmap() in Java8

Lets suppose we are applying map and flatmap on stream of streams. Example given below

Stream<List<Character>> stream = Stream.of({'a','b'},{'c','d'})

with map:  For input Stream of two lists {‘a’,’b’} and {‘c’,’d’}, output will be {{‘a’,’b’},{‘c’,’d’}} .Here two lists are placed inside a list, so the output will be list containing lists

With flat map: For input Stream of two lists {‘a’,’b’} and {‘c’,’d’}, output will be {{a,b,c,d}} .Here two lists are flattened and only the values are placed in list, so the output will be list containing only elements

What are Functional interfaces how we can define them?

Functional interfaces are interfaces which have only one single abstract method in it. Example:  Runnable Interface since it has only single abstract method, run().

From Java8, we can use @FunctionalInterface to define a functional interface. Although this annotation is optional, once it is used then declaring more than one abstract method will throw compile time error.

Rules of Method Overloading and Method Overriding

There are specific rules while we implement method overloading and overriding in Java with regards to increasing/decreasing visibility of methods of parent class in child class and throwing Checked Exceptions in child class. Complete rules are posted in this below link

https://malliktalksjava.com/2020/05/29/rules-of-method-overloading-and-overriding/

Exception Handling flow having return statements in try/catch/finally blocks

  • Once try block encounters a return statement, the flow immediately transfers to finally block. Let say,it prints “print statement from finally”.
  • Upon the completion of finally block execution, control goes back to the return statement in the try block and returns “returning from try block”.
  • If finally block has a return statement, then the return statements from try/catch blocks will be overridden.

Exception Handling flow while exceptions thrown in catch/finally blocks

  • If the catch block completes normally, then the finally block is executed. Then there is a choice:
  • If the finally block completes normally, then the try statement completes normally. If the finally block completes abruptly for any reason, then the try statement completes abruptly for the same reason.
  • If the catch block completes abruptly for reason R, then the finally block is executed. Then there is a choice:
    If the finally block completes normally, then the try statement completes abruptly for reason R.
    If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and reason R is discarded).

FixedThreadPool vs CachedThreadPool vs ScheduledThreadPool

  • newCachedThreadPool(): creates an expandable thread pool executor. New threads are created as needed, and previously constructed threads are reused when they are available. Idle threads are kept in the pool for one minute. This executor is suitable for applications that launch many short-lived concurrent tasks.
  • newFixedThreadPool(int n): creates an executor with a fixed number of threads in the pool. This executor ensures that there are no more than n concurrent threads at any time. If additional tasks are submitted when all threads are active, they will wait in the queue until a thread becomes available. If any thread terminates due to failure during execution, it will be replaced by a new one. The threads in the pool will exist until it is explicitly shutdown. Use this executor if you and to limit the maximum number of concurrent threads.
  • newScheduledThreadPool(int corePoolSize): creates an executor that can schedule tasks to execute after a given delay, or to execute periodically. Consider using this executor if you want to schedule tasks to execute concurrently.

What is ThreadLocal?

ThreadLocal class provides thread-local variables. It enables you to create variables that can only be read and write by the same thread. If two threads are executing the same code and that code has a reference to a ThreadLocal variable then the two threads can’t see the local variables of each other.

Diffence Volatile vs AtomicInteger?

volatile keyword is used on variables to solve the visibility problem in multi-threaded environment.  AtomicInteger is used if we perform compound operations(incrementing(i++) decrementing(i–)) on variables.

volatile is used on boolean flags, AtomicInteger is used for counters.

 

Differences between yield, join, & sleep

yield() method pauses the currently executing thread temporarily for giving a chance to the remaining waiting threads of the same priority to execute. If there is no waiting thread or all the waiting threads have a lower priority then the same thread will continue its execution. The yielded thread when it will get the chance for execution is decided by the thread scheduler whose behavior is vendor dependent.

join() If any executing thread t1 calls join() on t2 i.e; t2.join() immediately t1 will enter into waiting state until t2 completes its execution.

sleep() Based on our requirement we can make a thread to be in sleeping state for a specified period of time

Differences between Runnable and Callable

  • Runnable object does not return a result whereas a Callable object returns a result.
  • Runnable object cannot throw a checked exception wheras a Callable object can throw an exception.
  • The Runnable interface has been around since Java 1.0 whereas Callable was only introduced in Java 1.5.
class ThreadA implements Runnable {
@Override
public void run() { }
}

public class ThreadB implements Callable<String> {
@Override
public String call() throws Exception {
return "Thread B ran Successfully";
}
}

What is Semaphore in concurrency?

Semaphore is used to restrict the entry to a service to a fixed number of threads at a given time. This is generally used on slow services to make it available for fixed number of requests.

Semaphore semaphore = new Semphore(no_of_permits);

In run() method of a thread, we can use semaphore.acquire() before accessing the slow service and semaphore.release() after to ensure fixed number (defined as no_of_permits) of threads are eligible to access it.

Difference between CyclicBarrier and CountDownLatch?

Both CyclicBarrier and CountDownLatch are used in Multi threading scenario where one Thread waits for one or more Thread to complete their job before it continues processing but main difference between two is that, you can not reuse same CountDownLatch instance once count reaches to zero and latch is open, on the other hand, CyclicBarrier can be reused by resetting Barrier, Once barrier is broken.

  • Initialization of countdownlatch is CountDownLatch latch = new CountDownLatch(4);
  • Method used to countdown (generally used inside run method of thread at a specific point) is latch.countDown()
  • Method used to await a specific thread till countdown number completes is latch.await()
  • Phaser can be used either to perform functionality of both CyclicBarrier and CountDownLatch

References:
https://docs.oracle.com/en/java/javase/
https://stackoverflow.com/
https://dzone.com/

Rules of method overloading and overriding


In this post we will see the rules which needs to adhered while implementing method overriding and overloading with regards to increasing/decreasing visibility of methods of parent class in child class and throwing Checked Exceptions in child class.

Method Overriding rules

For terminology, original method is known as overridden method and new method is known as overriding method. Below rules must be followed to override a methods in Java :

  • Overriding method cannot throw checked exception which is higher in hierarchy than the checked Exception thrown by overridden method. For example if overridden method throws IOException which is checked Exception, than overriding method can not throw java.lang.Exception because it comes higher in type hierarchy.
    "Exception 'Exception' is not compatible with throws clause in" 
    
    **** Overriding method can have Runtime Exceptions declared even if Overridden method does not throw any type of Exceptions.
  • Overriding method can not reduce access of overridden method. It means if overridden method is defined as public than overriding method can not be protected or package private. Similarly if original method is protected then overriding method cannot be package-private. You can see what happens if you violate this rule in Java,
     "You cannot reduce visibility of inherited method of a class".
  • Overriding method can increase access of overridden method. This is opposite of earlier rule.
    ****According to this if overridden method is declared as protected then overriding method can be protected or public
  • private, static, final methods can not be overridden.
    "Cannot override the final method from Parent"
  • Return type of overriding method must be same as overridden method. Changing return type of method in child class will throw compile time error
    "return type is incompatible with parent class method"
    

Method Overloading rules

Here is the list of rules which must be followed to overload a method:

  • First rule to overload a method is to change method signature. method signature is made of number of arguments, type of arguments and order of arguments if they are of different types.  One can change any of these or combinations of them to overload a method in Java.
  • Return type of method is not part of method signature, hence changing the return type alone will not overload a method in Java.  In fact, it will result in compile time error.

Spring Boot and Netflix Eureka Integration


In this post we will learn how to integrate applications developed in Spring Boot with Netflix Eureka.

First step is to create two Spring Boot application services

  • customer-service
  • order-service

Go to https://start.spring.io and create order-service app using below config details.

Mainly for our use case, adding Spring Web, Eureka Server dependencies are the required ones

Likewise, create customer-service app with same config details used for order-service by adding Spring Web, Eureka Server dependencies.

Next, create eureka-server app with below config . Adding Eureka Server is main important config for our use case

Next, Import the projects created from the above into Eclipse IDE.

Add @EnableEurekaServer on EurekaServerApplication class as shown Below

package com.venkat;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}

Add below properties to the application.properties

server.port=8090
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

Next, Add @EnableEurekaClient on CustomerServiceApplication class in customer-service  app as shown below

@SpringBootApplication
@EnableEurekaClient
public class CustomerServiceApplication {
public static void main(String[] args) throws RestClientException, IOException {
SpringApplication.run(CustomerServiceApplication.class, args);
}

@Bean
public ConsumerControllerClient consumerControllerClient()
{
return new ConsumerControllerClient();
}
}

Likewise, Add @EnableEurekaClient on OrderServiceApplication class in order-service app as shown below

@SpringBootApplication
@EnableEurekaClient
public class OrderSerivceApplication {

public static void main(String[] args) {
SpringApplication.run(OrderSerivceApplication.class, args);
}
}

Next, Add below configuration in customer-service and order-service
application.properties files

customer-service

spring.application.name=customer-service
server.port=8091
eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka

order-service

spring.application.name=order-service
server.port=8080
eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka

Next, Create Order.java in model package as shown below with orderId, itemName, itemType, Cost attributes.

package com.venkat.model;

public class Order {
private String orderId;
private String itemName;
private String itemType;
private double cost;

public Order() {
}

public String getOrderId() {
return orderId;
}

public void setOrderId(String orderId) {
this.orderId = orderId;
}

public String getItemName() {
return itemName;
}

public void setItemName(String itemName) {
this.itemName = itemName;
}

public String getItemType() {
return itemType;
}

public void setItemType(String itemType) {
this.itemType = itemType;
}

public double getCost() {
return cost;
}

public void setCost(double cost) {
this.cost = cost;
}
}

Create OrderController with a REST GET mapping for /customerorder to return Order object

package com.venkat.controllers;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.venkat.model.Order;

@RestController
public class OrderController {

@RequestMapping(value = "/customerorder", method = RequestMethod.GET)
public Order customerOrder() {
Order order = new Order();
order.setOrderId("TIF567");
order.setItemName("Dosa");
order.setItemType("Tiffin");
order.setCost(40.00);
return order;
}
}

Create a ConsumerControllerClient.java class as shown below

package com.venkat.controllers;

import java.io.IOException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

@RestController
public class ConsumerControllerClient {

@Autowired
private DiscoveryClient discoveryClient;

@GetMapping(path="/customerorderinfo")
public String getCustomerOrder() throws RestClientException, IOException {

List<ServiceInstance> instances = discoveryClient.getInstances("ORDER-SERVICE");

// Creating URL for calling order-service
ServiceInstance serviceInstance = instances.get(0);
String baseURL = serviceInstance.getUri().toString();
String completeURL = baseURL + "/customerorder";

// Calling order-service
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = null;
try {
response = restTemplate.exchange(completeURL, HttpMethod.GET, getHeaders(), String.class);
} catch (Exception ex) {
System.out.println(ex);
}
System.out.println(response.getBody());
return response.getBody();
}

private static HttpEntity<?> getHeaders() throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
return new HttpEntity<>(headers);
}

}

Final step is to Run EurekaServer, order-service, customer-service apps

Open http://localhost:8090 (port on which eureka server is running). Here you will see
order-service,customer-service app instances registered with it.

Output on hitting REST Endpoint http://localhost:8091/customerorderinfo is given below

Conclusion

In the above post we have seen how to register two service applications with Netflix Eureka
Server and communicate between the services via Eureka server registry without knowing the
host, port info of the service to which we are communicating with.

Spring Boot Starters


Spring Boot Starters

Spring Boot provides a number of starters which allow us to add jars in the classpath. Spring Boot Starters are the dependency descriptors. Spring Boot built-in starters make development easier, rapid and easily maintainable.

Naming Pattern

In the Spring Boot framework, all the starters follow a similar naming pattern: spring-boot-starter-*, where * denotes a particular type of application.

Example, if we require to use Spring and JPA for database access, spring-boot-starter-data-jpa dependency in our pom.xml file of the project can be included.

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

If we are developing REST API, spring-boot-starter-web dependency can be used.

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

If gradle is being used as build tool, then following can be added to build.gradle file in the project.

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
}

Below are the jars which are added to project’s classpath on adding “spring-boot-starter-data-jpa”

Spring Boot Starters can be broadly classified into three categories

  1. Production Starters
  2. Application Starters
  3. Technical Starters

Below is complete list of the starters available in above categories

Spring Boot Production Starters

Name

Description

spring-boot-starter-actuator This provides production-ready features to help you monitor and manage your application.
spring-boot-starter-remote-shell This is used for the CRaSH remote shell to monitor and manage your application over SSH. Deprecated since 1.5.

Spring Boot Application Starters

Name

Description

spring-boot-starter-thymeleaf For building MVC web applications using Thymeleaf views.
spring-boot-starter-data-couchbase For the Couchbase document-oriented database and Spring Data Couchbase.
spring-boot-starter-artemis For JMS messaging using Apache Artemis.
spring-boot-starter-web-services For Spring Web Services.
spring-boot-starter-mail To support Java Mail and Spring Framework’s email sending.
spring-boot-starter-data-redis Used for Redis key-value data store with Spring Data Redis and the Jedis client.
spring-boot-starter-web For building the web application, including RESTful applications using Spring MVC. It uses Tomcat as the default embedded container.
spring-boot-starter-data-gemfire Used to GemFire distributed data store and Spring Data GemFire.
spring-boot-starter-activemq For JMS messaging using Apache ActiveMQ.
spring-boot-starter-data-elasticsearch For Elasticsearch search and analytics engine and Spring Data Elasticsearch.
spring-boot-starter-integration It is used for Spring Integration.
spring-boot-starter-test Used to test Spring Boot applications with libraries, including JUnit, Hamcrest, and Mockito.
spring-boot-starter-jdbc Used for JDBC with the Tomcat JDBC connection pool.
spring-boot-starter-mobile Used for building web applications using Spring Mobile.
spring-boot-starter-validation Used for Java Bean Validation with Hibernate Validator.
spring-boot-starter-hateoas Used to build a hypermedia-based RESTful web application with Spring MVC and Spring HATEOAS.
spring-boot-starter-jersey Used to build RESTful web applications using JAX-RS and Jersey. An alternative to spring-boot-starter-web.
spring-boot-starter-data-neo4j Used for the Neo4j graph database and Spring Data Neo4j.
spring-boot-starter-data-ldap Used for Spring Data LDAP.
spring-boot-starter-websocket Used for building the WebSocket applications. It uses Spring Framework’s WebSocket support.
spring-boot-starter-aop For aspect-oriented programming with Spring AOP and AspectJ.
spring-boot-starter-amqp For Spring AMQP and Rabbit MQ.
spring-boot-starter-data-cassandra For Cassandra distributed database and Spring Data Cassandra.
spring-boot-starter-social-facebook For Spring Social Facebook.
spring-boot-starter-jta-atomikos For JTA transactions using Atomikos.
spring-boot-starter-security It is used for Spring Security.
spring-boot-starter-mustache It is used for building MVC web applications using Mustache views.
spring-boot-starter-data-jpa Used for Spring Data JPA with Hibernate.
spring-boot-starter Used for core starter, including auto-configuration support, logging, and YAML.
spring-boot-starter-groovy-templates Used for building MVC web applications using Groovy Template views.
spring-boot-starter-freemarker It is used for building MVC web applications using FreeMarker views.
spring-boot-starter-batch For Spring Batch.
spring-boot-starter-social-linkedin For Spring Social LinkedIn.
spring-boot-starter-cache For Spring Framework’s caching support.
spring-boot-starter-data-solr It is used for the Apache Solr search platform with Spring Data Solr.
spring-boot-starter-data-mongodb It is used for MongoDB document-oriented database and Spring Data MongoDB.
spring-boot-starter-jooq Used for jOOQ to access SQL databases. An alternative to spring-boot-starter-data-jpa or spring-boot-starter-jdbc.
spring-boot-starter-jta-narayana Used for Spring Boot Narayana JTA Starter.
spring-boot-starter-cloud-connectors It is used for Spring Cloud Connectors that simplifies connecting to services in cloud platforms like Cloud Foundry and Heroku.
spring-boot-starter-jta-bitronix It is used for JTA transactions using Bitronix.
spring-boot-starter-social-twitter For Spring Social Twitter.
spring-boot-starter-data-rest For exposing Spring Data repositories over REST using Spring Data REST.

Spring Boot Technical Starters

Name Description
spring-boot-starter-undertow Used for Undertow as the embedded servlet container. An alternative to spring-boot-starter-tomcat.
spring-boot-starter-jetty Used for Jetty as the embedded servlet container. An alternative to spring-boot-starter-tomcat.
spring-boot-starter-logging Used for logging using Logback. Default logging starter.
spring-boot-starter-tomcat Used for Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web.
spring-boot-starter-log4j2 Used for Log4j2 for logging. An alternative to spring-boot-starter-logging.

Convert Maven Project to Gradle Project


Install Gradle into your machine, here are the Gradle installation steps: https://docs.gradle.org/current/userguide/installation.html#installation

After successful installation of Gradle, below command should work in your command prompt/terminal window.

> gradle -v

------------------------------------------------------------
Gradle <<gradle version>>
------------------------------------------------------------

Now navigate to the maven root project directory(where pom.xml exists) and execute the below command:

 > gradle init 

When you run the command, gradle basically pars the existing pom.xmls and generates the corresponding Gradle build scripts. Gradle will also create a settings script if you’re migrating a multi-project build.

The new Gradle build includes the following:

  • All the custom repositories that are specified in the POM
  • External and inter-project dependencies
  • The appropriate plugins to build the project

Once successful migration of the project, you can run the below command to build the gradle project.

> gradle build

This will run the tests and produce the required artifacts without any extra intervention on your part.

Note: If your project contains multiple modules in which each module have its own pom with dependencies, then you may need to run `gradle init` command in each directory where ever pom exists.

Gradle Vs Maven


Started my software developement career in Java with Ant build tool. By the time I want to learn about Ant, my team has migrated to Maven in early 2011. Since then, Maven is only the build tool that have been using for all the applications.

Currently, Gradle and Maven are the two major build tools that many developers use during the software developement process. Some times it is very difficult to make a decision on which build tool to be used and why to use it? Most of the software developers are comforatble to use Maven, as it is standardised few years back or it might be already integrated with their existing applications.

But using a right build tool actually improves the devlopement and deployment time for a individual developers. In this article, I would like to discuss about Gradle and Maven build tools. At the end, we can conclude which build tool is a best fit for your application.

Gradle:

Gradle is a dependency management and a build automation tool used for different programming languages like Java, Android, C/C++. Gradle is based on a graph of task dependencies – in which tasks are the things that do the work.

Gradle led to smaller configuration files – compared to maven- with less clutter since the language was specifically designed to solve specific domain problems. Gradle’s configuration file is by convention called build.gradle.

Sample build.gradle file is below:

apply plugin: ‘java’

repositories {
mavenCentral()
}

jar {
baseName = ‘gradleExample’
version = ‘1.0.0-SNAPSHOT’
}

dependencies {
compile ‘junit:junit:4.12’
}

Maven:

Apache Maven is a dependency management and a build automation tool, primarily used for Java applications. Maven is based on a fixed and linear model of phases.

Maven prescribes strict project structure using configuration file called pom.xml, which also contains build and dependency management instructions. Maven’s build process is based on the available plugins in pom.xml. Maven supports wide range of plugins available in the market.

Here is the sample Spring-boot application maven pom.xml file

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.1.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>in.malliktalksjava</groupId>
	<artifactId>spring-boot-maven</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-boot-maven</name>
<properties>
    <java.version>1.8</java.version>
</properties>

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Which build tool is best suitable?

Both Maven and Gradle have their respective strengths and weaknesses, here are some points considered on Maven Vs Gradle

  • Flexibility: Both Gradle and Maven provide convention over configuration. However, Maven provides a very rigid model that makes customization tedious and sometimes impossible. While this can make it easier to understand any given Maven build, as long as you don’t have any special requirements, it also makes it unsuitable for many automation problems. Gradle, on the other hand, is built with an empowered and responsible user in mind.
  • Performance: Improving build time is one of the most direct ways to ship faster. Both Gradle and Maven employ some form of parallel project building and parallel dependency resolution. The biggest differences are Gradle’s mechanisms for work avoidance and incrementality. Here is the Performance comparision results for Maven and Gradle: https://gradle.org/gradle-vs-maven-performance/
  • User Experiance:  Maven also supports a wide variety of build life-cycle steps and integrates seamlessly with third-party tools such as CI servers, code coverage plugins, and artifact repository systems, among others. As far as plugins go, there is a growing number of available plugins now, and there are large vendors that have Gradle-compatible plugins. However, there are still more available plugins for Maven compared to the number available for Gradle. Gradle provides an interactive web-based UI for debugging and optimizing builds: build scans. These can also be hosted on-premise to allow an organization to collect build history and do trend analysis, compare builds for debugging, or optimize build times.
  • Dependency Management: Both build systems provide built-in capability to resolve dependencies from configurable repositories. Both are able to cache dependencies locally and download them in parallel.

Conclusion:

By this time, you might have already decided which tool is best suite for your requirement. Known fact is that, maven holds the majority of build tool market today but Gradle will be definately a good adoption for complex codebases and newly applications.

Here is the video based explanation for the same article:

Helpful Articles:

https://gradle.org/maven-vs-gradle/

https://dzone.com/articles/gradle-vs-maven

https://gradle.org/gradle-vs-maven-performance/

String.join() Example – Java 8


Java 8 has String.join() method where first parameter is separator and then you can pass either multiple strings or some instance of Iterable having instances of strings as second parameter. Here is the sample program:

package in.mallikatalksjava.java8;
import java.time.ZoneId;

public class StringJoinDemo {
   public static void main(String[] args) {
	String joined = String.join("", "mallik", "talks", "java",".in");
	System.out.println(joined);
		
	String directory = String.join("/", "C:", "java", "programs");
	System.out.println(directory);

	String ids = String.join(", ", ZoneId.getAvailableZoneIds());
	System.out.println(ids);
	}
}

Output:
malliktalksjava.in
C:/java/programs
Asia/Aden, America/Cuiaba, Etc/GMT+9, Etc/GMT+8, Africa/Nairobi, America/Marigot, Asia/Aqtau ....etc.

Node JS experienced interview questions


Is Node.js Single-threaded? Why it is required?

Yes, Node Js is single threaded to perform asynchronous processing.
All Node JS applications uses “Single Threaded Event Loop Model” architecture to handle multiple concurrent clients. Doing async processing on a single thread could provide more performance and scalability under typical web loads than the typical thread-based implementation.

What are events in Node Js?

An event is an action or occurrence recognized by software/app that is handled by event handler by writing a code that will be executed when the event fired.
Mouse move, Click, file copied or deleted are some examples of events.
In Node Js there are two types of events.
1)System Events: The event that comes from the C++ side.
2)Custom Events: Custom events are user-defined events.

What is an event loop in Node Js?

In Node Js processes are single threaded, to supports concurrency it uses events and callbacks. An event loop is a mechanism that allows Node.js to perform non-blocking I/O operations.

What is Express JS?

Express JS is an application framework which is light-weighted node JS. A number of flexible, useful and important features are provided by this JavaScript framework for the development of mobile as well as web applications with the help of node JS.

List some features of Express JS.

Some of the main features of Express JS are listed below: –

  • It is used for setting up middlewares so as to provide a response to the HTTP or RESTful requests.
  • With the help of express JS, the routing table can be defined for performing various HTTP operations.
  • It is also used for dynamically rendering HTML pages which are based on passing arguments to the templates.
  • It provides each and every feature which is provided by core Node JS.
  • The performance of Express JS is adequate due to the presence of a thin layer prepared by the Express JS.
  • It is used for organizing the web applications into the MVC architecture.
  • Everything from routes to rendering view and performing HTTP requests can be managed by Express JS.

Why we need to use Express.js in a node application?

Below are the few reasons why to use Express with Node.js

  • Express js is built on top of Node.js. It is the perfect framework for ultra-fast Input / Output.
  • Cross Platform
  • Support MVC Design pattern
  • Support of NoSQL databases out of the box.
  • Multiple templating engine support i.e. Jade or EJS which reduces the amount of HTML code you have to write for a page.
  • Support Middleware, basic web-server creation, and easy routing tools.

What are the differences between readFile and createReadStream in Node.js?

  • readFile load the whole file which you had marked to read whereas createReadStream reads the complete file in the parts of the size you have declared.
  • The client will receive the data faster in the case of createReadStream in contrast with readFile.
  • In readFile, a file will first completely read by memory and then transfers to a client but in later option, a file will be read by memory in a part which is sent to clients and the process continue until all the parts finish.

Show example for asynchronously/blocking and asynchronously/non-blocking

Normally NodeJs reads the content of a file in non-blocking, asynchronous way. Node Js uses its fs core API to deal with files. The easiest way to read the entire content of a file in nodeJs is with fs.readFile method. Below is sample code to read a file in NodeJs asynchronously and synchronously.

Reading a file in node asynchronously/ non-blocking

var fs = require('fs');  
fs.readFile('DATA', 'utf8', function(err, contents) { console.log(contents);
});
console.log('after calling readFile');

Reading a file in node asynchronously/blocking

var fs = require('fs'); 
var contents = fs.readFileSync('DATA', 'utf8'); console.log(contents);

What are Streams? List types of streams available in Node Js?

Streams are special types of objects in Node that allow us to read data from a source or write data to a destination continuously. There are 4 types of streams available in Node Js, they are

  • Readable − For reading operation.
  • Writable − For writing operation.
  • Duplex − Used for both read and write operation.
  • Transform − A type of duplex stream where the output is computed based on the input.

How to generate unique UUIDs/ guid in Node Js

Use node-uuid package to generate unique UUIDs/ guid in Node Js. Below code demonstrates how to generate it.

var uuid = require('node-uuid'); 
// Generate a v1 (time-based) id
uuid.v1();
// Generate a v4 (random) id
uuid.v4();

Rewrite the code sample without try/catch block:

Source: medium.com

Consider the code:

async function check(req, res) {
  try {
    const a = await someOtherFunction();
    const b = await somethingElseFunction();
    res.send("result")
  } catch (error) {
    res.send(error.stack);
  }
}

Rewrite the code sample without try/catch block.

Answer:

async function getData(){
  const a = await someFunction().catch((error)=>console.log(error));
  const b = await someOtherFunction().catch((error)=>console.log(error));
  if (a && b) console.log("some result")
}

or if you wish to know which specific function caused error:

async function loginController() {
  try {
    const a = await loginService().
    catch((error) => {
      throw new CustomErrorHandler({
        code: 101,
        message: "a failed",
        error: error
      })
    });
    const b = await someUtil().
    catch((error) => {
      throw new CustomErrorHandler({
        code: 102,
        message: "b failed",
        error: error
      })
    });
    //someoeeoe
    if (a && b) console.log("no one failed")
  } catch (error) {
    if (!(error instanceof CustomErrorHandler)) {
      console.log("gen error", error)
    }
  }
}

How to convert a JKS Keystore to a PKCS12 (.p12) format


To convert a JKS (.jks) keystore to a PKCS12 (.p12) keystore, run the following command:

Note: This command is supported on JDK / JRE keytool versions 1.6 and greater.

keytool -importkeystore -srckeystore <jks_file_name.jks> -destkeystore <pk12_file_name.p12> -srcstoretype JKS -deststoretype PKCS12 -deststorepass <password>

To verify the content of .p12 (e.g. pk12_file_name.p12), run the following command:
keytool -list -v -keystore <“pk12_file_name.p12”> -storetype <password>