Dan K
2019-07-22 81fbcfc2409f885dd8405042b05d272d4eb629e5
WIP(ch9lab) add source for java-based todo-api app
20 files added
610 ■■■■■ changed files
todo-api-micro/pom.xml 111 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/fabric8/deployment.yml 21 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/fabric8/route.yml 18 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/fabric8/svc.yml 21 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/java/com/redhat/training/example/todoapi/rest/HelloWorldEndpoint.java 19 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/java/com/redhat/training/example/todoapi/rest/Main.java 25 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/java/com/redhat/training/model/Host.java 24 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/java/com/redhat/training/model/Item.java 53 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/java/com/redhat/training/rest/CORSRequestFilter.java 30 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/java/com/redhat/training/rest/CORSResponseFilter.java 32 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/java/com/redhat/training/rest/HostService.java 28 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/java/com/redhat/training/rest/ItemService.java 97 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/java/com/redhat/training/rest/RestApplication.java 8 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/java/com/redhat/training/ui/PaginatedListWrapper.java 72 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/resources/META-INF/persistence.xml 18 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/resources/modules/com/mysql/main/module.xml 16 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/resources/project-defaults.yml 13 ●●●●● patch | view | raw | blame | history
todo-api-micro/src/main/resources/sql/create.sql 1 ●●●● patch | view | raw | blame | history
todo-api-micro/src/main/resources/sql/drop.sql 1 ●●●● patch | view | raw | blame | history
todo-api-micro/src/main/resources/sql/load.sql 2 ●●●●● patch | view | raw | blame | history
todo-api-micro/pom.xml
New file
@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.redhat.training.example</groupId>
  <artifactId>todo-api</artifactId>
  <name>WildFly Swarm Example</name>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>war</packaging>
  <properties>
    <version.wildfly.swarm>2017.12.1</version.wildfly.swarm>
    <version.mysql>6.0.6</version.mysql>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <failOnMissingWebXml>false</failOnMissingWebXml>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <fabric8.maven.plugin.version>3.1.80.redhat-000019</fabric8.maven.plugin.version>
    <fabric8.version>2.3.6</fabric8.version>
  </properties>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.wildfly.swarm</groupId>
        <artifactId>bom-all</artifactId>
        <version>${version.wildfly.swarm}</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <build>
    <finalName>demo</finalName>
    <plugins>
      <plugin>
        <groupId>org.wildfly.swarm</groupId>
        <artifactId>wildfly-swarm-plugin</artifactId>
        <version>${version.wildfly.swarm}</version>
        <executions>
          <execution>
            <goals>
              <goal>package</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>io.fabric8</groupId>
        <artifactId>fabric8-maven-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>resource</goal>
              <goal>build</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <generator>
            <includes>
              <include>wildfly-swarm</include>
            </includes>
            <excludes>
              <exclude>webapp</exclude>
            </excludes>
            <config>
              <wildfly-swarm>
                <fromMode>isTag</fromMode>
                <from>redhat-openjdk18-openshift</from>
              </wildfly-swarm>
            </config>
          </generator>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <!-- Java EE 7 dependency -->
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <version>7.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- WildFly Swarm Fractions -->
    <dependency>
      <groupId>org.wildfly.swarm</groupId>
      <artifactId>jaxrs-jsonp</artifactId>
    </dependency>
    <dependency>
      <groupId>org.wildfly.swarm</groupId>
      <artifactId>jpa</artifactId>
    </dependency>
    <dependency>
      <groupId>org.wildfly.swarm</groupId>
      <artifactId>ejb</artifactId>
    </dependency>
    <dependency>
      <groupId>org.wildfly.swarm</groupId>
      <artifactId>datasources</artifactId>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>${version.mysql}</version>
    </dependency>
  </dependencies>
</project>
todo-api-micro/src/main/fabric8/deployment.yml
New file
@@ -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}'
todo-api-micro/src/main/fabric8/route.yml
New file
@@ -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}
todo-api-micro/src/main/fabric8/svc.yml
New file
@@ -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}
todo-api-micro/src/main/java/com/redhat/training/example/todoapi/rest/HelloWorldEndpoint.java
New file
@@ -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();
    }
}
todo-api-micro/src/main/java/com/redhat/training/example/todoapi/rest/Main.java
New file
@@ -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();
    }
}
todo-api-micro/src/main/java/com/redhat/training/model/Host.java
New file
@@ -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;
    }
}
todo-api-micro/src/main/java/com/redhat/training/model/Item.java
New file
@@ -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();
    }
}
todo-api-micro/src/main/java/com/redhat/training/rest/CORSRequestFilter.java
New file
@@ -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());
        }
    }
}
todo-api-micro/src/main/java/com/redhat/training/rest/CORSResponseFilter.java
New file
@@ -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<String, Object> 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" );
    }
}
todo-api-micro/src/main/java/com/redhat/training/rest/HostService.java
New file
@@ -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;
    }
}
todo-api-micro/src/main/java/com/redhat/training/rest/ItemService.java
New file
@@ -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<Item> findItems(int startPosition, int maxResults, String sortFields, String sortDirections) {
        TypedQuery<Item> 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));
    }
}
todo-api-micro/src/main/java/com/redhat/training/rest/RestApplication.java
New file
@@ -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 {
}
todo-api-micro/src/main/java/com/redhat/training/ui/PaginatedListWrapper.java
New file
@@ -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<Item> 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<Item> getList() {
        return list;
    }
    public void setList(List<Item> list) {
        this.list = list;
    }
}
todo-api-micro/src/main/resources/META-INF/persistence.xml
New file
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="Items" transaction-type="JTA">
        <jta-data-source>java:jboss/datasources/MySQLDS</jta-data-source>
        <properties>
            <property name="javax.persistence.schema-generation.database.action" value="none"/>
            <property name="javax.persistence.schema-generation.create-source" value="script"/>
            <property name="javax.persistence.schema-generation.drop-source" value="script"/>
            <property name="javax.persistence.schema-generation.create-script-source" value="sql/create.sql"/>
            <property name="javax.persistence.schema-generation.drop-script-source" value="sql/drop.sql"/>
            <property name="javax.persistence.sql-load-script-source" value="sql/load.sql"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
        </properties>
    </persistence-unit>
</persistence>
todo-api-micro/src/main/resources/modules/com/mysql/main/module.xml
New file
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Copyright 2015 Red Hat, Inc. and/or its affiliates.
  ~
  ~ Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
  -->
<module xmlns="urn:jboss:module:1.3" name="com.mysql">
    <resources>
        <artifact name="mysql:mysql-connector-java:6.0.6"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="javax.transaction.api"/>
    </dependencies>
</module>
todo-api-micro/src/main/resources/project-defaults.yml
New file
@@ -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}
todo-api-micro/src/main/resources/sql/create.sql
New file
@@ -0,0 +1 @@
CREATE TABLE `Item` (`id` BIGINT not null auto_increment primary key, `description` VARCHAR(100), `done` BIT);
todo-api-micro/src/main/resources/sql/drop.sql
New file
@@ -0,0 +1 @@
DROP TABLE `Item`;
todo-api-micro/src/main/resources/sql/load.sql
New file
@@ -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);