DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Enterprise AI Trend Report: Gain insights on ethical AI, MLOps, generative AI, large language models, and much more.

2024 Cloud survey: Share your insights on microservices, containers, K8s, CI/CD, and DevOps (+ enter a $750 raffle!) for our Trend Reports.

PostgreSQL: Learn about the open-source RDBMS' advanced capabilities, core components, common commands and functions, and general DBA tasks.

AI Automation Essentials. Check out the latest Refcard on all things AI automation, including model training, data security, and more.

Related

  • Using Identity-Based Policies With Amazon DynamoDB
  • Performance Optimization in Agile IoT Cloud Applications: Leveraging Grafana and Similar Tools
  • Optimizing Cost and Performance in AWS EC2 Backup
  • Cloud Applications: A Step-By-Step Development Process

Trending

  • Modern Python: Patterns, Features, and Strategies for Writing Efficient Code (Part 1)
  • JUnit, 4, 5, Jupiter, Vintage
  • Securing Cloud Infrastructure: Leveraging Key Management Technologies
  • Using My New Raspberry Pi To Run an Existing GitHub Action
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. AWS: Pushing Jakarta EE Full Platform Applications to the Cloud

AWS: Pushing Jakarta EE Full Platform Applications to the Cloud

In this article, readers will learn how to deploy more complex Jakarta EE applications as serverless services with AWS Fargate.

By 
Nicolas Duminil user avatar
Nicolas Duminil
DZone Core CORE ·
Apr. 20, 23 · Analysis
Like (5)
Save
Tweet
Share
7.3K Views

Join the DZone community and get the full member experience.

Join For Free

In a previous blog post, I demonstrated how to deploy Jakarta EE applications as serverless services with AWS Fargate. The Jakarta EE application I used as an example in the previously mentioned post was a basic one. Now, it's time to go further and see what it takes to do the same thing with more complex Jakarta EE applications involving a wide variety of components like RESTful, CDI, Enterprise Beans, and Server Pages.

Jakarta EE Full Platform is the superset of what has been commonly called "enterprise Java." While not officially coined as a Jakarta EE profile, such as the Core Profile or the Web Profile, the Full Platform includes the whole bunch of the Jakarta EE specifications implementations, from the most essential ones, like Servlet, to the most uncharted ones, like RMI or SAAJ.

In this article, we'll be using Jakarta EE 10 and its implementation by WildFly 27.0.1.Final release.

The Project

The project used in order to illustrate this blog ticket may be found here. It consists of a Maven-based Jakarta EE 10 sample application for items management involving the following components:

  • a RESTful 3.1 endpoint that aims at CRUD-ing items;
  • a CDI 4.0 component on the domain layer;
  • an Enterprise Bean Lite 4.0 component implementing the facade design pattern;
  • a Faces 4.0 front-end providing an easy way to test the application.

I tried to carefully choose these components in order to have as much as a reasonable variety of Jakarta EE implementations, such that to justify the deployment of a Full Platform server like WildFly. And while some analysts still think that WildFly, like all the existent Jakarta EE implementations, is a heavy platform, I'll demonstrate how fast and easy it can be deployed on AWS in a Fargate serverless context.

But, before going into infrastructure and deployment considerations, let's first have a detailed analysis of each project's layer.

The Faces 4.0 Front End

Our front-end layer consists of an XHTML-based view using Facelets. As the reader might know, Jakarta EE Faces and JSF (Java Server Faces) were historically used to support two view technologies: JSP (Java Server Pages) and Facelets. The new 4.0 release is deprecating the JSP support, and it adds a new programmatic one based on the jakarta.faces.view.facelets.Facelet interface. While this new API might be practical for developers who prefer having a pure Java view definition, it always has been considered that a clean software architecture has to separate the business logic from the visual presentation, including using a different declarative notation, like Facelets. That's for this reason that, in this example, I didn't give way to the temptation of using this new Faces API, but I kept using the old good Facelets notation and one of its most useful features: the templating. 

The listing below shows the file template.xhtml and the way that it defines our Facelets template:

HTML
 
Default Content
" data-lang="text/html">
<html xmlns:ui="jakarta.faces.facelets"	xmlns:h="jakarta.faces.html">
  <h:head>
	<h:outputStylesheet name="style.css"/>
  </h:head>
  <h:body>
    <div class="page">
      <div class="header">
        <ui:include src="header.xhtml"/>
      </div>
      <div class="content">
        <ui:insert name="content">Default Content</ui:insert>
      </div>
      <div class="footer">
        <ui:include src="footer.xhtml"/>
      </div>
    </div>
  </h:body>
</html>


