Sunday, June 14, 2020

Appium how to do scrolling.

In this post, I will show you how to do scrolling in Appium. Appium provides the TouchAction API for gesture implementation.

1. Create an Appium driver:

First, let's create an Appium driver. The general configuration looks like as below:

import io.appium.java_client.android.AndroidDriver;
import org.junit.After;
import org.junit.Before;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.net.MalformedURLException;
import java.net.URL;

public class AppiumTest {

    private static AndroidDriver driver;
    private static WebDriverWait wait;

    @Before
    public static void setUp() throws MalformedURLException {
        DesiredCapabilities cap = new DesiredCapabilities();
        cap.setCapability("platformName", "Android");
        cap.setCapability("deviceName", "your device name");
        cap.setCapability("appPackage", "appPackage");
        cap.setCapability("appActivity", "appActivity");
        cap.setCapability("automationName", "UiAutomator1");
        cap.setCapability("autoGrantPermissions", true);
        cap.setCapability("autoAcceptAlerts", "true");
        driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), cap);
        wait = new WebDriverWait(driver,60);
    }
    
    @After
    public static void tearDown(){
        driver.quit();
    }

}
This is a sample config to create an Appium driver which we will use later.





2. Scrolling:

//AppiumTest.java
private static void scroll(int scrollStart, int scrollEnd) {
        new TouchAction(driver)
                .press(point(0, scrollStart))
                .waitAction(WaitOptions.waitOptions(Duration.ofSeconds(10)))
                .moveTo(point(0, scrollEnd))
                .release().perform();
    }
Here, we are dealing with scrolling, so we are adjusting the value for the y-axis. The press() method allows you to press on the position x, y coordinates. You can use some offset value for x coordinate instead of 0 x-offset value. The waitAction() method will wait until the duration provided. The moveTo() method allows moving current touch action to a new position specified. The release() method removes the touch. Next, we will adjust the scrollStart and scrollEnd arguments to move down and up.

3. Scrolling Down:


//AppiumTest.java
public static void scrollDown() {
        MobileElement element = (MobileElement) driver.findElement(By.id("resourceId"));
        if (element == null){
            return;
        }
        int numberOfTimes = 10;
        Dimension dimension = driver.manage().window().getSize();
        int windowsHeight = dimension.getHeight();
        int scrollStart = (int) (windowsHeight * 0.5);
        int scrollEnd = (int) (windowsHeight * 0.3);
        int elementLocationOffset = windowsHeight-500;
        for (int i = 0; i < numberOfTimes; i++) {
            int elementLocationY = element.getLocation().y;
            if (elementLocationY < elementLocationOffset){
                i = numberOfTimes;
                System.out.println("Element available.");
            }else {
                scroll(scrollStart, scrollEnd);
                System.out.println("Element not available. Scrolling...");
            }
        }
    }

In the above scrolling down example, we are trying to scroll down until the element is visible on the screen. Here, we are getting the dimension of the screen window; as we are scrolling so, we use windows height to manipulate the position to scroll.




For e.g, if windows height is 1000 scrollStart will be 500 and scrollEnd will be 300 which means while calling scroll() method it will press to the position (x,y) (0, 500) and move to (x,y)(0, 300) which results in scrolling downward. We are looping so that it will scroll down until the element will arrive to the elementLocationOffset position where the element will be visible on the screen.

For testing element availability, if the above approach doesn't work you can try finding the element as below:

for (int i = 0; i < numberOfTimes; i++) {
            List elements = driver.findElements(By.id("resourceId"));
            if (elements.size() > 0){
                i = numberOfTimes;
                System.out.println("Element available.");
            }else {
                scroll(scrollStart, scrollEnd);
                System.out.println("Element not available. Scrolling...");
            }
        }

4. Scrolling Up:

If you want to scroll Up then you need to adjust the coordinates as below:

 int scrollStart = (int) (windowsHeight * 0.3);
 int scrollEnd = (int) (windowsHeight * 0.7);
 
For e.g: if the window's height is 1000 then scrollStart will be 300 and scrollEnd will be 700 which means while calling scroll() method it will press to the position (x,y) (0, 300) and move to (x,y)(0, 700) which results in scrolling upward. Adjust the value that suits you.

The overall Implementation looks like below:

package appium;

