> ## Documentation Index
> Fetch the complete documentation index at: https://developer.upsun.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Eclipse MicroProfiles: gain agility, release faster

> Explore how Eclipse MicroProfile optimizes Enterprise Java for microservices architecture. Learn about Java frameworks and Platform.sh for cloud deployment.

export const PostMeta = ({data = {}}) => {
  const {author, date, image} = data;
  const authors = Array.isArray(author) ? author : author ? [author] : [];
  const resolveAuthor = slug => {
    const entry = AUTHOR_MAP[slug] || ({});
    const name = entry.name || slug;
    const github = entry.github || null;
    const linkedin = entry.linkedin || null;
    const url = github ? `https://github.com/${github}` : linkedin || null;
    const avatarUrl = github ? `https://github.com/${github}.png?size=64` : null;
    return {
      name,
      url,
      avatarUrl
    };
  };
  const formattedDate = date ? new Date(date).toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  }) : null;
  if (!image && authors.length === 0 && !formattedDate) return null;
  const AUTHOR_MAP = {
    "aaron-collier": {
      "name": "Aaron Collier"
    },
    "aaron-dudenhofer": {
      "name": "Aaron Dudenhofer"
    },
    "aaron-porter": {
      "name": "Aaron Porter"
    },
    "adriaan-odendaal": {
      "name": "Adriaan Odendaal"
    },
    "ajmal": {
      "name": "Ajmal Siddiqui"
    },
    "akalipetis": {
      "name": "Antonis Kalipetis"
    },
    "alexander-varwijk": {
      "name": "Alexander Varwijk"
    },
    "alicia-bevilacqua": {
      "name": "Alicia Bevilacqua"
    },
    "amelie-deguerry": {
      "name": "Amelie Deguerry"
    },
    "anacidre": {
      "name": "Ana Cidre",
      "linkedin": "https://www.linkedin.com/in/ana-cidre"
    },
    "andoni": {
      "name": "Andoni Auzmendi"
    },
    "andrei-taranu": {
      "name": "Andrei (Alex) Taranu",
      "linkedin": "https://www.linkedin.com/in/andrei-alex-taranu/"
    },
    "andrew-baxter": {
      "name": "Andrew Baxter"
    },
    "andrew-melck": {
      "name": "Andrew Melck"
    },
    "antoine-crochet-damais": {
      "name": "Antoine Crochet Damais"
    },
    "augustin-delaporte": {
      "name": "Augustin Delaporte",
      "linkedin": "https://www.linkedin.com/in/augustindelaporte/"
    },
    "branislav-bujisic": {
      "name": "Branislav Bujisic"
    },
    "carl-smith": {
      "name": "Carl Smith"
    },
    "caroline-leroy": {
      "name": "Caroline Leroy"
    },
    "cati-mayer": {
      "name": "Cati Mayer"
    },
    "catplat": {
      "name": "C Trinkwon"
    },
    "ceelolulu": {
      "name": "Celeste van der Watt"
    },
    "chadwcarlson": {
      "name": "Chad Carlson",
      "github": "chadwcarlson",
      "linkedin": "https://www.linkedin.com/in/chadwcarlson"
    },
    "chris-ward": {
      "name": "Chris Ward"
    },
    "chris-yates": {
      "name": "Chris Yates"
    },
    "christian-sieber": {
      "name": "Christian Sieber"
    },
    "christopher-lockheardt": {
      "name": "Christopher Lockheardt"
    },
    "christopher-skene": {
      "name": "Christopher Skene"
    },
    "chuck-morgan": {
      "name": "Chuck Morgan"
    },
    "corey-dockendorf": {
      "name": "Corey Dockendorf"
    },
    "crell": {
      "name": "Crell"
    },
    "damz": {
      "name": "Damz"
    },
    "dan-morrison": {
      "name": "Dan Morrison"
    },
    "davidbonachera": {
      "name": "David Bonachera",
      "github": "davidbonachera",
      "linkedin": "https://www.linkedin.com/in/davidbonachera"
    },
    "dereliahmet1": {
      "name": "Ahmet Faruk Dereli"
    },
    "devicezero": {
      "name": "Jonas Kröger",
      "github": "devicezero",
      "linkedin": "https://www.linkedin.com/in/jonaskroeger/"
    },
    "doug-goldberg": {
      "name": "Doug Goldberg"
    },
    "duncan-naves": {
      "name": "Duncan Naves",
      "github": "duncannaves",
      "linkedin": "https://www.linkedin.com/in/duncan-naves-a94423aa"
    },
    "erika-bustamante": {
      "name": "Erika Bustamante"
    },
    "fabpot": {
      "name": "Fabien Potencier"
    },
    "flovntp": {
      "name": "Florent Huck",
      "github": "flovntp",
      "linkedin": "https://www.linkedin.com/in/florenthuck"
    },
    "fred-plais": {
      "name": "Fred Plais"
    },
    "gauthier-garnier": {
      "name": "Gauthier Garnier"
    },
    "gilzow": {
      "name": "Paul Gilzow"
    },
    "gmoigneu": {
      "name": "Guillaume Moigneu",
      "github": "gmoigneu",
      "linkedin": "https://www.linkedin.com/in/guillaumemoigneu/"
    },
    "gregqualls": {
      "name": "Greg Qualls"
    },
    "guguss": {
      "name": "Augustin Delaporte"
    },
    "haylee-millar": {
      "name": "Haylee Millar"
    },
    "ivana-kotur": {
      "name": "Ivana Kotur"
    },
    "jackrabbithanna": {
      "name": "Mark Hanna"
    },
    "jared-wright": {
      "name": "Jared Wright",
      "github": "jww-sh",
      "linkedin": "https://www.linkedin.com/in/jaredwaynewright"
    },
    "jessica-orozco": {
      "name": "Jessica Orozco"
    },
    "joey-stanford": {
      "name": "Joey Stanford"
    },
    "john-grubb": {
      "name": "John Grubb"
    },
    "jonas-kruger": {
      "name": "Jonas Kruger"
    },
    "kathryn-frazer": {
      "name": "Kathryn Frazer"
    },
    "kemiojo": {
      "name": "Kemi Elizabeth Ojogbede"
    },
    "kieronsambrook-smith": {
      "name": "Kieronsambrook Smith"
    },
    "laurent-arnoud": {
      "name": "Laurent Arnoud"
    },
    "letoya-boyne": {
      "name": "Letoya Boyne"
    },
    "lolautruche": {
      "name": "Jérôme Vieilledent"
    },
    "lyly-lepinay": {
      "name": "Lyly Lepinay"
    },
    "manauwar-alam": {
      "name": "Manauwar Alam"
    },
    "marc-antoine-porri": {
      "name": "Marc Antoine Porri"
    },
    "maria-antinkaapo": {
      "name": "Maria Antinkaapo"
    },
    "maria-de-anton": {
      "name": "Maria De Anton"
    },
    "mark-dorison": {
      "name": "Mark Dorison"
    },
    "markus-hausammann": {
      "name": "Markus Hausammann"
    },
    "mary-thomas": {
      "name": "Mary Thomas"
    },
    "mathias-bolt-lesniak": {
      "name": "Mathias Bolt Lesniak"
    },
    "mathieu-strauch": {
      "name": "Mathieu Strauch"
    },
    "matthias-van-woensel": {
      "name": "Matthias Van Woensel",
      "linkedin": "https://www.linkedin.com/in/matthias-van-woensel-267a069"
    },
    "michael-sharp": {
      "name": "Michael Sharp"
    },
    "mupsi": {
      "name": "Marine Gandy"
    },
    "natalie-harper": {
      "name": "Natalie Harper"
    },
    "ngommenginger": {
      "name": "Nicolas Gommenginger",
      "linkedin": "https://www.linkedin.com/in/nicolas-gommenginger"
    },
    "nicholas-bennison": {
      "name": "Nicholas Bennison"
    },
    "nicholas-vahalik": {
      "name": "Nicholas Vahalik"
    },
    "nick-hardiman": {
      "name": "Nick Hardiman"
    },
    "nickanderegg": {
      "name": "Nickanderegg"
    },
    "nicolas-grekas": {
      "name": "Nicolas Grekas",
      "github": "nicolas-grekas",
      "linkedin": "https://www.linkedin.com/in/nicolasgrekas/"
    },
    "niti-malwade": {
      "name": "Niti Malwade"
    },
    "opensocialteam": {
      "name": "Opensocialteam"
    },
    "ori-pekelman": {
      "name": "Ori Pekelman"
    },
    "otavio-santana": {
      "name": "Otavio Santana"
    },
    "palwandi": {
      "name": "Pawan Alwandi",
      "github": "pawpy",
      "linkedin": "https://www.linkedin.com/in/pawanalwandi"
    },
    "patrick-boest": {
      "name": "Patrick Boest"
    },
    "patrick-dawkins": {
      "name": "Patrick Dawkins",
      "github": "pjcdawkins",
      "linkedin": "https://www.linkedin.com/in/patrickdawkins"
    },
    "patrick-klima": {
      "name": "Patrick Klima"
    },
    "pjcdawkins": {
      "name": "Pjcdawkins"
    },
    "prineet-kaurbhurji": {
      "name": "Prineet Kaurbhurji"
    },
    "quentin-sinig": {
      "name": "Quentin Sinig"
    },
    "ralt": {
      "name": "Florian Margaine",
      "github": "ralt",
      "linkedin": "https://www.linkedin.com/in/florian-margaine-43971136"
    },
    "ramanathanramakrishnamurthy": {
      "name": "Ramanathanramakrishnamurthy"
    },
    "remi-lejeune": {
      "name": "Rémi Lejeune"
    },
    "ribel": {
      "name": "Taras Kruts"
    },
    "robert-douglass": {
      "name": "Robert Douglass"
    },
    "rudy-weber": {
      "name": "Rudy Weber"
    },
    "ryan-hicks": {
      "name": "Ryan Hicks"
    },
    "sabri-helal": {
      "name": "Sabri Helal"
    },
    "savannah-bergeron": {
      "name": "Savannah Bergeron"
    },
    "shannon-vettes": {
      "name": "Shannon Vettes"
    },
    "shawn-ogasawara": {
      "name": "Shawn Ogasawara",
      "linkedin": "https://www.linkedin.com/in/shawn-ogasawara-83a9a0/"
    },
    "shawna-spoor": {
      "name": "Shawna Spoor"
    },
    "shedrack-akintayo": {
      "name": "Shedrack Akintayo"
    },
    "simon-ruggier": {
      "name": "Simon Ruggier"
    },
    "sophie-van-der-kindere": {
      "name": "Sophie Van Der Kindere"
    },
    "stefanos-thampis": {
      "name": "Stefanos Thampis"
    },
    "stephen-weinberg": {
      "name": "Stephen Weinberg"
    },
    "sukhman-virk": {
      "name": "Sukhman Virk"
    },
    "sumaira-nazir": {
      "name": "Sumaira Nazir"
    },
    "sumer": {
      "name": "Sümer Cip"
    },
    "syed-raza": {
      "name": "Syed Raza"
    },
    "tamara-bacchia": {
      "name": "Tamara Bacchia"
    },
    "tara-arnold": {
      "name": "Tara Arnold"
    },
    "theosakamg": {
      "name": "Mickael Gaillard",
      "github": "theosakamg"
    },
    "thomasdiluccio": {
      "name": "Thomas di Luccio"
    },
    "tim-anderson": {
      "name": "Tim Anderson"
    },
    "tom-helmer-hansen": {
      "name": "Tom Helmer Hansen"
    },
    "tylermills": {
      "name": "Tyler Mills"
    },
    "upsun": {
      "name": "Upsun"
    },
    "veronika-tolkachova": {
      "name": "Veronika Tolkachova",
      "linkedin": "https://www.linkedin.com/in/veronika-tolkachova-169167a2"
    },
    "vince-parker": {
      "name": "Vince Parker"
    },
    "vinnie-russo": {
      "name": "Vincenzo Russo"
    },
    "vrobert78": {
      "name": "Vincent Robert",
      "github": "vrobert78",
      "linkedin": "https://www.linkedin.com/in/vincent-robert-498a883"
    },
    "yuriy-babenko": {
      "name": "Yuriy Babenko"
    },
    "yuriy-gerasimov": {
      "name": "Yuriy Gerasimov"
    }
  };
  return <div className="post-meta">
      {(authors.length > 0 || formattedDate) && <div className="post-meta-info">
          {authors.length > 0 && <div className="post-meta-authors">
              {authors.map(slug => {
    const {name, url, avatarUrl} = resolveAuthor(slug);
    const inner = <>
                    {avatarUrl && <img src={avatarUrl} alt={name} className="post-meta-avatar" />}
                    <span className="post-meta-author-name">{name}</span>
                  </>;
    return url ? <a key={slug} href={url} target="_blank" rel="noopener noreferrer" className="post-meta-author">
                    {inner}
                  </a> : <span key={slug} className="post-meta-author">{inner}</span>;
  })}
            </div>}
          {authors.length > 0 && formattedDate && <span className="post-meta-separator" aria-hidden="true">·</span>}
          {formattedDate && <span className="post-meta-date">{formattedDate}</span>}
        </div>}
      {image && <img src={image} alt="" className="post-meta-image" aria-hidden="true" />}
    </div>;
};

