Jaime Ramírez
2020-05-08 3593d30cc38a36f8f10985a63fa643592457e0a2
Added vertx-greet app for chapter05 (#14)

6 files added
368 ■■■■■ changed files
vertx-greet/.gitignore 87 ●●●●● patch | view | raw | blame | history
vertx-greet/Dockerfile 17 ●●●●● patch | view | raw | blame | history
vertx-greet/README.adoc 61 ●●●●● patch | view | raw | blame | history
vertx-greet/pom.xml 118 ●●●●● patch | view | raw | blame | history
vertx-greet/src/main/java/io/vertx/greet/GreetMain.java 24 ●●●●● patch | view | raw | blame | history
vertx-greet/src/main/java/io/vertx/greet/GreetServer.java 61 ●●●●● patch | view | raw | blame | history
vertx-greet/.gitignore
New file
@@ -0,0 +1,87 @@
##############################
## Java
##############################
.mtj.tmp/
*.class
*.jar
*.war
*.ear
*.nar
hs_err_pid*
##############################
## Maven
##############################
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
pom.xml.bak
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar
##############################
## Gradle
##############################
bin/
build/
.gradle
.gradletasknamecache
gradle-app.setting
!gradle-wrapper.jar
##############################
## IntelliJ
##############################
out/
.idea/
.idea_modules/
*.iml
*.ipr
*.iws
##############################
## Eclipse
##############################
.settings/
bin/
tmp/
.metadata
.classpath
.project
*.tmp
*.bak
*.swp
*~.nib
local.properties
.loadpath
.factorypath
##############################
## NetBeans
##############################
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
nb-configuration.xml
##############################
## Visual Studio Code
##############################
.vscode/
##############################
## OS X
##############################
.DS_Store
# Logs
logs
*.log
vertx-greet/Dockerfile
New file
@@ -0,0 +1,17 @@
FROM openjdk:8-jre-alpine
ENV VERTICLE_FILE vertx-greet-3.9.0-fat.jar
# Set the location of the verticles
ENV VERTICLE_HOME /usr/verticles
EXPOSE 8080
COPY target/$VERTICLE_FILE $VERTICLE_HOME/
# Launch the verticle
WORKDIR $VERTICLE_HOME
ENTRYPOINT ["sh", "-c"]
CMD ["exec java -jar $VERTICLE_FILE"]
vertx-greet/README.adoc
New file
@@ -0,0 +1,61 @@
= Vert.x Greet service
A simple Vert.x greeting service with the following features:
* Configurable greeting message.
* Request counter.
* Basic rate limiting.
In this example Vert.x is used embedded. I.e. we use the Vert.x APIs directly in our own classes rather than deploying
the code in verticles.
== How to run
You can run or debug the example in your IDE by just right clicking the main class and run as.. or debug as...
The pom.xml uses the Maven shade plugin to assemble the application and all it's dependencies into a single "fat" jar.
To run with maven
    mvn compile exec:java
To build a "fat jar"
    mvn package
To run the fat jar:
    java -jar target/maven-simplest-3.9.0-fat.jar
(You can take that jar and run it anywhere there is a Java 8+ JDK. It contains all the dependencies it needs so you
don't need to install Vert.x on the target machine).
You can also run the fat jar with maven:
    mvn package exec:exec@run-app
Now point your browser at http://localhost:8080
== Configuration
The service uses two optional environment variables to control the greeting message and a very basic rate limiting feature:
* GRETTING: defines the message returned when requesting the route `/`. If not specified, a default message is used.
* MAX_REQUESTS_PER_SECOND: Indicates the number of requests per second that the service is able to handle. When a user surpasses this limit, the service returns 503 for each rate-limited request. Ignore this variable to deactivate the rate limit.
== Container Image
To publish the application as a container image in quay.io, first build the jar:
    mvn package
Next, build the image:
    docker build -t quay.io/redhattraining/ossm-vertx-greet .
Finally, push the image to quay:
    docker push quay.io/redhattraining/ossm-vertx-greet
vertx-greet/pom.xml
New file
@@ -0,0 +1,118 @@
<?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>io.vertx</groupId>
  <artifactId>vertx-greet</artifactId>
  <version>3.9.0</version>
  <properties>
    <!-- the main class -->
    <exec.mainClass>io.vertx.greet.GreetMain</exec.mainClass>
  </properties>
  <dependencies>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-core</artifactId>
      <version>${project.version}</version>
    </dependency>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-web</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>
  <build>
    <pluginManagement>
      <plugins>
        <!-- We specify the Maven compiler plugin as we need to set it to Java 1.8 -->
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.1</version>
          <configuration>
            <source>1.8</source>
            <target>1.8</target>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
    <!--
    You only need the part below if you want to build your application into a fat executable jar.
    This is a jar that contains all the dependencies required to run it, so you can just run it with
    java -jar
    -->
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.3</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <manifestEntries>
                    <Main-Class>${exec.mainClass}</Main-Class>
                  </manifestEntries>
                </transformer>
                <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                  <resource>META-INF/services/io.vertx.core.spi.VerticleFactory</resource>
                </transformer>
              </transformers>
              <artifactSet>
              </artifactSet>
              <outputFile>${project.build.directory}/${project.artifactId}-${project.version}-fat.jar</outputFile>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.4.0</version>
        <executions>
          <execution>
            <!-- run the application using the fat jar -->
            <id>run-app</id>
            <goals>
              <goal>exec</goal>
            </goals>
            <configuration>
              <executable>java</executable>
              <arguments>
                <argument>-jar</argument>
                <argument>target/${project.artifactId}-${project.version}-fat.jar</argument>
              </arguments>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <profiles>
    <profile>
      <id>staging</id>
      <repositories>
        <repository>
          <id>staging</id>
          <url>https://oss.sonatype.org/content/repositories/iovertx-3868/</url>
        </repository>
      </repositories>
    </profile>
  </profiles>
</project>
vertx-greet/src/main/java/io/vertx/greet/GreetMain.java
New file
@@ -0,0 +1,24 @@
package io.vertx.greet;
import java.util.Optional;
public class GreetMain {
    public static void main(String[] args) {
        String GREETING = Optional.ofNullable(System.getenv("GREETING")).orElse("Hello World!").trim();
        String MAX_REQUESTS_PER_SECOND = Optional.ofNullable(System.getenv("MAX_REQUESTS_PER_SECOND")).orElse("0").trim();
        if (!MAX_REQUESTS_PER_SECOND.equals("0")) {
            System.out.println("Service will limit requests to " + MAX_REQUESTS_PER_SECOND + " req/second");
        }
        GreetServer server = new GreetServer(
            GREETING,
            Float.parseFloat(MAX_REQUESTS_PER_SECOND)
        );
        server.start();
    }
}
vertx-greet/src/main/java/io/vertx/greet/GreetServer.java
New file
@@ -0,0 +1,61 @@
package io.vertx.greet;
import java.time.Instant;
import io.vertx.core.Vertx;
import io.vertx.ext.web.Router;
public class GreetServer {
    private int counter;
    private float maxRequestsPerSecond;
    private String greeting;
    private Instant lastRequestInstant;
    private Vertx vertx;
    GreetServer(String greeting, float maxRequestsPerSecond) {
        this.greeting = greeting;
        this.maxRequestsPerSecond = maxRequestsPerSecond;
        lastRequestInstant = Instant.MIN;
        vertx = Vertx.vertx();
    }
    public void start() {
        vertx
            .createHttpServer()
            .requestHandler(defineRoutes())
            .listen(8080);
    }
    private Router defineRoutes() {
        Router router = Router.router(vertx);
        router.get("/").handler(req -> {
            Instant now = Instant.now();
            if (isRequestWithinRateLimits(now)) {
                req.response().end(greeting + "\n");
            } else {
                req.response().setStatusCode(503).end();
            }
            lastRequestInstant = now;
            counter++;
        });
        router.get("/counter").handler(req ->
            req.response().end(counter + "\n")
        );
        return router;
    }
    private boolean isRequestWithinRateLimits(Instant instant) {
        if (maxRequestsPerSecond == 0) {
            return true;
        }
        long millis = (long) (1000 / maxRequestsPerSecond);
        return lastRequestInstant.plusMillis(millis).isBefore(instant);
    }
}