├── .editorconfig ├── .github └── workflows │ └── maven.yml ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.adoc ├── assembly.xml ├── cover.pages ├── cover.pdf ├── intro ├── README.adoc └── images │ ├── event-bus.png │ ├── event-loop.png │ └── verticle-threading-config.png ├── jitpack.yml ├── mvnw ├── mvnw.cmd ├── outro └── README.adoc ├── pom.xml ├── render-html.sh ├── render-pdf.sh ├── step-1 ├── README.adoc ├── images │ ├── edit.png │ ├── index.png │ └── page.png ├── pom.xml ├── redeploy.bat ├── redeploy.sh └── src │ └── main │ ├── java │ └── io │ │ └── vertx │ │ └── guides │ │ └── wiki │ │ └── MainVerticle.java │ └── resources │ ├── logback.xml │ └── templates │ ├── footer.ftl │ ├── header.ftl │ ├── index.ftl │ └── page.ftl ├── step-10 ├── README.adoc ├── images │ └── edited-warning.png ├── pom.xml ├── redeploy.bat ├── redeploy.sh └── src │ └── main │ ├── java │ └── io │ │ └── vertx │ │ └── guides │ │ └── wiki │ │ ├── MainVerticle.java │ │ ├── database │ │ ├── ErrorCodes.java │ │ ├── SqlQuery.java │ │ ├── WikiDatabaseService.java │ │ ├── WikiDatabaseServiceImpl.java │ │ ├── WikiDatabaseVerticle.java │ │ └── package-info.java │ │ └── http │ │ └── HttpServerVerticle.java │ └── resources │ ├── db-queries.properties │ ├── logback.xml │ └── webroot │ ├── index.html │ └── wiki.js ├── step-2 ├── README.adoc ├── images │ ├── verticles-refactoring.key │ └── verticles-refactoring.png ├── pom.xml ├── redeploy.bat ├── redeploy.sh └── src │ └── main │ ├── java │ └── io │ │ └── vertx │ │ └── guides │ │ └── wiki │ │ ├── HttpServerVerticle.java │ │ ├── MainVerticle.java │ │ └── WikiDatabaseVerticle.java │ └── resources │ ├── db-queries.properties │ ├── logback.xml │ └── templates │ ├── footer.ftl │ ├── header.ftl │ ├── index.ftl │ └── page.ftl ├── step-3 ├── README.adoc ├── pom.xml ├── redeploy.bat ├── redeploy.sh └── src │ └── main │ ├── java │ └── io │ │ └── vertx │ │ └── guides │ │ └── wiki │ │ ├── MainVerticle.java │ │ ├── database │ │ ├── ErrorCodes.java │ │ ├── SqlQuery.java │ │ ├── WikiDatabaseService.java │ │ ├── WikiDatabaseServiceImpl.java │ │ ├── WikiDatabaseVerticle.java │ │ └── package-info.java │ │ └── http │ │ └── HttpServerVerticle.java │ └── resources │ ├── db-queries.properties │ ├── logback.xml │ └── templates │ ├── footer.ftl │ ├── header.ftl │ ├── index.ftl │ └── page.ftl ├── step-4 ├── README.adoc ├── pom.xml ├── redeploy.bat ├── redeploy.sh └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── vertx │ │ │ └── guides │ │ │ └── wiki │ │ │ ├── MainVerticle.java │ │ │ ├── database │ │ │ ├── ErrorCodes.java │ │ │ ├── SqlQuery.java │ │ │ ├── WikiDatabaseService.java │ │ │ ├── WikiDatabaseServiceImpl.java │ │ │ ├── WikiDatabaseVerticle.java │ │ │ └── package-info.java │ │ │ └── http │ │ │ └── HttpServerVerticle.java │ └── resources │ │ ├── db-queries.properties │ │ ├── logback.xml │ │ └── templates │ │ ├── footer.ftl │ │ ├── header.ftl │ │ ├── index.ftl │ │ └── page.ftl │ └── test │ └── java │ └── io │ └── vertx │ └── guides │ └── wiki │ ├── database │ └── WikiDatabaseVerticleTest.java │ └── http │ └── SampleHttpServerTest.java ├── step-5 ├── README.adoc ├── images │ ├── backup-button.png │ ├── backup-created.png │ └── snippet.png ├── pom.xml ├── redeploy.bat ├── redeploy.sh └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── vertx │ │ │ └── guides │ │ │ └── wiki │ │ │ ├── MainVerticle.java │ │ │ ├── database │ │ │ ├── ErrorCodes.java │ │ │ ├── SqlQuery.java │ │ │ ├── WikiDatabaseService.java │ │ │ ├── WikiDatabaseServiceImpl.java │ │ │ ├── WikiDatabaseVerticle.java │ │ │ └── package-info.java │ │ │ └── http │ │ │ └── HttpServerVerticle.java │ └── resources │ │ ├── db-queries.properties │ │ ├── logback.xml │ │ └── templates │ │ ├── footer.ftl │ │ ├── header.ftl │ │ ├── index.ftl │ │ └── page.ftl │ └── test │ └── java │ └── io │ └── vertx │ └── guides │ └── wiki │ ├── database │ └── WikiDatabaseVerticleTest.java │ └── http │ └── SampleHttpServerTest.java ├── step-6 ├── README.adoc ├── images │ └── webapi-httpie.png ├── pom.xml ├── redeploy.bat ├── redeploy.sh └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── vertx │ │ │ └── guides │ │ │ └── wiki │ │ │ ├── MainVerticle.java │ │ │ ├── database │ │ │ ├── ErrorCodes.java │ │ │ ├── SqlQuery.java │ │ │ ├── WikiDatabaseService.java │ │ │ ├── WikiDatabaseServiceImpl.java │ │ │ ├── WikiDatabaseVerticle.java │ │ │ └── package-info.java │ │ │ └── http │ │ │ └── HttpServerVerticle.java │ └── resources │ │ ├── db-queries.properties │ │ ├── logback.xml │ │ └── templates │ │ ├── footer.ftl │ │ ├── header.ftl │ │ ├── index.ftl │ │ └── page.ftl │ └── test │ └── java │ └── io │ └── vertx │ └── guides │ └── wiki │ ├── database │ └── WikiDatabaseVerticleTest.java │ └── http │ ├── ApiTest.java │ └── SampleHttpServerTest.java ├── step-7 ├── README.adoc ├── gen-keystore.sh ├── images │ ├── as-baz.png │ ├── as-root.png │ ├── invalid-cert.png │ └── login-form.png ├── keystore.jceks ├── pom.xml ├── redeploy.bat ├── redeploy.sh ├── server-keystore.jks └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── vertx │ │ │ └── guides │ │ │ └── wiki │ │ │ ├── DatabaseConstants.java │ │ │ ├── MainVerticle.java │ │ │ ├── database │ │ │ ├── ErrorCodes.java │ │ │ ├── SqlQuery.java │ │ │ ├── WikiDatabaseService.java │ │ │ ├── WikiDatabaseServiceImpl.java │ │ │ ├── WikiDatabaseVerticle.java │ │ │ └── package-info.java │ │ │ └── http │ │ │ ├── AuthInitializerVerticle.java │ │ │ └── HttpServerVerticle.java │ └── resources │ │ ├── auth-db-schema.sql │ │ ├── db-queries.properties │ │ ├── logback.xml │ │ └── templates │ │ ├── footer.ftl │ │ ├── header.ftl │ │ ├── index.ftl │ │ ├── login.ftl │ │ └── page.ftl │ └── test │ └── java │ └── io │ └── vertx │ └── guides │ └── wiki │ ├── database │ └── WikiDatabaseVerticleTest.java │ └── http │ ├── ApiTest.java │ └── SampleHttpServerTest.java ├── step-8 ├── README.adoc ├── gen-keystore.sh ├── pom.xml ├── redeploy.bat ├── redeploy.sh └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── vertx │ │ │ └── guides │ │ │ └── wiki │ │ │ ├── DatabaseConstants.java │ │ │ ├── MainVerticle.java │ │ │ ├── database │ │ │ ├── ErrorCodes.java │ │ │ ├── SqlQuery.java │ │ │ ├── WikiDatabaseService.java │ │ │ ├── WikiDatabaseServiceImpl.java │ │ │ ├── WikiDatabaseVerticle.java │ │ │ └── package-info.java │ │ │ └── http │ │ │ ├── AuthInitializerVerticle.java │ │ │ └── HttpServerVerticle.java │ └── resources │ │ ├── db-queries.properties │ │ ├── keystore.jceks │ │ ├── logback.xml │ │ ├── server-keystore.jks │ │ └── templates │ │ ├── footer.ftl │ │ ├── header.ftl │ │ ├── index.ftl │ │ ├── login.ftl │ │ └── page.ftl │ └── test │ └── java │ └── io │ └── vertx │ └── guides │ └── wiki │ ├── database │ └── WikiDatabaseVerticleTest.java │ └── http │ ├── ApiTest.java │ └── SampleHttpServerTest.java └── step-9 ├── README.adoc ├── images ├── edit-page.png └── new-page.png ├── pom.xml ├── redeploy.bat ├── redeploy.sh └── src └── main ├── java └── io │ └── vertx │ └── guides │ └── wiki │ ├── MainVerticle.java │ ├── database │ ├── ErrorCodes.java │ ├── SqlQuery.java │ ├── WikiDatabaseService.java │ ├── WikiDatabaseServiceImpl.java │ ├── WikiDatabaseVerticle.java │ └── package-info.java │ └── http │ └── HttpServerVerticle.java └── resources ├── db-queries.properties ├── logback.xml └── webroot ├── index.html └── wiki.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | end_of_line = lf 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | matrix: 12 | java: [1.8, 11] 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: Set up JDK ${{ matrix.java }} 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: ${{ matrix.java }} 20 | - name: Build with Maven and Java ${{ matrix.java }} 21 | run: mvn -B package --file pom.xml 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .settings/ 2 | .classpath 3 | .project 4 | hs_err_pid* 5 | target/ 6 | **/src/main/generated/ 7 | .idea/ 8 | db/ 9 | *.iws 10 | *.ipr 11 | *.iml 12 | .vertx 13 | guide.html 14 | guide.pdf 15 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem 'asciidoctor' 4 | 5 | gem 'asciidoctor-pdf' 6 | gem 'rouge' 7 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | Ascii85 (1.0.3) 5 | addressable (2.5.2) 6 | public_suffix (>= 2.0.2, < 4.0) 7 | afm (0.2.2) 8 | asciidoctor (1.5.8) 9 | asciidoctor-pdf (1.5.0.alpha.16) 10 | asciidoctor (>= 1.5.0) 11 | prawn (>= 1.3.0, < 2.3.0) 12 | prawn-icon (= 1.3.0) 13 | prawn-svg (>= 0.21.0, < 0.28.0) 14 | prawn-table (= 0.2.2) 15 | prawn-templates (>= 0.0.3, <= 0.1.1) 16 | safe_yaml (~> 1.0.4) 17 | thread_safe (~> 0.3.6) 18 | treetop (= 1.5.3) 19 | css_parser (1.6.0) 20 | addressable 21 | hashery (2.1.2) 22 | pdf-core (0.7.0) 23 | pdf-reader (2.1.0) 24 | Ascii85 (~> 1.0.0) 25 | afm (~> 0.2.1) 26 | hashery (~> 2.0) 27 | ruby-rc4 28 | ttfunk 29 | polyglot (0.3.5) 30 | prawn (2.2.2) 31 | pdf-core (~> 0.7.0) 32 | ttfunk (~> 1.5) 33 | prawn-icon (1.3.0) 34 | prawn (>= 1.1.0, < 3.0.0) 35 | prawn-svg (0.27.1) 36 | css_parser (~> 1.3) 37 | prawn (>= 0.11.1, < 3) 38 | prawn-table (0.2.2) 39 | prawn (>= 1.3.0, < 3.0.0) 40 | prawn-templates (0.1.1) 41 | pdf-reader (~> 2.0) 42 | prawn (~> 2.2) 43 | public_suffix (3.0.3) 44 | rouge (3.3.0) 45 | ruby-rc4 (0.1.5) 46 | safe_yaml (1.0.4) 47 | thread_safe (0.3.6) 48 | treetop (1.5.3) 49 | polyglot (~> 0.3) 50 | ttfunk (1.5.1) 51 | 52 | PLATFORMS 53 | ruby 54 | 55 | DEPENDENCIES 56 | asciidoctor 57 | asciidoctor-pdf 58 | rouge 59 | 60 | BUNDLED WITH 61 | 1.17.1 62 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = A gentle guide to asynchronous programming with Eclipse Vert.x for Java developers 2 | Julien Ponge ; Thomas Segismont ; Julien Viet 3 | v1.5.0 2019/07/25 4 | :doctype: book 5 | 6 | ifdef::env-github[] 7 | image:https://github.com/vert-x3/vertx-guide-for-java-devs/workflows/Java%20CI/badge.svg?branch=3.8["Build status"] 8 | endif::[] 9 | 10 | :leveloffset: +1 11 | 12 | [WARNING] 13 | ==== 14 | This guide is no longer maintained. 15 | It targets Vert.x 3 and uses some modules that are no longer recommended (e.g. Auth Shiro). 16 | 17 | For Vert.x 4, you could get a copy of the https://www.manning.com/books/vertx-in-action[Vert.x in Action] book. 18 | ==== 19 | 20 | ifdef::rendered-pdf-link[] 21 | NOTE: This document is also link:{rendered-pdf-link}[available as a PDF]. 22 | endif::[] 23 | 24 | .Acknowledgements 25 | This document has received contributions from Arnaud Esteve, Marc Paquette, Ashley Bye, Ger-Jan te Dorsthorst, Htet Aung Shine, Bruno Guimarães 26 | and others. 27 | 28 | :imagesdir: intro 29 | include::intro/README.adoc[] 30 | 31 | :imagesdir: step-1 32 | include::step-1/README.adoc[] 33 | 34 | :imagesdir: step-2 35 | include::step-2/README.adoc[] 36 | 37 | :imagesdir: step-3 38 | include::step-3/README.adoc[] 39 | 40 | :imagesdir: step-4 41 | include::step-4/README.adoc[] 42 | 43 | :imagesdir: step-5 44 | include::step-5/README.adoc[] 45 | 46 | :imagesdir: step-6 47 | include::step-6/README.adoc[] 48 | 49 | :imagesdir: step-7 50 | include::step-7/README.adoc[] 51 | 52 | :imagesdir: step-8 53 | include::step-8/README.adoc[] 54 | 55 | :imagesdir: step-9 56 | include::step-9/README.adoc[] 57 | 58 | :imagesdir: step-10 59 | include::step-10/README.adoc[] 60 | 61 | :imagesdir: outro 62 | include::outro/README.adoc[] 63 | 64 | :leveloffset: -1 65 | -------------------------------------------------------------------------------- /assembly.xml: -------------------------------------------------------------------------------- 1 | 4 | docs 5 | 6 | zip 7 | 8 | false 9 | 10 | 11 | 12 | pom.xml 13 | cover.pdf 14 | intro/README.adoc 15 | intro/images/**/* 16 | outro/README.adoc 17 | outro/images/**/* 18 | step-*/README.adoc 19 | step-*/pom.xml 20 | step-*/gen-keystore.sh 21 | step-*/src/**/* 22 | step-*/images/**/* 23 | 24 | 25 | 26 | 27 | 28 | README.adoc 29 | index.adoc 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /cover.pages: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/cover.pages -------------------------------------------------------------------------------- /cover.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/cover.pdf -------------------------------------------------------------------------------- /intro/images/event-bus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/intro/images/event-bus.png -------------------------------------------------------------------------------- /intro/images/event-loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/intro/images/event-loop.png -------------------------------------------------------------------------------- /intro/images/verticle-threading-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/intro/images/verticle-threading-config.png -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - oraclejdk8 3 | install: 4 | - mvn clean install -N 5 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 22 | 4.0.0 23 | 24 | io.vertx 25 | guide-for-java-devs 26 | 1.5.0 27 | 28 | pom 29 | 30 | 31 | step-1 32 | step-2 33 | step-3 34 | step-4 35 | step-5 36 | step-6 37 | step-7 38 | step-8 39 | step-9 40 | step-10 41 | 42 | 43 | 44 | 45 | 46 | maven-assembly-plugin 47 | 2.6 48 | 49 | assembly.xml 50 | 51 | 52 | 53 | package 54 | 55 | single 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /render-html.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | bundle exec asciidoctor \ 3 | -b html \ 4 | -o guide.html \ 5 | -a icons=font \ 6 | -a source-highlighter=highlight.js \ 7 | -a data-uri \ 8 | -a toc=left \ 9 | -a toclevels=4 \ 10 | -a sectnums \ 11 | README.adoc 12 | -------------------------------------------------------------------------------- /render-pdf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | bundle exec asciidoctor-pdf \ 3 | -o guide.pdf \ 4 | -a icons=font \ 5 | -a source-highlighter=rouge \ 6 | -a autofit-option \ 7 | -a toc \ 8 | -a toclevels=4 \ 9 | -a sectnums \ 10 | -a front-cover-image=cover.pdf \ 11 | README.adoc 12 | -------------------------------------------------------------------------------- /step-1/images/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-1/images/edit.png -------------------------------------------------------------------------------- /step-1/images/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-1/images/index.png -------------------------------------------------------------------------------- /step-1/images/page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-1/images/page.png -------------------------------------------------------------------------------- /step-1/redeploy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SET LAUNCHER="io.vertx.core.Launcher" 4 | SET VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | SET CMD="mvn compile" 6 | SET VERTX_CMD="run" 7 | SET CMD_LINE_ARGS=%* 8 | 9 | call mvn compile dependency:copy-dependencies 10 | 11 | java -cp "target\dependency\*;target\classes" %LAUNCHER% %VERTX_CMD% %VERTICLE% --redeploy="src\main\**\*" --on-redeploy=%CMD% --launcher-class=%LAUNCHER% %CMD_LINE_ARGS% --java-opts="-Dhsqldb.reconfig_logging=false" 12 | -------------------------------------------------------------------------------- /step-1/redeploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export LAUNCHER="io.vertx.core.Launcher" 4 | export VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | export CMD="mvn compile" 6 | export VERTX_CMD="run" 7 | 8 | mvn compile dependency:copy-dependencies 9 | java \ 10 | -cp $(echo target/dependency/*.jar | tr ' ' ':'):"target/classes" \ 11 | $LAUNCHER $VERTX_CMD $VERTICLE \ 12 | --redeploy="src/main/**/*" --on-redeploy=$CMD \ 13 | --launcher-class=$LAUNCHER \ 14 | --java-opts="-Dhsqldb.reconfig_logging=false" \ 15 | $@ 16 | -------------------------------------------------------------------------------- /step-1/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /step-1/src/main/resources/templates/footer.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /step-1/src/main/resources/templates/header.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | ${title} | A Sample Vert.x-powered Wiki 12 | 13 | 14 | 15 |
16 | -------------------------------------------------------------------------------- /step-1/src/main/resources/templates/index.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 |
7 |
8 |
9 | 10 |
11 | 12 |
13 |
14 |

