From 81fbcfc2409f885dd8405042b05d272d4eb629e5 Mon Sep 17 00:00:00 2001 From: Dan K Date: Mon, 22 Jul 2019 15:38:35 -0400 Subject: [PATCH] WIP(ch9lab) add source for java-based todo-api app --- todo-api-micro/pom.xml | 111 ++++++++++++++++++ .../src/main/fabric8/deployment.yml | 21 ++++ todo-api-micro/src/main/fabric8/route.yml | 18 +++ todo-api-micro/src/main/fabric8/svc.yml | 21 ++++ .../todoapi/rest/HelloWorldEndpoint.java | 19 +++ .../training/example/todoapi/rest/Main.java | 25 ++++ .../java/com/redhat/training/model/Host.java | 24 ++++ .../java/com/redhat/training/model/Item.java | 53 +++++++++ .../training/rest/CORSRequestFilter.java | 30 +++++ .../training/rest/CORSResponseFilter.java | 32 +++++ .../com/redhat/training/rest/HostService.java | 28 +++++ .../com/redhat/training/rest/ItemService.java | 97 +++++++++++++++ .../redhat/training/rest/RestApplication.java | 8 ++ .../training/ui/PaginatedListWrapper.java | 72 ++++++++++++ .../main/resources/META-INF/persistence.xml | 18 +++ .../modules/com/mysql/main/module.xml | 16 +++ .../src/main/resources/project-defaults.yml | 13 ++ .../src/main/resources/sql/create.sql | 1 + .../src/main/resources/sql/drop.sql | 1 + .../src/main/resources/sql/load.sql | 2 + 20 files changed, 610 insertions(+) create mode 100755 todo-api-micro/pom.xml create mode 100644 todo-api-micro/src/main/fabric8/deployment.yml create mode 100644 todo-api-micro/src/main/fabric8/route.yml create mode 100644 todo-api-micro/src/main/fabric8/svc.yml create mode 100755 todo-api-micro/src/main/java/com/redhat/training/example/todoapi/rest/HelloWorldEndpoint.java create mode 100644 todo-api-micro/src/main/java/com/redhat/training/example/todoapi/rest/Main.java create mode 100644 todo-api-micro/src/main/java/com/redhat/training/model/Host.java create mode 100644 todo-api-micro/src/main/java/com/redhat/training/model/Item.java create mode 100644 todo-api-micro/src/main/java/com/redhat/training/rest/CORSRequestFilter.java create mode 100644 todo-api-micro/src/main/java/com/redhat/training/rest/CORSResponseFilter.java create mode 100644 todo-api-micro/src/main/java/com/redhat/training/rest/HostService.java create mode 100644 todo-api-micro/src/main/java/com/redhat/training/rest/ItemService.java create mode 100644 todo-api-micro/src/main/java/com/redhat/training/rest/RestApplication.java create mode 100644 todo-api-micro/src/main/java/com/redhat/training/ui/PaginatedListWrapper.java create mode 100644 todo-api-micro/src/main/resources/META-INF/persistence.xml create mode 100644 todo-api-micro/src/main/resources/modules/com/mysql/main/module.xml create mode 100644 todo-api-micro/src/main/resources/project-defaults.yml create mode 100644 todo-api-micro/src/main/resources/sql/create.sql create mode 100644 todo-api-micro/src/main/resources/sql/drop.sql create mode 100644 todo-api-micro/src/main/resources/sql/load.sql diff --git a/todo-api-micro/pom.xml b/todo-api-micro/pom.xml new file mode 100755 index 0000000000..b227a1153b --- /dev/null +++ b/todo-api-micro/pom.xml @@ -0,0 +1,111 @@ + + + 4.0.0 + com.redhat.training.example + todo-api + WildFly Swarm Example + 1.0.0-SNAPSHOT + war + + + 2017.12.1 + 6.0.6 + 1.8 + 1.8 + false + UTF-8 + 3.1.80.redhat-000019 + 2.3.6 + + + + + + org.wildfly.swarm + bom-all + ${version.wildfly.swarm} + import + pom + + + + + + demo + + + org.wildfly.swarm + wildfly-swarm-plugin + ${version.wildfly.swarm} + + + + package + + + + + + io.fabric8 + fabric8-maven-plugin + + + + resource + build + + + + + + + wildfly-swarm + + + webapp + + + + isTag + redhat-openjdk18-openshift + + + + + + + + + + + + javax + javaee-api + 7.0 + provided + + + + org.wildfly.swarm + jaxrs-jsonp + + + org.wildfly.swarm + jpa + + + org.wildfly.swarm + ejb + + + org.wildfly.swarm + datasources + + + + mysql + mysql-connector-java + ${version.mysql} + + + diff --git a/todo-api-micro/src/main/fabric8/deployment.yml b/todo-api-micro/src/main/fabric8/deployment.yml new file mode 100644 index 0000000000..f9fa89d382 --- /dev/null +++ b/todo-api-micro/src/main/fabric8/deployment.yml @@ -0,0 +1,21 @@ +spec: + template: + spec: + containers: + - + resources: + requests: + cpu: "0.2" +# memory: 256Mi + limits: + cpu: "1.0" +# memory: 256Mi + env: + - name: DATABASE_USER + value: '${database.user}' + - name: DATABASE_PASSWORD + value: '${database.password}' + - name: DATABASE_SVC_HOSTNAME + value: '${database.svc.hostname}' + - name: DATABASE_NAME + value: '${database.name}' diff --git a/todo-api-micro/src/main/fabric8/route.yml b/todo-api-micro/src/main/fabric8/route.yml new file mode 100644 index 0000000000..d7f59ab5e2 --- /dev/null +++ b/todo-api-micro/src/main/fabric8/route.yml @@ -0,0 +1,18 @@ +--- +apiVersion: v1 +kind: Route +metadata: + labels: + expose: "true" + app: ${project.artifactId} + provider: fabric8 + version: "1.0" + group: com.redhat.training + name: ${project.artifactId} +spec: + host: ${hostname} + port: + targetPort: ${service-port} + to: + kind: Service + name: ${project.artifactId} diff --git a/todo-api-micro/src/main/fabric8/svc.yml b/todo-api-micro/src/main/fabric8/svc.yml new file mode 100644 index 0000000000..b812eb9839 --- /dev/null +++ b/todo-api-micro/src/main/fabric8/svc.yml @@ -0,0 +1,21 @@ +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + fabric8.io/iconUrl: img/icons/camel.svg + labels: + expose: "true" + app: ${project.artifactId} + provider: fabric8 + version: "1.0" + group: com.redhat.training + name: ${project.artifactId} +spec: + ports: + - name: http + port: ${service-port} + protocol: TCP + targetPort: ${service-port} + selector: + deploymentconfig: ${project.artifactId} diff --git a/todo-api-micro/src/main/java/com/redhat/training/example/todoapi/rest/HelloWorldEndpoint.java b/todo-api-micro/src/main/java/com/redhat/training/example/todoapi/rest/HelloWorldEndpoint.java new file mode 100755 index 0000000000..ec8817b1ff --- /dev/null +++ b/todo-api-micro/src/main/java/com/redhat/training/example/todoapi/rest/HelloWorldEndpoint.java @@ -0,0 +1,19 @@ +package com.redhat.training.example.todoapi.rest; + + +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.ws.rs.GET; +import javax.ws.rs.Produces; + + +@Path("/hello") +public class HelloWorldEndpoint { + + @GET + @Produces("text/plain") + public Response doGet() { + return Response.ok("Hello World!").build(); + + } +} diff --git a/todo-api-micro/src/main/java/com/redhat/training/example/todoapi/rest/Main.java b/todo-api-micro/src/main/java/com/redhat/training/example/todoapi/rest/Main.java new file mode 100644 index 0000000000..2dbeece908 --- /dev/null +++ b/todo-api-micro/src/main/java/com/redhat/training/example/todoapi/rest/Main.java @@ -0,0 +1,25 @@ +package com.redhat.training.example.todoapi.rest; + +import org.wildfly.swarm.Swarm; +import org.wildfly.swarm.datasources.DatasourcesFraction; + +public class Main { + public static void main(String[] args) throws Exception { + String host = System.getenv("HOST"); + new Swarm() + .fraction(new DatasourcesFraction() + .jdbcDriver("mysql", (d) -> { + d.driverClassName("com.mysql.cj.jdbc.Driver"); + d.xaDatasourceClass("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"); + d.driverModuleName("com.mysql"); + }) + .dataSource("MySQLDS", (ds) -> { + ds.driverName("mysql"); + ds.connectionUrl("jdbc:mysql://"+host+":8889/todo"); + ds.userName("root"); + ds.password("root"); + })) + .start() + .deploy(); + } +} diff --git a/todo-api-micro/src/main/java/com/redhat/training/model/Host.java b/todo-api-micro/src/main/java/com/redhat/training/model/Host.java new file mode 100644 index 0000000000..30dbcf21e9 --- /dev/null +++ b/todo-api-micro/src/main/java/com/redhat/training/model/Host.java @@ -0,0 +1,24 @@ +package com.redhat.training.model; + +import java.net.InetAddress; + +public class Host { + + private String ip; + private String hostname; + + public Host(String ip, String hostname) { + this.ip = ip; + this.hostname = hostname; + } + + public String getIp() { + return ip; + } + + public String getHostname() { + return hostname; + } + +} + diff --git a/todo-api-micro/src/main/java/com/redhat/training/model/Item.java b/todo-api-micro/src/main/java/com/redhat/training/model/Item.java new file mode 100644 index 0000000000..5067fe5e50 --- /dev/null +++ b/todo-api-micro/src/main/java/com/redhat/training/model/Item.java @@ -0,0 +1,53 @@ +package com.redhat.training.model; + +import javax.persistence.*; + +@Entity +public class Item { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String description; + + private Boolean done = false; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Boolean isDone() { + return done; + } + + public void setDone(Boolean done) { + this.done = done; + } + + @Override + public boolean equals(Object o) { + if (this == o) { return true; } + if (o == null || getClass() != o.getClass()) { return false; } + + Item item = (Item) o; + + return id.equals(item.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} diff --git a/todo-api-micro/src/main/java/com/redhat/training/rest/CORSRequestFilter.java b/todo-api-micro/src/main/java/com/redhat/training/rest/CORSRequestFilter.java new file mode 100644 index 0000000000..d8b03ce826 --- /dev/null +++ b/todo-api-micro/src/main/java/com/redhat/training/rest/CORSRequestFilter.java @@ -0,0 +1,30 @@ +package com.redhat.training.rest; + +import java.io.IOException; +import java.util.logging.Logger; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; + +@Provider +@PreMatching +public class CORSRequestFilter implements ContainerRequestFilter { + + private final static Logger log = Logger.getLogger(CORSRequestFilter.class.getName()); + + @Override + public void filter(ContainerRequestContext requestCtx) throws IOException { + log.fine("Executing REST request filter"); + + // When HttpMethod comes as OPTIONS, just acknowledge that it accepts... + if (requestCtx.getRequest().getMethod().equals( "OPTIONS" )) { + log.fine("HTTP Method (OPTIONS) - Detected!"); + + // Just send a OK signal back to the browser + requestCtx.abortWith(Response.status(Response.Status.OK).build()); + } + } +} diff --git a/todo-api-micro/src/main/java/com/redhat/training/rest/CORSResponseFilter.java b/todo-api-micro/src/main/java/com/redhat/training/rest/CORSResponseFilter.java new file mode 100644 index 0000000000..642119092b --- /dev/null +++ b/todo-api-micro/src/main/java/com/redhat/training/rest/CORSResponseFilter.java @@ -0,0 +1,32 @@ +package com.redhat.training.rest; + +import java.io.IOException; +import java.util.logging.Logger; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; + +@Provider +@PreMatching +public class CORSResponseFilter implements ContainerResponseFilter { + + private final static Logger log = Logger.getLogger(CORSResponseFilter.class.getName()); + + @Override + public void filter(ContainerRequestContext requestCtx, ContainerResponseContext responseCtx) throws IOException { + log.fine("Executing REST response filter"); + + MultivaluedMap headers = responseCtx.getHeaders(); + + headers.add("Access-Control-Allow-Origin", "*"); + headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS"); + headers.add("Access-Control-Allow-Headers", "X-Requested-With, Content-Type"); + //responseCtx.getHeaders().add( "Access-Control-Allow-Credentials", "true" ); + } + +} diff --git a/todo-api-micro/src/main/java/com/redhat/training/rest/HostService.java b/todo-api-micro/src/main/java/com/redhat/training/rest/HostService.java new file mode 100644 index 0000000000..f62aac111f --- /dev/null +++ b/todo-api-micro/src/main/java/com/redhat/training/rest/HostService.java @@ -0,0 +1,28 @@ +package com.redhat.training.rest; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import javax.ejb.Stateless; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import com.redhat.training.model.Host; + +@Stateless +@Path("host") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public class HostService { + + @GET + public Host getHostInfo() throws UnknownHostException { + InetAddress address = InetAddress.getLocalHost(); + Host host = new Host(address.getHostAddress(), address.getHostName()); + return host; + } +} + diff --git a/todo-api-micro/src/main/java/com/redhat/training/rest/ItemService.java b/todo-api-micro/src/main/java/com/redhat/training/rest/ItemService.java new file mode 100644 index 0000000000..bf0b0301f1 --- /dev/null +++ b/todo-api-micro/src/main/java/com/redhat/training/rest/ItemService.java @@ -0,0 +1,97 @@ +package com.redhat.training.rest; + +import com.redhat.training.model.Item; +import com.redhat.training.ui.PaginatedListWrapper; + +import javax.ejb.Stateless; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.Query; +import javax.persistence.TypedQuery; +import javax.ws.rs.*; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.MediaType; + +import java.util.List; + +@Stateless +@Path("items") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public class ItemService extends Application { + + @PersistenceContext + private EntityManager entityManager; + + private Integer countItems() { + Query query = entityManager.createQuery("SELECT COUNT(i.id) FROM Item i"); + return ((Long) query.getSingleResult()).intValue(); + } + + private List findItems(int startPosition, int maxResults, String sortFields, String sortDirections) { + TypedQuery query = + entityManager.createQuery("SELECT i FROM Item i ORDER BY i." + sortFields + " " + sortDirections, + Item.class); + query.setFirstResult(startPosition); + query.setMaxResults(maxResults); + return query.getResultList(); + } + + private PaginatedListWrapper findItems(PaginatedListWrapper wrapper) { + wrapper.setTotalResults(countItems()); + int start = (wrapper.getCurrentPage() - 1) * wrapper.getPageSize(); + wrapper.setList(findItems(start, + wrapper.getPageSize(), + wrapper.getSortFields(), + wrapper.getSortDirections())); + return wrapper; + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public PaginatedListWrapper listItems(@DefaultValue("1") + @QueryParam("page") + Integer page, + @DefaultValue("id") + @QueryParam("sortFields") + String sortFields, + @DefaultValue("asc") + @QueryParam("sortDirections") + String sortDirections) { + PaginatedListWrapper paginatedListWrapper = new PaginatedListWrapper(); + paginatedListWrapper.setCurrentPage(page); + paginatedListWrapper.setSortFields(sortFields); + paginatedListWrapper.setSortDirections(sortDirections); + paginatedListWrapper.setPageSize(10); + return findItems(paginatedListWrapper); + } + + @GET + @Path("{id}") + public Item getitem(@PathParam("id") Long id) { + return entityManager.find(Item.class, id); + } + + @POST + public Item saveItem(Item item) { + if (item.getId() == null) { + Item itemToSave = new Item(); + itemToSave.setDescription(item.getDescription()); + itemToSave.setDone(item.isDone()); + entityManager.persist(item); + } else { + Item itemToUpdate = getitem(item.getId()); + itemToUpdate.setDescription(item.getDescription()); + itemToUpdate.setDone(item.isDone()); + item = entityManager.merge(itemToUpdate); + } + + return item; + } + + @DELETE + @Path("{id}") + public void deleteItem(@PathParam("id") Long id) { + entityManager.remove(getitem(id)); + } +} diff --git a/todo-api-micro/src/main/java/com/redhat/training/rest/RestApplication.java b/todo-api-micro/src/main/java/com/redhat/training/rest/RestApplication.java new file mode 100644 index 0000000000..d6aa93ae82 --- /dev/null +++ b/todo-api-micro/src/main/java/com/redhat/training/rest/RestApplication.java @@ -0,0 +1,8 @@ +package com.redhat.training.rest; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("/todo/api") +public class RestApplication extends Application { +} diff --git a/todo-api-micro/src/main/java/com/redhat/training/ui/PaginatedListWrapper.java b/todo-api-micro/src/main/java/com/redhat/training/ui/PaginatedListWrapper.java new file mode 100644 index 0000000000..7eaeb51428 --- /dev/null +++ b/todo-api-micro/src/main/java/com/redhat/training/ui/PaginatedListWrapper.java @@ -0,0 +1,72 @@ +package com.redhat.training.ui; + +import com.redhat.training.model.Item; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import java.io.Serializable; +import java.util.List; + +@XmlRootElement +public class PaginatedListWrapper implements Serializable { + + private static final long serialVersionUID = 1L; + + private Integer currentPage; + private Integer pageSize; + private Integer totalResults; + + private String sortFields; + private String sortDirections; + @XmlElement + private List list; + + public Integer getCurrentPage() { + return currentPage; + } + + public void setCurrentPage(Integer currentPage) { + this.currentPage = currentPage; + } + + public Integer getPageSize() { + return pageSize; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + public Integer getTotalResults() { + return totalResults; + } + + public void setTotalResults(Integer totalResults) { + this.totalResults = totalResults; + } + + public String getSortFields() { + return sortFields; + } + + public void setSortFields(String sortFields) { + this.sortFields = sortFields; + } + + public String getSortDirections() { + return sortDirections; + } + + public void setSortDirections(String sortDirections) { + this.sortDirections = sortDirections; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } +} diff --git a/todo-api-micro/src/main/resources/META-INF/persistence.xml b/todo-api-micro/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000000..acf40ff06b --- /dev/null +++ b/todo-api-micro/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,18 @@ + + + + java:jboss/datasources/MySQLDS + + + + + + + + + + + diff --git a/todo-api-micro/src/main/resources/modules/com/mysql/main/module.xml b/todo-api-micro/src/main/resources/modules/com/mysql/main/module.xml new file mode 100644 index 0000000000..6d887280a8 --- /dev/null +++ b/todo-api-micro/src/main/resources/modules/com/mysql/main/module.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/todo-api-micro/src/main/resources/project-defaults.yml b/todo-api-micro/src/main/resources/project-defaults.yml new file mode 100644 index 0000000000..16a4f1e604 --- /dev/null +++ b/todo-api-micro/src/main/resources/project-defaults.yml @@ -0,0 +1,13 @@ +swarm: + datasources: + jdbc-drivers: + com.mysql: + driver-class-name: com.mysql.cj.jdbc.Driver + xa-datasource-class-name: com.mysql.jdbc.jdbc2.optional.MysqlXADataSource + driver-module-name: com.mysql + data-sources: + MySQLDS: + driver-name: com.mysql + connection-url: jdbc:mysql://${env.DATABASE_SVC_HOSTNAME}:3306/${env.DATABASE_NAME} + user-name: ${env.DATABASE_USER} + password: ${env.DATABASE_PASSWORD} diff --git a/todo-api-micro/src/main/resources/sql/create.sql b/todo-api-micro/src/main/resources/sql/create.sql new file mode 100644 index 0000000000..6289f7c387 --- /dev/null +++ b/todo-api-micro/src/main/resources/sql/create.sql @@ -0,0 +1 @@ +CREATE TABLE `Item` (`id` BIGINT not null auto_increment primary key, `description` VARCHAR(100), `done` BIT); diff --git a/todo-api-micro/src/main/resources/sql/drop.sql b/todo-api-micro/src/main/resources/sql/drop.sql new file mode 100644 index 0000000000..35ef5b3674 --- /dev/null +++ b/todo-api-micro/src/main/resources/sql/drop.sql @@ -0,0 +1 @@ +DROP TABLE `Item`; diff --git a/todo-api-micro/src/main/resources/sql/load.sql b/todo-api-micro/src/main/resources/sql/load.sql new file mode 100644 index 0000000000..6dec667b69 --- /dev/null +++ b/todo-api-micro/src/main/resources/sql/load.sql @@ -0,0 +1,2 @@ +INSERT INTO `Item` (`id`,`description`,`done`) VALUES (1,'Pick up newspaper', 0); +INSERT INTO `Item` (`id`,`description`,`done`) VALUES (2,'Buy groceries', 1);