As we can see, our HTML page is divided into three regions, a header, content, and a footer. Each region is defined in a separate .xhtml file. Don't hesitate to open the files named header.xhtmland, respectively, footer.xhtml located in the src/main/webapp/resources/templates directory and to see how each one of these regions are defined.

The region named content is defined in the index.xhtml file, located in the src/main/webapp directory. 

HTML
 
<html
  xmlns:ui="jakarta.faces.facelets"
  xmlns:f="jakarta.faces.core"
  xmlns:h="jakarta.faces.html"
  xmlns:mc="jakarta.faces.composite/mycomponents">
  <body>
    <ui:composition template="/templates/template.xhtml">
      <ui:define name="content">
        <mc:item key = "#{item.key}" value ="#{item.value}" actionListener="#{itemManager.save()}"/>
        <h:form id="items">
          <h:dataTable value="#{itemManager.itemList}" var="it" styleClass="table" headerClass="table-header" rowClasses="table-odd-row,table-even-row">
            <h:column>
              <f:facet name="header">Key</f:facet>
              <h:outputText value="#{it.key}"/>
            </h:column>
            <h:column>
              <f:facet name="header">Value</f:facet>
              <h:outputText value="#{it.value}"/>
            </h:column>
            <h:column>
              <f:facet name="header">Delete</f:facet>
              <h:commandButton actionListener="#{itemManager.delete(it)}" styleClass="buttons" value="Delete"/>
            </h:column>
          </h:dataTable>
        </h:form>
      </ui:define>
    </ui:composition>
  </body>
</html>


The ui:composition and ui:define tags in the listing above state that here we're defining the element named content in the template.xhtml file. The namespace jakarta.faces.composite is a new feature of the JSF 2.3, included in Faces 4.0 as well, and aims at defining composite components. The tag mc:item in the listing below references such a composite component, while its definition is shown in the file item.xhtml located in the src/main/webapp/resources/mycomponents directory.

HTML
 
<html xmlns:cc="jakarta.faces.composite" xmlns:h="jakarta.faces.html">
  <cc:interface>
    <cc:attribute name="key"/>
    <cc:attribute name="value"/>
    <cc:attribute name="actionListener" method-signature="void action(javax.faces.event.Event)" targets="form:saveButton"/>
  </cc:interface>
  <cc:implementation>
    <h:form id="form">
      <h:panelGrid columns="2">
        <h:outputText value="Key:" for="inputTextKey"/>
        <h:inputText value="#{cc.attrs.key}" id="inputTextKey"/>
        <h:outputText value="Value:" for="inputTextValue"/>
        <h:inputText value="#{cc.attrs.value}" id="inputTextValue"/>
      </h:panelGrid>
      <h:commandButton id="saveButton" value="Save"/>
      <h:messages errorStyle="color: red" infoStyle="color: green" globalOnly="true" />
    </h:form>
  </cc:implementation>
</html>


Our composite component here above defines a form consisting of a grid with two columns and a command button. This simple interface allows us to CRUD items.

At this point of the presentation, I have to apologize to the readers for the poor styling of the visual part of the project. As a matter of fact, I have to admit that I completely lack any graphical or visual designing skills. However, I tried to style them as much as I could the presentation and the maximum I could come to is in the file style.css located in the src/main/webapp/resource directory. Please don't hesitate to adapt and customize this file such that the visual presentation of the front end becomes more attractive.

The CDI 4.0 Component Layer

The listing below shows the class ItemManager which instance is driving the items CRUD operations:

Java
 
@Model
public class ItemManager
{
  @Inject
  private ItemFacade itemFacade;
  @Produces
  @Named
  private Item item = new Item();

  @Produces
  @Named
  public List<Item> getItemList()
  {
    return itemFacade.getItemList();
  }

  public void save()
  {
    itemFacade.addToList(item);
    FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Added item " + item.getKey(), null);
    FacesContext.getCurrentInstance().addMessage(null, facesMsg);
    item = new Item();
  }

  public void delete(Item item)
  {
    itemFacade.removeFromList(item);
  }

  public boolean isFull()
  {
    return (itemFacade.getItemList().size() > 0);
  }
}


Notice how annotations like @Produces and @Named are used in the listing above in order to produce new bean instances and, respectively, to export them to EL (Expression Language), such that to be used in the view component in expressions like #{item.key} and #{item.value} or #{itemList}.

The Enterprise Bean 4.0 Component Layer

The ItemManager CDI bean is injecting an instance of the ItemFacade, which is the effective service performing the items CRUD operations. This service is implemented as a stateless session Enterprise Bean, as shown by the listing below:

Java
 
@Singleton
@Named
public class ItemFacade implements Serializable
{
  private List<Item> itemList;