${title}

15 |
16 | 17 |
18 | <#list pages> 19 |

Pages:

20 |
    21 | <#items as page> 22 |
  • ${page}
  • 23 | 24 |
25 | <#else> 26 |

The wiki is currently empty!

27 | 28 |
29 | 30 |
31 | 32 | <#include "footer.ftl"> 33 | -------------------------------------------------------------------------------- /step-1/src/main/resources/templates/page.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 | 7 | Home 8 | 10 | 11 |

12 | { 13 | ${title} 14 | } 15 |

16 |
17 | 18 |
19 | ${content} 20 |
21 | 22 |
23 |
24 |
25 | 26 | 27 | 28 | 29 |
30 | 31 | <#if id != -1> 32 | 33 | 34 |
35 |
36 | 37 |
38 |
39 |

Rendered: ${timestamp}

40 |
41 | 42 |
43 | 44 | <#include "footer.ftl"> 45 | -------------------------------------------------------------------------------- /step-10/images/edited-warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-10/images/edited-warning.png -------------------------------------------------------------------------------- /step-10/redeploy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SET LAUNCHER="io.vertx.core.Launcher" 4 | SET VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | SET CMD="mvn compile" 6 | SET VERTX_CMD="run" 7 | SET CMD_LINE_ARGS=%* 8 | 9 | call mvn compile dependency:copy-dependencies 10 | 11 | java -cp "target\dependency\*;target\classes" %LAUNCHER% %VERTX_CMD% %VERTICLE% --redeploy="src\main\**\*" --on-redeploy=%CMD% --launcher-class=%LAUNCHER% %CMD_LINE_ARGS% --java-opts="-Dhsqldb.reconfig_logging=false" 12 | -------------------------------------------------------------------------------- /step-10/redeploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export LAUNCHER="io.vertx.core.Launcher" 4 | export VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | export CMD="mvn compile" 6 | export VERTX_CMD="run" 7 | 8 | mvn compile dependency:copy-dependencies 9 | java \ 10 | -cp $(echo target/dependency/*.jar | tr ' ' ':'):"target/classes" \ 11 | $LAUNCHER $VERTX_CMD $VERTICLE \ 12 | --redeploy="src/main/**/*" --on-redeploy=$CMD \ 13 | --launcher-class=$LAUNCHER \ 14 | --java-opts="-Dhsqldb.reconfig_logging=false" \ 15 | $@ 16 | -------------------------------------------------------------------------------- /step-10/src/main/java/io/vertx/guides/wiki/MainVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki; 19 | 20 | import io.reactivex.Single; 21 | import io.vertx.core.DeploymentOptions; 22 | import io.vertx.core.Promise; 23 | import io.vertx.reactivex.core.AbstractVerticle; 24 | 25 | /** 26 | * @author Julien Ponge 27 | */ 28 | public class MainVerticle extends AbstractVerticle { 29 | 30 | @Override 31 | public void start(Promise promise) throws Exception { 32 | 33 | Single dbVerticleDeployment = vertx.rxDeployVerticle("io.vertx.guides.wiki.database.WikiDatabaseVerticle"); 34 | 35 | DeploymentOptions opts = new DeploymentOptions().setInstances(2); 36 | dbVerticleDeployment 37 | .flatMap(id -> vertx.rxDeployVerticle("io.vertx.guides.wiki.http.HttpServerVerticle", opts)) 38 | .subscribe(id -> promise.complete(), promise::fail); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /step-10/src/main/java/io/vertx/guides/wiki/database/ErrorCodes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | public enum ErrorCodes { 24 | NO_ACTION_SPECIFIED, 25 | BAD_ACTION, 26 | DB_ERROR 27 | } 28 | -------------------------------------------------------------------------------- /step-10/src/main/java/io/vertx/guides/wiki/database/SqlQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | enum SqlQuery { 24 | CREATE_PAGES_TABLE, 25 | ALL_PAGES, 26 | GET_PAGE, 27 | CREATE_PAGE, 28 | SAVE_PAGE, 29 | DELETE_PAGE, 30 | ALL_PAGES_DATA, 31 | GET_PAGE_BY_ID 32 | } 33 | -------------------------------------------------------------------------------- /step-10/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.codegen.annotations.Fluent; 21 | import io.vertx.codegen.annotations.GenIgnore; 22 | import io.vertx.codegen.annotations.ProxyGen; 23 | import io.vertx.codegen.annotations.VertxGen; 24 | import io.vertx.core.AsyncResult; 25 | import io.vertx.core.Handler; 26 | import io.vertx.core.Vertx; 27 | import io.vertx.core.json.JsonArray; 28 | import io.vertx.core.json.JsonObject; 29 | import io.vertx.ext.jdbc.JDBCClient; 30 | 31 | import java.util.HashMap; 32 | import java.util.List; 33 | 34 | /** 35 | * @author Julien Ponge 36 | */ 37 | @ProxyGen 38 | @VertxGen 39 | public interface WikiDatabaseService { 40 | 41 | @GenIgnore 42 | static WikiDatabaseService create(JDBCClient dbClient, HashMap sqlQueries, Handler> readyHandler) { 43 | return new WikiDatabaseServiceImpl(dbClient, sqlQueries, readyHandler); 44 | } 45 | 46 | @GenIgnore 47 | static io.vertx.guides.wiki.database.reactivex.WikiDatabaseService createProxy(Vertx vertx, String address) { 48 | return new io.vertx.guides.wiki.database.reactivex.WikiDatabaseService(new WikiDatabaseServiceVertxEBProxy(vertx, address)); 49 | } 50 | 51 | @Fluent 52 | WikiDatabaseService fetchAllPages(Handler> resultHandler); 53 | 54 | @Fluent 55 | WikiDatabaseService fetchPage(String name, Handler> resultHandler); 56 | 57 | @Fluent 58 | WikiDatabaseService fetchPageById(int id, Handler> resultHandler); 59 | 60 | @Fluent 61 | WikiDatabaseService createPage(String title, String markdown, Handler> resultHandler); 62 | 63 | @Fluent 64 | WikiDatabaseService savePage(int id, String markdown, Handler> resultHandler); 65 | 66 | @Fluent 67 | WikiDatabaseService deletePage(int id, Handler> resultHandler); 68 | 69 | @Fluent 70 | WikiDatabaseService fetchAllPagesData(Handler>> resultHandler); 71 | } 72 | -------------------------------------------------------------------------------- /step-10/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.Promise; 22 | import io.vertx.core.json.JsonObject; 23 | import io.vertx.ext.jdbc.JDBCClient; 24 | import io.vertx.serviceproxy.ServiceBinder; 25 | 26 | import java.io.FileInputStream; 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.util.HashMap; 30 | import java.util.Properties; 31 | 32 | /** 33 | * @author Julien Ponge 34 | */ 35 | public class WikiDatabaseVerticle extends AbstractVerticle { 36 | 37 | public static final String CONFIG_WIKIDB_JDBC_URL = "wikidb.jdbc.url"; 38 | public static final String CONFIG_WIKIDB_JDBC_DRIVER_CLASS = "wikidb.jdbc.driver_class"; 39 | public static final String CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE = "wikidb.jdbc.max_pool_size"; 40 | public static final String CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE = "wikidb.sqlqueries.resource.file"; 41 | public static final String CONFIG_WIKIDB_QUEUE = "wikidb.queue"; 42 | 43 | @Override 44 | public void start(Promise promise) throws Exception { 45 | 46 | HashMap sqlQueries = loadSqlQueries(); 47 | 48 | JDBCClient dbClient = JDBCClient.createShared(vertx, new JsonObject() 49 | .put("url", config().getString(CONFIG_WIKIDB_JDBC_URL, "jdbc:hsqldb:file:db/wiki")) 50 | .put("driver_class", config().getString(CONFIG_WIKIDB_JDBC_DRIVER_CLASS, "org.hsqldb.jdbcDriver")) 51 | .put("max_pool_size", config().getInteger(CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE, 30))); 52 | 53 | WikiDatabaseService.create(dbClient, sqlQueries, ready -> { 54 | if (ready.succeeded()) { 55 | ServiceBinder binder = new ServiceBinder(vertx); 56 | binder.setAddress(CONFIG_WIKIDB_QUEUE).register(WikiDatabaseService.class, ready.result()); 57 | promise.complete(); 58 | } else { 59 | promise.fail(ready.cause()); 60 | } 61 | }); 62 | } 63 | 64 | /* 65 | * Note: this uses blocking APIs, but data is small... 66 | */ 67 | private HashMap loadSqlQueries() throws IOException { 68 | 69 | String queriesFile = config().getString(CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE); 70 | InputStream queriesInputStream; 71 | if (queriesFile != null) { 72 | queriesInputStream = new FileInputStream(queriesFile); 73 | } else { 74 | queriesInputStream = getClass().getResourceAsStream("/db-queries.properties"); 75 | } 76 | 77 | Properties queriesProps = new Properties(); 78 | queriesProps.load(queriesInputStream); 79 | queriesInputStream.close(); 80 | 81 | HashMap sqlQueries = new HashMap<>(); 82 | sqlQueries.put(SqlQuery.CREATE_PAGES_TABLE, queriesProps.getProperty("create-pages-table")); 83 | sqlQueries.put(SqlQuery.ALL_PAGES, queriesProps.getProperty("all-pages")); 84 | sqlQueries.put(SqlQuery.GET_PAGE, queriesProps.getProperty("get-page")); 85 | sqlQueries.put(SqlQuery.CREATE_PAGE, queriesProps.getProperty("create-page")); 86 | sqlQueries.put(SqlQuery.SAVE_PAGE, queriesProps.getProperty("save-page")); 87 | sqlQueries.put(SqlQuery.DELETE_PAGE, queriesProps.getProperty("delete-page")); 88 | sqlQueries.put(SqlQuery.ALL_PAGES_DATA, queriesProps.getProperty("all-pages-data")); 89 | sqlQueries.put(SqlQuery.GET_PAGE_BY_ID, queriesProps.getProperty("get-page-by-id")); 90 | return sqlQueries; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /step-10/src/main/java/io/vertx/guides/wiki/database/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @author Julien Ponge 20 | */ 21 | @ModuleGen(groupPackage = "io.vertx.guides.wiki.database", name = "wiki-database") 22 | package io.vertx.guides.wiki.database; 23 | 24 | import io.vertx.codegen.annotations.ModuleGen; 25 | -------------------------------------------------------------------------------- /step-10/src/main/resources/db-queries.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | # Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | create-pages-table=create table if not exists Pages (Id integer identity primary key, Name varchar(255) unique, Content clob) 18 | get-page=select Id, Content from Pages where Name = ? 19 | get-page-by-id=select * from Pages where Id = ? 20 | create-page=insert into Pages values (NULL, ?, ?) 21 | save-page=update Pages set Content = ? where Id = ? 22 | all-pages=select Name from Pages 23 | delete-page=delete from Pages where Id = ? 24 | all-pages-data=select * from Pages 25 | -------------------------------------------------------------------------------- /step-10/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /step-2/images/verticles-refactoring.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-2/images/verticles-refactoring.key -------------------------------------------------------------------------------- /step-2/images/verticles-refactoring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-2/images/verticles-refactoring.png -------------------------------------------------------------------------------- /step-2/redeploy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SET LAUNCHER="io.vertx.core.Launcher" 4 | SET VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | SET CMD="mvn compile" 6 | SET VERTX_CMD="run" 7 | SET CMD_LINE_ARGS=%* 8 | 9 | call mvn compile dependency:copy-dependencies 10 | 11 | java -cp "target\dependency\*;target\classes" %LAUNCHER% %VERTX_CMD% %VERTICLE% --redeploy="src\main\**\*" --on-redeploy=%CMD% --launcher-class=%LAUNCHER% %CMD_LINE_ARGS% --java-opts="-Dhsqldb.reconfig_logging=false" 12 | -------------------------------------------------------------------------------- /step-2/redeploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export LAUNCHER="io.vertx.core.Launcher" 4 | export VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | export CMD="mvn compile" 6 | export VERTX_CMD="run" 7 | 8 | mvn compile dependency:copy-dependencies 9 | java \ 10 | -cp $(echo target/dependency/*.jar | tr ' ' ':'):"target/classes" \ 11 | $LAUNCHER $VERTX_CMD $VERTICLE \ 12 | --redeploy="src/main/**/*" --on-redeploy=$CMD \ 13 | --launcher-class=$LAUNCHER \ 14 | --java-opts="-Dhsqldb.reconfig_logging=false" \ 15 | $@ 16 | -------------------------------------------------------------------------------- /step-2/src/main/java/io/vertx/guides/wiki/MainVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.DeploymentOptions; 22 | import io.vertx.core.Promise; 23 | 24 | /** 25 | * @author Julien Ponge 26 | */ 27 | // tag::main[] 28 | public class MainVerticle extends AbstractVerticle { 29 | 30 | @Override 31 | public void start(Promise promise) throws Exception { 32 | 33 | Promise dbVerticleDeployment = Promise.promise(); // <1> 34 | vertx.deployVerticle(new WikiDatabaseVerticle(), dbVerticleDeployment); // <2> 35 | 36 | dbVerticleDeployment.future().compose(id -> { // <3> 37 | 38 | Promise httpVerticleDeployment = Promise.promise(); 39 | vertx.deployVerticle( 40 | "io.vertx.guides.wiki.HttpServerVerticle", // <4> 41 | new DeploymentOptions().setInstances(2), // <5> 42 | httpVerticleDeployment); 43 | 44 | return httpVerticleDeployment.future(); // <6> 45 | 46 | }).setHandler(ar -> { // <7> 47 | if (ar.succeeded()) { 48 | promise.complete(); 49 | } else { 50 | promise.fail(ar.cause()); 51 | } 52 | }); 53 | } 54 | } 55 | // end::main[] 56 | -------------------------------------------------------------------------------- /step-2/src/main/resources/db-queries.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | # Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # // tag::queries[] 19 | 20 | create-pages-table=create table if not exists Pages (Id integer identity primary key, Name varchar(255) unique, Content clob) 21 | get-page=select Id, Content from Pages where Name = ? 22 | create-page=insert into Pages values (NULL, ?, ?) 23 | save-page=update Pages set Content = ? where Id = ? 24 | all-pages=select Name from Pages 25 | delete-page=delete from Pages where Id = ? 26 | 27 | # // end::queries[] -------------------------------------------------------------------------------- /step-2/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /step-2/src/main/resources/templates/footer.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /step-2/src/main/resources/templates/header.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | ${title} | A Sample Vert.x-powered Wiki 12 | 13 | 14 | 15 |
16 | -------------------------------------------------------------------------------- /step-2/src/main/resources/templates/index.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 |
7 |
8 |
9 | 10 |
11 | 12 |
13 |
14 |

${title}

15 |
16 | 17 |
18 | <#list pages> 19 |

Pages:

20 |
    21 | <#items as page> 22 |
  • ${page}
  • 23 | 24 |
25 | <#else> 26 |

The wiki is currently empty!

27 | 28 |
29 | 30 |
31 | 32 | <#include "footer.ftl"> 33 | -------------------------------------------------------------------------------- /step-2/src/main/resources/templates/page.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 | 7 | Home 8 | 10 | 11 |

12 | { 13 | ${title} 14 | } 15 |

16 |
17 | 18 |
19 | ${content} 20 |
21 | 22 |
23 |
24 |
25 | 26 | 27 | 28 | 29 |
30 | 31 | <#if id != -1> 32 | 33 | 34 |
35 |
36 | 37 |
38 |
39 |

Rendered: ${timestamp}

