OpenLiberty / draft-guide-jakarta-faces

Other
0 stars 0 forks source link

// Copyright (c) 2024 IBM Corporation and others. // Licensed under Creative Commons Attribution-NoDerivatives // 4.0 International (CC BY-ND 4.0) // https://creativecommons.org/licenses/by-nd/4.0/ // // Contributors: // IBM Corporation // :projectid: jakarta-faces :page-layout: guide-multipane :page-duration: 25 minutes :page-releasedate: 2024-12-07 :page-essential: false :page-description: Learn how to build a dynamic web application using Jakarta Faces, Jakarta Contexts and Dependency Injection, and Jakarta Expression Language. :guide-author: Open Liberty :page-tags: ['jakarta-ee'] :page-related-guides: ['grpc-intro'] :page-permalink: /guides/{projectid} :imagesdir: /img/guide/{projectid} :page-seo-title: Building a dynamic web application using Jakarta Faces, Jakarta Contexts and Dependency Injection, and Jakarta Expression Language :page-seo-description: A getting started tutorial on how to build a dynamic web application using Jakarta Faces for the user interface (UI), Jakarta Contexts and Dependency Injection (CDI) for bean management, and Jakarta Expression Language (EL) for data binding and handling in Java. :common-includes: https://raw.githubusercontent.com/OpenLiberty/guides-common/prod :source-highlighter: prettify = Building a dynamic web application using Jakarta Faces

[.hidden] NOTE: This repository contains the guide documentation source. To view the guide in published form, view it on the https://openliberty.io/guides/{projectid}.html[Open Liberty website].

Learn how to build a dynamic web application using Jakarta Faces, Jakarta Contexts and Dependency Injection, and Jakarta Expression Language.

// ================================================================================================= // What you'll learn // =================================================================================================

== What you'll learn

You'll learn how to build a dynamic web application using Jakarta Faces for the user interface (UI), Jakarta Contexts and Dependency Injection (CDI) for managing backend logic, and Jakarta Expression Language (EL) for data binding.

Jakarta Faces is a powerful framework for building web applications with reusable UI components. It provides an API for managing component state, handling events, server-side validation, page navigation, and supports internationalization. The framework also offers tag libraries for adding components and binding them to server-side objects, simplifying UI development. Jakarta Contexts and Dependency Injection provides a flexible way to manage the lifecycle of backend beans, allowing managed beans to be automatically created and injected when needed. Jakarta Expression Language allows data binding between the UI and the backend, enabling componenets to display dynamic data and respond to user actions.

The application you will build in this guide is a dynamic web application that displays system load data on demand. Using Jakarta Faces for the UI, you'll create a table to show the system's cpu load and heap memory usage. You'll also learn how to use CDI to provide the system load data from a managed bean, and to use Jakarta Expression Language to bind this data to the UI components.

// ================================================================================================= // Getting started // ================================================================================================= [role='command'] include::{common-includes}/gitclone.adoc[]

=== Try what you'll build

The finish directory in the root of this guide contains the finished application. Give it a try before you proceed.

To try out the application, first go to the finish directory and run Maven with the liberty:run goal to build the application and deploy it to Open Liberty:

[role='command']

cd finish
mvn liberty:run

After you see the following message, your Liberty instance is ready.

[source, role="no_copy"]

The defaultServer server is ready to run a smarter planet.

Check out the web application at the http://localhost:9080/index.xhtml URL. Click the image:refresh.png[refresh icon, 18, 18] refresh button, located next to the table title, to update and display the latest system load data in the table.

After you are finished checking out the application, stop the Liberty instance by pressing CTRL+C in the command-line session where you ran Liberty. Alternatively, you can run the liberty:stop goal from the finish directory in another shell session:

[role='command']

mvn liberty:stop

// ================================================================================================= // Creating a static Jakarta Faces page // ================================================================================================= == Creating a static Jakarta Faces page

Start by creating a static Jakarta Faces page that displays an empty table for system load data, which serves as the starting point for your application.

Navigate to the start directory to begin.

When you run Open Liberty in https://openliberty.io/docs/latest/development-mode.html[dev mode^], dev mode listens for file changes and automatically recompiles and deploys your updates whenever you save a new change. Run the following goal to start Open Liberty in dev mode:

[role='command']

mvn liberty:dev

After you see the following message, your Liberty instance is ready in dev mode:

[source, role="no_copy"]


Dev mode holds your command-line session to listen for file changes. Open another command-line session to continue, or open the project in your editor.

[role="code_command hotspot file=0", subs="quotes"]

Create the index.xhtml file.

src/main/webapp/index.xhtml

index.xhtml [source, xhtml, linenums, role='code_column hide_tags=copyright']

include::staging/index.xhtml[]

footer.xhtml [source, xhtml, linenums, role='code_column hide_tags=copyright']

include::finish/src/main/webapp/WEB-INF/includes/footer.xhtml[]