import io.appium.java_client.MobileElement;
import io.appium.java_client.TouchAction;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.touch.WaitOptions;
import org.junit.After;
import org.junit.Before;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;

import static io.appium.java_client.touch.offset.PointOption.point;


public class AppiumTest {

    private static AndroidDriver driver;
    

    @Before
    public static void setUp() throws MalformedURLException {
        DesiredCapabilities cap = new DesiredCapabilities();
        cap.setCapability("platformName", "Android");
        cap.setCapability("deviceName", "your device");
        cap.setCapability("appPackage", "appPackage");
        cap.setCapability("appActivity", "appActivity");
        cap.setCapability("automationName", "UiAutomator1");
        cap.setCapability("autoGrantPermissions", true);
        cap.setCapability("autoAcceptAlerts", "true");
        driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), cap);
    }


    public static void scrollDown() {
        MobileElement element = (MobileElement) driver.findElement(By.id("resourceId"));
        if (element == null){
            return;
        }
        int numberOfTimes = 10;
        Dimension dimension = driver.manage().window().getSize();
        int windowsHeight = dimension.getHeight();
        int scrollStart = (int) (windowsHeight * 0.5);
        int scrollEnd = (int) (windowsHeight * 0.3);
        int elementLocationOffset = windowsHeight-500;
        for (int i = 0; i < numberOfTimes; i++) {
            int elementLocationY = element.getLocation().y;
            if (elementLocationY < elementLocationOffset){
                i = numberOfTimes;
                System.out.println("Element available.");
            }else {
                scroll(scrollStart, scrollEnd);
                System.out.println("Element not available. Scrolling...");
            }
        }
    }

    private static void scroll(int scrollStart, int scrollEnd) {
        new TouchAction(driver)
                .press(point(0, scrollStart))
                .waitAction(WaitOptions.waitOptions(Duration.ofSeconds(1)))
                .moveTo(point(0, scrollEnd))
                .release().perform();
    }

    @After
    public static void tearDown(){
        driver.quit();
    }

}




Share:

Saturday, June 13, 2020

How to convert the JSON file to Map and List in Java using Gson.

In this post, we are going to convert the JSON file to Map or List. Here, we are using the Gson library which provides a clean way to do so. You can download the Gson jar file from here.


Now, load the jar file from your IDE.

For IntelliJ Idea:

Go to: File >> Project Structure(Ctr + Alt + Shift + s) >> Libraries and click the + icon on the top left corner and select library file that we downloaded. Apply and save. If you are using in an existing project like Gradle or Maven: 

For Gradle:

Inside build.gradle file under dependencies,
compile 'com.google.code.gson:gson:2.8.6'



For Maven:

Inside pom.xml
<dependency>
  <groupid>com.google.code.gson</groupid>
  <artifactid>gson</artifactid>
  <version>2.8.6</version>
</dependency>

Create a Class that converts a JSON file to Map or List.
package jsonToMap;

import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Map;


public class JsonConverter {

    public static void main(String[] args) {
        String baseDir = System.getProperty("user.dir");
        String jsonPath = baseDir+"/src/jsonToMap/resources/sample.json";
        //convert json map to Map
        Map jsonMap = getMapFromJson(jsonPath);
        System.out.println(jsonMap);
       
    }