40 |
41 | 42 |
43 | 44 | <#include "footer.ftl"> 45 | -------------------------------------------------------------------------------- /step-3/redeploy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SET LAUNCHER="io.vertx.core.Launcher" 4 | SET VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | SET CMD="mvn compile" 6 | SET VERTX_CMD="run" 7 | SET CMD_LINE_ARGS=%* 8 | 9 | call mvn compile dependency:copy-dependencies 10 | 11 | java -cp "target\dependency\*;target\classes" %LAUNCHER% %VERTX_CMD% %VERTICLE% --redeploy="src\main\**\*" --on-redeploy=%CMD% --launcher-class=%LAUNCHER% %CMD_LINE_ARGS% --java-opts="-Dhsqldb.reconfig_logging=false" 12 | -------------------------------------------------------------------------------- /step-3/redeploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export LAUNCHER="io.vertx.core.Launcher" 4 | export VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | export CMD="mvn compile" 6 | export VERTX_CMD="run" 7 | 8 | mvn compile dependency:copy-dependencies 9 | java \ 10 | -cp $(echo target/dependency/*.jar | tr ' ' ':'):"target/classes" \ 11 | $LAUNCHER $VERTX_CMD $VERTICLE \ 12 | --redeploy="src/main/**/*" --on-redeploy=$CMD \ 13 | --launcher-class=$LAUNCHER \ 14 | --java-opts="-Dhsqldb.reconfig_logging=false" \ 15 | $@ 16 | -------------------------------------------------------------------------------- /step-3/src/main/java/io/vertx/guides/wiki/MainVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.DeploymentOptions; 22 | import io.vertx.core.Promise; 23 | import io.vertx.guides.wiki.database.WikiDatabaseVerticle; 24 | 25 | /** 26 | * @author Julien Ponge 27 | */ 28 | public class MainVerticle extends AbstractVerticle { 29 | 30 | @Override 31 | public void start(Promise promise) throws Exception { 32 | 33 | Promise dbVerticleDeployment = Promise.promise(); 34 | vertx.deployVerticle(new WikiDatabaseVerticle(), dbVerticleDeployment); 35 | 36 | dbVerticleDeployment.future().compose(id -> { 37 | 38 | Promise httpVerticleDeployment = Promise.promise(); 39 | vertx.deployVerticle( 40 | "io.vertx.guides.wiki.http.HttpServerVerticle", 41 | new DeploymentOptions().setInstances(2), 42 | httpVerticleDeployment); 43 | 44 | return httpVerticleDeployment.future(); 45 | 46 | }).setHandler(ar -> { 47 | if (ar.succeeded()) { 48 | promise.complete(); 49 | } else { 50 | promise.fail(ar.cause()); 51 | } 52 | }); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /step-3/src/main/java/io/vertx/guides/wiki/database/ErrorCodes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | public enum ErrorCodes { 24 | NO_ACTION_SPECIFIED, 25 | BAD_ACTION, 26 | DB_ERROR 27 | } 28 | -------------------------------------------------------------------------------- /step-3/src/main/java/io/vertx/guides/wiki/database/SqlQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | enum SqlQuery { 24 | CREATE_PAGES_TABLE, 25 | ALL_PAGES, 26 | GET_PAGE, 27 | CREATE_PAGE, 28 | SAVE_PAGE, 29 | DELETE_PAGE 30 | } 31 | -------------------------------------------------------------------------------- /step-3/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.codegen.annotations.Fluent; 21 | import io.vertx.codegen.annotations.GenIgnore; 22 | import io.vertx.codegen.annotations.ProxyGen; 23 | import io.vertx.codegen.annotations.VertxGen; 24 | import io.vertx.core.AsyncResult; 25 | import io.vertx.core.Handler; 26 | import io.vertx.core.Vertx; 27 | import io.vertx.core.json.JsonArray; 28 | import io.vertx.core.json.JsonObject; 29 | import io.vertx.ext.jdbc.JDBCClient; 30 | 31 | import java.util.HashMap; 32 | 33 | /** 34 | * @author Julien Ponge 35 | */ 36 | // tag::interface[] 37 | @ProxyGen 38 | @VertxGen 39 | public interface WikiDatabaseService { 40 | 41 | @Fluent 42 | WikiDatabaseService fetchAllPages(Handler> resultHandler); 43 | 44 | @Fluent 45 | WikiDatabaseService fetchPage(String name, Handler> resultHandler); 46 | 47 | @Fluent 48 | WikiDatabaseService createPage(String title, String markdown, Handler> resultHandler); 49 | 50 | @Fluent 51 | WikiDatabaseService savePage(int id, String markdown, Handler> resultHandler); 52 | 53 | @Fluent 54 | WikiDatabaseService deletePage(int id, Handler> resultHandler); 55 | 56 | // (...) 57 | // end::interface[] 58 | 59 | // tag::create[] 60 | @GenIgnore 61 | static WikiDatabaseService create(JDBCClient dbClient, HashMap sqlQueries, Handler> readyHandler) { 62 | return new WikiDatabaseServiceImpl(dbClient, sqlQueries, readyHandler); 63 | } 64 | // end::create[] 65 | 66 | // tag::proxy[] 67 | @GenIgnore 68 | static WikiDatabaseService createProxy(Vertx vertx, String address) { 69 | return new WikiDatabaseServiceVertxEBProxy(vertx, address); 70 | } 71 | // end::proxy[] 72 | } 73 | -------------------------------------------------------------------------------- /step-3/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.Promise; 22 | import io.vertx.core.json.JsonObject; 23 | import io.vertx.ext.jdbc.JDBCClient; 24 | import io.vertx.serviceproxy.ServiceBinder; 25 | 26 | import java.io.FileInputStream; 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.util.HashMap; 30 | import java.util.Properties; 31 | 32 | /** 33 | * @author Julien Ponge 34 | */ 35 | // tag::dbverticle[] 36 | public class WikiDatabaseVerticle extends AbstractVerticle { 37 | 38 | public static final String CONFIG_WIKIDB_JDBC_URL = "wikidb.jdbc.url"; 39 | public static final String CONFIG_WIKIDB_JDBC_DRIVER_CLASS = "wikidb.jdbc.driver_class"; 40 | public static final String CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE = "wikidb.jdbc.max_pool_size"; 41 | public static final String CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE = "wikidb.sqlqueries.resource.file"; 42 | public static final String CONFIG_WIKIDB_QUEUE = "wikidb.queue"; 43 | 44 | @Override 45 | public void start(Promise promise) throws Exception { 46 | 47 | HashMap sqlQueries = loadSqlQueries(); 48 | 49 | JDBCClient dbClient = JDBCClient.createShared(vertx, new JsonObject() 50 | .put("url", config().getString(CONFIG_WIKIDB_JDBC_URL, "jdbc:hsqldb:file:db/wiki")) 51 | .put("driver_class", config().getString(CONFIG_WIKIDB_JDBC_DRIVER_CLASS, "org.hsqldb.jdbcDriver")) 52 | .put("max_pool_size", config().getInteger(CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE, 30))); 53 | 54 | WikiDatabaseService.create(dbClient, sqlQueries, ready -> { 55 | if (ready.succeeded()) { 56 | ServiceBinder binder = new ServiceBinder(vertx); 57 | binder 58 | .setAddress(CONFIG_WIKIDB_QUEUE) 59 | .register(WikiDatabaseService.class, ready.result()); // <1> 60 | promise.complete(); 61 | } else { 62 | promise.fail(ready.cause()); 63 | } 64 | }); 65 | } 66 | 67 | /* 68 | * Note: this uses blocking APIs, but data is small... 69 | */ 70 | private HashMap loadSqlQueries() throws IOException { 71 | 72 | String queriesFile = config().getString(CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE); 73 | InputStream queriesInputStream; 74 | if (queriesFile != null) { 75 | queriesInputStream = new FileInputStream(queriesFile); 76 | } else { 77 | queriesInputStream = getClass().getResourceAsStream("/db-queries.properties"); 78 | } 79 | 80 | Properties queriesProps = new Properties(); 81 | queriesProps.load(queriesInputStream); 82 | queriesInputStream.close(); 83 | 84 | HashMap sqlQueries = new HashMap<>(); 85 | sqlQueries.put(SqlQuery.CREATE_PAGES_TABLE, queriesProps.getProperty("create-pages-table")); 86 | sqlQueries.put(SqlQuery.ALL_PAGES, queriesProps.getProperty("all-pages")); 87 | sqlQueries.put(SqlQuery.GET_PAGE, queriesProps.getProperty("get-page")); 88 | sqlQueries.put(SqlQuery.CREATE_PAGE, queriesProps.getProperty("create-page")); 89 | sqlQueries.put(SqlQuery.SAVE_PAGE, queriesProps.getProperty("save-page")); 90 | sqlQueries.put(SqlQuery.DELETE_PAGE, queriesProps.getProperty("delete-page")); 91 | return sqlQueries; 92 | } 93 | } 94 | // end::dbverticle[] 95 | -------------------------------------------------------------------------------- /step-3/src/main/java/io/vertx/guides/wiki/database/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @author Julien Ponge 20 | */ 21 | // tag::module[] 22 | @ModuleGen(groupPackage = "io.vertx.guides.wiki.database", name = "wiki-database") 23 | package io.vertx.guides.wiki.database; 24 | 25 | import io.vertx.codegen.annotations.ModuleGen; 26 | // end::module[] -------------------------------------------------------------------------------- /step-3/src/main/resources/db-queries.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | # Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | create-pages-table=create table if not exists Pages (Id integer identity primary key, Name varchar(255) unique, Content clob) 19 | get-page=select Id, Content from Pages where Name = ? 20 | create-page=insert into Pages values (NULL, ?, ?) 21 | save-page=update Pages set Content = ? where Id = ? 22 | all-pages=select Name from Pages 23 | delete-page=delete from Pages where Id = ? 24 | -------------------------------------------------------------------------------- /step-3/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /step-3/src/main/resources/templates/footer.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /step-3/src/main/resources/templates/header.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | ${title} | A Sample Vert.x-powered Wiki 12 | 13 | 14 | 15 |
16 | -------------------------------------------------------------------------------- /step-3/src/main/resources/templates/index.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 |
7 |
8 |
9 | 10 |
11 | 12 |
13 |
14 |

${title}

15 |
16 | 17 |
18 | <#list pages> 19 |

Pages:

20 |
    21 | <#items as page> 22 |
  • ${page}
  • 23 | 24 |
25 | <#else> 26 |

The wiki is currently empty!

27 | 28 |
29 | 30 |
31 | 32 | <#include "footer.ftl"> 33 | -------------------------------------------------------------------------------- /step-3/src/main/resources/templates/page.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 | 7 | Home 8 | 10 | 11 |

12 | { 13 | ${title} 14 | } 15 |

16 |
17 | 18 |
19 | ${content} 20 |
21 | 22 |
23 |
24 |
25 | 26 | 27 | 28 | 29 |
30 | 31 | <#if id != -1> 32 | 33 | 34 |
35 |
36 | 37 |
38 |
39 |

Rendered: ${timestamp}

40 |
41 | 42 |
43 | 44 | <#include "footer.ftl"> 45 | -------------------------------------------------------------------------------- /step-4/README.adoc: -------------------------------------------------------------------------------- 1 | = Testing Vert.x code 2 | 3 | TIP: The corresponding source code is in the `step-4` folder of the guide repository. 4 | 5 | Up to this point we have been developing the wiki implementation without testing. 6 | This is of course not a good practice, so let us see how to write tests for Vert.x code. 7 | 8 | == Getting started 9 | 10 | The `vertx-unit` module provides utilities to test asynchronous operations in Vert.x. 11 | Aside from that, you can use your testing framework of choice like JUnit. 12 | 13 | With JUnit, the required Maven dependencies are the following: 14 | 15 | [source,xml,indent=0] 16 | ---- 17 | include::pom.xml[tags=test-deps] 18 | ---- 19 | 20 | JUnit tests need to be annotated with the `VertxUnitRunner` runner to use the `vertx-unit` features: 21 | 22 | [source,java] 23 | ---- 24 | @RunWith(VertxUnitRunner.class) 25 | public class SomeTest { 26 | // (...) 27 | } 28 | ---- 29 | 30 | With that runner, JUnit test and life-cycle methods accept a `TestContext` argument. 31 | This object provides access to basic assertions, a context to store data, and several async-oriented helpers that we will see in this section. 32 | 33 | To illustrate that, let us consider an asynchronous scenario where we want to check that a timer task has been called once, and that a periodic task has been called 3 times. 34 | Since that code is asynchronous, the test method exits before the test completes, so making that test pass or fail also needs to be done in an asynchronous fashion: 35 | 36 | [source,java,indent=0] 37 | ---- 38 | include::src/test/java/io/vertx/guides/wiki/database/WikiDatabaseVerticleTest.java[tags=async-basic] 39 | ---- 40 | <1> `TestContext` is a parameter provided by the runner. 41 | <2> Since we are in unit tests, we need to create a Vert.x context. 42 | <3> Here is an example of a basic `TestContext` assertion. 43 | <4> We get a first `Async` object that can later be completed (or failed). 44 | <5> This `Async` object works as a countdown that completes successfully after 3 calls. 45 | <6> We complete when the timer fires. 46 | <7> Each periodic task tick triggers a countdown. The test passes when all `Async` objects have completed. 47 | <8> There is a default (long) timeout for asynchronous test cases, but it can be overridden through the JUnit `@Test` annotation. 48 | 49 | == Testing database operations 50 | 51 | The database service is a good fit for writing tests. 52 | 53 | We first need to deploy the database verticle. 54 | We will configure the JDBC connection to be HSQLDB with an in-memory storage, and upon success we will fetch a service proxy for our test cases. 55 | 56 | Since these operations are involving, we leverage the JUnit _before_ / _after_ life-cycle methods: 57 | 58 | [source,java,indent=0] 59 | ---- 60 | include::src/test/java/io/vertx/guides/wiki/database/WikiDatabaseVerticleTest.java[tags=prepare] 61 | ---- 62 | <1> We only override some of the verticle settings, the others will have default values. 63 | <2> `asyncAssertSuccess` is useful to provide a handler that checks for the success of an asynchronous operation. There is a variant with no arguments, and a variant like this one where we can chain the result to another handler. 64 | 65 | Cleaning up the Vert.x context is straightforward, and again we use `asyncAssertSuccess` to ensure that no error was encountered: 66 | 67 | [source,java,indent=0] 68 | ---- 69 | include::src/test/java/io/vertx/guides/wiki/database/WikiDatabaseVerticleTest.java[tags=finish] 70 | ---- 71 | 72 | The service operations are essentially CRUD operations, so a JUnit test case combining all of them is a fine way to test: 73 | 74 | [source,java,indent=0] 75 | ---- 76 | include::src/test/java/io/vertx/guides/wiki/database/WikiDatabaseVerticleTest.java[tags=crud] 77 | ---- 78 | <1> This is where the sole `Async` eventually completes. 79 | <2> This is an alternative to exiting the test case method and relying on a JUnit timeout. Here the execution on the test case thread waits until either the `Async` completes or the timeout period elapses. -------------------------------------------------------------------------------- /step-4/redeploy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SET LAUNCHER="io.vertx.core.Launcher" 4 | SET VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | SET CMD="mvn compile" 6 | SET VERTX_CMD="run" 7 | SET CMD_LINE_ARGS=%* 8 | 9 | call mvn compile dependency:copy-dependencies 10 | 11 | java -cp "target\dependency\*;target\classes" %LAUNCHER% %VERTX_CMD% %VERTICLE% --redeploy="src\main\**\*" --on-redeploy=%CMD% --launcher-class=%LAUNCHER% %CMD_LINE_ARGS% --java-opts="-Dhsqldb.reconfig_logging=false" 12 | -------------------------------------------------------------------------------- /step-4/redeploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export LAUNCHER="io.vertx.core.Launcher" 4 | export VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | export CMD="mvn compile" 6 | export VERTX_CMD="run" 7 | 8 | mvn compile dependency:copy-dependencies 9 | java \ 10 | -cp $(echo target/dependency/*.jar | tr ' ' ':'):"target/classes" \ 11 | $LAUNCHER $VERTX_CMD $VERTICLE \ 12 | --redeploy="src/main/**/*" --on-redeploy=$CMD \ 13 | --launcher-class=$LAUNCHER \ 14 | --java-opts="-Dhsqldb.reconfig_logging=false" \ 15 | $@ 16 | -------------------------------------------------------------------------------- /step-4/src/main/java/io/vertx/guides/wiki/MainVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.DeploymentOptions; 22 | import io.vertx.core.Promise; 23 | import io.vertx.guides.wiki.database.WikiDatabaseVerticle; 24 | 25 | /** 26 | * @author Julien Ponge 27 | */ 28 | public class MainVerticle extends AbstractVerticle { 29 | 30 | @Override 31 | public void start(Promise promise) throws Exception { 32 | 33 | Promise dbVerticleDeployment = Promise.promise(); 34 | vertx.deployVerticle(new WikiDatabaseVerticle(), dbVerticleDeployment); 35 | 36 | dbVerticleDeployment.future().compose(id -> { 37 | 38 | Promise httpVerticleDeployment = Promise.promise(); 39 | vertx.deployVerticle( 40 | "io.vertx.guides.wiki.http.HttpServerVerticle", 41 | new DeploymentOptions().setInstances(2), 42 | httpVerticleDeployment); 43 | 44 | return httpVerticleDeployment.future(); 45 | 46 | }).setHandler(ar -> { 47 | if (ar.succeeded()) { 48 | promise.complete(); 49 | } else { 50 | promise.fail(ar.cause()); 51 | } 52 | }); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /step-4/src/main/java/io/vertx/guides/wiki/database/ErrorCodes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | public enum ErrorCodes { 24 | NO_ACTION_SPECIFIED, 25 | BAD_ACTION, 26 | DB_ERROR 27 | } 28 | -------------------------------------------------------------------------------- /step-4/src/main/java/io/vertx/guides/wiki/database/SqlQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | enum SqlQuery { 24 | CREATE_PAGES_TABLE, 25 | ALL_PAGES, 26 | GET_PAGE, 27 | CREATE_PAGE, 28 | SAVE_PAGE, 29 | DELETE_PAGE 30 | } 31 | -------------------------------------------------------------------------------- /step-4/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.codegen.annotations.Fluent; 21 | import io.vertx.codegen.annotations.GenIgnore; 22 | import io.vertx.codegen.annotations.ProxyGen; 23 | import io.vertx.codegen.annotations.VertxGen; 24 | import io.vertx.core.AsyncResult; 25 | import io.vertx.core.Handler; 26 | import io.vertx.core.Vertx; 27 | import io.vertx.core.json.JsonArray; 28 | import io.vertx.core.json.JsonObject; 29 | import io.vertx.ext.jdbc.JDBCClient; 30 | 31 | import java.util.HashMap; 32 | 33 | /** 34 | * @author Julien Ponge 35 | */ 36 | @ProxyGen 37 | @VertxGen 38 | public interface WikiDatabaseService { 39 | 40 | @GenIgnore 41 | static WikiDatabaseService create(JDBCClient dbClient, HashMap sqlQueries, Handler> readyHandler) { 42 | return new WikiDatabaseServiceImpl(dbClient, sqlQueries, readyHandler); 43 | } 44 | 45 | @GenIgnore 46 | static WikiDatabaseService createProxy(Vertx vertx, String address) { 47 | return new WikiDatabaseServiceVertxEBProxy(vertx, address); 48 | } 49 | 50 | @Fluent 51 | WikiDatabaseService fetchAllPages(Handler> resultHandler); 52 | 53 | @Fluent 54 | WikiDatabaseService fetchPage(String name, Handler> resultHandler); 55 | 56 | @Fluent 57 | WikiDatabaseService createPage(String title, String markdown, Handler> resultHandler); 58 | 59 | @Fluent 60 | WikiDatabaseService savePage(int id, String markdown, Handler> resultHandler); 61 | 62 | @Fluent 63 | WikiDatabaseService deletePage(int id, Handler> resultHandler); 64 | } 65 | -------------------------------------------------------------------------------- /step-4/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.Promise; 22 | import io.vertx.core.json.JsonObject; 23 | import io.vertx.ext.jdbc.JDBCClient; 24 | import io.vertx.serviceproxy.ServiceBinder; 25 | 26 | import java.io.FileInputStream; 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.util.HashMap; 30 | import java.util.Properties; 31 | 32 | /** 33 | * @author Julien Ponge 34 | */ 35 | public class WikiDatabaseVerticle extends AbstractVerticle { 36 | 37 | public static final String CONFIG_WIKIDB_JDBC_URL = "wikidb.jdbc.url"; 38 | public static final String CONFIG_WIKIDB_JDBC_DRIVER_CLASS = "wikidb.jdbc.driver_class"; 39 | public static final String CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE = "wikidb.jdbc.max_pool_size"; 40 | public static final String CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE = "wikidb.sqlqueries.resource.file"; 41 | public static final String CONFIG_WIKIDB_QUEUE = "wikidb.queue"; 42 | 43 | @Override 44 | public void start(Promise promise) throws Exception { 45 | 46 | HashMap sqlQueries = loadSqlQueries(); 47 | 48 | JDBCClient dbClient = JDBCClient.createShared(vertx, new JsonObject() 49 | .put("url", config().getString(CONFIG_WIKIDB_JDBC_URL, "jdbc:hsqldb:file:db/wiki")) 50 | .put("driver_class", config().getString(CONFIG_WIKIDB_JDBC_DRIVER_CLASS, "org.hsqldb.jdbcDriver")) 51 | .put("max_pool_size", config().getInteger(CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE, 30))); 52 | 53 | WikiDatabaseService.create(dbClient, sqlQueries, ready -> { 54 | if (ready.succeeded()) { 55 | ServiceBinder binder = new ServiceBinder(vertx); 56 | binder.setAddress(CONFIG_WIKIDB_QUEUE).register(WikiDatabaseService.class, ready.result()); 57 | promise.complete(); 58 | } else { 59 | promise.fail(ready.cause()); 60 | } 61 | }); 62 | } 63 | 64 | /* 65 | * Note: this uses blocking APIs, but data is small... 66 | */ 67 | private HashMap loadSqlQueries() throws IOException { 68 | 69 | String queriesFile = config().getString(CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE); 70 | InputStream queriesInputStream; 71 | if (queriesFile != null) { 72 | queriesInputStream = new FileInputStream(queriesFile); 73 | } else { 74 | queriesInputStream = getClass().getResourceAsStream("/db-queries.properties"); 75 | } 76 | 77 | Properties queriesProps = new Properties(); 78 | queriesProps.load(queriesInputStream); 79 | queriesInputStream.close(); 80 | 81 | HashMap sqlQueries = new HashMap<>(); 82 | sqlQueries.put(SqlQuery.CREATE_PAGES_TABLE, queriesProps.getProperty("create-pages-table")); 83 | sqlQueries.put(SqlQuery.ALL_PAGES, queriesProps.getProperty("all-pages")); 84 | sqlQueries.put(SqlQuery.GET_PAGE, queriesProps.getProperty("get-page")); 85 | sqlQueries.put(SqlQuery.CREATE_PAGE, queriesProps.getProperty("create-page")); 86 | sqlQueries.put(SqlQuery.SAVE_PAGE, queriesProps.getProperty("save-page")); 87 | sqlQueries.put(SqlQuery.DELETE_PAGE, queriesProps.getProperty("delete-page")); 88 | return sqlQueries; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /step-4/src/main/java/io/vertx/guides/wiki/database/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @author Julien Ponge 20 | */ 21 | @ModuleGen(groupPackage = "io.vertx.guides.wiki.database", name = "wiki-database") 22 | package io.vertx.guides.wiki.database; 23 | 24 | import io.vertx.codegen.annotations.ModuleGen; 25 | -------------------------------------------------------------------------------- /step-4/src/main/resources/db-queries.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | # Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | create-pages-table=create table if not exists Pages (Id integer identity primary key, Name varchar(255) unique, Content clob) 19 | get-page=select Id, Content from Pages where Name = ? 20 | create-page=insert into Pages values (NULL, ?, ?) 21 | save-page=update Pages set Content = ? where Id = ? 22 | all-pages=select Name from Pages 23 | delete-page=delete from Pages where Id = ? 24 | -------------------------------------------------------------------------------- /step-4/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /step-4/src/main/resources/templates/footer.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /step-4/src/main/resources/templates/header.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | ${title} | A Sample Vert.x-powered Wiki 12 | 13 | 14 | 15 |
16 | -------------------------------------------------------------------------------- /step-4/src/main/resources/templates/index.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 |
7 |
8 |
9 | 10 |
11 | 12 |
13 |
14 |

