July 17, 2021

Java throw Keyword With Examples

In the post try-catch block we have already seen some examples of exceptions but all those exceptions are thrown by Java run time. You may choose to throw an exception explicitly in your Java code, that can be done using throw statement in Java.

General form of Java throw statement

The throw statement requires a single argument; a throwable object.

throw throwableObj;

Here throwableObj must be an instance of Throwable class or any of its subclass.

How to get Throwable class instance

If you want to throw an exception explicitly you can get this Throwable class instance in two ways-

  1. You can create an instance using new operator. See example.
  2. You can use the exception parameter of the catch block and rethrow the exception. See example.

If there is a throw statement in a Java code then execution stops as soon as throw statement is encountered. Nearest catch block is checked for the matching exception type, if catch block has the matching exception type then that block handles the thrown exception. If matching exception type is not found then the next higher context is checked and so on.

Throw statement example with new exception instance

As stated above one of the way you can throw exception in your code is by creating an exception instance using new operator.

public class ThrowDemo {
  public static void main(String[] args) {
    try{
      if(args.length != 2){
        throw new IllegalArgumentException("Two parameters should be passed");
      }
    }catch(IllegalArgumentException exp){
      System.out.println("Exception in the code " + exp.getMessage());
      exp.printStackTrace();
    }
  }
}
Output
Exception in the code Two parameters should be passed
java.lang.IllegalArgumentException: Two parameters should be passed
at com.knpcode.ThrowDemo.main(ThrowDemo.java:8)

In the above code exception is thrown if 2 arguments are not passed. The constructor used while creating exception instance is the one that takes String argument. That way you can pass a clear reason why exception is thrown. There is a method getMessage() method in Exception classes that can be used to display that message.

Java throw statement example when same exception is rethrown

You can also rethrow the exception that is caught in a catch block. One of the common reason to do that is to see if there is any exception handler for that specific exception which is thrown. As example if you have a catch block with Exception as exception type it will catch most of the exceptions since Exception is higher up in the exception hierarchy . You can rethrow that exception to be caught by an exception handler with the specific exception type.

public class ExceptionDemo {
  public static void main(String[] args) {
    ExceptionDemo ed = new ExceptionDemo();
    try{
      ed.division(7, 0);
    }catch(ArithmeticException exp){
      System.out.println("Exception occurred while dividing" + exp.getMessage());
      exp.printStackTrace();
    }
  }
	
  private void division(int num1, int num2){
    double result;
    try{
      result = num1/num2;
      System.out.println("Result" + result);
    }catch(Exception exp){
      System.out.println("Exception occurred while dividing" + exp.getMessage());
      throw exp;
    }	
  }
}
Output
Exception occurred while dividing/ by zero
java.lang.ArithmeticException: / by zero
	at com.knpcode.ExceptionDemo.division(ExceptionDemo.java:18)
	at com.knpcode.ExceptionDemo.main(ExceptionDemo.java:8)
Exception occurred while dividing/ by zero
java.lang.ArithmeticException: / by zero
	at com.knpcode.ExceptionDemo.division(ExceptionDemo.java:18)
	at com.knpcode.ExceptionDemo.main(ExceptionDemo.java:8)

In the above code division method has a catch block with parameter of class Exception. From there you are rethrowing the caught exception. In the calling method it is caught again by the catch block which has parameter of type ArithmeticException.

Rethrowing a different exception

You can also catch one type of exception and rethrow exception of another type using Java throw keyword. Actually it is a best practice for exception handling to do that when you are propagating exception through separate layers. That helps in preserving loose coupling of your code.

For example, in your DB layer SQLException is caught there is no sense in letting the same exception propagate to your business layer. In this case best thing to do is catch the SQLException which is a checked exception in your DAO layer and rethrow another exception (unchecked) that should propagate to business layer. You should send the original exception instance as a parameter.

catch(SQLException ex){
  throw new RuntimeException("Error in DB layer", ex);
}

That's all for the topic Java throw Keyword With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

July 16, 2021

Spring Boot Microservices Eureka + Ribbon

In the article Spring Boot Microservices example we saw an example of Spring Boot Microservice where we used Eureka for service registration and discovery. In this post we’ll extend that example further to see how to use both Eureka and Ribbon load balancer with Spring Boot to load the balance among micro services instances.

In the example there were two separate services User and Account which were registered with Eureka. From User service there was a call to Account service to fetch some data. In this post we’ll see how to configure more than one instances of Account service and use Ribbon load balancer to route the calls among those instances of Account service.

Load Balancing

In simple terms load balancing means distributing the load across several resources rather than putting all the load on a single resource. That helps in increasing throughput as there are more resources to share the load, increases reliability as there are more redundant resource to process the request even if any one resource goes down so there is no single point of failure.

Using Ribbon load balancing with Eureka

As we know Eureka is used for service registration and discovery where as Ribbon is a client side load balancer. Here I’ll try to explain how these two tools work together.

Eureka server maintains a service registry by registering each microservice with the Eureka server. When the inter-service communication happens, calling service interrogates the service registry using DiscoveryClient and gets in return all the instances of the called microservice. Now the question is, out of all the returned instances which one to call?

That’s where client load balancer like Ribbon comes in the picture. Client side load balancer uses an algorithm, like round robin (calling each instance in sequence) or using zone information (to locate a server in the same zone as the client), to get the instance of service that has to be called.

Spring Boot Microservice with loadbalancing

Spring Boot Micro Service with Ribbon example

In the Spring Boot Microservices example we have already seen how to configure Eureka server and how to register micro services User and Account with it by enabling discovery client (Using @EnableDiscoveryClient (or @EnableEurekaClient) annotation).

One problem was the URL used while calling Account service from User which hardcodes the host and port. That means every time same service will be called even if you create more instances of Account.

List<Account> accounts = new RestTemplate().exchange(
       "http://localhost:9000/accounts/{empId}", HttpMethod.GET, null, new
       ParameterizedTypeReference<List<Account>>(){}, id).getBody();

What we want is an abstraction so that the correct host and port is resolved at run time, that’s what we’ll try to configure using Netflix’s Ribbon load balancing service. To enable Ribbon you need to add the following dependency in pom.xml

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

Though this dependency is added automatically when you add dependency for eureka client. So, this dependency will suffice.

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

Creating another instance of Account Microservice

Now we want to scale up our service and need multiple copies of Account. We already created a Spring Boot project for the same with the following in application.properties.

eureka.client.service-url.default-zone=http://localhost:8761/eureka
server.port=9000
spring.application.name=account

After starting this instance you can change the port to 9001 and start the Account application again. That way you will have two instances one listening at port 9000 and another at port 9001.

You can also create a Separate Spring Boot project copy the files from Account and paste the following in application.properties

eureka.client.service-url.default-zone=http://localhost:8761/eureka
server.port=9001
spring.application.name=account

