Skip to content

Commit 456712e

Browse files
committed
[WFLY-21081] Add a quickstart showing Jakarta Data
1 parent 0ea81c7 commit 456712e

File tree

25 files changed

+3020
-0
lines changed

25 files changed

+3020
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: WildFly todo-jakarta-data Quickstart CI
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened, ready_for_review]
6+
paths:
7+
- 'todo-jakarta-data/**'
8+
- '.github/workflows/quickstart_ci.yml'
9+
jobs:
10+
call-quickstart_ci:
11+
uses: ./.github/workflows/quickstart_ci.yml
12+
with:
13+
QUICKSTART_PATH: todo-jakarta-data
14+
TEST_PROVISIONED_SERVER: true
15+
TEST_OPENSHIFT: true
16+
MATRIX_OS: '"ubuntu-latest"'
17+
EXTRA_RUN_ARGS: '-DPOSTGRESQL_DATABASE=todos -DPOSTGRESQL_SERVICE_HOST=localhost -DPOSTGRESQL_SERVICE_PORT=5432 -DPOSTGRESQL_USER=todos -DPOSTGRESQL_PASSWORD=mysecretpassword -DPOSTGRESQL_DATASOURCE=ToDos'
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/sh
2+
docker run --name todo-jakarta-data-db -e POSTGRES_USER=todos -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgres
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
postgresql:
2+
primary:
3+
podSecurityContext:
4+
enabled: true
5+
fsGroup: 1001
6+
containerSecurityContext:
7+
enabled: true
8+
runAsUser: 1001
9+
runAsGroup: 0
10+
runAsNonRoot: true
11+
allowPrivilegeEscalation: false
12+
seccompProfile:
13+
type: RuntimeDefault
14+
capabilities:
15+
drop:
16+
- ALL
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
function installPrerequisites()
2+
{
3+
echo "Adding bitnami repository"
4+
helm repo add bitnami https://charts.bitnami.com/bitnami
5+
6+
helm dependency update charts/
7+
}
8+
9+
function helmInstall() {
10+
application="${1}"
11+
helm_set_arguments="$2"
12+
13+
# TODO https://issues.redhat.com/browse/WFLY-18574 remove this when persistence is working
14+
helm_set_arguments="${helm_set_arguments} -f ../.ci/openshift-ci/build-root/scripts/qs-overrides/todo-jakarta-data/ci.yaml"
15+
16+
helm install "${application}" charts/ --wait --timeout="${helm_install_timeout}" ${helm_set_arguments}
17+
echo $?
18+
}
19+
20+
21+
22+
function cleanPrerequisites()
23+
{
24+
helm uninstall "${application}"
25+
helm repo remove bitnami
26+
}
27+
28+
function getHelmSetVariablePrefix() {
29+
echo "wildfly."
30+
}
31+
32+
function helmInstallFailed() {
33+
echo "----> Getting status of all pods"
34+
kubectl get pods
35+
echo "----> Checking logs for postgres pod"
36+
kubectl logs todo-jakarta-data-postgresql-0
37+
echo "----> Checking events"
38+
kubectl get events
39+
}

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@
287287
<module>tasks-jsf</module>
288288
<module>temperature-converter</module>
289289
<module>todo-backend</module>
290+
<module>todo-jakarta-data</module>
290291
<module>thread-racing</module>
291292
<module>websocket-endpoint</module>
292293
<module>websocket-hello</module>
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
include::../shared-doc/attributes.adoc[]
2+
3+
= todo-jakata-data: quickstart for backend deployment on OpenShift
4+
:toc: left
5+
:icons: font
6+
:idprefix:
7+
:idseparator: -
8+
:keywords: openshift,galleon,helm
9+
:level: Intermediate
10+
:technologies: Jakarta Data, Jakarta REST, OpenShift, Galleon
11+
:openshift: true
12+
:archiveType: war
13+
:useHelmChartDir: true
14+
:helm-install-prerequisites-openshift: ../todo-backend/helm-install-prerequisites.adoc
15+
:helm-install-prerequisites-kubernetes: ../todo-backend/helm-install-prerequisites.adoc
16+
:helmSetWildFlyArgumentPrefix: wildfly.
17+
18+
[abstract]
19+
The `todo-jakarta-data` quickstart demonstrates how to implement a backend that exposes a HTTP API with Jakarta REST
20+
to manage a list of ToDo which are persisted in a database with Jakarta Data.
21+
It is very similar to the `todo-backend` quickstart but uses Jakarta Data instead of Jakarta Persistence to handle
22+
interaction with the backend database.
23+
24+
ifndef::ProductRelease[]
25+
This quickstart shows how to set up a local deployment of this backend as well as a deployment on OpenShift to connect
26+
to a PostgreSQL database also hosted on OpenShift.
27+
endif::[]
28+
ifdef::ProductRelease[]
29+
This quickstart shows how to deploy a {productName} application on OpenShift that connects
30+
to a PostgreSQL database also hosted on OpenShift.
31+
endif::[]
32+
33+
34+
== What is it?
35+
36+
The `todo-jakarta-data` quickstart demonstrates how to implement a backend that exposes a HTTP API with `Jakarta REST`
37+
to manage a list of ToDo which are persisted in a database with `Jakarta Data`.
38+
39+
* The backend exposes a HTTP API to manage a list of todos that complies with the specs defined at https://todobackend.com/specs/index.html[todobackend.com].
40+
* It requires a connection to a PostgreSQL database to persist the todos.
41+
ifndef::ProductRelease[]
42+
* It uses the Server Provisioning for local and cloud deployment
43+
endif::[]
44+
* It can be build with {productName} S2I images for cloud deployment
45+
ifndef::ProductRelease[]
46+
* It is deployed on OpenShift using the https://docs.wildfly.org/wildfly-charts/[Helm Chart for {productName}].
47+
endif::[]
48+
ifdef::ProductRelease[]
49+
* It is deployed on OpenShift using the https://jbossas.github.io/eap-charts//[Helm Chart for {productName}].
50+
endif::[]
51+
52+
This quickstart is the same as the `todo-backend` quickstart, but uses `Jakarta Data` for its persistence layer,
53+
instead of `Jakarta Persistence`.
54+
To see the differences, compare this quickstart's `ToDoRepository` interface with the `ToDoDAO` interface
55+
and `ToDoDAOImpl` class in `todo-backend`.
56+
57+
// Link to the quickstart source
58+
include::../shared-doc/view-the-source.adoc[leveloffset=+1]
59+
// System Requirements
60+
include::../shared-doc/system-requirements.adoc[leveloffset=+1]
61+
62+
== Architecture
63+
64+
=== Architecture with S2I
65+
66+
This backend is built using {productName} S2I Builder and Runtime images.
67+
68+
ifndef::ProductRelease[]
69+
When the image is built, `org.wildfly.plugins:wildfly-maven-plugin` plugin provisions the {productName} application server and all the feature packs it needs for its features.
70+
The layers are defined in the `pom.xml` file in the `<configuration>` section of the `org.wildfly.plugins:wildfly-maven-plugin` plugin:
71+
72+
[source,xml]
73+
----
74+
<layers>
75+
<layer>cloud-server</layer>
76+
<layer>jakarta-data</layer>
77+
<layer>postgresql-datasource</layer>
78+
</layers>
79+
----
80+
endif::[]
81+
82+
ifdef::ProductRelease[]
83+
When the image is built, `org.jboss.eap.plugins:eap-maven-plugin` plugin provisions the {productName} application server and all the feature packs it needs for its features.
84+
The layers are defined in the `pom.xml` file in the `<configuration>` section of the `org.jboss.eap.plugins:eap-maven-plugin` plugin:
85+
86+
[source,xml]
87+
----
88+
<layers>
89+
<layer>cloud-server</layer>
90+
<layer>jakarta-data</layer>
91+
<layer>postgresql-datasource</layer>
92+
</layers>
93+
----
94+
endif::[]
95+
96+
The `cloud-server` layer provides everything needed to run the backend on OpenShift. This also includes access to
97+
Jakarta EE APIs such as CDI, Jakarta REST, etc, along with the Hibernate support used by Jakarta Data.
98+
The `jakarta-data` layer provides the Jakarta Data API.
99+
These two layers come from the {productName} feature pack provided in the
100+
{productName} S2I builder image.
101+
102+
ifndef::ProductRelease[]
103+
The `postgresql-datasource` layer provides a JDBC driver and DataSource to connect to a PostgreSQL database. It is also provided by
104+
`org.wildfly:wildfly-datasources-galleon-pack` which is included in the WildFly S2I image.
105+
106+
The Git repository for this feature pack is hosted at https://github.com/wildfly-extras/wildfly-datasources-galleon-pack.
107+
It provides JDBC drivers and datasources for different databases but for this quickstart, we will only need the `postgresql-datasource`.
108+
endif::[]
109+
110+
ifdef::ProductRelease[]
111+
The `postgresql-datasource` layer provides a JDBC driver and DataSource to connect to a PostgreSQL database. It is also provided by
112+
the `org.jboss.eap:eap-datasources-galleon-pack` feature pack.
113+
114+
The Git repository for this feature pack is hosted at https://github.com/jbossas/eap-datasources-galleon-pack.
115+
It provides JDBC drivers and datasources for different databases but for this quickstart, we will only need the `postgresql-datasource`.
116+
endif::[]
117+
118+
=== Generation of the Jakarta Data Repository implementation
119+
120+
A key feature of Jakarta Data is it does not require application developers to write detailed code to write from and write to the backend database.
121+
Developers just need declare their entities (using Jakarta Persistence annotations like `@Entity`) and then write an repository interface that describes the desired persistence operations, using the Jakarta Data annotations.
122+
It is then up to the Jakarta Data implementation to generate an implementation of that interface.
123+
124+
WildFly's implementation of Jakarta Data, Hibernate Data Repositories, generates that implementation at application build time using an annotation processor run as part of compilation of the application.
125+
126+
This is handled in the project `pom.xml` by configuring the `maven-compiler-plugin`:
127+
128+
[source,xml]
129+
----
130+
<plugin>
131+
<groupId>org.apache.maven.plugins</groupId>
132+
<artifactId>maven-compiler-plugin</artifactId>
133+
<configuration>
134+
<annotationProcessorPaths>
135+
<path>
136+
<groupId>org.hibernate.orm</groupId>
137+
<artifactId>hibernate-jpamodelgen</artifactId>
138+
<version>${version.org.hibernate.jpamodelgen}</version>
139+
</path>
140+
</annotationProcessorPaths>
141+
</configuration>
142+
</plugin>
143+
----
144+
145+
=== Connection to the PostgreSQL database
146+
147+
ifndef::ProductRelease[]
148+
As mentioned, the JDBC drivers and datasource configuration that the backend uses to connect to the PostgreSQL database
149+
is provided by the `org.wildfly:wildfly-datasources-galleon-pack` feature pack.
150+
endif::[]
151+
ifdef::ProductRelease[]
152+
As mentioned, the JDBC drivers and datasource configuration that the backend uses to connect to the PostgreSQL database
153+
is provided by the `org.jboss.eap:eap-datasources-galleon-pack` feature pack.
154+
endif::[]
155+
156+
By default, it exposes a single datasource.
157+
In the backend, the name of this datasource is `ToDos` and is specified in the `persistence.xml` to configure Hibernate:
158+
159+
[source,xml]
160+
----
161+
<persistence-unit name="ToDos">
162+
<jta-data-source>java:jboss/datasources/ToDos</jta-data-source>
163+
</persistence-unit>
164+
----
165+
166+
At runtime, we only need a few environment variables to establish the connection from {productName} to the external PostgreSQL database:
167+
168+
* `POSTGRESQL_DATABASE` - the name of the database (that will be called `todos`)
169+
* `POSTGRESQL_SERVICE_HOST` - the host to connect to the database
170+
* `POSTGRESQL_SERVICE_PORT` - The port to connect to the database
171+
* `POSTGRESQL_USER` & `POSTGRESQL_PASSWORD` - the credentials to connect to the database
172+
* `POSTGRESQL_DATASOURCE` - The name of the datasource (as mentioned above, it will be `ToDos`)
173+
174+
=== Filters for Cross-Origin Resource Sharing (CORS)
175+
176+
The Web frontend for this quickstart uses JavaScript calls to query the backend's HTTP API.
177+
We must enable Cross-Origin Resource Sharing (CORS) filters in the `undertow` subsystem of {productName} to allow
178+
these HTTP requests to succeed.
179+
180+
ifdef::ProductRelease[]
181+
==== Configuration with {productName} S2I
182+
183+
As we use S2I to provision the server and build the application, we provide a CLI script that contains all the commands to create and configure the CORS filters in Undertow. This script is located in the `src/scripts/cors_filters.cli`.
184+
endif::[]
185+
186+
This script is executed at build time and will provide the following HTTP headers to enabled CORS:
187+
188+
* `Access-Control-Allow-Origin: *`
189+
* `Access-Control-Allow-Methods: GET, POST, OPTION, PUT, DELETE, PATCH`
190+
* `Access-Control-Allow-Headers: accept, authorization, content-type, x-requested-with`
191+
* `Access-Control-Allow-Credentials: true`
192+
* `Access-Control-Max-Age: 1`
193+
194+
By default, the backend accepts requests from any origin (`*`). This is only simplicity. It is possible to restrict
195+
the allowed origin using the environment variable `CORS_ORIGIN` at runtime.
196+
197+
== Run the Backend Locally
198+
199+
=== Package the Backend
200+
201+
The backend is packaged and deployed on a provisioned server:
202+
203+
[source,options="nowrap"]
204+
----
205+
$ mvn clean package
206+
----
207+
208+
=== Run a Local PostgreSQL Database
209+
210+
Before running the backend locally, we need to have a local PostgreSQL database that we can connect to.
211+
We use the `postgresql` docker image to create one:
212+
213+
[source,options="nowrap"]
214+
----
215+
$ docker run --name todo-backend-db -e POSTGRES_USER=todos -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 postgres
216+
----
217+
218+
This will create a database named `todos` that we can connect to on `localhost:5432` with the credentials `todos / mysecretpassword`.
219+
220+
=== Run the Application
221+
222+
With the PostgreSQL database running, we can start the backend by passing the required environment variables to connect to the database:
223+
224+
[source,options="nowrap"]
225+
----
226+
$ ./target/server/bin/standalone.sh -Denv.POSTGRESQL_DATABASE=todos -Denv.POSTGRESQL_DATASOURCE=ToDos -Denv.POSTGRESQL_SERVICE_HOST=localhost -Denv.POSTGRESQL_SERVICE_PORT=5432 -Denv.POSTGRESQL_USER=todos -Denv.POSTGRESQL_PASSWORD=mysecretpassword
227+
----
228+
229+
The backend is running, and we can use the HTTP API to manage a list of todos:
230+
231+
[source,options="nowrap"]
232+
----
233+
# get a list of todos
234+
$ curl http://localhost:8080/todo-jakarta-data
235+
[]
236+
237+
# create a todo with the title "This is my first todo item!"
238+
$ curl -X POST -H "Content-Type: application/json" -d '{"title": "This is my first todo item!"}' http://localhost:8080
239+
{"completed":false,"id":1,"order":0,"title":"This is my first todo item!","url":"https://localhost:8080/1"}%
240+
241+
# get a list of todos with the one that was just created
242+
$ curl http://localhost:8080/todo-jakarta-data
243+
[{"completed":false,"id":1,"order":0,"title":"This is my first todo item!","url":"https://localhost:8080/1"}]
244+
----
245+
246+
Please note that the quickstart includes integration tests, which may be executed using the following command:
247+
248+
[source,subs="attributes+",options="nowrap"]
249+
----
250+
$ mvn verify -Pintegration-testing
251+
----
252+
253+
//===========================================================
254+
// Openshift - START
255+
== Run the Backend on OpenShift
256+
257+
// OpenShift
258+
include::../shared-doc/build-and-run-the-quickstart-with-openshift.adoc[leveloffset=+1]
259+
include::../todo-backend/additional-readme-openshift.adoc[leveloffset=+1]
260+
// OpenShift - END
261+
//===========================================================
262+
263+
//===========================================================
264+
// Kubernetes - START
265+
ifndef::ProductRelease,EAPXPRelease[]
266+
== Run the Backend on Kubernetes
267+
268+
//Kubernetes
269+
include::../shared-doc/build-and-run-the-quickstart-with-kubernetes.adoc[leveloffset=+1]
270+
include::../todo-backend/additional-readme-kubernetes.adoc[leveloffset=+1]
271+
endif::[]
272+
// Kubernetes - END
273+
//===========================================================
274+
275+
276+
== Conclusion
277+
278+
This quickstart shows how the datasource feature pack provided by {productName} simplifies the deployment
279+
of a {productName} Jakarta EE backend on OpenShift to connect to an external database and exposes an HTTP API.
280+
281+
The use of a Server Provisioned deployment makes it seamless to move from a local deployment for development to a
282+
deployment on cloud platforms such as OpenShift and Kubernetes.

0 commit comments

Comments
 (0)