In the [hotspot file=0]index.xhtml file, the [hotspot=xmlns file=0]xmlns attributes define the XML namespaces for various Jakarta Faces tag libraries. These namespaces allow the page to use Jakarta Faces tags for templating, creating UI components, and enabling core functionality like form submissions and data binding. For more information on the various tag libraries and their roles in Jakarta Faces, refer to the https://jakarta.ee/learn/docs/jakartaee-tutorial/current/web/faces-facelets/faces-facelets.html#_tag_libraries_supported_by_facelets[Jakarta Faces Tag Libraries Documentation^].

The [hotspot file=0]index.xhtml file combines standard HTML elements with Jakarta Faces components, providing both static layout and dynamic functionality. Standard HTML elements, like <div> and <section>, structure the page's layout. Jakarta Faces tags offer additional features beyond standard HTML, such as managing UI components, including resources, and binding data. For example, the [hotspot=outputStylesheet file=0]<h:outputStylesheet> tag loads a CSS file for styling, and the [hotspot=uiIncludeFooter file=0]<ui:include> tag incorporates reusable components, such as the provided [hotspot file=1]footer.xhtml file, to streamline maintenance and reuse across multiple pages.

At this point, the page defines a table that has no data entries. We'll add dynamic content in the following steps.

// ================================================================================================= // Mapping Faces Servlet // ================================================================================================= == Mapping Faces Servlet

Before you can access the Jakarta Faces page, you need to configure the Faces Servlet in your application. This servlet handles all requests for .xhtml pages and processes them using Jakarta Faces.

[role="code_command hotspot file=0", subs="quotes"]

Create the web.xml file.

src/main/webapp/WEB-INF/web.xml

web.xml [source, xml, linenums, role='code_column']

include::finish/src/main/webapp/WEB-INF/web.xml[]

The [hotspot=servlet file=0]<servlet> element defines the Faces Servlet that is responsible for processing requests for Jakarta Faces pages. The [hotspot=load-on-startup file=0]<load-on-startup> element with a value of 1 specifies that the servlet should be loaded and initialized when the application starts.

The [hotspot=servlet-mapping file=0]<servlet-mapping> element specifies which URL patterns are routed to the Faces Servlet. In this case, all URLs ending with .xhtml are mapped to be processed by Jakarta Faces. This ensures that any request for a .xhtml page is handled by the Faces Servlet, which manages the lifecycle of Jakarta Faces components, processes the page, and renders the output.

By configuring both the servlet and the servlet mapping, you're ensuring that Jakarta Faces pages are properly processed and delivered in response to user requests.

The [hotspot=project-stage file=0]jakarta.faces.PROJECT_STAGE context parameter determines the current stage of the application in its development lifecycle. Because it is currently set to [hotspot=project-stage-dev file=0]Development, you will see additional debugging information, including developer-friendly warning messages such as WARNING: Apache MyFaces Core is running in DEVELOPMENT mode. For more information about valid values and how to set the PROJECT_STAGE parameter, you can refer to the official https://jakarta.ee/specifications/faces/4.1/apidocs/jakarta.faces/jakarta/faces/application/projectstage[Jakarta Faces ProjectStage documentation^].

In your dev mode console, type r and press enter/return key to restart the Liberty instance so that Liberty reads the configuration changes. When you see the following message, your Liberty instance is ready in dev mode:

[source, role="no_copy"]


Check out the web application that you created at the http://localhost:9080/index.xhtml URL. You should see the static page with the system loads table displaying only the headers and no data.

// ================================================================================================= // Implementing backend logic with dependency injection // ================================================================================================= == Implementing backend logic with dependency injection

To provide system load data to your web application, you'll create a CDI-managed bean that retrieves information about the system's CPU load and memory usage. This bean will be accessible from the Jakarta Faces page and will supply the data to be displayed.

[role="code_command hotspot file=0", subs="quotes"]

Create the SystemLoadBean class.

src/main/java/io/openliberty/guides/bean/SystemLoadBean.java

SystemLoadBean.java [source, java, linenums, role='code_column hide_tags=copyright']

include::finish/src/main/java/io/openliberty/guides/bean/SystemLoadBean.java[]

Annotate the [hotspot file=0]SystemLoadBean class with a [hotspot=namedAnnotation file=0]@Named annotation to make it accessible in the Jakarta Faces pages under the name [hotspot=namedAnnotation file=0]systemLoadBean. Because the [hotspot=applicationScopedAnnotation file=0]SystemLoadBean bean is a CDI managed bean, a scope is necessary. An application scope is used in this example. To learn more about CDI, see the https://openliberty.io/guides/cdi-intro.html[Injecting dependencies into microservices^] guide.

The [hotspot=postConstruct file=0]@PostConstruct annotation ensures the [hotspot=init file=0]init() method runs after the [hotspot=systemLoadBean file=0]SystemLoadBean is initialized and dependencies are injected. The [hotspot=init file=0]init() method sets up any required resources for the bean's lifecyccle.

The [hotspot=fetchSystemLoadMethod file=0]fetchSystemLoad() method retrieves the current system load and memory usage, then updates the list of system load data.

The [hotspot=getSystemLoads file=0]getSystemLoads() method is a getter method for accessing the list of system load data from the Jakarta Faces page.

// ================================================================================================= // Binding data to the UI with expression language // ================================================================================================= == Binding data to the UI with expression language

