///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2019, 2020 Oracle and/or its affiliates.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

///////////////////////////////////////////////////////////////////////////////

= Helidon MP JPA Guide
:description: Helidon MP JPA Guide
:keywords: helidon, guide, transaction, jpa, microprofile

This guide shows how to configure and use the
https://jcp.org/en/jsr/detail?id=338[Java Persistence API (JPA)] from
within a Helidon MP application.

== What You Need

|===
|About 30 minutes
|<<about/03_prerequisites.adoc,Helidon Prerequisites>>
|<<guides/20_datasource.adoc,An understanding of named data source support in Helidon MP>>
|<<guides/22_jta.adoc,An understanding of transaction support in Helidon MP>>
|An understanding of JPA itself
|===

== What You'll Do

By following this guide, you’ll enhance a bare-bones Helidon MP
application to use JPA, with automatic transaction support, backed by
https://www.eclipse.org/eclipselink/#jpa[EclipseLink], to access an
in-memory https://www.h2database.com/html/main.html[H2
database]. You’ll see how to install the relevant dependencies and add
JPA-related code to your application.

== Use the Maven Archetype to Generate a Helidon MP Application

In a shell, `cd` into an empty directory and run this:

[source,bash,subs="attributes+"]
----
mvn archetype:generate \
    -DinteractiveMode=false \
    -DarchetypeGroupId=io.helidon.archetypes \
    -DarchetypeArtifactId=helidon-mp \
    -DarchetypeVersion={helidon-version} \
    -DgroupId=io.helidon.example \
    -DartifactId=helidon-jpa \
    -Dpackage=io.helidon.example.jpa \
    -DrestResourceName=ExampleResource \
    -DapplicationName=ExampleApplication
----

Now `cd` into `helidon-jpa`.  The rest of this guide will assume all
relative paths are relative to this directory.

== Add the H2 Database Driver to the Runtime Classpath

Add the following dependency in your `pom.xml`:

[source,xml]
.`pom.xml`
----
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.199</version>
    <scope>runtime</scope>
</dependency>
----

In a production application, you may use a different database, so in
that case you may add a different database driver dependency here
instead.

== Add the Hikari Connection Pool Extension to the Runtime Classpath

Add the following dependency in your `pom.xml`:

[source,xml]
.`pom.xml`
----
<dependency>
    <groupId>io.helidon.integrations.cdi</groupId>
    <artifactId>helidon-integrations-cdi-datasource-hikaricp</artifactId>
    <scope>runtime</scope>
</dependency>
----

== Add the JTA Extension to the Runtime Classpath

Add the following dependency in your `pom.xml`:

[source,xml]
.`pom.xml`
----
<dependency>
    <groupId>io.helidon.integrations.cdi</groupId>
    <artifactId>helidon-integrations-cdi-jta-weld</artifactId>
    <scope>runtime</scope>
</dependency>
----

== Add the Provider-Independent Helidon JPA Extension to the Runtime Classpath

Add the following dependency in your `pom.xml`:

[source,xml]
.`pom.xml`
----
<dependency>
    <groupId>io.helidon.integrations.cdi</groupId>
    <artifactId>helidon-integrations-cdi-jpa</artifactId>
    <scope>runtime</scope>
</dependency>
----

== Add the EclipseLink JPA Extension to the Runtime Classpath

Add the following dependency in your `pom.xml`:

[source,xml]
.`pom.xml`
----
<dependency>
    <groupId>io.helidon.integrations.cdi</groupId>
    <artifactId>helidon-integrations-cdi-eclipselink</artifactId>
    <scope>runtime</scope>
</dependency>
----

== Add the JTA and JPA Dependencies to the Provided Classpath

Add the following dependencies in your `pom.xml`:

[source,xml]
.`pom.xml`
----
<dependency>
    <groupId>jakarta.persistence</groupId>
    <artifactId>jakarta.persistence-api</artifactId>
    <version>2.2.2</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax.transaction</groupId>
    <artifactId>javax.transaction-api</artifactId>
    <version>1.2</version>
    <scope>provided</scope>
</dependency>
----

== Add DDL to Create the Relevant Database Tables

Add the following file under `src/main/resources`:

[source,sql]
.`src/main/resources/greeting.ddl`
----
CREATE TABLE IF NOT EXISTS GREETING (
    SALUTATION VARCHAR(64) NOT NULL PRIMARY KEY,
    RESPONSE VARCHAR(64) NOT NULL
);

MERGE INTO GREETING (SALUTATION, RESPONSE) VALUES ('Marco', 'Polo');
----

== Add an `application.yaml` File With Database Connectivity Information

Replace the contents of the following file under `src/main/resources`:

[source,yaml]
.`src/main/resources/application.yaml`
----
server:
    port: 8080
javax:
    sql:
        DataSource:
            greetingDataSource:
                dataSourceClassName: org.h2.jdbcx.JdbcDataSource
                dataSource:
                    url: jdbc:h2:mem:greeting;INIT=RUNSCRIPT FROM 'classpath:greeting.ddl' <1>
                    user: sa
                    password: ""

