Skip to content

Files

Latest commit

4c0bd03 · May 10, 2017

History

History
This branch is 107 commits ahead of, 3 commits behind matijaklj/kumuluzee-samples:master.

jpa

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
May 9, 2017
May 10, 2017
May 4, 2017

KumuluzEE JPA and CDI sample

Develop JPA entities and use CDI within a REST service and pack it as a KumuluzEE microservice.

The objective of this sample is to demonstrate how to develop JPA entities and use CDI. The tutorial guides you through the development of JPA entities and CDI within a REST service and shows how to pack it as a KumuluzEE microservice. You will add KumuluzEE dependencies into pom.xml. To develop the JPA entities, you will create @Entity classes. You will implement a CustomerService CDI class. Finally, you will call this class from the REST service class. Required knowledge: basic familiarity with JPA, CDI and basic concepts of REST and JSON.

Requirements

In order to run this example you will need the following:

  1. Java 8 (or newer), you can use any implementation:

    • If you have installed Java, you can check the version by typing the following in a command line:

      java -version
      
  2. Maven 3.2.1 (or newer):

    • If you have installed Maven, you can check the version by typing the following in a command line:

      mvn -version
      
  3. Git:

    • If you have installed Git, you can check the version by typing the following in a command line:

      git --version
      

Prerequisites

In order to run this sample you will have to setup a local PostgreSQL database:

  • database host: localhost:5432
  • database name: customers
  • user: postgres
  • password: postgres

The required tables will be created automatically upon running the sample.

Usage