    private static Map getMapFromJson(String filePath){
        Gson gson = new Gson();
        JsonReader reader = null;
        try {
            reader = new JsonReader(new FileReader(filePath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return gson.fromJson(reader, Map.class);
    }

}

Also, the sample.json file contains the JSON map under the directory provided.

//sample.json
{
  "text":"first text",
  "digit":1234,
  "boolean":true
}

In the above example, first, it will read the JSON file using JsonReader and we used Gson to convert to Map.

If you want to convert the file which contains the JSON list to List, you can provide the class to convert as below.
//sample.json
[
  {
    "text":"first text",
    "digit":1234,
    "boolean":true
  },
  {
    "text":"second text",
    "digit":1234,
    "boolean":true
  },
  {
    "text":"third text",
    "digit":1234,
    "boolean":true
  }
]


/JsonConverter.java
private static List getListFromJson(String filePath){
        Gson gson = new Gson();
        JsonReader reader = null;
        try {
            reader = new JsonReader(new FileReader(filePath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return gson.fromJson(reader, List.class);
    }
If you want to convert to Custom class, create a class compatible with the fields from the JSON file and provide that class while converting. For e.g:
//sample.json
{
  "text":"first text",
  "digit":1234,
  "aBoolean":true
}


//Sample.java
public class Sample {

    private String text;
    private Double digit;
    private Boolean aBoolean;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Double getDigit() {
        return digit;
    }

    public void setDigit(Double digit) {
        this.digit = digit;
    }

    public Boolean getaBoolean() {
        return aBoolean;
    }

    public void setaBoolean(Boolean aBoolean) {
        this.aBoolean = aBoolean;
    }
}


//JsonConverter.java
private static Sample getSampleFromJson(String filePath){
        Gson gson = new Gson();
        JsonReader reader = null;
        try {
            reader = new JsonReader(new FileReader(filePath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return gson.fromJson(reader, Sample.class);
    }
Here, we pass the class Sample while converting from the JSON. Make sure your JSON file and class structure match.



Share:

Sunday, June 7, 2020

Create a Self-Signed free SSL certificate for Tomcat on CentOS Linux using Let's Encrypt.

How to Install and configure a free SSL/TLS certificate for Tomcat using Let's Encrypt on Centos Linux.





In this tutorial, we are going to create and set up a free SSL/TLS certificate on the Linux CentOS server. We are using Let's Encrypt for this which provides the free SSL and is valid for 90 days. You can renew it during that time duration. We will show how to renew it too. You can find about Let's Encrypt from here.

This service is used by many people to secure their website worldwide so, it's totally trust-worthy and supported if you can't afford from other paid service provider.


2. prerequisites:

We consider you already have the following setup.

  1. Running CentOS server
  2. Running tomcat server
  3. Domain pointed to the server Ip address


3. Install Certbort and create an SSL certificate:

First, SSH into to the running CentOS server where you want to create your SSL certificate. To create an SSL certificate, we need to first install Certbort on the server so, let's do it. I recommend selecting the desired version from here, which will give the command to install Certbot.


Install Certbot:
yum -y install yum-utils
     yum-config-manager --enable rhui-REGION-rhel-server-extras rhui-REGION-rhel-server-optional 
     sudo yum install certbot

Create a certificate:

If you have already running service which uses port 80 stop it. To obtain an SSL certificate for your domain using a built-in "standalone" webserver type the following command:
sudo certbot certonly --standalone -d example.com
Here, replace the domain name you want to secure instead of example.com 

which will create the following certificate file to the directory:"/etc/letsencrypt/live/example.com/"
cert.pem, chain.pem, fullchain.pem, privkey.pem.

Now, logged in as root user and go to that directory

sudo -i
cd /etc/letsencrypt/live/example.com/

Next step is to convert those certificate PEM file to password-based PFX format so that we can use in tomcat configuration. We can do this by using the OpenSSL command as below.
openssl pkcs12 -export -out bundle.pfx -inkey privkey.pem -in cert.pem -certfile chain.pem -password pass:password
Replace the password with your desired one. It will create a password-protected file bundle.pfx under the same directory "/etc/letsencrypt/live/example.com/" which we need to use in tomcat configuration.

 



4. Tomcat configuration for HTTPs:

Go to your tomcat directory, and backup the server.xml file; as we are going to change the file.
cp conf/server.xml conf/server-copy.xml
Edit the server.xml file.
sudo vi conf/server.xml  // no need to type sudo if you are logged in as root user
You can see the following commented XML tag, which we are going to change:

For Tomcat 7:


For tomcat 8:



Add the following changes near to the above XML tag or you can simply change that XML tag as below.



Here, we are changing port 8443 to 443, keystoreType as "PKCS12", keystoreFile as the path of the pfx file created previously and keystorePass as your password that we used while creating PFX file. 

Change the port 8080 to 80:

Under server.xml you can find the following tag.



change the above XML tag as below:



Here, we are changing the port from 8080 to 80 and 8443 to 443. By doing so, if your domain running with port 8080 i.e example.com:8080, now it will open with port 80 i.e example.com. If you type your domain in the browser then you can run it with both HTTP and https i.e http://example.com and https://example.com.

Save the server.xml file by clicking "Esc" key and type ":wq!" and hit Enter.

As we want to always redirect our domain to https. To do so, open the web.xml file under conf/web.xml.

 
sudo vi conf/web.xml
Click "Shift + G" to go the end of the file and add the below code at the end of the file as below.
<security-constraint>
  <web-resource-collection>
  <web-resource-name>Entire Application</web-resource-name>
   <url-pattern>/*</url-pattern>
 </web-resource-collection>
  <!--auth-constraint goes here if you requre authentication-->
 <user-data-constraint>
 <transport-guarantee>CONFIDENTIAL</transport-guarantee>
 </user-data-constraint>
 </security-constraint>
 


Save the file. This will always redirect to HTTPs.

 
5. Renew certificate:

The certificate is valid for only 90 days so we need to renew before expiry. For this, stop tomcat and type the following command:
sudo certbot renew
sudo -i
cd /etc/letsencrypt/live/example.com/
openssl pkcs12 -export -out bundle.pfx -inkey privkey.pem -in cert.pem -certfile chain.pem -password pass:password
Don't forget to use your existing password. And restart the tomcat server.



Share:

Friday, June 5, 2020

IntelliJ Idea doesn't detect existing Java project.

What to do if your IntelliJ Idea doesn't detect your existing project. Sometimes it may be due to it doesn't find the JDK on you configure path. If you have such a problem reconfigure the JDK.
 
For this, go to: File >> Project Structures(Ctr + Alt + Shift + s) >> Project




Click New >> JDK and provide the path and select JDK. Sometimes it may be due to other versions of JDK setup, in that case, click and select the desired version of java from dropdown menu. Then click apply and ok. That may solve the issue with java not detecting.

Sometimes, although Java is detected we are not able to use the feature of Intellij idea like, run and debug classes, step in step out from class by ctr + click on method or class, find the usage of class and method by click on it. In this case, simply close the project and import it again. For this,

Go to: File >> Close Project >> Import Project




Select your desired project, and select "create from existing source", select the desired library and java version and finish the setup. This will resolve the issues 


Share:

Thursday, June 4, 2020

How to create thumbnail Image using Java.

In this tutorial, I will show you how we can create thumbnail images using Java. Thumbnails are the reduced size of images or videos. Basically, if your website is loading a lot of images with larger pixel values i.e larger size then, the performance of the website will be poor. 

So, while loading web pages with images first showing thumbnails of images and when the user clicks on it then load the original images will increase the user experience and performance of the website.

Here, in order to do so, we are using the library called " thumbnailator" which will help to generate high-quality thumbnails.





Add Dependency:

Download the jar file from here. Load the downloaded jar file on your project.

For IntelliJ Idea:

Go to: File >> Project Structure(Ctr + Alt + Shift + s) >> Libraries  and click the + icon on the top left corner and select library file that we downloaded. Apply and save, now we are ready to write code. If you are using in an existing project like Gradle or Maven:

For Gradle:

Inside build.gradle file under dependencies, 
compile 'net.coobird:thumbnailator:0.4.8'

For Maven:

Inside pom.xml
<dependency>
  <groupid>net.coobird</groupid>
  <artifactid>thumbnailator</artifactid>
  <version>0.4.8</version>
</dependency>

Create thumbnail from image file:

Let's create a class called Thumbnail.java:
import net.coobird.thumbnailator.Thumbnails;
import java.io.File;
import java.io.IOException;

    public class Thumbnail {

    public static void main(String[] args) {
        String inputImagePath = "E:/image.jpg"; //input image path
        File inputFile = new File(inputImagePath);
        String fileName = inputFile.getName();
        String outputPath = "E:" + "/T_"+fileName; //output path to write thumbnail image
        Thumbnail.createFromImageFile(inputFile, outputPath);
    }

    private static void createFromImageFile(File inputFile, String outputPath){
        try {
            Thumbnails.of(inputFile)
                    .size(500, 500)
                    .toFile(outputPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Here, the image is resized to the square of size 500*500 i.e width*height.


Create thumbnail from Buffered image:

private static void createFromBufferedImage(BufferedImage image, String outputPath){
        try {
            Thumbnails.of(image)
                    .size(500, 500)
                    .toFile(outputPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Create thumbnail Image by scaling:

private static void createByScaling(File inputFile, String outputPath){
        try {
            Thumbnails.of(inputFile)
                    .scale(0.25)
                    .toFile(outputPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
Here, it creates a thumbnail that is 25% of the original image.



Share:

Wednesday, June 3, 2020

Convert Tiff file to JPG/PNG using Java.

How to convert a tiff(tif) file to JPG/PNG using Java.

While dealing with the tiff file, we may have the problem that some browser doesn't support it. Please visit for image format support for different browser here. In this tutorial, we are going to convert the tiff file to a jpg or png file format in an efficient way.



Dependencies required.

In order to convert tiff to other image formats, we are using Jai image i/o  library. Download the jar file from here. As we are using lib version "jai-imageio-core-1.4.0" here, you can find jar file under Assets. Load the jar file in your IDE or if you have existing projects like Maven or Gradle add the dependency as below.

For Gradle:

Add in build.gradle under "dependencies"
compile 'com.github.jai-imageio:jai-imageio-core:1.4.0'

For Maven:

Add in pom.xml
 <dependencies>
    <dependency>
        <groupid>com.github.jai-imageio</groupid>
        <artifactid>jai-imageio-core</artifactid>
        <version>1.4.0</version>
    </dependency>
</dependencies>

Convert Tiff to PNG/JPG

Let's create a class called "TiffConverter.java"

TiffConverter.java:
public static void main(String[] args) {
        File tiffFile = new File("/home/360learntocode/im.tif"); //input path to tif file
        String outputPath = "/home/360learntocode/"; //output path to write file
        String convertFormat = "jpg"; //jpg, png, bmp
        try {
            TiffConverter.convertTiff(tiffFile, outputPath, convertFormat);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Provide the appropriate input and output path. You can provide the desired conversion format. As the conversion will reduce the pixel value of the image for jpg, png although BMP conversion doesn't reduce the pixel value.
private static File convertTiff(File tiffFile, String outputPath, String convertFormat) throws IOException {
        String fileName = tiffFile.getName();
        String ext = getFileExtension(fileName);
        fileName = fileName.replace(ext, "."+convertFormat);
        BufferedImage tiff = ImageIO.read(tiffFile);
        File output = new File(outputPath + fileName);
        ImageIO.write(tiff, convertFormat, output);
        return output;
    }





We are using the library to manipulate and convert the tif file. BufferedImage is used to handle and manipulate the image data. For more visit here.

  //get file extension from file name
    private static String getFileExtension(String fileName) {
        int lastIndexOf = fileName.lastIndexOf(".");
        return fileName.substring(lastIndexOf).toLowerCase();
    }
 

Finally, we successfully converted the Tiff/Tif File to the desired format like jpg, png, BMP.

The overall implementation looks like as below:
 import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;


public class TiffConverter {

    public static void main(String[] args) {
        File tiffFile = new File("/home/360learntocode/im.tif"); //input path to tif file
        String outputPath = "/home/360learntocode/"; //output path to write file
        String convertFormat = "jpg"; //jpg, png, bmp
        try {
            TiffConverter.convertTiff(tiffFile, outputPath, convertFormat);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static File convertTiff(File tiffFile, String outputPath, String convertFormat) throws IOException {
        String fileName = tiffFile.getName();
        String ext = getFileExtension(fileName);
        fileName = fileName.replace(ext, "."+convertFormat);
        BufferedImage tiff = ImageIO.read(tiffFile);
        File output = new File(outputPath + fileName);
        ImageIO.write(tiff, convertFormat, output);
        return output;
    }

    //get file extension from file name
    private static String getFileExtension(String fileName) {
        int lastIndexOf = fileName.lastIndexOf(".");
        return fileName.substring(lastIndexOf).toLowerCase();
    }
}
Share:

Tuesday, June 2, 2020

Hot reloading the resources file for changes in Grails.


How to hot reload the resources file when the changes happened in Grails.


I was working on Grails 3.3.0 and hot reloading was not working while changing in the resources files. So, I found some workaround which is worth sharing here. There are the following steps to resolve the issue.

  1. Configure to watch the directory.
  2. Watch the directory for code changes
  3. Reload spring resources config
  4. Load from the application

Configure to watch the directory:




Here I am creating a class BeanWatcher.groovy to watch the config file changes.


import grails.spring.BeanBuilder
import grails.util.Environment
import grails.util.Holders
import groovy.util.logging.Slf4j
import org.grails.core.exceptions.GrailsConfigurationException
import org.grails.spring.DefaultRuntimeSpringConfiguration
import org.grails.spring.RuntimeSpringConfigUtilities
import org.springframework.beans.factory.support.BeanDefinitionRegistry

import java.nio.file.FileSystems
import java.nio.file.FileVisitResult
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.SimpleFileVisitor
import java.nio.file.StandardWatchEventKinds
import java.nio.file.WatchEvent
import java.nio.file.WatchKey
import java.nio.file.WatchService
import java.nio.file.attribute.BasicFileAttributes
import java.util.concurrent.atomic.AtomicBoolean
    
    class BeanWatcher extends Thread{
    
    
    private final WatchService watchService
    private long sleepTime = 1000
    private AtomicBoolean stop = new AtomicBoolean(false)
    
    public BeanWatcher(Path path){
        watchService = FileSystems.getDefault().newWatchService()
        walkAndRegisterDirectories(path)

    }
    

    private void walkAndRegisterDirectories(final Path start){
        // register directory and sub-directories
        Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs){
                registerDirectory(dir)
                return FileVisitResult.CONTINUE
            }
        })
    }
    

    private void registerDirectory(dir){

        dir.register(
                watchService,
                StandardWatchEventKinds.ENTRY_MODIFY)
    }
    
    
     @Override
    void run() {

       
    }
    
     static void configureBeanWatcher(){
        Environment environment = Environment.current
        File baseDir = new File(environment.getReloadLocation()).canonicalFile
        String location = baseDir.canonicalPath
        File watchDir = new File(location, "grails-app/conf/spring")
        Path path = watchDir.toPath()
        BeanWatcher beanWatcher = new BeanWatcher(path)
        beanWatcher.start()
    }
    
    
    }

I want to watch the config spring file so I provided the path: "grails-app/conf/spring" under the project directory. As we are running in the thread so the current thread will not be interrupted for each time file changes. Here, we are registering directories and sub-directories.


Watch the directory for code changes:

    @Override
    void run() {

        try {
            WatchKey key
            try {
                while ((key = watchService.take()) != null) {
                    List<WatchEvent <?>> watchEvents = key.pollEvents()
                    for (WatchEvent <?> event : watchEvents) {
                        WatchEvent.Kind <?> kind = event.kind()
                        WatchEvent <Path> pathWatchEvent = cast(event)
                        Path name = pathWatchEvent.context()
                        Path dir = (Path) key.watchable()
                        Path child = dir.resolve(name).toAbsolutePath()
                        File childFile = child.toFile()
                        if(kind == StandardWatchEventKinds.ENTRY_MODIFY){
                            onChange(childFile)
                        }
                    }
                    key.reset()
                }
            } catch (InterruptedException e) {
                e.printStackTrace()
            }
        } catch (IOException e) {
            e.printStackTrace()
        }

    }
        

    @SuppressWarnings("unchecked")
    private static <T> WatchEvent<T> cast(WatchEvent<?> event) {
        return (WatchEvent<T>)event
    }
        
The above code will listen to the file changes and call the method onChange for each time the file changes. Now, it's time to reload our resources file while changes occurred.


Reload spring resources config:

   private static void onChange(File file) { // the changed file 
        processBeanDefinitionRegistry()
    }
    
    public static void processBeanDefinitionRegistry(){
        def springConfig = new DefaultRuntimeSpringConfiguration()
        def application = Holders.grailsApplication
        def context = application.mainContext
        def beanResources = context.getResource(RuntimeSpringConfigUtilities.SPRING_RESOURCES_GROOVY)
        if (beanResources?.exists()) {
            def gcl = new GroovyClassLoader(application.classLoader)
            try {
                RuntimeSpringConfigUtilities.reloadSpringResourcesConfig(springConfig, application, gcl.parseClass(new GroovyCodeSource(beanResources.URL)))
            } catch (Throwable e) {
                throw new GrailsConfigurationException("Error loading spring/resources.groovy file: ${e.message}", e)
            }
        }
        def bb = new BeanBuilder(null, springConfig, application.classLoader)
        bb.registerBeans((BeanDefinitionRegistry)application.getMainContext())
    }
    


This is the code snippet that I found in the grails where they used to reload the file. This will reload and re-configure the resources file.






Load from the application:

We set up all the necessary config and necessary code inside BeanWatcher.groovy now lets load the file from application for this add the following code.

Application.groovy

    if (Environment.current == Environment.DEVELOPMENT){
            BeanWatcher.configureBeanWatcher()
        }
    
This is only for the development env so we did the same.
Share: