How to build a Camel route to JPA



In this tutorial we will learn how to persist some data on a PostgreSQL Database using a Camel route which is based on the Java Persistence API (JPA) defined in a project.

The steps to complete this tutorial are:

  1. Let's start from a maven archetype
  2. Create the entity bean
  3. Configure the persistence.xml
  4. Configure the camel-context
  5. Define the camel route
  6. enjoy running it !

1. Camel Maven archetype

Start by creating the skeleton of your Camel project using its archetype:

mvn archetype:generate                   \
  -DarchetypeGroupId=org.apache.camel.archetypes  \
  -DarchetypeArtifactId=camel-archetype-spring   \
  -DarchetypeVersion=3.0.0 \
  -DgroupId=com.example.camel.jpa \
  -DartifactId=camel-jpa \
  -Dversion=1.0-SNAPSHOT

Next, we will adjust the dependencies in pom.xml so that we are able to use JPA, Hibernate and JAXB for marshalling:

<dependencyManagement>
    <dependencies>
      <!-- Camel BOM -->
      <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-parent</artifactId>
        <version>3.0.0</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-jaxb</artifactId>

    </dependency>
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-jpa</artifactId>
    </dependency>
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.2.12</version>
    </dependency>

    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-core</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-spring</artifactId>
    </dependency>

    <!-- logging -->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-api</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-slf4j-impl</artifactId>
      <scope>runtime</scope>
    </dependency>

    <!-- testing -->
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-test-spring</artifactId>
      <scope>test</scope>
    </dependency>

  </dependencies>

Now let's move to the code.

2. Create the Entity bean

The class Person represents the entity bean that will be inserted into the database:

package com.example.camel.jpa.model;

import javax.persistence.GenerationType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
 

@XmlRootElement
@XmlType
@Entity(name="Person")
public class Person {
    private Long id;
    private String name;
    private String surname;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSurname() {
        return surname;
    }
    public void setSurname(String surname) {
        this.surname = surname;
    }
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }


}

To help jaxb to create the JAXBContext we add the file jaxb.index under the resources folder of the project, using the same package structure of your Model bean:

│   └── resources
│       ├── com
│       │   └── example
│       │       └── camel
│       │           └── jpa
│       │               └── model
│       │                   └── jaxb.index

The jaxb.index file will contain just the name of the Class:

Person

3. Configure the persistence.xml

In the META-INF folder we add the following persistence.xml file with the jdbc properties to connect to the PostgreSQL database:

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="persistenceUnit"
                      transaction-type="RESOURCE_LOCAL">

        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" /> <!-- DB Driver -->
            <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost/cameldb" /> <!-- BD Mane -->
            <property name="javax.persistence.jdbc.user" value="camel" /> <!-- DB User -->
            <property name="javax.persistence.jdbc.password" value="camel" /> <!-- DB Password -->

            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL95Dialect"/> <!-- DB Dialect -->
            <property name="hibernate.hbm2ddl.auto" value="create-drop" /> <!-- create / create-drop / update -->

            <property name="hibernate.show_sql" value="true" /> <!-- Show SQL in console -->
            <property name="hibernate.format_sql" value="true" /> <!-- Show SQL formatted -->
        </properties>

    </persistence-unit>


</persistence>

4. Configure the camel-context

The following file, using spring, configures a camel context. A simple java route is added to the camel context.

In the camel context we add the jpa component. It needs also an EntityManagerFactory and a JpaTransactionManager.

<?xml version="1.0" encoding="UTF-8"?>
<!-- Configures the Camel Context-->

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">


  <camelContext trace="true" xmlns="http://camel.apache.org/schema/spring">
    <routeBuilder ref="myroute"/>
  </camelContext>
  <bean id="myroute" class="com.example.camel.jpa.MyRouteBuilder"/>
  <bean id="jpa" class="org.apache.camel.component.jpa.JpaComponent">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
    <property name="transactionManager" ref="jpaTxManager"/>
  </bean>
  <bean id="jpaTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
  </bean>
  <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="persistenceUnit"/>
  </bean>
</beans>

5. Define the camel route

The camel route is defined by MyRouteBuilder class in the configure method.

package com.example.camel.jpa;

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.dataformat.JaxbDataFormat;


public class MyRouteBuilder extends RouteBuilder {

    public void configure() {
        JaxbDataFormat jxb = new JaxbDataFormat();
        jxb.setContextPath("com.example.camel.jpa.model");

        from("file:src/data?noop=true")
                .unmarshal(jxb)
                .to("jpa:com.example.camel.jpa.model.Person");

    }
}

A JaxbDataFormat transforms data from xml to a Person entity and the jpa component inserts it in the database. The XML is picked up from the data folder:

<person>
    <name>Francesco</name>
    <surname>Marchioni</surname>
</person>

Here is the final view of the project:

camel jpa tutorial camel jpa tutorial

6. Enjoy running it

In order to test the project we will need a PostgreSQL database instance. For the sake of brevity we will just boot it with Docker as follows:

docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 --name camel_jpa -e POSTGRES_USER=camel -e POSTGRES_PASSWORD=camel -e POSTGRES_DB=cameldb -p 5432:5432 postgres:10.5

Now you can build and run the project with:

mvn clean install camel:run

Check from the output that the Table Person has been created and one rows has been inserted (the trace="true" option on the camel context make camel to trace the exchange transported in the route):

[pache.camel.spring.Main.main()] LogHelper                      INFO  HHH000204: Processing PersistenceUnitInfo [
	name: persistenceUnit
	...]
[pache.camel.spring.Main.main()] Version                        INFO  HHH000412: Hibernate Core {5.2.16.Final}
[pache.camel.spring.Main.main()] Environment                    INFO  HHH000206: hibernate.properties not found
[pache.camel.spring.Main.main()] Version                        INFO  HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
[pache.camel.spring.Main.main()] pooling                        WARN  HHH10001002: Using Hibernate built-in connection pool (not for production use!)
[pache.camel.spring.Main.main()] pooling                        INFO  HHH10001005: using driver [org.postgresql.Driver] at URL [jdbc:postgresql://localhost/cameldb]
[pache.camel.spring.Main.main()] pooling                        INFO  HHH10001001: Connection properties: {user=camel, password=****}
[pache.camel.spring.Main.main()] pooling                        INFO  HHH10001003: Autocommit mode: false
[pache.camel.spring.Main.main()] rManagerConnectionProviderImpl INFO  HHH000115: Hibernate connection pool size: 20 (min=1)
[pache.camel.spring.Main.main()] Dialect                        INFO  HHH000400: Using dialect: org.hibernate.dialect.PostgreSQL95Dialect
[pache.camel.spring.Main.main()] LobCreatorBuilderImpl          INFO  HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
[pache.camel.spring.Main.main()] BasicTypeRegistry              INFO  HHH000270: Type registration [java.util.UUID] overrides previous : org.hibernate.type.UUIDBinaryType@590e21d9
Hibernate: 
    
    drop table if exists Person cascade
[pache.camel.spring.Main.main()] access                         INFO  HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@538522bf] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
[pache.camel.spring.Main.main()] SqlExceptionHelper             WARN  SQL Warning Code: 0, SQLState: 00000
[pache.camel.spring.Main.main()] SqlExceptionHelper             WARN  table "person" does not exist, skipping
Hibernate: 
    
    drop sequence if exists hibernate_sequence
[pache.camel.spring.Main.main()] SqlExceptionHelper             WARN  SQL Warning Code: 0, SQLState: 00000
[pache.camel.spring.Main.main()] SqlExceptionHelper             WARN  sequence "hibernate_sequence" does not exist, skipping
Hibernate: create sequence hibernate_sequence start 1 increment 1
[pache.camel.spring.Main.main()] access                         INFO  HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@8d4116] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: 
    
    create table Person (
       id int8 not null,
        name varchar(255),
        surname varchar(255),
        primary key (id)
    )