Now that you have the backend logic implemented with CDI, you'll update the Jakarta Faces page to display the dynamic system load data by binding the UI components to the backend data using Jakarta Expression Language.

[role="code_command hotspot file=0", subs="quotes"]

Replace the index.xhtml file.

src/main/webapp/index.xhtml

index.xhtml [source, xhtml, linenums, role='code_column hide_tags=copyright']

include::finish/src/main/webapp/index.xhtml[]

// file 1 SystemLoadBean.java [source, java, linenums, role='code_column hide_tags=copyright']

include::finish/src/main/java/io/openliberty/guides/bean/SystemLoadBean.java[]

The [hotspot file=0]index.xhtml uses a [hotspot=commandButton file=0]<h:commandButton> tag to create the refresh button, where the action [hotspot=commandButtonAction file=0]#{systemLoadBean.fetchSystemLoad} invokes the [hotspot=fetchSystemLoadMethod file=1]fetchSystemLoad() method using Jakarta Expression Language when the button is clicked. This EL expression references the [hotspot=namedAnnotation file=1]systemLoadBean managed bean, triggering the method to update the system load data. The [hotspot=ajaxTag file=0]<f:ajax> tag ensures that the [hotspot=systemLoadForm file=0]systemLoadForm component is re-rendered without a full page reload.

The [hotspot=systemLoadsTable file=0]systemLoadsTable is populated using the [hotspot=uiRepeat file=0]<ui:repeat> tag, which iterates over the list of system load data provided by the [hotspot=namedAnnotation file=1]systemLoadBean. The EL expression [hotspot=dataBind file=0]#{systemLoadBean.systemLoads} calls the [hotspot=getSystemLoads file=1]getSystemLoads() method from the managed bean, binding the data to the UI components. If the systemLoadBean hasn't been created yet, it is automatically initialized at this point. For each entry, the time, cpuLoad, and memoryUsage fields are displayed using [hotspot=outputText1 hotspot=outputText2 hotspot=outputText3 file=0]<h:outputText>. The [hotspot=convertNumber1 hotspot=convertNumber2 file=0]<f:convertNumber> tag formats cpuLoad to seven decimal places and memoryUsage to two decimal places.

// ================================================================================================= // Running the application // ================================================================================================= == Running the application

server.xml [source, xml, linenums, role='code_column']

include::finish/src/main/liberty/config/server.xml[]

The required [hotspot=faces file=0]faces, [hotspot=expressionLanguage file=0]expressionLanguage, and [hotspot=cdi file=0]cdi features have been enabled for you in the Liberty server.xml configuration file.

Because you started the Open Liberty in dev mode at the beginning of the guide, so all the changes were automatically picked up.

Navigate to the http://localhost:9080/index.xhtml to view your web application. Click on the image:refresh.png[refresh icon, 18, 18] refresh button to trigger an update on the system loads table.

// ================================================================================================= // Testing the application // ================================================================================================= == Testing the application

While you can manually verify the web application by visiting http://localhost:9080/index.xhtml, automated tests are a much better approach because they are more reliable and trigger a failure if a breaking change is introduced. You can write unit tests for your CDI bean to ensure that the basic operations you implemented function correctly.

[role="code_command hotspot file=0", subs="quotes"]

Create the SystemLoadBeanTest class.

src/test/java/io/openliberty/guides/bean/SystemLoadBeanTest.java

SystemLoadBeanTest.java [source, java, linenums, role='code_column hide_tags=copyright']

include::finish/src/test/java/io/openliberty/guides/bean/SystemLoadBeanTest.java[]

The [hotspot=setUp file=0]setUp() method is annotated with the [hotspot=BeforeEach file=0]@BeforeEach annotation, indicating that it is run before each test case to ensure a clean state for each test execution. In this case, it creates a new instance of SystemLoadBean and manually calls the init() method to initialize the list of system load data before each test.

The [hotspot=testInitMethod file=0]testInitMethod() test case verifies that after initializing SystemLoadBean, the list of system load data is not null and contains at least one entry.

The [hotspot=testFetchSystemLoad file=0]testFetchSystemLoad() test case verifies that after calling the fetchSystemLoad() method, the size of the list of system load data increases by one.

The [hotspot=testDataIntegrity file=0]testDataIntegrity() test case verifies that each SystemLoadData entry in the list of system load data contains valid values for time, cpuLoad, and memoryUsage.

=== Running the tests

Because you started Open Liberty in dev mode, you can run the tests by pressing the enter/return key from the command-line session where you started dev mode.

You see the following output:

[source, role='no_copy']


T E S T S

Running io.openliberty.guides.bean.SystemLoadBeanTest Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.037 s -- in io.openliberty.guides.bean.SystemLoadBeanTest

Results:

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0

When you are done checking out the service, exit dev mode by pressing CTRL+C in the command-line session where you ran Liberty.

// ================================================================================================= // Great work! You're done! // =================================================================================================

== Great work! You're done!

You just built a dynamic web application on Open Liberty by using Jakarta Faces for the user interface, CDI for managing beans, and Jakarta Expression Language for binding and handling data.

include::{common-includes}/attribution.adoc[subs="attributes"]