diff --git a/README.adoc b/README.adoc index 761fd5578c..e5da8c73c8 100644 --- a/README.adoc +++ b/README.adoc @@ -504,6 +504,7 @@ NOTE: Some of these quickstarts use the H2 database included with WildFly. It is | link:tasks-rs/README{outfilesuffix}[tasks-rs]|JPA, JAX-RS | The `tasks-rs` quickstart demonstrates how to implement a JAX-RS service that uses JPA persistence. | Intermediate | _none_ | link:temperature-converter/README{outfilesuffix}[temperature-converter]|CDI, JSF, SLSB EJB | The `temperature-converter` quickstart does temperature conversion using an EJB Stateless Session Bean (SLSB), CDI, and a JSF front-end client. | Beginner | _none_ | link:thread-racing/README{outfilesuffix}[thread-racing]|Batch, CDI, EE Concurrency, JAX-RS, JMS, JPA, JSON, Web Sockets | A thread racing web application that demonstrates technologies introduced or updated in the latest Jakarta EE specification. | Beginner | _none_ +| link:todo-backend/README{outfilesuffix}[todo-backend]|JPA, JAX-RS, OpenShift, Galleon | The `todo-backend` quickstart demonstrates how to deploy a backend on OpenShift that exposes a HTTP API with JAX-RS and persists data in an external database with JPA | Intermediate | _none_ | link:websocket-client/README{outfilesuffix}[websocket-client]|Web Socket, CDI Events, JSON, SSL | Demonstrates use of a Javascript WebSocket client, WebSocket configuration, programmatic binding, and secure WebSocket. | Intermediate | _none_ | link:websocket-endpoint/README{outfilesuffix}[websocket-endpoint]|CDI, WebSocket, JSON-P | Shows how to use WebSockets with JSON to broadcast information to all open WebSocket sessions in {productName}. | Beginner | _none_ | link:websocket-hello/README{outfilesuffix}[websocket-hello]|WebSocket, CDI, JSF | The `websocket-hello` quickstart demonstrates how to create a simple WebSocket application. | Beginner | _none_ diff --git a/pom.xml b/pom.xml index a448980306..bc115782f5 100644 --- a/pom.xml +++ b/pom.xml @@ -80,6 +80,9 @@ 24.0.0.Beta1-SNAPSHOT 24.0.0.Beta1-SNAPSHOT + 23.0.0.Final + 4.0.0.Final + 1.2.0.Beta1 5.4 @@ -448,6 +451,7 @@ tasks-jsf tasks-rs temperature-converter + todo-backend thread-racing websocket-client websocket-endpoint diff --git a/todo-backend/README.adoc b/todo-backend/README.adoc new file mode 100644 index 0000000000..d8cf949367 --- /dev/null +++ b/todo-backend/README.adoc @@ -0,0 +1,304 @@ +include::../shared-doc/attributes.adoc[] + += todo-backend: quickstart for backend deployment on OpenShift +:toc: left +:icons: font +:idprefix: +:idseparator: - +:keywords: openshift,galleon,helm +:level: Intermediate +:technologies: JPA, JAX-RS, OpenShift, Galleon + +[abstract] +The `todo-backend` quickstart demonstrates how to implement a backend that exposes a HTTP API with JAX-RS +to manage a list of ToDo which are persisted in a database with JPA. + +This quickstart shows how to setup a local deployment of this backend as well as a deployment on OpenShift to connect +to a PostgreSQL database also hosted on OpenShift. + + +== What is it? + +The `todo-back` quickstart demonstrates how to implement a backend that exposes a HTTP API with `JAX-RS` +to manage a list of ToDo which are persisted in a database with `JPA`. + +* 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]. +* It requires a connection to a PostgreSQL database to persist the todos. +* It uses the Bootable Jar for local and cloud deployment +* It is deployed on OpenShift using the https://docs.wildfly.org/wildfly-charts/[Helm Chart for ${productName}]. + +== Architecture + +// System Requirements +include::../shared-doc/system-requirements.adoc[leveloffset=+1] + +This backend is built and deployed as Bootable Jar that provisions the {productName} application server and all the feature packs it needs for its features. +The layers are defined in the `pom.xml` file in the `` section of the `org.wildfly.plugins:wildfly-jar-maven-plugin` plugin: + +[source,xml] +---- + + cloud-server + postgresql-datasource + ejb + +---- + +The `cloud-server` and `ejb` layers provides everything need to run the backend on OpenShift. This also includes access to +Jakarta EE APIs such as CDI, JAX-RS, JPA, etc. These two layers comes from the {productName} feature pack provided by the Bootable Jar plugin: + +[source,xml] +---- + + wildfly@maven(org.jboss.universe:community-universe)#${version.server.bootable-jar} + +---- + +The `postgresql-datasource` layer provides a JDBC driver and DataSource to connect to a PostgreSQL database. It is not provided +by the {productName} feature pack but by an extra feature pack: + +[source,xml] +---- + + org.wildfly + wildfly-datasources-galleon-pack + ${version.wildfly-datasources-galleon-pack} + +---- + +The Git repository for this feature pack is hosted at https://github.com/wildfly-extras/wildfly-datasources-galleon-pack. +It provides JDBC drivers and datasources for different databases but for this quickstart, we will only need the `postgresql-datasource`. + +=== Connection to the PostgreSQL database + +As mentioned, the JDBC drivers and datasource configuration that the backend uses to connect to the PostgreSQL database +is provided by the `org.wildfly:wildfly-datasources-galleon-pack` feature pack. By default, it exposes a single datasource. +In the backend, the name of this datasource is `ToDos` and is specified in the `persistence.xml` to configure JPA: + +[source,xml] +---- + + java:jboss/datasources/ToDos + +---- + +At runtime, we only need a few environment variables to establish the connection from {productName} to the external PostgreSQL database: + +* `POSTGRESQL_DATABASE` - the name of the database (that will be called `todos`) +* `POSTGRESQL_SERVICE_HOST` - the host to connect to the database +* `POSTGRESQL_SERVICE_PORT` - The port to connecto to the database +* `POSTGRESQL_USER` & `POSTGRESQL_PASSWORD` - the credentials to connect to the database +* `POSTGRESQL_DATASOURCE` - The name of the datasourcs (as mentioned above, it will be `ToDos`) + +=== Filters for Cross-Origin Resource Sharing (CORS) + +The Web frontend for this quickstart uses JavaScript calls to query the backend's HTTP API. +We must enable Cross-Origin Resource Sharing (CORS) filters in the `undertow` subsystem of {productName}. + +As we use Bootable Jar to 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`. + +This script is executed at build time and will provide the following HTTP headers to enabled CORS: + +* `Access-Control-Allow-Origin: *` +* `Access-Control-Allow-Methods: GET, POST, OPTION, PUT, DELETE, PATCH` +* `Access-Control-Allow-Headers: accept, authorization, content-type, x-requested-with` +* `Access-Control-Allow-Credentials: true` +* `Access-Control-Max-Age: 1` + +By default, the backend accepts requests from any origin (`*``). This is only simplicity. It is possible to restrict +the allowed origin using the environment variable `CORS_ORIGIN` at runtime. + +== Package the backend as a Bootable Jar + +The backend is packaged as a Bootable Jar and configured to be deployable on OpenShift with the Maven Profile `bootable-jar-openshift` which is active +by default: + +[source,options="nowrap"] +---- +$ mvn clean package +---- + +== Run the backend locally + +=== Local PostgreSQL database + +Before running the backend locally, we need to have a local PostgreSQL database that we can connect to. +We use the `postgresql` docker image to create one: + +[source,options="nowrap"] +---- +$ docker run --name todos-db \ + -e POSTGRES_USER=todos \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 5432:5432 \ + postgres +---- + +This will create a database named `todos-db` that we can connect to on `localhost:5432` with the credentials `todos / mysecretpassword`. + +=== Run the backend + +With the PostgreSQL database running, we can start the backend by passing the required environment variables to connect to the database: + +[source,options="nowrap"] +---- +$ POSTGRESQL_DATABASE=todos \ + POSTGRESQL_SERVICE_HOST=localhost \ + POSTGRESQL_SERVICE_PORT=5432 \ + POSTGRESQL_USER=todos \ + POSTGRESQL_PASSWORD=mysecretpassword \ + POSTGRESQL_DATASOURCE=ToDos \ + java -jar target/todo-backend-bootable.jar +... +14:41:58,111 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0010: Deployed "todo-backend.war" (runtime-name : "ROOT.war") +... +---- + +The backend is running, and we can use the HTTP API to manage a list of todos: + +[source,options="nowrap"] +---- +# get a list of todos +$ curl http://localhost:8080 +[] + +# create a todo with the title "This is my first todo item!" +$ curl -X POST -H "Content-Type: application/json" -d '{"title": "This is my first todo item!"}' http://localhost:8080/ +{"completed":false,"id":1,"order":0,"title":"This is my first todo item!","url":"https://localhost:8080/1"}% + +# get a list of todos with the one that was just created +$ curl http://localhost:8080 +[{"completed":false,"id":1,"order":0,"title":"This is my first todo item!","url":"https://localhost:8080/1"} +---- + +== Run the Backend on OpenShift + +=== Prerequisites + +* You must be logged in OpenShift and have an `oc` client to connect to OpenShift +* https://helm.sh[Helm] must be installed to deploy the backend on OpenShift. + +Once you have installed Helm, you need to add the repository that provides Helm Charts for {productName}: + +[source,options="nowrap"] +---- +$ helm repo add wildfly https://docs.wildfly.org/wildfly-charts/ +"wildfly" has been added to your repositories +$ helm search repo wildfly +NAME CHART VERSION APP VERSION DESCRIPTION +wildfly/wildfly 1.1.0 22.0 Build and Deploy WildFly applications on OpenShift +---- + +=== Deploy a PostgreSQL Database on OpenShift + +[source,options="nowrap"] +---- +$ oc new-app postgresql-ephemeral \ + -p DATABASE_SERVICE_NAME=todos-db \ + -p POSTGRESQL_DATABASE=todos +---- + +This will create a PostgreSQL database named `todos` on OpenShift that can be accessed on the port `5432` on the service `todos-db`. +We don't need to copy the credentials to connect to the database as we will retrieve them later using the `todos-db` secret that was created +when the database is deployed. + +=== Build and Deploy the Backend on OpenShift + +The backend will be built and deployed on OpenShift with a Helm Chart for {productName}. + +[source,options="nowrap"] +---- +$ helm install todo-backend -f todo-backend.yaml wildfly/wildfly +NAME: todo-backend +... +STATUS: deployed +REVISION: 1 +---- + +The Helm Chart for this quickstart contains all the information to build an image from the source code using Bootable Jar: + +[source,options="nowrap"] +---- +build: + uri: https://github.com/wildfly/quickstart.git + mode: bootable-jar +---- + +The Helm Chart also contains the environment variables required to connect to the PostgreSQL database. +In local deployment the credentials were passed directly as the values of the environment variables. +For OpenShift, we rely on secrets so that the credentials are never copied outside OpenShift: + +[source,options="nowrap"] +---- +deploy: + env: + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + key: database-password + name: todos-db +---- + +When the application is deployed, the value for the `POSTGRESQL_PASSWORD` will be taken from the key `database-password` +in the secrets `todos-db`. + +Let's wait for the application to be built and deployed: + +[source,options="nowrap"] +---- +$ oc get dc/todo-backend -w +NAME REVISION DESIRED CURRENT TRIGGERED BY +todo-backend 0 3 0 config,image(todo-backend:latest) +... +todo-backend 1 3 3 config,image(todo-backend:latest) +---- + +=== Use the todobackend Web application + +Once the backend is deployed on OpenShift, it can be accessed from the route `todo-backend`. +Let's find the host that we can use to connect to this backend: + +[source,options="nowrap"] +---- +$ oc get route todo-backend -o jsonpath="{.spec.host}" +todo-backend-jmesnil1-dev.apps.sandbox.x8i5.p1.openshiftapps.com +---- + +This value will be different for every installation of the backend. + +[WARNING] +==== +Make sure to prepend the host with `https://` to be able to connect to the backend from the ToDo Backend Specs or Client +==== + +We can verify that this application is properly working as a ToDo Backend by running its https://todobackend.com/specs/index.html[specs] on it. + + +Once all tests passed, we can use the https://todobackend.com/client/index.html[todobackend client] to have a Web application connected to the backend. + +=== Clean up + +==== Remove the Backend + +The backend can be deleted from OpenShift by running the command: + +[source,options="nowrap"] +---- +$ helm delete todo-backend +release "todo-backend" uninstalled +---- + +==== Remove the Database + +The PostresSQL database can be deleted from OpenShift by running the commands: + +[source,options="nowrap"] +---- +$ oc delete all -l template=postgresql-ephemeral-template +replicationcontroller "todos-db-1" deleted +service "todos-db" deleted +deploymentconfig.apps.openshift.io "todos-db" deleted +$ oc delete secret todos-db +secret "todos-db" deleted +---- \ No newline at end of file diff --git a/todo-backend/pom.xml b/todo-backend/pom.xml new file mode 100644 index 0000000000..608024d60d --- /dev/null +++ b/todo-backend/pom.xml @@ -0,0 +1,137 @@ + + + + 4.0.0 + + org.wildfly.quickstarts + quickstart-parent + + 24.0.0.Beta1-SNAPSHOT + ../pom.xml + + + todo-backend + war + Quickstart: Todo backend + This project demonstrates how to implement a Todo-Backend application to manage ToDos + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.html + repo + + + + + 1.2.3.Final + + + + + jakarta.enterprise + jakarta.enterprise.cdi-api + provided + + + jakarta.persistence + jakarta.persistence-api + provided + + + org.jboss.spec.javax.ejb + jboss-ejb-api_3.2_spec + provided + + + org.jboss.spec.javax.ws.rs + jboss-jaxrs-api_2.1_spec + provided + + + org.jboss.resteasy + resteasy-jackson2-provider + provided + + + + + + ${project.artifactId} + + + + + bootable-jar-openshift + + true + + + + + org.wildfly.plugins + wildfly-jar-maven-plugin + ${version.wildfly-jar.maven.plugin} + + + + wildfly@maven(org.jboss.universe:community-universe)#${version.server.bootable-jar} + + + org.wildfly + wildfly-datasources-galleon-pack + ${version.wildfly-datasources-galleon-pack} + + + + + cloud-server + postgresql-datasource + ejb + + + + + + false + + + + + + + true + + + + + + package + + + + + + + + + diff --git a/todo-backend/src/main/java/org/wildfly/quickstarts/todos/Resources.java b/todo-backend/src/main/java/org/wildfly/quickstarts/todos/Resources.java new file mode 100644 index 0000000000..19de930299 --- /dev/null +++ b/todo-backend/src/main/java/org/wildfly/quickstarts/todos/Resources.java @@ -0,0 +1,42 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2020, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.quickstarts.todos; + +import javax.ejb.Stateful; +import javax.enterprise.context.RequestScoped; +import javax.enterprise.inject.Produces; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.PersistenceContextType; + +@Stateful +@RequestScoped +public class Resources { + + @PersistenceContext(type = PersistenceContextType.EXTENDED) + private EntityManager em; + + @Produces + public EntityManager getEm() { + return em; + } +} \ No newline at end of file diff --git a/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDo.java b/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDo.java new file mode 100644 index 0000000000..7b6a078c76 --- /dev/null +++ b/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDo.java @@ -0,0 +1,143 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2020, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.quickstarts.todos; + +import static java.util.Optional.ofNullable; +import static javax.persistence.GenerationType.IDENTITY; + +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Objects; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.ws.rs.core.UriBuilder; + +@Entity +public class ToDo { + + @Id + @GeneratedValue(strategy = IDENTITY) + private Long id; + private String title; + private Boolean completed = false; + @Column(name = "\"order\"") + private int order; + private URL url; + + public ToDo() { + + } + + public ToDo(String title) { + this.title = title; + } + + public ToDo(Long id, String title, Boolean completed, int order, URL url) { + this.id = id; + this.title = title; + this.completed = completed; + this.order = order; + this.url = url; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public boolean isCompleted() { + return completed; + } + + public void setCompleted(Boolean completed) { + this.completed = completed; + } + + public Boolean getCompleted(){ + return this.completed == null ? false : this.completed; + } + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + public URL getUrl() throws MalformedURLException, URISyntaxException { + if (this.id != null) { + return UriBuilder.fromUri(url.toURI()).scheme(url.getProtocol()).path(id.toString()).build().toURL(); + } + return this.url; + } + + public void setUrl(URL url) { + this.url = url; + } + + public void update(ToDo newTodo) { + this.title = ofNullable(newTodo.title).orElse(title); + this.completed = ofNullable(newTodo.completed).orElse(completed); + this.order = ofNullable(newTodo.order).orElse(order); + this.url = ofNullable(newTodo.url).orElse(url); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ToDo toDo = (ToDo) o; + return id == toDo.id; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public String toString() { + return "ToDo{" + + "id=" + id + + ", title='" + title + '\'' + + ", completed=" + completed + + ", order=" + order + + ", url=" + url + + '}'; + } +} diff --git a/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDoBackendApplication.java b/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDoBackendApplication.java new file mode 100644 index 0000000000..4c8488cae7 --- /dev/null +++ b/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDoBackendApplication.java @@ -0,0 +1,29 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2020, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.quickstarts.todos; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("") +public class ToDoBackendApplication extends Application{ +} diff --git a/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDoController.java b/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDoController.java new file mode 100644 index 0000000000..86937a9f54 --- /dev/null +++ b/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDoController.java @@ -0,0 +1,106 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2020, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.quickstarts.todos; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +import java.net.MalformedURLException; +import java.util.List; +import java.util.Optional; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.transaction.Transactional; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.PATCH; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +@Path("") +@RequestScoped +public class ToDoController { + + @Inject + private ToDoDAO todoDAO; + + @Context + private UriInfo uriInfo; + + @GET + @Produces(APPLICATION_JSON) + public List getAllTodos(){ + return todoDAO.findAll(); + } + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + public ToDo getTodoFrom(@PathParam("id") long id) { + Optional todo = todoDAO.findById(id); + return todo.orElseThrow(() -> new NotFoundException("ToDo does not exist!")); + } + + @DELETE + @Transactional + public void deleteAllTodos(){ + todoDAO.findAll().forEach(todo -> todoDAO.remove(todo)); + } + + @DELETE + @Path("{id}") + @Transactional + public Response deleteTodoFrom(@PathParam("id") long id) { + Optional optional = todoDAO.findById(id); + ToDo todo = optional.orElseThrow(() -> new NotFoundException("ToDo does not exist!")); + todoDAO.remove(todo); + return Response.ok().build(); + } + + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + @Transactional + public ToDo addTodo(ToDo todo) throws MalformedURLException { + todo.setUrl(uriInfo.getAbsolutePathBuilder().scheme("https").build().toURL()); + todoDAO.insert(todo); + return todo; + } + + @PATCH + @Path("{id}") + @Produces(APPLICATION_JSON) + @Consumes(APPLICATION_JSON) + @Transactional + public ToDo updateTodo(@PathParam("id") long id, ToDo update) { + System.out.println("ToDoController.updateTodo"); + System.out.println("id = " + id + ", update = " + update); + return todoDAO.update(id, update).orElseThrow(() -> new NotFoundException("ToDo does not exist!")); + } +} \ No newline at end of file diff --git a/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDoDAO.java b/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDoDAO.java new file mode 100644 index 0000000000..1eaff4ab29 --- /dev/null +++ b/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDoDAO.java @@ -0,0 +1,41 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2020, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.quickstarts.todos; + +import java.util.List; +import java.util.Optional; + +import javax.ejb.Local; + +@Local +public interface ToDoDAO { + + List findAll(); + + Optional findById(Long id); + + void remove(ToDo todo); + + void insert(ToDo todo); + + Optional update(Long id, ToDo todo); +} \ No newline at end of file diff --git a/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDoDAOImpl.java b/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDoDAOImpl.java new file mode 100644 index 0000000000..5e2dd88b53 --- /dev/null +++ b/todo-backend/src/main/java/org/wildfly/quickstarts/todos/ToDoDAOImpl.java @@ -0,0 +1,81 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2020, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.quickstarts.todos; + + +import java.util.List; +import java.util.Optional; + +import javax.ejb.Stateful; +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.UriInfo; + +@Stateful +public class ToDoDAOImpl implements ToDoDAO { + + @Inject + private EntityManager em; + + @Context + UriInfo uriInfo; + + @Override + public List findAll() { + TypedQuery query = em.createQuery("FROM ToDo", ToDo.class); + return query.getResultList(); + } + + public Optional findById(Long id) { + System.out.println("ToDoDAOImpl.findById"); + System.out.println("id = " + id); + ToDo toDo = em.find(ToDo.class, id); + System.out.println("toDo = " + toDo); + return Optional.ofNullable(toDo); + } + + @Override + public void remove(ToDo todo) { + em.remove(todo); + } + + @Override + public void insert(ToDo todo) { + em.persist(todo); + } + + @Override + public Optional update(Long id, ToDo newTodo) { + System.out.println("ToDoDAOImpl.update"); + System.out.println("id = " + id + ", newTodo = " + newTodo); + Optional optional = findById(id); + System.out.println("optional before update= " + optional); + if (optional.isPresent()) { + optional.get().update(newTodo); + System.out.println("optional after update= " + optional); + return optional; + } + return Optional.empty(); + } +} \ No newline at end of file diff --git a/todo-backend/src/main/resources/META-INF/persistence.xml b/todo-backend/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000000..a9d9e54e20 --- /dev/null +++ b/todo-backend/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,31 @@ + + + + + java:jboss/datasources/ToDos + + + + + + + diff --git a/todo-backend/src/main/scripts/cors_filters.cli b/todo-backend/src/main/scripts/cors_filters.cli new file mode 100644 index 0000000000..12b029fbba --- /dev/null +++ b/todo-backend/src/main/scripts/cors_filters.cli @@ -0,0 +1,16 @@ +echo Adding Undertow Filters for CORS +# Access-Control-Allow-Origin +/subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Allow-Origin":add() +/subsystem=undertow/configuration=filter/response-header="Access-Control-Allow-Origin":add(header-name="Access-Control-Allow-Origin",header-value="${env.CORS_ORIGIN:*}") +# Access-Control-Allow-Methods +/subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Allow-Methods":add() +/subsystem=undertow/configuration=filter/response-header="Access-Control-Allow-Methods":add(header-name="Access-Control-Allow-Methods",header-value="GET, POST, OPTION, PUT, DELETE, PATCH") +# Access-Control-Allow-Headers +/subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Allow-Headers":add() +/subsystem=undertow/configuration=filter/response-header="Access-Control-Allow-Headers":add(header-name="Access-Control-Allow-Headers",header-value="accept, authorization, content-type, x-requested-with") +# Access-Control-Allow-Credentials +/subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Allow-Credentials":add() +/subsystem=undertow/configuration=filter/response-header="Access-Control-Allow-Credentials":add(header-name="Access-Control-Allow-Credentials",header-value="true") +# Access-Control-Max-Age +/subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Max-Age":add() +/subsystem=undertow/configuration=filter/response-header="Access-Control-Max-Age":add(header-name="Access-Control-Max-Age",header-value="1") \ No newline at end of file diff --git a/todo-backend/src/main/webapp/WEB-INF/beans.xml b/todo-backend/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000000..d3ddf148e7 --- /dev/null +++ b/todo-backend/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,24 @@ + + + + + diff --git a/todo-backend/todo-backend.yaml b/todo-backend/todo-backend.yaml new file mode 100644 index 0000000000..c1c153911c --- /dev/null +++ b/todo-backend/todo-backend.yaml @@ -0,0 +1,43 @@ +# This configuration file can be used to build and deploy the todo-backend +# quickstart on OpenShift with the Helm Chart for WildFly. +build: + uri: https://github.com/quickstart/quickstart.git + ref: todo-backend + mode: bootable-jar + env: + - name: ARTIFACT_DIR + value: todo-backend/target + - name: MAVEN_ARGS_APPEND + value: -am -pl todo-backend + - name: MAVEN_OPTS + value: '-XX:MetaspaceSize=96m -XX:MaxMetaspaceSize=256m' +deploy: + replicas: 3 + env: + # Env vars to connect to PostgreSQL DB + - name: POSTGRESQL_DATABASE + valueFrom: + secretKeyRef: + key: database-name + name: todos-db + - name: POSTGRESQL_USER + valueFrom: + secretKeyRef: + key: database-user + name: todos-db + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + key: database-password + name: todos-db + - name: POSTGRESQL_DATASOURCE + value: ToDos + - name: POSTGRESQL_SERVICE_HOST + value: todos-db + - name: POSTGRESQL_SERVICE_PORT + value: "5432" + # Env to avoid OOME + - name: GC_MAX_METASPACE_SIZE + value: "256" + - name: GC_METASPACE_SIZE + value: "96"