Either way you will have two instances running of the same service. You can verify it in Eureka Server by accessing URL - http://localhost:8761/

Eureka with ribbon

Creating LoadBalanced aware RestTemplate

Since we are using an instance of RestTemplate to make a call to another Service so we can make the RestTemplate bean load balanced aware. That can be done using @LoadBalanced annotation which instructs Netflix Ribbon to wrap this RestTemplate bean with load balancing advice.

Create a Config.java class in SpringBootUser project as given below.

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
 
@Configuration 
public class Config { 
  @Bean 
  @LoadBalanced
  RestTemplate restTemplate() { 
    return new RestTemplate(); 
  } 
}

Injecting the load balanced RestTemplate

Now you can inject this load balanced RestTemplate into the UserService. Then, in the URL, you can use the logical name of the service that was used to register it with Eureka. That’s how we are using this URL http://ACCOUNT/accounts/{empId} to access Account MicroService instance.

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.client.RestTemplate;

@Service
public class UserService {
  @Autowired
  private RestTemplate restTemplate;
    public List<Account> showEmployees(@PathVariable("id") String id) {
    System.out.println(id);
    
    List<Account> accounts = restTemplate.exchange(
    "http://ACCOUNT/accounts/{empId}", HttpMethod.GET, null, new
    ParameterizedTypeReference<List<Account>>(){}, id).getBody();
    // Another call (to demo load balancing)
    accounts = restTemplate.exchange(
            "http://ACCOUNT/accounts/{empId}", HttpMethod.GET, null, new
            ParameterizedTypeReference<List<Account>>(){}, id).getBody();
    return accounts;          
  }
}

Testing the application

Once the changes are done start all the applications i.e. Eureka Server, User MicroService and two instances of Account MicroService.

In the console of SpringBootUser application you can see that the Load balancer has recognized the list of servers and one of them will be called to service the request.