[pache.camel.spring.Main.main()] SchemaCreatorImpl              INFO  HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@758c039c'
[pache.camel.spring.Main.main()] LocalEntityManagerFactoryBean  INFO  Initialized JPA EntityManagerFactory for persistence unit 'persistenceUnit'
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Apache Camel 3.0.0 (CamelContext: camel-1) is starting
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Tracing is enabled on CamelContext: camel-1
[pache.camel.spring.Main.main()] DefaultManagementStrategy      INFO  JMX is disabled
[pache.camel.spring.Main.main()] JpaComponent                   INFO  Using EntityManagerFactory configured: org.springframework.orm.jpa.LocalEntityManagerFactoryBean@60a13630
[pache.camel.spring.Main.main()] JpaComponent                   INFO  Using TransactionManager configured on this component: org.springframework.orm.jpa.JpaTransactionManager@152da0e0
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
[pache.camel.spring.Main.main()] FileEndpoint                   INFO  Endpoint is configured with noop=true so forcing endpoint to be idempotent as well
[pache.camel.spring.Main.main()] FileEndpoint                   INFO  Using default memory based idempotent repository with cache max size: 1000
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Route: route1 started and consuming from: file://src/data?noop=true
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Total 1 routes, of which 1 are started
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Apache Camel 3.0.0 (CamelContext: camel-1) started in 0.501 seconds
[pache.camel.spring.Main.main()] BaseMainSupport                INFO  Using properties from classpath:application.properties
[pache.camel.spring.Main.main()] DefaultShutdownStrategy        INFO  Starting to graceful shutdown 1 routes (timeout 300 seconds)
[el-1) thread #3 - ShutdownTask] DefaultShutdownStrategy        INFO  Route: route1 shutdown complete, was consuming from: file://src/data?noop=true
[pache.camel.spring.Main.main()] DefaultShutdownStrategy        INFO  Graceful shutdown of 1 routes completed in 0 seconds
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Route: route1 is stopped, was consuming from: file://src/data?noop=true
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Route: route1 is shutdown and removed, was consuming from: file://src/data?noop=true
[pache.camel.spring.Main.main()] FileEndpoint                   INFO  Endpoint is configured with noop=true so forcing endpoint to be idempotent as well
[pache.camel.spring.Main.main()] FileEndpoint                   INFO  Using default memory based idempotent repository with cache max size: 1000
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Route: route1 started and consuming from: file://src/data?noop=true
[pache.camel.spring.Main.main()] DefaultRoutesCollector         INFO  Loading additional Camel XML routes from: classpath:camel/*.xml
[pache.camel.spring.Main.main()] DefaultRoutesCollector         INFO  Loading additional Camel XML rests from: classpath:camel-rest/*.xml
[1) thread #4 - file://src/data] StaxConverter                  INFO  Created XMLInputFactory: com.sun.xml.internal.stream.XMLInputFactoryImpl@23759ec0. DOMSource/DOMResult may have issues with com.sun.xml.internal.stream.XMLInputFactoryImpl@23759ec0. We suggest using Woodstox.
Hibernate: 
    select
        nextval ('hibernate_sequence')
Hibernate: 
    insert 
    into
        Person
        (name, surname, id) 
    values
        (?, ?, ?)

Perfect. You can also log into the Docker container image and check that the data is actually there:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
f19c77664c8d        postgres:10.5       "docker-entrypoint..."   About an hour ago   Up About an hour    0.0.0.0:5432->5432/tcp   camel_jpa

$ docker exec -it f19c77664c8d /bin/bash

# psql cameldb camel
psql (10.5 (Debian 10.5-2.pgdg90+1))
Type "help" for help.

cameldb=# \dt;
        List of relations
 Schema |  Name  | Type  | Owner 
--------+--------+-------+-------
 public | person | table | camel
(1 row)


cameldb=# select * from person;
 id |   name    |  surname  
----+-----------+-----------
  1 | Francesco | Marchioni
(1 row)

What about reading data from database?

Exercise: Try it:

public void configure() {

        JaxbDataFormat jxb = new JaxbDataFormat();
        jxb.setContextPath("com.example.camel.jpa.model");

        from("jpa:com.example.camel.jpa.model.Person?consumer.query=select o from com.example.camel.jpa.model.Person")
        .marshal(jaxb)
        .log("${body}");
           
    }

Summary

We have just covered how to manage JPA marshalling using a Camel Route and the Camel JPA component.

The complete code is here:  https://github.com/fmarchioni/masteringintegration/tree/master/camel-jpa

 

FREE WildFly Application Server - JBoss - Quarkus - Drools Tutorials
Cookie Policy

Cookie Policy This website uses cookies that are necessary to its functioning and required to achieve the purposes illustrated in the privacy policy. By accepting this OR scrolling this page OR continuing to browse, you agree to our privacy policy.

© 2020 Your Company. All Rights Reserved. Designed By JoomShaper

Please publish modules in offcanvas position.