${title}

15 |
16 | 17 |
18 | <#list pages> 19 |

Pages:

20 |
    21 | <#items as page> 22 |
  • ${page}
  • 23 | 24 |
25 | <#else> 26 |

The wiki is currently empty!

27 | 28 |
29 | 30 |
31 | 32 | <#include "footer.ftl"> 33 | -------------------------------------------------------------------------------- /step-4/src/main/resources/templates/page.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 | 7 | Home 8 | 10 | 11 |

12 | { 13 | ${title} 14 | } 15 |

16 |
17 | 18 |
19 | ${content} 20 |
21 | 22 |
23 |
24 |
25 | 26 | 27 | 28 | 29 |
30 | 31 | <#if id != -1> 32 | 33 | 34 |
35 |
36 | 37 |
38 |
39 |

Rendered: ${timestamp}

40 |
41 | 42 |
43 | 44 | <#include "footer.ftl"> 45 | -------------------------------------------------------------------------------- /step-4/src/test/java/io/vertx/guides/wiki/database/WikiDatabaseVerticleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.core.DeploymentOptions; 21 | import io.vertx.core.Vertx; 22 | import io.vertx.core.json.JsonObject; 23 | import io.vertx.ext.unit.Async; 24 | import io.vertx.ext.unit.TestContext; 25 | import io.vertx.ext.unit.junit.VertxUnitRunner; 26 | import org.junit.After; 27 | import org.junit.Before; 28 | import org.junit.Test; 29 | import org.junit.runner.RunWith; 30 | 31 | /** 32 | * @author Julien Ponge 33 | */ 34 | @RunWith(VertxUnitRunner.class) 35 | public class WikiDatabaseVerticleTest { 36 | 37 | // tag::prepare[] 38 | private Vertx vertx; 39 | private WikiDatabaseService service; 40 | 41 | @Before 42 | public void prepare(TestContext context) throws InterruptedException { 43 | vertx = Vertx.vertx(); 44 | 45 | JsonObject conf = new JsonObject() // <1> 46 | .put(WikiDatabaseVerticle.CONFIG_WIKIDB_JDBC_URL, "jdbc:hsqldb:mem:testdb;shutdown=true") 47 | .put(WikiDatabaseVerticle.CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE, 4); 48 | 49 | vertx.deployVerticle(new WikiDatabaseVerticle(), new DeploymentOptions().setConfig(conf), 50 | context.asyncAssertSuccess(id -> // <2> 51 | service = WikiDatabaseService.createProxy(vertx, WikiDatabaseVerticle.CONFIG_WIKIDB_QUEUE))); 52 | } 53 | // end::prepare[] 54 | 55 | // tag::finish[] 56 | @After 57 | public void finish(TestContext context) { 58 | vertx.close(context.asyncAssertSuccess()); 59 | } 60 | // end::finish[] 61 | 62 | // tag::async-basic[] 63 | @Test /*(timeout=5000)*/ // <8> 64 | public void async_behavior(TestContext context) { // <1> 65 | Vertx vertx = Vertx.vertx(); // <2> 66 | context.assertEquals("foo", "foo"); // <3> 67 | Async a1 = context.async(); // <4> 68 | Async a2 = context.async(3); // <5> 69 | vertx.setTimer(100, n -> a1.complete()); // <6> 70 | vertx.setPeriodic(100, n -> a2.countDown()); // <7> 71 | } 72 | // end::async-basic[] 73 | 74 | // tag::crud[] 75 | @Test 76 | public void crud_operations(TestContext context) { 77 | Async async = context.async(); 78 | 79 | service.createPage("Test", "Some content", context.asyncAssertSuccess(v1 -> { 80 | 81 | service.fetchPage("Test", context.asyncAssertSuccess(json1 -> { 82 | context.assertTrue(json1.getBoolean("found")); 83 | context.assertTrue(json1.containsKey("id")); 84 | context.assertEquals("Some content", json1.getString("rawContent")); 85 | 86 | service.savePage(json1.getInteger("id"), "Yo!", context.asyncAssertSuccess(v2 -> { 87 | 88 | service.fetchAllPages(context.asyncAssertSuccess(array1 -> { 89 | context.assertEquals(1, array1.size()); 90 | 91 | service.fetchPage("Test", context.asyncAssertSuccess(json2 -> { 92 | context.assertEquals("Yo!", json2.getString("rawContent")); 93 | 94 | service.deletePage(json1.getInteger("id"), v3 -> { 95 | 96 | service.fetchAllPages(context.asyncAssertSuccess(array2 -> { 97 | context.assertTrue(array2.isEmpty()); 98 | async.complete(); // <1> 99 | })); 100 | }); 101 | })); 102 | })); 103 | })); 104 | })); 105 | })); 106 | async.awaitSuccess(5000); // <2> 107 | } 108 | // end::crud[] 109 | } 110 | -------------------------------------------------------------------------------- /step-4/src/test/java/io/vertx/guides/wiki/http/SampleHttpServerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.http; 19 | 20 | import io.vertx.core.Promise; 21 | import io.vertx.core.Vertx; 22 | import io.vertx.core.buffer.Buffer; 23 | import io.vertx.ext.unit.Async; 24 | import io.vertx.ext.unit.TestContext; 25 | import io.vertx.ext.unit.junit.VertxUnitRunner; 26 | import io.vertx.ext.web.client.HttpResponse; 27 | import io.vertx.ext.web.client.WebClient; 28 | import org.junit.After; 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | import org.junit.runner.RunWith; 32 | 33 | /** 34 | * @author Julien Ponge 35 | */ 36 | @RunWith(VertxUnitRunner.class) 37 | public class SampleHttpServerTest { 38 | 39 | private Vertx vertx; 40 | 41 | @Before 42 | public void prepare() { 43 | vertx = Vertx.vertx(); 44 | } 45 | 46 | @After 47 | public void finish(TestContext context) { 48 | vertx.close(context.asyncAssertSuccess()); 49 | } 50 | 51 | @Test 52 | public void start_http_server(TestContext context) { 53 | Async async = context.async(); 54 | 55 | vertx 56 | .createHttpServer().requestHandler(req -> 57 | req.response().putHeader("Content-Type", "text/plain").end("Ok")) 58 | .listen(8080, context.asyncAssertSuccess(server -> { 59 | 60 | WebClient webClient = WebClient.create(vertx); 61 | 62 | webClient.get(8080, "localhost", "/").send(ar -> { 63 | if (ar.succeeded()) { 64 | HttpResponse response = ar.result(); 65 | context.assertTrue(response.headers().contains("Content-Type")); 66 | context.assertEquals("text/plain", response.getHeader("Content-Type")); 67 | context.assertEquals("Ok", response.body().toString()); 68 | async.complete(); 69 | } else { 70 | async.resolve(Promise.failedPromise(ar.cause())); 71 | } 72 | }); 73 | })); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /step-5/images/backup-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-5/images/backup-button.png -------------------------------------------------------------------------------- /step-5/images/backup-created.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-5/images/backup-created.png -------------------------------------------------------------------------------- /step-5/images/snippet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-5/images/snippet.png -------------------------------------------------------------------------------- /step-5/redeploy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SET LAUNCHER="io.vertx.core.Launcher" 4 | SET VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | SET CMD="mvn compile" 6 | SET VERTX_CMD="run" 7 | SET CMD_LINE_ARGS=%* 8 | 9 | call mvn compile dependency:copy-dependencies 10 | 11 | java -cp "target\dependency\*;target\classes" %LAUNCHER% %VERTX_CMD% %VERTICLE% --redeploy="src\main\**\*" --on-redeploy=%CMD% --launcher-class=%LAUNCHER% %CMD_LINE_ARGS% --java-opts="-Dhsqldb.reconfig_logging=false" 12 | -------------------------------------------------------------------------------- /step-5/redeploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export LAUNCHER="io.vertx.core.Launcher" 4 | export VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | export CMD="mvn compile" 6 | export VERTX_CMD="run" 7 | 8 | mvn compile dependency:copy-dependencies 9 | java \ 10 | -cp $(echo target/dependency/*.jar | tr ' ' ':'):"target/classes" \ 11 | $LAUNCHER $VERTX_CMD $VERTICLE \ 12 | --redeploy="src/main/**/*" --on-redeploy=$CMD \ 13 | --launcher-class=$LAUNCHER \ 14 | --java-opts="-Dhsqldb.reconfig_logging=false" \ 15 | $@ 16 | -------------------------------------------------------------------------------- /step-5/src/main/java/io/vertx/guides/wiki/MainVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.DeploymentOptions; 22 | import io.vertx.core.Promise; 23 | import io.vertx.guides.wiki.database.WikiDatabaseVerticle; 24 | 25 | /** 26 | * @author Julien Ponge 27 | */ 28 | public class MainVerticle extends AbstractVerticle { 29 | 30 | @Override 31 | public void start(Promise promise) throws Exception { 32 | 33 | Promise dbVerticleDeployment = Promise.promise(); 34 | vertx.deployVerticle(new WikiDatabaseVerticle(), dbVerticleDeployment); 35 | 36 | dbVerticleDeployment.future().compose(id -> { 37 | 38 | Promise httpVerticleDeployment = Promise.promise(); 39 | vertx.deployVerticle( 40 | "io.vertx.guides.wiki.http.HttpServerVerticle", 41 | new DeploymentOptions().setInstances(2), 42 | httpVerticleDeployment); 43 | 44 | return httpVerticleDeployment.future(); 45 | 46 | }).setHandler(ar -> { 47 | if (ar.succeeded()) { 48 | promise.complete(); 49 | } else { 50 | promise.fail(ar.cause()); 51 | } 52 | }); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /step-5/src/main/java/io/vertx/guides/wiki/database/ErrorCodes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | public enum ErrorCodes { 24 | NO_ACTION_SPECIFIED, 25 | BAD_ACTION, 26 | DB_ERROR 27 | } 28 | -------------------------------------------------------------------------------- /step-5/src/main/java/io/vertx/guides/wiki/database/SqlQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | enum SqlQuery { 24 | CREATE_PAGES_TABLE, 25 | ALL_PAGES, 26 | GET_PAGE, 27 | CREATE_PAGE, 28 | SAVE_PAGE, 29 | DELETE_PAGE, 30 | ALL_PAGES_DATA 31 | } 32 | -------------------------------------------------------------------------------- /step-5/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.codegen.annotations.Fluent; 21 | import io.vertx.codegen.annotations.GenIgnore; 22 | import io.vertx.codegen.annotations.ProxyGen; 23 | import io.vertx.codegen.annotations.VertxGen; 24 | import io.vertx.core.AsyncResult; 25 | import io.vertx.core.Handler; 26 | import io.vertx.core.Vertx; 27 | import io.vertx.core.json.JsonArray; 28 | import io.vertx.core.json.JsonObject; 29 | import io.vertx.ext.jdbc.JDBCClient; 30 | 31 | import java.util.HashMap; 32 | import java.util.List; 33 | 34 | /** 35 | * @author Julien Ponge 36 | */ 37 | @ProxyGen 38 | @VertxGen 39 | public interface WikiDatabaseService { 40 | 41 | @GenIgnore 42 | static WikiDatabaseService create(JDBCClient dbClient, HashMap sqlQueries, Handler> readyHandler) { 43 | return new WikiDatabaseServiceImpl(dbClient, sqlQueries, readyHandler); 44 | } 45 | 46 | @GenIgnore 47 | static WikiDatabaseService createProxy(Vertx vertx, String address) { 48 | return new WikiDatabaseServiceVertxEBProxy(vertx, address); 49 | } 50 | 51 | @Fluent 52 | WikiDatabaseService fetchAllPages(Handler> resultHandler); 53 | 54 | @Fluent 55 | WikiDatabaseService fetchPage(String name, Handler> resultHandler); 56 | 57 | @Fluent 58 | WikiDatabaseService createPage(String title, String markdown, Handler> resultHandler); 59 | 60 | @Fluent 61 | WikiDatabaseService savePage(int id, String markdown, Handler> resultHandler); 62 | 63 | @Fluent 64 | WikiDatabaseService deletePage(int id, Handler> resultHandler); 65 | 66 | // tag::fetchAllPagesData[] 67 | @Fluent 68 | WikiDatabaseService fetchAllPagesData(Handler>> resultHandler); 69 | // end::fetchAllPagesData[] 70 | } 71 | -------------------------------------------------------------------------------- /step-5/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.Promise; 22 | import io.vertx.core.json.JsonObject; 23 | import io.vertx.ext.jdbc.JDBCClient; 24 | import io.vertx.serviceproxy.ServiceBinder; 25 | 26 | import java.io.FileInputStream; 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.util.HashMap; 30 | import java.util.Properties; 31 | 32 | /** 33 | * @author Julien Ponge 34 | */ 35 | public class WikiDatabaseVerticle extends AbstractVerticle { 36 | 37 | public static final String CONFIG_WIKIDB_JDBC_URL = "wikidb.jdbc.url"; 38 | public static final String CONFIG_WIKIDB_JDBC_DRIVER_CLASS = "wikidb.jdbc.driver_class"; 39 | public static final String CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE = "wikidb.jdbc.max_pool_size"; 40 | public static final String CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE = "wikidb.sqlqueries.resource.file"; 41 | public static final String CONFIG_WIKIDB_QUEUE = "wikidb.queue"; 42 | 43 | @Override 44 | public void start(Promise promise) throws Exception { 45 | 46 | HashMap sqlQueries = loadSqlQueries(); 47 | 48 | JDBCClient dbClient = JDBCClient.createShared(vertx, new JsonObject() 49 | .put("url", config().getString(CONFIG_WIKIDB_JDBC_URL, "jdbc:hsqldb:file:db/wiki")) 50 | .put("driver_class", config().getString(CONFIG_WIKIDB_JDBC_DRIVER_CLASS, "org.hsqldb.jdbcDriver")) 51 | .put("max_pool_size", config().getInteger(CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE, 30))); 52 | 53 | WikiDatabaseService.create(dbClient, sqlQueries, ready -> { 54 | if (ready.succeeded()) { 55 | ServiceBinder binder = new ServiceBinder(vertx); 56 | binder.setAddress(CONFIG_WIKIDB_QUEUE).register(WikiDatabaseService.class, ready.result()); 57 | promise.complete(); 58 | } else { 59 | promise.fail(ready.cause()); 60 | } 61 | }); 62 | } 63 | 64 | /* 65 | * Note: this uses blocking APIs, but data is small... 66 | */ 67 | private HashMap loadSqlQueries() throws IOException { 68 | 69 | String queriesFile = config().getString(CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE); 70 | InputStream queriesInputStream; 71 | if (queriesFile != null) { 72 | queriesInputStream = new FileInputStream(queriesFile); 73 | } else { 74 | queriesInputStream = getClass().getResourceAsStream("/db-queries.properties"); 75 | } 76 | 77 | Properties queriesProps = new Properties(); 78 | queriesProps.load(queriesInputStream); 79 | queriesInputStream.close(); 80 | 81 | HashMap sqlQueries = new HashMap<>(); 82 | sqlQueries.put(SqlQuery.CREATE_PAGES_TABLE, queriesProps.getProperty("create-pages-table")); 83 | sqlQueries.put(SqlQuery.ALL_PAGES, queriesProps.getProperty("all-pages")); 84 | sqlQueries.put(SqlQuery.GET_PAGE, queriesProps.getProperty("get-page")); 85 | sqlQueries.put(SqlQuery.CREATE_PAGE, queriesProps.getProperty("create-page")); 86 | sqlQueries.put(SqlQuery.SAVE_PAGE, queriesProps.getProperty("save-page")); 87 | sqlQueries.put(SqlQuery.DELETE_PAGE, queriesProps.getProperty("delete-page")); 88 | sqlQueries.put(SqlQuery.ALL_PAGES_DATA, queriesProps.getProperty("all-pages-data")); 89 | return sqlQueries; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /step-5/src/main/java/io/vertx/guides/wiki/database/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @author Julien Ponge 20 | */ 21 | @ModuleGen(groupPackage = "io.vertx.guides.wiki.database", name = "wiki-database") 22 | package io.vertx.guides.wiki.database; 23 | 24 | import io.vertx.codegen.annotations.ModuleGen; 25 | -------------------------------------------------------------------------------- /step-5/src/main/resources/db-queries.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | # Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | create-pages-table=create table if not exists Pages (Id integer identity primary key, Name varchar(255) unique, Content clob) 19 | get-page=select Id, Content from Pages where Name = ? 20 | create-page=insert into Pages values (NULL, ?, ?) 21 | save-page=update Pages set Content = ? where Id = ? 22 | all-pages=select Name from Pages 23 | delete-page=delete from Pages where Id = ? 24 | all-pages-data=select * from Pages 25 | -------------------------------------------------------------------------------- /step-5/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /step-5/src/main/resources/templates/footer.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /step-5/src/main/resources/templates/header.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | ${title} | A Sample Vert.x-powered Wiki 12 | 13 | 14 | 15 |
16 | -------------------------------------------------------------------------------- /step-5/src/main/resources/templates/index.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 |
7 |
8 |
9 | 10 |
11 | 12 |
13 |
14 |

${title}

15 |
16 | 17 |
18 | <#list pages> 19 |

Pages:

20 |
    21 | <#items as page> 22 |
  • ${page}
  • 23 | 24 |
25 | <#else> 26 |

The wiki is currently empty!

27 | 28 | <#if backup_gist_url?has_content> 29 | 33 | <#else> 34 |

35 | Backup 36 |

37 | 38 |
39 | 40 |
41 | 42 | <#include "footer.ftl"> 43 | -------------------------------------------------------------------------------- /step-5/src/main/resources/templates/page.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 | 7 | Home 8 | 10 | 11 |

12 | { 13 | ${title} 14 | } 15 |

16 |
17 | 18 |
19 | ${content} 20 |
21 | 22 |
23 |
24 |
25 | 26 | 27 | 28 | 29 |
30 | 31 | <#if id != -1> 32 | 33 | 34 |
35 |
36 | 37 |
38 |
39 |

Rendered: ${timestamp}

40 |
41 | 42 |
43 | 44 | <#include "footer.ftl"> 45 | -------------------------------------------------------------------------------- /step-5/src/test/java/io/vertx/guides/wiki/http/SampleHttpServerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.http; 19 | 20 | import io.vertx.core.Promise; 21 | import io.vertx.core.Vertx; 22 | import io.vertx.core.buffer.Buffer; 23 | import io.vertx.ext.unit.Async; 24 | import io.vertx.ext.unit.TestContext; 25 | import io.vertx.ext.unit.junit.VertxUnitRunner; 26 | import io.vertx.ext.web.client.HttpResponse; 27 | import io.vertx.ext.web.client.WebClient; 28 | import org.junit.After; 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | import org.junit.runner.RunWith; 32 | 33 | /** 34 | * @author Julien Ponge 35 | */ 36 | @RunWith(VertxUnitRunner.class) 37 | public class SampleHttpServerTest { 38 | 39 | private Vertx vertx; 40 | 41 | @Before 42 | public void prepare() { 43 | vertx = Vertx.vertx(); 44 | } 45 | 46 | @After 47 | public void finish(TestContext context) { 48 | vertx.close(context.asyncAssertSuccess()); 49 | } 50 | 51 | // tag::client[] 52 | @Test 53 | public void start_http_server(TestContext context) { 54 | Async async = context.async(); 55 | 56 | vertx.createHttpServer().requestHandler(req -> 57 | req.response().putHeader("Content-Type", "text/plain").end("Ok")) 58 | .listen(8080, context.asyncAssertSuccess(server -> { 59 | 60 | WebClient webClient = WebClient.create(vertx); 61 | 62 | webClient.get(8080, "localhost", "/").send(ar -> { 63 | if (ar.succeeded()) { 64 | HttpResponse response = ar.result(); 65 | context.assertTrue(response.headers().contains("Content-Type")); 66 | context.assertEquals("text/plain", response.getHeader("Content-Type")); 67 | context.assertEquals("Ok", response.body().toString()); 68 | webClient.close(); 69 | async.complete(); 70 | } else { 71 | async.resolve(Promise.failedPromise(ar.cause())); 72 | } 73 | }); 74 | })); 75 | } 76 | // end::client[] 77 | } 78 | -------------------------------------------------------------------------------- /step-6/README.adoc: -------------------------------------------------------------------------------- 1 | = Exposing a web API 2 | 3 | TIP: The corresponding source code is in the `step-6` folder of the guide repository. 4 | 5 | Exposing a web HTTP/JSON API is very straightforward using what we have already covered from the `vertx-web` module. 6 | We are going to expose a web API with the following URL scheme: 7 | 8 | * `GET /api/pages` gives a document will all wiki page names and identifiers, 9 | * `POST /api/pages` creates a new wiki page from a document, 10 | * `PUT /api/pages/:id` updates a wiki page from a document, 11 | * `DELETE /api/pages/:id` deletes a wiki page. 12 | 13 | Here is a screenshot of interacting with the API using the https://httpie.org/[HTTPie command-line tool]: 14 | 15 | image::images/webapi-httpie.png[] 16 | 17 | == Web sub-routers 18 | 19 | We are going to add new route handlers to the `HttpServerVerticle`. 20 | While we could just add handlers to the existing router, we can also take advantage of _sub-routers_. 21 | They allow a router to be mounted as a sub-router of another one, which can be useful for organizing and/or re-using handlers. 22 | 23 | Here is the code for the API router: 24 | 25 | [source,java,indent=0] 26 | ---- 27 | include::src/main/java/io/vertx/guides/wiki/http/HttpServerVerticle.java[tags=apiRouter] 28 | ---- 29 | <1> This is where we mount our router, so requests starting with the `/api` path will be directed to `apiRouter`. 30 | 31 | == Handlers 32 | 33 | Here is the code for the different API router handlers. 34 | 35 | === Root resource 36 | 37 | [source,java,indent=0] 38 | ---- 39 | include::src/main/java/io/vertx/guides/wiki/http/HttpServerVerticle.java[tags=apiRoot] 40 | ---- 41 | <1> We just remap database results in page information entry objects. 42 | <2> The resulting JSON array becomes the value for the `pages` key in the response payload. 43 | <3> `JsonObject#encode()` gives a compact `String` representation of the JSON data. 44 | 45 | === Getting a page 46 | 47 | [source,java,indent=0] 48 | ---- 49 | include::src/main/java/io/vertx/guides/wiki/http/HttpServerVerticle.java[tags=apiGetPage] 50 | ---- 51 | 52 | === Creating a page 53 | 54 | [source,java,indent=0] 55 | ---- 56 | include::src/main/java/io/vertx/guides/wiki/http/HttpServerVerticle.java[tags=apiCreatePage] 57 | ---- 58 | 59 | This handler and other handlers need to deal with incoming JSON documents. 60 | The following `validateJsonPageDocument` method is a helper for doing validation and early error reporting, so that the remainder of the processing assume the presence of certain JSON entries: 61 | 62 | [source,java,indent=0] 63 | ---- 64 | include::src/main/java/io/vertx/guides/wiki/http/HttpServerVerticle.java[tags=validateJsonPageDocument] 65 | ---- 66 | 67 | === Updating a page 68 | 69 | [source,java,indent=0] 70 | ---- 71 | include::src/main/java/io/vertx/guides/wiki/http/HttpServerVerticle.java[tags=apiUpdatePage] 72 | ---- 73 | 74 | The `handleSimpleDbReply` method is a helper for finishing the request processing: 75 | 76 | [source,java,indent=0] 77 | ---- 78 | include::src/main/java/io/vertx/guides/wiki/http/HttpServerVerticle.java[tags=handleSimpleDbReply] 79 | ---- 80 | 81 | === Deleting a page 82 | 83 | [source,java,indent=0] 84 | ---- 85 | include::src/main/java/io/vertx/guides/wiki/http/HttpServerVerticle.java[tags=apiDeletePage] 86 | ---- 87 | 88 | == Unit testing the API 89 | 90 | We write a basic test case in the `io.vertx.guides.wiki.http.ApiTest` class. 91 | 92 | The preamble consists in preparing the test environment. 93 | The HTTP server verticle needs the database verticle to be running, so we need to deploy both in our test Vert.x context: 94 | 95 | [source,java,indent=0] 96 | ---- 97 | include::src/test/java/io/vertx/guides/wiki/http/ApiTest.java[tags=preamble] 98 | ---- 99 | <1> We use a different JDBC URL to use an in-memory database for the tests. 100 | 101 | The proper test case is a simple scenario where all types of requests are being made. 102 | It creates a page, fetches it, updates it then deletes it: 103 | 104 | [source,java,indent=0] 105 | ---- 106 | include::src/test/java/io/vertx/guides/wiki/http/ApiTest.java[tags=play-with-api] 107 | ---- 108 | 109 | TIP: The test uses `Future` objects composition rather than nested callbacks; the last composition must complete the 110 | async future or the test will eventually time out. 111 | -------------------------------------------------------------------------------- /step-6/images/webapi-httpie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-6/images/webapi-httpie.png -------------------------------------------------------------------------------- /step-6/redeploy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SET LAUNCHER="io.vertx.core.Launcher" 4 | SET VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | SET CMD="mvn compile" 6 | SET VERTX_CMD="run" 7 | SET CMD_LINE_ARGS=%* 8 | 9 | call mvn compile dependency:copy-dependencies 10 | 11 | java -cp "target\dependency\*;target\classes" %LAUNCHER% %VERTX_CMD% %VERTICLE% --redeploy="src\main\**\*" --on-redeploy=%CMD% --launcher-class=%LAUNCHER% %CMD_LINE_ARGS% --java-opts="-Dhsqldb.reconfig_logging=false" 12 | -------------------------------------------------------------------------------- /step-6/redeploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export LAUNCHER="io.vertx.core.Launcher" 4 | export VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | export CMD="mvn compile" 6 | export VERTX_CMD="run" 7 | 8 | mvn compile dependency:copy-dependencies 9 | java \ 10 | -cp $(echo target/dependency/*.jar | tr ' ' ':'):"target/classes" \ 11 | $LAUNCHER $VERTX_CMD $VERTICLE \ 12 | --redeploy="src/main/**/*" --on-redeploy=$CMD \ 13 | --launcher-class=$LAUNCHER \ 14 | --java-opts="-Dhsqldb.reconfig_logging=false" \ 15 | $@ 16 | -------------------------------------------------------------------------------- /step-6/src/main/java/io/vertx/guides/wiki/MainVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.DeploymentOptions; 22 | import io.vertx.core.Future; 23 | import io.vertx.core.Promise; 24 | import io.vertx.guides.wiki.database.WikiDatabaseVerticle; 25 | 26 | /** 27 | * @author Julien Ponge 28 | */ 29 | public class MainVerticle extends AbstractVerticle { 30 | 31 | @Override 32 | public void start(Promise promise) throws Exception { 33 | 34 | Promise dbDeployPromise = Promise.promise(); 35 | vertx.deployVerticle(new WikiDatabaseVerticle(), dbDeployPromise); 36 | Future dbDeployFuture = dbDeployPromise.future(); 37 | 38 | Future deployHttpFuture = dbDeployFuture.compose(id -> { 39 | Promise deployHttpPromise = Promise.promise(); 40 | vertx.deployVerticle( 41 | "io.vertx.guides.wiki.http.HttpServerVerticle", 42 | new DeploymentOptions().setInstances(2), 43 | deployHttpPromise); 44 | return deployHttpPromise.future(); 45 | }); 46 | 47 | deployHttpFuture.setHandler(ar -> { 48 | if (ar.succeeded()) { 49 | promise.complete(); 50 | } else { 51 | promise.fail(ar.cause()); 52 | } 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /step-6/src/main/java/io/vertx/guides/wiki/database/ErrorCodes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | public enum ErrorCodes { 24 | NO_ACTION_SPECIFIED, 25 | BAD_ACTION, 26 | DB_ERROR 27 | } 28 | -------------------------------------------------------------------------------- /step-6/src/main/java/io/vertx/guides/wiki/database/SqlQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | enum SqlQuery { 24 | CREATE_PAGES_TABLE, 25 | ALL_PAGES, 26 | GET_PAGE, 27 | CREATE_PAGE, 28 | SAVE_PAGE, 29 | DELETE_PAGE, 30 | ALL_PAGES_DATA, 31 | GET_PAGE_BY_ID 32 | } 33 | -------------------------------------------------------------------------------- /step-6/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.codegen.annotations.Fluent; 21 | import io.vertx.codegen.annotations.GenIgnore; 22 | import io.vertx.codegen.annotations.ProxyGen; 23 | import io.vertx.codegen.annotations.VertxGen; 24 | import io.vertx.core.AsyncResult; 25 | import io.vertx.core.Handler; 26 | import io.vertx.core.Vertx; 27 | import io.vertx.core.json.JsonArray; 28 | import io.vertx.core.json.JsonObject; 29 | import io.vertx.ext.jdbc.JDBCClient; 30 | 31 | import java.util.HashMap; 32 | import java.util.List; 33 | 34 | /** 35 | * @author Julien Ponge 36 | */ 37 | @ProxyGen 38 | @VertxGen 39 | public interface WikiDatabaseService { 40 | 41 | @GenIgnore 42 | static WikiDatabaseService create(JDBCClient dbClient, HashMap sqlQueries, Handler> readyHandler) { 43 | return new WikiDatabaseServiceImpl(dbClient, sqlQueries, readyHandler); 44 | } 45 | 46 | @GenIgnore 47 | static WikiDatabaseService createProxy(Vertx vertx, String address) { 48 | return new WikiDatabaseServiceVertxEBProxy(vertx, address); 49 | } 50 | 51 | @Fluent 52 | WikiDatabaseService fetchAllPages(Handler> resultHandler); 53 | 54 | @Fluent 55 | WikiDatabaseService fetchPage(String name, Handler> resultHandler); 56 | 57 | @Fluent 58 | WikiDatabaseService fetchPageById(int id, Handler> resultHandler); 59 | 60 | @Fluent 61 | WikiDatabaseService createPage(String title, String markdown, Handler> resultHandler); 62 | 63 | @Fluent 64 | WikiDatabaseService savePage(int id, String markdown, Handler> resultHandler); 65 | 66 | @Fluent 67 | WikiDatabaseService deletePage(int id, Handler> resultHandler); 68 | 69 | @Fluent 70 | WikiDatabaseService fetchAllPagesData(Handler>> resultHandler); 71 | } 72 | -------------------------------------------------------------------------------- /step-6/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.Promise; 22 | import io.vertx.core.json.JsonObject; 23 | import io.vertx.ext.jdbc.JDBCClient; 24 | import io.vertx.serviceproxy.ServiceBinder; 25 | 26 | import java.io.FileInputStream; 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.util.HashMap; 30 | import java.util.Properties; 31 | 32 | /** 33 | * @author Julien Ponge 34 | */ 35 | public class WikiDatabaseVerticle extends AbstractVerticle { 36 | 37 | public static final String CONFIG_WIKIDB_JDBC_URL = "wikidb.jdbc.url"; 38 | public static final String CONFIG_WIKIDB_JDBC_DRIVER_CLASS = "wikidb.jdbc.driver_class"; 39 | public static final String CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE = "wikidb.jdbc.max_pool_size"; 40 | public static final String CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE = "wikidb.sqlqueries.resource.file"; 41 | public static final String CONFIG_WIKIDB_QUEUE = "wikidb.queue"; 42 | 43 | @Override 44 | public void start(Promise promise) throws Exception { 45 | 46 | HashMap sqlQueries = loadSqlQueries(); 47 | 48 | JDBCClient dbClient = JDBCClient.createShared(vertx, new JsonObject() 49 | .put("url", config().getString(CONFIG_WIKIDB_JDBC_URL, "jdbc:hsqldb:file:db/wiki")) 50 | .put("driver_class", config().getString(CONFIG_WIKIDB_JDBC_DRIVER_CLASS, "org.hsqldb.jdbcDriver")) 51 | .put("max_pool_size", config().getInteger(CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE, 30))); 52 | 53 | WikiDatabaseService.create(dbClient, sqlQueries, ready -> { 54 | if (ready.succeeded()) { 55 | ServiceBinder binder = new ServiceBinder(vertx); 56 | binder.setAddress(CONFIG_WIKIDB_QUEUE).register(WikiDatabaseService.class, ready.result()); 57 | promise.complete(); 58 | } else { 59 | promise.fail(ready.cause()); 60 | } 61 | }); 62 | } 63 | 64 | /* 65 | * Note: this uses blocking APIs, but data is small... 66 | */ 67 | private HashMap loadSqlQueries() throws IOException { 68 | 69 | String queriesFile = config().getString(CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE); 70 | InputStream queriesInputStream; 71 | if (queriesFile != null) { 72 | queriesInputStream = new FileInputStream(queriesFile); 73 | } else { 74 | queriesInputStream = getClass().getResourceAsStream("/db-queries.properties"); 75 | } 76 | 77 | Properties queriesProps = new Properties(); 78 | queriesProps.load(queriesInputStream); 79 | queriesInputStream.close(); 80 | 81 | HashMap sqlQueries = new HashMap<>(); 82 | sqlQueries.put(SqlQuery.CREATE_PAGES_TABLE, queriesProps.getProperty("create-pages-table")); 83 | sqlQueries.put(SqlQuery.ALL_PAGES, queriesProps.getProperty("all-pages")); 84 | sqlQueries.put(SqlQuery.GET_PAGE, queriesProps.getProperty("get-page")); 85 | sqlQueries.put(SqlQuery.CREATE_PAGE, queriesProps.getProperty("create-page")); 86 | sqlQueries.put(SqlQuery.SAVE_PAGE, queriesProps.getProperty("save-page")); 87 | sqlQueries.put(SqlQuery.DELETE_PAGE, queriesProps.getProperty("delete-page")); 88 | sqlQueries.put(SqlQuery.ALL_PAGES_DATA, queriesProps.getProperty("all-pages-data")); 89 | sqlQueries.put(SqlQuery.GET_PAGE_BY_ID, queriesProps.getProperty("get-page-by-id")); 90 | return sqlQueries; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /step-6/src/main/java/io/vertx/guides/wiki/database/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @author Julien Ponge 20 | */ 21 | @ModuleGen(groupPackage = "io.vertx.guides.wiki.database", name = "wiki-database") 22 | package io.vertx.guides.wiki.database; 23 | 24 | import io.vertx.codegen.annotations.ModuleGen; 25 | -------------------------------------------------------------------------------- /step-6/src/main/resources/db-queries.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | # Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | create-pages-table=create table if not exists Pages (Id integer identity primary key, Name varchar(255) unique, Content clob) 19 | get-page=select Id, Content from Pages where Name = ? 20 | get-page-by-id=select * from Pages where Id = ? 21 | create-page=insert into Pages values (NULL, ?, ?) 22 | save-page=update Pages set Content = ? where Id = ? 23 | all-pages=select Name from Pages 24 | delete-page=delete from Pages where Id = ? 25 | all-pages-data=select * from Pages 26 | -------------------------------------------------------------------------------- /step-6/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /step-6/src/main/resources/templates/footer.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /step-6/src/main/resources/templates/header.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | ${title} | A Sample Vert.x-powered Wiki 12 | 13 | 14 | 15 |
16 | -------------------------------------------------------------------------------- /step-6/src/main/resources/templates/index.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 |
7 |
8 |
9 | 10 |
11 | 12 |
13 |
14 |

${title}

15 |
16 | 17 |
18 | <#list pages> 19 |

Pages:

20 |
    21 | <#items as page> 22 |
  • ${page}
  • 23 | 24 |
25 | <#else> 26 |

The wiki is currently empty!

27 | 28 | <#if backup_gist_url?has_content> 29 | 33 | <#else> 34 |

35 | Backup 36 |

37 | 38 |
39 | 40 |
41 | 42 | <#include "footer.ftl"> 43 | -------------------------------------------------------------------------------- /step-6/src/main/resources/templates/page.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 | 7 | Home 8 | 10 | 11 |

12 | { 13 | ${title} 14 | } 15 |

16 |
17 | 18 |
19 | ${content} 20 |
21 | 22 |
23 |
24 |
25 | 26 | 27 | 28 | 29 |
30 | 31 | <#if id != -1> 32 | 33 | 34 |
35 |
36 | 37 |
38 |
39 |

Rendered: ${timestamp}

40 |
41 | 42 |
43 | 44 | <#include "footer.ftl"> 45 | -------------------------------------------------------------------------------- /step-6/src/test/java/io/vertx/guides/wiki/http/SampleHttpServerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.http; 19 | 20 | import io.vertx.core.Promise; 21 | import io.vertx.core.Vertx; 22 | import io.vertx.core.buffer.Buffer; 23 | import io.vertx.ext.unit.Async; 24 | import io.vertx.ext.unit.TestContext; 25 | import io.vertx.ext.unit.junit.VertxUnitRunner; 26 | import io.vertx.ext.web.client.HttpResponse; 27 | import io.vertx.ext.web.client.WebClient; 28 | import org.junit.After; 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | import org.junit.runner.RunWith; 32 | 33 | /** 34 | * @author Julien Ponge 35 | */ 36 | @RunWith(VertxUnitRunner.class) 37 | public class SampleHttpServerTest { 38 | 39 | private Vertx vertx; 40 | 41 | @Before 42 | public void prepare() { 43 | vertx = Vertx.vertx(); 44 | } 45 | 46 | @After 47 | public void finish(TestContext context) { 48 | vertx.close(context.asyncAssertSuccess()); 49 | } 50 | 51 | @Test 52 | public void start_http_server(TestContext context) { 53 | Async async = context.async(); 54 | 55 | vertx 56 | .createHttpServer().requestHandler(req -> 57 | req.response().putHeader("Content-Type", "text/plain").end("Ok")) 58 | .listen(8080, context.asyncAssertSuccess(server -> { 59 | 60 | WebClient webClient = WebClient.create(vertx); 61 | 62 | webClient.get(8080, "localhost", "/").send(ar -> { 63 | if (ar.succeeded()) { 64 | HttpResponse response = ar.result(); 65 | context.assertTrue(response.headers().contains("Content-Type")); 66 | context.assertEquals("text/plain", response.getHeader("Content-Type")); 67 | context.assertEquals("Ok", response.body().toString()); 68 | webClient.close(); 69 | async.complete(); 70 | } else { 71 | async.resolve(Promise.failedPromise(ar.cause())); 72 | } 73 | }); 74 | })); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /step-7/gen-keystore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Keys for HTTPS..." 4 | 5 | # tag::https-keygen[] 6 | keytool -genkey \ 7 | -alias test \ 8 | -keyalg RSA \ 9 | -keystore server-keystore.jks \ 10 | -keysize 2048 \ 11 | -validity 360 \ 12 | -dname CN=localhost \ 13 | -keypass secret \ 14 | -storepass secret 15 | # end::https-keygen[] 16 | 17 | echo "Done." 18 | -------------------------------------------------------------------------------- /step-7/images/as-baz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-7/images/as-baz.png -------------------------------------------------------------------------------- /step-7/images/as-root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-7/images/as-root.png -------------------------------------------------------------------------------- /step-7/images/invalid-cert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-7/images/invalid-cert.png -------------------------------------------------------------------------------- /step-7/images/login-form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-7/images/login-form.png -------------------------------------------------------------------------------- /step-7/keystore.jceks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-7/keystore.jceks -------------------------------------------------------------------------------- /step-7/redeploy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SET LAUNCHER="io.vertx.core.Launcher" 4 | SET VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | SET CMD="mvn compile" 6 | SET VERTX_CMD="run" 7 | SET CMD_LINE_ARGS=%* 8 | 9 | call mvn compile dependency:copy-dependencies 10 | 11 | java -cp "target\dependency\*;target\classes" %LAUNCHER% %VERTX_CMD% %VERTICLE% --redeploy="src\main\**\*" --on-redeploy=%CMD% --launcher-class=%LAUNCHER% %CMD_LINE_ARGS% --java-opts="-Dhsqldb.reconfig_logging=false" 12 | -------------------------------------------------------------------------------- /step-7/redeploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export LAUNCHER="io.vertx.core.Launcher" 4 | export VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | export CMD="mvn compile" 6 | export VERTX_CMD="run" 7 | 8 | mvn compile dependency:copy-dependencies 9 | java \ 10 | -cp $(echo target/dependency/*.jar | tr ' ' ':'):"target/classes" \ 11 | $LAUNCHER $VERTX_CMD $VERTICLE \ 12 | --redeploy="src/main/**/*" --on-redeploy=$CMD \ 13 | --launcher-class=$LAUNCHER \ 14 | --java-opts="-Dhsqldb.reconfig_logging=false" \ 15 | $@ 16 | -------------------------------------------------------------------------------- /step-7/server-keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-7/server-keystore.jks -------------------------------------------------------------------------------- /step-7/src/main/java/io/vertx/guides/wiki/DatabaseConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | // tag::code[] 19 | package io.vertx.guides.wiki; 20 | 21 | public interface DatabaseConstants { 22 | 23 | String CONFIG_WIKIDB_JDBC_URL = "wikidb.jdbc.url"; 24 | String CONFIG_WIKIDB_JDBC_DRIVER_CLASS = "wikidb.jdbc.driver_class"; 25 | String CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE = "wikidb.jdbc.max_pool_size"; 26 | 27 | String DEFAULT_WIKIDB_JDBC_URL = "jdbc:hsqldb:file:db/wiki"; 28 | String DEFAULT_WIKIDB_JDBC_DRIVER_CLASS = "org.hsqldb.jdbcDriver"; 29 | int DEFAULT_JDBC_MAX_POOL_SIZE = 30; 30 | } 31 | // end::code[] 32 | -------------------------------------------------------------------------------- /step-7/src/main/java/io/vertx/guides/wiki/MainVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki; 19 | 20 | import io.vertx.core.*; 21 | import io.vertx.guides.wiki.database.WikiDatabaseVerticle; 22 | import io.vertx.guides.wiki.http.AuthInitializerVerticle; 23 | 24 | /** 25 | * @author Julien Ponge 26 | */ 27 | // tag::code[] 28 | public class MainVerticle extends AbstractVerticle { 29 | 30 | @Override 31 | public void start(Promise promise) { 32 | 33 | Promise dbDeploymentPromise = Promise.promise(); 34 | vertx.deployVerticle(new WikiDatabaseVerticle(), dbDeploymentPromise); 35 | 36 | Future authDeploymentFuture = dbDeploymentPromise.future().compose(id -> { 37 | Promise deployPromise = Promise.promise(); 38 | vertx.deployVerticle(new AuthInitializerVerticle(), deployPromise); 39 | return deployPromise.future(); 40 | }); 41 | 42 | Future deployHttpFuture = authDeploymentFuture.compose(id -> { 43 | Promise deployPromise = Promise.promise(); 44 | vertx.deployVerticle("io.vertx.guides.wiki.http.HttpServerVerticle", new DeploymentOptions().setInstances(2), deployPromise); 45 | return deployPromise.future(); 46 | }); 47 | 48 | deployHttpFuture.setHandler(ar -> { 49 | if (ar.succeeded()) { 50 | promise.complete(); 51 | } else { 52 | promise.fail(ar.cause()); 53 | } 54 | }); 55 | } 56 | } 57 | // end::code[] 58 | -------------------------------------------------------------------------------- /step-7/src/main/java/io/vertx/guides/wiki/database/ErrorCodes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | public enum ErrorCodes { 24 | NO_ACTION_SPECIFIED, 25 | BAD_ACTION, 26 | DB_ERROR 27 | } 28 | -------------------------------------------------------------------------------- /step-7/src/main/java/io/vertx/guides/wiki/database/SqlQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | enum SqlQuery { 24 | CREATE_PAGES_TABLE, 25 | ALL_PAGES, 26 | GET_PAGE, 27 | CREATE_PAGE, 28 | SAVE_PAGE, 29 | DELETE_PAGE, 30 | ALL_PAGES_DATA, 31 | GET_PAGE_BY_ID 32 | } 33 | -------------------------------------------------------------------------------- /step-7/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.codegen.annotations.Fluent; 21 | import io.vertx.codegen.annotations.GenIgnore; 22 | import io.vertx.codegen.annotations.ProxyGen; 23 | import io.vertx.codegen.annotations.VertxGen; 24 | import io.vertx.core.AsyncResult; 25 | import io.vertx.core.Handler; 26 | import io.vertx.core.Vertx; 27 | import io.vertx.core.json.JsonArray; 28 | import io.vertx.core.json.JsonObject; 29 | import io.vertx.ext.jdbc.JDBCClient; 30 | 31 | import java.util.HashMap; 32 | import java.util.List; 33 | 34 | /** 35 | * @author Julien Ponge 36 | */ 37 | @ProxyGen 38 | @VertxGen 39 | public interface WikiDatabaseService { 40 | 41 | @GenIgnore 42 | static WikiDatabaseService create(JDBCClient dbClient, HashMap sqlQueries, Handler> readyHandler) { 43 | return new WikiDatabaseServiceImpl(dbClient, sqlQueries, readyHandler); 44 | } 45 | 46 | @GenIgnore 47 | static WikiDatabaseService createProxy(Vertx vertx, String address) { 48 | return new WikiDatabaseServiceVertxEBProxy(vertx, address); 49 | } 50 | 51 | @Fluent 52 | WikiDatabaseService fetchAllPages(Handler> resultHandler); 53 | 54 | @Fluent 55 | WikiDatabaseService fetchPage(String name, Handler> resultHandler); 56 | 57 | @Fluent 58 | WikiDatabaseService fetchPageById(int id, Handler> resultHandler); 59 | 60 | @Fluent 61 | WikiDatabaseService createPage(String title, String markdown, Handler> resultHandler); 62 | 63 | @Fluent 64 | WikiDatabaseService savePage(int id, String markdown, Handler> resultHandler); 65 | 66 | @Fluent 67 | WikiDatabaseService deletePage(int id, Handler> resultHandler); 68 | 69 | @Fluent 70 | WikiDatabaseService fetchAllPagesData(Handler>> resultHandler); 71 | } 72 | -------------------------------------------------------------------------------- /step-7/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.Promise; 22 | import io.vertx.core.json.JsonObject; 23 | import io.vertx.ext.jdbc.JDBCClient; 24 | import io.vertx.serviceproxy.ServiceBinder; 25 | 26 | import java.io.FileInputStream; 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.util.HashMap; 30 | import java.util.Properties; 31 | 32 | /** 33 | * @author Julien Ponge 34 | */ 35 | public class WikiDatabaseVerticle extends AbstractVerticle implements io.vertx.guides.wiki.DatabaseConstants { 36 | 37 | public static final String CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE = "wikidb.sqlqueries.resource.file"; 38 | public static final String CONFIG_WIKIDB_QUEUE = "wikidb.queue"; 39 | 40 | @Override 41 | public void start(Promise promise) throws Exception { 42 | 43 | HashMap sqlQueries = loadSqlQueries(); 44 | 45 | // tag::use-common-config[] 46 | JDBCClient dbClient = JDBCClient.createShared(vertx, new JsonObject() 47 | .put("url", config().getString(CONFIG_WIKIDB_JDBC_URL, DEFAULT_WIKIDB_JDBC_URL)) 48 | .put("driver_class", config().getString(CONFIG_WIKIDB_JDBC_DRIVER_CLASS, DEFAULT_WIKIDB_JDBC_DRIVER_CLASS)) 49 | .put("max_pool_size", config().getInteger(CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE, DEFAULT_JDBC_MAX_POOL_SIZE))); 50 | // end::use-common-config[] 51 | 52 | WikiDatabaseService.create(dbClient, sqlQueries, ready -> { 53 | if (ready.succeeded()) { 54 | ServiceBinder binder = new ServiceBinder(vertx); 55 | binder.setAddress(CONFIG_WIKIDB_QUEUE).register(WikiDatabaseService.class, ready.result()); 56 | promise.complete(); 57 | } else { 58 | promise.fail(ready.cause()); 59 | } 60 | }); 61 | } 62 | 63 | /* 64 | * Note: this uses blocking APIs, but data is small... 65 | */ 66 | private HashMap loadSqlQueries() throws IOException { 67 | 68 | String queriesFile = config().getString(CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE); 69 | InputStream queriesInputStream; 70 | if (queriesFile != null) { 71 | queriesInputStream = new FileInputStream(queriesFile); 72 | } else { 73 | queriesInputStream = getClass().getResourceAsStream("/db-queries.properties"); 74 | } 75 | 76 | Properties queriesProps = new Properties(); 77 | queriesProps.load(queriesInputStream); 78 | queriesInputStream.close(); 79 | 80 | HashMap sqlQueries = new HashMap<>(); 81 | sqlQueries.put(SqlQuery.CREATE_PAGES_TABLE, queriesProps.getProperty("create-pages-table")); 82 | sqlQueries.put(SqlQuery.ALL_PAGES, queriesProps.getProperty("all-pages")); 83 | sqlQueries.put(SqlQuery.GET_PAGE, queriesProps.getProperty("get-page")); 84 | sqlQueries.put(SqlQuery.CREATE_PAGE, queriesProps.getProperty("create-page")); 85 | sqlQueries.put(SqlQuery.SAVE_PAGE, queriesProps.getProperty("save-page")); 86 | sqlQueries.put(SqlQuery.DELETE_PAGE, queriesProps.getProperty("delete-page")); 87 | sqlQueries.put(SqlQuery.ALL_PAGES_DATA, queriesProps.getProperty("all-pages-data")); 88 | sqlQueries.put(SqlQuery.GET_PAGE_BY_ID, queriesProps.getProperty("get-page-by-id")); 89 | return sqlQueries; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /step-7/src/main/java/io/vertx/guides/wiki/database/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @author Julien Ponge 20 | */ 21 | @ModuleGen(groupPackage = "io.vertx.guides.wiki.database", name = "wiki-database") 22 | package io.vertx.guides.wiki.database; 23 | 24 | import io.vertx.codegen.annotations.ModuleGen; 25 | -------------------------------------------------------------------------------- /step-7/src/main/resources/auth-db-schema.sql: -------------------------------------------------------------------------------- 1 | create table if not exists user (username varchar(255), password varchar(255), password_salt varchar(255)); 2 | create table if not exists user_roles (username varchar(255), role varchar(255)); 3 | create table if not exists roles_perms (role varchar(255), perm varchar(255)); 4 | 5 | insert into roles_perms values ('writer', 'update'); 6 | insert into roles_perms values ('editor', 'create'); 7 | insert into roles_perms values ('editor', 'delete'); 8 | insert into roles_perms values ('editor', 'update'); 9 | insert into roles_perms values ('writer', 'update'); 10 | insert into roles_perms values ('admin', 'create'); 11 | insert into roles_perms values ('admin', 'delete'); 12 | insert into roles_perms values ('admin', 'update'); 13 | -------------------------------------------------------------------------------- /step-7/src/main/resources/db-queries.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | # Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | create-pages-table=create table if not exists Pages (Id integer identity primary key, Name varchar(255) unique, Content clob) 18 | get-page=select Id, Content from Pages where Name = ? 19 | get-page-by-id=select * from Pages where Id = ? 20 | create-page=insert into Pages values (NULL, ?, ?) 21 | save-page=update Pages set Content = ? where Id = ? 22 | all-pages=select Name from Pages 23 | delete-page=delete from Pages where Id = ? 24 | all-pages-data=select * from Pages 25 | -------------------------------------------------------------------------------- /step-7/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /step-7/src/main/resources/templates/footer.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /step-7/src/main/resources/templates/header.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | ${title} | A Sample Vert.x-powered Wiki 12 | 13 | 14 | 15 |
16 | -------------------------------------------------------------------------------- /step-7/src/main/resources/templates/index.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 | <#if canCreatePage> 7 |
8 |
9 |
10 | 11 |
12 | 13 |
14 |
15 | 16 |

${title}

17 | 20 |
21 | 22 |
23 | <#list pages> 24 |

Pages:

25 |
    26 | <#items as page> 27 |
  • ${page}
  • 28 | 29 |
30 | <#else> 31 |

The wiki is currently empty!

32 | 33 | 34 | <#if canCreatePage> 35 | <#if backup_gist_url?has_content> 36 | 40 | <#else> 41 |

42 | Backup 43 |

44 | 45 | 46 |
47 | 48 |
49 | 50 | <#include "footer.ftl"> 51 | -------------------------------------------------------------------------------- /step-7/src/main/resources/templates/login.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 |
7 |
8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | 16 |
17 | 18 | <#include "footer.ftl"> 19 | -------------------------------------------------------------------------------- /step-7/src/main/resources/templates/page.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 | 7 | Home 8 | <#if canSavePage> 9 | 11 | 12 | Logout (${username}) 13 | 14 |

15 | { 16 | ${title} 17 | } 18 |

19 |
20 | 21 |
22 | ${content} 23 |
24 | 25 | <#if canSavePage> 26 |
27 |
28 |
29 | 30 | 31 | 32 | 33 |
34 | 35 | <#if id != -1 && canDeletePage> 36 | 37 | 38 |
39 |
40 | 41 | 42 |
43 |
44 |

Rendered: ${timestamp}

45 |
46 | 47 |
48 | 49 | <#include "footer.ftl"> 50 | -------------------------------------------------------------------------------- /step-7/src/test/java/io/vertx/guides/wiki/http/SampleHttpServerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.http; 19 | 20 | import io.vertx.core.Promise; 21 | import io.vertx.core.Vertx; 22 | import io.vertx.core.buffer.Buffer; 23 | import io.vertx.ext.unit.Async; 24 | import io.vertx.ext.unit.TestContext; 25 | import io.vertx.ext.unit.junit.VertxUnitRunner; 26 | import io.vertx.ext.web.client.HttpResponse; 27 | import io.vertx.ext.web.client.WebClient; 28 | import org.junit.After; 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | import org.junit.runner.RunWith; 32 | 33 | /** 34 | * @author Julien Ponge 35 | */ 36 | @RunWith(VertxUnitRunner.class) 37 | public class SampleHttpServerTest { 38 | 39 | private Vertx vertx; 40 | 41 | @Before 42 | public void prepare() { 43 | vertx = Vertx.vertx(); 44 | } 45 | 46 | @After 47 | public void finish(TestContext context) { 48 | vertx.close(context.asyncAssertSuccess()); 49 | } 50 | 51 | @Test 52 | public void start_http_server(TestContext context) { 53 | Async async = context.async(); 54 | 55 | vertx 56 | .createHttpServer().requestHandler(req -> 57 | req.response().putHeader("Content-Type", "text/plain").end("Ok")) 58 | .listen(8080, context.asyncAssertSuccess(server -> { 59 | 60 | WebClient webClient = WebClient.create(vertx); 61 | 62 | webClient.get(8080, "localhost", "/").send(ar -> { 63 | if (ar.succeeded()) { 64 | HttpResponse response = ar.result(); 65 | context.assertTrue(response.headers().contains("Content-Type")); 66 | context.assertEquals("text/plain", response.getHeader("Content-Type")); 67 | context.assertEquals("Ok", response.bodyAsString()); 68 | webClient.close(); 69 | async.complete(); 70 | } else { 71 | async.resolve(Promise.failedPromise(ar.cause())); 72 | } 73 | }); 74 | })); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /step-8/gen-keystore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Keys for HTTPS..." 4 | 5 | keytool -genkey -alias test -keyalg RSA -keystore server-keystore.jks -keysize 2048 -validity 360 -dname CN=localhost -keypass secret -storepass secret 6 | 7 | echo "Done." 8 | -------------------------------------------------------------------------------- /step-8/redeploy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SET LAUNCHER="io.vertx.core.Launcher" 4 | SET VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | SET CMD="mvn compile" 6 | SET VERTX_CMD="run" 7 | SET CMD_LINE_ARGS=%* 8 | 9 | call mvn compile dependency:copy-dependencies 10 | 11 | java -cp "target\dependency\*;target\classes" %LAUNCHER% %VERTX_CMD% %VERTICLE% --redeploy="src\main\**\*" --on-redeploy=%CMD% --launcher-class=%LAUNCHER% %CMD_LINE_ARGS% --java-opts="-Dhsqldb.reconfig_logging=false" 12 | -------------------------------------------------------------------------------- /step-8/redeploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export LAUNCHER="io.vertx.core.Launcher" 4 | export VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | export CMD="mvn compile" 6 | export VERTX_CMD="run" 7 | 8 | mvn compile dependency:copy-dependencies 9 | java \ 10 | -cp $(echo target/dependency/*.jar | tr ' ' ':'):"target/classes" \ 11 | $LAUNCHER $VERTX_CMD $VERTICLE \ 12 | --redeploy="src/main/**/*" --on-redeploy=$CMD \ 13 | --launcher-class=$LAUNCHER \ 14 | --java-opts="-Dhsqldb.reconfig_logging=false" \ 15 | $@ 16 | -------------------------------------------------------------------------------- /step-8/src/main/java/io/vertx/guides/wiki/DatabaseConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | // tag::code[] 19 | package io.vertx.guides.wiki; 20 | 21 | public interface DatabaseConstants { 22 | 23 | String CONFIG_WIKIDB_JDBC_URL = "wikidb.jdbc.url"; 24 | String CONFIG_WIKIDB_JDBC_DRIVER_CLASS = "wikidb.jdbc.driver_class"; 25 | String CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE = "wikidb.jdbc.max_pool_size"; 26 | 27 | String DEFAULT_WIKIDB_JDBC_URL = "jdbc:hsqldb:file:db/wiki"; 28 | String DEFAULT_WIKIDB_JDBC_DRIVER_CLASS = "org.hsqldb.jdbcDriver"; 29 | int DEFAULT_JDBC_MAX_POOL_SIZE = 30; 30 | } 31 | // end::code[] 32 | -------------------------------------------------------------------------------- /step-8/src/main/java/io/vertx/guides/wiki/MainVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki; 19 | 20 | import io.reactivex.Single; 21 | import io.vertx.core.DeploymentOptions; 22 | import io.vertx.core.Promise; 23 | import io.vertx.reactivex.core.AbstractVerticle; 24 | 25 | /** 26 | * @author Julien Ponge 27 | */ 28 | public class MainVerticle extends AbstractVerticle { 29 | 30 | @Override 31 | public void start(Promise promise) throws Exception { 32 | 33 | // tag::rx-deploy-verticle[] 34 | Single dbVerticleDeployment = vertx.rxDeployVerticle( 35 | "io.vertx.guides.wiki.database.WikiDatabaseVerticle"); 36 | // end::rx-deploy-verticle[] 37 | 38 | // tag::rx-sequential-composition[] 39 | dbVerticleDeployment 40 | .flatMap(id -> { // <1> 41 | 42 | Single httpVerticleDeployment = vertx.rxDeployVerticle( 43 | "io.vertx.guides.wiki.http.HttpServerVerticle", 44 | new DeploymentOptions().setInstances(2)); 45 | 46 | return httpVerticleDeployment; 47 | }) 48 | .flatMap(id -> vertx.rxDeployVerticle("io.vertx.guides.wiki.http.AuthInitializerVerticle")) // <2> 49 | .subscribe(id -> promise.complete(), promise::fail); // <3> 50 | // end::rx-sequential-composition[] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /step-8/src/main/java/io/vertx/guides/wiki/database/ErrorCodes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | public enum ErrorCodes { 24 | NO_ACTION_SPECIFIED, 25 | BAD_ACTION, 26 | DB_ERROR 27 | } 28 | -------------------------------------------------------------------------------- /step-8/src/main/java/io/vertx/guides/wiki/database/SqlQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | enum SqlQuery { 24 | CREATE_PAGES_TABLE, 25 | ALL_PAGES, 26 | GET_PAGE, 27 | CREATE_PAGE, 28 | SAVE_PAGE, 29 | DELETE_PAGE, 30 | ALL_PAGES_DATA, 31 | GET_PAGE_BY_ID 32 | } 33 | -------------------------------------------------------------------------------- /step-8/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.codegen.annotations.Fluent; 21 | import io.vertx.codegen.annotations.GenIgnore; 22 | import io.vertx.codegen.annotations.ProxyGen; 23 | import io.vertx.codegen.annotations.VertxGen; 24 | import io.vertx.core.AsyncResult; 25 | import io.vertx.core.Handler; 26 | import io.vertx.core.Vertx; 27 | import io.vertx.core.json.JsonArray; 28 | import io.vertx.core.json.JsonObject; 29 | import io.vertx.ext.jdbc.JDBCClient; 30 | 31 | import java.util.HashMap; 32 | import java.util.List; 33 | 34 | /** 35 | * @author Julien Ponge 36 | */ 37 | @ProxyGen 38 | @VertxGen 39 | public interface WikiDatabaseService { 40 | 41 | @GenIgnore 42 | static WikiDatabaseService create(JDBCClient dbClient, HashMap sqlQueries, Handler> readyHandler) { 43 | return new WikiDatabaseServiceImpl(dbClient, sqlQueries, readyHandler); 44 | } 45 | 46 | @GenIgnore 47 | static io.vertx.guides.wiki.database.reactivex.WikiDatabaseService createProxy(Vertx vertx, String address) { 48 | return new io.vertx.guides.wiki.database.reactivex.WikiDatabaseService(new WikiDatabaseServiceVertxEBProxy(vertx, address)); 49 | } 50 | 51 | @Fluent 52 | WikiDatabaseService fetchAllPages(Handler> resultHandler); 53 | 54 | @Fluent 55 | WikiDatabaseService fetchPage(String name, Handler> resultHandler); 56 | 57 | @Fluent 58 | WikiDatabaseService fetchPageById(int id, Handler> resultHandler); 59 | 60 | @Fluent 61 | WikiDatabaseService createPage(String title, String markdown, Handler> resultHandler); 62 | 63 | @Fluent 64 | WikiDatabaseService savePage(int id, String markdown, Handler> resultHandler); 65 | 66 | @Fluent 67 | WikiDatabaseService deletePage(int id, Handler> resultHandler); 68 | 69 | @Fluent 70 | WikiDatabaseService fetchAllPagesData(Handler>> resultHandler); 71 | } 72 | -------------------------------------------------------------------------------- /step-8/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.Promise; 22 | import io.vertx.core.json.JsonObject; 23 | import io.vertx.ext.jdbc.JDBCClient; 24 | import io.vertx.serviceproxy.ServiceBinder; 25 | 26 | import java.io.FileInputStream; 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.util.HashMap; 30 | import java.util.Properties; 31 | 32 | /** 33 | * @author Julien Ponge 34 | */ 35 | public class WikiDatabaseVerticle extends AbstractVerticle { 36 | 37 | public static final String CONFIG_WIKIDB_JDBC_URL = "wikidb.jdbc.url"; 38 | public static final String CONFIG_WIKIDB_JDBC_DRIVER_CLASS = "wikidb.jdbc.driver_class"; 39 | public static final String CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE = "wikidb.jdbc.max_pool_size"; 40 | public static final String CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE = "wikidb.sqlqueries.resource.file"; 41 | public static final String CONFIG_WIKIDB_QUEUE = "wikidb.queue"; 42 | 43 | @Override 44 | public void start(Promise promise) throws Exception { 45 | 46 | HashMap sqlQueries = loadSqlQueries(); 47 | 48 | JDBCClient dbClient = JDBCClient.createShared(vertx, new JsonObject() 49 | .put("url", config().getString(CONFIG_WIKIDB_JDBC_URL, "jdbc:hsqldb:file:db/wiki")) 50 | .put("driver_class", config().getString(CONFIG_WIKIDB_JDBC_DRIVER_CLASS, "org.hsqldb.jdbcDriver")) 51 | .put("max_pool_size", config().getInteger(CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE, 30))); 52 | 53 | WikiDatabaseService.create(dbClient, sqlQueries, ready -> { 54 | if (ready.succeeded()) { 55 | ServiceBinder binder = new ServiceBinder(vertx); 56 | binder.setAddress(CONFIG_WIKIDB_QUEUE).register(WikiDatabaseService.class, ready.result()); 57 | promise.complete(); 58 | } else { 59 | promise.fail(ready.cause()); 60 | } 61 | }); 62 | } 63 | 64 | /* 65 | * Note: this uses blocking APIs, but data is small... 66 | */ 67 | private HashMap loadSqlQueries() throws IOException { 68 | 69 | String queriesFile = config().getString(CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE); 70 | InputStream queriesInputStream; 71 | if (queriesFile != null) { 72 | queriesInputStream = new FileInputStream(queriesFile); 73 | } else { 74 | queriesInputStream = getClass().getResourceAsStream("/db-queries.properties"); 75 | } 76 | 77 | Properties queriesProps = new Properties(); 78 | queriesProps.load(queriesInputStream); 79 | queriesInputStream.close(); 80 | 81 | HashMap sqlQueries = new HashMap<>(); 82 | sqlQueries.put(SqlQuery.CREATE_PAGES_TABLE, queriesProps.getProperty("create-pages-table")); 83 | sqlQueries.put(SqlQuery.ALL_PAGES, queriesProps.getProperty("all-pages")); 84 | sqlQueries.put(SqlQuery.GET_PAGE, queriesProps.getProperty("get-page")); 85 | sqlQueries.put(SqlQuery.CREATE_PAGE, queriesProps.getProperty("create-page")); 86 | sqlQueries.put(SqlQuery.SAVE_PAGE, queriesProps.getProperty("save-page")); 87 | sqlQueries.put(SqlQuery.DELETE_PAGE, queriesProps.getProperty("delete-page")); 88 | sqlQueries.put(SqlQuery.ALL_PAGES_DATA, queriesProps.getProperty("all-pages-data")); 89 | sqlQueries.put(SqlQuery.GET_PAGE_BY_ID, queriesProps.getProperty("get-page-by-id")); 90 | return sqlQueries; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /step-8/src/main/java/io/vertx/guides/wiki/database/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @author Julien Ponge 20 | */ 21 | @ModuleGen(groupPackage = "io.vertx.guides.wiki.database", name = "wiki-database") 22 | package io.vertx.guides.wiki.database; 23 | 24 | import io.vertx.codegen.annotations.ModuleGen; 25 | -------------------------------------------------------------------------------- /step-8/src/main/resources/db-queries.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | # Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | create-pages-table=create table if not exists Pages (Id integer identity primary key, Name varchar(255) unique, Content clob) 18 | get-page=select Id, Content from Pages where Name = ? 19 | get-page-by-id=select * from Pages where Id = ? 20 | create-page=insert into Pages values (NULL, ?, ?) 21 | save-page=update Pages set Content = ? where Id = ? 22 | all-pages=select Name from Pages 23 | delete-page=delete from Pages where Id = ? 24 | all-pages-data=select * from Pages 25 | -------------------------------------------------------------------------------- /step-8/src/main/resources/keystore.jceks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-8/src/main/resources/keystore.jceks -------------------------------------------------------------------------------- /step-8/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /step-8/src/main/resources/server-keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-8/src/main/resources/server-keystore.jks -------------------------------------------------------------------------------- /step-8/src/main/resources/templates/footer.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /step-8/src/main/resources/templates/header.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | ${title} | A Sample Vert.x-powered Wiki 12 | 13 | 14 | 15 |
16 | -------------------------------------------------------------------------------- /step-8/src/main/resources/templates/index.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 | <#if canCreatePage> 7 |
8 |
9 |
10 | 11 |
12 | 13 |
14 |
15 | 16 |

${title}

17 | 20 |
21 | 22 |
23 | <#list pages> 24 |

Pages:

25 |
    26 | <#items as page> 27 |
  • ${page}
  • 28 | 29 |
30 | <#else> 31 |

The wiki is currently empty!

32 | 33 | 34 | <#if canCreatePage> 35 | <#if backup_gist_url?has_content> 36 | 40 | <#else> 41 |

42 | Backup 43 |

44 | 45 | 46 |
47 | 48 |
49 | 50 | <#include "footer.ftl"> 51 | -------------------------------------------------------------------------------- /step-8/src/main/resources/templates/login.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 |
7 |
8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | 16 |
17 | 18 | <#include "footer.ftl"> 19 | -------------------------------------------------------------------------------- /step-8/src/main/resources/templates/page.ftl: -------------------------------------------------------------------------------- 1 | <#include "header.ftl"> 2 | 3 |
4 | 5 |
6 | 7 | Home 8 | <#if canSavePage> 9 | 11 | 12 | Logout (${username}) 13 | 14 |

15 | { 16 | ${title} 17 | } 18 |

19 |
20 | 21 |
22 | ${content} 23 |
24 | 25 | <#if canSavePage> 26 |
27 |
28 |
29 | 30 | 31 | 32 | 33 |
34 | 35 | <#if id != -1 && canDeletePage> 36 | 37 | 38 |
39 |
40 | 41 | 42 |
43 |
44 |

Rendered: ${timestamp}

45 |
46 | 47 |
48 | 49 | <#include "footer.ftl"> 50 | -------------------------------------------------------------------------------- /step-8/src/test/java/io/vertx/guides/wiki/http/SampleHttpServerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.http; 19 | 20 | import io.vertx.core.Promise; 21 | import io.vertx.core.Vertx; 22 | import io.vertx.core.buffer.Buffer; 23 | import io.vertx.ext.unit.Async; 24 | import io.vertx.ext.unit.TestContext; 25 | import io.vertx.ext.unit.junit.VertxUnitRunner; 26 | import io.vertx.ext.web.client.HttpResponse; 27 | import io.vertx.ext.web.client.WebClient; 28 | import org.junit.After; 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | import org.junit.runner.RunWith; 32 | 33 | /** 34 | * @author Julien Ponge 35 | */ 36 | @RunWith(VertxUnitRunner.class) 37 | public class SampleHttpServerTest { 38 | 39 | private Vertx vertx; 40 | 41 | @Before 42 | public void prepare() { 43 | vertx = Vertx.vertx(); 44 | } 45 | 46 | @After 47 | public void finish(TestContext context) { 48 | vertx.close(context.asyncAssertSuccess()); 49 | } 50 | 51 | @Test 52 | public void start_http_server(TestContext context) { 53 | Async async = context.async(); 54 | 55 | vertx 56 | .createHttpServer().requestHandler(req -> 57 | req.response().putHeader("Content-Type", "text/plain").end("Ok")) 58 | .listen(8080, context.asyncAssertSuccess(server -> { 59 | 60 | WebClient webClient = WebClient.create(vertx); 61 | 62 | webClient.get(8080, "localhost", "/").send(ar -> { 63 | if (ar.succeeded()) { 64 | HttpResponse response = ar.result(); 65 | context.assertTrue(response.headers().contains("Content-Type")); 66 | context.assertEquals("text/plain", response.getHeader("Content-Type")); 67 | context.assertEquals("Ok", response.bodyAsString()); 68 | webClient.close(); 69 | async.complete(); 70 | } else { 71 | async.resolve(Promise.failedPromise(ar.cause())); 72 | } 73 | }); 74 | })); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /step-9/images/edit-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-9/images/edit-page.png -------------------------------------------------------------------------------- /step-9/images/new-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vert-x3/vertx-guide-for-java-devs/846b56a5b6187d5368ded6a9bfda73f4549e8b57/step-9/images/new-page.png -------------------------------------------------------------------------------- /step-9/redeploy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SET LAUNCHER="io.vertx.core.Launcher" 4 | SET VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | SET CMD="mvn compile" 6 | SET VERTX_CMD="run" 7 | SET CMD_LINE_ARGS=%* 8 | 9 | call mvn compile dependency:copy-dependencies 10 | 11 | java -cp "target\dependency\*;target\classes" %LAUNCHER% %VERTX_CMD% %VERTICLE% --redeploy="src\main\**\*" --on-redeploy=%CMD% --launcher-class=%LAUNCHER% %CMD_LINE_ARGS% --java-opts="-Dhsqldb.reconfig_logging=false" 12 | -------------------------------------------------------------------------------- /step-9/redeploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export LAUNCHER="io.vertx.core.Launcher" 4 | export VERTICLE="io.vertx.guides.wiki.MainVerticle" 5 | export CMD="mvn compile" 6 | export VERTX_CMD="run" 7 | 8 | mvn compile dependency:copy-dependencies 9 | java \ 10 | -cp $(echo target/dependency/*.jar | tr ' ' ':'):"target/classes" \ 11 | $LAUNCHER $VERTX_CMD $VERTICLE \ 12 | --redeploy="src/main/**/*" --on-redeploy=$CMD \ 13 | --launcher-class=$LAUNCHER \ 14 | --java-opts="-Dhsqldb.reconfig_logging=false" \ 15 | $@ 16 | -------------------------------------------------------------------------------- /step-9/src/main/java/io/vertx/guides/wiki/MainVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki; 19 | 20 | import io.reactivex.Single; 21 | import io.vertx.core.DeploymentOptions; 22 | import io.vertx.core.Promise; 23 | import io.vertx.reactivex.core.AbstractVerticle; 24 | 25 | /** 26 | * @author Julien Ponge 27 | */ 28 | public class MainVerticle extends AbstractVerticle { 29 | 30 | @Override 31 | public void start(Promise promise) throws Exception { 32 | 33 | Single dbVerticleDeployment = vertx.rxDeployVerticle("io.vertx.guides.wiki.database.WikiDatabaseVerticle"); 34 | 35 | DeploymentOptions opts = new DeploymentOptions().setInstances(2); 36 | dbVerticleDeployment 37 | .flatMap(id -> vertx.rxDeployVerticle("io.vertx.guides.wiki.http.HttpServerVerticle", opts)) 38 | .subscribe(id -> promise.complete(), promise::fail); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /step-9/src/main/java/io/vertx/guides/wiki/database/ErrorCodes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | public enum ErrorCodes { 24 | NO_ACTION_SPECIFIED, 25 | BAD_ACTION, 26 | DB_ERROR 27 | } 28 | -------------------------------------------------------------------------------- /step-9/src/main/java/io/vertx/guides/wiki/database/SqlQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | /** 21 | * @author Julien Ponge 22 | */ 23 | enum SqlQuery { 24 | CREATE_PAGES_TABLE, 25 | ALL_PAGES, 26 | GET_PAGE, 27 | CREATE_PAGE, 28 | SAVE_PAGE, 29 | DELETE_PAGE, 30 | ALL_PAGES_DATA, 31 | GET_PAGE_BY_ID 32 | } 33 | -------------------------------------------------------------------------------- /step-9/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.codegen.annotations.Fluent; 21 | import io.vertx.codegen.annotations.GenIgnore; 22 | import io.vertx.codegen.annotations.ProxyGen; 23 | import io.vertx.codegen.annotations.VertxGen; 24 | import io.vertx.core.AsyncResult; 25 | import io.vertx.core.Handler; 26 | import io.vertx.core.Vertx; 27 | import io.vertx.core.json.JsonArray; 28 | import io.vertx.core.json.JsonObject; 29 | import io.vertx.ext.jdbc.JDBCClient; 30 | 31 | import java.util.HashMap; 32 | import java.util.List; 33 | 34 | /** 35 | * @author Julien Ponge 36 | */ 37 | @ProxyGen 38 | @VertxGen 39 | public interface WikiDatabaseService { 40 | 41 | @GenIgnore 42 | static WikiDatabaseService create(JDBCClient dbClient, HashMap sqlQueries, Handler> readyHandler) { 43 | return new WikiDatabaseServiceImpl(dbClient, sqlQueries, readyHandler); 44 | } 45 | 46 | @GenIgnore 47 | static io.vertx.guides.wiki.database.reactivex.WikiDatabaseService createProxy(Vertx vertx, String address) { 48 | return new io.vertx.guides.wiki.database.reactivex.WikiDatabaseService(new WikiDatabaseServiceVertxEBProxy(vertx, address)); 49 | } 50 | 51 | @Fluent 52 | WikiDatabaseService fetchAllPages(Handler> resultHandler); 53 | 54 | @Fluent 55 | WikiDatabaseService fetchPage(String name, Handler> resultHandler); 56 | 57 | @Fluent 58 | WikiDatabaseService fetchPageById(int id, Handler> resultHandler); 59 | 60 | @Fluent 61 | WikiDatabaseService createPage(String title, String markdown, Handler> resultHandler); 62 | 63 | @Fluent 64 | WikiDatabaseService savePage(int id, String markdown, Handler> resultHandler); 65 | 66 | @Fluent 67 | WikiDatabaseService deletePage(int id, Handler> resultHandler); 68 | 69 | @Fluent 70 | WikiDatabaseService fetchAllPagesData(Handler>> resultHandler); 71 | } 72 | -------------------------------------------------------------------------------- /step-9/src/main/java/io/vertx/guides/wiki/database/WikiDatabaseVerticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.vertx.guides.wiki.database; 19 | 20 | import io.vertx.core.AbstractVerticle; 21 | import io.vertx.core.Promise; 22 | import io.vertx.core.json.JsonObject; 23 | import io.vertx.ext.jdbc.JDBCClient; 24 | import io.vertx.serviceproxy.ServiceBinder; 25 | 26 | import java.io.FileInputStream; 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.util.HashMap; 30 | import java.util.Properties; 31 | 32 | /** 33 | * @author Julien Ponge 34 | */ 35 | public class WikiDatabaseVerticle extends AbstractVerticle { 36 | 37 | public static final String CONFIG_WIKIDB_JDBC_URL = "wikidb.jdbc.url"; 38 | public static final String CONFIG_WIKIDB_JDBC_DRIVER_CLASS = "wikidb.jdbc.driver_class"; 39 | public static final String CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE = "wikidb.jdbc.max_pool_size"; 40 | public static final String CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE = "wikidb.sqlqueries.resource.file"; 41 | public static final String CONFIG_WIKIDB_QUEUE = "wikidb.queue"; 42 | 43 | @Override 44 | public void start(Promise promise) throws Exception { 45 | 46 | HashMap sqlQueries = loadSqlQueries(); 47 | 48 | JDBCClient dbClient = JDBCClient.createShared(vertx, new JsonObject() 49 | .put("url", config().getString(CONFIG_WIKIDB_JDBC_URL, "jdbc:hsqldb:file:db/wiki")) 50 | .put("driver_class", config().getString(CONFIG_WIKIDB_JDBC_DRIVER_CLASS, "org.hsqldb.jdbcDriver")) 51 | .put("max_pool_size", config().getInteger(CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE, 30))); 52 | 53 | WikiDatabaseService.create(dbClient, sqlQueries, ready -> { 54 | if (ready.succeeded()) { 55 | ServiceBinder binder = new ServiceBinder(vertx); 56 | binder.setAddress(CONFIG_WIKIDB_QUEUE).register(WikiDatabaseService.class, ready.result()); 57 | promise.complete(); 58 | } else { 59 | promise.fail(ready.cause()); 60 | } 61 | }); 62 | } 63 | 64 | /* 65 | * Note: this uses blocking APIs, but data is small... 66 | */ 67 | private HashMap loadSqlQueries() throws IOException { 68 | 69 | String queriesFile = config().getString(CONFIG_WIKIDB_SQL_QUERIES_RESOURCE_FILE); 70 | InputStream queriesInputStream; 71 | if (queriesFile != null) { 72 | queriesInputStream = new FileInputStream(queriesFile); 73 | } else { 74 | queriesInputStream = getClass().getResourceAsStream("/db-queries.properties"); 75 | } 76 | 77 | Properties queriesProps = new Properties(); 78 | queriesProps.load(queriesInputStream); 79 | queriesInputStream.close(); 80 | 81 | HashMap sqlQueries = new HashMap<>(); 82 | sqlQueries.put(SqlQuery.CREATE_PAGES_TABLE, queriesProps.getProperty("create-pages-table")); 83 | sqlQueries.put(SqlQuery.ALL_PAGES, queriesProps.getProperty("all-pages")); 84 | sqlQueries.put(SqlQuery.GET_PAGE, queriesProps.getProperty("get-page")); 85 | sqlQueries.put(SqlQuery.CREATE_PAGE, queriesProps.getProperty("create-page")); 86 | sqlQueries.put(SqlQuery.SAVE_PAGE, queriesProps.getProperty("save-page")); 87 | sqlQueries.put(SqlQuery.DELETE_PAGE, queriesProps.getProperty("delete-page")); 88 | sqlQueries.put(SqlQuery.ALL_PAGES_DATA, queriesProps.getProperty("all-pages-data")); 89 | sqlQueries.put(SqlQuery.GET_PAGE_BY_ID, queriesProps.getProperty("get-page-by-id")); 90 | return sqlQueries; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /step-9/src/main/java/io/vertx/guides/wiki/database/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | * Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @author Julien Ponge 20 | */ 21 | @ModuleGen(groupPackage = "io.vertx.guides.wiki.database", name = "wiki-database") 22 | package io.vertx.guides.wiki.database; 23 | 24 | import io.vertx.codegen.annotations.ModuleGen; 25 | -------------------------------------------------------------------------------- /step-9/src/main/resources/db-queries.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. 3 | # Copyright (c) 2017 INSA Lyon, CITI Laboratory. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | create-pages-table=create table if not exists Pages (Id integer identity primary key, Name varchar(255) unique, Content clob) 18 | get-page=select Id, Content from Pages where Name = ? 19 | get-page-by-id=select * from Pages where Id = ? 20 | create-page=insert into Pages values (NULL, ?, ?) 21 | save-page=update Pages set Content = ? where Id = ? 22 | all-pages=select Name from Pages 23 | delete-page=delete from Pages where Id = ? 24 | all-pages-data=select * from Pages 25 | -------------------------------------------------------------------------------- /step-9/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | --------------------------------------------------------------------------------