2020-04-25 17:02:06.405  INFO 9908 --- [nio-8080-exec-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: ACCOUNT.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-04-25 17:02:06.573  INFO 9908 --- [nio-8080-exec-1] c.n.u.concurrent.ShutdownEnabledTimer    : Shutdown hook installed for: NFLoadBalancer-PingTimer-ACCOUNT
2020-04-25 17:02:06.575  INFO 9908 --- [nio-8080-exec-1] c.netflix.loadbalancer.BaseLoadBalancer  : Client: ACCOUNT instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=ACCOUNT,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2020-04-25 17:02:06.637  INFO 9908 --- [nio-8080-exec-1] c.n.l.DynamicServerListLoadBalancer      : Using serverListUpdater PollingServerListUpdater
2020-04-25 17:02:06.905  INFO 9908 --- [nio-8080-exec-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: ACCOUNT.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-04-25 17:02:06.923  INFO 9908 --- [nio-8080-exec-1] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client ACCOUNT initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=ACCOUNT,current list of Servers=[user:9000, user:9001],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;	Instance count:2;	Active connections count: 0;	Circuit breaker tripped count: 0;	Active connections per server: 0.0;]
},Server stats: [[Server:user:9000;	Zone:defaultZone;	Total Requests:0;	Successive connection failure:0;	Total blackout seconds:0;	Last connection made:Thu Jan 01 05:30:00 IST 1970;	First connection made: Thu Jan 01 05:30:00 IST 1970;	Active Connections:0;	total failure count in last (1000) msecs:0;	average resp time:0.0;	90 percentile resp time:0.0;	95 percentile resp time:0.0;	min resp time:0.0;	max resp time:0.0;	stddev resp time:0.0]
, [Server:user:9001;	Zone:defaultZone;	Total Requests:0;	Successive connection failure:0;	Total blackout seconds:0;	Last connection made:Thu Jan 01 05:30:00 IST 1970;	First connection made: Thu Jan 01 05:30:00 IST 1970;	Active Connections:0;	total failure count in last (1000) msecs:0;	average resp time:0.0;	90 percentile resp time:0.0;	95 percentile resp time:0.0;	min resp time:0.0;	max resp time:0.0;	stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@7ef76128

Accessing services

You can start the service by accessing URL- http://localhost:8080/user/1

Try to access the same URL in different browser tabs and you can see that requests are getting divided between two Account service instances.

Download source code- https://github.com/knpcode/SpringBoot-MicroService-Ribbon

That's all for the topic Spring Boot Microservices Eureka + Ribbon. If something is missing or you have something to share about the topic please write a comment.


You may also like

July 15, 2021

Spring Boot Microservices Example

In this article we’ll see a Spring Boot Microservices example with Eureka used for service registration and discovering the service. We’ll have two separate services User and Account developed as Microservices. With two microservices we'll also see how to call one microservice from another using RestTemplate.

When a large monolith application is split into two or more microservices those microservices may need to interact with each other. To do that these microservices need to be aware of each others existence and should be able to find each other. This process is known as service discovery. There is a tool called Eureka created by Netflix that can act as a discovery server, for that you need to register your microservices with the Eureka server.

So, in this Spring Boot Microservices example we are going to create 3 separate Spring Boot applications two for the functionality of User and Account and third one for Eureka Server.

Spring Boot application for Eureka Server

First we’ll create a Spring Boot project for configuring Eureka Server, this application acts as a service registry.

Starter you need to add for Eureka Server is spring-cloud-starter-netflix-eureka-server

Maven dependencies – pom.xml

pom.xml with the starter dependencies. Note that Spring Boot version used is 2.3.4.RELEASE and Spring Cloud version is Hoxton.SR8

<?xml version="1.0" encoding="UTF-8"?>
<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.3.4.RELEASE</version>
    <relativePath/>
  </parent>
  <groupId>com.knpcode</groupId>
  <artifactId>springeureka</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>EurekaServer</name>
  <description>Eureka Server project</description>

  <properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-server</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>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

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

</project>

Application class

Application class with main method.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

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

In the application class apart from @SpringBootApplication annotation another annotation @EnableEurekaServer is also added.

@EnableEurekaServer annotation indicates that we want to run a Eureka Server. By seeing a dependency on Spring Cloud Eureaka, Spring Boot automatically configures the application as a service registry.

Eureka Server Configuration

In the application.properties put the following.

server.port=8761
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

server.port configures the port Eureka Server runs on.

For a stand alone instance we don’t want Eureka Server to be a client too that is why these two entries-

eureka.client.register-with-eureka=false

eureka.client.fetch-registry=false

Running Eureka Server

Eureka server application is ready and you can run the EurekaServerApplication class to start the Eureka Server.

You should get the following messages if every thing runs fine-

2020-03-12 14:53:16.457  INFO 14400 --- [      Thread-10] e.s.EurekaServerInitializerConfiguration : Started Eureka Server
2020-03-12 14:53:16.503  INFO 14400 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8761 (http) with context path ''
2020-03-12 14:53:16.507  INFO 14400 --- [           main] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 8761
2020-03-12 14:53:19.314  INFO 14400 --- [           main] o.n.s.EurekaServerApplication            : Started EurekaServerApplication in 30.203 seconds (JVM running for 33.929)

You can see the Eureka Server console by accessing URL- http://localhost:8761/

Spring boot eureka server

As you can see currently no instances are registered with Eureka. That’s what is the next task, to create Spring Boot microservices and register them with Eureka Server.

Spring Boot Account application

Create another Spring Boot project for Account Microservice, starter dependency for eureka client has to be added, in place of eureka-server, to register this Microservice as Eureka client. All the other dependencies remain same as used in Eureka Server application.

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

Rest Controller class

We’ll add a controller with the functionality to find all the accounts for the passed EmployeeId.

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AccountController {
  @Autowired
  private AccountService accountService;
  
  @GetMapping(value="/accounts/{empId}") 
  public List<Account>getAccountsByEmpId(@PathVariable String empId) { 
    System.out.println("EmpId------" + empId);
    List<Account> empAccountList = accountService.findAccountsByEmpId(empId);
    return empAccountList; 
  }
}

AccountService class

In the AccountService class you can see there is a dummy method to get the Accounts rather than accessing DB in order to keep the focus on interaction between microservices.

import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;

@Service
public class AccountService {
  public List<Account> findAccountsByEmpId(String empId){
    List<Account> accountList = getAccountList();
    List<Account> empAccountList = new ArrayList<>();
    for(Account account :  accountList) {
      if(account.getEmpId().equals(empId))
        empAccountList.add(account);
    }
    return empAccountList;
  }
    
  private List<Account> getAccountList(){
    List<Account> accountList = new ArrayList<>();
    accountList.add(new Account("1", "AC1", "MT"));
    accountList.add(new Account("1", "AC2", "IN"));
    accountList.add(new Account("2", "AC3", "IN"));
    return accountList;
  }
}
DTO Class

There is also an Account class that acts as a DTO or a model bean.

public class Account {
  private String empId;
  private String accountId;
  private String branch;
  Account(){
    
  }
  Account(String empId, String accountId, String branch){
    this.empId = empId;
    this.accountId = accountId;
    this.branch = branch;
  }
  public String getEmpId() {
    return empId;
  }
  public void setEmpId(String empId) {
    this.empId = empId;
  }
  public String getAccountId() {
    return accountId;
  }
  public void setAccountId(String accountId) {
    this.accountId = accountId;
  }
  public String getBranch() {
    return branch;
  }
  public void setBranch(String branch) {
    this.branch = branch;
  }
}

Application class

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class SpringBootAccountApplication {
  public static void main(String[] args) {
    SpringApplication.run(SpringBootAccountApplication.class, args);
  }
}

Application class is annotated with the @EnableDiscoveryClient (so that this application can be discovered as Eureka client, you can also use @EnableEurekaClient annotation instead of @EnableDiscoveryClient) along with the @SpringBootApplication annotation.

Configuration for Eureka Client

Following properties are also to be added to the application.properties file to register Account Microservice as Eureka client.

eureka.client.service-url.default-zone=http://localhost:8761/eureka
server.port=9000
spring.application.name=account

eureka.client.service-url.default-zone property tells our microservice where to look for Eureka Server.

Using spring.application.name you give a logical name to your microservice.

Server port is configured as 9000 so this Account application runs on port 9000.

Registering Account Microservice as Eureka client

Run the SpringBootAccountApplication class to start this RESTful service. It will automatically be registered as Eureka client. You can verify that seeing the messages on the console.

2020-03-12 15:23:58.585  INFO 12416 --- [  restartedMain] o.s.c.n.e.s.EurekaServiceRegistry        : Registering application ACCOUNT with eureka with status UP
2020-03-12 15:23:58.588  INFO 12416 --- [  restartedMain] com.netflix.discovery.DiscoveryClient    : Saw local status change event StatusChangeEvent [timestamp=1584006838588, current=UP, previous=STARTING]
2020-03-12 15:23:58.597  INFO 12416 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_ACCOUNT/user:account:9000: registering service...
2020-03-12 15:23:58.940  INFO 12416 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9000 (http) with context path ''
2020-03-12 15:23:58.945  INFO 12416 --- [  restartedMain] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 9000
2020-03-12 15:23:59.194  INFO 12416 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_ACCOUNT/user:account:9000 - registration status: 204
2020-03-12 15:24:02.128  INFO 12416 --- [  restartedMain] o.n.a.SpringBootAccountApplication       : Started SpringBootAccountApplication in 31.85 seconds (JVM running for 35.175)

Verifying Eureka Server

If you refresh the URL for Eureka Server- http://localhost:8761/ now you should see an instance registered. Name of the instance is same as what was configured as a logical name using the following property.

spring.application.name=account

Spring Boot microservice example

Spring Boot User application

Another microservice we need to create is the User service so create another project. There again add the same starter dependency to register this Microservice as Eureka client.

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

Rest Controller class

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
  @Autowired
  private UserService userService;
  
  @GetMapping(value="/user/{id}")
  public List<Account> showEmployees(@PathVariable("id") String id) {     
    List<Account> accounts = userService.showEmployees(id);
    // displaying accounts
    for(Account acct : accounts) {
      System.out.println(acct.getEmpId());
      System.out.println(acct.getAccountId());
      System.out.println(acct.getBranch());
    }
    return accounts;          
  }
}
UserService Class

In method showEmployees there is a call to the Account microservice to get all the associated accounts for the passed employee ID.

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.client.RestTemplate;

@Service
public class UserService {
  @Autowired
  private RestTemplate restTemplate;
  public List<Account> showEmployees(@PathVariable("id") String id) {
    System.out.println(id);
    //List<Account> accounts = new RestTemplate().exchange(
    //"http://localhost:9000/accounts/{empId}", HttpMethod.GET, null, new
    //ParameterizedTypeReference<List<Account>>(){}, id).getBody();
    
    List<Account> accounts = restTemplate.exchange(
    "http://ACCOUNT/accounts/{empId}", HttpMethod.GET, null, new
    ParameterizedTypeReference<List<Account>>(){}, id).getBody();
    return accounts;          
  }
}

restTemplate.exchange() is the method used for making remote call to another microservice.

  • First argument to restTemplate.exchange() is the URL to the Account microservice- "http://ACCOUNT/accounts/{empId}"
  • Second argument specifies that it is a HTTP Get command.
  • Third argument specifies the entity (headers and/or body) to write to the request. As we are not passing any request entity so it is null.
  • Fourth argument specifies the type of the response.
  • Fifth argument specifies the variables to expand in the template. We are passing id there which will replace {empId} in the URL.

Using Ribbon Load Balancer

In the above method you can see that the URL used for calling Microservice is http://ACCOUNT/accounts/{empId} though you can also use http://localhost:9000/accounts/{empId} but that hardcodes the location which is not good.

To avoid that hardcoding we are using Netflix's Ribbon service which can be integrated with Eureka. What we need to do is to mark a RestTemplate bean to be configured to use a LoadBalancerClient, to do that we can create RestTemplate bean as following.

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration 
public class Config { 
  @Bean 
  @LoadBalanced
  RestTemplate restTemplate() { 
    return new RestTemplate(); 
  } 
}

Once you have this Load balanced restTemplate instance then you can use the logical name of the service, in the URL, that was used to register it with Eureka. That’s how we are using this URL http://ACCOUNT/accounts/{empId} to access Account MicroService.

Application class

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class SpringBootUserApplication {
  public static void main(String[] args) {
    SpringApplication.run(SpringBootUserApplication.class, args);
  }
}

Configuration for Eureka Client

Following properties are also to be added to the application.properties file to register User Microservice as Eureka client.

eureka.client.service-url.default-zone=http://localhost:8761/eureka
spring.application.name=user

Run the SpringBootUserApplication to start User MicroService. It will automatically be registered as Eureka client. You can verify that by seeing the messages on the console.

2020-03-12 16:24:00.228  INFO 9844 --- [  restartedMain] o.s.c.n.e.s.EurekaServiceRegistry        : Registering application USER with eureka with status UP
2020-03-12 16:24:00.231  INFO 9844 --- [  restartedMain] com.netflix.discovery.DiscoveryClient    : Saw local status change event StatusChangeEvent [timestamp=1584010440231, current=UP, previous=STARTING]
2020-03-12 16:24:00.240  INFO 9844 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_USER/user:user: registering service...
2020-03-12 16:24:00.402  INFO 9844 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_USER/user:user - registration status: 204
2020-03-12 16:24:00.572  INFO 9844 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-03-12 16:24:00.577  INFO 9844 --- [  restartedMain] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 8080
2020-03-12 16:24:03.278  INFO 9844 --- [  restartedMain] com.knpcode.user.SpringBootUserApplication   : Started SpringBootUserApplication in 28.889 seconds (JVM running for 33.647)

If you refresh the URL for Eureka Server- http://localhost:8761/ you should see both the MicroServices registered as Eureka clients.

Microservice with load balancing

Communication between MicroServices

Now we have two MicroSerivces created and running. Both of the MicroServices are registered with Eureka so these services can be discovered using Eureka.

Now when you access the URL http://localhost:8080/user/1 it will be serviced by showEmployees() method of the UserController in SpringBootUser application. From there using restTemplate.exchange() method it communicates with Account service.

Microservice with eureka client discovery

The URL (http://ACCOUNT/accounts/{empId}) passed in the exchange method triggers the whole process of load balancing and discovering the Eureka client as evident from the log messages.

2020-03-12 16:36:37.733  INFO 9844 --- [nio-8080-exec-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: ACCOUNT.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-03-12 16:36:37.915  INFO 9844 --- [nio-8080-exec-1] c.n.u.concurrent.ShutdownEnabledTimer    : Shutdown hook installed for: NFLoadBalancer-PingTimer-ACCOUNT
2020-03-12 16:36:37.916  INFO 9844 --- [nio-8080-exec-1] c.netflix.loadbalancer.BaseLoadBalancer  : Client: ACCOUNT instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=ACCOUNT,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2020-03-12 16:36:37.963  INFO 9844 --- [nio-8080-exec-1] c.n.l.DynamicServerListLoadBalancer      : Using serverListUpdater PollingServerListUpdater
2020-03-12 16:36:38.090  INFO 9844 --- [nio-8080-exec-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: ACCOUNT.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-03-12 16:36:38.098  INFO 9844 --- [nio-8080-exec-1] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client ACCOUNT initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=ACCOUNT,current list of Servers=[user:9000],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;	Instance count:1;	Active connections count: 0;	Circuit breaker tripped count: 0;	Active connections per server: 0.0;]
},Server stats: [[Server:user:9000;	Zone:defaultZone;	Total Requests:0;	Successive connection failure:0;	Total blackout seconds:0;	Last connection made:Thu Jan 01 05:30:00 IST 1970;	First connection made: Thu Jan 01 05:30:00 IST 1970;	Active Connections:0;	total failure count in last (1000) msecs:0;	average resp time:0.0;	90 percentile resp time:0.0;	95 percentile resp time:0.0;	min resp time:0.0;	max resp time:0.0;	stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@5820f552
1
AC1
MT
1
AC2
IN
2020-03-12 16:36:38.995  INFO 9844 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty  : Flipping property: ACCOUNT.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
favicon.ico
2020-03-12 16:38:59.147  INFO 9844 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver      : Resolving eureka endpoints via configuration
2020-03-12 16:43:59.150  INFO 9844 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver      : Resolving eureka endpoints via configuration

Download sourcecode- SpringBoot-MicroService-Example

That's all for the topic Spring Boot Microservices Example. If something is missing or you have something to share about the topic please write a comment.


You may also like

July 10, 2021

How to Copy a Directory in Java

This post shows how to copy a directory in Java where all the files and sub folders with in a directory are recursively copied to a new directory.

Options for copying a directory in Java

For copying the folder tree structure which includes the sub-directories and all the files you can use one of the following options in Java-

  • Using File.listFiles() method which returns an array of abstract pathnames denoting the files in the directory. Then you can iterate the array to list the files and copy them to the target directory, you will have to recursively call your method to list files with in the sub-directories. See example.
  • Java 7 onward you can use Files.walkFileTree method which walks a file tree rooted at a given starting file. See example.
  • Java 8 onward you can use Files.walk() method which returns the Path objects as stream by walking the file tree rooted at a given starting file. See example.

Directory structure used

Java programs shown here to copy a directory in Java use the following directory structure.

copy a folder in Java

With in the parent folder there is one sub folder Child with two files and one file is stored in the parent folder.

Copying directory in Java using Files.walk() method

Java 8 onward You can use Files.walk() method which returns the Path objects as stream. Each path in that Stream can be checked then to verify whether it's a directory or a file. If it is a file, it has to be copied to the target location, in case of directory you need to create that directory at the target location.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class CopyDirectory {
  public static void main(String[] args) {
    final String SOURCE_DIR = "F:/knpcode/Parent";
    final String TARGET_DIR = "F:/knpcode/Parent_New";
    directoryCopy(SOURCE_DIR, TARGET_DIR);
  }

  private static void directoryCopy(String sourceDir, String targetDir){
    Path sourcePath = Paths.get(sourceDir);
    Path targetPath = Paths.get(targetDir);
    try(Stream<Path> filePaths = Files.walk(sourcePath)) {
      filePaths.forEach(filePath -> {
        try {
          if (Files.isRegularFile(filePath)) {
            Path newFile = targetPath.resolve(sourcePath.relativize(filePath));
            Files.copy(filePath, newFile);
            System.out.println("Copied file " + newFile);
          }else{
            Path newDir = targetPath.resolve(sourcePath.relativize(filePath));
            Files.createDirectory(newDir);
            System.out.println("Created Directory " + newDir);
          }
        }catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        } 
      });
    }catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
Output
Created Directory F:\knpcode\Parent_New
Created Directory F:\knpcode\Parent_New\Child
Copied file F:\knpcode\Parent_New\Child\hello.txt
Copied file F:\knpcode\Parent_New\Child\Project.docx
Copied file F:\knpcode\Parent_New\Test.txt

Copying directory in Java using Files.walkFileTree() method

Java 7 onward You can use Files.walkFileTree() method using which you can walk the tree structure of the source directory and copy all files and sub-directories in the process.

One of the argument of this method is a FileVisitor interface. You do need to provide implementation of this interface as per your requirement.

FileVisitor interface has four methods, for listing files in a folder you do need to implement two of them; preVisitDirectory and visitFile.

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;

public class CopyDirectory {
  public static void main(String[] args) {
    final String SOURCE_DIR = "F:/knpcode/Parent";
    final String TARGET_DIR = "G:/Parent_New";
    try {
      directoryCopy(SOURCE_DIR, TARGET_DIR);
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  private static void directoryCopy(String sourceDir, String targetDir) throws IOException{
    Path sourcePath = Paths.get(sourceDir);
    Path targetPath = Paths.get(targetDir);
    // Walk the tree structure using WalkFileTree method       
    Files.walkFileTree(sourcePath, new SimpleFileVisitor<Path>(){
      @Override
      // Before visiting the directory, create directory 
      public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
        Path newDir = targetPath.resolve(sourcePath.relativize(dir));
        System.out.println("Path- " + newDir.toString());
        Files.createDirectory(newDir);
        return FileVisitResult.CONTINUE;
      }
      @Override
      // For each visited file copy it
      public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
        Path newFile = targetPath.resolve(sourcePath.relativize(file));
        System.out.println("Path- " + newFile.getFileName());
        Files.copy(file, newFile);                
        return FileVisitResult.CONTINUE;
      }
    });  
  }
}

Copying directory in Java using File.listFiles() method

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

public class CopyDirectory {
  public static void main(String[] args) {
    final String SOURCE_PATH = "F:/knpcode/Parent";
    final String TARGET_PATH = "F:/knpcode/Parent_New";
    File sourceDir = new File(SOURCE_PATH);
    File targetDir = new File(TARGET_PATH);
    try {
      directoryCopy(sourceDir, targetDir);
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  private static void directoryCopy(File sourceDir, File targetDir) throws IOException{
    if(sourceDir.isDirectory()){
      // create target directory
      if(!targetDir.exists()){
        targetDir.mkdir();
        System.out.println("Created Directory " + targetDir);
      }
      File[] fileList = sourceDir.listFiles();
      for(File file : fileList){
        File sourceFile =  new File(sourceDir, file.getName());
        File targetFile = new File(targetDir, file.getName());
        // Recursive call in case of directory
        directoryCopy(sourceFile, targetFile);
      }
    }else{ // if it is a file
      Files.copy(sourceDir.toPath(), targetDir.toPath());
      System.out.println("Copied file " + targetDir);
    }
  }
}
Output
Created Directory F:\knpcode\Parent_New
Created Directory F:\knpcode\Parent_New\Child
Copied file F:\knpcode\Parent_New\Child\hello.txt
Copied file F:\knpcode\Parent_New\Child\Project.docx
Copied file F:\knpcode\Parent_New\Test.txt

That's all for the topic How to Copy a Directory in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like

July 9, 2021

Delete a File or Directory Using a Java Program

This post shows how to delete a file or directory using a Java program and how to delete a directory recursively in Java. For deleting a file or directory, Java provides following options.

  • delete()- You can use the delete method of java.io.File class. This method deletes the file or directory denoted by this abstract pathname. If you are trying to delete a directory, then the directory must be empty in order to be deleted. Method returns true if the file or directory is successfully deleted otherwise returns false.
  • Files.delete(Path path)- Java 7 onward Files.delete() method can be used to delete a file or directory. For deleting a directory it must be ensured that the directory is empty. This method throws NoSuchFileException if the file does not exist and throws DirectoryNotEmptyException if the file is a directory and could not otherwise be deleted because the directory is not empty.
  • Files.deleteIfExists(Path path)- Another option in Files class to delete a file or directory is to use deleteIfExists() method. This method deletes a file or folder if it exists and returns true if the file was deleted by this method; false if the file could not be deleted because it did not exist. Same restriction for the directory applies that directory must be empty.

In the post we’ll see Java examples of deleting files and directories using the above mentioned methods. We’ll also see how to delete a non-empty directory by recursively deleting the files and sub-directories and ultimately deleting the parent directory.

Deleting file using java.io.File delete method

In the example code all the scenarios are covered-

  1. A file that exists at the given path is deleted.
  2. Trying to delete a file that doesn’t exist.
  3. Deleting an empty directory.
  4. Trying to delete non-empty directory.
public class DeleteFile {
  public static void main(String[] args) {
    File file = new File("F:\\knpcode\\Test\\postend.txt");
    fileDelete(file);

    // trying to delete file that doesn't exist
    file = new File("F:\\knpcode\\Test\\postend.txt");
    fileDelete(file);

    // Deleting empty directory
    file = new File("F:\\knpcode\\Test");
    fileDelete(file);

    // Deleting non-empty directory
    file = new File("F:\\knpcode\\Parent");
    fileDelete(file);
  }
	
  private static void fileDelete(File file){
    if(file.delete()){
      System.out.println("File " + file.getName() + " deleted successfully");
    }else{
      System.out.println("File " + file.getName() + " not deleted as it doesn't exist/non-empty directory");
    }
  }
}
Output
File postend.txt deleted successfully
File postend.txt not deleted as it doesn't exist/non-empty directory
File Test deleted successfully
File Parent not deleted as it doesn't exist/non-empty directory

Deleting file using Files delete and deleteIfExists method

Files.delete method to delete file

import java.io.IOException;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Paths;

public class DeleteFile {
  public static void main(String[] args) {
    try {
      Files.delete(Paths.get("F:\\knpcode\\Test\\postend.txt"));
      // deleting same file again - file that doesn't exist scenario
      Files.delete(Paths.get("F:\\knpcode\\Test\\postend.txt"));
    } catch (NoSuchFileException e) {	
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    catch (DirectoryNotEmptyException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
Output
java.nio.file.NoSuchFileException: F:\knpcode\Test\postend.txt
	at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)
	at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
	at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
	at sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:269)
	at sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103)
	at java.nio.file.Files.delete(Files.java:1126)
	at com.knpcode.programs.DeleteFile.main(DeleteFile.java:16)

Files.deleteIfExists method to delete file

public class DeleteFile {

  public static void main(String[] args) {
    try {
      if(Files.deleteIfExists(Paths.get("F:\\knpcode\\Test\\postend.txt")))
        System.out.println("File deleted successfully");
      else
        System.out.println("File not deleted");
      // deleting same file again - file that doesn't exist scenario
      if(Files.deleteIfExists(Paths.get("F:\\knpcode\\Test\\postend.txt")))
        System.out.println("File deleted successfully");
      else
        System.out.println("File not deleted");
    }
    catch (DirectoryNotEmptyException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
Output
File deleted successfully
File not deleted

Files.delete method to delete folder in Java

public class DeleteFile {
  public static void main(String[] args) {
    try {      
      // Deleting empty directory
      Files.delete(Paths.get("F:\\knpcode\\Test"));
      
      // Deleting non-empty directory
      Files.delete(Paths.get("F:\\knpcode\\Parent"));
      
    } catch (NoSuchFileException e) {	
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    catch (DirectoryNotEmptyException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
Output
java.nio.file.DirectoryNotEmptyException: F:\knpcode\Parent
	at sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:266)
	at sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103)
	at java.nio.file.Files.delete(Files.java:1126)
	at com.knpcode.programs.DeleteFile.main(DeleteFile.java:22)

Deleting non-empty directory recursively in Java

As you can see from the above examples directory should be empty to be deleted, in case of non-empty directory it is not deleted. For deleting a non-empty directory you need to recursively walk through the folder structure and delete all the files and sub-directories before deleting the parent directory which is empty by then.

For recursively deleting a file in Java there are two options-

  1. Using File.listFiles() method which returns an array of abstract pathnames denoting the files in the directory. Then you can iterate the array to delete the files and you will have to recursively call your method to delete files with in the sub-directories.
  2. Java 7 onward you can use Files.walkFileTree() method which walks a file tree rooted at a given starting file.

Directory structure used

Java programs shown here to delete a non-empty directory in Java use the following directory structure.

delete directory using Java

With in the parent folder there are two sub-folders Child with two files and Empty with no file. One file is stored in the parent folder.

Deleting directory recursively using File.listFiles() method

public class DeleteDirectory {
  public static void main(String[] args) {
    // Source folder
    final String SOURCE_DIR = "F:/knpcode/Parent";
    File sourceDir = new File(SOURCE_DIR);
    directoryDeletion(sourceDir);
  }
	
  private static void directoryDeletion(File sourceDir){
    if(!sourceDir.isDirectory()){
      System.out.println("Not a directory.");
      return;
    }
    File[] fileList = sourceDir.listFiles();
    for(File file : fileList){
      // if directory call method recursively to 
      // list files with in sub-directories for deletion
      if(file.isDirectory()){
        System.out.println("Sub Directory- " + file.getName());
        directoryDeletion(file);
      }else{				 
        System.out.println("Deleting file- " + file.getName());
        // if it is a file then delete it
        file.delete();
      }
    }
    // For deleting sub-directories and parent directory
    System.out.println("Deleting Directory - " + sourceDir.getName());
    sourceDir.delete();
  }
}
Output
Sub Directory- Child
Deleting file- hello.txt
Deleting file- Project.docx
Deleting Directory - Child
Sub Directory- Empty
Deleting Directory - Empty
Deleting file- Test.txt
Deleting Directory – Parent

Deleting directory recursively using Java Files.walkFileTree method

Java 7 onward You can use Files.walkFileTree() method using which you can walk the tree structure of the source directory and delete all the files and sub-directories in the process. One of the argument of this method is a FileVisitor interface. You do need to provide implementation of this interface as per your requirement.

FileVisitor interface has four methods, for deleting directory recursively you do need to implement two of them; postVisitDirectory() (to delete directory after visiting all the files) and visitFile (to delete files).

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;

public class DeleteDirectory {
  public static void main(String[] args) {
    // Source folder
    final String SOURCE_PATH = "F:/knpcode/Parent";
    try {
      directoryDeletion(SOURCE_PATH);
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
  }
	
  private static void directoryDeletion(String sourceDir) throws IOException {
    Path sourcePath = Paths.get(sourceDir);
    Files.walkFileTree(sourcePath, new SimpleFileVisitor<Path>(){
      @Override
      // Before visiting the directory, create directory 
      public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {		    		
        System.out.println("Deleting Directory- " + dir.toString());
        Files.delete(dir);
        return FileVisitResult.CONTINUE;
      }
      @Override
      // For each visited file delete it
      public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException{
        System.out.println("Deleting file- " + file.getFileName());
        Files.delete(file);                
        return FileVisitResult.CONTINUE;
      }
    });  
  }
}
Output
Deleting file- hello.txt
Deleting file- Project.docx
Deleting Directory- F:\knpcode\Parent\Child
Deleting Directory- F:\knpcode\Parent\Empty
Deleting file- Test.txt
Deleting Directory- F:\knpcode\Parent

That's all for the topic Delete a File or Directory Using a Java Program. If something is missing or you have something to share about the topic please write a comment.


You may also like

Renaming a File Using Java Program

This post shows how to rename a file using a Java program. The options you have in Java for renaming a file are as given below-

  1. renameTo(File dest)- You can use renameTo() method of the java.io.File class. See example.
  2. Files.move()- Java 7 onward you can also use Files.move() method to rename a file. See example.

Renaming a file using renameTo() method Java program

renameTo() method renames the file denoted by this abstract pathname.

Note that many aspects of the behavior of this method are inherently platform-dependent: The rename operation might not be able to move a file from one filesystem to another, it might not be atomic, and it might not succeed if a file with the destination abstract pathname already exists.

Method returns true if and only if the renaming succeeded; false otherwise. The return value should always be checked to make sure that the rename operation was successful.

In the Java example we’ll cover the scenario where you want to hide a file in Unix system by appending a "." in front of the file name. For doing that you can rename a file to have a new name as "."+fileName.

import java.io.File;

public class RenameFile {
  public static void main(String[] args) {		
    File file = new File("/home/knpcode/Documents/output");
    System.out.println("New Name- " + file.getParent()+"/."+file.getName());
    // renaming file 
    if(file.renameTo(new File(file.getParent()+"/."+file.getName()))) {
      System.out.println("File renamed successfully");
    }else {
      System.out.println("File renaming failed");
    }		
  }
}
Output
New Name- /home/knpcode/Documents/.output
File renamed successfully

Renaming a file using Files.move() method Java program

Files.move() method is used to both move or rename a file to a target file.

Here is a Java example to rename a file, keeping the file in the same directory.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class RenameFile {
  public static void main(String[] args) {	
    // source files		
    Path filePath = Paths.get("/home/knpcode/Documents/output");
    try {
      //renaming file
      Files.move(filePath, filePath.resolveSibling("output_bck"));
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

Java example where the file is renamed and also moved from /home/knpcode/Documents/ to /home/knpcode/Documents/Test directory.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

public class RenameFile {
  public static void main(String[] args) {			
    Path filePath = Paths.get("/home/knpcode/Documents/output");
    Path targetPath = Paths.get("/home/knpcode/Documents/Test/output_bck");
    try {
      Files.move(filePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

That's all for the topic Renaming a File Using Java Program. If something is missing or you have something to share about the topic please write a comment.


You may also like

July 8, 2021

Get Range of Items Using Java Stream API

In this post we’ll see how to get range of items from any collection using Java Stream API.

For example I have a list of Products and I want another list of products as per following criteria-

1- List of products that fall with in a passed price range.

Product class
public class Product {
  private String productName;
  private double price;
  Product(String productName, double price){
    this.productName = productName;
    this.price = price;
  }
  public String getProductName() {
    return productName;
  }
  public void setProductName(String productName) {
    this.productName = productName;
  }
  public double getPrice() {
    return price;
  }
  public void setPrice(double price) {
    this.price = price;
  }
  @Override
  public String toString() {
    return getProductName() + " " + getPrice();
  }
}

Here the problem statement is to write a method that is passed minimum price and maximum price as arguments and it should return a list of products that fall with in that price range and this logic should be written using Java Stream API.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamRange {

  public static void main(String[] args) {
    StreamRange obj = new StreamRange();
    // Get a list of products
    List<Product> productList = obj.createList();
    obj.productsInPriceRange(productList, 3000, 50000);
  }
    
  // create list of Products
  private List<Product> createList(){
    List<Product> productList = Arrays.asList(new Product("Screw Driver", 250), 
                                    new Product("Trousers", 3000), 
                                    new Product("RAM", 2200.56), 
                                    new Product("Smart Watch", 8000),
                                    new Product("Laptop", 48000));
      
    return productList;
  }

  void productsInPriceRange(List<Product> productList, double fromPrice, double toPrice) {
    // sorting is done here so that result comes in price order, not actually needed for the logic
    List<Product> newList = productList.stream()
                                       .sorted((Product a, Product b) ->   Double.valueOf(a.getPrice())
                                            .compareTo(Double.valueOf(b.getPrice())))
                                       .filter(p -> (p.getPrice() >= fromPrice && p.getPrice() <= toPrice))
                                       .collect(Collectors.toList());
    System.out.println(newList);
  }   
}
Output
[Trousers 3000.0, Smart Watch 8000.0, Laptop 48000.0]

2. From the list of Products you want the top 3 priced products using Java Stream API.

void topNPricedProducts(List<Product> productList, int range) {
  // sorting is done in descending order here
  List<Product> newList = productList.stream()
                                     .sorted((Product a, Product b) -> Double.valueOf(b.getPrice())
                                           .compareTo(Double.valueOf(a.getPrice())))
                                     .limit(range)
                                     .collect(Collectors.toList());
  System.out.println(newList);
}

3. From the list of Products you want the bottom 3 priced products.

void bottomNPricedProducts(List<Product> productList, int range) {
    // ascending order sorting
    List<Product> newList = productList.stream()
                                       .sorted((Product a, Product b) -> Double.valueOf(a.getPrice())
                                                .compareTo(Double.valueOf(b.getPrice())))
                                       .limit(range)
                                       .collect(Collectors.toList());
    System.out.println(newList);
}

4. From the list you want a sub-list of products as per given from and to arguments.

void productSubList(List<Product> productList, int from, int to) {
  List<Product> newList = productList.stream()
                                     .skip(from)
                                     .limit(to)
                                     .collect(Collectors.toList());
  System.out.println(newList);
}

That's all for the topic Get Range of Items Using Java Stream API. If something is missing or you have something to share about the topic please write a comment.


You may also like

July 4, 2021

Producer-Consumer Problem Java Program

In this post we’ll see Java program for producer-consumer problem using threads.

Producer consumer problem

Producer consumer is a classic concurrency problem where synchronization and inter thread communication is required for proper execution.

In producer-consumer problem there are two processes Producer and Consumer sharing a common bounded buffer known as queue.

  • Producer process generates data and inserts it into the shared queue.
  • Consumer process consumes data from the shared queue.

The requirement here is that Producer should not try to add data to the shared buffer if it is already full, it should rather wait for the queue to have space for new elements. Same way, Consumer should not try to consume data from an empty buffer, it should wait for data to be inserted in the queue.

Producer-consumer Java program

Since inter-thread communication is required for the proper implementation of Producer-Consumer so this program can be written using wait-notify methods.

You can also make use of the Java concurrency package where many queue implementations are added. Using ArrayBlockingQueue you can easily implement the Producer-Consumer program in Java.

Java program for Producer-consumer using wait-notify

In the Java program a shared buffer is required that is used by both producer and consumer processes for that a LinkedList instance can be used.

There also two Runnable tasks for producer and consumer which are executed by two separate threads. Once a value is added to the queue producer should notify consumer task to wake up and should go to wait state itself.

Same way consumer task should be in wait state if queue is empty.

import java.util.LinkedList;
// Producer task
class Producer implements Runnable{
  LinkedList<Integer> list;
  Producer(LinkedList<Integer> list){
    this.list = list;
  }
  @Override
  public void run() {
    for(int i = 1; i <= 5; i++){
      synchronized(list) {
        // If there is already an element in the list wait
        while(list.size() >= 1){
          System.out.println("Waiting as queue is full..");
          try {
            list.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        System.out.println("Adding to queue- " + Thread.currentThread().getName() + " " + i);
        list.add(i);
        list.notify();    
      }
    }		
  }
}
//Consumer task
class Consumer implements Runnable{
  LinkedList<Integer> list;
  Consumer(LinkedList<Integer> list){
    this.list = list;
  }
  @Override
  public void run() {
    for(int i = 1; i <= 5; i++){
      synchronized(list) {
        // if there is no element in the list wait
        while(list.size() < 1){
          System.out.println("Waiting as queue is empty..");
          try {
            list.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        // if there is element in the list then retrieve it
        System.out.println("Consuming from queue- " + Thread.currentThread().getName() + " " + list.remove());
        list.notify();  
      }
    }		
  }
}

public class ProducerConsumer {
  public static void main(String[] args) {
    // shared list
    LinkedList<Integer> list = new LinkedList<Integer>();
    Thread t1 = new Thread(new Producer(list), "Producer");
    Thread t2 = new Thread(new Consumer(list), "Consumer");
    t1.start();
    t2.start(); 
  }
}
Output
Adding to queue- Producer 1
Waiting as queue is full..
Consuming from queue- Consumer 1
Waiting as queue is empty..
Adding to queue- Producer 2
Waiting as queue is full..
Consuming from queue- Consumer 2
Waiting as queue is empty..
Adding to queue- Producer 3
Waiting as queue is full..
Consuming from queue- Consumer 3
Waiting as queue is empty..
Adding to queue- Producer 4
Waiting as queue is full..
Consuming from queue- Consumer 4
Waiting as queue is empty..
Adding to queue- Producer 5
Consuming from queue- Consumer 5

Java program for Producer-consumer using BlockingQueue

Using a BlockingQueue implementation like ArrayBlockingQueue you can easily implement the Producer-Consumer program in Java.

BlockingQueue has put() method for adding to the queue which blocks if the queue capacity is full. Same way there is a take() method for retrieving from the head of the queue which blocks if there is no element available.

In the code ArrayBlockingQueue of capacity 1 is created so queue will have only one element and the insertion will be blocked until that element is retrieved.

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
// Producer task
class Producer implements Runnable{
  BlockingQueue<Integer> queue;
  Producer(BlockingQueue<Integer> queue){
    this.queue = queue;
  }
  @Override
  public void run() {
    for(int i = 1; i <= 5; i++){           
      try {
        queue.put(i);
        System.out.println("Adding to queue- " + i);
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }   
    }
  }		
}
//Consumer task
class Consumer implements Runnable{
  BlockingQueue<Integer> queue;
  Consumer(BlockingQueue<Integer> queue){
    this.queue = queue;
  }
  @Override
  public void run() {
    for(int i = 1; i <= 5; i++){
      try {
        // if there is element in the list then retrieve it
        System.out.println("Consuming from queue- "  + queue.take());
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }            
  }
}

public class ProducerConsumer {
  public static void main(String[] args) {
    BlockingQueue<Integer> bQueue = new ArrayBlockingQueue<Integer>(1);
    Thread t1 = new Thread(new Producer(bQueue), "Producer");
    Thread t2 = new Thread(new Consumer(bQueue), "Consumer");
    t1.start();
    t2.start(); 
  }
}
Output
Adding to queue- 1
Consuming from queue- 1
Adding to queue- 2
Consuming from queue- 2
Adding to queue- 3
Consuming from queue- 3
Adding to queue- 4
Consuming from queue- 4
Adding to queue- 5
Consuming from queue- 5

As you can see using ArrayBlockingQueue you don’t need to write logic for synchronizing threads and call wait and notify explicitly making it very simple to write producer-consumer Java program. It can be made more compact using Lambda expression.

public class ArrayBQ {
  public static void main(String[] args) {
    // BlockingQueue of capacity 1
    BlockingQueue<Integer> bQueue = new ArrayBlockingQueue<Integer>(1);
    // Producer 
    new Thread(()->{
      for(int i = 0; i < 5; i++){
        try {
          bQueue.put(i);
          System.out.println("Added to queue-" + i);  
          
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }).start();
        
    // Consumer
    new Thread(()->{
      for(int i = 0; i < 5; i++){
        try {
          System.out.println("Consumer retrieved- " + bQueue.take());
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }).start();
  }
}

That's all for the topic Producer-Consumer Problem Java Program. If something is missing or you have something to share about the topic please write a comment.


You may also like

How to Create a Deadlock in Java

If you are asked what is deadlock in Java it is almost always accompanied by the question how to create a deadlock in Java.

Deadlock in multi-threading is a scenario where two or more threads are waiting for each other to release the resources to make any further progress and blocked forever in the process.

Java program for creating deadlock

You may get deadlock in Java when you have nested synchronized blocks with reverse ordering of objects.

In the example two threads are created to run two separate runnable tasks. In each runnable task there are nested synchronized blocks acquiring object locks in reversed order thus creating a deadlock.

class ThreadA implements Runnable{
  private Object obj1;
  private Object obj2;
  ThreadA(Object obj1, Object obj2){
    this.obj1 = obj1;
    this.obj2 = obj2;
  }
  @Override
  public void run() {
    synchronized(obj1){
      System.out.println(Thread.currentThread().getName() + " acquired " + "obj1 lock");
      System.out.println(Thread.currentThread().getName() + " waiting for " + "obj2 lock");
      synchronized(obj2){
        System.out.println(Thread.currentThread().getName() + " acquired " + "obj2 lock");
      }
    }       
  }  
}
 
class ThreadB implements Runnable{
  private Object obj1;
  private Object obj2;
  ThreadB(Object obj1, Object obj2){
    this.obj1 = obj1;
    this.obj2 = obj2;
  }
  @Override
  public void run() {
    synchronized(obj2){
      System.out.println(Thread.currentThread().getName() + " acquired " + "obj2 lock");
      System.out.println(Thread.currentThread().getName() + " waiting for " + "obj1 lock");
      synchronized(obj1){
        System.out.println(Thread.currentThread().getName() + " acquired " + "obj1 lock");
      }
    }   
  }
}

public class DLDemo {
  public static void main(String[] args) {
    Object obj1 = new Object();
    Object obj2 = new Object();
    Thread t1 = new Thread(new ThreadA(obj1, obj2));
    Thread t2 = new Thread(new ThreadB(obj1, obj2));
    t1.start();
    t2.start();
  }
}
Output
Thread-0 acquired obj1 lock
Thread-0 waiting for obj2 lock
Thread-1 acquired obj2 lock
Thread-1 waiting for obj1 lock

You can see in run() method of ThreadA synchronized block acquires lock on obj1 and then tries to acquire lock on obj2. Same way in run() method of ThreadB synchronized block acquires lock on obj2 and then tries to acquire lock on obj1. This hangs the program by creating a deadlock as t1 thread is waiting to acquire lock on obj2 which is currently acquired by t2 thread and t2 thread is waiting to acquire lock on obj1 which is currently acquired by the t1 thread.

Creating deadlock by calling one synchronized method from another

Here is another example of creating deadlock in Java. It is similar to the first example here rather than having nested synchronized blocks there are two synchronized methods. The objects which are used to call the method and the object which are passed as an argument to these methods are reversed thus creating deadlock.

public class DLDemo {
  public synchronized void method1(DLDemo obj){
    System.out.println(Thread.currentThread().getName() + " In Method1");
    try {
      Thread.sleep(100);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    //Calling another synchronized method
    obj.method2(this);
  }
			  
  public synchronized void method2(DLDemo obj2){
    System.out.println("In Method2");
  }
 
  public static void main(String[] args) {
    DLDemo obj1 = new DLDemo();
    DLDemo obj2 = new DLDemo();
   
    new Thread(new Runnable() {
      public void run() { obj1.method1(obj2); }
    }).start();

    //Thread 2  
    new Thread(new Runnable() {
      public void run() { obj2.method1(obj1); }
    }).start();
  }
}
Output
Thread-0 In Method1
Thread-1 In Method1

From one thread synchronized method method1 is called using obj1 so this thread acquires a lock on obj1 then another synchronized method method2 is called using obj2.

From another thread synchronized method method1 is called using obj2 so this thread acquires a lock on obj2 then another synchronized method method2 is called using obj1.

That's all for the topic How to Create a Deadlock in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like