----

<1> The
http://www.h2database.com/html/features.html#execute_sql_on_connection[H2
`INIT` property] tells H2 what command to run upon starting up.  In
this case, it is going to
http://www.h2database.com/html/commands.html#runscript[load and run]
the DDL mentioned above.

== Add a Java Class to Represent a Greeting JPA Entity

Add the following Java class under `src/main/java/io/helidon/example/jpa`:

[source,java]
.`src/main/java/io/helidon/example/jpa/Greeting.java`
----
package io.helidon.example.jpa;

import java.io.Serializable;
import java.util.Objects;

import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Access(value = AccessType.FIELD) <1>
@Entity(name = "Greeting") <2>
@Table(name = "GREETING") <3>
public class Greeting implements Serializable { <4>

    @Column(
        insertable = true,
        name = "SALUTATION", <5>
        nullable = false,
        updatable = false
    )
    @Id <6>
    private String salutation;

    @Basic(optional = false) <7>
    @Column(
        insertable = true,
        name = "RESPONSE",
        nullable = false,
        updatable = true
    )
    private String response;

    @Deprecated
    protected Greeting() { <8>
        super();
    }

    public Greeting(String salutation, String response) { <9>
        super();
        this.salutation = Objects.requireNonNull(salutation);
        this.setResponse(response);
    }

    public String getSalutation() {
        return this.salutation;
    }

    public String getResponse() {
        return this.response;
    }

    public void setResponse(String response) {
        this.response = Objects.requireNonNull(response);
    }

    @Override
    public String toString() {
        return this.getSalutation() + " " + this.getResponse();
    }

}
----

<1> (Some of the annotations in this example, like this one, have
sensible defaults, but the example specifies them explicitly for
clarity.)  This
https://javaee.github.io/javaee-spec/javadocs/javax/persistence/Access.html[`Access`
annotation] says that JPA will access this class' fields directly,
rather than via getter and setter methods.

<2> The
https://javaee.github.io/javaee-spec/javadocs/javax/persistence/Entity.html[`Entity`
annotation] identifies this class as a JPA entity.  The
https://javaee.github.io/javaee-spec/javadocs/javax/persistence/Entity.html#name--[`name`
element] value can be used in JPQL queries.

<3> The
https://javaee.github.io/javaee-spec/javadocs/javax/persistence/Table.html[`Table`
annotation] identifies the database table to which this class will be
mapped.

<4> JPA entities should be `Serializable`.

<5> The
https://javaee.github.io/javaee-spec/javadocs/javax/persistence/Column.html[`Column`
annotation] specifies what column in the database the annotated field
maps to.  The elements of the `Column` annotation further describe the
column.

<6> The
https://javaee.github.io/javaee-spec/javadocs/javax/persistence/Id.html[`Id`
annotation] indicates this field will be mapped to the primary key of
the database table.

<7> The
https://javaee.github.io/javaee-spec/javadocs/javax/persistence/Basic.html[`Basic`
annotation] indicates this field will be mapped to an ordinary
("basic") column.

<8> All JPA entities need a zero-argument constructor, but it doesn't
have to be `public`.  This constructor satisfies this requirement.  It
is marked `Deprecated` and is non-`public` so that normal users have
to supply data for the `salutation` and `response` fields via the
other constructor.

<9> This is the constructor normal users will use.

== Add a `META-INF/persistence.xml` Descriptor

Add the following file under `src/main/resources/META-INF`:

[source,xml]
.`src/main/resources/META-INF/persistence.xml`
----
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" <1>
             xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
                                 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <persistence-unit name="greeting" transaction-type="JTA"> <2>
        <description>A persistence unit for the greeting example.</description>
        <jta-data-source>greetingDataSource</jta-data-source> <3>
        <class>io.helidon.example.jpa.Greeting</class> <4>
        <properties> <5>
            <property name="eclipselink.deploy-on-startup" value="true"/>
            <property name="eclipselink.jdbc.native-sql" value="true"/>
            <property name="eclipselink.logging.logger" value="JavaLogger"/>
            <property name="eclipselink.logging.parameters" value="true"/>
            <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.H2Platform"/> <6>
            <property name="eclipselink.target-server" value="io.helidon.integrations.cdi.eclipselink.CDISEPlatform"/> <7>
            <property name="eclipselink.weaving" value="false"/> <8>
        </properties>
    </persistence-unit>
</persistence>
----

<1> Helidon MP's JPA extension supports JPA 2.2.

<2> Note that `JTA` is the transaction type.  JTA transactions are
fully supported.

<3> Note that the name of the data source is the one configured in the
`application.yaml` file described earlier.

<4> The `Greeting` class you created is listed here.

<5> The properties listed here are in general
https://www.eclipse.org/eclipselink/documentation/2.7/jpa/extensions/persistenceproperties_ref.htm[EclipseLink
properties].  Many are optional, but a few (detailed below) are required.

