diff --git a/todo-api-micro/pom.xml b/todo-api-micro/pom.xml
new file mode 100755
index 0000000..b227a11
--- /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 0000000..f9fa89d
--- /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 0000000..d7f59ab
--- /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 0000000..b812eb9
--- /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 0000000..ec8817b
--- /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 0000000..2dbeece
--- /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 0000000..30dbcf2
--- /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 0000000..5067fe5
--- /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 0000000..d8b03ce
--- /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 0000000..6421190
--- /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 0000000..f62aac1
--- /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 0000000..bf0b030
--- /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 0000000..d6aa93a
--- /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 0000000..7eaeb51
--- /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 0000000..acf40ff
--- /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 0000000..6d88728
--- /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 0000000..16a4f1e
--- /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 0000000..6289f7c
--- /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 0000000..35ef5b3
--- /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 0000000..6dec667
--- /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);