The example uses maven to build and run the microservices.

  1. Build the sample using maven:

    $ cd jpa
    $ mvn clean package
  2. Run the sample:

    $ java -cp target/classes:target/dependency/* com.kumuluz.ee.EeApplication

    in Windows environment use the command

    java -cp target/classes;target/dependency/* com.kumuluz.ee.EeApplication

The application/service can be accessed on the following URL:

To shut down the example simply stop the processes in the foreground.

Tutorial

This tutorial will guide you through the steps required to create a simple REST microservice which uses JPA 2.1 and pack it as a KumuluzEE microservice. We will extend the existing KumuluzEE JAX-RS REST sample, with access to the database using JPA 2.1. Therefore, first complete the existing JAX-RS sample tutorial, or clone the JAX-RS sample code. We will use PostgreSQL in this tutorial.

We will follow these steps:

  • Complete the tutorial for KumuluzEE JAX-RS REST sample or clone the existing sample
  • Ensure access to PostgreSQL database.
  • Add Maven dependencies
  • Implement the persistence using standard JPA
  • Build the microservice
  • Run it

Add Maven dependencies

Since your existing starting point is the existing KumuluzEE JAX-RS REST sample, you should already have the dependencies for kumuluzee-bom, kumuluzee-core, kumuluzee-servlet-jetty and kumuluzee-jax-rs-jersey configured in pom.xml.

Add the kumuluzee-cdi-weld, kumuluzee-jpa-eclipselink and postgresql dependencies:

<dependency>
    <groupId>com.kumuluz.ee</groupId>
    <artifactId>kumuluzee-cdi-weld</artifactId>
</dependency>
<dependency>
    <groupId>com.kumuluz.ee</groupId>
    <artifactId>kumuluzee-jpa-eclipselink</artifactId>
</dependency>
<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.0.0</version>
</dependency>

Implement database access layer

Enhance existing Customer class with JPA annotations:

  • Add @Entity and @Table to make it persistable.
  • Add Customer.findCustomers named query for retrieving all customers from database
  • Mark attribute id as a primary key.
  • Change the default database column mapping.
@Entity
@Table(name = "customer")
@NamedQueries({
        @NamedQuery(
                name = "Customer.findCustomers",
                query = "SELECT c " +
                        "FROM Customer c"
        )
})
public class Customer implements Serializable {

    @Id
    private String id;
    @Column(name = "first_name")
    private String firstName;
    @Column(name = "last_name")
    private String lastName;

    // TODO: implement get and set methods
}

Implement CustomerService class. Implement it as a @RequestScoped CDI bean, and inject EntityManager. Use EntityManager to implement the following methods:

public Customer getCustomer(String customerId);
public List<Customer> getCustomers(); 
public void saveCustomer(Customer customer);
public void deleteCustomer(String customerId); 

Sample implementation of CustomerService class:

@RequestScoped
public class CustomerService {

    @PersistenceContext
    private EntityManager em;

    public Customer getCustomer(String customerId) {
        return em.find(Customer.class, customerId);
    }

    public List<Customer> getCustomers() {
        List<Customer> customers = em
                .createNamedQuery("Customer.findCustomers", Customer.class)
                .getResultList();

        return customers;
    }

    public void saveCustomer(Customer customer) {
        try {
            beginTx();
            em.persist(customer);
            commitTx();
        } catch (Exception e) {
            rollbackTx();
        }
    }

    public void deleteCustomer(String customerId) {
        Customer customer = em.find(Customer.class, customerId);
        if (customer != null) {
            try {
                beginTx();
                em.remove(customer);
                commitTx();
            } catch (Exception e) {
                rollbackTx();
            }
        }
    }

    private void beginTx() {
        if (!em.getTransaction().isActive())
            em.getTransaction().begin();
    }

    private void commitTx() {
        if (em.getTransaction().isActive())
            em.getTransaction().commit();
    }

    private void rollbackTx() {
        if (em.getTransaction().isActive())
            em.getTransaction().rollback();
    }
}

Implement REST Service

Make CustomerResource class a CDI bean by adding @RequestScoped annotation. Inject created CustomerService to CustomerResource using @Inject annotation. Replace the invocation of static Database class with invocation of injected CustomerService implementation. Sample implementation:

@RequestScoped
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("customers")
public class CustomerResource {

    @Inject
    private CustomerService customerBean;

    @GET
    public Response getAllCustomers() {
        List<Customer> customers = customerBean.getCustomers();
        return Response.ok(customers).build();
    }

    @GET
    @Path("{customerId}")
    public Response getCustomer(@PathParam("customerId") String customerId) {
        Customer customer = customerBean.getCustomer(customerId);
        return customer != null
                ? Response.ok(customer).build()
                : Response.status(Response.Status.NOT_FOUND).build();
    }

    @POST
    public Response addNewCustomer(Customer customer) {
        customerBean.saveCustomer(customer);
        return Response.noContent().build();
    }

    @DELETE
    @Path("{customerId}")
    public Response deleteCustomer(@PathParam("customerId") String customerId) {
        customerBean.deleteCustomer(customerId);
        return Response.noContent().build();
    }
}

Configure CDI

Create the directory resources/META-INF. In this directory create the file beans.xml with the following content to enable CDI:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_2.xsd"
       bean-discovery-mode="annotated">
</beans>

Configure database and persistence

Make sure, that you have database server prepared, as described in Prerequisites section.

In the directory resources/META-INF create the file persistence.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<persistence 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_1.xsd"
             version="2.1">
    <persistence-unit name="kumuluzee-samples-jpa" transaction-type="RESOURCE_LOCAL">

        <non-jta-data-source>jdbc/CustomersDS</non-jta-data-source>

        <class>com.kumuluz.ee.samples.jpa.Customer</class>

        <properties>
            <property name="javax.persistence.schema-generation.database.action" value="create"/>
            <property name="javax.persistence.schema-generation.create-source" value="metadata"/>
            <property name="javax.persistence.schema-generation.drop-source" value="metadata"/>
        </properties>
    </persistence-unit>
</persistence>

Modify the element class in the above example, to reflect the package and class name of entity Customer in your source code structure.

In the directory resources/META-INF add the file config.xml with the following database connectivity properties:

kumuluzee:
  datasources:
    - jndi-name: jdbc/CustomersDS
      connection-url: jdbc:postgresql://localhost:5432/customers
      username: postgres
      password: postgres
      max-pool-size: 20

Build the microservice and run it

To build the microservice and run the example, use the commands as described in previous sections.