PGP Encryption and Decryption using Apache Camel

In this example we will see how do to the file encryption and decryption using Apache Camel using pgp

1. Generate pgp keys

In order to do the encryption/decryption we required the pgp public and private keys, in this example we will use below portal to generate the keys. Once we created the files we need to place it in to our source resource folder
 

2. Create a maven project and add below dependencies

<properties>
        <camel.version>2.13.2</camel.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-ftp</artifactId>
            <version>2.14.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-core</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-crypto</artifactId>
            <version>${camel.version}</version>

        </dependency>
        <dependency>
            <groupId>bouncycastle</groupId>
            <artifactId>bcpg-jdk13</artifactId>
            <version>121</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

3. Create a Camel Route to start encryption
 
package com.vinod.test;

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.converter.crypto.PGPDataFormat;
import org.apache.camel.main.Main;

public class EncryptionTest {

    /**
     * @param args
     * @throws Exception
     */

    public static void main(String[] args) throws Exception {
        Main main = new Main();
        main.enableHangupSupport();
        main.addRouteBuilder(new MyRouteBuilder());
        main.run(args);

    }

}

class MyRouteBuilder extends RouteBuilder {

    @Override
    public void configure() {

        try {
            System.out.println("My Encryption/Decryption route started");
            // Encryption
            PGPDataFormat encrypt = new PGPDataFormat();
            encrypt.setKeyFileName("vinodpublickeyfile.pgp");
            encrypt.setKeyUserid("vinod");

            from("file:tobeencrypt?noop=true;delete=true").marshal(encrypt).to("file:encrypted");

            // Decryption

            PGPDataFormat decrypt = new PGPDataFormat();
            decrypt.setKeyFileName("vinodprivatekeyfile.pgp");
            decrypt.setKeyUserid("vinod");
            decrypt.setPassword("vinod@123");

            from("file:tobedecrypt").unmarshal(decrypt).to("file:decrypted");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5. Run the program

After running the above main program camel route will start and we can see the two directories are created and we can place the files which we needs to be encrypted.



Once we placed the file in to tobeencrypt directory Camel route will process that file and place in to encrypted directory after encryption




 

 

 

 

 

 

 

 

 

 

 

 

Download example

https://github.com/kkvinodkumaran/camel 

 

 

 

 

Servlet RequestDispatcher

The javax.servlet.RequestDispatcher interface class help your servlet to call another servlet, JSP file, or HTML file from inside another servlet.

There are two main method in this interfaces


1) forward(ServletRequest request, ServletResponse response)

                  —>> forwards a request from a servlet to another resource (servlet, JSP file, or HTML file) on the server

2) include(ServletRequest request, ServletResponse response)
                  —>> includes the content of a resource (servlet, JSP page, HTML file) in the response


Example

Servlet class

This servlet class will do the include or forward based on the action from the user interface
package com.vinod;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class MyServletDispatcher
 */

public class MyServletDispatcher extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */

    public MyServletDispatcher() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        RequestDispatcher rd = request.getRequestDispatcher("index.jsp");
        if (request.getParameter("action") != null) {
            String action = request.getParameter("action");
            if (action.equalsIgnoreCase("include")) {
                rd.include(request, response);
            } else if (action.equalsIgnoreCase("forward")) {
                rd.forward(request, response);
            }
        }
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}


Test jsp (Dispatcher.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <form name="input" action="http://localhost:8081/MyServletDispatcher"
        method="get">
        Enter Action: <input type="text" name="action"><input
            type="submit" value="Submit">
    </form>
</body>
</html>

index.JSP
 
<html>
<body>
<h2>Hello World!</h2>
</body>
</html>

Deploy and run the Dispatcher.jsp ( In this example using jetty server, so used jetty:run maven command to start the jetty server)
 


Download complete Example

https://github.com/kkvinodkumaran/myj2ee

Java Blocking Queues

java.util.concurrent.BlockingQueue is a Queue that supports operations that wait for the queue to become non-empty when retrieving and removing an element, and wait for space to become available in the queue when adding an element.

1. Thread safe
2. Allow duplicates
3. Not allowed null values

   

Types

  • ArrayBlockingQueue
  • DelayQueue
  • LinkedBlockingQueue
  • PriorityBlockingQueue
  • SynchronousQueue

Example

package com.vinod.test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BlockingQueueExamples {
   public static void main(String[] args) throws InterruptedException, ExecutionException {
      BlockingQueue<String> bq = new ArrayBlockingQueue<String>(1000);
      ExecutorService exec = Executors.newFixedThreadPool(2);
      exec.submit(new ConsumerThread(bq));
      exec.submit(new ProducerThread(bq));

   }

}

class ProducerThread implements Callable<Object> {
   private BlockingQueue<String> blockingQueue;

   public ProducerThread(BlockingQueue<String> blockingQueue) {
      this.blockingQueue = blockingQueue;
   }

   public Object call() throws Exception {
      System.out.println("Producer Started:");
      Thread.sleep(1000);
      blockingQueue.put("vinod");
      Thread.sleep(1000);
      blockingQueue.put("vinod1");
      Thread.sleep(1000);
      blockingQueue.put("vinod2");
      return null;
   }

}

class ConsumerThread implements Callable<Object> {
   private BlockingQueue<String> blockingQueue;

   public ConsumerThread(BlockingQueue<String> blockingQueue) {
      this.blockingQueue = blockingQueue;
   }

   public Object call() throws Exception {
      System.out.println("Consumer Started:");
      System.out.println(blockingQueue.take());
      System.out.println(blockingQueue.take());
      System.out.println(blockingQueue.take());

      return null;
   }

}

Output

Consumer Started:
Producer Started:
vinod
vinod1
vinod2

What is JVM Stack? when will get StackOverflowError ?

🧠 Understanding JVM Stack and StackOverflowError in Java

When you run a Java program, each thread in the Java Virtual Machine (JVM) gets its own stack memory.
This memory is essential for method execution, local variable storage, and tracking return addresses during program flow.

Let’s explore what the JVM Stack is, how it works, and why a StackOverflowError occurs.


⚙️ What Is the JVM Stack?

Each thread in the Java Virtual Machine has its own stack, which is created at the same time as the thread.

The JVM stack is made up of stack frames — each frame corresponds to a single method call.

Each frame contains:

  • 🧩 Local Variables: Variables defined inside methods.

  • ⚙️ Operand Stack: Used for intermediate calculations.

  • 🔁 Return Address: The point in code to return to after the method finishes.

When a method is invoked, a new frame is pushed onto the stack.
When that method finishes, its frame is popped off the stack.


⚠️ What Causes a StackOverflowError?

If a thread’s method calls go too deep — typically through uncontrolled recursion
the JVM eventually runs out of stack memory, resulting in a StackOverflowError.

This happens because:

  • Each recursive call adds a new frame to the stack.

  • There’s no base case to stop recursion.

  • The stack keeps growing until memory is exhausted.

At that point, the JVM throws:

Exception in thread "main" java.lang.StackOverflowError

💻 Example — Triggering a StackOverflowError

package com.vinod.test; /** * Simple example to demonstrate StackOverflowError in Java. * * Each recursive call to main() creates a new stack frame. * Since there is no exit condition, the stack overflows. * * @author vinod */ public class TestStackOverFlow { public static void main(String[] args) { // Recursive call with no termination main(args); } }

🧾 Output

Exception in thread "main" java.lang.StackOverflowError at com.vinod.test.TestStackOverFlow.main(TestStackOverFlow.java:6) at com.vinod.test.TestStackOverFlow.main(TestStackOverFlow.java:6) at com.vinod.test.TestStackOverFlow.main(TestStackOverFlow.java:6) at com.vinod.test.TestStackOverFlow.main(TestStackOverFlow.java:6) ...

🔍 Why It Happens — Step by Step

Let’s visualize what’s going on in this example:

Call #1main(args) ↳ Calls main(args) againCalls main(args) againCalls main(args) again ↳ ...

Each call to main() pushes a new frame onto the stack:

┌──────────────┐ │ main(args) │ ← newest frame ├──────────────┤ │ main(args) │ ├──────────────┤ │ main(args) │ ├──────────────┤ │ ... │ └──────────────┘

Since the recursion never terminates, the stack continues to grow until the JVM runs out of space.


🧩 How to Prevent StackOverflowError

Here are a few best practices:

  1. Always define a base condition in recursion.

    public static void recursiveMethod(int n) { if (n == 0) return; // base case recursiveMethod(n - 1); }
  2. Avoid deep or unbounded recursion.
    Convert recursive logic to iterative when possible.

  3. Increase JVM stack size (if necessary):

    java -Xss2m com.vinod.test.TestStackOverFlow

    (Sets thread stack size to 2MB — use cautiously!)


🧠 Key Takeaways

ConceptDescription
JVM StackMemory region per thread that stores method call frames
FrameContains local variables, operand stack, and return address
Created WhenA new thread is started
Destroyed WhenThe thread terminates
Error Typejava.lang.StackOverflowError
Common CauseInfinite recursion or excessively deep method calls

Spring @RestController

Spring @RestController

Spring 4.0 introduced @RestController, a specialized version of the controller which is a convenience annotation that does nothing more than add the @Controller and @ResponseBody annotations. By annotating the controller class with @RestController annotation, you no longer need to add @ResponseBody to all the request mapping methods.

Example

package com.vinod;

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

@RestController
public class RestControllerExample {
    @RequestMapping("/hello/{name}")
    public Customer message(@PathVariable String name) {
        return new Customer("Hello " + name, "USA");
    }

}

class Customer {
    private String name;
    private String address;

    public Customer(String name, String address) {
        super();
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

}

 

Download Complete example

https://github.com/kkvinodkumaran/myrepository/tree/master/vinod-spring-webservice

 

 

 

Uploading file using RestEasy

In this example we will see how to upload a file using RestEasy MultipartFormDataInput and Jetty server.

1. Create a maven web project and add below dependencies

<url>http://maven.apache.org</url>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <version.resteasy>3.0.4.Final</version.resteasy>

    </properties>
    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>9.2.3.v20140905</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>9.2.3.v20140905</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-client</artifactId>
            <version>${version.resteasy}</version>
        </dependency>

        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>jaxrs-api</artifactId>
            <version>${version.resteasy}</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-multipart-provider</artifactId>
            <version>${version.resteasy}</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-jaxb-provider</artifactId>
            <version>${version.resteasy}</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-spring</artifactId>
            <version>${version.resteasy}</version>
        </dependency>
    </dependencies>

 

2. Update web.xml

This is required to load RestEasy servlets

<context-param>
        <param-name>resteasy.scan</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/rest</param-value>
    </context-param>
    <listener>
        <listener-class>
            org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
        </listener-class>
    </listener>
    <servlet>
        <servlet-name>resteasy-servlet</servlet-name>
        <servlet-class>
            org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
        </servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>resteasy-servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

3. Write a service to upload file

package com.vinod.test;

import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;

@Path("/fileupload")
public class JaxRSFileUploadController {

    @POST
    @Path("/fileupload")
    @Consumes("multipart/form-data")
    @Produces(MediaType.APPLICATION_JSON)
    public Response fileupload(MultipartFormDataInput input) {
        String fileName = "";
        int status = -1;
        Response resp = null;
        try {
            Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
            List<InputPart> inputParts = uploadForm.get("fileUpload");
            for (InputPart inputPart : inputParts) {
                MultivaluedMap<String, String> header = inputPart.getHeaders();
                fileName = getFileName(header);
                File file = new File(fileName);
                InputStream inputStream = inputPart.getBody(InputStream.class, null);
                byte[] bytes = IOUtils.toByteArray(inputStream);
                FileUtils.writeByteArrayToFile(file, bytes);
            }
            System.out.println("File upload completed");
            resp = Response.ok().build();
        } catch (Exception e) {
            e.printStackTrace();
            status = status <= 0 ? 500 : status;
            resp = Response.status(status).header("Warning", e.getMessage()).build();
        }
        return resp;
    }

    private String getFileName(MultivaluedMap<String, String> multivaluedMap) {
        String[] contentDisposition = multivaluedMap.getFirst("Content-Disposition").split(";");
        for (String filename : contentDisposition) {
            if (filename.trim().startsWith("filename")) {
                String[] name = filename.split("=");
                String exactFileName = name[1].trim().replaceAll("\"", "");
                return exactFileName;
            }
        }
        return "temp";
    }
}
 
 
 
4. Update pom.xml jetty configuration

<build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.2.3.v20140905</version>
                <configuration>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                    <useTestScope>true</useTestScope>
                    <useProvidedScope>true</useProvidedScope>
                    <httpConnector>
                        <port>8081</port>
                    </httpConnector>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

 
5. Run it
 
Use jetty:run maven command to start jetty server and use the below html file to upload the file
 

<html>
<body>
<form method="post" action="http://localhost:8081/fileupload/fileupload" enctype="multipart/form-data">
    <label>Load your file:</label>
    <input type="file" name="fileUpload" />
    <br />
    <input type="submit" value="Upload file" />
</form>
</body>
</html>
 
 

6. Download example

https://github.com/kkvinodkumaran/webservices/tree/master/vinod-rest-file-test

 


Model Context Protocol (MCP) — Complete Guide for Backend Engineers

  Model Context Protocol (MCP) — Complete Guide for Backend Engineers Build Tools, Resources, and AI-Driven Services Using LangChain Moder...

Featured Posts