├── .editorconfig
├── .github
└── workflows
│ └── maven.yml
├── .gitignore
├── LICENSE
├── README.md
├── buildProjects.sh
├── cdi
├── .gitignore
├── Dockerfile
├── README.md
├── buildAndRun.bat
├── buildAndRun.sh
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── de
│ │ │ └── rieckpil
│ │ │ └── blog
│ │ │ ├── decorators
│ │ │ ├── Account.java
│ │ │ ├── CustomerAccount.java
│ │ │ └── LargeWithdrawDecorator.java
│ │ │ ├── events
│ │ │ ├── BookRequest.java
│ │ │ ├── BookRequestListener.java
│ │ │ ├── BookRequestPublisher.java
│ │ │ └── ForeignBook.java
│ │ │ ├── injection
│ │ │ ├── BookService.java
│ │ │ ├── IsbnValidator.java
│ │ │ └── LoggerProducer.java
│ │ │ ├── interceptors
│ │ │ ├── BookPaymentInterceptor.java
│ │ │ ├── BookPaymentProvider.java
│ │ │ └── SecurePayment.java
│ │ │ └── qualifiers
│ │ │ ├── BookDistributor.java
│ │ │ ├── BookPlaneDistributor.java
│ │ │ ├── BookShipDistributor.java
│ │ │ ├── BookStorage.java
│ │ │ ├── PlaneDistributor.java
│ │ │ └── ShipDistributor.java
│ └── webapp
│ │ └── WEB-INF
│ │ ├── beans.xml
│ │ ├── ibm-web-ext.xml
│ │ └── payara-web.xml
│ └── test
│ ├── java
│ └── de
│ │ └── rieckpil
│ │ └── blog
│ │ └── ApplicationIT.java
│ └── resources
│ └── log4j.properties
├── jax-rs
├── .gitignore
├── Dockerfile
├── README.md
├── buildAndRun.bat
├── buildAndRun.sh
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── de.rieckpil.blog
│ │ │ ├── Book.java
│ │ │ ├── BookResource.java
│ │ │ ├── ClientLoggingResponseFilter.java
│ │ │ ├── ContainerLoggingRequestFilter.java
│ │ │ ├── GZIPReaderInterceptor.java
│ │ │ ├── GZIPWriterInterceptor.java
│ │ │ ├── HttpMethodModificationFilter.java
│ │ │ ├── JAXRSApplication.java
│ │ │ ├── Logged.java
│ │ │ ├── QuoteResource.java
│ │ │ ├── UserAgentClientFilter.java
│ │ │ └── XPoweredByResponseHeaderFilter.java
│ └── webapp
│ │ └── WEB-INF
│ │ ├── beans.xml
│ │ ├── ibm-web-ext.xml
│ │ └── payara-web.xml
│ └── test
│ ├── java
│ └── de
│ │ └── rieckpil
│ │ └── blog
│ │ └── ApplicationIT.java
│ └── resources
│ └── log4j.properties
├── json-b
├── .gitignore
├── Dockerfile
├── README.md
├── buildAndRun.bat
├── buildAndRun.sh
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── de
│ │ │ └── rieckpil
│ │ │ └── blog
│ │ │ ├── Book.java
│ │ │ ├── BookAdapter.java
│ │ │ ├── CollectionMapping.java
│ │ │ ├── ConfiguredMapping.java
│ │ │ ├── CustomMapping.java
│ │ │ └── ObjectMapping.java
│ └── webapp
│ │ └── WEB-INF
│ │ ├── beans.xml
│ │ ├── ibm-web-ext.xml
│ │ └── payara-web.xml
│ └── test
│ ├── java
│ └── de
│ │ └── rieckpil
│ │ └── blog
│ │ └── ApplicationIT.java
│ └── resources
│ └── log4j.properties
├── json-p
├── .gitignore
├── Dockerfile
├── README.md
├── buildAndRun.bat
├── buildAndRun.sh
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── de
│ │ │ └── rieckpil
│ │ │ └── blog
│ │ │ ├── ModifyJson.java
│ │ │ ├── ReadingJson.java
│ │ │ ├── StreamingJson.java
│ │ │ └── WritingJson.java
│ ├── resources
│ │ └── books.json
│ └── webapp
│ │ └── WEB-INF
│ │ ├── beans.xml
│ │ ├── ibm-web-ext.xml
│ │ └── payara-web.xml
│ └── test
│ ├── java
│ └── de
│ │ └── rieckpil
│ │ └── blog
│ │ └── ApplicationIT.java
│ └── resources
│ └── log4j.properties
├── microprofile-config
├── .gitignore
├── Dockerfile
├── README.md
├── buildAndRun.bat
├── buildAndRun.sh
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── de
│ │ │ └── rieckpil
│ │ │ └── blog
│ │ │ ├── BasicConfigurationInjection.java
│ │ │ ├── CustomConfigConverter.java
│ │ │ ├── CustomConfigObject.java
│ │ │ ├── CustomConfigSource.java
│ │ │ └── Token.java
│ ├── resources
│ │ └── META-INF
│ │ │ ├── microprofile-config.properties
│ │ │ └── services
│ │ │ ├── org.eclipse.microprofile.config.spi.ConfigSource
│ │ │ └── org.eclipse.microprofile.config.spi.Converter
│ └── webapp
│ │ └── WEB-INF
│ │ ├── beans.xml
│ │ ├── ibm-web-ext.xml
│ │ └── payara-web.xml
│ └── test
│ ├── java
│ └── de
│ │ └── rieckpil
│ │ └── blog
│ │ └── ApplicationIT.java
│ └── resources
│ └── log4j.properties
├── microprofile-fault-tolerance
├── .gitignore
├── Dockerfile
├── README.md
├── buildAndRun.bat
├── buildAndRun.sh
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── de
│ │ │ └── rieckpil
│ │ │ └── blog
│ │ │ ├── PlaceHolderApiFallback.java
│ │ │ ├── RandomDataPrinter.java
│ │ │ └── RandomDataProvider.java
│ ├── resources
│ │ └── META-INF
│ │ │ └── microprofile-config.properties
│ └── webapp
│ │ └── WEB-INF
│ │ ├── beans.xml
│ │ ├── ibm-web-ext.xml
│ │ └── payara-web.xml
│ └── test
│ ├── java
│ └── de
│ │ └── rieckpil
│ │ └── blog
│ │ └── ApplicationIT.java
│ └── resources
│ └── log4j.properties
├── microprofile-health
├── .gitignore
├── Dockerfile
├── README.md
├── buildAndRun.bat
├── buildAndRun.sh
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── de
│ │ │ └── rieckpil
│ │ │ └── blog
│ │ │ ├── DiskSizeCheck.java
│ │ │ ├── FlakyLivenessCheck.java
│ │ │ ├── MultipleHealthCheck.java
│ │ │ └── ReadinessCheck.java
│ └── webapp
│ │ └── WEB-INF
│ │ ├── beans.xml
│ │ ├── ibm-web-ext.xml
│ │ └── payara-web.xml
│ └── test
│ ├── java
│ └── de
│ │ └── rieckpil
│ │ └── blog
│ │ └── ApplicationIT.java
│ └── resources
│ └── log4j.properties
├── microprofile-jwt-auth
├── .gitignore
├── Dockerfile
├── README.md
├── buildAndRun.bat
├── buildAndRun.sh
├── jwtenizr.jar
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── de
│ │ │ └── rieckpil
│ │ │ └── blog
│ │ │ ├── BookResource.java
│ │ │ ├── JAXRSConfiguration.java
│ │ │ └── OrderResources.java
│ ├── resources
│ │ └── META-INF
│ │ │ ├── microprofile-config.properties
│ │ │ └── publicKey.pem
│ └── webapp
│ │ └── WEB-INF
│ │ ├── beans.xml
│ │ ├── ibm-web-ext.xml
│ │ └── payara-web.xml
│ └── test
│ ├── java
│ └── de
│ │ └── rieckpil
│ │ └── blog
│ │ └── ApplicationIT.java
│ └── resources
│ └── log4j.properties
├── microprofile-metrics
├── .gitignore
├── Dockerfile
├── README.md
├── buildAndRun.bat
├── buildAndRun.sh
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── de
│ │ │ └── rieckpil
│ │ │ └── blog
│ │ │ ├── BookCommentClient.java
│ │ │ ├── BookRequestProcessor.java
│ │ │ ├── BookResource.java
│ │ │ └── JAXRSConfiguration.java
│ ├── resources
│ │ └── META-INF
│ │ │ └── microprofile-config.properties
│ └── webapp
│ │ └── WEB-INF
│ │ ├── beans.xml
│ │ ├── ibm-web-ext.xml
│ │ └── payara-web.xml
│ └── test
│ ├── java
│ └── de
│ │ └── rieckpil
│ │ └── blog
│ │ └── ApplicationIT.java
│ └── resources
│ └── log4j.properties
├── microprofile-open-api
├── .gitignore
├── Dockerfile
├── README.md
├── buildAndRun.bat
├── buildAndRun.sh
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── de
│ │ │ └── rieckpil
│ │ │ └── blog
│ │ │ ├── Book.java
│ │ │ ├── BookResource.java
│ │ │ └── JAXRSConfiguration.java
│ └── webapp
│ │ └── WEB-INF
│ │ ├── beans.xml
│ │ ├── ibm-web-ext.xml
│ │ └── payara-web.xml
│ └── test
│ ├── java
│ └── de
│ │ └── rieckpil
│ │ └── blog
│ │ └── ApplicationIT.java
│ └── resources
│ └── log4j.properties
├── microprofile-open-tracing
├── .gitignore
├── README.md
├── book-store-client
│ ├── .gitignore
│ ├── Dockerfile
│ ├── extension
│ │ └── lib
│ │ │ ├── com.ibm.ws.io.opentracing.zipkintracer-0.31.jar
│ │ │ └── features
│ │ │ └── opentracingZipkin-0.31.mf
│ ├── pom.xml
│ ├── server.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── de
│ │ │ │ └── rieckpil
│ │ │ │ └── blog
│ │ │ │ ├── BookProvider.java
│ │ │ │ ├── BookResource.java
│ │ │ │ ├── JAXRSConfiguration.java
│ │ │ │ └── PriceCalculator.java
│ │ └── webapp
│ │ │ └── WEB-INF
│ │ │ ├── beans.xml
│ │ │ ├── ibm-web-ext.xml
│ │ │ └── payara-web.xml
│ │ └── test
│ │ ├── java
│ │ └── de
│ │ │ └── rieckpil
│ │ │ └── blog
│ │ │ └── ApplicationIT.java
│ │ └── resources
│ │ └── log4j.properties
├── book-store
│ ├── .gitignore
│ ├── Dockerfile
│ ├── extension
│ │ └── lib
│ │ │ ├── com.ibm.ws.io.opentracing.zipkintracer-0.31.jar
│ │ │ └── features
│ │ │ └── opentracingZipkin-0.31.mf
│ ├── pom.xml
│ ├── server.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── de
│ │ │ │ └── rieckpil
│ │ │ │ └── blog
│ │ │ │ ├── BookResource.java
│ │ │ │ ├── ContainerLoggingRequestFilter.java
│ │ │ │ ├── JAXRSConfiguration.java
│ │ │ │ └── PriceResource.java
│ │ └── webapp
│ │ │ └── WEB-INF
│ │ │ ├── beans.xml
│ │ │ ├── ibm-web-ext.xml
│ │ │ └── payara-web.xml
│ │ └── test
│ │ ├── java
│ │ └── de
│ │ │ └── rieckpil
│ │ │ └── blog
│ │ │ └── ApplicationIT.java
│ │ └── resources
│ │ └── log4j.properties
├── buildAndRun.bat
├── buildAndRun.sh
└── docker-compose.yml
├── microprofile-rest-client
├── .gitignore
├── Dockerfile
├── README.md
├── buildAndRun.bat
├── buildAndRun.sh
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── de
│ │ │ └── rieckpil
│ │ │ └── blog
│ │ │ ├── GlobalClientHeaders.java
│ │ │ ├── JSONPlaceholderClient.java
│ │ │ ├── PostService.java
│ │ │ └── ResponseLoggingFilter.java
│ ├── resources
│ │ └── META-INF
│ │ │ └── microprofile-config.properties
│ └── webapp
│ │ └── WEB-INF
│ │ ├── beans.xml
│ │ ├── ibm-web-ext.xml
│ │ └── payara-web.xml
│ └── test
│ ├── java
│ └── de
│ │ └── rieckpil
│ │ └── blog
│ │ └── ApplicationIT.java
│ └── resources
│ └── log4j.properties
├── pom.xml
└── server.xml
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | tab_width = 2
8 | end_of_line = lf
9 | charset = utf-8
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
--------------------------------------------------------------------------------
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | name: Build Java
2 | on: [push, pull_request]
3 | jobs:
4 | build:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - uses: actions/checkout@v1
8 | - uses: actions/cache@v1
9 | with:
10 | path: ~/.m2/repository
11 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
12 | restore-keys: |
13 | ${{ runner.os }}-maven-
14 | - name: Set up JDK 11
15 | uses: actions/setup-java@v1
16 | with:
17 | java-version: 11
18 | - name: Build projects
19 | run: ./buildProjects.sh
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .project
3 | .settings/
4 | .idea
5 | *.iml
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Philip Riecks
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Getting started with MicroProfile
2 |
3 | [](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/actions)
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | » Repository for the Getting Started with MicroProfile [Course Bundle](https://rieckpil.de/p/eclipse-microprofile-course-bundle).
12 |
13 | ## Specifications:
14 |
15 | * **CDI**: [YouTube Video](https://youtu.be/Q8jHRDu9Fbo) - [Blog post](https://rieckpil.de/whatis-contexts-and-dependency-injection-cdi/) - [Source code](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/tree/master/cdi)
16 | * **JAX-RS**: [YouTube Video](https://youtu.be/-TmKXm0k7UI) - [Blog post](https://rieckpil.de/whatis-jakarta-restful-web-services-jax-rs/) - [Source code](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/tree/master/jax-rs)
17 | * **JSON-B**: [YouTube Video](https://youtu.be/3TbbivV2Epk) - [Blog post](https://rieckpil.de/whatis-json-binding-json-b/) - [Source code](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/tree/master/json-b)
18 | * **JSON-P**: [YouTube Video](https://youtu.be/2H7z_MbWwDQ) - [Blog post](https://rieckpil.de/whatis-json-processing-json-p/) - [Source code](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/tree/master/json-p)
19 | * **MicroProfile Config**: [YouTube Video](https://youtu.be/0h3QceSBBiY) - [Blog post](https://rieckpil.de/whatis-eclipse-microprofile-config/) - [Source code](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/tree/master/microprofile-config)
20 | * **MicroProfile Fault Tolerance**: [YouTube Video](https://www.youtube.com/watch?v=_O4EjWHF0TQ) - [Blog post](https://rieckpil.de/whatis-eclipse-microprofile-fault-tolerance/) - [Source code](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/tree/master/microprofile-fault-tolerance)
21 | * **MicroProfile Metrics**: [YouTube Video](https://www.youtube.com/watch?v=jI6DoNYVd-U) - [Blog post](https://rieckpil.de/whatis-eclipse-microprofile-metrics/) - [Source code](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/tree/master/microprofile-metrics)
22 | * **MicroProfile JWT Auth**: [YouTube Video](https://youtu.be/8O3D2tNx1uM) - [Blog post](https://rieckpil.de/whatis-eclipse-microprofile-jwt-auth/) - [Source code](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/tree/master/microprofile-jwt-auth)
23 | * **MicroProfile Rest Client**: [YouTube Video](https://youtu.be/HJWxI_T3FKo) - [Blog post](https://rieckpil.de/whatis-eclipse-microprofile-rest-client/) - [Source code](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/tree/master/microprofile-rest-client)
24 | * **MicroProfile OpenAPI**: [YouTube Video](https://www.youtube.com/watch?v=Rn7T26UW_H8) - [Blog post](https://rieckpil.de/whatis-eclipse-microprofile-openapi/) - [Source code](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/tree/master/microprofile-open-api)
25 | * **MicroProfile OpenTracing**: [YouTube Video](https://www.youtube.com/watch?v=b43XgElBxEo) - [Blog post](https://rieckpil.de/whatis-eclipse-microprofile-opentracing/) - [Source code](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/tree/master/microprofile-open-tracing)
26 | * **MicroProfile Health**: [YouTube Video](https://www.youtube.com/watch?v=nq_gdPUTx5c) - [Blog post](https://rieckpil.de/whatis-eclipse-microprofile-health/) - [Source code](https://github.com/rieckpil/getting-started-with-eclipse-microprofile/tree/master/microprofile-health)
27 |
28 | ## Technologies used for this series:
29 |
30 | * **MicroProfile 3.3**
31 | * **OpenLiberty 20.0.0.5**
32 | * **Java 11**
33 | * **Maven 3.6**
34 | * **WAD** (Watch and Deploy) from [Adam Bien](https://wad.sh/) ([setup](https://rieckpil.de/review-improved-java-jakarta-ee-productivity-with-adam-biens-wad-watch-and-deploy/))
35 | * **JWTENIZR** from [Adam Bien](http://jwtenizr.sh/)
36 |
37 | ## Start the example applications
38 |
39 | Each subfolder contains a `buildAndRun.sh` (Linux/Mac) and `buildAndRun.bat` (Windows) file to build and start the application on your machine using **Docker**. You just need **Java 11** and **Maven** installed and a running Docker daemon to start everything. Once the application is up- and running, you can visit http://localhost:9080 to access it (if any JAX-RS endpoint is available in the project).
40 |
41 | ## Open Liberty configuration
42 |
43 | All projects use the following base `server.xml` configuration:
44 |
45 | ```xml
46 |
47 |
48 |
49 |
50 | microProfile-3.3
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | ```
61 |
62 | The following `ibm-web-ext.xml` is used within the project to deploy the application to the root path `/`:
63 |
64 | ```xml
65 |
70 |
71 |
72 | ```
73 |
--------------------------------------------------------------------------------
/buildProjects.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 | set -o pipefail
5 |
6 | declare -a arr=(
7 | "cdi"
8 | "jax-rs"
9 | "json-b"
10 | "json-p"
11 | "microprofile-config"
12 | "microprofile-fault-tolerance"
13 | "microprofile-health"
14 | "microprofile-jwt-auth"
15 | "microprofile-metrics"
16 | "microprofile-open-api"
17 | "microprofile-open-tracing/book-store"
18 | "microprofile-open-tracing/book-store-client"
19 | "microprofile-rest-client"
20 | )
21 |
22 | for project in "${arr[@]}"
23 | do
24 | mvn -B -f $project/pom.xml clean verify
25 | done
26 |
--------------------------------------------------------------------------------
/cdi/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/cdi/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/cdi.war /config/dropins/
4 | COPY --chown=1001:0 target/server.xml /config
5 |
6 | RUN configure.sh
7 |
--------------------------------------------------------------------------------
/cdi/README.md:
--------------------------------------------------------------------------------
1 | # CDI (Contexts and Dependency Injection)
2 |
3 | * [GitHub](https://github.com/eclipse-ee4j/cdi)
4 | * [Spec](http://www.cdi-spec.org/)
5 | * Current version: **2.0** in MicroProfile **3.0**
6 | * Detailed blog post about this specification: [#WHATIS?: Contexts and Dependency Injection (CDI)](https://rieckpil.de/whatis-contexts-and-dependency-injection-cdi/)
7 | * YouTube video about this specification: [Getting started with Eclipse MicroProfile 3.0 - CDI 2.0](https://youtu.be/Q8jHRDu9Fbo)
--------------------------------------------------------------------------------
/cdi/buildAndRun.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call mvn clean package
3 | call docker build -t de.rieckpil.blog/cdi .
4 | call docker rm -f cdi
5 | call docker run -d -p 9080:9080 -p 9443:9443 --name cdi de.rieckpil.blog/cdi
--------------------------------------------------------------------------------
/cdi/buildAndRun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mvn clean package && docker build -t de.rieckpil.blog/cdi .
3 | docker rm -f cdi || true && docker run -d -p 9080:9080 -p 9443:9443 --name cdi de.rieckpil.blog/cdi
--------------------------------------------------------------------------------
/cdi/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../pom.xml
10 |
11 |
12 | 4.0.0
13 | cdi
14 | 1.0-SNAPSHOT
15 | war
16 |
17 |
18 | ${project.artifactId}
19 |
20 |
21 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/decorators/Account.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.decorators;
2 |
3 | public interface Account {
4 |
5 | Double getBalance();
6 |
7 | void withdrawMoney(Double amount);
8 | }
9 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/decorators/CustomerAccount.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.decorators;
2 |
3 | public class CustomerAccount implements Account {
4 |
5 | @Override
6 | public Double getBalance() {
7 | return 42.0;
8 | }
9 |
10 | @Override
11 | public void withdrawMoney(Double amount) {
12 | System.out.println("Withdraw money from customer: " + amount);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/decorators/LargeWithdrawDecorator.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.decorators;
2 |
3 | import javax.decorator.Decorator;
4 | import javax.decorator.Delegate;
5 | import javax.inject.Inject;
6 |
7 | @Decorator
8 | // @Priority(100)
9 | public abstract class LargeWithdrawDecorator implements Account {
10 |
11 | @Inject
12 | @Delegate
13 | private Account account;
14 |
15 | @Override
16 | public void withdrawMoney(Double amount) {
17 | if (amount >= 100.0) {
18 | System.out.println("A large amount of money gets withdrawn!!!");
19 | // e.g. do further checks
20 | }
21 | account.withdrawMoney(amount);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/events/BookRequest.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.events;
2 |
3 | public class BookRequest {
4 |
5 | private String bookName;
6 | private Integer customerId;
7 |
8 | public BookRequest() {
9 | }
10 |
11 | public BookRequest(String bookName, Integer customerId) {
12 | this.bookName = bookName;
13 | this.customerId = customerId;
14 | }
15 |
16 | public String getBookName() {
17 | return bookName;
18 | }
19 |
20 | public void setBookName(String bookName) {
21 | this.bookName = bookName;
22 | }
23 |
24 | public Integer getCustomerId() {
25 | return customerId;
26 | }
27 |
28 | public void setCustomerId(Integer customerId) {
29 | this.customerId = customerId;
30 | }
31 |
32 | @Override
33 | public String toString() {
34 | return "BookRequest{" +
35 | "bookName='" + bookName + '\'' +
36 | ", customerId=" + customerId +
37 | '}';
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/events/BookRequestListener.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.events;
2 |
3 | import javax.enterprise.context.ApplicationScoped;
4 | import javax.enterprise.event.Observes;
5 | import javax.enterprise.event.ObservesAsync;
6 | import javax.enterprise.event.TransactionPhase;
7 | import javax.enterprise.inject.Default;
8 |
9 | @ApplicationScoped
10 | public class BookRequestListener {
11 |
12 | public void onBookRequest(@Observes(during = TransactionPhase.AFTER_SUCCESS) @Default BookRequest bookRequest) {
13 | System.out.println("New book request incoming: " + bookRequest.toString());
14 | }
15 |
16 | public void onBookForeignRequest(@Observes @ForeignBook BookRequest bookRequest) {
17 | System.out.println("New foreign book request incoming: " + bookRequest.toString());
18 | }
19 |
20 | public void onBookRequestAsync(@ObservesAsync BookRequest bookRequest) {
21 | System.out.println("New book request incoming async: " + bookRequest.toString());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/events/BookRequestPublisher.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.events;
2 |
3 | import javax.enterprise.context.ApplicationScoped;
4 | import javax.enterprise.context.Initialized;
5 | import javax.enterprise.event.Event;
6 | import javax.enterprise.event.Observes;
7 | import javax.inject.Inject;
8 |
9 | @ApplicationScoped
10 | public class BookRequestPublisher {
11 |
12 | @Inject
13 | private Event bookRequestEvent;
14 |
15 | @Inject
16 | @ForeignBook
17 | private Event foreignBookRequestEvent;
18 |
19 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
20 |
21 | this.bookRequestEvent.fire(new BookRequest("MicroProfile 3.0", 1));
22 | this.foreignBookRequestEvent.fire(new BookRequest("MicroProfile 3.0 (German)", 1));
23 |
24 | this.bookRequestEvent
25 | .fireAsync(new BookRequest("MicroProfile 3.0", 1))
26 | .handle((request, error) -> {
27 | if (error == null) {
28 | System.out.println("Successfully fired async event");
29 | return request;
30 | } else {
31 | System.out.println("Error occured during async event");
32 | return null;
33 | }
34 | })
35 | .thenAccept(r -> System.out.println(r));
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/events/ForeignBook.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.events;
2 |
3 | import javax.inject.Qualifier;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.Target;
6 |
7 | import static java.lang.annotation.ElementType.*;
8 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
9 |
10 | @Qualifier
11 | @Retention(RUNTIME)
12 | @Target({TYPE, METHOD, FIELD, PARAMETER})
13 | public @interface ForeignBook {
14 | }
15 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/injection/BookService.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.injection;
2 |
3 | import de.rieckpil.blog.decorators.CustomerAccount;
4 | import de.rieckpil.blog.interceptors.BookPaymentProvider;
5 |
6 | import javax.enterprise.context.ApplicationScoped;
7 | import javax.enterprise.context.Initialized;
8 | import javax.enterprise.event.Observes;
9 | import javax.inject.Inject;
10 | import java.util.logging.Logger;
11 |
12 | @ApplicationScoped
13 | public class BookService {
14 |
15 | @Inject
16 | private Logger logger;
17 |
18 | @Inject
19 | private IsbnValidator isbnValidator;
20 |
21 | @Inject
22 | private BookPaymentProvider paymentProvider;
23 |
24 | @Inject
25 | private CustomerAccount customerAccount;
26 |
27 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
28 | this.paymentProvider.withdrawMoneyFromCustomer("Duke", 123);
29 | this.paymentProvider.withdrawMoneyFromCustomer("Mike", 123);
30 |
31 | this.storeBook("Java 11", "123-3-42-133713-4");
32 | this.storeBook("Java 42", "123-3-42-133713-");
33 |
34 | this.customerAccount.withdrawMoney(42.0);
35 | this.customerAccount.withdrawMoney(142.0);
36 | }
37 |
38 | public void storeBook(String bookName, String isbn) {
39 | if (isbnValidator.validateIsbn(isbn)) {
40 | logger.info("Store book with name: " + bookName);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/injection/IsbnValidator.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.injection;
2 |
3 | import javax.inject.Inject;
4 | import java.util.logging.Logger;
5 |
6 | public class IsbnValidator {
7 |
8 | @Inject
9 | private Logger logger;
10 |
11 | public boolean validateIsbn(String isbn) {
12 | if (isbn.replace("-", "").length() < 13) {
13 | logger.warning("ISBN validation failed for ISBN: " + isbn);
14 | return false;
15 | }
16 | return true;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/injection/LoggerProducer.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.injection;
2 |
3 | import javax.enterprise.inject.Produces;
4 | import javax.enterprise.inject.spi.InjectionPoint;
5 | import java.util.logging.Logger;
6 |
7 | public class LoggerProducer {
8 |
9 | @Produces
10 | public Logger produceLogger(InjectionPoint injectionPoint) {
11 | return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/interceptors/BookPaymentInterceptor.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.interceptors;
2 |
3 | import javax.interceptor.AroundInvoke;
4 | import javax.interceptor.Interceptor;
5 | import javax.interceptor.InvocationContext;
6 |
7 | @Interceptor
8 | @SecurePayment
9 | public class BookPaymentInterceptor {
10 |
11 | @AroundInvoke
12 | public Object secureBookPayment(InvocationContext ctx) throws Exception {
13 | System.out.println("--- Intercepting: " + ctx.getMethod().getName());
14 |
15 | if (((String) ctx.getParameters()[0]).equalsIgnoreCase("Duke")) {
16 | ctx.setParameters(new Object[]{"Duke", 999});
17 | }
18 |
19 | return ctx.proceed();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/interceptors/BookPaymentProvider.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.interceptors;
2 |
3 | @SecurePayment
4 | public class BookPaymentProvider {
5 |
6 | public void withdrawMoneyFromCustomer(String customerName, Integer amount) {
7 | System.out.println("Withdraw money from: " + customerName + " amount: " + amount);
8 | }
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/interceptors/SecurePayment.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.interceptors;
2 |
3 | import javax.interceptor.InterceptorBinding;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.Target;
6 |
7 | import static java.lang.annotation.ElementType.METHOD;
8 | import static java.lang.annotation.ElementType.TYPE;
9 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
10 |
11 | @InterceptorBinding
12 | @Target({METHOD, TYPE})
13 | @Retention(RUNTIME)
14 | public @interface SecurePayment {
15 | }
16 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/qualifiers/BookDistributor.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.qualifiers;
2 |
3 | public interface BookDistributor {
4 |
5 | void distributeBook(String bookName);
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/qualifiers/BookPlaneDistributor.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.qualifiers;
2 |
3 | @PlaneDistributor
4 | public class BookPlaneDistributor implements BookDistributor {
5 |
6 | @Override
7 | public void distributeBook(String bookName) {
8 | System.out.println("Distributing book by plane");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/qualifiers/BookShipDistributor.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.qualifiers;
2 |
3 | @ShipDistributor
4 | public class BookShipDistributor implements BookDistributor {
5 |
6 | @Override
7 | public void distributeBook(String bookName) {
8 | System.out.println("Distributing book by ship");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/qualifiers/BookStorage.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.qualifiers;
2 |
3 | import javax.annotation.PostConstruct;
4 | import javax.annotation.PreDestroy;
5 | import javax.enterprise.context.ApplicationScoped;
6 | import javax.enterprise.inject.Instance;
7 | import javax.inject.Inject;
8 |
9 | @ApplicationScoped
10 | public class BookStorage {
11 |
12 | @Inject
13 | private Instance bookDistributors;
14 |
15 | @Inject
16 | @PlaneDistributor
17 | private BookDistributor bookPlaneDistributor;
18 |
19 | @Inject
20 | @ShipDistributor
21 | private BookDistributor bookShipDistributor;
22 |
23 | @PostConstruct
24 | public void init() {
25 | this.distributeBookToCustomer("Java for Beginners");
26 | }
27 |
28 | @PreDestroy
29 | public void onPreDestroy() {
30 | System.out.println("Bean is going to be destroyed");
31 | }
32 |
33 | public void distributeBookToCustomer(String bookName) {
34 | bookDistributors.forEach(b -> b.distributeBook(bookName));
35 | bookPlaneDistributor.distributeBook(bookName);
36 | bookShipDistributor.distributeBook(bookName);
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/qualifiers/PlaneDistributor.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.qualifiers;
2 |
3 | import javax.inject.Qualifier;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.Target;
6 |
7 | import static java.lang.annotation.ElementType.*;
8 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
9 |
10 | @Qualifier
11 | @Retention(RUNTIME)
12 | @Target({TYPE, METHOD, FIELD, PARAMETER})
13 | public @interface PlaneDistributor {
14 | }
15 |
--------------------------------------------------------------------------------
/cdi/src/main/java/de/rieckpil/blog/qualifiers/ShipDistributor.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog.qualifiers;
2 |
3 | import javax.inject.Qualifier;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.Target;
6 |
7 | import static java.lang.annotation.ElementType.*;
8 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
9 |
10 | @Qualifier
11 | @Retention(RUNTIME)
12 | @Target({TYPE, METHOD, FIELD, PARAMETER})
13 | public @interface ShipDistributor {
14 | }
15 |
--------------------------------------------------------------------------------
/cdi/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | de.rieckpil.blog.interceptors.BookPaymentInterceptor
8 |
9 |
10 | de.rieckpil.blog.decorators.LargeWithdrawDecorator
11 |
12 |
13 |
--------------------------------------------------------------------------------
/cdi/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/cdi/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/cdi/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/cdi/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/jax-rs/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/jax-rs/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/jax-rs.war /config/dropins/
4 | COPY --chown=1001:0 target/server.xml /config
5 |
6 | RUN configure.sh
7 |
--------------------------------------------------------------------------------
/jax-rs/README.md:
--------------------------------------------------------------------------------
1 | # JAX-RS: Jakarta RESTful Web Services
2 |
3 | * [GitHub](https://github.com/eclipse-ee4j/jaxrs-api)
4 | * [Spec homepage](https://projects.eclipse.org/projects/ee4j.jaxrs)
5 | * Current version: **2.1** in MicroProfile **3.0**
6 | * Detailed blog post about this specification: [#WHATIS?: Jakarta RESTful Web Services (JAX-RS)](https://rieckpil.de/whatis-jakarta-restful-web-services-jax-rs/)
7 | * YouTube video about this specification: [Getting started with Eclipse MicroProfile 3.0 - JAX-RS 2.1](https://youtu.be/-TmKXm0k7UI)
8 |
9 | ## Request & response flow
10 |
11 | ```
12 | CLIENT SERVER
13 | +----------------------------------------------------------------+ +-----------------------------------------------------------------------------------+
14 | | | | |
15 | | ClientRequestFilter -> WriterInterceptor -> MessageBodyWriter ----------> PreMatchingRequestFilter -> ContainerRequestFilter ---> ReaderInterceptor |
16 | | | | | |
17 | | | | v |
18 | | | | MessageBodyReader |
19 | | | | | |
20 | | | | v |
21 | | | | ResourceMethod |
22 | | | | | |
23 | | | | v |
24 | | MessageBodyReader <- ReaderInterceptor <- ClientResponseFilter <----------- MessageBodyWriter <--- WriterInterceptor <--- ContainerResponseFilter |
25 | | | | |
26 | +----------------------------------------------------------------+ +-----------------------------------------------------------------------------------+
27 | ```
--------------------------------------------------------------------------------
/jax-rs/buildAndRun.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call mvn clean package
3 | call docker build -t de.rieckpil.blog/jax-rs .
4 | call docker rm -f jax-rs
5 | call docker run -d -p 9080:9080 -p 9443:9443 --name jax-rs de.rieckpil.blog/jax-rs
--------------------------------------------------------------------------------
/jax-rs/buildAndRun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mvn clean package && docker build -t de.rieckpil.blog/jax-rs .
3 | docker rm -f jax-rs || true && docker run -d -p 9080:9080 -p 9443:9443 --name jax-rs de.rieckpil.blog/jax-rs
--------------------------------------------------------------------------------
/jax-rs/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../pom.xml
10 |
11 |
12 | 4.0.0
13 | de.rieckpil.blog
14 | jax-rs
15 | 1.0-SNAPSHOT
16 | war
17 |
18 |
19 | ${project.artifactId}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/jax-rs/src/main/java/de.rieckpil.blog/Book.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | public class Book {
4 |
5 | private Long id;
6 | private String title;
7 | private String author;
8 |
9 | public Book() {
10 |
11 | }
12 |
13 | public Book(Long id, String title, String author) {
14 | this.id = id;
15 | this.title = title;
16 | this.author = author;
17 | }
18 |
19 | public Long getId() {
20 | return id;
21 | }
22 |
23 | public void setId(Long id) {
24 | this.id = id;
25 | }
26 |
27 | public String getTitle() {
28 | return title;
29 | }
30 |
31 | public void setTitle(String title) {
32 | this.title = title;
33 | }
34 |
35 | public String getAuthor() {
36 | return author;
37 | }
38 |
39 | public void setAuthor(String author) {
40 | this.author = author;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/jax-rs/src/main/java/de.rieckpil.blog/BookResource.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.annotation.PostConstruct;
4 | import javax.ws.rs.*;
5 | import javax.ws.rs.container.AsyncResponse;
6 | import javax.ws.rs.container.Suspended;
7 | import javax.ws.rs.core.*;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | @Path("books")
12 | @Produces(MediaType.APPLICATION_JSON)
13 | @Consumes(MediaType.APPLICATION_JSON)
14 | public class BookResource {
15 |
16 | private List bookStore;
17 |
18 | @PostConstruct
19 | public void init() {
20 | this.bookStore = new ArrayList<>();
21 | this.bookStore.add(new Book(1L, "Java 11", "Duke"));
22 | this.bookStore.add(new Book(2L, "Java 12", "Duke"));
23 | this.bookStore.add(new Book(3L, "Java 13", "Duke"));
24 | }
25 |
26 | @GET
27 | @Logged
28 | public Response getBooks(@HeaderParam("User-Agent") String userAgent) {
29 | System.out.println(userAgent);
30 | return Response.ok(this.bookStore).build();
31 | }
32 |
33 | @GET
34 | @Path("async")
35 | public void getBooksAsync(@Suspended final AsyncResponse asyncResponse) {
36 | // do long-running task with e.g. @Asynchronous annotation of MicroProfile Fault Tolerance or from EJB
37 | asyncResponse.resume(this.bookStore);
38 | }
39 |
40 | @GET
41 | @Path("/{id}")
42 | public Response getBookById(@PathParam("id") Long id, @QueryParam("title") @DefaultValue("") String title) {
43 | Book requestedBook = this.bookStore
44 | .stream()
45 | .filter(b -> b.getId().equals(id))
46 | .findFirst().orElse(null);
47 |
48 | if (requestedBook == null) {
49 | return Response.status(Response.Status.NOT_FOUND).build();
50 | }
51 |
52 | return Response.ok(requestedBook).build();
53 | }
54 |
55 | @POST
56 | public Response createNewBook(Book bookToStore, @Context UriInfo uriInfo) {
57 | this.bookStore.add(bookToStore);
58 | UriBuilder builder = uriInfo.getAbsolutePathBuilder();
59 | builder.path(bookToStore.getId().toString());
60 | return Response.created(builder.build()).build();
61 | }
62 |
63 | @DELETE
64 | @Path("/{id}")
65 | public Response deleteBook(@PathParam("id") Long id, @HeaderParam("User-Agent") String userAgent) {
66 | this.bookStore.remove(id);
67 | return Response.noContent().build();
68 | }
69 | }
70 |
71 |
--------------------------------------------------------------------------------
/jax-rs/src/main/java/de.rieckpil.blog/ClientLoggingResponseFilter.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.client.ClientRequestContext;
4 | import javax.ws.rs.client.ClientResponseContext;
5 | import javax.ws.rs.client.ClientResponseFilter;
6 | import javax.ws.rs.ext.Provider;
7 | import java.io.IOException;
8 |
9 | @Provider
10 | public class ClientLoggingResponseFilter implements ClientResponseFilter {
11 |
12 | @Override
13 | public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
14 | System.out.println("Response filter for JAX-RS Client");
15 | responseContext.getHeaders().forEach((k, v) -> System.out.println(k + ":" + v));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/jax-rs/src/main/java/de.rieckpil.blog/ContainerLoggingRequestFilter.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.container.ContainerRequestContext;
4 | import javax.ws.rs.container.ContainerRequestFilter;
5 | import javax.ws.rs.ext.Provider;
6 | import java.time.LocalDateTime;
7 |
8 | @Provider
9 | @Logged
10 | public class ContainerLoggingRequestFilter implements ContainerRequestFilter {
11 |
12 | @Override
13 | public void filter(ContainerRequestContext requestContext) {
14 | System.out.println("==============");
15 | System.out.println("Incoming request at: " + LocalDateTime.now());
16 | requestContext.getHeaders().forEach((k, v) -> System.out.println(k + ":" + v));
17 | System.out.println("==============");
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/jax-rs/src/main/java/de.rieckpil.blog/GZIPReaderInterceptor.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.WebApplicationException;
4 | import javax.ws.rs.ext.ReaderInterceptor;
5 | import javax.ws.rs.ext.ReaderInterceptorContext;
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.util.zip.GZIPInputStream;
9 |
10 | public class GZIPReaderInterceptor implements ReaderInterceptor {
11 |
12 | @Override
13 | public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
14 | final InputStream originalInputStream = context.getInputStream();
15 | context.setInputStream(new GZIPInputStream(originalInputStream));
16 | return context.proceed();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/jax-rs/src/main/java/de.rieckpil.blog/GZIPWriterInterceptor.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.WebApplicationException;
4 | import javax.ws.rs.ext.WriterInterceptor;
5 | import javax.ws.rs.ext.WriterInterceptorContext;
6 | import java.io.IOException;
7 | import java.io.OutputStream;
8 | import java.util.zip.GZIPOutputStream;
9 |
10 | public class GZIPWriterInterceptor implements WriterInterceptor {
11 |
12 | @Override
13 | public void aroundWriteTo(WriterInterceptorContext context)
14 | throws IOException, WebApplicationException {
15 |
16 | final OutputStream outputStream = context.getOutputStream();
17 | context.setOutputStream(new GZIPOutputStream(outputStream));
18 | context.proceed();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/jax-rs/src/main/java/de.rieckpil.blog/HttpMethodModificationFilter.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.container.ContainerRequestContext;
4 | import javax.ws.rs.container.ContainerRequestFilter;
5 | import java.io.IOException;
6 |
7 | // uncomment to activate this evil filter ;)
8 | // @Provider
9 | public class HttpMethodModificationFilter implements ContainerRequestFilter {
10 |
11 | @Override
12 | public void filter(ContainerRequestContext requestContext) throws IOException {
13 |
14 | if (requestContext.getMethod().equalsIgnoreCase("DELETE")) {
15 | requestContext.setMethod("GET");
16 | }
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/jax-rs/src/main/java/de.rieckpil.blog/JAXRSApplication.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.ApplicationPath;
4 | import javax.ws.rs.core.Application;
5 |
6 | @ApplicationPath("resources")
7 | public class JAXRSApplication extends Application {
8 | }
9 |
--------------------------------------------------------------------------------
/jax-rs/src/main/java/de.rieckpil.blog/Logged.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.NameBinding;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 |
7 | @NameBinding
8 | @Retention(RetentionPolicy.RUNTIME)
9 | public @interface Logged {
10 | }
11 |
--------------------------------------------------------------------------------
/jax-rs/src/main/java/de.rieckpil.blog/QuoteResource.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.annotation.PostConstruct;
4 | import javax.annotation.PreDestroy;
5 | import javax.json.JsonObject;
6 | import javax.ws.rs.*;
7 | import javax.ws.rs.client.Client;
8 | import javax.ws.rs.client.ClientBuilder;
9 | import javax.ws.rs.client.WebTarget;
10 | import javax.ws.rs.core.MediaType;
11 | import javax.ws.rs.core.Response;
12 | import java.util.concurrent.CompletionStage;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | @Path("quotes")
16 | public class QuoteResource {
17 |
18 | private WebTarget quotesApiTarget;
19 | private Client client;
20 |
21 | @PostConstruct
22 | public void initClient() {
23 |
24 | ClientBuilder clientBuilder = ClientBuilder.newBuilder()
25 | .connectTimeout(5, TimeUnit.SECONDS)
26 | .readTimeout(5, TimeUnit.SECONDS)
27 | .register(UserAgentClientFilter.class)
28 | .register(ClientLoggingResponseFilter.class);
29 |
30 | this.client = clientBuilder.build();
31 | this.quotesApiTarget = client.target("https://quotes.rest").path("qod");
32 | }
33 |
34 | @PreDestroy
35 | public void tearDown() {
36 | this.client.close();
37 | }
38 |
39 | @GET
40 | @Produces(MediaType.TEXT_PLAIN)
41 | public Response getQuote() {
42 |
43 | JsonObject quoteApiResult = this.quotesApiTarget
44 | .request()
45 | .header("X-Foo", "bar")
46 | .accept(MediaType.APPLICATION_JSON)
47 | .get()
48 | .readEntity(JsonObject.class);
49 |
50 | CompletionStage rxQuoteApiResult = this.quotesApiTarget
51 | .request()
52 | .header("X-Foo", "bar")
53 | .accept(MediaType.APPLICATION_JSON)
54 | .rx()
55 | .get(JsonObject.class);
56 |
57 | String quote = quoteApiResult
58 | .get("contents").asJsonObject()
59 | .get("quotes").asJsonArray().get(0).asJsonObject()
60 | .get("quote").toString();
61 |
62 | return Response.ok(quote).build();
63 | }
64 |
65 | @POST
66 | @Consumes(MediaType.TEXT_PLAIN)
67 | public Response createQuote(String text) {
68 | System.out.println(text);
69 | return Response.created(null).build();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/jax-rs/src/main/java/de.rieckpil.blog/UserAgentClientFilter.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.client.ClientRequestContext;
4 | import javax.ws.rs.client.ClientRequestFilter;
5 | import javax.ws.rs.ext.Provider;
6 | import java.io.IOException;
7 |
8 | @Provider
9 | public class UserAgentClientFilter implements ClientRequestFilter {
10 |
11 | @Override
12 | public void filter(ClientRequestContext requestContext) throws IOException {
13 | requestContext.getHeaders().add("User-Agent", "MP-Service-XYZ");
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/jax-rs/src/main/java/de.rieckpil.blog/XPoweredByResponseHeaderFilter.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.annotation.Priority;
4 | import javax.ws.rs.container.ContainerRequestContext;
5 | import javax.ws.rs.container.ContainerResponseContext;
6 | import javax.ws.rs.container.ContainerResponseFilter;
7 | import javax.ws.rs.ext.Provider;
8 | import java.io.IOException;
9 |
10 | @Priority(100)
11 | @Provider
12 | public class XPoweredByResponseHeaderFilter implements ContainerResponseFilter {
13 |
14 | @Override
15 | public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
16 | responseContext.getHeaders().add("X-Powered-By", "MicroProfile");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/jax-rs/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/jax-rs/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/jax-rs/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/jax-rs/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/jax-rs/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/json-b/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/json-b/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/json-b.war /config/dropins/
4 | COPY --chown=1001:0 target/server.xml /config
5 |
6 | RUN configure.sh
7 |
--------------------------------------------------------------------------------
/json-b/README.md:
--------------------------------------------------------------------------------
1 | # JSON-B: Java API for JSON Binding
2 |
3 | * [GitHub](https://github.com/eclipse-ee4j/jsonb-api)
4 | * [Spec](https://javaee.github.io/jsonb-spec/index.html)
5 | * Current version: **1.0** in MicroProfile **3.0**
6 | * Detailed blog post about this specification: [#WHATIS?: JSON Binding (JSON-B)](https://rieckpil.de/whatis-json-binding-json-b/)
7 | * YouTube video about this specification: [Getting started with Eclipse MicroProfile 3.0 - JSON-B 1.0](https://youtu.be/3TbbivV2Epk)
8 |
--------------------------------------------------------------------------------
/json-b/buildAndRun.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call mvn clean package
3 | call docker build -t de.rieckpil.blog/json-b .
4 | call docker rm -f json-b
5 | call docker run -d -p 9080:9080 -p 9443:9443 --name json-b de.rieckpil.blog/json-b
--------------------------------------------------------------------------------
/json-b/buildAndRun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mvn clean package && docker build -t de.rieckpil.blog/json-b .
3 | docker rm -f json-b || true && docker run -d -p 9080:9080 -p 9443:9443 --name json-b de.rieckpil.blog/json-b
--------------------------------------------------------------------------------
/json-b/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../pom.xml
10 |
11 |
12 | 4.0.0
13 | de.rieckpil.blog
14 | json-b
15 | 1.0-SNAPSHOT
16 | war
17 |
18 |
19 | ${project.artifactId}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/json-b/src/main/java/de/rieckpil/blog/Book.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.json.bind.annotation.JsonbDateFormat;
4 | import javax.json.bind.annotation.JsonbNumberFormat;
5 | import javax.json.bind.annotation.JsonbProperty;
6 | import javax.json.bind.annotation.JsonbTransient;
7 | import java.math.BigDecimal;
8 | import java.time.LocalDate;
9 |
10 | // @JsonbNillable
11 | public class Book {
12 |
13 | @JsonbProperty(nillable = true)
14 | private String title;
15 |
16 | @JsonbDateFormat("dd.MM.yyyy")
17 | private LocalDate creationDate;
18 | private long pages;
19 |
20 | @JsonbTransient
21 | private boolean isPublished;
22 | private String author;
23 |
24 | @JsonbNumberFormat("#0.00")
25 | private BigDecimal price;
26 |
27 | public Book() {
28 | }
29 |
30 | // @JsonbCreator
31 | public Book(@JsonbProperty("book-title") String title) {
32 | this.title = title;
33 | }
34 |
35 | public Book(String title, LocalDate creationDate, long pages, boolean isPublished, String author, BigDecimal price) {
36 | this.title = title;
37 | this.creationDate = creationDate;
38 | this.pages = pages;
39 | this.isPublished = isPublished;
40 | this.author = author;
41 | this.price = price;
42 | }
43 |
44 | public String getTitle() {
45 | return title;
46 | }
47 |
48 | public void setTitle(String title) {
49 | this.title = title;
50 | }
51 |
52 | public LocalDate getCreationDate() {
53 | return creationDate;
54 | }
55 |
56 | public void setCreationDate(LocalDate creationDate) {
57 | this.creationDate = creationDate;
58 | }
59 |
60 | public long getPages() {
61 | return pages;
62 | }
63 |
64 | public void setPages(long pages) {
65 | this.pages = pages;
66 | }
67 |
68 | public boolean isPublished() {
69 | return isPublished;
70 | }
71 |
72 | public void setPublished(boolean published) {
73 | isPublished = published;
74 | }
75 |
76 | public String getAuthor() {
77 | return author;
78 | }
79 |
80 | public void setAuthor(String author) {
81 | this.author = author;
82 | }
83 |
84 | public BigDecimal getPrice() {
85 | return price;
86 | }
87 |
88 | public void setPrice(BigDecimal price) {
89 | this.price = price;
90 | }
91 |
92 | @Override
93 | public String toString() {
94 | return "Book{" +
95 | "title='" + title + '\'' +
96 | ", creationDate=" + creationDate +
97 | ", pages=" + pages +
98 | ", isPublished=" + isPublished +
99 | ", author='" + author + '\'' +
100 | ", price=" + price +
101 | '}';
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/json-b/src/main/java/de/rieckpil/blog/BookAdapter.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.json.Json;
4 | import javax.json.JsonObject;
5 | import javax.json.bind.adapter.JsonbAdapter;
6 | import java.math.BigDecimal;
7 | import java.time.LocalDate;
8 |
9 | public class BookAdapter implements JsonbAdapter {
10 |
11 | @Override
12 | public JsonObject adaptToJson(Book book) throws Exception {
13 | return Json.createObjectBuilder()
14 | .add("title", book.getTitle() + " - " + book.getAuthor())
15 | .add("creationDate", book.getCreationDate().toEpochDay())
16 | .add("pages", book.getPages())
17 | .add("price", book.getPrice().multiply(BigDecimal.valueOf(2l)))
18 | .build();
19 | }
20 |
21 | @Override
22 | public Book adaptFromJson(JsonObject jsonObject) throws Exception {
23 | Book book = new Book();
24 | book.setTitle(jsonObject.getString("title").split("-")[0].trim());
25 | book.setAuthor(jsonObject.getString("title").split("-")[1].trim());
26 | book.setPages(jsonObject.getInt("pages"));
27 | book.setPublished(false);
28 | book.setPrice(BigDecimal.valueOf(jsonObject.getJsonNumber("price").longValue()));
29 | book.setCreationDate(LocalDate.ofEpochDay(jsonObject.getInt("creationDate")));
30 | return book;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/json-b/src/main/java/de/rieckpil/blog/CollectionMapping.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.enterprise.context.ApplicationScoped;
4 | import javax.enterprise.context.Initialized;
5 | import javax.enterprise.event.Observes;
6 | import javax.json.bind.Jsonb;
7 | import javax.json.bind.JsonbBuilder;
8 | import java.math.BigDecimal;
9 | import java.time.LocalDate;
10 | import java.time.temporal.ChronoUnit;
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | @ApplicationScoped
15 | public class CollectionMapping {
16 |
17 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
18 | List bookList = new ArrayList<>();
19 | bookList.add(new Book("Java 11", LocalDate.now(), 100, true, "Duke", new BigDecimal(39.95)));
20 | bookList.add(new Book("Java 15", LocalDate.now().plus(365, ChronoUnit.DAYS), 110, false, "Duke", new BigDecimal(50.002)));
21 |
22 | Jsonb jsonb = JsonbBuilder.create();
23 |
24 | String result = jsonb.toJson(bookList);
25 | System.out.println(result);
26 |
27 | List serializedBookList = jsonb
28 | .fromJson(result, new ArrayList() {
29 | }.getClass().getGenericSuperclass());
30 |
31 | serializedBookList.forEach(b -> System.out.println(b.toString()));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/json-b/src/main/java/de/rieckpil/blog/ConfiguredMapping.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.enterprise.context.ApplicationScoped;
4 | import javax.enterprise.context.Initialized;
5 | import javax.enterprise.event.Observes;
6 | import javax.json.bind.Jsonb;
7 | import javax.json.bind.JsonbBuilder;
8 | import javax.json.bind.JsonbConfig;
9 | import javax.json.bind.config.PropertyNamingStrategy;
10 | import javax.json.bind.config.PropertyOrderStrategy;
11 | import java.math.BigDecimal;
12 | import java.time.LocalDate;
13 | import java.util.Locale;
14 |
15 | @ApplicationScoped
16 | public class ConfiguredMapping {
17 |
18 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
19 |
20 | Book book = new Book("Java 11", LocalDate.now(), 1, false, null, new BigDecimal(50.50));
21 |
22 | JsonbConfig config = new JsonbConfig()
23 | .withNullValues(false)
24 | .withFormatting(true)
25 | .withPropertyOrderStrategy(PropertyOrderStrategy.LEXICOGRAPHICAL)
26 | .withPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE_WITH_UNDERSCORES)
27 | .withDateFormat("dd-MM-YYYY", Locale.GERMAN);
28 |
29 | Jsonb jsonb = JsonbBuilder.create(config);
30 |
31 | String jsonString = jsonb.toJson(book);
32 | System.out.println(jsonString);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/json-b/src/main/java/de/rieckpil/blog/CustomMapping.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.enterprise.context.ApplicationScoped;
4 | import javax.enterprise.context.Initialized;
5 | import javax.enterprise.event.Observes;
6 | import javax.json.bind.Jsonb;
7 | import javax.json.bind.JsonbBuilder;
8 | import javax.json.bind.JsonbConfig;
9 | import java.math.BigDecimal;
10 | import java.time.LocalDate;
11 |
12 | @ApplicationScoped
13 | public class CustomMapping {
14 |
15 | private Book book = new Book("Java 11", LocalDate.now(), 1, false, "Duke", new BigDecimal(33.333));
16 |
17 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
18 | JsonbConfig config = new JsonbConfig()
19 | .withAdapters(new BookAdapter());
20 |
21 | Jsonb jsonb = JsonbBuilder.create(config);
22 |
23 | String jsonString = jsonb.toJson(book);
24 | System.out.println(jsonString);
25 |
26 | Book serializedBook = jsonb.fromJson(jsonString, Book.class);
27 | System.out.println(serializedBook);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/json-b/src/main/java/de/rieckpil/blog/ObjectMapping.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.enterprise.context.ApplicationScoped;
4 | import javax.enterprise.context.Initialized;
5 | import javax.enterprise.event.Observes;
6 | import javax.json.bind.Jsonb;
7 | import javax.json.bind.JsonbBuilder;
8 | import java.math.BigDecimal;
9 | import java.time.LocalDate;
10 |
11 | @ApplicationScoped
12 | public class ObjectMapping {
13 |
14 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
15 |
16 | Book book = new Book("Java 11", LocalDate.now(), 1, false, "Duke", new BigDecimal(44.444));
17 |
18 | Jsonb jsonb = JsonbBuilder.create();
19 |
20 | String resultJson = jsonb.toJson(book);
21 | System.out.println(resultJson);
22 |
23 | Book serializedBook = jsonb.fromJson(resultJson, Book.class);
24 | System.out.println(serializedBook.toString());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/json-b/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/json-b/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/json-b/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/json-b/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/json-b/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/json-p/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/json-p/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/json-p.war /config/dropins/
4 | COPY --chown=1001:0 target/server.xml /config
5 |
6 | RUN configure.sh
7 |
--------------------------------------------------------------------------------
/json-p/README.md:
--------------------------------------------------------------------------------
1 | # JSON-P: Java API for JSON Processing
2 |
3 | * [GitHub](https://github.com/eclipse-ee4j/jsonp)
4 | * [Spec](https://javaee.github.io/jsonp/)
5 | * Current version: **1.1** in MicroProfile **3.0**
6 | * Detailed blog post about this specification: [#WHATIS?: JSON Processing (JSON-P)](https://rieckpil.de/whatis-json-processing-json-p/)
7 | * YouTube video about this specification: [Getting started with Eclipse MicroProfile 3.0 - JSON-P 1.1](https://youtu.be/2H7z_MbWwDQ)
--------------------------------------------------------------------------------
/json-p/buildAndRun.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call mvn clean package
3 | call docker build -t de.rieckpil.blog/json-p .
4 | call docker rm -f json-p
5 | call docker run -d -p 9080:9080 -p 9443:9443 --name json-p de.rieckpil.blog/json-p
--------------------------------------------------------------------------------
/json-p/buildAndRun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mvn clean package && docker build -t de.rieckpil.blog/json-p .
3 | docker rm -f json-p || true && docker run -d -p 9080:9080 -p 9443:9443 --name json-p de.rieckpil.blog/json-p
--------------------------------------------------------------------------------
/json-p/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../pom.xml
10 |
11 |
12 | 4.0.0
13 | de.rieckpil.blog
14 | json-p
15 | 1.0-SNAPSHOT
16 | war
17 |
18 |
19 | ${project.artifactId}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/json-p/src/main/java/de/rieckpil/blog/ModifyJson.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.enterprise.context.ApplicationScoped;
4 | import javax.enterprise.context.Initialized;
5 | import javax.enterprise.event.Observes;
6 | import javax.json.*;
7 | import java.io.StringReader;
8 |
9 | public class ModifyJson {
10 |
11 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
12 | jsonPatch();
13 | jsonMergePatch();
14 | jsonPointer();
15 | }
16 |
17 | // read the official spec here: https://tools.ietf.org/html/rfc6901
18 | private void jsonPointer() {
19 | String jsonString = "{\"name\":\"duke\",\"age\":42,\"skills\":[\"Java SE\", \"Java EE\"]}";
20 |
21 | JsonObject jsonObject = Json.createReader(new StringReader(jsonString)).readObject();
22 |
23 | JsonPointer arrayElementPointer = Json.createPointer("/skills/1");
24 | JsonPointer agePointer = Json.createPointer("/age");
25 | JsonPointer namePointer = Json.createPointer("/name");
26 | JsonPointer addressPointer = Json.createPointer("/address");
27 | JsonPointer tagsPointer = Json.createPointer("/tags");
28 |
29 | System.out.println("Get array element with pointer: " + arrayElementPointer.getValue(jsonObject).toString());
30 | System.out.println("Remove age with pointer: " + agePointer.remove(jsonObject));
31 | System.out.println("Replace name with pointer: " + namePointer.replace(jsonObject, Json.createValue("john")));
32 | System.out.println("Check address with pointer: " + addressPointer.containsValue(jsonObject));
33 | System.out.println("Add tags with pointer: " + tagsPointer.add(jsonObject, Json.createArrayBuilder().add("nice").build()));
34 | }
35 |
36 | // read the official spec here: https://tools.ietf.org/html/rfc7386
37 | private void jsonMergePatch() {
38 | String jsonString = "{\"name\":\"duke\",\"age\":42,\"skills\":[\"Java SE\", \"Java EE\"]}";
39 |
40 | JsonObject jsonObject = Json.createReader(new StringReader(jsonString)).readObject();
41 |
42 | JsonObject merge = Json.createObjectBuilder()
43 | .add("name", "duke2")
44 | .add("isEmployee", true)
45 | .add("skills", Json.createArrayBuilder()
46 | .add("CSS")
47 | .add("HTML")
48 | .add("JavaScript")
49 | .build())
50 | .build();
51 |
52 | JsonMergePatch mergePatch = Json.createMergePatch(merge);
53 | JsonValue mergedJson = mergePatch.apply(jsonObject);
54 | System.out.println("Merged JSON: " + mergedJson);
55 | }
56 |
57 | // read the official spec here: https://tools.ietf.org/html/rfc6902
58 | private void jsonPatch() {
59 | String jsonString = "{\"name\":\"duke\",\"age\":42,\"skills\":[\"Java SE\", \"Java EE\"]}";
60 |
61 | JsonObject jsonObject = Json.createReader(new StringReader(jsonString)).readObject();
62 |
63 | JsonPatch patch = Json.createPatchBuilder()
64 | .add("/isRetired", false)
65 | .add("/skills/2", "Jakarta EE")
66 | .remove("/age")
67 | .replace("/name", "duke two")
68 | .build();
69 |
70 | JsonObject patchedJson = patch.apply(jsonObject);
71 | System.out.println("Patched JSON: " + patchedJson);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/json-p/src/main/java/de/rieckpil/blog/ReadingJson.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.enterprise.context.ApplicationScoped;
4 | import javax.enterprise.context.Initialized;
5 | import javax.enterprise.event.Observes;
6 | import javax.json.Json;
7 | import javax.json.JsonArray;
8 | import javax.json.JsonObject;
9 | import javax.json.JsonReader;
10 | import java.io.StringReader;
11 |
12 | public class ReadingJson {
13 |
14 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
15 | readFromString();
16 | readFromFile();
17 | }
18 |
19 | private void readFromString() {
20 | JsonReader jsonReader = Json.createReader(
21 | new StringReader("{\"name\":\"duke\",\"age\":42,\"skills\":[\"Java SE\", \"Java EE\"]}"));
22 | JsonObject jsonObject = jsonReader.readObject();
23 | System.out.println(jsonObject);
24 | }
25 |
26 | private void readFromFile() {
27 | JsonReader jsonReader = Json.createReader(this.getClass().getClassLoader()
28 | .getResourceAsStream("books.json"));
29 | JsonArray jsonArray = jsonReader.readArray();
30 | System.out.println(jsonArray);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/json-p/src/main/java/de/rieckpil/blog/StreamingJson.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.enterprise.context.ApplicationScoped;
4 | import javax.enterprise.context.Initialized;
5 | import javax.enterprise.event.Observes;
6 | import javax.json.Json;
7 | import javax.json.stream.JsonGenerator;
8 | import javax.json.stream.JsonParser;
9 | import java.io.StringReader;
10 | import java.io.StringWriter;
11 |
12 | import static javax.json.stream.JsonParser.Event;
13 |
14 | public class StreamingJson {
15 |
16 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
17 | parseJson();
18 | generateJson();
19 | }
20 |
21 | private void parseJson() {
22 | String jsonString = "{\"name\":\"duke\",\"isRetired\":false,\"age\":42,\"skills\":[\"Java SE\", \"Java EE\"]}";
23 | try (JsonParser parser = Json.createParser(new StringReader(jsonString))) {
24 | while (parser.hasNext()) {
25 | final Event event = parser.next();
26 | switch (event) {
27 | case START_ARRAY:
28 | System.out.println("Start of array");
29 | break;
30 | case END_ARRAY:
31 | System.out.println("End of array");
32 | break;
33 | case KEY_NAME:
34 | System.out.println("Key found " + parser.getString());
35 | break;
36 | case VALUE_STRING:
37 | System.out.println("Value found " + parser.getString());
38 | break;
39 | case VALUE_NUMBER:
40 | System.out.println("Number found " + parser.getLong());
41 | break;
42 | case VALUE_TRUE:
43 | System.out.println(true);
44 | break;
45 | case VALUE_FALSE:
46 | System.out.println(false);
47 | break;
48 | }
49 | }
50 | }
51 | }
52 |
53 | private void generateJson() {
54 | StringWriter stringWriter = new StringWriter();
55 |
56 | try (JsonGenerator jsonGenerator = Json.createGenerator(stringWriter)) {
57 | jsonGenerator.writeStartArray()
58 | .writeStartObject()
59 | .write("name", "duke")
60 | .writeEnd()
61 | .writeStartObject()
62 | .write("name", "jakarta")
63 | .writeEnd()
64 | .writeEnd();
65 | jsonGenerator.flush();
66 | }
67 |
68 | System.out.println(stringWriter.toString());
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/json-p/src/main/java/de/rieckpil/blog/WritingJson.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.enterprise.context.ApplicationScoped;
4 | import javax.enterprise.context.Initialized;
5 | import javax.enterprise.event.Observes;
6 | import javax.json.*;
7 | import javax.json.stream.JsonGenerator;
8 | import java.io.*;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 |
12 | public class WritingJson {
13 |
14 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) throws IOException {
15 | JsonObject json = Json.createObjectBuilder()
16 | .add("name", "Duke")
17 | .add("age", 42)
18 | .add("skills",
19 | Json.createArrayBuilder()
20 | .add("Java SE")
21 | .add("Java EE").
22 | build())
23 | .add("address",
24 | Json.createObjectBuilder()
25 | .add("street", "Mainstreet")
26 | .add("city", "Jakarta")
27 | .build())
28 | .build();
29 |
30 | JsonArray jsonArray = Json.createArrayBuilder()
31 | .add("foo")
32 | .add("bar")
33 | .add("duke")
34 | .build();
35 |
36 | System.out.println(json);
37 | prettyPrintJsonToConsole(json);
38 | prettyPrintJsonToFile(json);
39 | }
40 |
41 | private void prettyPrintJsonToConsole(JsonObject json) throws IOException {
42 | Map config = new HashMap<>();
43 | config.put(JsonGenerator.PRETTY_PRINTING, true);
44 |
45 | JsonWriterFactory writerFactory = Json.createWriterFactory(config);
46 | try (Writer stringWriter = new StringWriter();
47 | JsonWriter jsonWriter = writerFactory.createWriter(stringWriter)) {
48 | jsonWriter.write(json);
49 | System.out.println(stringWriter);
50 | }
51 | }
52 |
53 | private void prettyPrintJsonToFile(JsonObject json) throws IOException {
54 | Map config = new HashMap<>();
55 | config.put(JsonGenerator.PRETTY_PRINTING, true);
56 |
57 | JsonWriterFactory writerFactory = Json.createWriterFactory(config);
58 | try (OutputStream outputStream = new FileOutputStream(new File("/tmp/output.json"));
59 | JsonWriter jsonWriter = writerFactory.createWriter(outputStream)) {
60 | jsonWriter.write(json);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/json-p/src/main/resources/books.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "Java 11",
4 | "author": "Duke",
5 | "isPublished": true,
6 | "pages": 110
7 | },
8 | {
9 | "title": "Java 20",
10 | "author": "Duke",
11 | "isPublished": false,
12 | "pages": 200
13 | }
14 | ]
--------------------------------------------------------------------------------
/json-p/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/json-p/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/json-p/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/json-p/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/json-p/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/microprofile-config/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/microprofile-config/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/microprofile-config.war /config/dropins/
4 | COPY --chown=1001:0 target/server.xml /config
5 |
6 | RUN configure.sh
7 |
--------------------------------------------------------------------------------
/microprofile-config/README.md:
--------------------------------------------------------------------------------
1 | # MicroProfile Configuration
2 |
3 | Inject configuration properties from property files, environment variables, system variables and custom configuration sources
4 |
5 | * [GitHub](https://github.com/eclipse/microprofile-config)
6 | * [Specification](https://github.com/eclipse/microprofile-config/releases/download/1.3/microprofile-config-spec-1.3.pdf)
7 | * Current version: **1.3** in **MicroProfile 3.0**
8 | * Detailed blog post about this specification: [#WHATIS?: MicroProfile Config](https://rieckpil.de/whatis-eclipse-microprofile-config/)
9 | * YouTube video about this specification: [Getting started with Eclipse MicroProfile 3.0 - MicroProfile Config 1.3](https://www.youtube.com/watch?v=0h3QceSBBiY)
--------------------------------------------------------------------------------
/microprofile-config/buildAndRun.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call mvn clean package
3 | call docker build -t de.rieckpil.blog/microprofile-config .
4 | call docker rm -f microprofile-config
5 | call docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-config de.rieckpil.blog/microprofile-config
--------------------------------------------------------------------------------
/microprofile-config/buildAndRun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mvn clean package && docker build -t de.rieckpil.blog/microprofile-config .
3 | docker rm -f microprofile-config || true && docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-config de.rieckpil.blog/microprofile-config
--------------------------------------------------------------------------------
/microprofile-config/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../pom.xml
10 |
11 |
12 | 4.0.0
13 | de.rieckpil.blog
14 | microprofile-config
15 | 1.0-SNAPSHOT
16 | war
17 |
18 |
19 | ${project.artifactId}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/microprofile-config/src/main/java/de/rieckpil/blog/BasicConfigurationInjection.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.config.Config;
4 | import org.eclipse.microprofile.config.inject.ConfigProperty;
5 |
6 | import javax.enterprise.context.ApplicationScoped;
7 | import javax.enterprise.context.Initialized;
8 | import javax.enterprise.event.Observes;
9 | import javax.inject.Inject;
10 | import javax.inject.Provider;
11 | import java.util.List;
12 | import java.util.Optional;
13 |
14 | public class BasicConfigurationInjection {
15 |
16 | @Inject
17 | private Config config;
18 |
19 | @Inject
20 | @ConfigProperty(name = "message", defaultValue = "Hello World")
21 | private String message;
22 |
23 | @Inject
24 | @ConfigProperty(name = "my.app.password")
25 | private Optional password;
26 |
27 | @Inject
28 | @ConfigProperty(name = "my.app.timeout")
29 | private Provider timeout;
30 |
31 | @Inject
32 | @ConfigProperty(name = "my.app.users")
33 | private List usersList;
34 |
35 | @Inject
36 | @ConfigProperty(name = "my.app.users")
37 | private String[] usersArray;
38 |
39 | @Inject
40 | @ConfigProperty(name = "my.app.token")
41 | private Token token;
42 |
43 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
44 | System.out.println(config.getValue("message", String.class));
45 | System.out.println(message);
46 | System.out.println(password.orElseGet(() -> "DefaultPassword"));
47 | System.out.println(timeout.get());
48 | usersList.forEach(u -> System.out.println(u));
49 | System.out.println(usersArray);
50 | System.out.println(token);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/microprofile-config/src/main/java/de/rieckpil/blog/CustomConfigConverter.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.config.spi.Converter;
4 |
5 | public class CustomConfigConverter implements Converter {
6 |
7 | @Override
8 | public Token convert(String value) {
9 | String[] chunks = value.split(",");
10 | Token result = new Token(chunks[0], chunks[1]);
11 | return result;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/microprofile-config/src/main/java/de/rieckpil/blog/CustomConfigObject.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.config.Config;
4 | import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
5 |
6 | import javax.enterprise.context.ApplicationScoped;
7 | import javax.enterprise.context.Initialized;
8 | import javax.enterprise.event.Observes;
9 |
10 | public class CustomConfigObject {
11 |
12 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
13 | Config config = ConfigProviderResolver
14 | .instance()
15 | .getBuilder()
16 | .addDefaultSources()
17 | .withSources(new CustomConfigSource())
18 | .addDiscoveredConverters()
19 | .build();
20 |
21 | System.out.println("Customized config: " + config.getValue("message", String.class));
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/microprofile-config/src/main/java/de/rieckpil/blog/CustomConfigSource.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.config.spi.ConfigSource;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | //config sources per default: System properties (ordinal=400)
9 | //config sources per default: Environment variables (ordinal=300)
10 | //config source to search in META-INF/microprofile-config.properties (ordinal=100)
11 | public class CustomConfigSource implements ConfigSource {
12 |
13 | public static final String CUSTOM_PASSWORD = "CUSTOM_PASSWORD";
14 | public static final String MESSAGE = "Hello from custom ConfigSource";
15 |
16 | @Override
17 | public int getOrdinal() {
18 | return 500;
19 | }
20 |
21 | @Override
22 | public Map getProperties() {
23 | Map properties = new HashMap<>();
24 | properties.put("my.app.password", CUSTOM_PASSWORD);
25 | properties.put("message", MESSAGE);
26 | return properties;
27 | }
28 |
29 | @Override
30 | public String getValue(String key) {
31 | if (key.equalsIgnoreCase("my.app.password")) {
32 | return CUSTOM_PASSWORD;
33 | } else if (key.equalsIgnoreCase("message")) {
34 | return MESSAGE;
35 | }
36 | return null;
37 | }
38 |
39 | @Override
40 | public String getName() {
41 | return "randomConfigSource";
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/microprofile-config/src/main/java/de/rieckpil/blog/Token.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | public class Token {
4 |
5 | private String name;
6 | private String payload;
7 |
8 | public Token(String name, String payload) {
9 | this.name = name;
10 | this.payload = payload;
11 | }
12 |
13 | public String getName() {
14 | return name;
15 | }
16 |
17 | public void setName(String name) {
18 | this.name = name;
19 | }
20 |
21 | public String getPayload() {
22 | return payload;
23 | }
24 |
25 | public void setPayload(String payload) {
26 | this.payload = payload;
27 | }
28 |
29 | @Override
30 | public String toString() {
31 | return "Token{" +
32 | "name='" + name + '\'' +
33 | ", payload='" + payload + '\'' +
34 | '}';
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/microprofile-config/src/main/resources/META-INF/microprofile-config.properties:
--------------------------------------------------------------------------------
1 | message=Hello World Java EE 8
2 | my.app.timeout=10
3 | my.app.users=Duke, John, Mike, Fred
4 | my.app.token=TOKEN_1337, SUPER_SECRET_VALUE
5 |
--------------------------------------------------------------------------------
/microprofile-config/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource:
--------------------------------------------------------------------------------
1 | de.rieckpil.blog.CustomConfigSource
--------------------------------------------------------------------------------
/microprofile-config/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.Converter:
--------------------------------------------------------------------------------
1 | de.rieckpil.blog.CustomConfigConverter
--------------------------------------------------------------------------------
/microprofile-config/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/microprofile-config/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/microprofile-config/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/microprofile-config/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/microprofile-config/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/microprofile-fault-tolerance.war /config/dropins/
4 | COPY --chown=1001:0 target/server.xml /config
5 |
6 | RUN configure.sh
7 |
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/README.md:
--------------------------------------------------------------------------------
1 | # MicroProfile Fault Tolerance
2 |
3 | * [GitHub](https://github.com/eclipse/microprofile-fault-tolerance)
4 | * [Spec](https://github.com/eclipse/microprofile-fault-tolerance/releases/download/2.0/microprofile-fault-tolerance-spec-2.0.pdf)
5 | * Current version: **2.0** in MicroProfile **3.0**
6 | * Detailed blog post about this specification: [#WHATIS?: MicroProfile Fault Tolerance](https://rieckpil.de/whatis-eclipse-microprofile-fault-tolerance/)
7 | * YouTube video about this specification: [Getting started with Eclipse MicroProfile 3.0 - MicroProfile Fault Tolerance 2.0](https://www.youtube.com/watch?v=_O4EjWHF0TQ)
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/buildAndRun.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call mvn clean package
3 | call docker build -t de.rieckpil.blog/microprofile-fault-tolerance .
4 | call docker rm -f microprofile-fault-tolerance
5 | call docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-fault-tolerance de.rieckpil.blog/microprofile-fault-tolerance
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/buildAndRun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mvn clean package && docker build -t de.rieckpil.blog/microprofile-fault-tolerance .
3 | docker rm -f microprofile-fault-tolerance || true && docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-fault-tolerance de.rieckpil.blog/microprofile-fault-tolerance
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../pom.xml
10 |
11 |
12 | 4.0.0
13 | de.rieckpil.blog
14 | microprofile-fault-tolerance
15 | 1.0-SNAPSHOT
16 | war
17 |
18 |
19 | ${project.artifactId}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/src/main/java/de/rieckpil/blog/PlaceHolderApiFallback.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.faulttolerance.ExecutionContext;
4 | import org.eclipse.microprofile.faulttolerance.FallbackHandler;
5 |
6 | import javax.json.Json;
7 | import javax.json.JsonObject;
8 |
9 | public class PlaceHolderApiFallback implements FallbackHandler {
10 |
11 | @Override
12 | public JsonObject handle(ExecutionContext context) {
13 | return Json.createObjectBuilder()
14 | .add("comment", "Lorem ipsum")
15 | .add("postId", Long.valueOf(context.getParameters()[0].toString()))
16 | .build();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/src/main/java/de/rieckpil/blog/RandomDataPrinter.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.enterprise.context.ApplicationScoped;
4 | import javax.enterprise.context.Initialized;
5 | import javax.enterprise.event.Observes;
6 | import javax.inject.Inject;
7 |
8 | @ApplicationScoped
9 | public class RandomDataPrinter {
10 |
11 | @Inject
12 | private RandomDataProvider randomDataProvider;
13 |
14 | public void initialize(@Observes @Initialized(ApplicationScoped.class) Object init) throws InterruptedException {
15 |
16 | System.out.println(randomDataProvider.getPostById(1L));
17 | System.out.println(randomDataProvider.accessFlakyService());
18 | System.out.println(randomDataProvider.getDataFromLongRunningTask());
19 |
20 | // for (int i = 0; i < 20; i++) {
21 | // System.out.println(randomDataProvider.getRandomData());
22 | // Thread.sleep(500);
23 | // }
24 | //
25 | // for (int i = 0; i < 10; i++) {
26 | // final String threadName = "Thread" + i;
27 | // new Thread(() -> randomDataProvider.getConcurrentServiceData(threadName)).start();
28 | // System.out.println(threadName + " started");
29 | // }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/src/main/java/de/rieckpil/blog/RandomDataProvider.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.faulttolerance.*;
4 |
5 | import javax.annotation.PostConstruct;
6 | import javax.enterprise.context.ApplicationScoped;
7 | import javax.json.Json;
8 | import javax.json.JsonObject;
9 | import javax.ws.rs.client.Client;
10 | import javax.ws.rs.client.ClientBuilder;
11 | import javax.ws.rs.client.WebTarget;
12 | import javax.ws.rs.core.MediaType;
13 | import java.time.LocalTime;
14 | import java.time.temporal.ChronoUnit;
15 | import java.util.concurrent.CompletableFuture;
16 | import java.util.concurrent.Future;
17 | import java.util.concurrent.ThreadLocalRandom;
18 | import java.util.concurrent.TimeUnit;
19 |
20 | @ApplicationScoped
21 | public class RandomDataProvider {
22 |
23 | private WebTarget webTarget;
24 |
25 | @PostConstruct
26 | public void setUp() {
27 | Client client = ClientBuilder.newBuilder()
28 | .connectTimeout(5, TimeUnit.SECONDS)
29 | .readTimeout(5, TimeUnit.SECONDS)
30 | .build();
31 |
32 | this.webTarget = client
33 | .target("https://jsonplaceholder.typicode.com/posts");
34 | }
35 |
36 | @Fallback(PlaceHolderApiFallback.class)
37 | // @Fallback(fallbackMethod = "getDefaultPost")
38 | public JsonObject getPostById(Long id) {
39 | return this.webTarget
40 | .path(String.valueOf(id))
41 | .request()
42 | .accept(MediaType.APPLICATION_JSON)
43 | .get(JsonObject.class);
44 | }
45 |
46 | public JsonObject getDefaultPost(Long id) {
47 | return Json.createObjectBuilder()
48 | .add("comment", "Lorem ipsum")
49 | .add("postId", id)
50 | .build();
51 | }
52 |
53 | @CircuitBreaker(successThreshold = 10, requestVolumeThreshold = 5, failureRatio = 0.5, delay = 500)
54 | @Fallback(fallbackMethod = "getFallbackData")
55 | public String getRandomData() {
56 | if (ThreadLocalRandom.current().nextLong(1000) < 300) {
57 | return "random duke";
58 | } else {
59 | throw new RuntimeException("Random data not available");
60 | }
61 | }
62 |
63 | @Timeout(value = 4, unit = ChronoUnit.SECONDS)
64 | @Fallback(fallbackMethod = "getFallbackData")
65 | public String getDataFromLongRunningTask() throws InterruptedException {
66 | Thread.sleep(4500);
67 | return "duke";
68 | }
69 |
70 | @Retry(maxDuration = 5000, maxRetries = 3, delay = 500, jitter = 200)
71 | @Fallback(fallbackMethod = "getFallbackData")
72 | public String accessFlakyService() {
73 |
74 | System.out.println("Trying to access flaky service at " + LocalTime.now());
75 |
76 | if (ThreadLocalRandom.current().nextLong(1000) < 50) {
77 | return "flaky duke";
78 | } else {
79 | throw new RuntimeException("Flaky service not accessible");
80 | }
81 | }
82 |
83 | @Bulkhead(5)
84 | @Asynchronous
85 | public Future getConcurrentServiceData(String name) {
86 | try {
87 | System.out.println(name + " is accessing the concurrent service");
88 | Thread.sleep(2000);
89 | } catch (InterruptedException e) {
90 | e.printStackTrace();
91 | } finally {
92 | return CompletableFuture.completedFuture("concurrent duke");
93 | }
94 | }
95 |
96 | public String getFallbackData() {
97 | return "fallback duke";
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/src/main/resources/META-INF/microprofile-config.properties:
--------------------------------------------------------------------------------
1 | de.rieckpil.blog.RandomDataProvider/accessFlakyService/Retry/maxRetries=10
2 | de.rieckpil.blog.RandomDataProvider/accessFlakyService/Retry/delay=300
3 | de.rieckpil.blog.RandomDataProvider/accessFlakyService/Retry/maxDuration=5000
4 |
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/microprofile-fault-tolerance/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/microprofile-health/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/microprofile-health/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/microprofile-health.war /config/dropins/
4 | COPY --chown=1001:0 target/server.xml /config
5 |
6 | RUN configure.sh
7 |
--------------------------------------------------------------------------------
/microprofile-health/README.md:
--------------------------------------------------------------------------------
1 | # MicroProfile Health
2 |
3 | * [GitHub](https://github.com/eclipse/microprofile-health)
4 | * [Spec](https://github.com/eclipse/microprofile-health/releases/download/2.0.1/microprofile-health-spec.pdf)
5 | * Current version: **2.0.1** in **MicroProfile 3.0**
6 | * Detailed blog post about this specification: [#WHATIS?: MicroProfile Health](https://rieckpil.de/whatis-eclipse-microprofile-health/)
7 | * YouTube video about this specification: [Getting started with Eclipse MicroProfile 3.0 - MicroProfile Health 2.0](https://www.youtube.com/watch?v=nq_gdPUTx5c)
--------------------------------------------------------------------------------
/microprofile-health/buildAndRun.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call mvn clean package
3 | call docker build -t de.rieckpil.blog/microprofile-health .
4 | call docker rm -f microprofile-health
5 | call docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-health de.rieckpil.blog/microprofile-health
--------------------------------------------------------------------------------
/microprofile-health/buildAndRun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mvn clean package && docker build -t de.rieckpil.blog/microprofile-health .
3 | docker rm -f microprofile-health || true && docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-health de.rieckpil.blog/microprofile-health
--------------------------------------------------------------------------------
/microprofile-health/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../pom.xml
10 |
11 |
12 | 4.0.0
13 | de.rieckpil.blog
14 | microprofile-health
15 | 1.0-SNAPSHOT
16 | war
17 |
18 |
19 | ${project.artifactId}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/microprofile-health/src/main/java/de/rieckpil/blog/DiskSizeCheck.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.health.HealthCheck;
4 | import org.eclipse.microprofile.health.HealthCheckResponse;
5 | import org.eclipse.microprofile.health.HealthCheckResponseBuilder;
6 | import org.eclipse.microprofile.health.Liveness;
7 |
8 | import java.io.File;
9 |
10 | @Liveness
11 | public class DiskSizeCheck implements HealthCheck {
12 |
13 | @Override
14 | public HealthCheckResponse call() {
15 |
16 | File file = new File("/");
17 | long freeSpace = file.getFreeSpace() / 1024 / 1024;
18 |
19 | HealthCheckResponseBuilder responseBuilder = HealthCheckResponse.builder()
20 | .name("diskSizeCheck")
21 | .withData("remainingSpace", freeSpace);
22 |
23 | return responseBuilder
24 | .state(freeSpace > 100)
25 | .build();
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/microprofile-health/src/main/java/de/rieckpil/blog/FlakyLivenessCheck.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.health.HealthCheck;
4 | import org.eclipse.microprofile.health.HealthCheckResponse;
5 | import org.eclipse.microprofile.health.Liveness;
6 |
7 | import java.util.concurrent.ThreadLocalRandom;
8 |
9 | @Liveness
10 | public class FlakyLivenessCheck implements HealthCheck {
11 |
12 | @Override
13 | public HealthCheckResponse call() {
14 |
15 | return HealthCheckResponse
16 | .builder()
17 | .name("liveness")
18 | .state(ThreadLocalRandom.current().nextBoolean())
19 | .build();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/microprofile-health/src/main/java/de/rieckpil/blog/MultipleHealthCheck.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.health.HealthCheck;
4 | import org.eclipse.microprofile.health.HealthCheckResponse;
5 | import org.eclipse.microprofile.health.Liveness;
6 | import org.eclipse.microprofile.health.Readiness;
7 |
8 | @Readiness
9 | @Liveness
10 | public class MultipleHealthCheck implements HealthCheck {
11 |
12 | @Override
13 | public HealthCheckResponse call() {
14 | return HealthCheckResponse
15 | .builder()
16 | .name("generalCheck")
17 | .withData("foo", "bar")
18 | .withData("uptime", 42)
19 | .withData("isReady", true)
20 | .up()
21 | .build();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/microprofile-health/src/main/java/de/rieckpil/blog/ReadinessCheck.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.health.HealthCheck;
4 | import org.eclipse.microprofile.health.HealthCheckResponse;
5 | import org.eclipse.microprofile.health.Readiness;
6 |
7 | @Readiness
8 | public class ReadinessCheck implements HealthCheck {
9 |
10 | @Override
11 | public HealthCheckResponse call() {
12 | return HealthCheckResponse.builder()
13 | .name("readiness")
14 | .up()
15 | .build();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/microprofile-health/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/microprofile-health/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/microprofile-health/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/microprofile-health/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/microprofile-health/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
24 | jwt-token.json
25 | jwtenizr-config.json
26 | microprofile-config.properties
27 | token.jwt
28 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/microprofile-jwt-auth.war /config/dropins/
4 | COPY --chown=1001:0 target/server.xml /config
5 |
6 | RUN configure.sh
7 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/README.md:
--------------------------------------------------------------------------------
1 | # MicroProfile JWT Auth
2 |
3 | * [GitHub](https://github.com/eclipse/microprofile-jwt-auth)
4 | * [Spec](https://github.com/eclipse/microprofile-jwt-auth/releases/download/1.1/microprofile-jwt-auth-spec-1.1.pdf)
5 | * Current version: **1.1** in MicroProfile **3.0**
6 | * Detailed blog post about this specification: [#WHATIS?: MicroProfile JWT Auth](https://rieckpil.de/whatis-eclipse-microprofile-jwt-auth/)
7 | * YouTube video about this specification: [Getting started with Eclipse MicroProfile 3.0 - MicroProfile JWT Auth 1.1](https://youtu.be/8O3D2tNx1uM)
8 |
9 | ## Steps to run this project
10 |
11 | 1. Run `java -jar jwtenizr.jar`
12 | 2. Adjust the created `jwt-token.json` like the following:
13 | ```json
14 | {
15 | "iss": "rieckpil",
16 | "jti": "42",
17 | "sub": "duke",
18 | "upn": "duke",
19 | "groups": [
20 | "chief",
21 | "hacker",
22 | "admin"
23 | ],
24 | "administrator_id": 42,
25 | "administrator_level": "HIGH"
26 | }
27 | ```
28 | 3. Re-run `java -jar jwtenizr.jar`
29 | 4. Take the public key from the generated `microprofile-config.properties` file and paste it to `src/main/resources/META-INF/publicKey.pem` in the inner section, e.g.:
30 | ```shell script
31 | -----BEGIN RSA PUBLIC KEY-----
32 | MydoO3l7rOiRw5PMtlxHYRqK51eql2pVvp+lASalwIDAQAB
33 | -----END RSA PUBLIC KEY-----
34 | ```
35 | 5. Start the application with `./buildAndRun.sh` or `buildAndRun.bat`
36 | 6. Use the cURL console output of the last run of `jwtenizr` and adjust the port and URL path, e.g.:
37 | ```shell script
38 | curl -i -H'Authorization: Bearer eyXYZ' http://localhost:9080/resources/books
39 | ```
40 | or use Postman and take the JWT from the generated `token.jwt` file
41 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/buildAndRun.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call mvn clean package
3 | call docker build -t de.rieckpil.blog/microprofile-jwt-auth .
4 | call docker rm -f microprofile-jwt-auth
5 | call docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-jwt-auth de.rieckpil.blog/microprofile-jwt-auth
--------------------------------------------------------------------------------
/microprofile-jwt-auth/buildAndRun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mvn clean package && docker build -t de.rieckpil.blog/microprofile-jwt-auth .
3 | docker rm -f microprofile-jwt-auth || true && docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-jwt-auth de.rieckpil.blog/microprofile-jwt-auth
--------------------------------------------------------------------------------
/microprofile-jwt-auth/jwtenizr.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rieckpil/getting-started-with-microprofile/3c6984b2c26ec70919e0fd8779136161563960cb/microprofile-jwt-auth/jwtenizr.jar
--------------------------------------------------------------------------------
/microprofile-jwt-auth/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../pom.xml
10 |
11 |
12 | 4.0.0
13 | de.rieckpil.blog
14 | microprofile-jwt-auth
15 | 1.0-SNAPSHOT
16 | war
17 |
18 |
19 | ${project.artifactId}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/src/main/java/de/rieckpil/blog/BookResource.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.jwt.Claim;
4 | import org.eclipse.microprofile.jwt.JsonWebToken;
5 |
6 | import javax.annotation.security.RolesAllowed;
7 | import javax.enterprise.context.RequestScoped;
8 | import javax.inject.Inject;
9 | import javax.json.Json;
10 | import javax.json.JsonNumber;
11 | import javax.json.JsonObject;
12 | import javax.ws.rs.GET;
13 | import javax.ws.rs.Path;
14 | import javax.ws.rs.Produces;
15 | import javax.ws.rs.core.MediaType;
16 | import javax.ws.rs.core.Response;
17 | import java.security.Principal;
18 |
19 | @Path("books")
20 | @RequestScoped
21 | @Produces(MediaType.APPLICATION_JSON)
22 | public class BookResource {
23 |
24 | @Inject
25 | private Principal principal;
26 |
27 | @Inject
28 | private JsonWebToken jsonWebToken;
29 |
30 | @Inject
31 | @Claim("administrator_id")
32 | private JsonNumber administrator_id;
33 |
34 | @GET
35 | @RolesAllowed("admin")
36 | public Response getBook() {
37 |
38 | System.out.println("Secret book for " + principal.getName() + " with roles " + jsonWebToken.getGroups());
39 | System.out.println("Administrator level: " + jsonWebToken.getClaim("administrator_level").toString());
40 | System.out.println("Administrator id: " + administrator_id);
41 |
42 | JsonObject secretBook = Json.createObjectBuilder()
43 | .add("title", "secret")
44 | .add("author", "duke")
45 | .build();
46 |
47 | return Response.ok(secretBook).build();
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/src/main/java/de/rieckpil/blog/JAXRSConfiguration.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.auth.LoginConfig;
4 |
5 | import javax.ws.rs.ApplicationPath;
6 | import javax.ws.rs.core.Application;
7 |
8 | @ApplicationPath("resources")
9 | @LoginConfig(authMethod = "MP-JWT")
10 | public class JAXRSConfiguration extends Application {
11 | }
12 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/src/main/java/de/rieckpil/blog/OrderResources.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.annotation.security.PermitAll;
4 | import javax.json.Json;
5 | import javax.json.JsonObject;
6 | import javax.ws.rs.GET;
7 | import javax.ws.rs.Path;
8 | import javax.ws.rs.Produces;
9 | import javax.ws.rs.core.MediaType;
10 | import javax.ws.rs.core.Response;
11 |
12 | @Path("orders")
13 | @Produces(MediaType.APPLICATION_JSON)
14 | public class OrderResources {
15 |
16 | @GET
17 | @PermitAll
18 | public Response getOrder() {
19 | JsonObject order = Json.createObjectBuilder()
20 | .add("amount", 42)
21 | .add("product", "bike")
22 | .build();
23 |
24 | return Response.ok(order).build();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/src/main/resources/META-INF/microprofile-config.properties:
--------------------------------------------------------------------------------
1 | mp.jwt.verify.publickey.location=/META-INF/publicKey.pem
2 | mp.jwt.verify.issuer=rieckpil
3 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/src/main/resources/META-INF/publicKey.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PUBLIC KEY-----
2 | ENTER_PUBLIC_KEY_HERE
3 | -----END RSA PUBLIC KEY-----
--------------------------------------------------------------------------------
/microprofile-jwt-auth/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/microprofile-jwt-auth/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/microprofile-metrics/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/microprofile-metrics/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/microprofile-metrics.war /config/dropins/
4 | COPY --chown=1001:0 target/server.xml /config/
5 |
6 | RUN configure.sh
7 |
--------------------------------------------------------------------------------
/microprofile-metrics/README.md:
--------------------------------------------------------------------------------
1 | # MicroProfile Metrics
2 |
3 | * [GitHub](https://github.com/eclipse/microprofile-metrics)
4 | * [Spec](https://github.com/eclipse/microprofile-metrics/releases/download/2.0/microprofile-metrics-spec-2.0.pdf)
5 | * Current version: **2.0** in MicroProfile **3.0**
6 | * Detailed blog post about this specification: [#WHATIS?: MicroProfile Metrics](https://rieckpil.de/whatis-eclipse-microprofile-metrics/)
7 | * YouTube video about this specification: [Getting started with Eclipse MicroProfile 3.0 - MicroProfile Metrics 2.0](https://www.youtube.com/watch?v=jI6DoNYVd-U)
--------------------------------------------------------------------------------
/microprofile-metrics/buildAndRun.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call mvn clean package
3 | call docker build -t de.rieckpil.blog/microprofile-metrics .
4 | call docker rm -f microprofile-metrics
5 | call docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-metrics de.rieckpil.blog/microprofile-metrics
6 | call docker logs -f microprofile-metrics
--------------------------------------------------------------------------------
/microprofile-metrics/buildAndRun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mvn clean package && docker build -t de.rieckpil.blog/microprofile-metrics .
3 | docker rm -f microprofile-metrics || true && docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-metrics de.rieckpil.blog/microprofile-metrics
--------------------------------------------------------------------------------
/microprofile-metrics/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../pom.xml
10 |
11 |
12 | 4.0.0
13 | microprofile-metrics
14 | 1.0-SNAPSHOT
15 | war
16 |
17 |
18 | ${project.artifactId}
19 |
20 |
21 |
--------------------------------------------------------------------------------
/microprofile-metrics/src/main/java/de/rieckpil/blog/BookCommentClient.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.metrics.MetricRegistry;
4 | import org.eclipse.microprofile.metrics.annotation.Counted;
5 | import org.eclipse.microprofile.metrics.annotation.RegistryType;
6 | import org.eclipse.microprofile.metrics.annotation.Timed;
7 |
8 | import javax.annotation.PostConstruct;
9 | import javax.inject.Inject;
10 | import javax.json.JsonObject;
11 | import javax.ws.rs.client.Client;
12 | import javax.ws.rs.client.ClientBuilder;
13 | import javax.ws.rs.client.WebTarget;
14 | import javax.ws.rs.core.Response;
15 | import java.util.concurrent.ThreadLocalRandom;
16 | import java.util.concurrent.TimeUnit;
17 |
18 | public class BookCommentClient {
19 |
20 | @Inject
21 | @RegistryType(type = MetricRegistry.Type.APPLICATION)
22 | private MetricRegistry metricRegistry;
23 |
24 | private WebTarget bookCommentsWebTarget;
25 |
26 | @Counted(name = "bookCommentClientInvocations", description = "Counting the invocations of the constructor")
27 | public BookCommentClient() {
28 | }
29 |
30 | @PostConstruct
31 | public void setUp() {
32 | Client client = ClientBuilder
33 | .newBuilder()
34 | .connectTimeout(5, TimeUnit.SECONDS)
35 | .readTimeout(5, TimeUnit.SECONDS)
36 | .build();
37 |
38 | this.bookCommentsWebTarget = client.target("https://jsonplaceholder.typicode.com/comments");
39 | }
40 |
41 | @Timed(name = "getBookCommentByBookIdDuration")
42 | //@SimplyTimed(name = "getBookCommentByBookIdDuration")
43 | public String getBookCommentByBookId(String bookId) {
44 | this.sleepRandom();
45 |
46 | Response response = this.bookCommentsWebTarget.path(bookId).request().get();
47 |
48 | this.metricRegistry.counter("bookCommentApiResponseCode" + response.getStatus()).inc();
49 |
50 | return response.readEntity(JsonObject.class).getString("body");
51 | }
52 |
53 | private void sleepRandom() {
54 | try {
55 | Thread.sleep(ThreadLocalRandom.current().nextLong(1000));
56 | } catch (InterruptedException e) {
57 | e.printStackTrace();
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/microprofile-metrics/src/main/java/de/rieckpil/blog/BookRequestProcessor.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.metrics.annotation.Gauge;
4 |
5 | import javax.enterprise.context.ApplicationScoped;
6 | import java.util.concurrent.ThreadLocalRandom;
7 |
8 | @ApplicationScoped
9 | public class BookRequestProcessor {
10 |
11 | @Gauge(unit = "amount")
12 | public Long remainingBookRequestsToProcess() {
13 | // monitor e.g. current size of a JMS queue
14 | return ThreadLocalRandom.current().nextLong(0, 1_000_000);
15 | }
16 |
17 | public String getLatestBookRequestId() {
18 | return String.valueOf(ThreadLocalRandom.current().nextLong(10));
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/microprofile-metrics/src/main/java/de/rieckpil/blog/BookResource.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.metrics.annotation.Metered;
4 |
5 | import javax.enterprise.context.RequestScoped;
6 | import javax.inject.Inject;
7 | import javax.ws.rs.GET;
8 | import javax.ws.rs.Path;
9 | import javax.ws.rs.Produces;
10 | import javax.ws.rs.core.MediaType;
11 | import javax.ws.rs.core.Response;
12 |
13 | @RequestScoped
14 | @Path("books")
15 | public class BookResource {
16 |
17 | @Inject
18 | private BookCommentClient bookCommentClient;
19 |
20 | @Inject
21 | private BookRequestProcessor bookRequestProcessor;
22 |
23 | @GET
24 | @Metered(name = "getBookCommentForLatestBookRequest", tags = {"spec=JAX-RS", "level=REST"})
25 | @Produces(MediaType.TEXT_PLAIN)
26 | public Response getBookCommentForLatestBookRequest() {
27 | String latestBookRequestId = bookRequestProcessor.getLatestBookRequestId();
28 | return Response.ok(this.bookCommentClient.getBookCommentByBookId(latestBookRequestId)).build();
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/microprofile-metrics/src/main/java/de/rieckpil/blog/JAXRSConfiguration.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.ApplicationPath;
4 | import javax.ws.rs.core.Application;
5 |
6 | @ApplicationPath("resources")
7 | public class JAXRSConfiguration extends Application {
8 | }
9 |
--------------------------------------------------------------------------------
/microprofile-metrics/src/main/resources/META-INF/microprofile-config.properties:
--------------------------------------------------------------------------------
1 | message=Hello World Java EE 8
--------------------------------------------------------------------------------
/microprofile-metrics/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/microprofile-metrics/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/microprofile-metrics/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/microprofile-metrics/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/microprofile-metrics/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/microprofile-open-api/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/microprofile-open-api/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/microprofile-open-api.war /config/dropins/
4 | COPY --chown=1001:0 target/server.xml /config/
5 |
6 | RUN configure.sh
7 |
--------------------------------------------------------------------------------
/microprofile-open-api/README.md:
--------------------------------------------------------------------------------
1 | # MicroProfile OpenAPI
2 |
3 | * [GitHub](https://github.com/eclipse/microprofile-open-api)
4 | * [Spec](https://download.eclipse.org/microprofile/microprofile-open-api-1.1/microprofile-openapi-spec.pdf)
5 | * Current version: **1.1** in MicroProfile **3.0**
6 | * Detailed blog post about this specification: [#WHATIS?: MicroProfile OpenAPI](https://rieckpil.de/whatis-eclipse-microprofile-openapi/)
7 | * YouTube video about this specification: [Getting started with Eclipse MicroProfile 3.0 - MicroProfile OpenAPI 1.1](https://www.youtube.com/watch?v=Rn7T26UW_H8)
8 |
--------------------------------------------------------------------------------
/microprofile-open-api/buildAndRun.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call mvn clean package
3 | call docker build -t de.rieckpil.blog/microprofile-open-api .
4 | call docker rm -f microprofile-open-api
5 | call docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-open-api de.rieckpil.blog/microprofile-open-api
6 | call docker logs -f microprofile-open-api
--------------------------------------------------------------------------------
/microprofile-open-api/buildAndRun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mvn clean package && docker build -t de.rieckpil.blog/microprofile-open-api .
3 | docker rm -f microprofile-open-api || true && docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-open-api de.rieckpil.blog/microprofile-open-api && docker logs -f microprofile-open-api
--------------------------------------------------------------------------------
/microprofile-open-api/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../pom.xml
10 |
11 |
12 | 4.0.0
13 | de.rieckpil.blog
14 | microprofile-open-api
15 | 1.0-SNAPSHOT
16 | war
17 |
18 |
19 | ${project.artifactId}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/microprofile-open-api/src/main/java/de/rieckpil/blog/Book.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.openapi.annotations.media.Schema;
4 |
5 | @Schema(name = "Book", description = "POJO that represents a book.")
6 | public class Book {
7 |
8 | @Schema(required = true, example = "MicroProfile")
9 | private String title;
10 |
11 | @Schema(required = true, example = "Duke")
12 | private String author;
13 |
14 | @Schema(required = true, readOnly = true, example = "1")
15 | private Long id;
16 |
17 | public Book() {
18 | }
19 |
20 | public Book(String title, String author, Long id) {
21 | this.title = title;
22 | this.author = author;
23 | this.id = id;
24 | }
25 |
26 | public String getTitle() {
27 | return title;
28 | }
29 |
30 | public void setTitle(String title) {
31 | this.title = title;
32 | }
33 |
34 | public String getAuthor() {
35 | return author;
36 | }
37 |
38 | public void setAuthor(String author) {
39 | this.author = author;
40 | }
41 |
42 | public Long getId() {
43 | return id;
44 | }
45 |
46 | public void setId(Long id) {
47 | this.id = id;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/microprofile-open-api/src/main/java/de/rieckpil/blog/BookResource.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.openapi.annotations.Operation;
4 | import org.eclipse.microprofile.openapi.annotations.media.Content;
5 | import org.eclipse.microprofile.openapi.annotations.media.Schema;
6 | import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
7 | import org.eclipse.microprofile.openapi.annotations.tags.Tag;
8 |
9 | import javax.json.JsonObject;
10 | import javax.ws.rs.*;
11 | import javax.ws.rs.core.Context;
12 | import javax.ws.rs.core.MediaType;
13 | import javax.ws.rs.core.Response;
14 | import javax.ws.rs.core.UriInfo;
15 |
16 | @Path("books")
17 | public class BookResource {
18 |
19 | @GET
20 | @Operation(summary = "Get all books", description = "Returns all available books of the book store XYZ")
21 | @APIResponse(responseCode = "404", description = "No books found")
22 | @APIResponse(responseCode = "418", description = "I'm a teapot")
23 | @APIResponse(responseCode = "500", description = "Server unavailable")
24 | @Tag(name = "BETA", description = "This API is currently in beta state")
25 | @Produces(MediaType.APPLICATION_JSON)
26 | public Response getAllBooks() {
27 | System.out.println("Get all books...");
28 | return Response.ok(new Book("MicroProfile", "Duke", 1L)).build();
29 | }
30 |
31 | @GET
32 | @APIResponse(description = "Book",
33 | content = @Content(mediaType = "application/json",
34 | schema = @Schema(implementation = Book.class)))
35 | @Path("/{id}")
36 | @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
37 | public Response getBookById(@PathParam("id") Long id) {
38 | System.out.println("Get book by id...");
39 | return Response.ok(new Book("MicroProfile", "Duke", 1L)).build();
40 | }
41 |
42 | @POST
43 | public Response createNewBook(JsonObject jsonObject, @Context UriInfo uriInfo) {
44 | System.out.println("Creating new book...");
45 | return Response.created(uriInfo.getAbsolutePathBuilder().build()).build();
46 | }
47 |
48 | @DELETE
49 | @Path("/{id}")
50 | public Response deleteBookById(@PathParam("id") Long id) {
51 | System.out.println("Deleting book...");
52 | return Response.noContent().build();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/microprofile-open-api/src/main/java/de/rieckpil/blog/JAXRSConfiguration.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.ApplicationPath;
4 | import javax.ws.rs.core.Application;
5 |
6 | @ApplicationPath("resources")
7 | public class JAXRSConfiguration extends Application {
8 | }
9 |
--------------------------------------------------------------------------------
/microprofile-open-api/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/microprofile-open-api/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/microprofile-open-api/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/microprofile-open-api/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/microprofile-open-api/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/README.md:
--------------------------------------------------------------------------------
1 | # MicroProfile OpenTracing
2 |
3 | * [GitHub](https://github.com/eclipse/microprofile-opentracing)
4 | * [Spec](https://github.com/eclipse/microprofile-opentracing/releases/download/1.3/microprofile-opentracing-spec-1.3.pdf)
5 | * Current version: **1.3** in MicroProfile **3.0**
6 | * Detailed blog post about this specification: [#WHATIS?: MicroProfile OpenTracing](https://rieckpil.de/whatis-eclipse-microprofile-opentracing/)
7 | * YouTube video about this specification: [Getting started with Eclipse MicroProfile 3.0 - MicroProfile OpenTracing 1.3](https://www.youtube.com/watch?v=b43XgElBxEo)
8 |
9 | ## Steps to run this example
10 |
11 | 1. Ensure your Docker daemon is running (required Docker engine: 18.02.0+)
12 | 2. Execute either `buildAndRun.bat` (Windows) or `./buildAndRun.sh` (Linux & Mac) to build both projects and start the everything with `docker-compose`
13 | 3. Wait until everything is up and running
14 | 4. Visit http://localhost:9080/resources/books in your browser (response takes up to 1 - 3 seconds)
15 | 5. Visit http://localhost:9411/zipkin/ in your browser and search for available traces
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/microprofile-open-tracing-client.war /config/dropins/
4 | COPY --chown=1001:0 server.xml /config/
5 | COPY --chown=1001:0 extension /opt/ol/wlp/usr/extension
6 |
7 | RUN configure.sh
8 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/extension/lib/com.ibm.ws.io.opentracing.zipkintracer-0.31.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rieckpil/getting-started-with-microprofile/3c6984b2c26ec70919e0fd8779136161563960cb/microprofile-open-tracing/book-store-client/extension/lib/com.ibm.ws.io.opentracing.zipkintracer-0.31.jar
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/extension/lib/features/opentracingZipkin-0.31.mf:
--------------------------------------------------------------------------------
1 | IBM-Feature-Version: 2
2 | IBM-ShortName: opentracingZipkin-0.31
3 | Subsystem-Content: com.ibm.websphere.appserver.opentracing-1.1; ibm.tolerates:="1.2,1.3"; type="osgi.subsystem.feature",
4 | com.ibm.ws.opentracing.zipkin; version="[1.3.0,1.3.200)",
5 | com.ibm.websphere.appserver.jaxrs-2.0; type="osgi.subsystem.feature"; ibm.tolerates:=2.1,
6 | com.ibm.websphere.appserver.cdi-1.2; type="osgi.subsystem.feature"; ibm.tolerates:=2.0
7 | Subsystem-Description: %description
8 | Subsystem-License: https://www.eclipse.org/legal/epl-v10.html
9 | Subsystem-Localization: OSGI-INF/l10n/com.ibm.websphere.appserver.opentracingZipkin-0.31
10 | Subsystem-ManifestVersion: 1
11 | Subsystem-Name: Opentracing Zipkin Tracer implementation
12 | Subsystem-SymbolicName: com.ibm.websphere.appserver.opentracingZipkin-0.31; visibility:=public; singleton:=true
13 | Subsystem-Type: osgi.subsystem.feature
14 | Subsystem-Version: 1.0.0
15 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../../pom.xml
10 |
11 |
12 | 4.0.0
13 | de.rieckpil.blog
14 | microprofile-open-tracing-client
15 | 1.0-SNAPSHOT
16 | war
17 |
18 |
19 | ${project.artifactId}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/server.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | microProfile-3.3
6 | usr:opentracingZipkin-0.31
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/src/main/java/de/rieckpil/blog/BookProvider.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.annotation.PostConstruct;
4 | import javax.annotation.PreDestroy;
5 | import javax.enterprise.context.RequestScoped;
6 | import javax.inject.Inject;
7 | import javax.json.Json;
8 | import javax.json.JsonArray;
9 | import javax.json.JsonObject;
10 | import javax.json.JsonValue;
11 | import javax.json.stream.JsonCollectors;
12 | import javax.ws.rs.client.Client;
13 | import javax.ws.rs.client.ClientBuilder;
14 | import javax.ws.rs.client.WebTarget;
15 | import javax.ws.rs.core.MediaType;
16 | import java.util.ArrayList;
17 | import java.util.List;
18 | import java.util.concurrent.TimeUnit;
19 |
20 | @RequestScoped
21 | public class BookProvider {
22 |
23 | @Inject
24 | private PriceCalculator priceCalculator;
25 |
26 | private WebTarget bookStoreTarget;
27 | private Client client;
28 |
29 | @PostConstruct
30 | public void setup() {
31 | this.client = ClientBuilder
32 | .newBuilder()
33 | .connectTimeout(2, TimeUnit.SECONDS)
34 | .readTimeout(2, TimeUnit.SECONDS)
35 | .build();
36 |
37 | this.bookStoreTarget = client.target("http://book-store:9080/resources/books");
38 | }
39 |
40 | public JsonArray getBooksFromBookStore() {
41 |
42 | JsonArray books = this.bookStoreTarget
43 | .request()
44 | .accept(MediaType.APPLICATION_JSON)
45 | .get()
46 | .readEntity(JsonArray.class);
47 |
48 | List result = new ArrayList();
49 |
50 | for (JsonObject book : books.getValuesAs(JsonValue::asJsonObject)) {
51 | result.add(Json.createObjectBuilder()
52 | .add("title", book.getString("title"))
53 | .add("price", priceCalculator.getPriceForBook(book.getInt("id")))
54 | .build());
55 | }
56 |
57 | return result
58 | .stream()
59 | .collect(JsonCollectors.toJsonArray());
60 | }
61 |
62 | @PreDestroy
63 | public void tearDown() {
64 | this.client.close();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/src/main/java/de/rieckpil/blog/BookResource.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.inject.Inject;
4 | import javax.ws.rs.GET;
5 | import javax.ws.rs.Path;
6 | import javax.ws.rs.Produces;
7 | import javax.ws.rs.core.MediaType;
8 | import javax.ws.rs.core.Response;
9 |
10 | @Path("books")
11 | public class BookResource {
12 |
13 | @Inject
14 | private BookProvider bookProvider;
15 |
16 | @GET
17 | @Produces(MediaType.APPLICATION_JSON)
18 | public Response getBooks() {
19 | return Response.ok(bookProvider.getBooksFromBookStore()).build();
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/src/main/java/de/rieckpil/blog/JAXRSConfiguration.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.ApplicationPath;
4 | import javax.ws.rs.core.Application;
5 |
6 | @ApplicationPath("resources")
7 | public class JAXRSConfiguration extends Application {
8 | }
9 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/src/main/java/de/rieckpil/blog/PriceCalculator.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.annotation.PostConstruct;
4 | import javax.enterprise.context.RequestScoped;
5 | import javax.ws.rs.client.Client;
6 | import javax.ws.rs.client.ClientBuilder;
7 | import javax.ws.rs.client.WebTarget;
8 | import java.util.concurrent.TimeUnit;
9 |
10 | @RequestScoped
11 | public class PriceCalculator {
12 |
13 | private WebTarget bookStorePriceTarget;
14 | private Double discount = 1.5;
15 |
16 | @PostConstruct
17 | public void setUp() {
18 | Client client = ClientBuilder
19 | .newBuilder()
20 | .connectTimeout(2, TimeUnit.SECONDS)
21 | .readTimeout(2, TimeUnit.SECONDS)
22 | .build();
23 |
24 | this.bookStorePriceTarget = client.target("http://book-store:9080/resources/prices");
25 | }
26 |
27 | public Double getPriceForBook(int id) {
28 | Double bookPrice = this.bookStorePriceTarget.path(String.valueOf(id)).request().get().readEntity(Double.class);
29 | return Math.round((bookPrice - discount) * 100.0) / 100.0;
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store-client/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/microprofile-open-tracing-server.war /config/dropins/
4 | COPY --chown=1001:0 server.xml /config/
5 | COPY --chown=1001:0 extension /opt/ol/wlp/usr/extension
6 |
7 | RUN configure.sh
8 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/extension/lib/com.ibm.ws.io.opentracing.zipkintracer-0.31.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rieckpil/getting-started-with-microprofile/3c6984b2c26ec70919e0fd8779136161563960cb/microprofile-open-tracing/book-store/extension/lib/com.ibm.ws.io.opentracing.zipkintracer-0.31.jar
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/extension/lib/features/opentracingZipkin-0.31.mf:
--------------------------------------------------------------------------------
1 | IBM-Feature-Version: 2
2 | IBM-ShortName: opentracingZipkin-0.31
3 | Subsystem-Content: com.ibm.websphere.appserver.opentracing-1.1; ibm.tolerates:="1.2,1.3"; type="osgi.subsystem.feature",
4 | com.ibm.ws.opentracing.zipkin; version="[1.3.0,1.3.200)",
5 | com.ibm.websphere.appserver.jaxrs-2.0; type="osgi.subsystem.feature"; ibm.tolerates:=2.1,
6 | com.ibm.websphere.appserver.cdi-1.2; type="osgi.subsystem.feature"; ibm.tolerates:=2.0
7 | Subsystem-Description: %description
8 | Subsystem-License: https://www.eclipse.org/legal/epl-v10.html
9 | Subsystem-Localization: OSGI-INF/l10n/com.ibm.websphere.appserver.opentracingZipkin-0.31
10 | Subsystem-ManifestVersion: 1
11 | Subsystem-Name: Opentracing Zipkin Tracer implementation
12 | Subsystem-SymbolicName: com.ibm.websphere.appserver.opentracingZipkin-0.31; visibility:=public; singleton:=true
13 | Subsystem-Type: osgi.subsystem.feature
14 | Subsystem-Version: 1.0.0
15 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../../pom.xml
10 |
11 |
12 | 4.0.0
13 | de.rieckpil.blog
14 | microprofile-open-tracing-server
15 | 1.0-SNAPSHOT
16 | war
17 |
18 |
19 | ${project.artifactId}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/server.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | microProfile-3.3
6 | usr:opentracingZipkin-0.31
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/src/main/java/de/rieckpil/blog/BookResource.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.annotation.PostConstruct;
4 | import javax.enterprise.context.ApplicationScoped;
5 | import javax.json.Json;
6 | import javax.json.JsonArray;
7 | import javax.json.JsonObject;
8 | import javax.ws.rs.GET;
9 | import javax.ws.rs.Path;
10 | import javax.ws.rs.Produces;
11 | import javax.ws.rs.core.MediaType;
12 | import javax.ws.rs.core.Response;
13 |
14 | @Path("books")
15 | @ApplicationScoped
16 | public class BookResource {
17 |
18 | private JsonArray books;
19 |
20 | @PostConstruct
21 | public void setup() {
22 |
23 | JsonObject bookOne = Json.createObjectBuilder()
24 | .add("id", 1)
25 | .add("title", "MicroProfile 3.0")
26 | .build();
27 |
28 | JsonObject bookTwo = Json.createObjectBuilder()
29 | .add("id", 2)
30 | .add("title", "Jakarta EE 8")
31 | .build();
32 |
33 | JsonObject bookThree = Json.createObjectBuilder()
34 | .add("id", 3)
35 | .add("title", "Java 13")
36 | .build();
37 |
38 | this.books = Json.createArrayBuilder()
39 | .add(bookOne)
40 | .add(bookTwo)
41 | .add(bookThree)
42 | .build();
43 |
44 | }
45 |
46 | @GET
47 | @Produces(MediaType.APPLICATION_JSON)
48 | public Response getAvailableBooks() {
49 | return Response.ok(this.books).build();
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/src/main/java/de/rieckpil/blog/ContainerLoggingRequestFilter.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.container.ContainerRequestContext;
4 | import javax.ws.rs.container.ContainerRequestFilter;
5 | import javax.ws.rs.ext.Provider;
6 | import java.time.LocalDateTime;
7 |
8 | @Provider
9 | public class ContainerLoggingRequestFilter implements ContainerRequestFilter {
10 |
11 | @Override
12 | public void filter(ContainerRequestContext requestContext) {
13 | System.out.println("==============");
14 | System.out.println("Incoming request at: " + LocalDateTime.now());
15 | requestContext.getHeaders().forEach((k, v) -> System.out.println(k + ":" + v));
16 | System.out.println("==============");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/src/main/java/de/rieckpil/blog/JAXRSConfiguration.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.ApplicationPath;
4 | import javax.ws.rs.core.Application;
5 |
6 | @ApplicationPath("resources")
7 | public class JAXRSConfiguration extends Application {
8 | }
9 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/src/main/java/de/rieckpil/blog/PriceResource.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.enterprise.context.ApplicationScoped;
4 | import javax.ws.rs.GET;
5 | import javax.ws.rs.Path;
6 | import javax.ws.rs.PathParam;
7 | import javax.ws.rs.Produces;
8 | import javax.ws.rs.core.MediaType;
9 | import javax.ws.rs.core.Response;
10 | import java.util.concurrent.ThreadLocalRandom;
11 |
12 | @Path("prices")
13 | @ApplicationScoped
14 | public class PriceResource {
15 |
16 | @GET
17 | @Path("/{id}")
18 | @Produces(MediaType.TEXT_PLAIN)
19 | public Response getPriceForBook(@PathParam("id") Integer bookId) {
20 | System.out.println("Retrieving price for book with id: " + bookId);
21 | sleepRandom();
22 | return Response.ok(ThreadLocalRandom.current().nextDouble(20.0, 42.0)).build();
23 | }
24 |
25 | private void sleepRandom() {
26 | try {
27 | Thread.sleep(ThreadLocalRandom.current().nextLong(100, 500));
28 | } catch (InterruptedException e) {
29 | e.printStackTrace();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/book-store/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/microprofile-open-tracing/buildAndRun.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call mvn clean -f book-store/pom.xml package
3 | call mvn clean -f book-store-client/pom.xml package
4 | call docker-compose build
5 | call docker-compose up --force-recreate
--------------------------------------------------------------------------------
/microprofile-open-tracing/buildAndRun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mvn clean -f book-store/pom.xml package && mvn clean -f book-store-client/pom.xml package
3 | docker-compose build && docker-compose up --force-recreate
--------------------------------------------------------------------------------
/microprofile-open-tracing/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 | services:
3 | book-store-client:
4 | build: book-store-client/
5 | ports:
6 | - "9080:9080"
7 | - "9443:9443"
8 | links:
9 | - zipkin
10 | - book-store
11 | book-store:
12 | build: book-store/
13 | links:
14 | - zipkin
15 | zipkin:
16 | image: openzipkin/zipkin
17 | ports:
18 | - "9411:9411"
19 |
--------------------------------------------------------------------------------
/microprofile-rest-client/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | .apt_generated
5 | .classpath
6 | .factorypath
7 | .project
8 | .settings
9 | .springBeans
10 | .sts4-cache
11 |
12 | .idea
13 | *.iws
14 | *.iml
15 | *.ipr
16 |
17 | /nbproject/private/
18 | /build/
19 | /nbbuild/
20 | /dist/
21 | /nbdist/
22 | /.nb-gradle/
23 |
--------------------------------------------------------------------------------
/microprofile-rest-client/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openliberty/open-liberty:20.0.0.5-kernel-java11-openj9-ubi
2 |
3 | COPY --chown=1001:0 target/microprofile-rest-client.war /config/dropins/
4 | COPY --chown=1001:0 target/server.xml /config
5 |
6 | RUN configure.sh
7 |
--------------------------------------------------------------------------------
/microprofile-rest-client/README.md:
--------------------------------------------------------------------------------
1 | # MicroProfile Rest Client
2 |
3 | * [GitHub](https://github.com/eclipse/microprofile-rest-client)
4 | * [Spec](https://download.eclipse.org/microprofile/microprofile-rest-client-1.3/microprofile-rest-client-1.3.pdf)
5 | * Current version: **1.3** in MicroProfile **3.0**
6 | * Detailed blog post about this specification: [#WHATIS?: MicroProfile Rest Client](https://rieckpil.de/whatis-eclipse-microprofile-rest-client/)
7 | * YouTube video about this specification: [Getting started with Eclipse MicroProfile 3.0 - MicroProfile Rest Client 1.3](https://youtu.be/HJWxI_T3FKo)
--------------------------------------------------------------------------------
/microprofile-rest-client/buildAndRun.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call mvn clean package
3 | call docker build -t de.rieckpil.blogmicroprofile-rest-client .
4 | call docker rm -f microprofile-rest-client
5 | call docker run -d -p 9080:9080 -p 9443:9443 --name mmicroprofile-rest-client de.rieckpil.blog/microprofile-rest-client
--------------------------------------------------------------------------------
/microprofile-rest-client/buildAndRun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mvn clean package && docker build -t de.rieckpil.blog/microprofile-rest-client .
3 | docker rm -f microprofile-rest-client || true && docker run -d -p 9080:9080 -p 9443:9443 --name microprofile-rest-client de.rieckpil.blog/microprofile-rest-client
--------------------------------------------------------------------------------
/microprofile-rest-client/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | ../pom.xml
10 |
11 |
12 | 4.0.0
13 | de.rieckpil.blog
14 | microprofile-rest-client
15 | 1.0-SNAPSHOT
16 | war
17 |
18 |
19 | ${project.artifactId}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/microprofile-rest-client/src/main/java/de/rieckpil/blog/GlobalClientHeaders.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.config.inject.ConfigProperty;
4 | import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;
5 |
6 | import javax.enterprise.context.ApplicationScoped;
7 | import javax.inject.Inject;
8 | import javax.ws.rs.core.MultivaluedHashMap;
9 | import javax.ws.rs.core.MultivaluedMap;
10 |
11 | @ApplicationScoped
12 | public class GlobalClientHeaders implements ClientHeadersFactory {
13 |
14 | @Inject
15 | @ConfigProperty(name = "secrets.value")
16 | private String secretValue;
17 |
18 | @Override
19 | public MultivaluedMap update(MultivaluedMap incomingHeaders, MultivaluedMap clientOutgoingHeaders) {
20 |
21 | System.out.println("--- Incoming headers of the JAX-RS environment");
22 | incomingHeaders.forEach((k, v) -> System.out.println(k + ":" + v));
23 |
24 | System.out.println("--- Specified outgoing headers of the Rest Client");
25 | clientOutgoingHeaders.forEach((k, v) -> System.out.println(k + ":" + v));
26 |
27 | MultivaluedMap resultHeader = new MultivaluedHashMap();
28 | resultHeader.putAll(incomingHeaders);
29 | resultHeader.putAll(clientOutgoingHeaders);
30 |
31 | resultHeader.add("X-Secret-Header", secretValue);
32 | resultHeader.add("X-Global-Header", "duke");
33 | resultHeader.add("X-Special-Header", "MicroProfile");
34 |
35 | System.out.println("--- Header of the Rest Client after merging");
36 | resultHeader.forEach((k, v) -> System.out.println(k + ":" + v));
37 |
38 | return resultHeader;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/microprofile-rest-client/src/main/java/de/rieckpil/blog/JSONPlaceholderClient.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
4 | import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
5 | import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
6 | import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
7 |
8 | import javax.json.JsonArray;
9 | import javax.json.JsonObject;
10 | import javax.ws.rs.*;
11 | import javax.ws.rs.core.MediaType;
12 | import javax.ws.rs.core.Response;
13 | import java.util.Base64;
14 | import java.util.concurrent.CompletionStage;
15 |
16 | @RegisterRestClient
17 | @Consumes(MediaType.APPLICATION_JSON)
18 | @Produces(MediaType.APPLICATION_JSON)
19 | @RegisterProvider(ResponseLoggingFilter.class)
20 | @RegisterClientHeaders(GlobalClientHeaders.class)
21 | @ClientHeaderParam(name = "X-Application-Name", value = "MP-blog")
22 | public interface JSONPlaceholderClient {
23 |
24 | @GET
25 | @Path("/posts")
26 | JsonArray getAllPosts(@QueryParam("orderBy") String orderDirection);
27 |
28 | @GET
29 | @Path("/posts/{id}")
30 | CompletionStage getPostById(@PathParam("id") String id);
31 |
32 | @GET
33 | @Path("/posts/{id}/comments")
34 | JsonArray getCommentsForPostByPostId(@PathParam("id") String id);
35 |
36 | @POST
37 | @Path("/posts")
38 | Response createPost(JsonObject post);
39 |
40 | @DELETE
41 | @Path("/posts/{id}")
42 | Response deletePostById(@PathParam("id") String id);
43 |
44 | @PUT
45 | @ClientHeaderParam(name = "Authorization", value = "{generateAuthHeader}")
46 | @Path("/posts/{id}")
47 | Response updatePostById(@PathParam("id") String id, JsonObject post, @HeaderParam("X-Request-Id") String requestIdHeader);
48 |
49 | default String generateAuthHeader() {
50 | return "Basic " + new String(Base64.getEncoder().encode("duke:SECRET".getBytes()));
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/microprofile-rest-client/src/main/java/de/rieckpil/blog/PostService.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.eclipse.microprofile.rest.client.RestClientBuilder;
4 | import org.eclipse.microprofile.rest.client.inject.RestClient;
5 |
6 | import javax.enterprise.context.ApplicationScoped;
7 | import javax.enterprise.context.Initialized;
8 | import javax.enterprise.event.Observes;
9 | import javax.inject.Inject;
10 | import javax.json.Json;
11 | import javax.json.JsonObject;
12 | import javax.ws.rs.core.Response;
13 | import java.net.URI;
14 | import java.net.URISyntaxException;
15 | import java.util.UUID;
16 | import java.util.concurrent.TimeUnit;
17 |
18 | @ApplicationScoped
19 | public class PostService {
20 |
21 | @Inject
22 | @RestClient
23 | JSONPlaceholderClient jsonPlaceholderClient;
24 |
25 | public void init(@Observes @Initialized(ApplicationScoped.class) Object init) throws URISyntaxException {
26 | restClientBuilderExample();
27 | // getAllPosts();
28 | // getSinglePost();
29 | // createNewPost();
30 | // updateExistingPost();
31 | // deletePost();
32 | }
33 |
34 | private void restClientBuilderExample() throws URISyntaxException {
35 | System.out.println("------ Rest Client builder example ------");
36 |
37 | JSONPlaceholderClient jsonApiClient = RestClientBuilder.newBuilder()
38 | .baseUri(new URI("https://jsonplaceholder.typicode.com"))
39 | .register(ResponseLoggingFilter.class)
40 | .connectTimeout(2, TimeUnit.SECONDS)
41 | .readTimeout(2, TimeUnit.SECONDS)
42 | .build(JSONPlaceholderClient.class);
43 |
44 | jsonApiClient.getPostById("1").thenAccept(System.out::println);
45 | }
46 |
47 | private void deletePost() {
48 | System.out.println("------ delete a post ------");
49 |
50 | Response postDeletionResult = jsonPlaceholderClient.deletePostById("42");
51 |
52 | System.out.println(postDeletionResult.readEntity(JsonObject.class));
53 | }
54 |
55 | private void updateExistingPost() {
56 | System.out.println("------ update a post ------");
57 |
58 | JsonObject postUpdate = Json.createObjectBuilder()
59 | .add("id", 42)
60 | .add("title", "Jakarta EE 8")
61 | .add("body", "Work with Jakarta EE 8")
62 | .add("userId", 1)
63 | .build();
64 |
65 | Response postUpdateResult = jsonPlaceholderClient.updatePostById("42", postUpdate, UUID.randomUUID().toString());
66 |
67 | System.out.println(postUpdateResult.readEntity(JsonObject.class));
68 | }
69 |
70 | private void createNewPost() {
71 | System.out.println("------ create new post ------");
72 |
73 | JsonObject post = Json.createObjectBuilder()
74 | .add("id", 42)
75 | .add("title", "MicroProfile")
76 | .add("body", "Work with MicroProfile")
77 | .add("userId", 1)
78 | .build();
79 |
80 | Response postCreationResult = jsonPlaceholderClient.createPost(post);
81 |
82 | System.out.println(postCreationResult.readEntity(JsonObject.class));
83 | }
84 |
85 | private void getSinglePost() {
86 | System.out.println("------ single post ASYNC ------");
87 | jsonPlaceholderClient.getPostById("1").thenAccept(System.out::println);
88 | }
89 |
90 | private void getAllPosts() {
91 | System.out.println("------ all posts ------");
92 |
93 | jsonPlaceholderClient.getAllPosts("ASC")
94 | .stream()
95 | .limit(5)
96 | .forEach(System.out::println);
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/microprofile-rest-client/src/main/java/de/rieckpil/blog/ResponseLoggingFilter.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import javax.ws.rs.client.ClientRequestContext;
4 | import javax.ws.rs.client.ClientResponseContext;
5 | import javax.ws.rs.client.ClientResponseFilter;
6 | import java.io.IOException;
7 |
8 | public class ResponseLoggingFilter implements ClientResponseFilter {
9 |
10 | @Override
11 | public void filter(ClientRequestContext clientRequestContext, ClientResponseContext clientResponseContext) throws IOException {
12 | System.out.println("Status code is: " + clientResponseContext.getStatus());
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/microprofile-rest-client/src/main/resources/META-INF/microprofile-config.properties:
--------------------------------------------------------------------------------
1 | de.rieckpil.blog.JSONPlaceholderClient/mp-rest/url=https://jsonplaceholder.typicode.com
2 | de.rieckpil.blog.JSONPlaceholderClient/mp-rest/connectTimeout=3000
3 | de.rieckpil.blog.JSONPlaceholderClient/mp-rest/readTimeout=3000
4 | secrets.value=FOO
5 |
--------------------------------------------------------------------------------
/microprofile-rest-client/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/microprofile-rest-client/src/main/webapp/WEB-INF/ibm-web-ext.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/microprofile-rest-client/src/main/webapp/WEB-INF/payara-web.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
6 |
--------------------------------------------------------------------------------
/microprofile-rest-client/src/test/java/de/rieckpil/blog/ApplicationIT.java:
--------------------------------------------------------------------------------
1 | package de.rieckpil.blog;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.microshed.testing.jupiter.MicroShedTest;
5 | import org.microshed.testing.testcontainers.ApplicationContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 |
8 | @MicroShedTest
9 | public class ApplicationIT {
10 |
11 | @Container
12 | public static ApplicationContainer app = new ApplicationContainer()
13 | .withAppContextRoot("/")
14 | .withReadinessPath("/health/ready");
15 |
16 | @Test
17 | public void testApplicationStarts() {
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/microprofile-rest-client/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 | log4j.appender=org.apache.log4j.ConsoleAppender
3 | log4j.appender.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%r %p %c %x - %m%n
7 | log4j.logger.org.microshed.testing=DEBUG
8 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 | 4.0.0
6 | de.rieckpil.blog
7 | microprofile-course-parent
8 | 1.0-SNAPSHOT
9 | pom
10 |
11 |
12 |
13 | org.eclipse.microprofile
14 | microprofile
15 | ${microprofile.version}
16 | pom
17 | provided
18 |
19 |
20 | org.microshed
21 | microshed-testing-liberty
22 | ${microshed-testing.version}
23 | test
24 |
25 |
26 | org.junit.jupiter
27 | junit-jupiter
28 | ${junit-jupiter.version}
29 | test
30 |
31 |
32 | org.slf4j
33 | slf4j-log4j12
34 | ${slf4j-log4j12.version}
35 | test
36 |
37 |
38 |
39 |
40 | 11
41 | 3.3
42 | 5.6.0
43 | 0.9
44 | 1.7.29
45 | ${java.version}
46 | ${java.version}
47 | UTF-8
48 | UTF-8
49 |
50 |
51 |
52 |
53 |
54 | org.apache.maven.plugins
55 | maven-war-plugin
56 | 3.2.3
57 |
58 | false
59 |
60 |
61 |
62 | io.openliberty.tools
63 | liberty-maven-plugin
64 | 3.1
65 |
66 | 20.0.0.5
67 | ../server.xml
68 |
69 |
70 |
71 | maven-resources-plugin
72 | 3.1.0
73 |
74 |
75 | copy-resources
76 | validate
77 |
78 | copy-resources
79 |
80 |
81 | ${project.basedir}/target
82 |
83 |
84 | ../
85 |
86 | server.xml
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | maven-failsafe-plugin
96 | 3.0.0-M3
97 |
98 |
99 | integration-test
100 |
101 | integration-test
102 |
103 |
104 | false
105 |
106 |
107 |
108 | verify
109 |
110 | verify
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/server.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | microProfile-3.3
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------