<PostMeta data={{ author: ["otavio-santana"], date: "2019-07-15", image: "/images/posts/unknown/eclipse-microprofiles-gain-agility-release-faster/eclipse-microprofiles-gain-agility-release-faster.webp" }} />

<Tip>
  This post was originally published on the Platform.sh blog and reflects information from the time of publication.
</Tip>

*Divide and conquer*—the most critical Roman strategy—works efficiently in several areas. The context to take any giant issue and break it down into small pieces to make the job easier to understand, making it scalable and agile, and allowing more people to work on it to deliver faster. The microservice was born from this principle. The microservices architecture is a variant of the service-oriented architecture style that structures an application as a collection of loosely coupled services. In a microservices architecture, services are fine-grained, and protocols are lightweight. In Java, there are several frameworks (including Spring Boot, which we explored in a [previous post](/posts/unknown/java-hello-world-at-platform.sh)). Today, let’s walk through the Java/JakartaEE side and talk about the [Eclipse MicroProfile](https://microprofile.io/).

The goal of the Eclipse MicroProfile initiative: to optimize Enterprise Java for the microservices architecture. It’s based on a subset of JakartaEE APIs, so we can build MicroProfile applications the same way we build JakartaEE ones.

MicroProfiles define standard APIs for building microservices and deliver portable applications across multiple MicroProfile runtimes.

## Show me the code

Ok, let's start talking code. Not to digress (you’ll see my rationale in the next paragraph!), but in August, I'll be starting a fantastic trip around Latin America to talk about Java, cloud computing, NoSQL, and I’ll be joining the Oracle Groundbreakers Tour LATAM 2019:

* [Argentina – August 6](https://www.aroug.org)
* [Brazil/SP – August 9](https://www.guob.com.br/)
* [Ecuador – August 13](https://www.ecuoug.org/)
* [Colombia – August 15-16](https://www.asuoc.org.co/)
* [Panama – August 19](https://www.facebook.com/oug.panama)
* [Costa Rica – August 21](https://apex.oracle.com/pls/apex/f?p=29385:1::::::)
* [Mexico – August 23](https://www.oramex.org/)
* [Guatemala – August 26](https://www.facebook.com/oracleguatemala/)

To celebrate, let’s create a microservice with an Eclipse MicroProfile that manages countries for the Latin America trip. The first step in the [Maven project](https://maven.apache.org/guides/getting-started/) is to set up the libraries needed for the project.

```xml theme={null}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>sh.platform.start</groupId>
	<artifactId>thorntail-jpa</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>war</packaging>

	<properties>
    	<version.thorntail>2.4.0.Final</version.thorntail>
    	<maven.compiler.source>1.8</maven.compiler.source>
    	<maven.compiler.target>1.8</maven.compiler.target>
    	<failOnMissingWebXml>false</failOnMissingWebXml>
    	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>
	<dependencyManagement>
    	<dependencies>
        	<dependency>
            	<groupId>io.thorntail</groupId>
            	<artifactId>bom-all</artifactId>
            	<version>${version.thorntail}</version>
            	<scope>import</scope>
            	<type>pom</type>
        	</dependency>
    	</dependencies>
	</dependencyManagement>

	<dependencies>
    	<dependency>
        	<groupId>io.thorntail</groupId>
        	<artifactId>microprofile</artifactId>
    	</dependency>
    	<dependency>
        	<groupId>org.hibernate</groupId>
        	<artifactId>hibernate-entitymanager</artifactId>
        	<version>5.4.3.Final</version>
    	</dependency>
    	<dependency>
        	<groupId>sh.platform</groupId>
        	<artifactId>config</artifactId>
        	<version>2.2.1</version>
    	</dependency>
    	<dependency>
        	<groupId>postgresql</groupId>
        	<artifactId>postgresql</artifactId>
        	<version>9.1-901-1.jdbc4</version>
    	</dependency>
	</dependencies>

	<build>
    	<finalName>country</finalName>
    	<plugins>
        	<plugin>
            	<groupId>io.thorntail</groupId>
            	<artifactId>thorntail-maven-plugin</artifactId>
            	<version>${version.thorntail}</version>
        	</plugin>
    	</plugins>
	</build>

	<repositories>
    	<repository>
        	<id>oss.sonatype.org-snapshot</id>
        	<url>http://oss.sonatype.org/content/repositories/snapshots</url>
        	<releases>
            	<enabled>false</enabled>
        	</releases>
        	<snapshots>
            	<enabled>true</enabled>
        	</snapshots>
    	</repository>
	</repositories>

</project>
```

There’s no specification that covers the storage technology on the Eclipse MicroProfile, but once the MicroProfile has synergy with Jakarta EE, it will use a Java Persistence API ([JPA](https://www.vogella.com/tutorials/JavaPersistenceAPI/article.html)).

JPA entity classes are user-defined classes whose instances can be stored in an annotation-driven database. There are annotations such as @Entity, @Table, @Id, and @Column that make the object-to-database transition smoother than doing it manually, helping to speed development.

```java theme={null}
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import java.util.Objects;

@Entity
@Table(name = "country")
public class Country {

	@Id
	@GeneratedValue
	private Integer id;

	@Column
	@NotBlank
	private String name;

	@Column
	private String city;

	@Column
	private String twitter;

	@Column
	private String link;

}
```

After defining the model, let's enable the JPA and CDI technologies. In the root of the code, we'll create two files in the folder `src/main/resources/META-INF`

<div class="emphasize">
  <div class="inner">
    <p>
      Bean.xml. The bean.xml file will enable the CDI (Contexts and Dependency Injection), which is a standard dependency injection framework on Jakarta EE. It enables us to manage the lifecycle of stateful components via domain-specific lifecycle contexts and inject components (services) into client objects in a type-safe way.
    </p>
  </div>

  <div class="accent" />
</div>

```xml theme={null}
<?xml version="1.0"?>
<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_2_0.xsd"
   	bean-discovery-mode="all"
   	version="2.0">
</beans>
```

<div class="emphasize">
  <div class="inner">
    <p>
      Persistence.xml. The persistence.xml is the central piece of configuration. That makes it one of the most important files of your persistence layer. It defines the JPA provider, the driver, user, password, and so on. For this sample code, we'll use PostgreSQL, but don't worry about the blank configuration; it will be defined in real time using Platform Config Reader.
    </p>
  </div>

  <div class="accent" />
</div>

```xml theme={null}
<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="jpa-example">
    	<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    	<class>sh.platform.template.Country</class>
    	<properties>
        	<property name="javax.persistence.jdbc.url" value="" />
        	<property name="javax.persistence.jdbc.driver" value="" />
        	<property name="javax.persistence.jdbc.user" value="" />
        	<property name="javax.persistence.jdbc.password" value="" />
        	<property name="hibernate.default_schema" value="public" />
        	<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL94Dialect"/>
        	<property name="hibernate.connection.autocommit" value="true" />
        	<property name="hibernate.hbm2ddl.auto" value="update"/>
        	<property name="show_sql" value="update"/>
    	</properties>
	</persistence-unit>
</persistence>
```

Our next step is to combine the JPA and CDI. In brief, this combination will make the EntityManagerFactory eligible through all applications using the [Inject annotation](https://javaee.github.io/javaee-spec/javadocs/javax/inject/Inject.html).

```java theme={null}
import sh.platform.config.Config;
import sh.platform.config.JPA;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

@ApplicationScoped
class EntityManagerConfiguration {

	private EntityManagerFactory entityManagerFactory;

	private EntityManager entityManager;

	@PostConstruct
	void setUp() {
    	Config config = new Config();
    	final JPA credential = config.getCredential("postgresql", JPA::new);
    	entityManagerFactory = credential.getPostgreSQL("jpa-example");
    	entityManager = entityManagerFactory.createEntityManager();
	}

	@Produces
	@ApplicationScoped
	EntityManagerFactory getEntityManagerFactory() {
    	return entityManagerFactory;
	}

	@Produces
	@ApplicationScoped
	EntityManager getEntityManager() {
    	return entityManager;
	}

	void close(@Disposes EntityManagerFactory entityManagerFactory) {
    	entityManagerFactory.close();
	}

	void close(@Disposes EntityManager entityManager) {
    	entityManager.close();
	}

}
```

The CDI has impressive features, including the [scope](https://docs.oracle.com/javaee/7/tutorial/cdi-basic008.htm). Therefore, we can define an [EntityManager](https://javaee.github.io/javaee-spec/javadocs/javax/persistence/EntityManager.html) to be used in the whole application, and when the application shuts down, it will close the containers [one by one](https://www.javacodegeeks.com/2013/05/java-ee-cdi-disposer-methods-example.html).

```java theme={null}
import javax.interceptor.InterceptorBinding;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Inherited
@InterceptorBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Transactional {
}

import sh.platform.config.Config;
import sh.platform.config.JPA;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

@ApplicationScoped
class EntityManagerConfiguration {

	private EntityManagerFactory entityManagerFactory;

	private EntityManager entityManager;

	@PostConstruct
	void setUp() {
    	Config config = new Config();
    	final JPA credential = config.getCredential("postgresql", JPA::new);
    	entityManagerFactory = credential.getPostgreSQL("jpa-example");
    	entityManager = entityManagerFactory.createEntityManager();
	}

	@Produces
	@ApplicationScoped
	EntityManagerFactory getEntityManagerFactory() {
    	return entityManagerFactory;
	}

	@Produces
	@ApplicationScoped
	EntityManager getEntityManager() {
    	return entityManager;
	}

	void close(@Disposes EntityManagerFactory entityManagerFactory) {
    	entityManagerFactory.close();
	}

	void close(@Disposes EntityManager entityManager) {
    	entityManager.close();
	}

}
```

The Country entity class and the database integration are now ready. The next step: the service layer with the CountryService class, which is the layer that integrates the database with the business. The CountryService class will do the essential CRUD operations on PostgreSQL to handle the transaction we need for the transactional annotation. It’s easy!

```java theme={null}
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import java.util.List;
import java.util.Optional;

@ApplicationScoped
public class CountryService {

	@Inject
	private EntityManager entityManager;

	@Transactional
	public Country insert(Country country) {
    	entityManager.persist(country);
    	return country;
	}

	@Transactional
	public void update(Country country) {
    	entityManager.persist(country);
	}

	@Transactional
	public void delete(Integer id) {
    	find(id).ifPresent(c -> entityManager.remove(c));
	}

	public Optional<Country> find(Integer id) {
    	return Optional.ofNullable(entityManager.find(Country.class, id));
	}

	public List<Country> findAll() {
    	String query = "select c from Country c";
    	return entityManager.createQuery(query).getResultList();
	}
}
```

The last piece of Java code is the rest integration, where we’re going to use a JAX-RS that belongs to both Eclipse MicroProfile and Jakarta EE. On JAX-RS, all HTTP methods and paths are annotation-driven, using intuitive annotations such as @GET, @PUT, or @DELETE. We can now do the integration in a more relaxed way, saying “juguetón!” (“playful” in Spanish).

```java theme={null}
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Optional;

import static javax.ws.rs.core.Response.Status.NO_CONTENT;
import static javax.ws.rs.core.Response.status;

@Path("countries")
@RequestScoped
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class CountryResource {

	@Inject
	private CountryService countryService;

	@GET
	public List<Country> doGet() {
    	return countryService.findAll();
	}

	@GET
	@Path("{id}")
	public Country findById(@PathParam("id") Integer id) {
    	final Optional<Country> conference = countryService.find(id);
    	return conference.orElseThrow(this::notFound);
	}

	@PUT
	@Path("{id}")
	public Country update(@PathParam("id") Integer id, Country countryUpdated) {
    	final Optional<Country> optional = countryService.find(id);
    	final Country country = optional.orElseThrow(() -> notFound());
    	country.update(countryUpdated);
    	countryService.update(country);
    	return country;
	}

	@DELETE
	@Path("{id}")
	public Response remove(@PathParam("id") Integer id) {
    	countryService.delete(id);
    	return status(NO_CONTENT).build();
	}

	@POST
	public Country insert(Country country) {
    	return countryService.insert(country);
	}

	private WebApplicationException notFound() {
    	return new WebApplicationException(Response.Status.NOT_FOUND);
	}

}
```

The last class enables the JAX-RS and defines the root URL for the services.

```java theme={null}
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("")
public class ApplicationConfig extends Application {
}
```

## Platform.sh structure

The Java application is now ready to go! The next step is to set up the Platform.sh files required to manage and deploy the application. In our first [Java post](/posts/unknown/java-hello-world-at-platform.sh), we took a deep dive into these three files:

* One Router (.platform/routes.yaml). Platform.sh allows you to define the [routes](https://docs.platform.sh/configuration/routes.html).
* Zero or more service containers (.platform/services.yaml). Platform.sh allows you to completely define and configure the [topology and services](https://docs.platform.sh/configuration/services.html) you want to use on your project.
* One or more application containers (.platform.app.yaml). You control your application and the way it will be built and deployed on Platform.sh via a single [configuration file](https://docs.platform.sh/configuration/app-containers.html).

The file that will change in this post is the [service file](https://docs.platform.sh/configuration/services.html), so you can define a database, search engine, cache, and so on. In this project, we'll set up [PostgreSQL](https://docs.platform.sh/configuration/services/postgresql.html) instead of [MySQL](https://docs.platform.sh/configuration/services/mysql.html).

```yaml theme={null}
postgresql:
  type: postgresql:11
  disk: 512
  size: S
```

We'll keep the route file the same [as in the first post](/posts/unknown/java-hello-world-at-platform.sh), but we'll change the platform.app.yaml to run thorntail uberjar.

```yaml theme={null}
# This file describes an application. You can have multiple applications
# in the same project.
#
# See https://docs.platform.sh/user_guide/reference/platform-app-yaml.html

# The name of this app. Must be unique within a project.
name: app

# The runtime the application uses.
type: "java:8"

disk: 1024

# The hooks executed at various points in the lifecycle of the application.
hooks:
  build: mvn -DskipTests clean package thorntail:package

# The relationships of the application with services or other applications.
#
# The left-hand side is the name of the relationship as it will be exposed
# to the application in the PLATFORM_RELATIONSHIPS variable. The right-hand
# side is in the form `<service name>:<endpoint name>`.
relationships:
  postgresql: "postgresql:postgresql"

# The configuration of the app when it is exposed to the web.
web:
  commands:
    start: java -jar -Xmx512m -Dswarm.http.port=$PORT -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses=true target/country-thorntail.jar
```

The application is now ready, so it’s time to move it to the cloud with Platform.sh using the following [sets](https://docs.platform.sh/gettingstarted/first-project.html):

* Create a [free trial account](https://docs.platform.sh/gettingstarted/first-project.html#your-first-project).
* Sign up with a new username and password, or login using a current GitHub, Bitbucket, or Google account. If you use a third-party login, you’ll be able to set a password for your Platform.sh account later.
* Select the region of the world where you want your site to live.
* Select the blank template.

After this wizard, Platform.sh will provision the whole infrastructure to you, as well as provide a Git remote repository. Before access, remember to set the SSH keys. The Platform.sh Git-driven infrastructure will automatically manage everything your application needs to push it to the master remote repository. You only need to write your code—including a few <a href="https://docs.platform.sh/overview/yaml/what-is-yaml.html">YAML files</a> that specify your desired infrastructure—and then commit it to Git and push.

```bash theme={null}
git remote add platform <platform.sh@gitrepository>
git commit -m "Initial project"
git push -u platform master
```

The code pushed will create the Java application, a PostgreSQL instance, and, when it's done, will return an IP address to the service.
Let's test the application. To test a REST application, any HTTP client is suitable.

```bash theme={null}
curl -X POST -H "Content-Type: application/json"  -d '{"name":"JConfColombia","city":"Medellín","twitter":"@MedellinJug","link":"http://www.jconfcolombia.org/2019/index.html"}' https://<service.ip>/countries
curl https://<service.ip>/countries
#result output here
```

And just like that, we’ve created our first Eclipse MicroProfile application at Platform.sh! But is there any way to make this process easier?

## New Eclipse MicroProfile templates have arrived

We're proud to announce that four new Java templates have arrived, and these new templates are all Eclipse MicroProfile providers:

<img src="https://mintcdn.com/upsun-c9761871/XkTGutbb3_ExMu0d/images/posts/unknown/eclipse-microprofiles-gain-agility-release-faster/thorntail.webp?fit=max&auto=format&n=XkTGutbb3_ExMu0d&q=85&s=a8a4c444c754e1398dca3d547c0eb3c1" alt="Thorntail" width="601" height="480" data-path="images/posts/unknown/eclipse-microprofiles-gain-agility-release-faster/thorntail.webp" />

Thorntail offers an innovative approach to packaging and running Java EE applications by packaging them with just enough of the server runtime to "java -jar" your application. It’s MicroProfile compatible, too. And it’s all much, much cooler than that.

[https://thorntail.io/](https://thorntail.io/)

<img src="https://mintcdn.com/upsun-c9761871/OR9CPqO13fyi9LoK/images/posts/unknown/eclipse-microprofiles-gain-agility-release-faster/payara.webp?fit=max&auto=format&n=OR9CPqO13fyi9LoK&q=85&s=408875994a79228b8d78115f7199989e" alt="Payara Micro" width="686" height="416" data-path="images/posts/unknown/eclipse-microprofiles-gain-agility-release-faster/payara.webp" />

Payara Micro is the open-source, lightweight, middleware platform of choice for containerized Java EE (Jakarta EE) microservices deployments. Less than 70MB in size, Payara Micro requires no installation or configuration. And there’s no need for code rewrites, so you can build and deploy a fully working app within minutes.

[https://www.payara.fish/software/payara-server/payara-micro/](https://www.payara.fish/software/payara-server/payara-micro/)

<img src="https://mintcdn.com/upsun-c9761871/OR9CPqO13fyi9LoK/images/posts/unknown/eclipse-microprofiles-gain-agility-release-faster/kumuluz.webp?fit=max&auto=format&n=OR9CPqO13fyi9LoK&q=85&s=1fc0b4645620a97218cf85d0c64e84cb" alt="kumuluz" width="280" height="280" data-path="images/posts/unknown/eclipse-microprofiles-gain-agility-release-faster/kumuluz.webp" />

Develop microservices with Java EE/Jakarta EE technologies and extend them with Node.js, Go and other languages. Migrate existing Java EE applications to microservices and cloud-native architecture.

[https://ee.kumuluz.com/](https://ee.kumuluz.com/)

<img src="https://mintcdn.com/upsun-c9761871/XkTGutbb3_ExMu0d/images/posts/unknown/eclipse-microprofiles-gain-agility-release-faster/tomee.webp?fit=max&auto=format&n=XkTGutbb3_ExMu0d&q=85&s=20850e4e2f2bfdb3042509c4e0eff796" alt="Apache TomEE" width="137" height="98" data-path="images/posts/unknown/eclipse-microprofiles-gain-agility-release-faster/tomee.webp" />

Apache TomEE is the Eclipse MicroProfile flavor that uses several Apache Project flavors, including Apache Tomcat and Apache OpenWebBeans.

In this post, we took a dive into the fantastic world of Eclipse MicroProfiles. We defined the concept of microservices and how to integrate them with JPA. There are many more combinations coming to our [Java stack](https://upsun.com/java/) to make Java developers’ lives easier using the latest generation of PaaS. If you’re in any of the cities I’ll be visiting in my upcoming tour, please feel free to contact me on [Twitter](https://twitter.com/otaviojava); it'll be amazing to get together and talk about Java while drinking something tropical from coconuts. Hasta la vista!!!
