> ## 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.

# Jakarta EE: Generation IV - a new hope

> Explore Jakarta EE & MongoDB on Platform.sh. Build enterprise apps with Java & NoSQL. Easy deployment with our tutorial.

export const PostMeta = ({data = {}}) => {
  const {author, date} = 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 (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",
      "linkedin": "https://www.linkedin.com/in/laurent-arnoud-861b44121/"
    },
    "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"
    },
    "maz-mohammadi": {
      "name": "Maz Mohammadi"
    },
    "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>}
    </div>;
};

<PostMeta data={{ author: ["otavio-santana"], date: "2019-07-30", image: "/images/posts/unknown/jakarta-ee-generation-iv-a-new-hope/jakarta-ee-generation-iv-a-new-hope.webp" }} />

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

Java Enterprise Edition (Java EE) is an umbrella that holds specifications and APIs with enterprise features like distributed computing and web services. Widely used in Java, Java EE runs on reference runtimes that can be microservices or application servers that handle transactions, security, scalability, concurrency, and management for the components it’s deploying.

Now that Enterprise Java has been standardized under the Eclipse Foundation—with the brand-new name Jakarta EE—there’s a new hope for Enterprise Java. This post will show a similar solution to Spring MVC with MongoDB on the Jakarta EE community side, with full support on Platform.sh.

For this project, we’ll need some assistance. To triumph over the imperial forces, these three projects can help us:

* [Eclipse Krazo](https://projects.eclipse.org/projects/ee4j.krazo). An implementation of action-based MVC specified by MVC 1.0 ([JSR-371](https://jcp.org/en/jsr/detail?id=371)). Eclipse Krazo builds on top of JAX-RS and currently contains support for RESTEasy, Jersey, and CXF with a well-defined SPI for other implementations.
* [Jakarta NoSQL](https://projects.eclipse.org/projects/ee4j.nosql). A framework to help developers create enterprise-grade applications using Java and NoSQL technologies. Jakarta NoSQL enables devs to create scalable applications while maintaining low coupling with the underlying NoSQL technology.
* [Bean Validation](https://beanvalidation.org/), [JSR 380](https://jcp.org/en/jsr/detail?id=380). A specification that creates its own annotations and validation, and ensures that the properties of a Class match specific criteria, using annotations such as `@NotNull`, `@Min`, and `@Max`.

## Show me the ~~force~~ code

The first step, as usual, is to create a Maven project, where we define the dependencies in the pom.xml file.

```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/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <groupId>org.superbiz</groupId>
 <artifactId>mvc-cxf</artifactId>
 <packaging>war</packaging>

 <name>OpenEJB :: Examples :: MVC (CXF-based)</name>
 <description>OpenEJB :: Web Examples :: MVC 1.0 - Jakarta NoSQL</description>
 <version>0.0.1-SNAPSHOT</version>
 <url>http://tomee.apache.org</url>

 <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <tomee.version>8.0.0-M3</tomee.version>
     <version.krazo>1.0.0-SNAPSHOT</version.krazo>
     <jnosql.version>0.1.0-SNAPSHOT</jnosql.version>
     <http.port>8888</http.port>
 </properties>

 <build>
     <finalName>ROOT</finalName>
     <plugins>
         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-compiler-plugin</artifactId>
             <version>3.5.1</version>
             <configuration>
                 <source>1.8</source>
                 <target>1.8</target>
             </configuration>
         </plugin>
         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-war-plugin</artifactId>
             <version>3.2.2</version>
             <configuration>
                 <failOnMissingWebXml>false</failOnMissingWebXml>
                 <packagingExcludes>pom.xml</packagingExcludes>
             </configuration>
         </plugin>
         <plugin>
             <groupId>org.apache.tomee.maven</groupId>
             <artifactId>tomee-maven-plugin</artifactId>
             <version>${tomee.version}</version>
             <configuration>
                 <tomeeHttpPort>${http.port}</tomeeHttpPort>
             </configuration>
         </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>

 <dependencies>
     <dependency>
         <groupId>jakarta.enterprise</groupId>
         <artifactId>jakarta.enterprise.cdi-api</artifactId>
         <version>2.0.1</version>
         <scope>provided</scope>
     </dependency>
     <dependency>
         <groupId>jakarta.ws.rs</groupId>
         <artifactId>jakarta.ws.rs-api</artifactId>
         <version>2.1.5</version>
         <scope>provided</scope>
     </dependency>
     <dependency>
         <groupId>jakarta.validation</groupId>
         <artifactId>jakarta.validation-api</artifactId>
         <version>2.0.1</version>
         <scope>provided</scope>
     </dependency>

     <dependency>
         <groupId>sh.platform</groupId>
         <artifactId>config</artifactId>
         <version>2.2.2-SNAPSHOT</version>
     </dependency>

     
     <dependency>
         <groupId>org.jnosql.artemis</groupId>
         <artifactId>artemis-document</artifactId>
         <version>${jnosql.version}</version>
     </dependency>
     <dependency>
         <groupId>org.jnosql.diana</groupId>
         <artifactId>mongodb-driver</artifactId>
         <version>${jnosql.version}</version>
     </dependency>

     
     <dependency>
         <groupId>org.eclipse.krazo</groupId>
         <artifactId>krazo-core</artifactId>
         <version>${version.krazo}</version>
     </dependency>
     <dependency>
         <groupId>org.eclipse.krazo</groupId>
         <artifactId>krazo-cxf</artifactId>
         <version>${version.krazo}</version>
     </dependency>
     <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>jstl</artifactId>
         <version>1.2</version>
     </dependency>

 </dependencies>
</project>
```

One crucial point to remember is that with the Jakarta EE specification, we can use several vendors without impacting the application. In this tutorial, we'll use Apache TomEE.

The next step is to define the user model. To make this all smoother, this user just has country, state, name, age, JUG, and description tags as information. So, two classes:

* The Person class: name, age, JUG, and any description
* The Address class: country and state

As with any simple register page, the user information comes through in a page form, so the MVC frameworks come with the FormParam annotation. This way, the developer can connect the form with any input field once the annotation matches the input tag exactly.

The MongoDB integration with the model is easy, too; JNoSQL has annotations that look like those of the JPA, so the developer defines the Entity, the Column, and the ID using the `Entity`, `Column`, and `Id` annotations, respectively.

One difference with MongoDB is that we can store the Address class information as a field instead of making it a relationship, as we usually do with SQL technology. So, we'll use the Address as a subdocument of the Person entity, which is faster because it reduces the number of joins and is more natural to query.

```java theme={null}
@Entity
public class Person {

 @Id
 @FormParam("id")
 @Convert(ObjectIdConverter.class)
 private String id;

 @FormParam("name")
 @NotEmpty(message = "can not be empty")
 @Size(min = 1, max = 20)
 @MvcBinding
 @Column
 private String name;

 @FormParam("age")
 @MvcBinding
 @Min(18)
 @Column
 private int age;

 @BeanParam
 @Valid
 @Column
 private Address address;

 @FormParam("server")
 @NotNull
 @MvcBinding
 @Column
 private String server;

 @FormParam("description")
 @NotEmpty(message = "can not be empty")
 @MvcBinding
 @Size(min = 10)
 @Column
 private String description;
}

@Entity
public class Address {

 @FormParam("country")
 @NotEmpty(message = "can not be empty")
 @MvcBinding
 @Column
 private String country;

 @FormParam("state")
 @NotEmpty(message = "can not be empty")
 @MvcBinding
 @Column
 private String state;
}
```

The repository is a [DDD](https://dzone.com/articles/ddd-part-i-introduction) pattern that acts as a mediator between the domain and data mapping layers using a collection-like interface for accessing domain objects. To create a Person repository, we need an interface that extends `Repository`. That’s all; JNoSQL will handle the implementation for you.

Here’s the method with a query whose whole point is to let the Java developer create any method using the JNoSQL convention. Then, the framework will implement it.

```java theme={null}
public interface PersonRepository extends Repository<Person, String> {

 Optional<Person> findById(Long id);

 List<Person> findAll();
}
```

The controller is the bridge to connect the view and the model. `Models` is a map of the name-to-model instances used by ViewEngine to process a view. `Viewable` is an abstraction that encapsulates information about a view. The other points are clear enough. Use the GET annotation to define access and POST to define the PATH that establishes a URL path.

```java theme={null}
import static java.util.stream.Collectors.toList;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;

import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import javax.inject.Inject;
import javax.mvc.Controller;
import javax.mvc.Models;
import javax.mvc.View;
import javax.mvc.binding.BindingResult;
import javax.validation.Valid;
import javax.validation.executable.ExecutableType;
import javax.validation.executable.ValidateOnExecution;
import javax.ws.rs.BeanParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.WebApplicationException;

import org.eclipse.krazo.engine.Viewable;

@Controller
@Path("mvc")
public class PersonController {

 private static final Supplier<WebApplicationException> NOT_FOUND_EXCEPTION = () -> new WebApplicationException(NOT_FOUND);

 @Inject
 private Models models;

 @Inject
 private Messages message;

 @Inject
 private Errors erros;

 @Inject
 private BindingResult bindingResult;

 @Inject
 private PersonRepository repository;

 @GET
 @Path("new")
 public Viewable newElement() {
     this.models.put("countries", getCountries());
     return new Viewable("insert.jsp");
 }

 @GET
 @Path("show")
 @View("list.jsp")
 public void list() {
     this.models.put("list", repository.findAll());
 }

 @POST
 @Path("add")
 @ValidateOnExecution(type = ExecutableType.NONE)
 public String add(@Valid @BeanParam Person person) {
     if (bindingResult.isFailed()) {

         this.getErrors();
         this.models.put("countries", getCountries());
         this.models.put("person", person);
         return "insert.jsp";

     }
     repository.save(person);
     message.setMessageRedirect("The " + person.getName() + " was successfully registered ! ");
     return "redirect:mvc/show";
 }

 @POST
 @Path("update")
 @ValidateOnExecution(type = ExecutableType.NONE)
 public String update(@Valid @BeanParam Person person) {
     if (bindingResult.isFailed()) {

         this.getErros();
         this.models.put("countries", getCountries());
         this.models.put("person", person);
         return "change.jsp";

     }
     repository.save(person);
     message.setMessageRedirect("The " + person.getName() + " was changed successfully ! ");
     return "redirect:mvc/show";
 }

 @GET
 @Path("update/{id}")
 public Viewable update(@PathParam("id") String id) {

     Optional<Person> person = repository.findById(id);
     this.models.put("person", person.orElseThrow(NOT_FOUND_EXCEPTION));
     this.models.put("countries", getCountries());
     return new Viewable("change.jsp", models);
 }

 @GET
 @Path("remove/{id}")
 public String delete(@PathParam("id") String id) {
     Optional<Person> person = repository.findById(id);
     repository.deleteById(person.map(Person::getId).orElseThrow(NOT_FOUND_EXCEPTION));
     message.setMessageRedirect("The register was successfully Excluded ! ");
     return "redirect:mvc/show";
 }

 private String getCountryName(String country) {
     return new Locale(country, country).getDisplayCountry(Locale.ENGLISH);
 }

 private List<String> getCountries() {
     return Arrays.stream(Locale.getISOCountries())
                  .map(country -> getCountryName(country))
                  .sorted((a, b) -> a.compareTo(b))
                  .collect(Collectors.toList());
 }

 private void getErros() {
     erros.setErrors(bindingResult.getAllErrors()
                                  .stream()
                                  .collect(toList()));
 }
}

@Named("message")
@RedirectScoped
public class Messages implements Serializable {

 private static final long serialVersionUID = 1L;

 private String messageRedirect;

 public String getMessageRedirect() {
     return messageRedirect;
 }

 public void setMessageRedirect(String messageRedirect) {
     this.messageRedirect = messageRedirect;
 }
}

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import javax.mvc.binding.ParamError;

@Named("error")
@RequestScoped
public class Errors {

 private List<ParamError> errors = new ArrayList<>();

 public void setErrors(List<ParamError> messages) {
     this.errors = messages;
 }

 public String getErrors() {
     return errors.stream()
                  .map(ParamError::getMessage)
                  .collect(Collectors.joining("<br>"));
 }

 public String getMessage(String param) {
     return errors.stream()
                  .filter(v -> v.getParamName().equals(param))
                  .map(ParamError::getMessage)
                  .findFirst()
                  .orElse("");
 }
}
```

The view/visualization layer will work with the classic JSP pages, which are very popular in the Java world. Note: there are a few view engines that accommodate several files such as asciidoc, HTML 5, peb, html, vm, [and so on](https://github.com/eclipse-ee4j/krazo/tree/master/ext).

```html theme={null}

<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>MVC 1.0 DEMO</title>
  </head>
  <body>
    <jsp:include page="/templates/menu.jsp"></jsp:include>

    <h1 align="center">Be welcome!</h1>

    <div align="center">
      <img
        src="${pageContext.request.contextPath}/resources/images/tomee.png"
        class="img-responsive"
        alt="templates"
      />
    </div>
    <br />
    <br />
    <jsp:include page="/templates/footer.jsp"></jsp:include>
  </body>
</html>

<%@ page contentType="text/html;charset=UTF-8" language="java"%> <%@ taglib
prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>MVC 1.0 DEMO</title>
  </head>
  <body>
    <div class="container">
      <c:if test="${error.errors.length() != 0}">
        <div class="row">
          <div class="col-md-12">
            <p class="alert alert-danger">${error.errors}</p>
          </div>
        </div>
      </c:if>
      <div class="row">
        <div class="col-md-4 col-md-offset-4">
          <form action="add" method="post">
            <h2>New register</h2>
            <div class="form-group">
              <label for="name">Name:</label>
              <input
                id="name"
                name="name"
                class="form-control"
                autofocus
                value="${person.name}"
              />
              <c:if
                test="${mvc.encoders.html(error.getMessage('name').length() != 0)}"
              >
                <div class="row">
                  <div class="col-md-12">
                    <p class="alert alert-danger">
                      ${mvc.encoders.html(error.getMessage("name"))}
                    </p>
                  </div>
                </div>
              </c:if>
            </div>
            <div class="form-group">
              <label for="age">Age:</label>
              <input
                type="number"
                id="age"
                name="age"
                class="form-control"
                value="${person.age}"
              />
              <c:if
                test="${mvc.encoders.html(error.getMessage('age').length() != 0)}"
              >
                <div class="row">
                  <div class="col-md-12">
                    <p class="alert alert-danger">
                      ${mvc.encoders.html(error.getMessage("age"))}
                    </p>
                  </div>
                </div>
              </c:if>
            </div>

            <div class="form-group">
              <label for="state">State:</label>
              <input
                type="text"
                id="state"
                name="state"
                class="form-control"
                value="${person.address.state}"
              />
              <c:if
                test="${mvc.encoders.html(error.getMessage('state').length() != 0)}"
              >
                <div class="row">
                  <div class="col-md-12">
                    <p class="alert alert-danger">
                      ${mvc.encoders.html(error.getMessage("state"))}
                    </p>
                  </div>
                </div>
              </c:if>
            </div>
            <div class="form-group">
              <label for="state">Application Server:</label> <br />
              <label class="radio-inline">
                <input
                  type="radio"
                  name="server"
                  value="TomEE"
                  class="form-check-input"
                />TomEE</label
              >
              <label class="radio-inline">
                <input
                  type="radio"
                  name="server"
                  value="Wildfly"
                  class="form-check-input"
                />Wildfly</label
              >
              <label class="radio-inline">
                <input
                  type="radio"
                  name="server"
                  value="Payara"
                  class="form-check-input"
                />Payara</label
              >

              <c:if
                test="${mvc.encoders.html(error.getMessage('server').length() != 0)}"
              >
                <div class="row">
                  <div class="col-md-12">
                    <p class="alert alert-danger">
                      ${mvc.encoders.html(error.getMessage("server"))}
                    </p>
                  </div>
                </div>
              </c:if>
            </div>
            <div class="form-group">
              <label for="country">Country:</label>
              <select id="country" name="country" class="form-control">
                <option value="${person.address.country}">
                  ${person.address.country}
                </option>
                <c:forEach var="countries" items="${countries}">
                  <option>${countries}</option>
                </c:forEach>
              </select>

              <c:if
                test="${mvc.encoders.html(error.getMessage('country').length() != 0)}"
              >
                <div class="row">
                  <div class="col-md-12">
                    <p class="alert alert-danger">
                      ${mvc.encoders.html(error.getMessage("country"))}
                    </p>
                  </div>
                </div>
              </c:if>
            </div>
            <div class="form-group">
              <label for="description">Description:</label>
              <textarea
                type=""
                id="description"
                name="description"
                class="form-control"
              >
${person.description}</textarea
              >
              <c:if
                test="${mvc.encoders.html(error.getMessage('description').length() != 0)}"
              >
                <div class="row">
                  <div class="col-md-12">
                    <p class="alert alert-danger">
                      ${mvc.encoders.html(error.getMessage("description"))}
                    </p>
                  </div>
                </div>
              </c:if>
            </div>
            <button class="btn btn-primary btn-block" type="submit">
              Register
            </button>
          </form>
        </div>
      </div>
    </div>
    <br />
    <br />
    <jsp:include page="/templates/footer.jsp"></jsp:include>
  </body>
</html>
```

## Platform.sh structure

The Java application is ready to go! The next step is to set 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 how each of these files configure the necessary containers in the virtual cluster:

* 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 you want to use on your [project](https://docs.platform.sh/configuration/services.html).
* 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 [services file](https://docs.platform.sh/configuration/services.html), which allows you to define a database, search engine, cache, and so on. In this project, we'll set [MongoDB](https://docs.platform.sh/configuration/services/mongodb.html) instead of [MySQL](https://docs.platform.sh/configuration/services/mysql.html).

```yaml theme={null}
database:
  type: mongodb:3.6
  disk: 1024
```

## Platform.sh and Java

For the database, we need to define where the connection comes from. Platform.sh provides connection credentials to services using the `PLATFORM_RELATIONSHIPS` environmental variable.

```java theme={null}
import com.mongodb.MongoClient;
import jakarta.nosql.document.DocumentCollectionManager;
import org.jnosql.diana.mongodb.document.MongoDBDocumentCollectionManagerFactory;
import org.jnosql.diana.mongodb.document.MongoDBDocumentConfiguration;
import sh.platform.config.Config;
import sh.platform.config.MongoDB;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;

@ApplicationScoped
public class PersonProducer {

 @Produces
 @ApplicationScoped
 public DocumentCollectionManager getDocumentCollectionManager() {
     Config config = new Config();
     final MongoDB mongo = config.getCredential("mongodb", MongoDB::new);
     final MongoClient mongoClient = mongo.get();
     MongoDBDocumentConfiguration configuration = new MongoDBDocumentConfiguration();
     MongoDBDocumentCollectionManagerFactory factory = configuration.get(mongoClient);
     return factory.get(mongo.getDatabase());
 }

 public void close(@Disposes DocumentCollectionManager manager) {
     manager.close();
 }
}
```

The [Java Config Reader](https://github.com/platformsh/config-reader-java) library offers classes that will read the information from the variable and return an object that represents the services, like a DataSource for MySQL, PostgreSQL, MongoClient, Redis, or any other services you’ve defined in `.platform/services.yaml`!

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

* Create a new [free trial account](https://auth.api.platform.sh/register?trial_type=general).
* Sign up with a new user 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.
* Add a new project by selecting “Create a blank project” from the template list after you have named it.

After this wizard, Platform.sh will provision the whole infrastructure for you, providing your project a remote Git repository. The Platform.sh Git-driven infrastructure means it will automatically manage everything your application needs to push it to the master remote repository. After you set up your [SSH keys](https://docs.platform.sh/development/ssh.html#using-ssh-keys), you only need to write your code—including a few [YAML files](https://docs.platform.sh/overview/yaml/what-is-yaml.html) that [specify](/posts/unknown/java-hello-world-at-platform.sh) your desired infrastructure—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
```

Code pushed will create both the Java application and a MongoDB instance, and, when it's done, will return an IP address to the service.

In this tutorial, we showed the new hope for Java Enterprise with Jakarta EE. We made an [application using APIs from Java EE/Jakarta EE](https://github.com/platformsh/java-quick-start/tree/master/jakarta/tomee-mongodb) specification and put it on the cloud easily with Platform.sh. The Java community, including several organizations like the Eclipse Foundation, is tight-knit and represents a brave new technology throughout the galaxy.