<6> https://www.eclipse.org/eclipselink/documentation/2.7/jpa/extensions/persistenceproperties_ref.htm#target-database[This
property] is required when EclipseLink is the JPA provider.  It is set
to `org.eclipse.persistence.platform.database.H2Platform` because this
example uses the H2 database.

<7> https://www.eclipse.org/eclipselink/documentation/2.7/jpa/extensions/persistenceproperties_ref.htm#target-server[This
property] is required, and when EclipseLink is the JPA provider must
have the value
`io.helidon.integrations.cdi.eclipselink.CDISEPlatform`.

<8> https://www.eclipse.org/eclipselink/documentation/2.7/jpa/extensions/persistenceproperties_ref.htm#weaving[This
property] is required when EclipseLink is the JPA provider and must be
set to `false`.

== Modify the `pom.xml` File To Support Static Weaving

_Weaving_ is the term that describes the bytecode manipulation that
JPA providers perform upon your simple Java entity classes (like the
`Greeting` class you created above).  In Helidon MicroProfile's JPA
extension, weaving must be performed statically (at build time).  Here
we modify the `pom.xml` to make that happen.

Add the following plugin configuration in your `pom.xml`:

[source,xml]
.`pom.xml`
----
<plugin>
    <groupId>com.ethlo.persistence.tools</groupId>
    <artifactId>eclipselink-maven-plugin</artifactId>
    <version>2.7.1.1</version>
    <dependencies> <!--1-->
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
    </dependencies>
    <executions>
        <execution>
            <id>weave</id>
            <phase>process-classes</phase>
            <goals>
                <goal>weave</goal> <!--2-->
            </goals>
        </execution>
        <execution>
            <id>modelgen</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>modelgen</goal> <!--3-->
            </goals>
        </execution>
    </executions>
</plugin>
----

<1> https://github.com/ethlo/eclipselink-maven-plugin[This plugin]
requires this `<dependencies>` section as a workaround.

<2> Static weaving is performed on compiled classes in place.

<3> The
https://javaee.github.io/tutorial/persistence-criteria002.html#GJIUP[JPA
static metamodel] is generated by this goal.

== Inject a Container-Managed `EntityManager`

In the `src/main/java/io/helidon/example/jpa/ExampleResource.java` file, add the following
imports:

[source,java]
.`src/main/java/io/helidon/example/jpa/ExampleResource.java`
----
import javax.enterprise.context.Dependent;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
----

Annotate the resource class declaration with `@Dependent`:

[source,java]
.`src/main/java/io/helidon/example/jpa/ExampleResource.java`
----
@Dependent <1>
public class ExampleResource {
----

<1> This ensures that `io.helidon.example.jpa.ExampleResource` is a
discoverable CDI bean.

Then add the following annotated field declaration:

[source,java]
.`src/main/java/io/helidon/example/jpa/ExampleResource.java`
----
@PersistenceContext <1>
private EntityManager em;
----

<1> The
https://javaee.github.io/javaee-spec/javadocs/javax/persistence/PersistenceContext.html[`@PersistenceContext`
annotation] indicates that you want an `EntityManager` injected here.

== Use the Injected `EntityManager`

In the `src/main/java/io/helidon/example/jpa/ExampleResource.java`
file, add the following import:

[source,java]
.`src/main/java/io/helidon/example/jpa/ExampleResource.java`
----
import javax.transaction.Transactional;
import javax.ws.rs.PathParam;
----

Add the following resource method to the `ExampleResource` class:

[source,java]
.`src/main/java/io/helidon/example/jpa/ExampleResource.java`
----
@GET
@Path("response/{salutation}")
@Produces("text/plain")
@Transactional <1>
public String getResponse(@PathParam("salutation") String salutation) {
    final Greeting greeting = this.em.find(Greeting.class, salutation);
    final String returnValue;
    if (greeting == null) {
        returnValue = null;
    } else {
        returnValue = greeting.getResponse();
    }
    return returnValue;
}
----

<1> A JTA transaction will be automatically started at the beginning
of this method when it is invoked as a result of an incoming HTTP
request, and committed or rolled back when the method terminates
normally or exceptionally.  The injected `EntityManager` will join the
transaction automatically.

== Add Logging

Add the following file under `src/main/resources`:

[source,properties]
.`src/main/resources/logging.properties`
----
.level=INFO
handlers=io.helidon.common.HelidonConsoleHandler
java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n

com.zaxxer.hikari.level=INFO
h2database.level=WARNING
io.netty.level=INFO
org.eclipse.persistence.level=FINE
org.glassfish.jersey.server.level=CONFIG
----

== Build the Application

Execute the following from the root directory of your application:

[source,bash]
----
mvn package
----

== Run the Application

Execute the following from the root directory of your application:

[source,bash]
----
java -jar target/helidon-jpa.jar
----

== Test the Application

Execute the following:

[source,bash]
----
curl http://localhost:8080/example/response/Marco
----

Observe that `Polo` is returned.