  public ItemFacade()
  {
  }

  @PostConstruct
  public void postConstruct()
  {
    itemList = new ArrayList<Item>();
  }

  public List<Item> getItemList()
  {
    return itemList;
  }

  public void setItemList(List<Item> itemList)
  {
    this.itemList = itemList;
  }

  public int addToList(Item item)
  {
    itemList.add(item);
    return itemList.size();
  }

  public int addToList(String key, String value)
  {
    itemList.add(new Item(key, value));
    return itemList.size();
  }

  public int removeFromList(Item item)
  {
    itemList.remove(item);
    return itemList.size();
  }

  public int removeFromList(int idx)
  {
    itemList.remove(idx);
    return itemList.size();
  }

  public void removeAll()
  {
    itemList.clear();
  }
}


We could imagine that the facade component would perform some persistence operations like storing the items in a database or sending JMS messages to a message broker. In our simple example, we only store them in a collection.

The RESTful 3.1 Endpoint

This endpoint exposes the operations required for CRUD items, as shown in the table below:               

Resource HTTP Request Action Java Method
/items/list GET Get the full list of the currently registered items public List<Item> getItems()
/items POST Create a new item public Response createItem()
/items/{id} GET Get the item identified by its key, passed as a path parameter public Item getItemByPathParam()
/items GET Get the item identified by its key, passed as a query parameter public Item getItemByQueryId()
/items/{id} DELETE Remove the item identified by its key public Response removeItem()

Nothing new here. This is just a very classical RESTful endpoint, as we use to see often.

Testing Locally

Before deploying to the cloud, we need to make sure first that our application works as expected. As it isn't worth deploying it as long as it doesn't work. Our pom.xml file defines several profiles, as follows:

  • arq-managed: This profile defines an Arquillian integration test in order to deploy our WAR on a managed WildFly server;
  • arq-remote: This profile defines an Arquillian integration test in order to deploy our WAR on a managed WildFly server;
  • arq-docker: This profile defines an Arquillian integration test in order to deploy our WAR on a WildFly server running in a Docker container;
  • docker: This profile is useful to test the Faces front-end in an interactive way. It doesn't use Arquillian, but it only deploys the WAR on a WildFly application server running in a Docker container, giving you the possibility to use your preferred browser and to perform manual tests;
  • aws: This profile allows us to execute integration tests without Arquillian once that the application has been deployed on the cloud.
For example, in order to execute Arquillian integration tests in a managed WildFly container, execute the following command:
Shell
 
$ mvn -Parq-managed clean package verify


A WildFly server will be downloaded and executed locally, and Arquillian will deploy in it the WAR before executing the integration tests, which should succeed. In the same way, if you want to perform tests in a WildFly server running in a Docker container, you may execute the following command:

Shell
 
$ mvn -Parq-docker clean package verify


If you want to perform manual tests without Arquillian, you need to do the following:

Shell
 
$ mvn clean package docker:build docker:run


This will start a Docker container running a WildFly server, and you will be able to connect to this URL in order to check if your Faces front end works.

Pushing to the Cloud

In a previous blog ticket, I've already investigated the use of the AWS Fargate serverless service as an efficient way to deploy Jakarta EE applications on the cloud. It is this same service that we'll be using here to deploy the WildFly application server, together with our Jakarta EE 10 application.  Assuming that copilot is already installed on your box, the only thing to do is to run the following command:

Shell
 
$ copilot init --app duke-app --name duke --type "Load Balanced Web Service" --dockerfile ./DockerfileWithWAR --port 8080 --deploy


The execution of this command might take some time, depending on your bandwidth. Once finished, you'll see a message similar to the following:

 
- You can access your service at http://duke-Publi-V5NKFZU77FWB-1356331722.eu-west-3.elb.amazonaws.com over the internet.


Now you can connect to this URL and check whether the Faces front-end works as was the case when tested locally. If you prefer to execute integration tests, you can use the aws profile, as follows:

Shell
 
$ mvn -Paws clean package verify


Don't forget to clean up your environment as soon as you've finished playing:

Shell
 
$ copilot app delete


Again, the execution of this command might take some time.

Enjoy!


AWS applications WildFly Cloud

Opinions expressed by DZone contributors are their own.

Related

  • Using Identity-Based Policies With Amazon DynamoDB
  • Performance Optimization in Agile IoT Cloud Applications: Leveraging Grafana and Similar Tools
  • Optimizing Cost and Performance in AWS EC2 Backup
  • Cloud Applications: A Step-By-Step Development Process

Partner Resources


Comments

ABOUT US

  • About DZone
  • Send feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: