├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── config ├── README.md ├── basic-injection │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── org │ │ │ │ └── eclipse │ │ │ │ └── microprofile12 │ │ │ │ └── config │ │ │ │ └── basicinjection │ │ │ │ ├── ApplicationInit.java │ │ │ │ └── Servlet.java │ │ └── resources │ │ │ └── META-INF │ │ │ └── microprofile-config.properties │ │ └── test │ │ └── java │ │ └── org │ │ └── eclipse │ │ └── microprofile12 │ │ └── config │ │ └── basicinjection │ │ └── BasicInjectionTest.java ├── config-source │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── org │ │ │ │ └── eclipse │ │ │ │ └── microprofile12 │ │ │ │ └── config │ │ │ │ └── configsource │ │ │ │ ├── ApplicationInit.java │ │ │ │ ├── EchoConfigSource.java │ │ │ │ └── Servlet.java │ │ └── resources │ │ │ └── META-INF │ │ │ └── services │ │ │ └── org.eclipse.microprofile.config.spi.ConfigSource │ │ └── test │ │ └── java │ │ └── org │ │ └── eclipse │ │ └── microprofile12 │ │ └── config │ │ └── configsource │ │ ├── ConfigSourceNotPresentTest.java │ │ └── ConfigSourcePresentTest.java ├── converter │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── org │ │ │ │ └── eclipse │ │ │ │ └── microprofile12 │ │ │ │ └── config │ │ │ │ └── converter │ │ │ │ ├── ApplicationInit.java │ │ │ │ ├── CustomConverter.java │ │ │ │ ├── Servlet.java │ │ │ │ └── TestPojo.java │ │ └── resources │ │ │ └── META-INF │ │ │ ├── microprofile-config.properties │ │ │ └── services │ │ │ └── org.eclipse.microprofile.config.spi.Converter │ │ └── test │ │ └── java │ │ └── org │ │ └── eclipse │ │ └── microprofile12 │ │ └── config │ │ └── converter │ │ └── ConverterTest.java ├── default-conversion │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── org │ │ │ │ └── eclipse │ │ │ │ └── microprofile12 │ │ │ │ └── config │ │ │ │ └── defaultconversion │ │ │ │ ├── ApplicationInit.java │ │ │ │ └── Servlet.java │ │ └── resources │ │ │ └── META-INF │ │ │ └── microprofile-config.properties │ │ └── test │ │ └── java │ │ └── org │ │ └── eclipse │ │ └── microprofile12 │ │ └── config │ │ └── defaultconversion │ │ └── DefaultConversionTest.java └── pom.xml ├── fault-tolerance ├── README.md ├── asynchronous │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── org │ │ │ │ └── eclipse │ │ │ │ └── microprofile12 │ │ │ │ └── faulttolerance │ │ │ │ └── asynchronous │ │ │ │ ├── MyAsyncBeanClassLevel.java │ │ │ │ └── MyAsyncBeanMethodLevel.java │ │ └── resources │ │ │ └── project-defaults.yml │ │ └── test │ │ └── java │ │ └── org │ │ └── eclipse │ │ └── microprofile12 │ │ └── faulttolerance │ │ └── asynchronous │ │ ├── AsyncClassBeanTest.java │ │ └── AsyncMethodBeanTest.java ├── bulkhead │ ├── micro-pre-boot-commands.txt │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── org │ │ │ │ └── eclipse │ │ │ │ └── microprofile │ │ │ │ └── samples12 │ │ │ │ └── bulkhead │ │ │ │ ├── AsynchronousBulkheadBean.java │ │ │ │ ├── ClassLevelBulkheadBean.java │ │ │ │ └── MethodLevelBulkheadBean.java │ │ └── resources │ │ │ └── project-defaults.yml │ │ └── test │ │ └── java │ │ └── org │ │ └── eclipse │ │ └── microprofile12 │ │ └── faulttolerance │ │ └── bulkhead │ │ ├── AsynchronousBulkheadBeanTest.java │ │ ├── ClassLevelBulkheadBeanTest.java │ │ └── MethodLevelBulkheadBeanTest.java ├── circuitbreaker │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── org │ │ │ └── eclipse │ │ │ └── microprofile │ │ │ └── samples12 │ │ │ └── circuitbreaker │ │ │ ├── ClassLevelCircuitBreakerBean.java │ │ │ └── MethodLevelCircuitBreakerBean.java │ │ └── test │ │ └── java │ │ └── org │ │ └── eclipse │ │ └── microprofile12 │ │ └── faulttolerance │ │ └── circuitbreaker │ │ ├── ClassLevelCircuitBreakerBeanTest.java │ │ └── MethodLevelCircuitBreakerBeanTest.java ├── fallback │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── org │ │ │ └── eclipse │ │ │ └── microprofile │ │ │ └── samples12 │ │ │ └── fallback │ │ │ ├── FallbackBean.java │ │ │ └── StringFallbackHandler.java │ │ └── test │ │ └── java │ │ └── org │ │ └── eclipse │ │ └── microprofile │ │ └── samples12 │ │ └── fallback │ │ └── FallbackBeanTest.java ├── pom.xml ├── retry │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── org │ │ │ └── eclipse │ │ │ └── microprofile │ │ │ └── samples12 │ │ │ └── retry │ │ │ └── RetryBean.java │ │ └── test │ │ └── java │ │ └── org │ │ └── eclipse │ │ └── microprofile │ │ └── samples12 │ │ └── retry │ │ └── RetryBeanTest.java └── timeout │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── eclipse │ │ │ └── microprofile │ │ │ └── samples12 │ │ │ └── timeout │ │ │ ├── AsynchronousTimeoutBean.java │ │ │ ├── ClassLevelTimeoutBean.java │ │ │ └── MethodLevelTimeoutBean.java │ └── resources │ │ └── project-defaults.yml │ └── test │ └── java │ └── org │ └── eclipse │ └── microprofile │ └── samples12 │ └── timeout │ ├── AsynchronousTimeoutBeanTest.java │ ├── ClassLevelTimeoutBeanTest.java │ └── MethodLevelTimeoutBeanTest.java ├── jwt-auth ├── README.md ├── basic-authentication │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── org │ │ │ │ └── eclipse │ │ │ │ └── microprofile12 │ │ │ │ └── jwtauth │ │ │ │ └── basic │ │ │ │ ├── ApplicationInit.java │ │ │ │ └── Servlet.java │ │ └── resources │ │ │ ├── META-INF │ │ │ └── MP-JWT-SIGNER │ │ │ ├── jwt-roles.properties │ │ │ ├── payara-mp-jwt.properties │ │ │ ├── project-defaults.yml │ │ │ └── publicKey.pem │ │ └── test │ │ ├── java │ │ └── org │ │ │ └── eclipse │ │ │ └── microprofile12 │ │ │ └── jwtauth │ │ │ └── basic │ │ │ └── BasicAuthenticationTest.java │ │ └── resources │ │ ├── jwt-token.json │ │ └── privateKey.pem ├── jaxrs │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── org │ │ │ │ └── eclipse │ │ │ │ └── microprofile12 │ │ │ │ └── jwtauth │ │ │ │ └── jaxrs │ │ │ │ ├── ApplicationInit.java │ │ │ │ └── Resource.java │ │ └── resources │ │ │ ├── jwt-roles.properties │ │ │ ├── payara-mp-jwt.properties │ │ │ ├── project-defaults.yml │ │ │ └── publicKey.pem │ │ └── test │ │ ├── java │ │ └── org │ │ │ └── eclipse │ │ │ └── microprofile12 │ │ │ └── jwtauth │ │ │ └── jaxrs │ │ │ └── JaxRsTest.java │ │ └── resources │ │ ├── jwt-token.json │ │ └── privateKey.pem └── pom.xml ├── metrics ├── application-metrics │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── org │ │ │ └── eclipse │ │ │ └── microprofile12 │ │ │ └── metrics │ │ │ └── application │ │ │ ├── ApplicationInit.java │ │ │ └── UserResource.java │ │ └── test │ │ └── java │ │ └── org │ │ └── eclipse │ │ └── microprofile12 │ │ └── metrics │ │ └── application │ │ └── ApplicationMetricsTest.java ├── base-metrics │ ├── pom.xml │ └── src │ │ └── test │ │ └── java │ │ └── org │ │ └── eclipse │ │ └── microprofile12 │ │ └── metrics │ │ └── base │ │ └── BaseMetricsTest.java └── pom.xml ├── pom.xml └── test-utils ├── pom.xml └── src └── main ├── java └── org │ └── eclipse │ └── microprofile12 │ ├── CliCommands.java │ ├── JwtTokenGenerator.java │ ├── Libraries.java │ ├── Parameter.java │ ├── ParameterRule.java │ └── ServerOperations.java └── resources ├── arquillian-thorntail.xml ├── arquillian.xml ├── key.jks ├── logging.properties └── server.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # Directories # 2 | build/ 3 | bin/ 4 | target/ 5 | libs/ 6 | tmp/ 7 | node_modules/ 8 | 9 | # OS Files # 10 | .DS_Store 11 | 12 | *.class 13 | 14 | # Package Files # 15 | *.jar 16 | *.war 17 | *.ear 18 | *.db 19 | rebel.xml 20 | 21 | ###################### 22 | # Windows 23 | ###################### 24 | 25 | # Windows image file caches 26 | Thumbs.db 27 | 28 | # Folder config file 29 | Desktop.ini 30 | 31 | ###################### 32 | # OSX 33 | ###################### 34 | 35 | .DS_Store 36 | .svn 37 | 38 | # Thumbnails 39 | ._* 40 | 41 | # Files that might appear on external disk 42 | .Spotlight-V100 43 | .Trashes 44 | 45 | ###################### 46 | # NetBeans 47 | ###################### 48 | nbproject/ 49 | build/ 50 | nbbuild/ 51 | dist/ 52 | nbdist/ 53 | nbactions.xml 54 | nb-configuration.xml 55 | 56 | ###################### 57 | # IDEA 58 | ###################### 59 | *.iml 60 | *.ipr 61 | *.iws 62 | .idea/ 63 | atlassian-ide-plugin.xml 64 | 65 | 66 | ###################### 67 | # Eclipse 68 | ###################### 69 | 70 | *.pydevproject 71 | .project 72 | .metadata 73 | *.tmp 74 | *.bak 75 | *.swp 76 | *~.nib 77 | local.properties 78 | .classpath 79 | .settings/ 80 | .loadpath 81 | 82 | # External tool builders 83 | .externalToolBuilders/ 84 | 85 | # Locally stored "Eclipse launch configurations" 86 | *.launch 87 | 88 | # CDT-specific 89 | .cproject 90 | 91 | # PDT-specific 92 | .buildpath 93 | 94 | # Testing environment specific 95 | derby.log 96 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | 5 | env: 6 | - SERVER=payara-ci-managed 7 | - SERVER=payara-micro-managed 8 | - SERVER=liberty-ci-managed 9 | - SERVER=wildfly-ci-managed 10 | 11 | install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -Pnothing 12 | 13 | script: mvn clean install -P $SERVER --fail-at-end -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Except where otherwise indicated, everything in this repository is licensed under the MIT license: 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Eclipse MicroProfile 1.2 samples # 2 | 3 | [![Build Status](https://travis-ci.org/javaee-samples/microprofile1.2-samples.svg?branch=master)](https://travis-ci.org/javaee-samples/microprofile1.2-samples) 4 | 5 | This workspace consists of MicroProfile 1.2 Samples and unit tests. MicroProfile is a code first, open API initiative about optimizing Enterprise Java for a microservices architecture. See [microprofile.io](https://microprofile.io) for additional info. 6 | 7 | Samples are categorized in different directories, one for each technology/spec. 8 | 9 | 10 | ## How to run? ## 11 | 12 | Samples are tested on Payara using Arquillian. Arquillian uses container profiles to start up and deploy tests to individual containers (servers). 13 | 14 | Only one container profile can be active at a given time, otherwise there will be dependency conflicts. 15 | 16 | These are the available container profiles: 17 | 18 | * Payara 19 | * ``payara-ci-managed`` 20 | 21 | This profile will install a Payara server and start up the server per sample. 22 | Useful for CI servers. The Payara version that's used can be set via the ``payara.version`` property. 23 | This is the default profile and does not have to be specified explicitly. 24 | 25 | * ``payara-micro-managed`` 26 | 27 | This profile will install Payara Micro and start up the jar per sample. 28 | Useful for CI servers. The Payara Micro version that's used can be set via the ``payara.micro.version`` property. 29 | 30 | * ``payara-remote`` 31 | 32 | This profile requires you to start up a Payara server outside of the build. Each sample will then 33 | reuse this instance to run the tests. 34 | Useful for development to avoid the server start up cost per sample. 35 | * Liberty 36 | * ``liberty-ci-managed`` 37 | 38 | This profile uses the special "wlp-microProfile1" distribution of Liberty, which contains the MicroProfile APIs out of the box 39 | and start up the server per sample. 40 | Useful for CI servers. The Liberty version that's used can be set via the ``liberty.version`` property. 41 | * Thorntail 42 | * ``thorntail`` 43 | 44 | This profile is based on Thorntail, and includes the MicroProfile 1.2 fragment. The actual Thorntail code and thus 45 | the WildFly code is handled internally by the Arquillian connector. 46 | Useful for CI servers. The Thorntail version that's used can be set via the ``thorntail.version`` property. 47 | 48 | The containers that download and install a server (the \*-ci-managed profiles) allow you to override the version used, e.g.: 49 | 50 | * `-Dpayara.version=5.0.0.174` 51 | 52 | This will change the version from the current one (e.g 5.0.0.172) to 5.0.0.174 for Payara testing purposes. 53 | 54 | 55 | **To run them in the console do**: 56 | 57 | 1. In the terminal, ``mvn test -fae`` at the top-level directory to start the tests for the default profile. 58 | 59 | When developing and runing them from IDE, remember to activate the profile before running the test. 60 | 61 | To learn more about Arquillian please refer to the [Arquillian Guides](http://arquillian.org/guides/) 62 | 63 | **To run only a subset of the tests do at the top-level directory**: 64 | 65 | 1. Install top level dependencies: ``mvn clean install -pl "test-utils" -am`` 66 | 1. cd into desired module, e.g.: ``cd cdi`` 67 | 1. Run tests against desired server, e.g.: ``mvn clean test -P payara-remote`` 68 | 69 | 70 | ## How to contribute ## 71 | 72 | With your help we can improve this set of samples, learn from each other and grow the community full of passionate people who care about the technology, innovation and code quality. Every contribution matters! 73 | 74 | There is just a bunch of things you should keep in mind before sending a pull request, so we can easily get all the new things incorporated into the master branch. 75 | 76 | Standard tests are jUnit based. Test classes naming must comply with surefire naming standards `**/*Test.java`, `**/*Test*.java` or `**/*TestCase.java`. 77 | 78 | For the sake of clarity and consistency, and to minimize the upfront complexity, we prefer standard jUnit tests using Java, with as additional helpers HtmlUnit, Hamcrest and of course Arquillian. Please don't use alternatives for these technologies. If any new dependency has to be introduced into this project it should provide something that's not covered by these existing dependencies. 79 | 80 | 81 | ### Some coding principles ### 82 | 83 | * When creating new source file do not put (or copy) any license header, as we use top-level license (MIT) for each and every file in this repository. 84 | * Please follow JBoss Community code formatting profile as defined in the [jboss/ide-config](https://github.com/jboss/ide-config#readme) repository. The details are explained there, as well as configurations for Eclipse, IntelliJ and NetBeans. 85 | 86 | 87 | ### Small Git tips ### 88 | 89 | * Make sure your [fork](https://help.github.com/articles/fork-a-repo) is always up-to-date. Simply run ``git pull upstream master`` and you are ready to hack. 90 | * When developing new features please create a feature branch so that we incorporate your changes smoothly. It's also convenient for you as you could work on few things in parallel ;) In order to create a feature branch and switch to it in one swoop you can use ``git checkout -b my_new_cool_feature`` 91 | 92 | That's it! Welcome in the community! 93 | 94 | ## CI Job ## 95 | 96 | CI jobs are executed by [Travis](https://travis-ci.org/javaee-samples/microprofile1.2-samples). Note that by the very nature of the samples provided here it's perfectly normal that not all tests pass. This normally would indicate a bug in the server on which the samples are executed. If you think it's really the test that's faulty, then please submit an issue or provide a PR with a fix. 97 | 98 | 99 | ## Run each sample in Docker 100 | 101 | * Install Docker client from http://boot2docker.io 102 | * Build the sample that you want to run as 103 | 104 | ``mvn clean package -DskipTests`` 105 | 106 | For example: (note the exact module doens't exist yet, wip here) 107 | 108 | ``mvn -f jaxrs/jaxrs-client/pom.xml clean package -DskipTests`` 109 | 110 | * Change the second line in ``Dockerfile`` to specify the location of the generated WAR file 111 | * Run boot2docker and give the command 112 | 113 | ``docker build -it -p 80:8080 javaee8-sample`` 114 | 115 | * In a different shell, find out the IP address of the running container as: 116 | 117 | ``boot2docker ip`` 118 | 119 | * Access the sample as http://IP_ADDRESS:80/jaxrs-client/webresources/persons. The exact URL would differ based upon the sample. 120 | 121 | -------------------------------------------------------------------------------- /config/README.md: -------------------------------------------------------------------------------- 1 | # Eclipse MicroProfile 1.2 Samples - Config 1.1 2 | 3 | - [Wiki project page](https://wiki.eclipse.org/MicroProfile/Config) 4 | - [Spec, API, TCK GitHub repo](https://github.com/eclipse/microprofile-config) 5 | 6 | ## Samples ## 7 | 8 | - **basic-injection** Shows the injection of some simple values from the `META-INF/microprofile-config.properties` file 9 | - **config-source** Shows how an alternative programmatic source for configuration values can be used 10 | - **converter** Shows how a custom converter is globally set so values from a config source can be converted to the type of the injection point. 11 | - **default-conversion** Shows that a number of default conversions can be applied to injected values 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /config/basic-injection/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | org.eclipse.microprofile.samples12 6 | config 7 | 1.0-SNAPSHOT 8 | 9 | 10 | basic-injection 11 | war 12 | MicroProfile 1.2: Config - Basic Injection 13 | 14 | 15 | -------------------------------------------------------------------------------- /config/basic-injection/src/main/java/org/eclipse/microprofile12/config/basicinjection/ApplicationInit.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.config.basicinjection; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | 5 | @ApplicationScoped 6 | public class ApplicationInit { 7 | 8 | 9 | } 10 | -------------------------------------------------------------------------------- /config/basic-injection/src/main/java/org/eclipse/microprofile12/config/basicinjection/Servlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 | * 4 | * Copyright (c) 2017-2018 Payara Foundation and/or its affiliates. All rights reserved. 5 | * 6 | * The contents of this file are subject to the terms of either the GNU 7 | * General Public License Version 2 only ("GPL") or the Common Development 8 | * and Distribution License("CDDL") (collectively, the "License"). You 9 | * may not use this file except in compliance with the License. You can 10 | * obtain a copy of the License at 11 | * https://github.com/payara/Payara/blob/master/LICENSE.txt 12 | * See the License for the specific 13 | * language governing permissions and limitations under the License. 14 | * 15 | * When distributing the software, include this License Header Notice in each 16 | * file and include the License file at glassfish/legal/LICENSE.txt. 17 | * 18 | * GPL Classpath Exception: 19 | * The Payara Foundation designates this particular file as subject to the "Classpath" 20 | * exception as provided by the Payara Foundation in the GPL Version 2 section of the License 21 | * file that accompanied this code. 22 | * 23 | * Modifications: 24 | * If applicable, add the following below the License Header, with the fields 25 | * enclosed by brackets [] replaced by your own identifying information: 26 | * "Portions Copyright [year] [name of copyright owner]" 27 | * 28 | * Contributor(s): 29 | * If you wish your version of this file to be governed by only the CDDL or 30 | * only the GPL Version 2, indicate your decision by adding "[Contributor] 31 | * elects to include this software in this distribution under the [CDDL or GPL 32 | * Version 2] license." If you don't indicate a single choice of license, a 33 | * recipient has the option to distribute your version of this file under 34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to 35 | * its licensees as provided above. However, if you add GPL Version 2 code 36 | * and therefore, elected the GPL Version 2 license, then the option applies 37 | * only if the new code is made subject to such option by the copyright 38 | * holder. 39 | */ 40 | package org.eclipse.microprofile12.config.basicinjection; 41 | 42 | import java.io.IOException; 43 | import java.util.Optional; 44 | 45 | import javax.inject.Inject; 46 | import javax.servlet.ServletException; 47 | import javax.servlet.annotation.WebServlet; 48 | import javax.servlet.http.HttpServlet; 49 | import javax.servlet.http.HttpServletRequest; 50 | import javax.servlet.http.HttpServletResponse; 51 | 52 | import org.eclipse.microprofile.config.inject.ConfigProperty; 53 | 54 | @WebServlet("/servlet") 55 | public class Servlet extends HttpServlet { 56 | 57 | private static final long serialVersionUID = 1L; 58 | 59 | // Example showing injection of a default property 60 | @Inject 61 | @ConfigProperty(name = "default.property", defaultValue = "Default Value") 62 | private String defaultProperty; 63 | 64 | // Example showing reading a config property from the META-INF/microprofile-config.properties file 65 | @Inject 66 | @ConfigProperty(name = "file.property") 67 | private String fileProperty; 68 | 69 | // Example showing reading a config property from the META-INF/microprofile-config.properties file 70 | @Inject 71 | @ConfigProperty(name = "application.property") 72 | private String applicationProperty; 73 | 74 | // Example injection of an optional value that's not required to be present 75 | @Inject 76 | @ConfigProperty(name = "application.optionalProperty") 77 | private Optional optionalApplicationProperty; 78 | 79 | @Override 80 | public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 81 | response.setContentType("text/plain"); 82 | response.getWriter().write( 83 | "default.property : " + defaultProperty + "\n" + 84 | "file.property : " + fileProperty + "\n" + 85 | "application.property : " + applicationProperty + "\n" + 86 | "application.optionalProperty : " + optionalApplicationProperty.orElse("Not defined") + "\n" 87 | ); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /config/basic-injection/src/main/resources/META-INF/microprofile-config.properties: -------------------------------------------------------------------------------- 1 | # Example application properties file 2 | file.property=File Property 3 | date.property=2000-01-01 4 | application.property=Some value 5 | -------------------------------------------------------------------------------- /config/basic-injection/src/test/java/org/eclipse/microprofile12/config/basicinjection/BasicInjectionTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.config.basicinjection; 2 | 3 | import static javax.ws.rs.client.ClientBuilder.newClient; 4 | import static javax.ws.rs.core.MediaType.TEXT_PLAIN; 5 | import static org.jboss.shrinkwrap.api.ShrinkWrap.create; 6 | import static org.junit.Assert.assertTrue; 7 | 8 | import java.io.IOException; 9 | import java.net.URI; 10 | import java.net.URL; 11 | 12 | import org.jboss.arquillian.container.test.api.Deployment; 13 | import org.jboss.arquillian.container.test.api.RunAsClient; 14 | import org.jboss.arquillian.junit.Arquillian; 15 | import org.jboss.arquillian.test.api.ArquillianResource; 16 | import org.jboss.shrinkwrap.api.spec.WebArchive; 17 | import org.junit.Test; 18 | import org.junit.runner.RunWith; 19 | 20 | /** 21 | * @author Arjan Tijms 22 | */ 23 | @RunWith(Arquillian.class) 24 | public class BasicInjectionTest { 25 | 26 | @ArquillianResource 27 | private URL base; 28 | 29 | @Deployment(testable = false) 30 | public static WebArchive createDeployment() { 31 | WebArchive archive = 32 | create(WebArchive.class, "BasicInjectionTest.war") 33 | .addClasses( 34 | ApplicationInit.class, 35 | Servlet.class 36 | ).addAsResource( 37 | "META-INF/microprofile-config.properties" 38 | ) 39 | ; 40 | 41 | System.out.println("************************************************************"); 42 | System.out.println(archive.toString(true)); 43 | System.out.println("************************************************************"); 44 | 45 | return archive; 46 | } 47 | 48 | @Test 49 | @RunAsClient 50 | public void testBasicInjection() throws IOException { 51 | 52 | String response = 53 | newClient() 54 | .target( 55 | URI.create(new URL(base, "servlet").toExternalForm())) 56 | .request(TEXT_PLAIN) 57 | .get(String.class); 58 | 59 | System.out.println("-------------------------------------------------------------------------"); 60 | System.out.println("Response: " + response); 61 | System.out.println("-------------------------------------------------------------------------"); 62 | 63 | assertTrue( 64 | response.contains("default.property : Default Value") 65 | ); 66 | 67 | assertTrue( 68 | response.contains("file.property : File Property") 69 | ); 70 | 71 | assertTrue( 72 | response.contains("application.property : Some value") 73 | ); 74 | 75 | } 76 | 77 | @Test 78 | @RunAsClient 79 | public void testOptional() throws IOException { 80 | 81 | String response = 82 | newClient() 83 | .target( 84 | URI.create(new URL(base, "servlet").toExternalForm())) 85 | .request(TEXT_PLAIN) 86 | .get(String.class); 87 | 88 | System.out.println("-------------------------------------------------------------------------"); 89 | System.out.println("Response: " + response); 90 | System.out.println("-------------------------------------------------------------------------"); 91 | 92 | assertTrue( 93 | // Liberty 94 | response.contains("application.optionalProperty : Not defined") || 95 | 96 | // Payara and WildFly 97 | response.contains("application.optionalProperty : org.eclipse.microprofile.config.configproperty.unconfigureddvalue") 98 | ); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /config/config-source/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | org.eclipse.microprofile.samples12 6 | config 7 | 1.0-SNAPSHOT 8 | 9 | 10 | config-source 11 | war 12 | MicroProfile 1.2: Config - Config Source 13 | 14 | 15 | -------------------------------------------------------------------------------- /config/config-source/src/main/java/org/eclipse/microprofile12/config/configsource/ApplicationInit.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.config.configsource; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | 5 | @ApplicationScoped 6 | public class ApplicationInit { 7 | 8 | 9 | } 10 | -------------------------------------------------------------------------------- /config/config-source/src/main/java/org/eclipse/microprofile12/config/configsource/EchoConfigSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 | * 4 | * Copyright (c) 2017-2018 Payara Foundation and/or its affiliates. All rights reserved. 5 | * 6 | * The contents of this file are subject to the terms of either the GNU 7 | * General Public License Version 2 only ("GPL") or the Common Development 8 | * and Distribution License("CDDL") (collectively, the "License"). You 9 | * may not use this file except in compliance with the License. You can 10 | * obtain a copy of the License at 11 | * https://github.com/payara/Payara/blob/master/LICENSE.txt 12 | * See the License for the specific 13 | * language governing permissions and limitations under the License. 14 | * 15 | * When distributing the software, include this License Header Notice in each 16 | * file and include the License file at glassfish/legal/LICENSE.txt. 17 | * 18 | * GPL Classpath Exception: 19 | * The Payara Foundation designates this particular file as subject to the "Classpath" 20 | * exception as provided by the Payara Foundation in the GPL Version 2 section of the License 21 | * file that accompanied this code. 22 | * 23 | * Modifications: 24 | * If applicable, add the following below the License Header, with the fields 25 | * enclosed by brackets [] replaced by your own identifying information: 26 | * "Portions Copyright [year] [name of copyright owner]" 27 | * 28 | * Contributor(s): 29 | * If you wish your version of this file to be governed by only the CDDL or 30 | * only the GPL Version 2, indicate your decision by adding "[Contributor] 31 | * elects to include this software in this distribution under the [CDDL or GPL 32 | * Version 2] license." If you don't indicate a single choice of license, a 33 | * recipient has the option to distribute your version of this file under 34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to 35 | * its licensees as provided above. However, if you add GPL Version 2 code 36 | * and therefore, elected the GPL Version 2 license, then the option applies 37 | * only if the new code is made subject to such option by the copyright 38 | * holder. 39 | */ 40 | package org.eclipse.microprofile12.config.configsource; 41 | 42 | import java.util.HashMap; 43 | import java.util.Map; 44 | 45 | import org.eclipse.microprofile.config.spi.ConfigSource; 46 | 47 | /** 48 | * 49 | * Example config source that echos back the input prepending the string "ECHO: " This config source 50 | * will resolve only property names that start with "echo." prefix, otherwise returns null. 51 | * 52 | *

53 | * Note: On Payara and WildFly this will function as a dynamic source, but on Liberty the protection 54 | * mandated by the spec to only handle declared property names is enforced. 55 | * 56 | * @author Steve Millidge (Payara Foundation) 57 | */ 58 | public class EchoConfigSource implements ConfigSource { 59 | 60 | @Override 61 | public Map getProperties() { 62 | Map properties = new HashMap<>(); 63 | properties.put("echo.property", getValue("echo.property")); 64 | return properties; 65 | } 66 | 67 | @Override 68 | public int getOrdinal() { 69 | return 10; 70 | } 71 | 72 | @Override 73 | public String getValue(String propertyName) { 74 | if (propertyName.startsWith("echo.")) { 75 | return "ECHO: " + propertyName; 76 | } 77 | 78 | return null; 79 | } 80 | 81 | @Override 82 | public String getName() { 83 | return "Echo"; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /config/config-source/src/main/java/org/eclipse/microprofile12/config/configsource/Servlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 | * 4 | * Copyright (c) 2017-2018 Payara Foundation and/or its affiliates. All rights reserved. 5 | * 6 | * The contents of this file are subject to the terms of either the GNU 7 | * General Public License Version 2 only ("GPL") or the Common Development 8 | * and Distribution License("CDDL") (collectively, the "License"). You 9 | * may not use this file except in compliance with the License. You can 10 | * obtain a copy of the License at 11 | * https://github.com/payara/Payara/blob/master/LICENSE.txt 12 | * See the License for the specific 13 | * language governing permissions and limitations under the License. 14 | * 15 | * When distributing the software, include this License Header Notice in each 16 | * file and include the License file at glassfish/legal/LICENSE.txt. 17 | * 18 | * GPL Classpath Exception: 19 | * The Payara Foundation designates this particular file as subject to the "Classpath" 20 | * exception as provided by the Payara Foundation in the GPL Version 2 section of the License 21 | * file that accompanied this code. 22 | * 23 | * Modifications: 24 | * If applicable, add the following below the License Header, with the fields 25 | * enclosed by brackets [] replaced by your own identifying information: 26 | * "Portions Copyright [year] [name of copyright owner]" 27 | * 28 | * Contributor(s): 29 | * If you wish your version of this file to be governed by only the CDDL or 30 | * only the GPL Version 2, indicate your decision by adding "[Contributor] 31 | * elects to include this software in this distribution under the [CDDL or GPL 32 | * Version 2] license." If you don't indicate a single choice of license, a 33 | * recipient has the option to distribute your version of this file under 34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to 35 | * its licensees as provided above. However, if you add GPL Version 2 code 36 | * and therefore, elected the GPL Version 2 license, then the option applies 37 | * only if the new code is made subject to such option by the copyright 38 | * holder. 39 | */ 40 | package org.eclipse.microprofile12.config.configsource; 41 | 42 | import java.io.IOException; 43 | 44 | import javax.inject.Inject; 45 | import javax.servlet.ServletException; 46 | import javax.servlet.annotation.WebServlet; 47 | import javax.servlet.http.HttpServlet; 48 | import javax.servlet.http.HttpServletRequest; 49 | import javax.servlet.http.HttpServletResponse; 50 | 51 | import org.eclipse.microprofile.config.inject.ConfigProperty; 52 | 53 | 54 | @WebServlet("/servlet") 55 | public class Servlet extends HttpServlet { 56 | 57 | private static final long serialVersionUID = 1L; 58 | 59 | @Inject 60 | @ConfigProperty(name = "echo.property", defaultValue = "Provided if EchoConfigSource disabled") 61 | private String propertyFromEchoConfigSource; 62 | 63 | @Override 64 | public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 65 | 66 | response.setContentType("text/plain"); 67 | 68 | response.getWriter().write( 69 | 70 | "echo.property : " + propertyFromEchoConfigSource); 71 | 72 | 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /config/config-source/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource: -------------------------------------------------------------------------------- 1 | org.eclipse.microprofile12.config.configsource.EchoConfigSource 2 | -------------------------------------------------------------------------------- /config/config-source/src/test/java/org/eclipse/microprofile12/config/configsource/ConfigSourceNotPresentTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.config.configsource; 2 | 3 | import static javax.ws.rs.client.ClientBuilder.newClient; 4 | import static javax.ws.rs.core.MediaType.TEXT_PLAIN; 5 | import static org.jboss.shrinkwrap.api.ShrinkWrap.create; 6 | import static org.junit.Assert.assertTrue; 7 | import static org.junit.Assert.assertFalse; 8 | 9 | import java.io.IOException; 10 | import java.net.URI; 11 | import java.net.URL; 12 | 13 | import org.jboss.arquillian.container.test.api.Deployment; 14 | import org.jboss.arquillian.container.test.api.RunAsClient; 15 | import org.jboss.arquillian.junit.Arquillian; 16 | import org.jboss.arquillian.test.api.ArquillianResource; 17 | import org.jboss.shrinkwrap.api.spec.WebArchive; 18 | import org.junit.Test; 19 | import org.junit.runner.RunWith; 20 | 21 | /** 22 | * @author Arjan Tijms 23 | */ 24 | @RunWith(Arquillian.class) 25 | public class ConfigSourceNotPresentTest { 26 | 27 | @ArquillianResource 28 | private URL base; 29 | 30 | @Deployment(testable = false) 31 | public static WebArchive createDeployment() { 32 | WebArchive archive = 33 | create(WebArchive.class, "ConfigSourceNotPresentTest.war") 34 | .addClasses( 35 | ApplicationInit.class, 36 | Servlet.class 37 | ) 38 | ; 39 | 40 | System.out.println("************************************************************"); 41 | System.out.println(archive.toString(true)); 42 | System.out.println("************************************************************"); 43 | 44 | return archive; 45 | } 46 | 47 | @Test 48 | @RunAsClient 49 | public void testConfigNotSourcePresent() throws IOException { 50 | 51 | String response = 52 | newClient() 53 | .target( 54 | URI.create(new URL(base, "servlet").toExternalForm())) 55 | .request(TEXT_PLAIN) 56 | .get(String.class); 57 | 58 | System.out.println("-------------------------------------------------------------------------"); 59 | System.out.println("Response: " + response); 60 | System.out.println("-------------------------------------------------------------------------"); 61 | 62 | assertFalse( 63 | response.contains("echo.property : ECHO: echo.property") 64 | ); 65 | 66 | assertTrue( 67 | response.contains("echo.property : Provided if EchoConfigSource disabled") 68 | ); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /config/config-source/src/test/java/org/eclipse/microprofile12/config/configsource/ConfigSourcePresentTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.config.configsource; 2 | 3 | import static javax.ws.rs.client.ClientBuilder.newClient; 4 | import static javax.ws.rs.core.MediaType.TEXT_PLAIN; 5 | import static org.jboss.shrinkwrap.api.ShrinkWrap.create; 6 | import static org.junit.Assert.assertTrue; 7 | 8 | import java.io.IOException; 9 | import java.net.URI; 10 | import java.net.URL; 11 | 12 | import org.jboss.arquillian.container.test.api.Deployment; 13 | import org.jboss.arquillian.container.test.api.RunAsClient; 14 | import org.jboss.arquillian.junit.Arquillian; 15 | import org.jboss.arquillian.test.api.ArquillianResource; 16 | import org.jboss.shrinkwrap.api.spec.WebArchive; 17 | import org.junit.Test; 18 | import org.junit.runner.RunWith; 19 | 20 | /** 21 | * @author Arjan Tijms 22 | */ 23 | @RunWith(Arquillian.class) 24 | public class ConfigSourcePresentTest { 25 | 26 | @ArquillianResource 27 | private URL base; 28 | 29 | @Deployment(testable = false) 30 | public static WebArchive createDeployment() { 31 | WebArchive archive = 32 | create(WebArchive.class, "ConfigSourcePresentTest.war") 33 | .addClasses( 34 | ApplicationInit.class, 35 | EchoConfigSource.class, 36 | Servlet.class 37 | ).addAsResource( 38 | "META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource" 39 | ) 40 | ; 41 | 42 | System.out.println("************************************************************"); 43 | System.out.println(archive.toString(true)); 44 | System.out.println("************************************************************"); 45 | 46 | return archive; 47 | } 48 | 49 | @Test 50 | @RunAsClient 51 | public void testConfigSourcePresent() throws IOException { 52 | 53 | String response = 54 | newClient() 55 | .target( 56 | URI.create(new URL(base, "servlet").toExternalForm())) 57 | .request(TEXT_PLAIN) 58 | .get(String.class); 59 | 60 | System.out.println("-------------------------------------------------------------------------"); 61 | System.out.println("Response: " + response); 62 | System.out.println("-------------------------------------------------------------------------"); 63 | 64 | assertTrue( 65 | response.contains("echo.property : ECHO: echo.property") 66 | ); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /config/converter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | org.eclipse.microprofile.samples12 6 | config 7 | 1.0-SNAPSHOT 8 | 9 | 10 | converter 11 | war 12 | MicroProfile 1.2: Config - Converter 13 | 14 | 15 | -------------------------------------------------------------------------------- /config/converter/src/main/java/org/eclipse/microprofile12/config/converter/ApplicationInit.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.config.converter; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | 5 | @ApplicationScoped 6 | public class ApplicationInit { 7 | 8 | 9 | } 10 | -------------------------------------------------------------------------------- /config/converter/src/main/java/org/eclipse/microprofile12/config/converter/CustomConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 | * 4 | * Copyright (c) 2017-2018 Payara Foundation and/or its affiliates. All rights reserved. 5 | * 6 | * The contents of this file are subject to the terms of either the GNU 7 | * General Public License Version 2 only ("GPL") or the Common Development 8 | * and Distribution License("CDDL") (collectively, the "License"). You 9 | * may not use this file except in compliance with the License. You can 10 | * obtain a copy of the License at 11 | * https://github.com/payara/Payara/blob/master/LICENSE.txt 12 | * See the License for the specific 13 | * language governing permissions and limitations under the License. 14 | * 15 | * When distributing the software, include this License Header Notice in each 16 | * file and include the License file at glassfish/legal/LICENSE.txt. 17 | * 18 | * GPL Classpath Exception: 19 | * The Payara Foundation designates this particular file as subject to the "Classpath" 20 | * exception as provided by the Payara Foundation in the GPL Version 2 section of the License 21 | * file that accompanied this code. 22 | * 23 | * Modifications: 24 | * If applicable, add the following below the License Header, with the fields 25 | * enclosed by brackets [] replaced by your own identifying information: 26 | * "Portions Copyright [year] [name of copyright owner]" 27 | * 28 | * Contributor(s): 29 | * If you wish your version of this file to be governed by only the CDDL or 30 | * only the GPL Version 2, indicate your decision by adding "[Contributor] 31 | * elects to include this software in this distribution under the [CDDL or GPL 32 | * Version 2] license." If you don't indicate a single choice of license, a 33 | * recipient has the option to distribute your version of this file under 34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to 35 | * its licensees as provided above. However, if you add GPL Version 2 code 36 | * and therefore, elected the GPL Version 2 license, then the option applies 37 | * only if the new code is made subject to such option by the copyright 38 | * holder. 39 | */ 40 | package org.eclipse.microprofile12.config.converter; 41 | 42 | import org.eclipse.microprofile.config.spi.Converter; 43 | 44 | /** 45 | * Example Custom Converter that wraps the value in a TestPojo object 46 | * 47 | * @author Steve Millidge (Payara Foundation) 48 | */ 49 | public class CustomConverter implements Converter { 50 | 51 | @Override 52 | public TestPojo convert(String value) { 53 | TestPojo result = new TestPojo(); 54 | result.value = value; 55 | return result; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /config/converter/src/main/java/org/eclipse/microprofile12/config/converter/Servlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 | * 4 | * Copyright (c) 2017-2018 Payara Foundation and/or its affiliates. All rights reserved. 5 | * 6 | * The contents of this file are subject to the terms of either the GNU 7 | * General Public License Version 2 only ("GPL") or the Common Development 8 | * and Distribution License("CDDL") (collectively, the "License"). You 9 | * may not use this file except in compliance with the License. You can 10 | * obtain a copy of the License at 11 | * https://github.com/payara/Payara/blob/master/LICENSE.txt 12 | * See the License for the specific 13 | * language governing permissions and limitations under the License. 14 | * 15 | * When distributing the software, include this License Header Notice in each 16 | * file and include the License file at glassfish/legal/LICENSE.txt. 17 | * 18 | * GPL Classpath Exception: 19 | * The Payara Foundation designates this particular file as subject to the "Classpath" 20 | * exception as provided by the Payara Foundation in the GPL Version 2 section of the License 21 | * file that accompanied this code. 22 | * 23 | * Modifications: 24 | * If applicable, add the following below the License Header, with the fields 25 | * enclosed by brackets [] replaced by your own identifying information: 26 | * "Portions Copyright [year] [name of copyright owner]" 27 | * 28 | * Contributor(s): 29 | * If you wish your version of this file to be governed by only the CDDL or 30 | * only the GPL Version 2, indicate your decision by adding "[Contributor] 31 | * elects to include this software in this distribution under the [CDDL or GPL 32 | * Version 2] license." If you don't indicate a single choice of license, a 33 | * recipient has the option to distribute your version of this file under 34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to 35 | * its licensees as provided above. However, if you add GPL Version 2 code 36 | * and therefore, elected the GPL Version 2 license, then the option applies 37 | * only if the new code is made subject to such option by the copyright 38 | * holder. 39 | */ 40 | package org.eclipse.microprofile12.config.converter; 41 | 42 | import java.io.IOException; 43 | 44 | import javax.inject.Inject; 45 | import javax.servlet.ServletException; 46 | import javax.servlet.annotation.WebServlet; 47 | import javax.servlet.http.HttpServlet; 48 | import javax.servlet.http.HttpServletRequest; 49 | import javax.servlet.http.HttpServletResponse; 50 | 51 | import org.eclipse.microprofile.config.inject.ConfigProperty; 52 | 53 | @WebServlet("/servlet") 54 | public class Servlet extends HttpServlet { 55 | 56 | private static final long serialVersionUID = 1L; 57 | 58 | /* 59 | * Example of injecting a value of an arbitrary type using a custom converter. TestPojo types are 60 | * converted using CustomConverter,java, which is registered via a service locator file 61 | */ 62 | @Inject 63 | @ConfigProperty(name = "pojo.value") 64 | private TestPojo pojo; 65 | 66 | @Override 67 | public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 68 | response.setContentType("text/plain"); 69 | response.getWriter().write("pojo.value : " + pojo); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /config/converter/src/main/java/org/eclipse/microprofile12/config/converter/TestPojo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 | * 4 | * Copyright (c) 2017-2018 Payara Foundation and/or its affiliates. All rights reserved. 5 | * 6 | * The contents of this file are subject to the terms of either the GNU 7 | * General Public License Version 2 only ("GPL") or the Common Development 8 | * and Distribution License("CDDL") (collectively, the "License"). You 9 | * may not use this file except in compliance with the License. You can 10 | * obtain a copy of the License at 11 | * https://github.com/payara/Payara/blob/master/LICENSE.txt 12 | * See the License for the specific 13 | * language governing permissions and limitations under the License. 14 | * 15 | * When distributing the software, include this License Header Notice in each 16 | * file and include the License file at glassfish/legal/LICENSE.txt. 17 | * 18 | * GPL Classpath Exception: 19 | * The Payara Foundation designates this particular file as subject to the "Classpath" 20 | * exception as provided by the Payara Foundation in the GPL Version 2 section of the License 21 | * file that accompanied this code. 22 | * 23 | * Modifications: 24 | * If applicable, add the following below the License Header, with the fields 25 | * enclosed by brackets [] replaced by your own identifying information: 26 | * "Portions Copyright [year] [name of copyright owner]" 27 | * 28 | * Contributor(s): 29 | * If you wish your version of this file to be governed by only the CDDL or 30 | * only the GPL Version 2, indicate your decision by adding "[Contributor] 31 | * elects to include this software in this distribution under the [CDDL or GPL 32 | * Version 2] license." If you don't indicate a single choice of license, a 33 | * recipient has the option to distribute your version of this file under 34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to 35 | * its licensees as provided above. However, if you add GPL Version 2 code 36 | * and therefore, elected the GPL Version 2 license, then the option applies 37 | * only if the new code is made subject to such option by the copyright 38 | * holder. 39 | */ 40 | package org.eclipse.microprofile12.config.converter; 41 | 42 | /** 43 | * 44 | * @author Steve Millidge (Payara Foundation) 45 | */ 46 | public class TestPojo { 47 | 48 | public String value; 49 | 50 | @Override 51 | public String toString() { 52 | return "TestPojo{" + "value=" + value + '}'; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /config/converter/src/main/resources/META-INF/microprofile-config.properties: -------------------------------------------------------------------------------- 1 | # Example application properties file 2 | pojo.value=Value for Test Pojo 3 | -------------------------------------------------------------------------------- /config/converter/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.Converter: -------------------------------------------------------------------------------- 1 | org.eclipse.microprofile12.config.converter.CustomConverter 2 | -------------------------------------------------------------------------------- /config/converter/src/test/java/org/eclipse/microprofile12/config/converter/ConverterTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.config.converter; 2 | 3 | import static javax.ws.rs.client.ClientBuilder.newClient; 4 | import static javax.ws.rs.core.MediaType.TEXT_PLAIN; 5 | import static org.jboss.shrinkwrap.api.ShrinkWrap.create; 6 | import static org.junit.Assert.assertTrue; 7 | 8 | import java.io.IOException; 9 | import java.net.URI; 10 | import java.net.URL; 11 | 12 | import org.jboss.arquillian.container.test.api.Deployment; 13 | import org.jboss.arquillian.container.test.api.RunAsClient; 14 | import org.jboss.arquillian.junit.Arquillian; 15 | import org.jboss.arquillian.test.api.ArquillianResource; 16 | import org.jboss.shrinkwrap.api.spec.WebArchive; 17 | import org.junit.Test; 18 | import org.junit.runner.RunWith; 19 | 20 | /** 21 | * @author Arjan Tijms 22 | */ 23 | @RunWith(Arquillian.class) 24 | public class ConverterTest { 25 | 26 | @ArquillianResource 27 | private URL base; 28 | 29 | @Deployment(testable = false) 30 | public static WebArchive createDeployment() { 31 | WebArchive archive = 32 | create(WebArchive.class) 33 | .addClasses( 34 | ApplicationInit.class, 35 | CustomConverter.class, 36 | Servlet.class, 37 | TestPojo.class 38 | ).addAsResource( 39 | "META-INF/services/org.eclipse.microprofile.config.spi.Converter" 40 | ).addAsResource( 41 | "META-INF/microprofile-config.properties" 42 | ) 43 | ; 44 | 45 | System.out.println("************************************************************"); 46 | System.out.println(archive.toString(true)); 47 | System.out.println("************************************************************"); 48 | 49 | return archive; 50 | } 51 | 52 | @Test 53 | @RunAsClient 54 | public void testConverter() throws IOException { 55 | 56 | String response = 57 | newClient() 58 | .target( 59 | URI.create(new URL(base, "servlet").toExternalForm())) 60 | .request(TEXT_PLAIN) 61 | .get(String.class); 62 | 63 | System.out.println("-------------------------------------------------------------------------"); 64 | System.out.println("Response: " + response); 65 | System.out.println("-------------------------------------------------------------------------"); 66 | 67 | assertTrue( 68 | response.contains("pojo.value : TestPojo{value=Value for Test Pojo}") 69 | ); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /config/default-conversion/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | org.eclipse.microprofile.samples12 6 | config 7 | 1.0-SNAPSHOT 8 | 9 | 10 | default-conversion 11 | war 12 | MicroProfile 1.2: Config - Default Conversion 13 | 14 | 15 | -------------------------------------------------------------------------------- /config/default-conversion/src/main/java/org/eclipse/microprofile12/config/defaultconversion/ApplicationInit.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.config.defaultconversion; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | 5 | @ApplicationScoped 6 | public class ApplicationInit { 7 | 8 | 9 | } 10 | -------------------------------------------------------------------------------- /config/default-conversion/src/main/java/org/eclipse/microprofile12/config/defaultconversion/Servlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 | * 4 | * Copyright (c) 2017-2018 Payara Foundation and/or its affiliates. All rights reserved. 5 | * 6 | * The contents of this file are subject to the terms of either the GNU 7 | * General Public License Version 2 only ("GPL") or the Common Development 8 | * and Distribution License("CDDL") (collectively, the "License"). You 9 | * may not use this file except in compliance with the License. You can 10 | * obtain a copy of the License at 11 | * https://github.com/payara/Payara/blob/master/LICENSE.txt 12 | * See the License for the specific 13 | * language governing permissions and limitations under the License. 14 | * 15 | * When distributing the software, include this License Header Notice in each 16 | * file and include the License file at glassfish/legal/LICENSE.txt. 17 | * 18 | * GPL Classpath Exception: 19 | * The Payara Foundation designates this particular file as subject to the "Classpath" 20 | * exception as provided by the Payara Foundation in the GPL Version 2 section of the License 21 | * file that accompanied this code. 22 | * 23 | * Modifications: 24 | * If applicable, add the following below the License Header, with the fields 25 | * enclosed by brackets [] replaced by your own identifying information: 26 | * "Portions Copyright [year] [name of copyright owner]" 27 | * 28 | * Contributor(s): 29 | * If you wish your version of this file to be governed by only the CDDL or 30 | * only the GPL Version 2, indicate your decision by adding "[Contributor] 31 | * elects to include this software in this distribution under the [CDDL or GPL 32 | * Version 2] license." If you don't indicate a single choice of license, a 33 | * recipient has the option to distribute your version of this file under 34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to 35 | * its licensees as provided above. However, if you add GPL Version 2 code 36 | * and therefore, elected the GPL Version 2 license, then the option applies 37 | * only if the new code is made subject to such option by the copyright 38 | * holder. 39 | */ 40 | package org.eclipse.microprofile12.config.defaultconversion; 41 | 42 | import java.io.IOException; 43 | import java.time.LocalDate; 44 | 45 | import javax.inject.Inject; 46 | import javax.servlet.ServletException; 47 | import javax.servlet.annotation.WebServlet; 48 | import javax.servlet.http.HttpServlet; 49 | import javax.servlet.http.HttpServletRequest; 50 | import javax.servlet.http.HttpServletResponse; 51 | 52 | import org.eclipse.microprofile.config.inject.ConfigProperty; 53 | 54 | @WebServlet("/servlet") 55 | public class Servlet extends HttpServlet { 56 | 57 | private static final long serialVersionUID = 1L; 58 | 59 | // Example config property that uses a default converter to LocalDate 60 | @Inject 61 | @ConfigProperty(name = "date.property") 62 | private LocalDate date; 63 | 64 | @Override 65 | public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 66 | response.setContentType("text/plain"); 67 | response.getWriter().write("date.property : " + date + "\n"); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /config/default-conversion/src/main/resources/META-INF/microprofile-config.properties: -------------------------------------------------------------------------------- 1 | # Example application properties file 2 | date.property=2000-01-01 3 | -------------------------------------------------------------------------------- /config/default-conversion/src/test/java/org/eclipse/microprofile12/config/defaultconversion/DefaultConversionTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.config.defaultconversion; 2 | 3 | import static javax.ws.rs.client.ClientBuilder.newClient; 4 | import static javax.ws.rs.core.MediaType.TEXT_PLAIN; 5 | import static org.jboss.shrinkwrap.api.ShrinkWrap.create; 6 | import static org.junit.Assert.assertTrue; 7 | 8 | import java.io.IOException; 9 | import java.net.URI; 10 | import java.net.URL; 11 | 12 | import org.eclipse.microprofile12.config.defaultconversion.ApplicationInit; 13 | import org.eclipse.microprofile12.config.defaultconversion.Servlet; 14 | import org.jboss.arquillian.container.test.api.Deployment; 15 | import org.jboss.arquillian.container.test.api.RunAsClient; 16 | import org.jboss.arquillian.junit.Arquillian; 17 | import org.jboss.arquillian.test.api.ArquillianResource; 18 | import org.jboss.shrinkwrap.api.spec.WebArchive; 19 | import org.junit.Test; 20 | import org.junit.runner.RunWith; 21 | 22 | /** 23 | * @author Arjan Tijms 24 | */ 25 | @RunWith(Arquillian.class) 26 | public class DefaultConversionTest { 27 | 28 | @ArquillianResource 29 | private URL base; 30 | 31 | @Deployment(testable = false) 32 | public static WebArchive createDeployment() { 33 | WebArchive archive = 34 | create(WebArchive.class) 35 | .addClasses( 36 | ApplicationInit.class, 37 | Servlet.class 38 | ).addAsResource( 39 | "META-INF/microprofile-config.properties" 40 | ) 41 | ; 42 | 43 | System.out.println("************************************************************"); 44 | System.out.println(archive.toString(true)); 45 | System.out.println("************************************************************"); 46 | 47 | return archive; 48 | } 49 | 50 | @Test 51 | @RunAsClient 52 | public void testDefaultConversion() throws IOException { 53 | 54 | String response = 55 | newClient() 56 | .target( 57 | URI.create(new URL(base, "servlet").toExternalForm())) 58 | .request(TEXT_PLAIN) 59 | .get(String.class); 60 | 61 | System.out.println("-------------------------------------------------------------------------"); 62 | System.out.println("Response: " + response); 63 | System.out.println("-------------------------------------------------------------------------"); 64 | 65 | assertTrue( 66 | response.contains("date.property : 2000-01-01") 67 | ); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /config/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | org.eclipse.microprofile.samples12 6 | samples-parent 7 | 1.0-SNAPSHOT 8 | 9 | 10 | config 11 | pom 12 | 13 | MicroProfile 1.2: Config 14 | 15 | 16 | basic-injection 17 | config-source 18 | converter 19 | default-conversion 20 | 21 | 22 | 23 | 24 | org.eclipse.microprofile.samples12 25 | test-utils 26 | ${project.version} 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /fault-tolerance/README.md: -------------------------------------------------------------------------------- 1 | # Eclipse MicroProfile 1.2 Samples - Fault Tolerance 2 | 3 | - [Wiki project page](https://wiki.eclipse.org/MicroProfile/Fault_Tolerance) 4 | - [Spec, API, TCK GitHub repo](https://github.com/eclipse/microprofile-fault-tolerance) 5 | 6 | ## Samples ## 7 | 8 | - **asynchronous** Demonstrates a CDI version of the EJB @Asynchronous annotation 9 | - **bulkhead** 10 | - **fallback** 11 | - **retry** 12 | - **timeout** 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /fault-tolerance/asynchronous/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | org.eclipse.microprofile.samples12 6 | fault-tolerance 7 | 1.0-SNAPSHOT 8 | 9 | 10 | asynchronous 11 | war 12 | MicroProfile 1.2: Fault Tolerance - Asynchronous 13 | 14 | 15 | -------------------------------------------------------------------------------- /fault-tolerance/asynchronous/src/main/java/org/eclipse/microprofile12/faulttolerance/asynchronous/MyAsyncBeanClassLevel.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.faulttolerance.asynchronous; 2 | 3 | import static java.lang.Thread.sleep; 4 | import static java.util.concurrent.CompletableFuture.completedFuture; 5 | 6 | import java.util.concurrent.Future; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | 10 | import javax.enterprise.context.ApplicationScoped; 11 | 12 | import org.eclipse.microprofile.faulttolerance.Asynchronous; 13 | 14 | /** 15 | * @author Arun Gupta 16 | * @author Arjan Tijms 17 | */ 18 | @Asynchronous 19 | @ApplicationScoped 20 | public class MyAsyncBeanClassLevel { 21 | 22 | public static final long AWAIT = 3000; 23 | 24 | public Future addNumbers(int n1, int n2) { 25 | try { 26 | // simulating a long running query 27 | sleep(AWAIT); 28 | } catch (InterruptedException ex) { 29 | Logger.getLogger(MyAsyncBeanClassLevel.class.getName()).log(Level.SEVERE, null, ex); 30 | } 31 | 32 | return completedFuture(n1 + n2); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /fault-tolerance/asynchronous/src/main/java/org/eclipse/microprofile12/faulttolerance/asynchronous/MyAsyncBeanMethodLevel.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.faulttolerance.asynchronous; 2 | 3 | import static java.lang.Thread.sleep; 4 | import static java.util.concurrent.CompletableFuture.completedFuture; 5 | import static java.util.logging.Level.SEVERE; 6 | 7 | import java.util.concurrent.Future; 8 | import java.util.logging.Logger; 9 | 10 | import javax.enterprise.context.ApplicationScoped; 11 | 12 | import org.eclipse.microprofile.faulttolerance.Asynchronous; 13 | 14 | /** 15 | * @author Arun Gupta 16 | * @author Arjan Tijms 17 | */ 18 | @ApplicationScoped 19 | public class MyAsyncBeanMethodLevel { 20 | 21 | public static final long AWAIT = 3000; 22 | 23 | @Asynchronous 24 | public Future addNumbers(int n1, int n2) { 25 | try { 26 | // Simulating a long running query 27 | sleep(AWAIT); 28 | } catch (InterruptedException ex) { 29 | Logger.getLogger(MyAsyncBeanMethodLevel.class.getName()).log(SEVERE, null, ex); 30 | } 31 | 32 | return completedFuture(n1 + n2); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /fault-tolerance/asynchronous/src/main/resources/project-defaults.yml: -------------------------------------------------------------------------------- 1 | swarm: 2 | hystrix: 3 | command: 4 | default: 5 | execution: 6 | isolation: 7 | thread: 8 | timeoutInMilliseconds: 3500 #MORE THAN MyAsyncBean*Level.AWAIT CONFIGURED IN TESTS 9 | -------------------------------------------------------------------------------- /fault-tolerance/asynchronous/src/test/java/org/eclipse/microprofile12/faulttolerance/asynchronous/AsyncClassBeanTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.faulttolerance.asynchronous; 2 | 3 | import static com.jayway.awaitility.Awaitility.await; 4 | import static java.lang.System.currentTimeMillis; 5 | import static org.eclipse.microprofile12.Libraries.awaitability; 6 | import static org.hamcrest.MatcherAssert.assertThat; 7 | import static org.hamcrest.Matchers.equalTo; 8 | import static org.hamcrest.Matchers.is; 9 | import static org.hamcrest.Matchers.lessThan; 10 | import static org.jboss.shrinkwrap.api.ShrinkWrap.create; 11 | 12 | import java.util.concurrent.ExecutionException; 13 | import java.util.concurrent.Future; 14 | 15 | import javax.inject.Inject; 16 | 17 | import org.jboss.arquillian.container.test.api.Deployment; 18 | import org.jboss.arquillian.junit.Arquillian; 19 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 20 | import org.jboss.shrinkwrap.api.spec.WebArchive; 21 | import org.junit.Test; 22 | import org.junit.runner.RunWith; 23 | 24 | /** 25 | * @author Jakub Marchwicki 26 | * @author Arjan Tijms 27 | */ 28 | @RunWith(Arquillian.class) 29 | public class AsyncClassBeanTest { 30 | 31 | @Inject 32 | private MyAsyncBeanClassLevel bean; 33 | 34 | @Deployment 35 | public static WebArchive createDeployment() { 36 | return create(WebArchive.class) 37 | .addAsLibraries(awaitability()) 38 | .addClasses(MyAsyncBeanClassLevel.class) 39 | .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml") 40 | .addAsResource("project-defaults.yml"); 41 | } 42 | 43 | @Test 44 | public void shouldReturnAsyncSum() throws ExecutionException, InterruptedException { 45 | Integer numberOne = 5; 46 | Integer numberTwo = 10; 47 | 48 | long start = currentTimeMillis(); 49 | Future resultFuture = bean.addNumbers(numberOne, numberTwo); 50 | 51 | assertThat(resultFuture.isDone(), is(equalTo(false))); 52 | assertThat(currentTimeMillis() - start, is(lessThan(MyAsyncBeanMethodLevel.AWAIT))); 53 | 54 | await().until(() -> resultFuture.isDone()); 55 | 56 | assertThat(resultFuture.get(), is(equalTo(numberOne + numberTwo))); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /fault-tolerance/asynchronous/src/test/java/org/eclipse/microprofile12/faulttolerance/asynchronous/AsyncMethodBeanTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.faulttolerance.asynchronous; 2 | 3 | import static com.jayway.awaitility.Awaitility.await; 4 | import static java.lang.System.currentTimeMillis; 5 | import static org.eclipse.microprofile12.Libraries.awaitability; 6 | import static org.hamcrest.MatcherAssert.assertThat; 7 | import static org.hamcrest.Matchers.equalTo; 8 | import static org.hamcrest.Matchers.is; 9 | import static org.hamcrest.Matchers.lessThan; 10 | import static org.jboss.shrinkwrap.api.ShrinkWrap.create; 11 | 12 | import java.util.concurrent.ExecutionException; 13 | import java.util.concurrent.Future; 14 | 15 | import javax.inject.Inject; 16 | 17 | import org.jboss.arquillian.container.test.api.Deployment; 18 | import org.jboss.arquillian.junit.Arquillian; 19 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 20 | import org.jboss.shrinkwrap.api.spec.WebArchive; 21 | import org.junit.Test; 22 | import org.junit.runner.RunWith; 23 | 24 | /** 25 | * @author Jakub Marchwicki 26 | * @author Arjan Tijms 27 | */ 28 | @RunWith(Arquillian.class) 29 | public class AsyncMethodBeanTest { 30 | 31 | @Inject 32 | private MyAsyncBeanMethodLevel bean; 33 | 34 | @Deployment 35 | public static WebArchive createDeployment() { 36 | return create(WebArchive.class) 37 | .addAsLibraries(awaitability()) 38 | .addClasses(MyAsyncBeanMethodLevel.class) 39 | .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml") 40 | .addAsResource("project-defaults.yml"); 41 | } 42 | 43 | @Test // Runs on Server 44 | public void shouldReturnAsyncSum() throws ExecutionException, InterruptedException { 45 | Integer numberOne = 5; 46 | Integer numberTwo = 10; 47 | 48 | long start = currentTimeMillis(); 49 | Future resultFuture = bean.addNumbers(numberOne, numberTwo); 50 | 51 | assertThat(resultFuture.isDone(), is(equalTo(false))); 52 | assertThat(currentTimeMillis() - start, is(lessThan(MyAsyncBeanMethodLevel.AWAIT))); 53 | 54 | await().until(() -> resultFuture.isDone()); 55 | 56 | assertThat(resultFuture.get(), is(equalTo(numberOne + numberTwo))); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /fault-tolerance/bulkhead/micro-pre-boot-commands.txt: -------------------------------------------------------------------------------- 1 | set resources.managed-executor-service.concurrent/__defaultManagedExecutorService.core-pool-size=0 2 | set resources.managed-executor-service.concurrent/__defaultManagedExecutorService.hung-after-seconds=0 3 | set resources.managed-executor-service.concurrent/__defaultManagedExecutorService.keep-alive-seconds=60 4 | set resources.managed-executor-service.concurrent/__defaultManagedExecutorService.long-running-tasks=false 5 | set resources.managed-executor-service.concurrent/__defaultManagedExecutorService.task-queue-capacity=2147483647 6 | set resources.managed-executor-service.concurrent/__defaultManagedExecutorService.maximum-pool-size=2147483647 7 | set resources.managed-scheduled-executor-service.concurrent/__defaultManagedScheduledExecutorService.core-pool-size=0 8 | set resources.managed-scheduled-executor-service.concurrent/__defaultManagedScheduledExecutorService.long-running-tasks=false 9 | set resources.managed-scheduled-executor-service.concurrent/__defaultManagedScheduledExecutorService.keep-alive-seconds=60 10 | set resources.managed-scheduled-executor-service.concurrent/__defaultManagedScheduledExecutorService.hung-after-seconds=0 11 | 12 | -------------------------------------------------------------------------------- /fault-tolerance/bulkhead/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.eclipse.microprofile.samples12 6 | fault-tolerance 7 | 1.0-SNAPSHOT 8 | 9 | 10 | bulkhead 11 | war 12 | 13 | MicroProfile 1.2: Fault Tolerance - Bulkhead 14 | 15 | 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-surefire-plugin 20 | 21 | 22 | --prebootcommandfile ${basedir}/micro-pre-boot-commands.txt 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /fault-tolerance/bulkhead/src/main/java/org/eclipse/microprofile/samples12/bulkhead/AsynchronousBulkheadBean.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.bulkhead; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | import java.util.concurrent.Future; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | import javax.enterprise.context.ApplicationScoped; 8 | import org.eclipse.microprofile.faulttolerance.Asynchronous; 9 | import org.eclipse.microprofile.faulttolerance.Bulkhead; 10 | 11 | /** 12 | * A Bean with both a Bulkhead and Asynchronous annotation applied. This combination means that the Bulkhead will allow 13 | * a specified number of tasks to queue for execution. 14 | * @author Andrew Pielage 15 | */ 16 | @Asynchronous 17 | @Bulkhead(value = 3, waitingTaskQueue = 5) 18 | @ApplicationScoped 19 | public class AsynchronousBulkheadBean { 20 | 21 | public static final long AWAIT = 3000; 22 | 23 | /** 24 | * Example method that simulates a long running task. 25 | * @return 26 | */ 27 | public Future method1() { 28 | try { 29 | // Simulate a long running query 30 | Thread.sleep(AWAIT); 31 | } catch (InterruptedException ex) { 32 | Logger.getLogger(AsynchronousBulkheadBean.class.getName()).log(Level.SEVERE, null, ex); 33 | } 34 | 35 | return CompletableFuture.completedFuture("Wibbles"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /fault-tolerance/bulkhead/src/main/java/org/eclipse/microprofile/samples12/bulkhead/ClassLevelBulkheadBean.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.bulkhead; 2 | 3 | import java.util.logging.Level; 4 | import java.util.logging.Logger; 5 | import javax.enterprise.context.ApplicationScoped; 6 | import org.eclipse.microprofile.faulttolerance.Bulkhead; 7 | 8 | /** 9 | * A Bean with a Bulkhead applied at the class level with default values. The Bulkhead will be applied to 10 | * every method in this class, only allowing 10 threads to access them (individually - they do not share 11 | * bulkhead tokens) concurrently, with no queueing allowed. 12 | * @author Andrew Pielage 13 | */ 14 | @Bulkhead 15 | @ApplicationScoped 16 | public class ClassLevelBulkheadBean { 17 | 18 | public static final long AWAIT = 3000; 19 | 20 | /** 21 | * Example method that simulates a long running query 22 | */ 23 | public void method1() { 24 | try { 25 | // Simulate a long running query 26 | Thread.sleep(AWAIT); 27 | } catch (InterruptedException ex) { 28 | Logger.getLogger(ClassLevelBulkheadBean.class.getName()).log(Level.SEVERE, null, ex); 29 | } 30 | } 31 | 32 | /** 33 | * Example method that simulates a long running query 34 | */ 35 | public void method2() { 36 | try { 37 | // Simulate a long running query 38 | Thread.sleep(AWAIT); 39 | } catch (InterruptedException ex) { 40 | Logger.getLogger(ClassLevelBulkheadBean.class.getName()).log(Level.SEVERE, null, ex); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /fault-tolerance/bulkhead/src/main/java/org/eclipse/microprofile/samples12/bulkhead/MethodLevelBulkheadBean.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.bulkhead; 2 | 3 | import java.util.logging.Level; 4 | import java.util.logging.Logger; 5 | import javax.enterprise.context.ApplicationScoped; 6 | import org.eclipse.microprofile.faulttolerance.Bulkhead; 7 | 8 | /** 9 | * A Bean with a Bulkhead applied at the method level, demonstrating how you can specify different bulkhead values for 10 | * each method. 11 | * @author Andrew Pielage 12 | */ 13 | @ApplicationScoped 14 | public class MethodLevelBulkheadBean { 15 | 16 | public static final long AWAIT = 3000; 17 | 18 | /** 19 | * Example method that simulates a long running query 20 | */ 21 | @Bulkhead(5) 22 | public void method1() { 23 | try { 24 | // Simulate a long running query 25 | Thread.sleep(AWAIT); 26 | } catch (InterruptedException ex) { 27 | Logger.getLogger(ClassLevelBulkheadBean.class.getName()).log(Level.SEVERE, null, ex); 28 | } 29 | } 30 | 31 | /** 32 | * Example method that simulates a long running query with its own bulkhead. 33 | */ 34 | @Bulkhead(3) 35 | public void method2() { 36 | try { 37 | // Simulate a long running query 38 | Thread.sleep(AWAIT); 39 | } catch (InterruptedException ex) { 40 | Logger.getLogger(ClassLevelBulkheadBean.class.getName()).log(Level.SEVERE, null, ex); 41 | } 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /fault-tolerance/bulkhead/src/main/resources/project-defaults.yml: -------------------------------------------------------------------------------- 1 | swarm: 2 | hystrix: 3 | threadpool: 4 | default: 5 | maximumSize: 10 #SHOULD BE >= AsynchronousBulkheadBean @Bulkead value + @Bulkhead waitingTaskQueue 6 | allowMaximumSizeToDivergeFromCoreSize: true 7 | command: 8 | default: 9 | execution: 10 | isolation: 11 | thread: 12 | timeoutInMilliseconds: 21500 #MORE THAN (AsynchronousBulkheadBean @Bulkead value + @Bulkhead waitingTaskQueue -1) * AsynchronousBulkheadBean.AWAIT 13 | -------------------------------------------------------------------------------- /fault-tolerance/bulkhead/src/test/java/org/eclipse/microprofile12/faulttolerance/bulkhead/AsynchronousBulkheadBeanTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.faulttolerance.bulkhead; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.ExecutionException; 6 | import java.util.concurrent.Future; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | import javax.inject.Inject; 10 | import org.eclipse.microprofile.faulttolerance.Bulkhead; 11 | import org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException; 12 | import org.eclipse.microprofile.samples12.bulkhead.AsynchronousBulkheadBean; 13 | import org.jboss.arquillian.container.test.api.Deployment; 14 | import org.jboss.arquillian.junit.Arquillian; 15 | import org.jboss.shrinkwrap.api.ShrinkWrap; 16 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 17 | import org.jboss.shrinkwrap.api.spec.WebArchive; 18 | import org.junit.Assert; 19 | import org.junit.Test; 20 | import org.junit.runner.RunWith; 21 | 22 | /** 23 | * Test class for the AsynchronousBulkheadBean class. 24 | * @author Andrew Pielage 25 | */ 26 | @RunWith(Arquillian.class) 27 | public class AsynchronousBulkheadBeanTest { 28 | 29 | @Inject 30 | AsynchronousBulkheadBean asynchronousBulkheadBean; 31 | 32 | @Deployment 33 | public static WebArchive createDeployment() { 34 | return ShrinkWrap.create(WebArchive.class) 35 | .addClasses(AsynchronousBulkheadBean.class) 36 | .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml") 37 | .addAsResource("project-defaults.yml"); 38 | } 39 | 40 | /** 41 | * Test that the bulkhead begins queueing task if more than the maximum number of threads are executing concurrently. 42 | * @throws NoSuchMethodException 43 | */ 44 | @Test 45 | public void bulkheadQueueTest() throws NoSuchMethodException { 46 | int numberOfExpectedFailures = 0; 47 | 48 | // Kick off more tasks than the bulkhead value, but less than the combined total, causing the bulkhead to block 49 | // and start queuing 50 | int numberOfTasks = AsynchronousBulkheadBean.class.getAnnotation(Bulkhead.class).value() 51 | + AsynchronousBulkheadBean.class.getAnnotation(Bulkhead.class).waitingTaskQueue() 52 | - 1; 53 | 54 | List> futures = new ArrayList<>(); 55 | for (int i = 0; i < numberOfTasks; i++) { 56 | futures.add(asynchronousBulkheadBean.method1()); 57 | } 58 | 59 | // Await and collect results to make sure everything has completed or thrown an exception 60 | int failures = 0; 61 | for (Future future : futures) { 62 | try { 63 | future.get(); 64 | } catch (InterruptedException ie) { 65 | Logger.getLogger(AsynchronousBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ie); 66 | Assert.fail("Got an unexpected InterruptedException"); 67 | } catch (ExecutionException ex) { 68 | Logger.getLogger(AsynchronousBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ex); 69 | Assert.fail("Got an unexpected ExecutionException"); 70 | } catch (BulkheadException be) { 71 | failures ++; 72 | } 73 | } 74 | 75 | // numberOfExpectedFailures tasks should fail 76 | Assert.assertTrue("Did not get " + numberOfExpectedFailures + ": " + failures, 77 | failures == numberOfExpectedFailures); 78 | } 79 | 80 | /** 81 | * Test that when the bulkhead queue is full, errors start to get thrown. 82 | * @throws NoSuchMethodException 83 | */ 84 | @Test 85 | public void bulkheadLimitTest() throws NoSuchMethodException { 86 | int numberOfExpectedFailures = 2; 87 | 88 | // Kick off more tasks than the bulkhead value and queue combined, causing the bulkhead to block 89 | // and start queuing, before throwing an exception 90 | int numberOfTasks = AsynchronousBulkheadBean.class.getAnnotation(Bulkhead.class).value() 91 | + AsynchronousBulkheadBean.class.getAnnotation(Bulkhead.class).waitingTaskQueue() 92 | + numberOfExpectedFailures; 93 | 94 | List> futures = new ArrayList<>(); 95 | for (int i = 0; i < numberOfTasks; i++) { 96 | futures.add(asynchronousBulkheadBean.method1()); 97 | } 98 | 99 | // Await and collect results to make sure everything has completed or thrown an exception 100 | int failures = 0; 101 | for (Future future : futures) { 102 | try { 103 | future.get(); 104 | } catch (InterruptedException ie) { 105 | Logger.getLogger(AsynchronousBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ie); 106 | Assert.fail("Got an unexpected InterruptedException"); 107 | } catch (ExecutionException ex) { 108 | if (ex.getCause() instanceof BulkheadException) { 109 | failures ++; 110 | } else { 111 | Logger.getLogger(AsynchronousBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ex); 112 | Assert.fail("Got an unexpected ExecutionException"); 113 | } 114 | } catch (BulkheadException be) { 115 | failures ++; 116 | } 117 | } 118 | 119 | // numberOfExpectedFailures tasks should fail 120 | Assert.assertTrue("Did not get " + numberOfExpectedFailures + ": " + failures, 121 | failures == numberOfExpectedFailures); 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /fault-tolerance/bulkhead/src/test/java/org/eclipse/microprofile12/faulttolerance/bulkhead/ClassLevelBulkheadBeanTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.faulttolerance.bulkhead; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.Callable; 6 | import java.util.concurrent.ExecutionException; 7 | import java.util.concurrent.ExecutorService; 8 | import java.util.concurrent.Executors; 9 | import java.util.concurrent.Future; 10 | import java.util.logging.Level; 11 | import java.util.logging.Logger; 12 | import javax.inject.Inject; 13 | import org.eclipse.microprofile.faulttolerance.Bulkhead; 14 | import org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException; 15 | import org.eclipse.microprofile.samples12.bulkhead.ClassLevelBulkheadBean; 16 | import org.jboss.arquillian.container.test.api.Deployment; 17 | import org.jboss.arquillian.junit.Arquillian; 18 | import org.jboss.shrinkwrap.api.ShrinkWrap; 19 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 20 | import org.jboss.shrinkwrap.api.spec.WebArchive; 21 | import org.junit.Assert; 22 | import org.junit.Test; 23 | import org.junit.runner.RunWith; 24 | 25 | /** 26 | * Test class for the ClassLevelBulkheadBean class. 27 | * @author Andrew Pielage 28 | */ 29 | @RunWith(Arquillian.class) 30 | public class ClassLevelBulkheadBeanTest { 31 | 32 | @Inject 33 | private ClassLevelBulkheadBean classLevelBulkheadBean; 34 | 35 | @Deployment 36 | public static WebArchive createDeployment() { 37 | return ShrinkWrap.create(WebArchive.class) 38 | .addClasses(ClassLevelBulkheadBean.class) 39 | .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); 40 | } 41 | 42 | /** 43 | * Test that the bulkhead prevents more than the configured number of threads to execute on the method concurrently. 44 | * @throws NoSuchMethodException 45 | */ 46 | @Test 47 | public void bulkheadLimitTest() throws NoSuchMethodException { 48 | int numberOfExpectedFailures = 2; 49 | 50 | // Kick off more tasks than the bulkhead value, causing the bulkhead to block 51 | int numberOfTasks = ClassLevelBulkheadBean.class.getAnnotation(Bulkhead.class).value() 52 | + numberOfExpectedFailures; 53 | List> method1Futures = executeMethod1Asynchronously(numberOfTasks); 54 | 55 | // Await and collect results to make sure everything has completed or thrown an exception 56 | int failures = 0; 57 | for (Future future : method1Futures) { 58 | try { 59 | future.get(); 60 | } catch (InterruptedException ie) { 61 | Logger.getLogger(ClassLevelBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ie); 62 | Assert.fail("Got an unexpected InterruptedException"); 63 | } catch (ExecutionException ex) { 64 | if (ex.getCause() instanceof BulkheadException) { 65 | failures ++; 66 | } else { 67 | Logger.getLogger(ClassLevelBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ex); 68 | Assert.fail("Got an unexpected ExecutionException"); 69 | } 70 | } 71 | } 72 | 73 | // numberOfExpectedFailures tasks should fail 74 | Assert.assertTrue("Did not get " + numberOfExpectedFailures + ": " + failures, 75 | failures == numberOfExpectedFailures); 76 | } 77 | 78 | /** 79 | * Test that the two methods do not share bulkhead tokens, even though the share the same class level annotation. 80 | * @throws NoSuchMethodException 81 | */ 82 | @Test 83 | public void methodsDoNotShareClassLevelBulkheadPermitsTest() throws NoSuchMethodException { 84 | int numberOfExpectedFailures = 2; 85 | 86 | // Kick off more tasks than the bulkhead value for both methods simultaneously, causing the bulkhead to block 87 | int numberOfTasks = ClassLevelBulkheadBean.class.getAnnotation(Bulkhead.class).value() 88 | + numberOfExpectedFailures; 89 | List> method1Futures = executeMethod1Asynchronously(numberOfTasks); 90 | List> method2Futures = executeMethod2Asynchronously(numberOfTasks); 91 | 92 | // Await and collect results to make sure everything has completed or thrown an exception 93 | int failures = 0; 94 | for (Future future : method1Futures) { 95 | try { 96 | future.get(); 97 | } catch (InterruptedException ie) { 98 | Logger.getLogger(ClassLevelBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ie); 99 | Assert.fail("Got an unexpected InterruptedException"); 100 | } catch (ExecutionException ex) { 101 | if (ex.getCause() instanceof BulkheadException) { 102 | failures ++; 103 | } else { 104 | Logger.getLogger(ClassLevelBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ex); 105 | Assert.fail("Got an unexpected ExecutionException"); 106 | } 107 | } 108 | } 109 | 110 | for (Future future : method2Futures) { 111 | try { 112 | future.get(); 113 | } catch (InterruptedException ie) { 114 | Logger.getLogger(ClassLevelBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ie); 115 | Assert.fail("Got an unexpected InterruptedException"); 116 | } catch (ExecutionException ex) { 117 | if (ex.getCause() instanceof BulkheadException) { 118 | failures ++; 119 | } else { 120 | Logger.getLogger(ClassLevelBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ex); 121 | Assert.fail("Got an unexpected ExecutionException"); 122 | } 123 | } 124 | } 125 | 126 | // Since we're doing this against two methods with separate bulkheads, they should not share bulkhead tokens, 127 | // meaning we should get numberOfExpectedFailures x 2 128 | numberOfExpectedFailures = numberOfExpectedFailures * 2; 129 | Assert.assertTrue("Did not get " + numberOfExpectedFailures + ": " + failures, 130 | failures == numberOfExpectedFailures); 131 | } 132 | 133 | /** 134 | * Helper method that kicks off a number of threads to concurrently execute the method1 method 135 | * @param iterations 136 | * @return A list of Future results 137 | */ 138 | private List> executeMethod1Asynchronously(int iterations) { 139 | List> futures = new ArrayList<>(); 140 | 141 | ExecutorService executorService = Executors.newFixedThreadPool(iterations); 142 | 143 | Callable task = () -> { 144 | classLevelBulkheadBean.method1(); 145 | return "Wibbles"; 146 | }; 147 | 148 | for (int i = 0; i < iterations; i++) { 149 | futures.add(executorService.submit(task)); 150 | } 151 | 152 | return futures; 153 | } 154 | 155 | /** 156 | * Helper method that kicks off a number of threads to concurrently execute the method2 method 157 | * @param iterations 158 | * @return A list of Future results 159 | */ 160 | private List> executeMethod2Asynchronously(int iterations) { 161 | List> futures = new ArrayList<>(); 162 | 163 | ExecutorService executorService = Executors.newFixedThreadPool(iterations); 164 | 165 | Callable task = () -> { 166 | classLevelBulkheadBean.method2(); 167 | return "Wobbles"; 168 | }; 169 | 170 | for (int i = 0; i < iterations; i++) { 171 | futures.add(executorService.submit(task)); 172 | } 173 | 174 | return futures; 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /fault-tolerance/bulkhead/src/test/java/org/eclipse/microprofile12/faulttolerance/bulkhead/MethodLevelBulkheadBeanTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.faulttolerance.bulkhead; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.Callable; 6 | import java.util.concurrent.ExecutionException; 7 | import java.util.concurrent.ExecutorService; 8 | import java.util.concurrent.Executors; 9 | import java.util.concurrent.Future; 10 | import java.util.logging.Level; 11 | import java.util.logging.Logger; 12 | import javax.inject.Inject; 13 | import org.eclipse.microprofile.faulttolerance.Bulkhead; 14 | import org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException; 15 | import org.eclipse.microprofile.samples12.bulkhead.MethodLevelBulkheadBean; 16 | import org.jboss.arquillian.container.test.api.Deployment; 17 | import org.jboss.arquillian.junit.Arquillian; 18 | import org.jboss.shrinkwrap.api.ShrinkWrap; 19 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 20 | import org.jboss.shrinkwrap.api.spec.WebArchive; 21 | import org.junit.Assert; 22 | import org.junit.Test; 23 | import org.junit.runner.RunWith; 24 | 25 | /** 26 | * Test class for the MethodLevelBulkheadBean class. 27 | * @author Andrew Pielage 28 | */ 29 | @RunWith(Arquillian.class) 30 | public class MethodLevelBulkheadBeanTest { 31 | 32 | @Inject 33 | MethodLevelBulkheadBean methodLevelBulkheadBean; 34 | 35 | @Deployment 36 | public static WebArchive createDeployment() { 37 | return ShrinkWrap.create(WebArchive.class) 38 | .addClasses(MethodLevelBulkheadBean.class) 39 | .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); 40 | } 41 | 42 | /** 43 | * Test that the bulkhead for method1 prevents more than the configured number of tasks to execute concurrently. 44 | * @throws NoSuchMethodException 45 | */ 46 | @Test 47 | public void method1BulkheadLimitTest() throws NoSuchMethodException { 48 | int numberOfExpectedFailures = 2; 49 | 50 | // Kick off more tasks than the bulkhead value, causing the bulkhead to block 51 | int numberOfTasks = MethodLevelBulkheadBean.class.getMethod("method1").getAnnotation(Bulkhead.class).value() 52 | + numberOfExpectedFailures; 53 | List> method1Futures = executeMethod1Asynchronously(numberOfTasks); 54 | 55 | // Await and collect results to make sure everything has completed or thrown an exception 56 | int failures = 0; 57 | for (Future future : method1Futures) { 58 | try { 59 | future.get(); 60 | } catch (InterruptedException ie) { 61 | Logger.getLogger(MethodLevelBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ie); 62 | Assert.fail("Got an unexpected InterruptedException"); 63 | } catch (ExecutionException ex) { 64 | if (ex.getCause() instanceof BulkheadException) { 65 | failures ++; 66 | } else { 67 | Logger.getLogger(MethodLevelBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ex); 68 | Assert.fail("Got an unexpected ExecutionException"); 69 | } 70 | } 71 | } 72 | 73 | // numberOfExpectedFailures tasks should fail 74 | Assert.assertTrue("Did not get " + numberOfExpectedFailures + ": " + failures, 75 | failures == numberOfExpectedFailures); 76 | } 77 | 78 | /** 79 | * Test that the bulkhead for method2 prevents more than the configured number of tasks to execute concurrently. 80 | * @throws NoSuchMethodException 81 | */ 82 | @Test 83 | public void method2BulkheadLimitTest() throws NoSuchMethodException { 84 | int numberOfExpectedFailures = 2; 85 | 86 | // Kick off more tasks than the bulkhead value, causing the bulkhead to block 87 | int numberOfTasks = MethodLevelBulkheadBean.class.getMethod("method2").getAnnotation(Bulkhead.class).value() 88 | + numberOfExpectedFailures; 89 | List> method2Futures = executeMethod2Asynchronously(numberOfTasks); 90 | 91 | // Await and collect results to make sure everything has completed or thrown an exception 92 | int failures = 0; 93 | for (Future future : method2Futures) { 94 | try { 95 | future.get(); 96 | } catch (InterruptedException ie) { 97 | Logger.getLogger(MethodLevelBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ie); 98 | Assert.fail("Got an unexpected InterruptedException"); 99 | } catch (ExecutionException ex) { 100 | if (ex.getCause() instanceof BulkheadException) { 101 | failures ++; 102 | } else { 103 | Logger.getLogger(MethodLevelBulkheadBeanTest.class.getName()).log(Level.SEVERE, null, ex); 104 | Assert.fail("Got an unexpected ExecutionException"); 105 | } 106 | } 107 | } 108 | 109 | // numberOfExpectedFailures tasks should fail 110 | Assert.assertTrue("Did not get " + numberOfExpectedFailures + ": " + failures, 111 | failures == numberOfExpectedFailures); 112 | } 113 | 114 | /** 115 | * Helper method that kicks off a number of threads to concurrently executes method1. 116 | * @param iterations 117 | * @return A list of Futures. 118 | */ 119 | private List> executeMethod1Asynchronously(int iterations) { 120 | List> futures = new ArrayList<>(); 121 | 122 | ExecutorService executorService = Executors.newFixedThreadPool(iterations); 123 | 124 | Callable task = () -> { 125 | methodLevelBulkheadBean.method1(); 126 | return "Wibbles"; 127 | }; 128 | 129 | for (int i = 0; i < iterations; i++) { 130 | futures.add(executorService.submit(task)); 131 | } 132 | 133 | return futures; 134 | } 135 | 136 | /** 137 | * Helper method that kicks off a number of threads to concurrently executes method2. 138 | * @param iterations 139 | * @return A list of Futures. 140 | */ 141 | private List> executeMethod2Asynchronously(int iterations) { 142 | List> futures = new ArrayList<>(); 143 | 144 | ExecutorService executorService = Executors.newFixedThreadPool(iterations); 145 | 146 | Callable task = () -> { 147 | methodLevelBulkheadBean.method2(); 148 | return "Wobbles"; 149 | }; 150 | 151 | for (int i = 0; i < iterations; i++) { 152 | futures.add(executorService.submit(task)); 153 | } 154 | 155 | return futures; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /fault-tolerance/circuitbreaker/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.eclipse.microprofile.samples12 6 | fault-tolerance 7 | 1.0-SNAPSHOT 8 | 9 | 10 | circuitbreaker 11 | war 12 | 13 | MicroProfile 1.2: Fault Tolerance - CircuitBreaker 14 | 15 | 16 | -------------------------------------------------------------------------------- /fault-tolerance/circuitbreaker/src/main/java/org/eclipse/microprofile/samples12/circuitbreaker/ClassLevelCircuitBreakerBean.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.circuitbreaker; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | import org.eclipse.microprofile.faulttolerance.CircuitBreaker; 5 | 6 | /** 7 | * A bean with a Circuitbreaker applied at the class level. 8 | * @author Andrew Pielage 9 | */ 10 | @CircuitBreaker(requestVolumeThreshold = 4) 11 | @ApplicationScoped 12 | public class ClassLevelCircuitBreakerBean { 13 | 14 | public static final String EXPECTED_ERROR_MESSAGE = "Method failed to execute"; 15 | 16 | /** 17 | * Example method that can be made to throw an exception. 18 | * @param shouldThrowException Whether an exception should be thrown or not 19 | */ 20 | public void throwException(boolean shouldThrowException) { 21 | if (shouldThrowException) { 22 | throw new RuntimeException(EXPECTED_ERROR_MESSAGE); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /fault-tolerance/circuitbreaker/src/main/java/org/eclipse/microprofile/samples12/circuitbreaker/MethodLevelCircuitBreakerBean.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.circuitbreaker; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | import org.eclipse.microprofile.faulttolerance.CircuitBreaker; 5 | 6 | /** 7 | * A bean with a Circuitbreaker applied at the method level. 8 | * @author Andrew Pielage 9 | */ 10 | @ApplicationScoped 11 | public class MethodLevelCircuitBreakerBean { 12 | public static final String EXPECTED_ERROR_MESSAGE = "Method failed to execute"; 13 | 14 | /** 15 | * Example method that can be made to throw an exception. 16 | * @param shouldThrowException 17 | */ 18 | @CircuitBreaker(requestVolumeThreshold = 6) 19 | public void throwException(boolean shouldThrowException) { 20 | if (shouldThrowException) { 21 | throw new RuntimeException(EXPECTED_ERROR_MESSAGE); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /fault-tolerance/circuitbreaker/src/test/java/org/eclipse/microprofile12/faulttolerance/circuitbreaker/ClassLevelCircuitBreakerBeanTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.faulttolerance.circuitbreaker; 2 | 3 | import java.time.Duration; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.concurrent.Callable; 7 | import java.util.concurrent.ExecutionException; 8 | import java.util.concurrent.ExecutorService; 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.Future; 11 | import java.util.logging.Level; 12 | import java.util.logging.Logger; 13 | import javax.inject.Inject; 14 | import org.eclipse.microprofile.faulttolerance.CircuitBreaker; 15 | import org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException; 16 | import org.eclipse.microprofile.samples12.circuitbreaker.ClassLevelCircuitBreakerBean; 17 | import org.jboss.arquillian.container.test.api.Deployment; 18 | import org.jboss.arquillian.junit.Arquillian; 19 | import org.jboss.shrinkwrap.api.ShrinkWrap; 20 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 21 | import org.jboss.shrinkwrap.api.spec.WebArchive; 22 | import org.junit.Assert; 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | 27 | /** 28 | * Test class for ClassLevelCircuitBreakerBean. 29 | * @author Andrew Pielage 30 | */ 31 | @RunWith(Arquillian.class) 32 | public class ClassLevelCircuitBreakerBeanTest { 33 | 34 | @Inject 35 | private ClassLevelCircuitBreakerBean classLevelCircuitBreakerBean; 36 | 37 | @Deployment 38 | public static WebArchive createDeployment() { 39 | return ShrinkWrap.create(WebArchive.class) 40 | .addClasses(ClassLevelCircuitBreakerBean.class) 41 | .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); 42 | } 43 | 44 | /** 45 | * When running against a remote profile, we need to wait for the circuitbreaker to reset between each test. 46 | * @throws NoSuchMethodException 47 | * @throws InterruptedException 48 | */ 49 | @Before 50 | public void resetCircuitBreaker() throws NoSuchMethodException, InterruptedException { 51 | // Wait to half-open the circuit breaker - previous tests may have run and left it in a sorry state 52 | long addedWaitTimeMillis = 3000; 53 | long timeToWaitMillis = Duration.of( 54 | ClassLevelCircuitBreakerBean.class.getAnnotation(CircuitBreaker.class).delay(), 55 | ClassLevelCircuitBreakerBean.class.getAnnotation(CircuitBreaker.class).delayUnit()).toMillis() 56 | + addedWaitTimeMillis; 57 | Thread.sleep(timeToWaitMillis); 58 | 59 | // Fill it with goodness 60 | int numberOfTasks = ((Double) ( 61 | ClassLevelCircuitBreakerBean.class.getAnnotation(CircuitBreaker.class).requestVolumeThreshold() 62 | * ClassLevelCircuitBreakerBean.class.getAnnotation(CircuitBreaker.class).failureRatio())).intValue() 63 | + ClassLevelCircuitBreakerBean.class.getAnnotation(CircuitBreaker.class).successThreshold(); 64 | executeThrowExceptionMethodAsynchronously(numberOfTasks, false); 65 | 66 | } 67 | 68 | /** 69 | * Test that the Circuitbreaker opens once enough failures have been thrown. 70 | */ 71 | @Test 72 | public void circuitBreakerOpensTest() { 73 | int numberOfExpectedFailures = 2; 74 | 75 | int numberOfTasks = ((Double) ( 76 | ClassLevelCircuitBreakerBean.class.getAnnotation(CircuitBreaker.class).requestVolumeThreshold() 77 | * ClassLevelCircuitBreakerBean.class.getAnnotation(CircuitBreaker.class).failureRatio())) 78 | .intValue() + numberOfExpectedFailures; 79 | 80 | // Throw errors to to open the circuit 81 | List> futures = executeThrowExceptionMethodAsynchronously(numberOfTasks, true); 82 | 83 | // Await and collect results to make sure everything has completed or thrown an exception 84 | int failures = 0; 85 | for (Future future : futures) { 86 | try { 87 | future.get(); 88 | } catch (InterruptedException ie) { 89 | Logger.getLogger(ClassLevelCircuitBreakerBeanTest.class.getName()).log(Level.SEVERE, null, ie); 90 | Assert.fail("Got an unexpected InterruptedException"); 91 | } catch (ExecutionException ex) { 92 | if (ex.getCause() instanceof CircuitBreakerOpenException) { 93 | failures ++; 94 | } else if (ex.getCause() instanceof RuntimeException 95 | && ex.getCause().getMessage().equals(ClassLevelCircuitBreakerBean.EXPECTED_ERROR_MESSAGE)) { 96 | // Om nom nom 97 | } else { 98 | Logger.getLogger(ClassLevelCircuitBreakerBeanTest.class.getName()).log(Level.SEVERE, null, ex); 99 | Assert.fail("Got an unexpected ExecutionException"); 100 | } 101 | } 102 | } 103 | 104 | // numberOfExpectedFailures tasks should fail 105 | Assert.assertTrue("Did not get " + numberOfExpectedFailures + ": " + failures, 106 | failures == numberOfExpectedFailures); 107 | } 108 | 109 | /** 110 | * Helper method that spawns a number of threads to execute against the throwException method concurrently. 111 | * @param iterations 112 | * @param shouldThrowException 113 | * @return 114 | */ 115 | private List> executeThrowExceptionMethodAsynchronously(int iterations, 116 | boolean shouldThrowException) { 117 | List> futures = new ArrayList<>(); 118 | 119 | ExecutorService executorService = Executors.newSingleThreadExecutor(); 120 | 121 | Callable task = () -> { 122 | classLevelCircuitBreakerBean.throwException(shouldThrowException); 123 | return null; 124 | }; 125 | 126 | for (int i = 0; i < iterations; i++) { 127 | futures.add(executorService.submit(task)); 128 | } 129 | 130 | return futures; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /fault-tolerance/circuitbreaker/src/test/java/org/eclipse/microprofile12/faulttolerance/circuitbreaker/MethodLevelCircuitBreakerBeanTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.faulttolerance.circuitbreaker; 2 | 3 | import java.time.Duration; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.concurrent.Callable; 7 | import java.util.concurrent.ExecutionException; 8 | import java.util.concurrent.ExecutorService; 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.Future; 11 | import java.util.logging.Level; 12 | import java.util.logging.Logger; 13 | import javax.inject.Inject; 14 | import org.eclipse.microprofile.faulttolerance.CircuitBreaker; 15 | import org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException; 16 | import org.eclipse.microprofile.samples12.circuitbreaker.MethodLevelCircuitBreakerBean; 17 | import org.jboss.arquillian.container.test.api.Deployment; 18 | import org.jboss.arquillian.junit.Arquillian; 19 | import org.jboss.shrinkwrap.api.ShrinkWrap; 20 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 21 | import org.jboss.shrinkwrap.api.spec.WebArchive; 22 | import org.junit.Assert; 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | 27 | /** 28 | * Test class for MethodLevelCircuitBreakerBean. 29 | * @author Andrew Pielage 30 | */ 31 | @RunWith(Arquillian.class) 32 | public class MethodLevelCircuitBreakerBeanTest { 33 | 34 | @Inject 35 | private MethodLevelCircuitBreakerBean methodLevelCircuitBreakerBean; 36 | 37 | @Deployment 38 | public static WebArchive createDeployment() { 39 | return ShrinkWrap.create(WebArchive.class) 40 | .addClasses(MethodLevelCircuitBreakerBean.class) 41 | .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); 42 | } 43 | 44 | /** 45 | * When running against a remote profile, we need to wait for the circuitbreaker to reset between each test. 46 | * @throws NoSuchMethodException 47 | * @throws InterruptedException 48 | */ 49 | @Before 50 | public void resetCircuitBreaker() throws NoSuchMethodException, InterruptedException { 51 | // Wait to half-open the circuit breaker - previous tests may have run and left it in a sorry state 52 | long addedWaitTimeMillis = 3000; 53 | long timeToWaitMillis = Duration.of( 54 | MethodLevelCircuitBreakerBean.class.getMethod("throwException", boolean.class) 55 | .getAnnotation(CircuitBreaker.class).delay(), 56 | MethodLevelCircuitBreakerBean.class.getMethod("throwException", boolean.class) 57 | .getAnnotation(CircuitBreaker.class).delayUnit()).toMillis() + addedWaitTimeMillis; 58 | Thread.sleep(timeToWaitMillis); 59 | 60 | // Fill it with goodness 61 | int numberOfTasks = ((Double) ( 62 | MethodLevelCircuitBreakerBean.class.getMethod("throwException", boolean.class) 63 | .getAnnotation(CircuitBreaker.class).requestVolumeThreshold() 64 | * MethodLevelCircuitBreakerBean.class.getMethod("throwException", boolean.class) 65 | .getAnnotation(CircuitBreaker.class).failureRatio())).intValue() 66 | + MethodLevelCircuitBreakerBean.class.getMethod("throwException", boolean.class) 67 | .getAnnotation(CircuitBreaker.class).successThreshold(); 68 | executeThrowExceptionMethodAsynchronously(numberOfTasks, false); 69 | } 70 | 71 | /** 72 | * Test that once a circuitbreaker has opened, that it recloses itself and allows executions again. 73 | * @throws NoSuchMethodException 74 | * @throws InterruptedException 75 | */ 76 | @Test 77 | public void circuitBreakerReclosesTest() throws NoSuchMethodException, InterruptedException { 78 | int numberOfExpectedFailures = 2; 79 | 80 | int numberOfTasks = ((Double) ( 81 | MethodLevelCircuitBreakerBean.class.getMethod("throwException", boolean.class) 82 | .getAnnotation(CircuitBreaker.class).requestVolumeThreshold() 83 | * MethodLevelCircuitBreakerBean.class.getMethod("throwException", boolean.class) 84 | .getAnnotation(CircuitBreaker.class).failureRatio())) 85 | .intValue() + numberOfExpectedFailures; 86 | 87 | // Force the method to throw errors to open the circuit 88 | List> futures = executeThrowExceptionMethodAsynchronously(numberOfTasks, true); 89 | 90 | // Await and collect results to make sure everything has completed or thrown an exception 91 | int failures = 0; 92 | for (Future future : futures) { 93 | try { 94 | future.get(); 95 | } catch (InterruptedException ie) { 96 | Logger.getLogger(MethodLevelCircuitBreakerBeanTest.class.getName()).log(Level.SEVERE, null, ie); 97 | Assert.fail("Got an unexpected InterruptedException"); 98 | } catch (ExecutionException ex) { 99 | if (ex.getCause() instanceof CircuitBreakerOpenException) { 100 | failures ++; 101 | } else if (ex.getCause() instanceof RuntimeException 102 | && ex.getCause().getMessage().equals(MethodLevelCircuitBreakerBean.EXPECTED_ERROR_MESSAGE)) { 103 | // Om nom nom 104 | } else { 105 | Logger.getLogger(MethodLevelCircuitBreakerBeanTest.class.getName()).log(Level.SEVERE, null, ex); 106 | Assert.fail("Got an unexpected ExecutionException"); 107 | } 108 | } 109 | } 110 | 111 | // numberOfExpectedFailures tasks should fail 112 | Assert.assertTrue("Did not get " + numberOfExpectedFailures + ": " + failures, 113 | failures == numberOfExpectedFailures); 114 | 115 | // Now we wait... 116 | long addedWaitTimeMillis = 3000; 117 | long timeToWaitMillis = Duration.of( 118 | MethodLevelCircuitBreakerBean.class.getMethod("throwException", boolean.class) 119 | .getAnnotation(CircuitBreaker.class).delay(), 120 | MethodLevelCircuitBreakerBean.class.getMethod("throwException", boolean.class) 121 | .getAnnotation(CircuitBreaker.class).delayUnit()).toMillis() + addedWaitTimeMillis; 122 | Thread.sleep(timeToWaitMillis); 123 | 124 | // We should now be able to send a message though as the circuitbreaker should be half-open 125 | try { 126 | methodLevelCircuitBreakerBean.throwException(false); 127 | Assert.assertTrue(true); 128 | } catch (Exception ex) { 129 | Logger.getLogger(MethodLevelCircuitBreakerBeanTest.class.getName()).log(Level.SEVERE, null, ex); 130 | Assert.fail("Got an unexpected Exception"); 131 | } 132 | } 133 | 134 | /** 135 | * Helper method that spawns a number of threads to execute against the throwException method concurrently. 136 | * @param iterations 137 | * @param shouldThrowException 138 | * @return 139 | */ 140 | private List> executeThrowExceptionMethodAsynchronously(int iterations, 141 | boolean shouldThrowException) { 142 | List> futures = new ArrayList<>(); 143 | 144 | ExecutorService executorService = Executors.newSingleThreadExecutor(); 145 | 146 | Callable task = () -> { 147 | methodLevelCircuitBreakerBean.throwException(shouldThrowException); 148 | return null; 149 | }; 150 | 151 | for (int i = 0; i < iterations; i++) { 152 | futures.add(executorService.submit(task)); 153 | } 154 | 155 | return futures; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /fault-tolerance/fallback/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | fault-tolerance 6 | org.eclipse.microprofile.samples12 7 | 1.0-SNAPSHOT 8 | 9 | 10 | fallback 11 | war 12 | 13 | MicroProfile 1.2: Fault Tolerance - Fallback 14 | 15 | 16 | -------------------------------------------------------------------------------- /fault-tolerance/fallback/src/main/java/org/eclipse/microprofile/samples12/fallback/FallbackBean.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.fallback; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | import org.eclipse.microprofile.faulttolerance.Fallback; 5 | import org.eclipse.microprofile.faulttolerance.Retry; 6 | 7 | /** 8 | * A bean demonstrating a simple use case of utilising a fallback handler or a fallback method with the Retry annotation. 9 | * @author Andrew Pielage 10 | */ 11 | @ApplicationScoped 12 | public class FallbackBean { 13 | 14 | public static final String defaultResponse = "I didn't fail!"; 15 | public static final String expectedResponse = "I fell back! Thank you MicroProfile!"; 16 | 17 | /** 18 | * Example method that can be made to throw an exception, kicking off the fallbackHandler after it has retried once. 19 | * @param fallback 20 | * @return 21 | */ 22 | @Retry(maxRetries = 1) 23 | @Fallback(StringFallbackHandler.class) 24 | public String demonstrateFallbackHandler(boolean fallback) { 25 | if (fallback) { 26 | throw new RuntimeException("I failed somehow! Save me MicroProfile!"); 27 | } else { 28 | return defaultResponse; 29 | } 30 | } 31 | 32 | /** 33 | * Example method that can be made to throw an exception, kicking off the fallback method after it has retried once. 34 | * @param fallback 35 | * @return 36 | */ 37 | @Retry(maxRetries = 1) 38 | @Fallback(fallbackMethod = "fallbackMethodExample") 39 | public String demonstrateFallbackMethod(boolean fallback) { 40 | if (fallback) { 41 | throw new RuntimeException("I failed somehow! Save me MicroProfile!"); 42 | } else { 43 | return defaultResponse; 44 | } 45 | } 46 | 47 | /** 48 | * Very basic example of a fallback method. 49 | * @param fallback Unused in this example method, but necessary because a fallback method must share the same return 50 | * type and parameters as the method it is the fallback for 51 | * @return 52 | */ 53 | public String fallbackMethodExample(boolean fallback) { 54 | return expectedResponse; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /fault-tolerance/fallback/src/main/java/org/eclipse/microprofile/samples12/fallback/StringFallbackHandler.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.fallback; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | import org.eclipse.microprofile.faulttolerance.ExecutionContext; 5 | import org.eclipse.microprofile.faulttolerance.FallbackHandler; 6 | 7 | /** 8 | * An example fallback handler for a method with a return type of String. 9 | * @author Andrew Pielage 10 | */ 11 | @ApplicationScoped 12 | public class StringFallbackHandler implements FallbackHandler { 13 | 14 | @Override 15 | public String handle(ExecutionContext ec) { 16 | return FallbackBean.expectedResponse; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /fault-tolerance/fallback/src/test/java/org/eclipse/microprofile/samples12/fallback/FallbackBeanTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.fallback; 2 | 3 | import javax.inject.Inject; 4 | import org.jboss.arquillian.container.test.api.Deployment; 5 | import org.jboss.arquillian.junit.Arquillian; 6 | import org.jboss.shrinkwrap.api.ShrinkWrap; 7 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 8 | import org.jboss.shrinkwrap.api.spec.WebArchive; 9 | import org.junit.Assert; 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | 13 | /** 14 | * Tests for the FallbackBean class. 15 | * @author Andrew Pielage 16 | */ 17 | @RunWith(Arquillian.class) 18 | public class FallbackBeanTest { 19 | 20 | @Inject 21 | private FallbackBean fallbackBean; 22 | 23 | @Deployment 24 | public static WebArchive createDeployment() { 25 | return ShrinkWrap.create(WebArchive.class) 26 | .addClasses(FallbackBean.class, StringFallbackHandler.class) 27 | .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); 28 | } 29 | 30 | /** 31 | * Tests the operation of the fallback handler. 32 | */ 33 | @Test 34 | public void fallbackHandlerTest() { 35 | String result = fallbackBean.demonstrateFallbackHandler(true); 36 | Assert.assertTrue("Did not get the expected result", result.equals(FallbackBean.expectedResponse)); 37 | } 38 | 39 | /** 40 | * Tests the operation of the fallback method. 41 | */ 42 | @Test 43 | public void fallbackMethodTest() { 44 | String result = fallbackBean.demonstrateFallbackMethod(true); 45 | Assert.assertTrue("Did not get the expected result", result.equals(FallbackBean.expectedResponse)); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /fault-tolerance/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.eclipse.microprofile.samples12 9 | samples-parent 10 | 1.0-SNAPSHOT 11 | 12 | 13 | fault-tolerance 14 | pom 15 | 16 | MicroProfile 1.2: Fault Tolerance 17 | 18 | 19 | asynchronous 20 | bulkhead 21 | circuitbreaker 22 | timeout 23 | retry 24 | fallback 25 | 26 | 27 | 28 | 29 | org.eclipse.microprofile.samples12 30 | test-utils 31 | ${project.version} 32 | 33 | 34 | -------------------------------------------------------------------------------- /fault-tolerance/retry/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | fault-tolerance 6 | org.eclipse.microprofile.samples12 7 | 1.0-SNAPSHOT 8 | 9 | 10 | retry 11 | war 12 | 13 | MicroProfile 1.2: Fault Tolerance - Retry 14 | 15 | 16 | -------------------------------------------------------------------------------- /fault-tolerance/retry/src/main/java/org/eclipse/microprofile/samples12/retry/RetryBean.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.retry; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | import org.eclipse.microprofile.faulttolerance.Retry; 5 | 6 | /** 7 | * A bean demonstrating the usage of the Retry annotation. 8 | * @author Andrew Pielage 9 | */ 10 | @ApplicationScoped 11 | @Retry(maxRetries = 8, delay = 500, jitter = 250) 12 | public class RetryBean { 13 | 14 | public static final int expectedAttempts = 5; 15 | 16 | // Counters for each method, used to count the number of attempts - this is most definitely not thread safe! 17 | private int method1Counter = 0; 18 | private int method2Counter = 0; 19 | 20 | /** 21 | * Example method that demonstrates the retry annotation by only succeeded once the counter has reached a 22 | * certain point. 23 | * @return 24 | */ 25 | public int demonstrateRetry() { 26 | if (method1Counter < expectedAttempts) { 27 | method1Counter++; 28 | throw new RuntimeException("Oh noes! Some exception! Method Counter is currently: " + method1Counter); 29 | } 30 | 31 | return method1Counter; 32 | } 33 | 34 | /** 35 | * An example method demonstrating how you can configure the retry annotation to abort on certain exceptions. 36 | * @param abort 37 | * @return 38 | * @throws InterruptedException Not actually interrupted, just used as an example 39 | */ 40 | @Retry(maxRetries = 5, abortOn = InterruptedException.class) 41 | public int demonstrateAbort(boolean abort) throws InterruptedException { 42 | if (method2Counter < expectedAttempts) { 43 | method2Counter++; 44 | 45 | if (abort) { 46 | throw new InterruptedException("Oh noes! A more serious exception!"); 47 | } else { 48 | throw new RuntimeException("Oh noes! Some exception! Method Counter is currently: " + method2Counter); 49 | } 50 | } 51 | 52 | return method2Counter; 53 | } 54 | 55 | /** 56 | * Helper method used to reset the counters. 57 | */ 58 | public void resetCounters() { 59 | method1Counter = 0; 60 | method2Counter = 0; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /fault-tolerance/retry/src/test/java/org/eclipse/microprofile/samples12/retry/RetryBeanTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.retry; 2 | 3 | import javax.inject.Inject; 4 | import org.jboss.arquillian.container.test.api.Deployment; 5 | import org.jboss.arquillian.junit.Arquillian; 6 | import org.jboss.shrinkwrap.api.ShrinkWrap; 7 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 8 | import org.jboss.shrinkwrap.api.spec.WebArchive; 9 | import org.junit.Assert; 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | 13 | /** 14 | * Tests for the RetryBean class. 15 | * @author Andrew Pielage 16 | */ 17 | @RunWith(Arquillian.class) 18 | public class RetryBeanTest { 19 | 20 | @Inject 21 | private RetryBean retryBean; 22 | 23 | @Deployment 24 | public static WebArchive createDeployment() { 25 | return ShrinkWrap.create(WebArchive.class) 26 | .addClasses(RetryBean.class) 27 | .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); 28 | } 29 | 30 | /** 31 | * Test that the method retries the expected number of times. 32 | */ 33 | @Test 34 | public void retryTest() { 35 | int numberOfAttempts = 0; 36 | numberOfAttempts = retryBean.demonstrateRetry(); 37 | 38 | Assert.assertTrue("Didn't get the expected number of attempts: " + numberOfAttempts, 39 | numberOfAttempts == RetryBean.expectedAttempts); 40 | } 41 | 42 | /** 43 | * Test that the method aborts on specific errors. 44 | */ 45 | @Test 46 | public void abortOnTest() { 47 | // Prove that the method doesn't just exit anyway by making it retry on an allowed exception. 48 | int numberOfAttempts = 0; 49 | try { 50 | numberOfAttempts = retryBean.demonstrateAbort(false); 51 | } catch (InterruptedException ie) { 52 | Assert.fail("Got an unexpected InterruptedException"); 53 | } 54 | 55 | Assert.assertTrue("Didn't get the expected number of attempts: " + numberOfAttempts, 56 | numberOfAttempts == RetryBean.expectedAttempts); 57 | 58 | // Reset the counters 59 | retryBean.resetCounters(); 60 | 61 | // Test that it exists on the specified exception 62 | try { 63 | retryBean.demonstrateAbort(true); 64 | } catch (InterruptedException ex) { 65 | return; 66 | } 67 | 68 | Assert.fail("Didn't get an InterruptedException when expected"); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /fault-tolerance/timeout/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | fault-tolerance 6 | org.eclipse.microprofile.samples12 7 | 1.0-SNAPSHOT 8 | 9 | 10 | timeout 11 | war 12 | 13 | MicroProfile 1.2: Fault Tolerance - Timeout 14 | 15 | 16 | -------------------------------------------------------------------------------- /fault-tolerance/timeout/src/main/java/org/eclipse/microprofile/samples12/timeout/AsynchronousTimeoutBean.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.timeout; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | import java.util.concurrent.Future; 5 | import javax.enterprise.context.ApplicationScoped; 6 | import org.eclipse.microprofile.faulttolerance.Asynchronous; 7 | import org.eclipse.microprofile.faulttolerance.Timeout; 8 | 9 | /** 10 | * A bean demonstrating how the Timeout and Asynchronous annotations can be used together. 11 | * @author Andrew Pielage 12 | */ 13 | @ApplicationScoped 14 | @Timeout 15 | public class AsynchronousTimeoutBean { 16 | 17 | public static final long AWAIT = 3000; 18 | 19 | /** 20 | * Example method that simulates a long running query, running in a different thread. 21 | * @param shouldTimeout 22 | * @return 23 | */ 24 | @Asynchronous 25 | public Future timeout(boolean shouldTimeout) { 26 | Boolean timedOut = false; 27 | 28 | if (shouldTimeout) { 29 | try { 30 | // Simulate a long running query 31 | Thread.sleep(AWAIT); 32 | } catch (InterruptedException ex) { 33 | timedOut = true; 34 | } 35 | } 36 | 37 | return CompletableFuture.completedFuture(timedOut); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /fault-tolerance/timeout/src/main/java/org/eclipse/microprofile/samples12/timeout/ClassLevelTimeoutBean.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.timeout; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | import org.eclipse.microprofile.faulttolerance.Timeout; 5 | 6 | /** 7 | * A bean demonstrating how to use the Timeout annotation. 8 | * @author Andrew Pielage 9 | */ 10 | @ApplicationScoped 11 | @Timeout(1500) 12 | public class ClassLevelTimeoutBean { 13 | 14 | public static final long AWAIT = 3000; 15 | 16 | /** 17 | * Example method that simulates a long running query. 18 | * @param shouldTimeout 19 | */ 20 | public void timeout(boolean shouldTimeout) { 21 | if (shouldTimeout) { 22 | try { 23 | // Simulate a long running query 24 | Thread.sleep(AWAIT); 25 | } catch (InterruptedException ex) { 26 | // Om nom nom 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /fault-tolerance/timeout/src/main/java/org/eclipse/microprofile/samples12/timeout/MethodLevelTimeoutBean.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.timeout; 2 | 3 | import java.time.temporal.ChronoUnit; 4 | import javax.enterprise.context.ApplicationScoped; 5 | import org.eclipse.microprofile.faulttolerance.Timeout; 6 | 7 | /** 8 | * A bean demonstrating how you can use the Timeout annotation on a specific method. 9 | * @author Andrew Pielage 10 | */ 11 | @ApplicationScoped 12 | public class MethodLevelTimeoutBean { 13 | 14 | public static final long AWAIT = 5000; 15 | 16 | /** 17 | * Example method that simulates a long running query. 18 | * @param shouldTimeout 19 | */ 20 | @Timeout(value = 2, unit = ChronoUnit.SECONDS) 21 | public void timeout(boolean shouldTimeout) { 22 | if (shouldTimeout) { 23 | try { 24 | // Simulate a long running query 25 | Thread.sleep(AWAIT); 26 | } catch (InterruptedException ex) { 27 | // Om nom nom 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /fault-tolerance/timeout/src/main/resources/project-defaults.yml: -------------------------------------------------------------------------------- 1 | swarm: 2 | hystrix: 3 | command: 4 | default: 5 | execution: 6 | isolation: 7 | thread: 8 | timeoutInMilliseconds: 3500 #MORE THAN AsynchronousTimeoutBean.AWAIT CONFIGURED IN TESTS 9 | -------------------------------------------------------------------------------- /fault-tolerance/timeout/src/test/java/org/eclipse/microprofile/samples12/timeout/AsynchronousTimeoutBeanTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.timeout; 2 | 3 | import java.util.concurrent.ExecutionException; 4 | import java.util.concurrent.Future; 5 | import javax.inject.Inject; 6 | 7 | import org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException; 8 | import org.jboss.arquillian.container.test.api.Deployment; 9 | import org.jboss.arquillian.junit.Arquillian; 10 | import org.jboss.shrinkwrap.api.ShrinkWrap; 11 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 12 | import org.jboss.shrinkwrap.api.spec.WebArchive; 13 | import org.junit.Assert; 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | 17 | /** 18 | * Test class for the AsynchronousTimeoutBean. 19 | * @author Andrew Pielage 20 | */ 21 | @RunWith(Arquillian.class) 22 | public class AsynchronousTimeoutBeanTest { 23 | 24 | @Inject 25 | private AsynchronousTimeoutBean asynchronousTimeoutBean; 26 | 27 | @Deployment 28 | public static WebArchive createDeployment() { 29 | return ShrinkWrap.create(WebArchive.class) 30 | .addClasses(AsynchronousTimeoutBean.class) 31 | .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml") 32 | .addAsResource("project-defaults.yml"); 33 | } 34 | 35 | /** 36 | * Tests that the timeout annotation interrupts a long running task and throws a TimeoutException upon calling 37 | * future.get(). 38 | * @throws InterruptedException 39 | * @throws ExecutionException 40 | */ 41 | @Test 42 | public void timeoutTest() throws InterruptedException, ExecutionException { 43 | Future future = asynchronousTimeoutBean.timeout(true); 44 | try { 45 | future.get(); 46 | } catch (TimeoutException toe) { 47 | return; 48 | } catch (ExecutionException ex) { 49 | if (ex.getCause() instanceof TimeoutException) { 50 | return; 51 | } 52 | } 53 | 54 | Assert.fail(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /fault-tolerance/timeout/src/test/java/org/eclipse/microprofile/samples12/timeout/ClassLevelTimeoutBeanTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.timeout; 2 | 3 | import javax.inject.Inject; 4 | import org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException; 5 | import org.jboss.arquillian.container.test.api.Deployment; 6 | import org.jboss.arquillian.junit.Arquillian; 7 | import org.jboss.shrinkwrap.api.ShrinkWrap; 8 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 9 | import org.jboss.shrinkwrap.api.spec.WebArchive; 10 | import org.junit.Assert; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | 14 | /** 15 | * Test class for ClassLevelTimeoutBean. 16 | * @author Andrew Pielage 17 | */ 18 | @RunWith(Arquillian.class) 19 | public class ClassLevelTimeoutBeanTest { 20 | 21 | @Inject 22 | private ClassLevelTimeoutBean classLevelTimeoutBean; 23 | 24 | @Deployment 25 | public static WebArchive createDeployment() { 26 | return ShrinkWrap.create(WebArchive.class) 27 | .addClasses(ClassLevelTimeoutBean.class) 28 | .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); 29 | } 30 | 31 | /** 32 | * Tests that the timeout annotation interrupts a long running task and throws a TimeoutException. 33 | */ 34 | @Test 35 | public void timeoutTest() { 36 | try { 37 | classLevelTimeoutBean.timeout(true); 38 | } catch (TimeoutException toe) { 39 | return; 40 | } 41 | 42 | Assert.fail(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /fault-tolerance/timeout/src/test/java/org/eclipse/microprofile/samples12/timeout/MethodLevelTimeoutBeanTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile.samples12.timeout; 2 | 3 | import javax.inject.Inject; 4 | import org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException; 5 | import org.jboss.arquillian.container.test.api.Deployment; 6 | import org.jboss.arquillian.junit.Arquillian; 7 | import org.jboss.shrinkwrap.api.ShrinkWrap; 8 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 9 | import org.jboss.shrinkwrap.api.spec.WebArchive; 10 | import org.junit.Assert; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | 14 | /** 15 | * Test class for MethodLevelTimeoutBeanTest 16 | * @author Andrew Pielage 17 | */ 18 | @RunWith(Arquillian.class) 19 | public class MethodLevelTimeoutBeanTest { 20 | 21 | @Inject 22 | private MethodLevelTimeoutBean methodLevelTimeoutBean; 23 | 24 | @Deployment 25 | public static WebArchive createDeployment() { 26 | return ShrinkWrap.create(WebArchive.class) 27 | .addClasses(MethodLevelTimeoutBean.class) 28 | .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); 29 | } 30 | 31 | /** 32 | * Tests that the timeout annotation interrupts a long running task and throws a TimeoutException. 33 | */ 34 | @Test 35 | public void timeoutTest() { 36 | try { 37 | methodLevelTimeoutBean.timeout(true); 38 | } catch (TimeoutException toe) { 39 | return; 40 | } 41 | 42 | Assert.fail(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /jwt-auth/README.md: -------------------------------------------------------------------------------- 1 | # Eclipse MicroProfile 1.2 Samples - JWT Auth 1.0 2 | 3 | - [Wiki project page](https://wiki.eclipse.org/MicroProfile/JWT_Auth) 4 | - [Spec, API, TCK GitHub repo](https://github.com/eclipse/microprofile-jwt-auth) 5 | 6 | **Note** for practical purposes these samples have been superseded by the ones at https://github.com/javaee-samples/microprofile1.4-samples/tree/master/jwt-auth 7 | 8 | ## Samples ## 9 | 10 | - **basic-authentication** The test sends a very basic signed JWT token to a protected servlet. The MP-JWT Auth implementation 11 | checks if the token is valid and sets the authenticated identity from the `upn` field and `groups` field 12 | **jaxrs ** Just like basic-authentication, but uses a JAX-RS endpoint. Specifically demonstrates the support of @RolesAllowed to secure and endpoint. 13 | 14 | 15 | 16 | ## Implementation config ## 17 | 18 | There's at least 2 items that need to be configured in an implementation specific way: the *issuer*, which represents the party that vended the token, and the *public key* which is used to verify the signature of a JWT token being sent to the server. 19 | 20 | - **Payara (tech preview)** 21 | - *issuer* - defined in "payara-mp-jwt.properties" which is placed in the classpath root of the application archive 22 | - *public key* - the file "publicKey.pem" which is also placed in the classpath root of the application archive 23 | - **Liberty** 24 | - *issuer* - defined in the "mpJwt" tag in "server.xml" which in the placed inside the installed Liberty: `[install dir]/wlp/usr/servers/defaultServer/server.xml` 25 | - *public key* - the file "key.jks" which in the placed inside the installed Liberty: `[install dir]/wlp/usr/servers/defaultServer/resources/security/key.jks` 26 | - **WildFly (Swarm)** 27 | - *issuer* - defined in "project-default.yml" which is placed in the classpath root of the application archive. This also configures the security system (security domain in JBoss terms) such that all artifacts to support MP-Auth JWT are installed 28 | - *public key* - the file "MP-JWT-SIGNER" which is placed in the classpath's META-INF of the application archive. 29 | 30 | 31 | ## TCK ## 32 | 33 | The public/private keys are taken from the MP-Auth TCK. The Liberty key is in a special format and has been taken from the Liberty TCK version. Config files for the various servers are inspired by those in the TCK and TCK extensions. 34 | 35 | See the following URLs: 36 | 37 | - [MP-Auth TCK](https://github.com/eclipse/microprofile-jwt-auth/tree/master/tck) 38 | - [Payara TCK Ext](https://github.com/payara/Payara/tree/Payara-5/appserver/payara-appserver-modules/microprofile/jwt-auth-tck) 39 | - [Liberty TCK](https://github.com/OpenLiberty/open-liberty/tree/master/dev/com.ibm.ws.security.mp.jwt_fat_tck) 40 | - [WildFly TCK Ext](https://github.com/MicroProfileJWT/wfswarm-jwt-auth-tck) 41 | 42 | -------------------------------------------------------------------------------- /jwt-auth/basic-authentication/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | org.eclipse.microprofile.samples12 6 | jwt-auth 7 | 1.0-SNAPSHOT 8 | 9 | 10 | basic-authentication 11 | war 12 | MicroProfile 1.2: JWT-AUTH - Basic Authentication 13 | 14 | 15 | -------------------------------------------------------------------------------- /jwt-auth/basic-authentication/src/main/java/org/eclipse/microprofile12/jwtauth/basic/ApplicationInit.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.jwtauth.basic; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | 5 | import org.eclipse.microprofile.auth.LoginConfig; 6 | 7 | @LoginConfig( 8 | authMethod = "MP-JWT", 9 | // Even though specified being only for HTTP Basic auth, JBoss/WildFly/Swarm mandates this 10 | // to refer to its proprietary "security domain" concept. 11 | realmName = "MP-JWT" 12 | ) 13 | @ApplicationScoped 14 | public class ApplicationInit { 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /jwt-auth/basic-authentication/src/main/java/org/eclipse/microprofile12/jwtauth/basic/Servlet.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.jwtauth.basic; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.annotation.security.DeclareRoles; 6 | import javax.servlet.ServletException; 7 | import javax.servlet.annotation.HttpConstraint; 8 | import javax.servlet.annotation.ServletSecurity; 9 | import javax.servlet.annotation.WebServlet; 10 | import javax.servlet.http.HttpServlet; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | 14 | 15 | @WebServlet("/servlet") 16 | @ServletSecurity(@HttpConstraint(rolesAllowed = "architect")) 17 | @DeclareRoles({"architect", "bar", "kaz"}) 18 | public class Servlet extends HttpServlet { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | @Override 23 | public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 24 | 25 | String webName = null; 26 | if (request.getUserPrincipal() != null) { 27 | webName = request.getUserPrincipal().getName(); 28 | } 29 | 30 | response.setContentType("text/plain"); 31 | 32 | response.getWriter().write( 33 | "This is a protected servlet \n" + 34 | 35 | "web username: " + webName + "\n" + 36 | 37 | "web user has role \"architect\": " + request.isUserInRole("architect") + "\n" + 38 | "web user has role \"bar\": " + request.isUserInRole("bar") + "\n" + 39 | "web user has role \"kaz\": " + request.isUserInRole("kaz") + "\n" 40 | ); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /jwt-auth/basic-authentication/src/main/resources/META-INF/MP-JWT-SIGNER: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEq 3 | Fyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwR 4 | TYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5e 5 | UF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9 6 | AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYn 7 | sIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9x 8 | nQIDAQAB 9 | -----END RSA PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /jwt-auth/basic-authentication/src/main/resources/jwt-roles.properties: -------------------------------------------------------------------------------- 1 | foo=bar -------------------------------------------------------------------------------- /jwt-auth/basic-authentication/src/main/resources/payara-mp-jwt.properties: -------------------------------------------------------------------------------- 1 | accepted.issuer=org.eclipse.microprofile12 2 | -------------------------------------------------------------------------------- /jwt-auth/basic-authentication/src/main/resources/project-defaults.yml: -------------------------------------------------------------------------------- 1 | # A project defaults for use with MP-JWT auth-method 2 | # Based on https://github.com/MicroProfileJWT/wfswarm-jwt-auth-tck/blob/master/src/main/resources/project-defaults.yml 3 | swarm: 4 | bind: 5 | address: localhost 6 | microprofile: 7 | jwtauth: 8 | token: 9 | issuedBy: "org.eclipse.microprofile12" 10 | logging: 11 | loggers: 12 | io.undertow.request.security: 13 | level: TRACE 14 | security: 15 | security-domains: 16 | MP-JWT: 17 | jaspi-authentication: 18 | login-module-stacks: 19 | roles-lm-stack: 20 | login-modules: 21 | # This stack performs the token verification and group to role mapping 22 | - login-module: rm 23 | code: org.wildfly.swarm.microprofile.jwtauth.deployment.auth.jaas.JWTLoginModule 24 | flag: required 25 | module-options: 26 | rolesProperties: jwt-roles.properties 27 | auth-modules: 28 | # This module integrates the MP-JWT custom authentication mechanism into the web container 29 | http: 30 | code: org.wildfly.extension.undertow.security.jaspi.modules.HTTPSchemeServerAuthModule 31 | module: org.wildfly.extension.undertow 32 | flag: required 33 | login-module-stack-ref: roles-lm-stack -------------------------------------------------------------------------------- /jwt-auth/basic-authentication/src/main/resources/publicKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEq 3 | Fyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwR 4 | TYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5e 5 | UF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9 6 | AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYn 7 | sIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9x 8 | nQIDAQAB 9 | -----END RSA PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /jwt-auth/basic-authentication/src/test/java/org/eclipse/microprofile12/jwtauth/basic/BasicAuthenticationTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.jwtauth.basic; 2 | 3 | import static javax.ws.rs.client.ClientBuilder.newClient; 4 | import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; 5 | import static javax.ws.rs.core.MediaType.TEXT_PLAIN; 6 | import static org.eclipse.microprofile12.JwtTokenGenerator.generateJWTString; 7 | import static org.jboss.shrinkwrap.api.ShrinkWrap.create; 8 | import static org.junit.Assert.assertFalse; 9 | import static org.junit.Assert.assertTrue; 10 | 11 | import java.io.IOException; 12 | import java.net.URI; 13 | import java.net.URL; 14 | 15 | import javax.ws.rs.core.Response; 16 | 17 | import org.eclipse.microprofile12.jwtauth.basic.ApplicationInit; 18 | import org.eclipse.microprofile12.jwtauth.basic.Servlet; 19 | import org.jboss.arquillian.container.test.api.Deployment; 20 | import org.jboss.arquillian.container.test.api.RunAsClient; 21 | import org.jboss.arquillian.junit.Arquillian; 22 | import org.jboss.arquillian.test.api.ArquillianResource; 23 | import org.jboss.shrinkwrap.api.spec.WebArchive; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | 27 | /** 28 | * @author Arjan Tijms 29 | */ 30 | @RunWith(Arquillian.class) 31 | public class BasicAuthenticationTest { 32 | 33 | @ArquillianResource 34 | private URL base; 35 | 36 | @Deployment(testable = false) 37 | public static WebArchive createDeployment() { 38 | WebArchive archive = 39 | create(WebArchive.class) 40 | .addClasses( 41 | ApplicationInit.class, 42 | Servlet.class 43 | ).addAsResource( 44 | // Payara Properties file configuring that "org.eclipse.microprofile12" is the valid issuer 45 | "payara-mp-jwt.properties" 46 | ).addAsResource( 47 | // WildFly file configuring that "org.eclipse.microprofile12" is the valid issuer and setting up 48 | // the security system (domain) such that all artifacts to support MP-Auth JWT are installed 49 | "project-defaults.yml" 50 | ).addAsResource( 51 | // Payara public key to verify the incoming signed JWT's signature 52 | "publicKey.pem" 53 | ).addAsResource( 54 | // WildFly public key to verify the incoming signed JWT's signature 55 | "META-INF/MP-JWT-SIGNER" 56 | ).addAsResource( 57 | // WildFly public key to verify the incoming signed JWT's signature 58 | "jwt-roles.properties" 59 | ) 60 | ; 61 | 62 | System.out.println("************************************************************"); 63 | System.out.println(archive.toString(true)); 64 | System.out.println("************************************************************"); 65 | 66 | return archive; 67 | 68 | } 69 | 70 | @Test 71 | @RunAsClient 72 | public void testProtectedPageNotLoggedin() throws IOException { 73 | 74 | Response response = 75 | newClient() 76 | .target( 77 | URI.create(new URL(base, "servlet").toExternalForm())) 78 | .request(TEXT_PLAIN) 79 | .get(); 80 | 81 | // Not logged-in thus should not be accessible. 82 | assertFalse( 83 | "Not authenticated, so should not have been able to access protected resource", 84 | response.readEntity(String.class).contains("This is a protected servlet") 85 | ); 86 | } 87 | 88 | @Test 89 | @RunAsClient 90 | public void testProtectedPageLoggedin() throws Exception { 91 | 92 | String response = 93 | newClient() 94 | .target( 95 | URI.create(new URL(base, "servlet").toExternalForm())) 96 | .request(TEXT_PLAIN) 97 | .header(AUTHORIZATION, "Bearer " + generateJWTString("jwt-token.json")) 98 | .get(String.class); 99 | 100 | // Now has to be logged-in so page is accessible 101 | assertTrue( 102 | "Should have been authenticated, but could not access protected resource", 103 | response.contains("This is a protected servlet") 104 | ); 105 | 106 | // Not only does the page needs to be accessible, the caller should have 107 | // the correct name and roles as well 108 | 109 | // Being able to access a page protected by a role but then seeing the un-authenticated 110 | // (anonymous) user would normally be impossible, but could happen if the authorization 111 | // system checks roles on the authenticated subject, but does not correctly expose 112 | // or propagate these to the HttpServletRequest 113 | assertFalse( 114 | "Protected resource could be accessed, but the user appears to be the unauthenticated user. " + 115 | "This should not be possible", 116 | response.contains("web username: null") 117 | ); 118 | 119 | // An authenticated user should have the exact name "test" and nothing else. 120 | assertTrue( 121 | "Protected resource could be accessed, but the username is not correct.", 122 | response.contains("web username: test") 123 | ); 124 | 125 | // Being able to access a page protected by role "architect" but failing 126 | // the test for this role would normally be impossible, but could happen if the 127 | // authorization system checks roles on the authenticated subject, but does not 128 | // correctly expose or propagate these to the HttpServletRequest 129 | assertTrue( 130 | "Resource protected by role \"architect\" could be accessed, but user fails test for this role." + 131 | "This should not be possible", 132 | response.contains("web user has role \"architect\": true") 133 | ); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /jwt-auth/basic-authentication/src/test/resources/jwt-token.json: -------------------------------------------------------------------------------- 1 | { 2 | "iss": "org.eclipse.microprofile12", 3 | "jti": "a-123", 4 | "sub": "24400320", 5 | "aud": "s6BhdRkqt3", 6 | "exp": 1311281970, 7 | "iat": 1311280970, 8 | "auth_time": 1311280969, 9 | "upn": "test", 10 | "groups": [ 11 | "architect", 12 | "master", 13 | "leader", 14 | "dev" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /jwt-auth/basic-authentication/src/test/resources/privateKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCWK8UjyoHgPTLa 3 | PLQJ8SoXLLjpHSjtLxMqmzHnFscqhTVVaDpCRCb6e3Ii/WniQTWw8RA7vf4djz4H 4 | OzvlfBFNgvUGZHXDwnmGaNVaNzpHYFMEYBhE8VGGiveSkzqeLZI+Y02G6sQAfDtN 5 | qqzM/l5QX8X34oQFaTBW1r49nftvCpITiwJvWyhkWtXP9RP8sXi1im5Vi3dhupOh 6 | nelk5n0BfajUYIbfHA6ORzjHRbt7NtBl0L2J+0/FUdHyKs6KMlFGNw8O0Dq88qnM 7 | uXoLJiewhg9332W3DFMeOveel+//cvDnRsCRtPgd4sXFPHh+UShkso7+DRsChXa6 8 | oGGQD3GdAgMBAAECggEAAjfTSZwMHwvIXIDZB+yP+pemg4ryt84iMlbofclQV8hv 9 | 6TsI4UGwcbKxFOM5VSYxbNOisb80qasb929gixsyBjsQ8284bhPJR7r0q8h1C+jY 10 | URA6S4pk8d/LmFakXwG9Tz6YPo3pJziuh48lzkFTk0xW2Dp4SLwtAptZY/+ZXyJ6 11 | 96QXDrZKSSM99Jh9s7a0ST66WoxSS0UC51ak+Keb0KJ1jz4bIJ2C3r4rYlSu4hHB 12 | Y73GfkWORtQuyUDa9yDOem0/z0nr6pp+pBSXPLHADsqvZiIhxD/O0Xk5I6/zVHB3 13 | zuoQqLERk0WvA8FXz2o8AYwcQRY2g30eX9kU4uDQAQKBgQDmf7KGImUGitsEPepF 14 | KH5yLWYWqghHx6wfV+fdbBxoqn9WlwcQ7JbynIiVx8MX8/1lLCCe8v41ypu/eLtP 15 | iY1ev2IKdrUStvYRSsFigRkuPHUo1ajsGHQd+ucTDf58mn7kRLW1JGMeGxo/t32B 16 | m96Af6AiPWPEJuVfgGV0iwg+HQKBgQCmyPzL9M2rhYZn1AozRUguvlpmJHU2DpqS 17 | 34Q+7x2Ghf7MgBUhqE0t3FAOxEC7IYBwHmeYOvFR8ZkVRKNF4gbnF9RtLdz0DMEG 18 | 5qsMnvJUSQbNB1yVjUCnDAtElqiFRlQ/k0LgYkjKDY7LfciZl9uJRl0OSYeX/qG2 19 | tRW09tOpgQKBgBSGkpM3RN/MRayfBtmZvYjVWh3yjkI2GbHA1jj1g6IebLB9SnfL 20 | WbXJErCj1U+wvoPf5hfBc7m+jRgD3Eo86YXibQyZfY5pFIh9q7Ll5CQl5hj4zc4Y 21 | b16sFR+xQ1Q9Pcd+BuBWmSz5JOE/qcF869dthgkGhnfVLt/OQzqZluZRAoGAXQ09 22 | nT0TkmKIvlza5Af/YbTqEpq8mlBDhTYXPlWCD4+qvMWpBII1rSSBtftgcgca9XLB 23 | MXmRMbqtQeRtg4u7dishZVh1MeP7vbHsNLppUQT9Ol6lFPsd2xUpJDc6BkFat62d 24 | Xjr3iWNPC9E9nhPPdCNBv7reX7q81obpeXFMXgECgYEAmk2Qlus3OV0tfoNRqNpe 25 | Mb0teduf2+h3xaI1XDIzPVtZF35ELY/RkAHlmWRT4PCdR0zXDidE67L6XdJyecSt 26 | FdOUH8z5qUraVVebRFvJqf/oGsXc4+ex1ZKUTbY0wqY1y9E39yvB3MaTmZFuuqk8 27 | f3cg+fr8aou7pr9SHhJlZCU= 28 | -----END RSA PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /jwt-auth/jaxrs/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | org.eclipse.microprofile.samples12 6 | jwt-auth 7 | 1.0-SNAPSHOT 8 | 9 | 10 | jaxrs 11 | war 12 | MicroProfile 1.2: JWT-AUTH - JAX-RS 13 | 14 | 15 | -------------------------------------------------------------------------------- /jwt-auth/jaxrs/src/main/java/org/eclipse/microprofile12/jwtauth/jaxrs/ApplicationInit.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.jwtauth.jaxrs; 2 | 3 | import javax.annotation.security.DeclareRoles; 4 | import javax.ws.rs.ApplicationPath; 5 | import javax.ws.rs.core.Application; 6 | 7 | import org.eclipse.microprofile.auth.LoginConfig; 8 | 9 | @LoginConfig( 10 | authMethod = "MP-JWT", 11 | // Even though specified being only for HTTP Basic auth, JBoss/WildFly/Swarm mandates this 12 | // to refer to its proprietary "security domain" concept. 13 | realmName = "MP-JWT" 14 | ) 15 | @DeclareRoles({"architect", "bar", "kaz"}) 16 | @ApplicationPath("/") 17 | public class ApplicationInit extends Application { 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /jwt-auth/jaxrs/src/main/java/org/eclipse/microprofile12/jwtauth/jaxrs/Resource.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.jwtauth.jaxrs; 2 | 3 | import static javax.ws.rs.core.MediaType.TEXT_PLAIN; 4 | 5 | import java.security.Principal; 6 | 7 | import javax.annotation.security.RolesAllowed; 8 | import javax.enterprise.context.ApplicationScoped; 9 | import javax.inject.Inject; 10 | import javax.ws.rs.GET; 11 | import javax.ws.rs.Path; 12 | import javax.ws.rs.Produces; 13 | 14 | @ApplicationScoped 15 | @Path("/resource") 16 | @Produces(TEXT_PLAIN) 17 | public class Resource { 18 | 19 | @Inject 20 | private Principal principal; 21 | 22 | @GET 23 | @Path("/protected") 24 | @RolesAllowed("architect") 25 | public String protectedResource() { 26 | return 27 | "This is a protected resource \n" + 28 | "web username: " + principal.getName() + "\n"; 29 | } 30 | 31 | @GET 32 | @Path("public") 33 | public String publicResource() { 34 | return 35 | "This is a public resource \n" + 36 | "web username: " + principal.getName() + "\n"; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /jwt-auth/jaxrs/src/main/resources/jwt-roles.properties: -------------------------------------------------------------------------------- 1 | foo=bar -------------------------------------------------------------------------------- /jwt-auth/jaxrs/src/main/resources/payara-mp-jwt.properties: -------------------------------------------------------------------------------- 1 | accepted.issuer=org.eclipse.microprofile12 2 | -------------------------------------------------------------------------------- /jwt-auth/jaxrs/src/main/resources/project-defaults.yml: -------------------------------------------------------------------------------- 1 | # A project defaults for use with MP-JWT auth-method 2 | # Based on https://github.com/MicroProfileJWT/wfswarm-jwt-auth-tck/blob/master/src/main/resources/project-defaults.yml 3 | swarm: 4 | bind: 5 | address: localhost 6 | microprofile: 7 | jwt: 8 | default-missing-method-permissions-deny-access: false 9 | token: 10 | issued-by: "org.eclipse.microprofile12" 11 | signer-pub-key: classpath:publicKey.pem 12 | logging: 13 | loggers: 14 | io.undertow.request.security: 15 | level: TRACE 16 | security: 17 | security-domains: 18 | MP-JWT: 19 | jaspi-authentication: 20 | login-module-stacks: 21 | roles-lm-stack: 22 | login-modules: 23 | # This stack performs the token verification and group to role mapping 24 | - login-module: rm 25 | code: org.wildfly.swarm.microprofile.jwtauth.deployment.auth.jaas.JWTLoginModule 26 | flag: required 27 | module-options: 28 | rolesProperties: jwt-roles.properties 29 | auth-modules: 30 | # This module integrates the MP-JWT custom authentication mechanism into the web container 31 | http: 32 | code: org.wildfly.extension.undertow.security.jaspi.modules.HTTPSchemeServerAuthModule 33 | module: org.wildfly.extension.undertow 34 | flag: required 35 | login-module-stack-ref: roles-lm-stack 36 | -------------------------------------------------------------------------------- /jwt-auth/jaxrs/src/main/resources/publicKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEq 3 | Fyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwR 4 | TYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5e 5 | UF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9 6 | AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYn 7 | sIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9x 8 | nQIDAQAB 9 | -----END RSA PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /jwt-auth/jaxrs/src/test/java/org/eclipse/microprofile12/jwtauth/jaxrs/JaxRsTest.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12.jwtauth.jaxrs; 2 | 3 | import static javax.ws.rs.client.ClientBuilder.newClient; 4 | import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; 5 | import static javax.ws.rs.core.MediaType.TEXT_PLAIN; 6 | import static org.eclipse.microprofile12.JwtTokenGenerator.generateJWTString; 7 | import static org.jboss.shrinkwrap.api.ShrinkWrap.create; 8 | import static org.junit.Assert.assertFalse; 9 | import static org.junit.Assert.assertTrue; 10 | 11 | import java.io.IOException; 12 | import java.net.URI; 13 | import java.net.URL; 14 | 15 | import javax.ws.rs.core.Response; 16 | 17 | import org.jboss.arquillian.container.test.api.Deployment; 18 | import org.jboss.arquillian.container.test.api.RunAsClient; 19 | import org.jboss.arquillian.junit.Arquillian; 20 | import org.jboss.arquillian.test.api.ArquillianResource; 21 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 22 | import org.jboss.shrinkwrap.api.spec.WebArchive; 23 | import org.junit.Test; 24 | import org.junit.runner.RunWith; 25 | 26 | /** 27 | * @author Arjan Tijms 28 | */ 29 | @RunWith(Arquillian.class) 30 | public class JaxRsTest { 31 | 32 | @ArquillianResource 33 | private URL base; 34 | 35 | @Deployment(testable = false) 36 | public static WebArchive createDeployment() { 37 | WebArchive archive = 38 | create(WebArchive.class) 39 | .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") 40 | .addClasses( 41 | ApplicationInit.class, 42 | Resource.class 43 | ).addAsResource( 44 | // Payara Properties file configuring that "org.eclipse.microprofile12" is the valid issuer 45 | "payara-mp-jwt.properties" 46 | ).addAsResource( 47 | // Thorntail file configuring that "org.eclipse.microprofile12" is the valid issuer and setting up 48 | // the security system (domain) such that all artifacts to support MP-Auth JWT are installed 49 | "project-defaults.yml" 50 | ).addAsResource( 51 | // Payara/Thorntail public key to verify the incoming signed JWT's signature 52 | "publicKey.pem" 53 | ).addAsResource( 54 | // WildFly public key to verify the incoming signed JWT's signature 55 | "jwt-roles.properties" 56 | ) 57 | ; 58 | 59 | System.out.println("************************************************************"); 60 | System.out.println(archive.toString(true)); 61 | System.out.println("************************************************************"); 62 | 63 | return archive; 64 | 65 | } 66 | 67 | @Test 68 | @RunAsClient 69 | public void testProtectedResourceNotLoggedin() throws IOException { 70 | 71 | System.out.println("-------------------------------------------------------------------------"); 72 | System.out.println("Base URL: " + base); 73 | System.out.println("-------------------------------------------------------------------------"); 74 | 75 | Response response = 76 | newClient() 77 | .target( 78 | URI.create(new URL(base, "resource/protected").toExternalForm())) 79 | .request(TEXT_PLAIN) 80 | .get(); 81 | 82 | // Not logged-in thus should not be accessible. 83 | assertFalse( 84 | "Not authenticated, so should not have been able to access protected resource", 85 | response.readEntity(String.class).contains("This is a protected resource") 86 | ); 87 | } 88 | 89 | @Test 90 | @RunAsClient 91 | public void testPublicResourceNotLoggedin() throws IOException { 92 | 93 | Response response = 94 | newClient() 95 | .target( 96 | URI.create(new URL(base, "resource/public").toExternalForm())) 97 | .request(TEXT_PLAIN) 98 | .get(); 99 | 100 | // Public resource, no log-in needed 101 | assertTrue( 102 | "Public resource is not constrained (protected) so should be accessible without sending the JWT token", 103 | response.readEntity(String.class).contains("This is a public resource") 104 | ); 105 | } 106 | 107 | @Test 108 | @RunAsClient 109 | public void testProtectedResourceLoggedin() throws Exception { 110 | 111 | String response = 112 | newClient() 113 | .target( 114 | URI.create(new URL(base, "resource/protected").toExternalForm())) 115 | .request(TEXT_PLAIN) 116 | .header(AUTHORIZATION, "Bearer " + generateJWTString("jwt-token.json")) 117 | .get(String.class); 118 | 119 | 120 | System.out.println("-------------------------------------------------------------------------"); 121 | System.out.println("Response: " + response); 122 | System.out.println("-------------------------------------------------------------------------"); 123 | 124 | // Now has to be logged-in so page is accessible 125 | assertTrue( 126 | "Should have been authenticated, but could not access protected resource", 127 | response.contains("This is a protected resource") 128 | ); 129 | 130 | // Not only does the resource needs to be accessible, the caller should have 131 | // the correct name 132 | 133 | // Being able to access a page protected by a role but then seeing the un-authenticated 134 | // (anonymous) user would normally be impossible, but could happen if the authorization 135 | // system checks roles on the authenticated subject, but does not correctly expose 136 | // or propagate these to the injected Principal 137 | assertFalse( 138 | "Protected resource could be accessed, but the user appears to be the unauthenticated user. " + 139 | "This should not be possible", 140 | response.contains("web username: null") 141 | ); 142 | 143 | // An authenticated user should have the exact name "test" and nothing else. 144 | assertTrue( 145 | "Protected resource could be accessed, but the username is not correct.", 146 | response.contains("web username: test") 147 | ); 148 | 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /jwt-auth/jaxrs/src/test/resources/jwt-token.json: -------------------------------------------------------------------------------- 1 | { 2 | "iss": "org.eclipse.microprofile12", 3 | "jti": "a-123", 4 | "sub": "24400320", 5 | "aud": "s6BhdRkqt3", 6 | "exp": 1311281970, 7 | "iat": 1311280970, 8 | "auth_time": 1311280969, 9 | "upn": "test", 10 | "groups": [ 11 | "architect", 12 | "master", 13 | "leader", 14 | "dev" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /jwt-auth/jaxrs/src/test/resources/privateKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCWK8UjyoHgPTLa 3 | PLQJ8SoXLLjpHSjtLxMqmzHnFscqhTVVaDpCRCb6e3Ii/WniQTWw8RA7vf4djz4H 4 | OzvlfBFNgvUGZHXDwnmGaNVaNzpHYFMEYBhE8VGGiveSkzqeLZI+Y02G6sQAfDtN 5 | qqzM/l5QX8X34oQFaTBW1r49nftvCpITiwJvWyhkWtXP9RP8sXi1im5Vi3dhupOh 6 | nelk5n0BfajUYIbfHA6ORzjHRbt7NtBl0L2J+0/FUdHyKs6KMlFGNw8O0Dq88qnM 7 | uXoLJiewhg9332W3DFMeOveel+//cvDnRsCRtPgd4sXFPHh+UShkso7+DRsChXa6 8 | oGGQD3GdAgMBAAECggEAAjfTSZwMHwvIXIDZB+yP+pemg4ryt84iMlbofclQV8hv 9 | 6TsI4UGwcbKxFOM5VSYxbNOisb80qasb929gixsyBjsQ8284bhPJR7r0q8h1C+jY 10 | URA6S4pk8d/LmFakXwG9Tz6YPo3pJziuh48lzkFTk0xW2Dp4SLwtAptZY/+ZXyJ6 11 | 96QXDrZKSSM99Jh9s7a0ST66WoxSS0UC51ak+Keb0KJ1jz4bIJ2C3r4rYlSu4hHB 12 | Y73GfkWORtQuyUDa9yDOem0/z0nr6pp+pBSXPLHADsqvZiIhxD/O0Xk5I6/zVHB3 13 | zuoQqLERk0WvA8FXz2o8AYwcQRY2g30eX9kU4uDQAQKBgQDmf7KGImUGitsEPepF 14 | KH5yLWYWqghHx6wfV+fdbBxoqn9WlwcQ7JbynIiVx8MX8/1lLCCe8v41ypu/eLtP 15 | iY1ev2IKdrUStvYRSsFigRkuPHUo1ajsGHQd+ucTDf58mn7kRLW1JGMeGxo/t32B 16 | m96Af6AiPWPEJuVfgGV0iwg+HQKBgQCmyPzL9M2rhYZn1AozRUguvlpmJHU2DpqS 17 | 34Q+7x2Ghf7MgBUhqE0t3FAOxEC7IYBwHmeYOvFR8ZkVRKNF4gbnF9RtLdz0DMEG 18 | 5qsMnvJUSQbNB1yVjUCnDAtElqiFRlQ/k0LgYkjKDY7LfciZl9uJRl0OSYeX/qG2 19 | tRW09tOpgQKBgBSGkpM3RN/MRayfBtmZvYjVWh3yjkI2GbHA1jj1g6IebLB9SnfL 20 | WbXJErCj1U+wvoPf5hfBc7m+jRgD3Eo86YXibQyZfY5pFIh9q7Ll5CQl5hj4zc4Y 21 | b16sFR+xQ1Q9Pcd+BuBWmSz5JOE/qcF869dthgkGhnfVLt/OQzqZluZRAoGAXQ09 22 | nT0TkmKIvlza5Af/YbTqEpq8mlBDhTYXPlWCD4+qvMWpBII1rSSBtftgcgca9XLB 23 | MXmRMbqtQeRtg4u7dishZVh1MeP7vbHsNLppUQT9Ol6lFPsd2xUpJDc6BkFat62d 24 | Xjr3iWNPC9E9nhPPdCNBv7reX7q81obpeXFMXgECgYEAmk2Qlus3OV0tfoNRqNpe 25 | Mb0teduf2+h3xaI1XDIzPVtZF35ELY/RkAHlmWRT4PCdR0zXDidE67L6XdJyecSt 26 | FdOUH8z5qUraVVebRFvJqf/oGsXc4+ex1ZKUTbY0wqY1y9E39yvB3MaTmZFuuqk8 27 | f3cg+fr8aou7pr9SHhJlZCU= 28 | -----END RSA PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /jwt-auth/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | org.eclipse.microprofile.samples12 6 | samples-parent 7 | 1.0-SNAPSHOT 8 | 9 | 10 | jwt-auth 11 | pom 12 | 13 | MicroProfile 1.2: JWT-AUTH 14 | 15 | 16 | basic-authentication 17 | jaxrs 18 | 19 | 20 | 21 | 22 | org.eclipse.microprofile.samples12 23 | test-utils 24 | ${project.version} 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /metrics/application-metrics/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | org.eclipse.microprofile.samples12 8 | metrics 9 | 1.0-SNAPSHOT 10 | 11 | 12 | application-metrics 13 | war 14 | MicroProfile 1.2: Metrics - Application Metrics 15 | 16 | 17 | -------------------------------------------------------------------------------- /metrics/application-metrics/src/main/java/org/eclipse/microprofile12/metrics/application/ApplicationInit.java: -------------------------------------------------------------------------------- 1 | /** Copyright Payara Services Limited **/ 2 | 3 | package org.eclipse.microprofile12.metrics.application; 4 | 5 | import javax.ws.rs.ApplicationPath; 6 | import javax.ws.rs.core.Application; 7 | 8 | /** 9 | * @author Gaurav Gupta 10 | */ 11 | @ApplicationPath("/") 12 | public class ApplicationInit extends Application { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /metrics/application-metrics/src/main/java/org/eclipse/microprofile12/metrics/application/UserResource.java: -------------------------------------------------------------------------------- 1 | /** Copyright Payara Services Limited **/ 2 | 3 | package org.eclipse.microprofile12.metrics.application; 4 | 5 | import static java.util.Arrays.asList; 6 | import java.util.List; 7 | import javax.enterprise.context.ApplicationScoped; 8 | import javax.ws.rs.GET; 9 | import javax.ws.rs.Path; 10 | import javax.ws.rs.core.Response; 11 | import org.eclipse.microprofile.metrics.MetricUnits; 12 | import org.eclipse.microprofile.metrics.annotation.Counted; 13 | import org.eclipse.microprofile.metrics.annotation.Gauge; 14 | 15 | /** 16 | * @author Gaurav Gupta 17 | */ 18 | @ApplicationScoped 19 | @Path("/user") 20 | public class UserResource { 21 | 22 | private final List users = asList("Arjan", "Gaurav", "Mert", "Mike", "Ondrej"); 23 | 24 | @GET 25 | @Path("/all") 26 | @Counted(monotonic = true) 27 | public Response getUsers() { 28 | return Response 29 | .ok(users) 30 | .build(); 31 | } 32 | 33 | @GET 34 | @Path("/count") 35 | @Gauge(unit = MetricUnits.NONE) 36 | public int getUserCount() { 37 | return users.size(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /metrics/application-metrics/src/test/java/org/eclipse/microprofile12/metrics/application/ApplicationMetricsTest.java: -------------------------------------------------------------------------------- 1 | /** Copyright Payara Services Limited **/ 2 | 3 | package org.eclipse.microprofile12.metrics.application; 4 | 5 | import static javax.ws.rs.client.ClientBuilder.newClient; 6 | import static javax.ws.rs.core.MediaType.TEXT_PLAIN; 7 | import static org.jboss.shrinkwrap.api.ShrinkWrap.create; 8 | import static org.junit.Assert.assertTrue; 9 | import java.io.IOException; 10 | import java.io.StringReader; 11 | import java.net.URI; 12 | import java.net.URL; 13 | import javax.json.Json; 14 | import javax.json.JsonObject; 15 | import javax.json.JsonReader; 16 | import javax.ws.rs.client.WebTarget; 17 | import static javax.ws.rs.core.MediaType.APPLICATION_JSON; 18 | import javax.ws.rs.core.Response; 19 | import org.jboss.arquillian.container.test.api.Deployment; 20 | import org.jboss.arquillian.container.test.api.RunAsClient; 21 | import org.jboss.arquillian.junit.Arquillian; 22 | import org.jboss.arquillian.junit.InSequence; 23 | import org.jboss.arquillian.test.api.ArquillianResource; 24 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 25 | import org.jboss.shrinkwrap.api.spec.WebArchive; 26 | import static org.junit.Assert.assertEquals; 27 | import org.junit.Before; 28 | import org.junit.Test; 29 | import org.junit.runner.RunWith; 30 | 31 | /** 32 | * @author Gaurav Gupta 33 | */ 34 | @RunWith(Arquillian.class) 35 | public class ApplicationMetricsTest { 36 | 37 | @ArquillianResource 38 | private URL base; 39 | 40 | @Deployment(testable = false) 41 | public static WebArchive createDeployment() { 42 | WebArchive archive 43 | = create(WebArchive.class) 44 | .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") 45 | .addClass(ApplicationInit.class) 46 | .addClass(UserResource.class); 47 | 48 | System.out.println("************************************************************"); 49 | System.out.println(archive.toString(true)); 50 | System.out.println("************************************************************"); 51 | 52 | return archive; 53 | } 54 | 55 | @Before 56 | public void init() throws IOException{ 57 | invokeUserResource(); 58 | } 59 | 60 | @Test 61 | @InSequence(1) 62 | @RunAsClient 63 | public void testBasePrometheusMetrics() throws IOException { 64 | Response response 65 | = getApplicationMetricTarget() 66 | .request(TEXT_PLAIN) 67 | .get(); 68 | String responseText = response.readEntity(String.class); 69 | System.out.println("testBasePrometheusMetrics " + responseText); 70 | assertTrue(responseText.contains("# TYPE application:org_eclipse_microprofile12_metrics_application_user_resource_get_users counter") 71 | || responseText.contains("# TYPE application_org_eclipse_microprofile12_metrics_application_UserResource_getUsers_total counter")); 72 | assertTrue(responseText.contains("# TYPE application:org_eclipse_microprofile12_metrics_application_user_resource_get_user_count gauge") 73 | || responseText.contains("# TYPE application_org_eclipse_microprofile12_metrics_application_UserResource_getUserCount gauge")); 74 | } 75 | 76 | @Test 77 | @InSequence(2) 78 | @RunAsClient 79 | public void testBaseJsonMetrics() throws IOException { 80 | Response response 81 | = getApplicationMetricTarget() 82 | .request(APPLICATION_JSON) 83 | .get(); 84 | JsonObject jsonObject = Json 85 | .createReader(new StringReader(response.readEntity(String.class))) 86 | .readObject(); 87 | 88 | assertEquals(jsonObject.getInt("org.eclipse.microprofile12.metrics.application.UserResource.getUsers"), 2); 89 | assertEquals(jsonObject.getInt("org.eclipse.microprofile12.metrics.application.UserResource.getUserCount"), 5); 90 | } 91 | 92 | private WebTarget getApplicationMetricTarget() throws IOException { 93 | return newClient().target(URI.create(new URL(base, "/metrics/application").toExternalForm())); 94 | } 95 | 96 | private void invokeUserResource() throws IOException{ 97 | //invoke UserResource.getUsers 98 | newClient() 99 | .target(URI.create(new URL(base, "user/all").toExternalForm())) 100 | .request(APPLICATION_JSON) 101 | .get(); 102 | 103 | //invoke UserResource.getUserCount 104 | newClient() 105 | .target(URI.create(new URL(base, "user/count").toExternalForm())) 106 | .request(APPLICATION_JSON) 107 | .get(); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /metrics/base-metrics/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | org.eclipse.microprofile.samples12 8 | metrics 9 | 1.0-SNAPSHOT 10 | 11 | 12 | base-metrics 13 | war 14 | MicroProfile 1.2: Metrics - Base Metrics 15 | 16 | 17 | -------------------------------------------------------------------------------- /metrics/base-metrics/src/test/java/org/eclipse/microprofile12/metrics/base/BaseMetricsTest.java: -------------------------------------------------------------------------------- 1 | /** Copyright Payara Services Limited **/ 2 | 3 | package org.eclipse.microprofile12.metrics.base; 4 | 5 | import static javax.ws.rs.client.ClientBuilder.newClient; 6 | import static javax.ws.rs.core.MediaType.TEXT_PLAIN; 7 | import static org.jboss.shrinkwrap.api.ShrinkWrap.create; 8 | import static org.junit.Assert.assertTrue; 9 | import java.io.IOException; 10 | import java.io.StringReader; 11 | import java.net.MalformedURLException; 12 | import java.net.URI; 13 | import java.net.URL; 14 | import javax.json.Json; 15 | import javax.json.JsonObject; 16 | import javax.ws.rs.client.WebTarget; 17 | import static javax.ws.rs.core.MediaType.APPLICATION_JSON; 18 | import javax.ws.rs.core.Response; 19 | import org.jboss.arquillian.container.test.api.Deployment; 20 | import org.jboss.arquillian.container.test.api.RunAsClient; 21 | import org.jboss.arquillian.junit.Arquillian; 22 | import org.jboss.arquillian.test.api.ArquillianResource; 23 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 24 | import org.jboss.shrinkwrap.api.spec.WebArchive; 25 | import org.junit.Test; 26 | import org.junit.runner.RunWith; 27 | 28 | /** 29 | * @author Gaurav Gupta 30 | */ 31 | @RunWith(Arquillian.class) 32 | public class BaseMetricsTest { 33 | 34 | @ArquillianResource 35 | private URL base; 36 | 37 | @Deployment(testable = false) 38 | public static WebArchive createDeployment() { 39 | WebArchive archive 40 | = create(WebArchive.class) 41 | .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); 42 | 43 | System.out.println("************************************************************"); 44 | System.out.println(archive.toString(true)); 45 | System.out.println("************************************************************"); 46 | 47 | return archive; 48 | } 49 | 50 | @Test 51 | @RunAsClient 52 | public void testBasePrometheusMetrics() throws IOException { 53 | Response response 54 | = getBaseMetricTarget() 55 | .request(TEXT_PLAIN) 56 | .get(); 57 | String responseText = response.readEntity(String.class); 58 | assertTrue(responseText.contains("# TYPE base:thread_max_count") 59 | || responseText.contains("# TYPE base_thread_max_count")); 60 | assertTrue(responseText.contains("# TYPE base:thread_count") 61 | || responseText.contains("# TYPE base_thread_count")); 62 | assertTrue(responseText.contains("# TYPE base:cpu_system_load_average") 63 | || responseText.contains("# TYPE base_cpu_systemLoadAverage")); 64 | assertTrue(responseText.contains("# TYPE base:jvm_uptime") 65 | || responseText.contains("# TYPE base_jvm_uptime_seconds")); 66 | } 67 | 68 | @Test 69 | @RunAsClient 70 | public void testBaseJsonMetrics() throws IOException { 71 | Response response 72 | = getBaseMetricTarget() 73 | .request(APPLICATION_JSON) 74 | .get(); 75 | JsonObject jsonObject = Json 76 | .createReader(new StringReader(response.readEntity(String.class))) 77 | .readObject(); 78 | assertTrue(jsonObject.containsKey("thread.max.count")); 79 | assertTrue(jsonObject.containsKey("thread.count")); 80 | assertTrue(jsonObject.containsKey("cpu.systemLoadAverage")); 81 | assertTrue(jsonObject.containsKey("jvm.uptime")); 82 | } 83 | 84 | private WebTarget getBaseMetricTarget() throws MalformedURLException { 85 | return newClient().target(URI.create(new URL(base, "/metrics/base").toExternalForm())); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /metrics/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | org.eclipse.microprofile.samples12 8 | samples-parent 9 | 1.0-SNAPSHOT 10 | 11 | 12 | metrics 13 | pom 14 | 15 | MicroProfile 1.2: Metrics 16 | 17 | 18 | base-metrics 19 | application-metrics 20 | 21 | 22 | 23 | 24 | org.eclipse.microprofile.samples12 25 | test-utils 26 | ${project.version} 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 4.0.0 8 | 9 | 10 | 3.5 11 | 12 | 13 | org.eclipse.microprofile.samples12 14 | samples-parent 15 | 1.0-SNAPSHOT 16 | pom 17 | 18 | Eclipse MicroProfile 1.2 Samples: root 19 | 20 | 21 | 1.8 22 | 3.5 23 | UTF-8 24 | 25 | false 26 | false 27 | 28 | ${skipTests} 29 | ${skipTests} 30 | ${skipTests} 31 | ${skipTests} 32 | 33 | 35 | 5.182-SNAPSHOT 36 | 5.182-SNAPSHOT 37 | 17.0.0.4 38 | 2.3.0.Final 39 | 40 | 1.0.Beta3 41 | 5.Beta3-m3 42 | 43 | 44 | 45 | 46 | central 47 | Central Repository 48 | 49 | https://repo.maven.apache.org/maven2 50 | 51 | 52 | true 53 | 54 | 55 | false 56 | 57 | 58 | 59 | 60 | payara-milestones 61 | Payara Milestones 62 | https://raw.github.com/payara/Payara_PatchedProjects/master 63 | 64 | true 65 | 66 | 67 | false 68 | 69 | 70 | 71 | 72 | ossrh 73 | Sonatype-snapshot 74 | https://oss.sonatype.org/content/repositories/snapshots 75 | 76 | false 77 | 78 | 79 | true 80 | 81 | 82 | 83 | 84 | jvnet-nexus-staging 85 | Java.net Staging Repositories 86 | https://maven.java.net/content/repositories/staging 87 | 88 | true 89 | 90 | 91 | false 92 | 93 | 94 | 95 | 96 | 97 | 98 | 100 | 101 | config 102 | fault-tolerance 103 | jwt-auth 104 | metrics 105 | test-utils 106 | 107 | 108 | 109 | 110 | 111 | org.jboss.arquillian 112 | arquillian-bom 113 | 1.4.0.Final 114 | import 115 | pom 116 | 117 | 118 | org.jboss.arquillian.container 119 | arquillian-container-test-api 120 | 1.4.0.Final 121 | 122 | 123 | com.h2database 124 | h2 125 | 1.4.197 126 | 127 | 128 | fish.payara.arquillian 129 | payara-client-ee7 130 | 1.0.Beta3-m3 131 | test 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | javax 140 | javaee-api 141 | 7.0 142 | provided 143 | 144 | 145 | 146 | org.eclipse.microprofile.config 147 | microprofile-config-api 148 | 1.1 149 | provided 150 | 151 | 152 | org.eclipse.microprofile.fault-tolerance 153 | microprofile-fault-tolerance-api 154 | 1.0 155 | provided 156 | 157 | 158 | org.eclipse.microprofile.jwt 159 | microprofile-jwt-auth-api 160 | 1.0 161 | provided 162 | 163 | 164 | org.eclipse.microprofile.metrics 165 | microprofile-metrics-api 166 | 1.0 167 | provided 168 | 169 | 170 | 171 | 172 | 173 | junit 174 | junit 175 | 4.13.1 176 | test 177 | 178 | 179 | org.hamcrest 180 | hamcrest-core 181 | 1.3 182 | test 183 | 184 | 185 | org.hamcrest 186 | hamcrest-library 187 | 1.3 188 | test 189 | 190 | 191 | org.jboss.arquillian.junit 192 | arquillian-junit-container 193 | test 194 | 195 | 196 | org.jboss.arquillian.protocol 197 | arquillian-protocol-servlet 198 | test 199 | 200 | 201 | org.jboss.shrinkwrap.resolver 202 | shrinkwrap-resolver-impl-maven 203 | test 204 | jar 205 | 206 | 207 | org.jboss.shrinkwrap.resolver 208 | shrinkwrap-resolver-impl-maven-archive 209 | test 210 | 211 | 212 | xmlunit 213 | xmlunit 214 | 1.6 215 | test 216 | 217 | 218 | org.skyscreamer 219 | jsonassert 220 | 1.5.0 221 | test 222 | 223 | 224 | net.sourceforge.htmlunit 225 | htmlunit 226 | 2.30 227 | test 228 | 229 | 230 | rhino 231 | js 232 | 1.7R2 233 | test 234 | 235 | 236 | org.json 237 | json 238 | 20180130 239 | test 240 | 241 | 242 | com.jayway.awaitility 243 | awaitility 244 | 1.7.0 245 | test 246 | 247 | 248 | 249 | 250 | 251 | ${project.artifactId} 252 | 253 | 254 | 255 | src/test/resources 256 | true 257 | 258 | 259 | 260 | 261 | 262 | org.apache.maven.plugins 263 | maven-compiler-plugin 264 | 3.7.0 265 | 266 | ${java.min.version} 267 | ${java.min.version} 268 | 269 | 270 | 271 | org.apache.maven.plugins 272 | maven-surefire-report-plugin 273 | 2.21.0 274 | 275 | true 276 | true 277 | 278 | 279 | 280 | org.apache.maven.plugins 281 | maven-surefire-plugin 282 | 2.21.0 283 | 284 | 285 | javax.annotation 286 | javax.annotation-api 287 | 1.3.2 288 | 289 | 290 | 291 | 292 | org.apache.maven.plugins 293 | maven-war-plugin 294 | 3.2.0 295 | 296 | true 297 | false 298 | 299 | 300 | 301 | org.apache.maven.plugins 302 | maven-enforcer-plugin 303 | 3.0.0-M1 304 | 305 | 306 | 307 | At least Maven in version 308 | ${maven.min.version} is 309 | required. 310 | ${maven.min.version} 311 | 312 | 313 | At least a JDK in version 314 | ${java.min.version} is 315 | required. 316 | ${java.min.version} 317 | 318 | 319 | 320 | 321 | 322 | 323 | enforce 324 | 325 | 326 | 327 | 328 | 329 | org.apache.maven.plugins 330 | maven-dependency-plugin 331 | 3.1.0 332 | 333 | 334 | org.apache.maven.plugins 335 | maven-resources-plugin 336 | 3.0.2 337 | 338 | 339 | org.wildfly.plugins 340 | wildfly-maven-plugin 341 | 1.2.1.Final 342 | 343 | 344 | 345 | 346 | 347 | 348 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | payara-ci-managed 359 | 360 | 361 | true 362 | 363 | 364 | 365 | 366 | fish.payara.arquillian 367 | payara-client-ee7 368 | 369 | 370 | 371 | 372 | fish.payara.arquillian 373 | arquillian-payara-server-4-managed 374 | ${payara.container.version} 375 | test 376 | 377 | 378 | 379 | 380 | 381 | 382 | org.apache.maven.plugins 383 | maven-dependency-plugin 384 | 385 | 386 | unpack 387 | process-test-classes 388 | 389 | unpack 390 | 391 | 392 | ${session.executionRootDirectory}/target 393 | ${session.executionRootDirectory}/target/dependency-maven-plugin-markers 394 | 395 | 396 | fish.payara.distributions 397 | payara-web 398 | ${payara.version} 399 | zip 400 | false 401 | ${session.executionRootDirectory}/target 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | org.apache.maven.plugins 410 | maven-surefire-plugin 411 | 412 | 413 | 414 | javax.annotation 415 | javax.annotation-api 416 | 1.3.1 417 | 418 | 419 | 420 | ${session.executionRootDirectory}/target/payara5 421 | 422 | 423 | 424 | ${session.executionRootDirectory}/target/payara5 425 | payara-remote 426 | payara 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | payara-micro-managed 436 | 437 | 438 | true 439 | true 440 | 441 | 442 | 443 | 445 | 446 | fish.payara.arquillian 447 | payara-client-ee7 448 | 449 | 450 | 451 | 452 | fish.payara.arquillian 453 | arquillian-payara-micro-5-managed 454 | ${payara.container.version} 455 | test 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | org.apache.maven.plugins 464 | maven-dependency-plugin 465 | 466 | 467 | process-test-classes 468 | 469 | copy 470 | 471 | 472 | 473 | 474 | fish.payara.extras 475 | payara-micro 476 | ${payara.micro.version} 477 | false 478 | ${session.executionRootDirectory}/target/ 479 | payara-micro-${payara.micro.version}.jar 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | maven-surefire-plugin 489 | 490 | 491 | ${session.executionRootDirectory}/target/payara-micro-${payara.micro.version}.jar 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | payara-remote 501 | 502 | 503 | 504 | fish.payara.arquillian 505 | payara-client-ee7 506 | 507 | 508 | 509 | 510 | fish.payara.arquillian 511 | arquillian-payara-server-4-remote 512 | ${payara.container.version} 513 | test 514 | 515 | 516 | 517 | 518 | 519 | maven-surefire-plugin 520 | 521 | 522 | payara-remote 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | liberty-ci-managed 536 | 537 | 538 | 539 | fish.payara.arquillian 540 | payara-client-ee7 541 | 542 | 543 | 544 | org.jboss.arquillian.container 545 | arquillian-wlp-managed-8.5 546 | 1.0.0.CR1 547 | test 548 | 549 | 550 | 551 | 552 | 553 | 554 | org.apache.maven.plugins 555 | maven-dependency-plugin 556 | 557 | 558 | unpack 559 | test-compile 560 | 561 | unpack 562 | 563 | 564 | 565 | 566 | 567 | io.openliberty 568 | openliberty-runtime 569 | ${liberty.version} 570 | 571 | 572 | 574 | zip 575 | false 576 | ${session.executionRootDirectory}/target/ 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | org.apache.maven.plugins 585 | maven-antrun-plugin 586 | 1.8 587 | 588 | 589 | unpack 590 | process-test-classes 591 | 592 | run 593 | 594 | 595 | 596 | 598 | Copying server.xml 599 | 602 | Copying key.jks 603 | 605 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | org.apache.maven.plugins 615 | maven-surefire-plugin 616 | 617 | 618 | liberty-ci-managed 619 | 620 | ${session.executionRootDirectory}/target/wlp 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | thorntail 634 | 635 | 636 | 637 | 638 | io.thorntail 639 | bom 640 | ${thorntail.version} 641 | import 642 | pom 643 | 644 | 645 | 646 | 647 | 648 | 649 | 651 | 652 | io.thorntail 653 | arquillian 654 | test 655 | 656 | 657 | io.thorntail 658 | microprofile 659 | 660 | 661 | 662 | 663 | 664 | 665 | maven-surefire-plugin 666 | 667 | 668 | 669 | 670 | arquillian-thorntail.xml 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | nothing 680 | 681 | 682 | 685 | 686 | javadocs 687 | 688 | 689 | javadocs 690 | 691 | 692 | 693 | 694 | 695 | org.apache.maven.plugins 696 | maven-dependency-plugin 697 | 2.4 698 | 699 | 700 | sources 701 | process-resources 702 | 703 | sources 704 | resolve 705 | 706 | 707 | javadoc 708 | false 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | org.apache.maven.plugins 722 | maven-surefire-report-plugin 723 | 2.19.1 724 | 725 | true 726 | true 727 | 728 | 729 | 730 | 731 | 732 | 733 | -------------------------------------------------------------------------------- /test-utils/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.eclipse.microprofile.samples12 8 | samples-parent 9 | 1.0-SNAPSHOT 10 | 11 | 12 | test-utils 13 | MicroProfile 1.2: test-utils 14 | 15 | 16 | 17 | junit 18 | junit 19 | 4.13.1 20 | 21 | 22 | org.jboss.arquillian.container 23 | arquillian-container-test-api 24 | 25 | 26 | org.jboss.shrinkwrap.resolver 27 | shrinkwrap-resolver-api-maven 28 | 29 | 30 | com.nimbusds 31 | nimbus-jose-jwt 32 | 5.1 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /test-utils/src/main/java/org/eclipse/microprofile12/CliCommands.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12; 2 | 3 | import static java.lang.Runtime.getRuntime; 4 | import static java.lang.Thread.currentThread; 5 | 6 | import java.io.IOException; 7 | import java.nio.file.Path; 8 | import java.nio.file.Paths; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Scanner; 12 | import java.util.logging.Logger; 13 | 14 | /** 15 | * Methods to execute "cli commands" against various servers. 16 | * 17 | * @author Arjan Tijms 18 | * 19 | */ 20 | public class CliCommands { 21 | 22 | private static final Logger logger = Logger.getLogger(CliCommands.class.getName()); 23 | private static final String OS = System.getProperty("os.name").toLowerCase(); 24 | 25 | public static int payaraGlassFish(List cliCommands) { 26 | 27 | String gfHome = System.getProperty("glassfishRemote_gfHome"); 28 | if (gfHome == null) { 29 | logger.info("glassfishRemote_gfHome not specified"); 30 | return -1; 31 | } 32 | 33 | Path gfHomePath = Paths.get(gfHome); 34 | if (!gfHomePath.toFile().exists()) { 35 | logger.severe("glassfishRemote_gfHome at " + gfHome + " does not exists"); 36 | return -1; 37 | } 38 | 39 | if (!gfHomePath.toFile().isDirectory()) { 40 | logger.severe("glassfishRemote_gfHome at " + gfHome + " is not a directory"); 41 | return -1; 42 | } 43 | 44 | Path asadminPath = gfHomePath.resolve(isWindows()? "bin/asadmin.bat" : "bin/asadmin"); 45 | 46 | if (!asadminPath.toFile().exists()) { 47 | logger.severe("asadmin command at " + asadminPath.toAbsolutePath() + " does not exists"); 48 | return -1; 49 | } 50 | 51 | List cmd = new ArrayList<>(); 52 | 53 | cmd.add(asadminPath.toAbsolutePath().toString()); 54 | cmd.addAll(cliCommands); 55 | 56 | ProcessBuilder processBuilder = new ProcessBuilder(cmd); 57 | processBuilder.redirectErrorStream(true); 58 | 59 | try { 60 | return 61 | waitToFinish( 62 | readAllInput( 63 | destroyAtShutDown( 64 | processBuilder.start()))); 65 | } catch (IOException e) { 66 | return -1; 67 | } 68 | } 69 | 70 | public static Process destroyAtShutDown(final Process process) { 71 | getRuntime().addShutdownHook(new Thread(new Runnable() { 72 | @Override 73 | public void run() { 74 | if (process != null) { 75 | process.destroy(); 76 | try { 77 | process.waitFor(); 78 | } catch (InterruptedException e) { 79 | currentThread().interrupt(); 80 | throw new RuntimeException(e); 81 | } 82 | } 83 | } 84 | })); 85 | 86 | return process; 87 | } 88 | 89 | public static Process readAllInput(Process process) { 90 | // Read any output from the process 91 | try (Scanner scanner = new Scanner(process.getInputStream())) { 92 | while (scanner.hasNextLine()) { 93 | System.out.println(scanner.nextLine()); 94 | } 95 | } 96 | 97 | return process; 98 | } 99 | 100 | public static int waitToFinish(Process process) { 101 | 102 | // Wait up to 30s for the process to finish 103 | int startupTimeout = 30 * 1000; 104 | while (startupTimeout > 0) { 105 | startupTimeout -= 200; 106 | try { 107 | Thread.sleep(200); 108 | } catch (InterruptedException e1) { 109 | // Ignore 110 | } 111 | 112 | try { 113 | int exitValue = process.exitValue(); 114 | 115 | System.out.println("Asadmin process exited with status " + exitValue); 116 | return exitValue; 117 | 118 | } catch (IllegalThreadStateException e) { 119 | // process is still running 120 | } 121 | } 122 | 123 | throw new IllegalStateException("Asadmin process seems stuck after waiting for 30 seconds"); 124 | } 125 | 126 | public static boolean isWindows() { 127 | return OS.contains("win"); 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /test-utils/src/main/java/org/eclipse/microprofile12/JwtTokenGenerator.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12; 2 | 3 | import static com.nimbusds.jose.JOSEObjectType.JWT; 4 | import static com.nimbusds.jose.JWSAlgorithm.RS256; 5 | import static com.nimbusds.jwt.JWTClaimsSet.parse; 6 | import static java.lang.Thread.currentThread; 7 | import static net.minidev.json.parser.JSONParser.DEFAULT_PERMISSIVE_MODE; 8 | 9 | import java.security.KeyFactory; 10 | import java.security.PrivateKey; 11 | import java.security.spec.PKCS8EncodedKeySpec; 12 | import java.util.Base64; 13 | 14 | import org.eclipse.microprofile.jwt.Claims; 15 | 16 | import com.nimbusds.jose.JWSHeader; 17 | import com.nimbusds.jose.crypto.RSASSASigner; 18 | import com.nimbusds.jwt.SignedJWT; 19 | 20 | import net.minidev.json.JSONObject; 21 | import net.minidev.json.parser.JSONParser; 22 | 23 | public class JwtTokenGenerator { 24 | 25 | public static String generateJWTString(String jsonResource) throws Exception { 26 | byte[] byteBuffer = new byte[16384]; 27 | currentThread().getContextClassLoader() 28 | .getResource(jsonResource) 29 | .openStream() 30 | .read(byteBuffer); 31 | 32 | JSONParser parser = new JSONParser(DEFAULT_PERMISSIVE_MODE); 33 | JSONObject jwtJson = (JSONObject) parser.parse(byteBuffer); 34 | 35 | long currentTimeInSecs = (System.currentTimeMillis() / 1000); 36 | long expirationTime = currentTimeInSecs + 1000; 37 | 38 | jwtJson.put(Claims.iat.name(), currentTimeInSecs); 39 | jwtJson.put(Claims.auth_time.name(), currentTimeInSecs); 40 | jwtJson.put(Claims.exp.name(), expirationTime); 41 | 42 | SignedJWT signedJWT = new SignedJWT(new JWSHeader 43 | .Builder(RS256) 44 | .keyID("/privateKey.pem") 45 | .type(JWT) 46 | .build(), parse(jwtJson)); 47 | 48 | signedJWT.sign(new RSASSASigner(readPrivateKey("privateKey.pem"))); 49 | 50 | return signedJWT.serialize(); 51 | } 52 | 53 | public static PrivateKey readPrivateKey(String resourceName) throws Exception { 54 | byte[] byteBuffer = new byte[16384]; 55 | int length = currentThread().getContextClassLoader() 56 | .getResource(resourceName) 57 | .openStream() 58 | .read(byteBuffer); 59 | 60 | String key = new String(byteBuffer, 0, length).replaceAll("-----BEGIN (.*)-----", "") 61 | .replaceAll("-----END (.*)----", "") 62 | .replaceAll("\r\n", "") 63 | .replaceAll("\n", "") 64 | .trim(); 65 | 66 | return KeyFactory.getInstance("RSA") 67 | .generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key))); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /test-utils/src/main/java/org/eclipse/microprofile12/Libraries.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12; 2 | 3 | import org.jboss.shrinkwrap.api.spec.JavaArchive; 4 | import org.jboss.shrinkwrap.resolver.api.maven.Maven; 5 | 6 | public class Libraries { 7 | 8 | public static JavaArchive[] awaitability() { 9 | return Maven.resolver() 10 | .loadPomFromFile("pom.xml") 11 | .resolve("com.jayway.awaitility:awaitility") 12 | .withTransitivity() 13 | .as(JavaArchive.class); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /test-utils/src/main/java/org/eclipse/microprofile12/Parameter.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.FIELD}) 10 | public @interface Parameter { 11 | } 12 | 13 | -------------------------------------------------------------------------------- /test-utils/src/main/java/org/eclipse/microprofile12/ParameterRule.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12; 2 | 3 | import org.jboss.arquillian.container.test.api.Deployment; 4 | 5 | import org.junit.rules.MethodRule; 6 | import org.junit.runners.model.FrameworkMethod; 7 | import org.junit.runners.model.Statement; 8 | 9 | import javax.naming.InitialContext; 10 | import javax.naming.NamingException; 11 | import java.lang.reflect.Field; 12 | import java.lang.reflect.Method; 13 | import java.util.List; 14 | 15 | /** 16 | * Helper class for Parametrized tests as described here: 17 | * http://blog.schauderhaft.de/2012/12/16/writing-parameterized-tests-with-junit-rules/ 18 | * 19 | * @param 20 | */ 21 | public class ParameterRule implements MethodRule { 22 | private final List params; 23 | 24 | public ParameterRule(List params) { 25 | if (params == null || params.size() == 0) { 26 | throw new IllegalArgumentException("'params' must be specified and have more then zero length!"); 27 | } 28 | this.params = params; 29 | } 30 | 31 | @Override 32 | public Statement apply(final Statement base, final FrameworkMethod method, final Object target) { 33 | return new Statement() { 34 | @Override 35 | public void evaluate() throws Throwable { 36 | boolean runInContainer = getDeploymentMethod(target).getAnnotation(Deployment.class).testable(); 37 | if (runInContainer) { 38 | evaluateParametersInContainer(base, target); 39 | } else { 40 | evaluateParametersInClient(base, target); 41 | } 42 | } 43 | }; 44 | } 45 | 46 | private Method getDeploymentMethod(Object target) throws NoSuchMethodException { 47 | Method[] methods = target.getClass().getDeclaredMethods(); 48 | for (Method method : methods) { 49 | if (method.getAnnotation(Deployment.class) != null) return method; 50 | } 51 | throw new IllegalStateException("No method with @Deployment annotation found!"); 52 | } 53 | 54 | private void evaluateParametersInContainer(Statement base, Object target) throws Throwable { 55 | if (isRunningInContainer()) { 56 | evaluateParamsToTarget(base, target); 57 | } else { 58 | ignoreStatementExecution(base); 59 | } 60 | } 61 | 62 | private void evaluateParametersInClient(Statement base, Object target) throws Throwable { 63 | if (isRunningInContainer()) { 64 | ignoreStatementExecution(base); 65 | } else { 66 | evaluateParamsToTarget(base, target); 67 | } 68 | } 69 | 70 | private boolean isRunningInContainer() { 71 | try { 72 | new InitialContext().lookup("java:comp/env"); 73 | return true; 74 | } catch (NamingException e) { 75 | return false; 76 | } 77 | } 78 | 79 | private void evaluateParamsToTarget(Statement base, Object target) throws Throwable { 80 | for (Object param : params) { 81 | Field targetField = getTargetField(target); 82 | if (!targetField.isAccessible()) { 83 | targetField.setAccessible(true); 84 | } 85 | targetField.set(target, param); 86 | base.evaluate(); 87 | } 88 | } 89 | 90 | private Field getTargetField(Object target) throws NoSuchFieldException { 91 | Field[] allFields = target.getClass().getDeclaredFields(); 92 | for (Field field : allFields) { 93 | if (field.getAnnotation(Parameter.class) != null) return field; 94 | } 95 | throw new IllegalStateException("No field with @Parameter annotation found! Forgot to add it?"); 96 | } 97 | 98 | private void ignoreStatementExecution(Statement base) { 99 | try { 100 | base.evaluate(); 101 | } catch (Throwable ignored) {} 102 | } 103 | } -------------------------------------------------------------------------------- /test-utils/src/main/java/org/eclipse/microprofile12/ServerOperations.java: -------------------------------------------------------------------------------- 1 | package org.eclipse.microprofile12; 2 | 3 | import java.nio.file.Paths; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /** 8 | * Various high level Java EE 7 samples specific operations to execute against 9 | * the various servers used for running the samples 10 | * 11 | * @author arjan 12 | * 13 | */ 14 | public class ServerOperations { 15 | 16 | /** 17 | * Add the default test user and credentials to the identity store of 18 | * supported containers 19 | */ 20 | public static void addUsersToContainerIdentityStore() { 21 | 22 | // TODO: abstract adding container managed users to utility class 23 | // TODO: consider PR for sending CLI commands to Arquillian 24 | 25 | String javaEEServer = System.getProperty("javaEEServer"); 26 | 27 | if ("glassfish-remote".equals(javaEEServer) || "payara-remote".equals(javaEEServer)) { 28 | 29 | System.out.println("Adding user for glassfish-remote"); 30 | 31 | List cmd = new ArrayList<>(); 32 | 33 | cmd.add("create-file-user"); 34 | cmd.add("--groups"); 35 | cmd.add("g1"); 36 | cmd.add("--passwordfile"); 37 | cmd.add(Paths.get("").toAbsolutePath() + "/src/test/resources/password.txt"); 38 | 39 | cmd.add("u1"); 40 | 41 | CliCommands.payaraGlassFish(cmd); 42 | } else { 43 | if (javaEEServer == null) { 44 | System.out.println("javaEEServer not specified"); 45 | } else { 46 | System.out.println(javaEEServer + " not supported"); 47 | } 48 | } 49 | 50 | // TODO: support other servers than Payara and GlassFish 51 | 52 | // WildFly ./bin/add-user.sh -a -u u1 -p p1 -g g1 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /test-utils/src/main/resources/arquillian-thorntail.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 11 | 12 | 13 | localhost 14 | ${thorntail.arquillian.daemon.port:12345} 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test-utils/src/main/resources/arquillian.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | production 11 | 12 | 13 | 14 | 15 | 16 | xml 17 | ${arquillian.liberty.wlpHome} 18 | 19 | 20 | 21 | 22 | 23 | xml 24 | ${arquillian.liberty.wlpHome} 25 | -Dwas.debug.mode=true -Dcom.ibm.websphere.ras.inject.at.transform=true -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /test-utils/src/main/resources/key.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaee-samples/microprofile1.2-samples/ea5b9f0d6a17d8eab847d6cb9e2dd2e07a71e90a/test-utils/src/main/resources/key.jks -------------------------------------------------------------------------------- /test-utils/src/main/resources/logging.properties: -------------------------------------------------------------------------------- 1 | handlers= java.util.logging.ConsoleHandler 2 | java.util.logging.ConsoleHandler.level = FINER 3 | 4 | org.jboss.arquillian.container.was.wlp_managed_8_5.WLPManagedContainer.level=FINER -------------------------------------------------------------------------------- /test-utils/src/main/resources/server.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | microProfile-1.2 7 | localConnector-1.0 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | --------------------------------------------------------------------------------