Chapter 11. The bootable JAR You can build and package a microservices application as a bootable JAR with the JBoss EAP JAR Maven plug-in. You can then run the application on a JBoss EAP bare-metal platform or a JBoss EAP OpenShift platform. 11.1. About the bootable JAR You can build and package a microservices application as a bootable JAR with the JBoss EAP JAR Maven plug-in. A bootable JAR contains a server, a packaged application, and the runtime required to launch the server. The JBoss EAP JAR Maven plug-in uses Galleon trimming capability to reduce the size and memory footprint of the server. Thus, you can configure the server according to your requirements, including only the Galleon layers that provide the capabilities that you need. The JBoss EAP JAR Maven plug-in supports the execution of JBoss EAP CLI script files to customize your server configuration. A CLI script includes a list of CLI commands for configuring the server. A bootable JAR is like a standard JBoss EAP server in the following ways: It supports JBoss EAP common management CLI commands. It can be managed using the JBoss EAP management console. The following limitations exist when packaging a server in a bootable JAR: CLI management operations that require a server restart are not supported. The server cannot be restarted in admin-only mode, which is a mode that starts services related to server administration. If you shut down the server, updates that you applied to the server are lost. Additionally, you can provision a hollow bootable JAR. This JAR contains only the server, so you can reuse the server to run a different application. Additional resources For information about capability trimming, see Capability Trimming . 11.2. JBoss EAP JAR Maven plug-in You can use the JBoss EAP JAR Maven plug-in to build an application as a bootable JAR. Check that you have the latest Maven plug-in such as 9.minor.micro.Final-redhat-XXXXX , where 9 is the major version, minor is the minor version, micro micro version and X is the Red Hat build number. For example: 9.0.1.Final-redhat-00009 . In a Maven project, the src directory contains all the source files required to build your application. After the JBoss EAP JAR Maven plug-in builds the bootable JAR, the generated JAR is located in target/<application>-bootable.jar . The JBoss EAP JAR Maven plug-in also provides the following functionality: Allows you to provision JBoss EAP XP server using JBoss EAP channels. Applies CLI script commands to the server. Uses the org.jboss.eap.xp:wildfly-galleon-pack Galleon feature pack and some of its layers for customizing the server configuration file. Supports the addition of extra files into the packaged bootable JAR, such as a keystore file. Includes the capability to create a hollow bootable JAR; that is, a bootable JAR that does not contain an application. After you use the JBoss EAP JAR Maven plug-in to create the bootable JAR, you can start the application by issuing the following command. Replace target/myapp-bootable.jar with the path to your bootable JAR. For example: Note To get a list of supported bootable JAR startup commands, append --help to the end of the startup command. For example, java -jar target/myapp-bootable.jar --help . Additional resources For information about supported JBoss EAP Galleon layers, see Available JBoss EAP layers . For information about supported Galleon plug-ins to build feature packs for your project, see the WildFly Galleon Maven Plugin Documentation . For information about selecting methods to configure the JBoss EAP Maven repository, see Use the Maven Repository . For information about Maven project directories, see Introduction to the Standard Directory Layout in the Apache Maven documentation. 11.3. Bootable JAR arguments View the arguments in the following table to learn about supported arguments for use with the bootable JAR. Table 11.1. Supported bootable JAR executable arguments Argument Description --help Displays the help message for the specified command and exit. --cli-script=<path> Specifies the path to a JBoss CLI script that executes when starting the bootable JAR. If the path specified is relative, the path is resolved against the working directory of the Java VM instance used to launch the bootable JAR. --deployment=<path> Argument specific to the hollow bootable JAR. Specifies the path to the WAR, JAR, EAR file or exploded directory that contains the application you want to deploy on a server. --display-galleon-config Print the content of the generated Galleon configuration file. --install-dir=<path> By default, the JVM settings are used to create a TEMP directory after the bootable JAR is started. You can use the --install-dir argument to specify a directory to install the server. -secmgr Runs the server with a security manager installed. -b<interface>=<value> Set system property jboss.bind.address.<interface> to the given value. For example, bmanagement=IP_ADDRESS . -b=<value> Set system property jboss.bind.address , which is used in configuring the bind address for the public interface. This defaults to 127.0.0.1 if no value is specified. -D<name>[=<value>] Specifies system properties that are set by the server at server runtime. The bootable JAR JVM does not set these system properties. --properties=<url> Loads system properties from a specified URL. -S<name>[=value] Set a security property. -u=<value> Set system property jboss.default.multicast.address , which is used in configuring the multicast address in the socket-binding elements in the configuration files. This defaults to 230.0.0.4 if no value is specified. --version Display the application server version and exit. 11.4. Specifying Galleon layers for your bootable JAR server You can specify Galleon layers to build a custom configuration for your server. Additionally, you can specify Galleon layers that you want excluded from the server. Starting with JBoss EAP XP 5.0, it is necessary to configure the JBoss EAP JAR Maven plug-in with the JBoss EAP 8.0 and JBoss EAP XP 5.0 channels to retrieve the server artifacts. For more information about JBoss EAP Channels, see managing JBoss EAP installation channels . To specify the JBoss EAP and JBoss EAP XP channels for provisioning the latest JBoss EAP XP 5.0 server, follow this example: Note Use the <feature-pack-location> element to specify feature pack location. In the Maven plug-in configuration file, the following example specifies org.jboss.eap.xp:wildfly-galleon-pack within the <feature-pack-location> element. <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> </configuration> If you need to reference more than one feature pack, list them in the <feature-packs> element. The following example shows the addition of the JBoss EAP datasources feature pack to the <feature-packs> element: <configuration> <feature-packs> <feature-pack> <location>org.jboss.eap.xp:wildfly-galleon-pack</location> </feature-pack> <feature-pack> <location>org.jboss.eap:eap-datasources-galleon-pack</location> </feature-pack> </feature-packs> </configuration> You can combine Galleon layers from multiple feature packs to configure the bootable JAR server to include only the supported Galleon layers that provide the capabilities that you need. Note On a bare-metal platform, if you do not specify Galleon layers in your configuration file then the provisioned server contains a configuration identical to that of a default standalone-microprofile.xml configuration. On an OpenShift platform, after you have added the <cloud/> configuration element in the plug-in configuration and you choose not to specify Galleon layers in your configuration file, the provisioned server contains a configuration that is adjusted for the cloud environment and is similar to a default standalone-microprofile-ha.xml . Prerequisites Maven is installed. You have checked the latest Maven plug-in version, such as 9.minor.micro.Final-redhat-XXXXX , where 9 is the major version, minor is the minor version, micro micro version and X is the Red Hat build number. For example: 9.0.1.Final-redhat-00009 . Note The examples shown in the procedure specify the following properties: USD{bootable.jar.maven.plugin.version} for the Maven plug-in version. You must set these properties in your project. For example: <properties> <bootable.jar.maven.plugin.version>9.0.1.Final-redhat-00009</bootable.jar.maven.plugin.version> </properties> Procedure Identify the supported JBoss EAP Galleon layers that provide the capabilities that you need to run your application. Reference a JBoss EAP feature pack location in the <plugin> element of the Maven project pom.xml file. The following example displays the inclusion of a single feature-pack, which includes the jaxrs-server base layer and the jpa-distributed layer . The jaxrs-server base layer provides additional support for the server. <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>USD{bootable.jar.maven.plugin.version}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> <layers> <layer>jaxrs-server</layer> <layer>jpa-distributed</layer> </layers> <excluded-layers> <layer>jpa</layer> </excluded-layers> ... </configuration> </plugin> </plugins> This example also shows the exclusion of the jpa layer from the project. Note If you include the jpa-distributed layer in your project, you must exclude the jpa layer from the jaxrs-server layer. The jpa layer configures a local infinispan hibernate cache, while the jpa-distributed layer configures a remote infinispan hibernate cache. Additional resources For information about available base layers, see Base layers . For information about supported Galleon plug-ins to build feature packs for your project, see the WildFly Galleon Maven Plugin Documentation . For information about selecting methods to configure the JBoss EAP Maven repository, see Maven and the JBoss EAP MicroProfile Maven repository . For information about managing your Maven dependencies, see Dependency Management in the Apache Maven Project documentation. 11.5. Using a bootable JAR on a JBoss EAP bare-metal platform You can package an application as a bootable JAR on a JBoss EAP bare-metal platform. A bootable JAR contains a server, a packaged application, and the runtime required to launch the server. This procedure demonstrates packaging the MicroProfile Config microservices application as a bootable JAR with the JBoss EAP JAR Maven plug-in. See MicroProfile Config Quickstart . You can use CLI scripts to configure the server during the packaging of the bootable JAR. Important On building a web application that must be packaged inside a bootable JAR, you must specify war in the <packaging> element of your pom.xml file. For example: <packaging>war</packaging> This value is required to package the build application as a WAR file and not as the default JAR file. In a Maven project that is used solely to build a hollow bootable JAR, set the packaging value to pom . For example: <packaging>pom</packaging> You are not limited to using pom packaging when you build a hollow bootable JAR for a Maven project. You can create one by specifying true in the <hollow-jar> element for any type of packaging, such as war . See Creating a hollow bootable JAR on a JBoss EAP bare-metal platform . Prerequisites <<<<<<< HEAD * You have checked the latest Maven plug-in version, such as MAVEN_PLUGIN_VERSION .X.GA.Final-redhat-00001 , where MAVEN_PLUGIN_VERSION is the major version and X is the microversion. See Index of /ga/org/wildfly/plugins/wildfly-jar-maven-plugin . * You have checked the latest Galleon feature pack version, such as 5.0.X.GA-redhat- BUILD_NUMBER , where X is the microversion of JBoss EAP XP and BUILD_NUMBER is the build number of the Galleon feature pack. Both X and BUILD_NUMBER can evolve during the JBoss EAP XP 5.0.0 product life cycle. See Index of /ga/org/jboss/eap/wildfly-galleon-pack . * You have created a Maven project, set up a parent dependency, and added dependencies for creating an MicroProfile application. See MicroProfile Config Quickstart . You have checked the latest Maven plug-in version, such as 9.minor.micro.Final-redhat-XXXXX , where 9 is the major version, minor is the minor version, micro micro version and X is the Red Hat build number. For example: 9.0.1.Final-redhat-00009 . You have created a Maven project, and added dependencies for creating an MicroProfile application. See MicroProfile Config development . >>>>>>> 10e16bc3 (EAPDOC:935 Bootable jar maven plugin for XP 5) Note The examples shown in the procedure specify the following properties: USD{bootable.jar.maven.plugin.version} for the Maven plug-in version. You must set these properties in your project. For example: <properties> <bootable.jar.maven.plugin.version>9.0.1.Final-redhat-00009</bootable.jar.maven.plugin.version> </properties> Procedure Add the following content to the <build> element of the pom.xml file. For example: <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>USD{bootable.jar.maven.plugin.version}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> <layers> <layer>jaxrs-server</layer> <layer>microprofile-platform</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> Note If you do not specify Galleon layers in your pom.xml file then the bootable JAR server contains a configuration that is identical to a standalone-microprofile.xml configuration. Package the application as a bootable JAR: Start the application: USD NAME="foo" java -jar target/microprofile-config-bootable.jar Note The example uses NAME as the environment variable, but you can choose to use jim , which is the default value. Note To view a list of supported bootable JAR arguments, append --help to the end of the java -jar target/microprofile-config-bootable.jar command. Specify the following URL in your web browser to access the MicroProfile Config application: http://localhost:8080/config/json Verification: Test the application behaves properly by issuing the following command in your terminal: curl http://localhost:8080/config/json The following is the expected output: {"result":"Hello foo"} Additional resources For information about available MicroProfile Config functionality, see MicroProfile Config . For information about ConfigSources , see MicroProfile Config reference . = Creating a hollow bootable JAR on a JBoss EAP bare-metal platform You can package an application as a hollow bootable JAR on a JBoss EAP bare-metal platform. A hollow bootable JAR contains only the JBoss EAP server. The hollow bootable JAR is packaged by the JBoss EAP JAR Maven plug-in. The application is provided at server runtime. The hollow bootable JAR is useful if you need to re-use the server configuration for a different application. Prerequisites You have created a Maven project for MicroProfile Config development. For example: See MicroProfile Config Quickstarts . You have completed the pom.xml file configuration steps outlined in Using a bootable JAR on a JBoss EAP bare-metal platform . You have checked the latest Maven plug-in version, such as 9.minor.micro.Final-redhat-XXXXX , where 9 is the major version, minor is the minor version, micro micro version and X is the Red Hat build number. For example: 9.0.1.Final-redhat-00009 . Procedure To build a hollow bootable JAR, you must set the <hollow-jar> plug-in configuration element to true in the project pom.xml file. For example: <plugins> <plugin> ... <configuration> <!-- This example configuration does not show a complete plug-in configuration --> ... <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> <hollow-jar>true</hollow-jar> </configuration> </plugin> </plugins> Note By specifying true in the <hollow-jar> element, the JBoss EAP JAR Maven plug-in does not include an application in the JAR. Build the hollow bootable JAR: Run the hollow bootable JAR: Important To specify the path to the WAR file that you want to deploy on the server, use the following argument, where <PATH_NAME> is the path to your deployment. --deployment=<PATH_NAME> Access the application: Note To register your web application in the root directory, name the application ROOT.war . Additional resources For information about available MicroProfile functionality, see MicroProfile Config . For more information about the JBoss EAP JAR Maven plug-in supported in JBoss EAP XP 5.0.0, see JBoss EAP Maven plug-in. = CLI scripts executed at build time You can create CLI scripts to configure the server during the packaging of the bootable JAR. A CLI script is a text file that contains a sequence of CLI commands that you can use to apply additional server configurations. For example, you can create a script to add a new logger to the logging subsystem. You can also specify more complex operations in a CLI script. For example, you can group security management operations into a single command to enable HTTP authentication for the management HTTP endpoint. Note You must define CLI scripts in the <cli-session> element of the plug-in configuration before you package an application as a bootable JAR. This ensures the server configuration settings persist after packaging the bootable JAR. Although you can combine predefined Galleon layers to configure a server that deploys your application, limitations do exist. For example, you cannot enable the HTTPS undertow listener using Galleon layers when packaging the bootable JAR. Instead, you must use a CLI script. You must define the CLI scripts in the <cli-session> element of the pom.xml file. The following table shows types of CLI session attributes: Table 11.2. CLI script attributes Argument Description script-files List of paths to script files. properties-file Optional attribute that specifies a path to a properties file. This file lists Java properties that scripts can reference by using the USD{my.prop} syntax. The following example sets public inet-address to the value of all.addresses : /interface=public:write-attribute(name=inet-address,value=USD{all.addresses}) resolve-expressions Optional attribute that contains a boolean value. Indicates if system properties or expressions are resolved before sending the operation requests to the server. Value is true by default. Note CLI scripts are started in the order that they are defined in the <cli-session> element of the pom.xml file. The JBoss EAP JAR Maven plug-in starts the embedded server for each CLI session. Thus, your CLI script does not have to start or stop the embedded server. = Executing CLI script at runtime You can apply changes to the server configuration during runtime; this gives you the flexibility to adjust the server with respect to the execution context. However, the preferred way to apply changes to the server is during build time. Procedure Launch the bootable JAR, and the --cli-script argument. For Example: java -jar myapp-bootable.jar --cli-scipt=my-scli-scipt.cli Note The CLI script must be a text file (UTF-8), the file extension if present is meaningless although .cli extension is advised. Operations that require your server to restart will terminate your bootable JAR instance. CLI commands such as connect , reload , shutdown , and any command related to embedded server are not operational. CLI commands such as jdbc-driver-info that cannot be executed in admin-mode are not supported. Important If you restart the server without executing the CLI script, your new server instance will not contain the changes from your server instance. = Using a bootable JAR on a JBoss EAP OpenShift platform == Using oc command to do binary build After you packaged an application as a bootable JAR, you can run the application on a JBoss EAP OpenShift platform. Important On OpenShift, you cannot use the EAP Operator automated transaction recovery feature with your bootable JAR. Prerequisites <<<<<<< HEAD * You have created a Maven project for MicroProfile Config Quickstart . * You have checked the latest Maven plug-in version, such as MAVEN_PLUGIN_VERSION .X.GA.Final-redhat-00001 , where MAVEN_PLUGIN_VERSION is the major version and X is the microversion. See Index of /ga/org/wildfly/plugins/wildfly-jar-maven-plugin . * You have checked the latest Galleon feature pack version, such as 5.0.X.GA-redhat- BUILD_NUMBER , where X is the microversion of JBoss EAP XP 4 and BUILD_NUMBER is the build number of the Galleon feature pack. Both X and BUILD_NUMBER can evolve during the JBoss EAP XP 5.0.0 product life cycle. See Index of /ga/org/jboss/eap/wildfly-galleon-pack . You have created a Maven project for MicroProfile Config development. For example: See MicroProfile Config Quickstarts . You have checked the latest Maven plug-in version, such as 9.minor.micro.Final-redhat-XXXXX , where 9 is the major version, minor is the minor version, micro micro version and X is the Red Hat build number. For example: 9.0.1.Final-redhat-00009 . >>>>>>> 10e16bc3 (EAPDOC:935 Bootable jar maven plugin for XP 5) Note The examples shown in the procedure specify the following properties: USD{bootable.jar.maven.plugin.version} for the Maven plug-in version. You must set these properties in your project. For example: <properties> <bootable.jar.maven.plugin.version>9.0.1.Final-redhat-00009</bootable.jar.maven.plugin.version> </properties> Procedure Add the following content to the <build> element of the pom.xml file. For example: <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>USD{bootable.jar.maven.plugin.version}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> <layers> <layer>jaxrs-server</layer> <layer>microprofile-platform</layer> </layers> <cloud/> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> Note You must include the <cloud/> element in the <configuration> element of the plug-in configuration, so the JBoss EAP Maven JAR plug-in can identify that you choose the OpenShift platform. Package the application: Log in to your OpenShift instance using the oc login command. Create a new project in OpenShift. For example: Enter the following oc commands to create an application image: 1 Creates an openshift sub-directory in the target directory. The packaged application is copied into the created sub-directory. 2 Imports the latest OpenJDK 17 imagestream tag and image information into the OpenShift project. 3 Creates a build configuration based on the microprofile-config-app directory and the OpenJDK 17 imagestream. 4 Uses the target/openshift sub-directory as the binary input to build the application. Note OpenShift applies a set of CLI script commands to the bootable JAR configuration file to adjust it to the cloud environment. You can access this script by opening the bootable-jar-build-artifacts/generated-cli-script.txt file in the Maven project /target directory . Verification: View a list of OpenShift pods available and check the pods build statuses by issuing the following command: Verify the built application image: The output shows the built application image details, such as name and image repository, tag, and so on. For the example in this procedure, the imagestream name and tag output displays microprofile-config-app:latest . Deploy the application: Important To provide system properties to the bootable JAR, you must use the JAVA_OPTS_APPEND environment variable. The following example demonstrates usage of the JAVA_OPTS_APPEND environment variable: A new application is created and started. The application configuration is exposed as a new service. Verification : Test the application behaves properly by issuing the following command in your terminal: Expected output: Additional resources For information about MicroProfile, see MicroProfile Config . For information about ConfigSources , see Default MicroProfile Config attributes . 11.5.1. Configure the bootable JAR for OpenShift Before using your bootable JAR, you can configure JVM settings to ensure that your standalone server operates correctly on JBoss EAP for OpenShift. Use the JAVA_OPTS_APPEND environment variable to configure JVM settings. Use the JAVA_ARGS command to provide arguments to the bootable JAR. You can use environment variables to set values for properties. For example, you can use the JAVA_OPTS_APPEND environment variable to set the -Dwildfly.statistics-enabled property to true : Statistics are now enabled for your server. Note Use the JAVA_ARGS environment variable, if you need to provide arguments to the bootable JAR. JBoss EAP for OpenShift provides a JDK 17 image. To run the application associated with your bootable JAR, you must first import the latest OpenJDK 17 imagestream tag and image information into your OpenShift project. You can then use environment variables to configure the JVM in the imported image. You can apply the same configuration options for configuring the JVM used for JBoss EAP for OpenShift S2I image, but with the following differences: Optional: The -Xlog capability is not available, but you can set garbage collection logging by enabling -Xlog:gc . For example: JAVA_OPTS_APPEND="-Xlog:gc*:file=/tmp/gc.log:time" . To increase initial metaspace size, you can set the GC_METASPACE_SIZE environment variable. For best metadata capacity performance, set the value to 96 . For better random file generation, use the JAVA_OPTS_APPEND environment variable to set java.security.egd property as -Djava.security.egd=file:/dev/urandom . These configurations improve the memory settings and garbage collection capability of JVM when running on your imported OpenJDK 17 image. 11.5.2. Using a ConfigMap in your application on OpenShift For OpenShift, you can use a deployment controller (dc) to mount the configmap into the pods used to run the application. A ConfigMap is an OpenShift resource that is used to store non-confidential data in key-value pairs. After you specify the microprofile-platform Galleon layer to add microprofile-config-smallrye subsystem and any extensions to the server configuration file, you can use a CLI script to add a new ConfigSource to the server configuration. You can save CLI scripts in an accessible directory, such as the /scripts directory, in the root directory of your Maven project. MicroProfile Config functionality is implemented in JBoss EAP using the SmallRye Config component and is provided by the microprofile-config-smallrye subsystem. This subsystem is included in the microprofile-platform Galleon layer. Prerequisites You have installed Maven. You have configured the JBoss EAP Maven repository. You have packaged an application as a bootable JAR and you can run the application on a JBoss EAP OpenShift platform. For information about building an application as a bootable JAR on an OpenShift platform, see Using a bootable JAR on a JBoss EAP OpenShift platform . Procedure Create a directory named scripts at the root directory of your project. For example: USD mkdir scripts Create a cli.properties file and save the file in the /scripts directory. Define the config.path and the config.ordinal system properties in this file. For example: Create a CLI script, such as mp-config.cli , and save it in an accessible directory in the bootable JAR, such as the /scripts directory. The following example shows the contents of the mp-config.cli script: The mp-config.cli CLI script creates a new ConfigSource , to which ordinal and path values are retrieved from a properties file. Save the script in the /scripts directory, which is located at the root directory of the project. Add the following configuration extract to the existing plug-in <configuration> element: <cli-sessions> <cli-session> <properties-file> scripts/cli.properties </properties-file> <script-files> <script>scripts/mp-config.cli</script> </script-files> </cli-session> </cli-sessions> Package the application: Log in to your OpenShift instance using the oc login command. Optional: If you have not previously created a target/openshift subdirectory, you must create the suddirectory by issuing the following command: Copy the packaged application into the created subdirectory. Use the target/openshift subdirectory as the binary input to build the application: Note OpenShift applies a set of CLI script commands to the bootable JAR configuration file to enable it for the cloud environment. You can access this script by opening the bootable-jar-build-artifacts/generated-cli-script.txt file in the Maven project /target directory. Create a ConfigMap . For example: Mount the ConfigMap into the application with the dc. For example: After executing the oc set volume command, the application is re-deployed with the new configuration settings. Test the output: USD curl http://USD(oc get route microprofile-config-app --template='{{ .spec.host }}')/config/json The following is the expected output: {"result":"Hello Name comes from Openshift ConfigMap"} Additional resources For information about MicroProfile Config ConfigSources attributes, see Default MicroProfile Config attributes . For information about bootable JAR arguments, see Supported bootable JAR arguments . 11.5.3. Creating a bootable JAR Maven project Follow the steps in the procedure to create an example Maven project. You must create a Maven project before you can perform the following procedures: Enabling JSON logging for your bootable JAR Enabling web session data storage for multiple bootable JAR instances Enabling HTTP authentication for bootable JAR with a CLI script Securing your JBoss EAP bootable JAR application with Red Hat build of Keycloak In the project pom.xml file, you can configure Maven to retrieve the project artifacts required to build your bootable JAR. Procedure Set up the Maven project: USD mvn archetype:generate \ -DgroupId=GROUP_ID \ -DartifactId=ARTIFACT_ID \ -DarchetypeGroupId=org.apache.maven.archetypes \ -DarchetypeArtifactId=maven-archetype-webapp \ -DinteractiveMode=false Where GROUP_ID is the groupId of your project and ARTIFACT_ID is the artifactId of your project. In the pom.xml file, configure Maven to retrieve the JBoss EAP BOM file from a remote repository. <repositories> <repository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> To configure Maven to automatically manage versions for the Jakarta EE artifacts in the jboss-eap-ee BOM, add the BOM to the <dependencyManagement> section of the project pom.xml file. For example: <dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.bom</groupId> <artifactId>jboss-eap-ee</artifactId> <version>8.0.2.GA-redhat-00007</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> Add the servlet API artifact, which is managed by the BOM, to the <dependency> section of the project pom.xml file, as shown in the following example: <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <scope>provided</scope> </dependency> Additional resources JBoss EAP XP Bootable JAR Maven Plugin . Specifying Galleon layers for your bootable JAR server . Securing your JBoss EAP bootable JAR application with Red Hat build of Keycloak . 11.5.4. Enabling JSON logging for your bootable JAR You can enable JSON logging for your bootable JAR by configuring the server logging configuration with a CLI script. When you enable JSON logging, you can use the JSON formatter to view log messages in JSON format. The example in this procedure shows you how to enable JSON logging for your bootable JAR on a bare-metal platform and an OpenShift platform. Prerequisites You have checked the latest Maven plug-in version, such as 9.minor.micro.Final-redhat-XXXXX , where 9 is the major version, minor is the minor version, micro micro version and X is the Red Hat build number. For example: 9.0.1.Final-redhat-00009 . You have created a Maven project, and added dependencies for creating an application. See Creating a bootable JAR Maven project . Important In the Maven archetype of your Maven project, you must specify the groupID and artifactID that are specific to your project. For example: Note The examples shown in the procedure specify the following properties: USD{bootable.jar.maven.plugin.version} for the Maven plug-in version. You must set these properties in your project. For example: <properties> <bootable.jar.maven.plugin.version>9.0.1.Final-redhat-00009</bootable.jar.maven.plugin.version> </properties> Procedure Add the JBoss Logging and Jakarta RESTful Web Services dependencies, which are managed by the BOM, to the <dependencies> section of the project pom.xml file. For example: <dependencies> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <scope>provided</scope> </dependency> </dependencies> Add the following content to the <build> element of the pom.xml file. For example: <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>USD{bootable.jar.maven.plugin.version}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-packs> <feature-pack> <location>org.jboss.eap.xp:wildfly-galleon-pack</location> </feature-pack> </feature-packs> <layers> <layer>jaxrs-server</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> Create the directory to store Java files: Where APPLICATION_ROOT is the directory containing the pom.xml configuration file for the application. Create a Java file RestApplication.java with the following content and save the file in the APPLICATION_ROOT/src/main/java/com/example/logging/ directory: package com.example.logging; import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; @ApplicationPath("/") public class RestApplication extends Application { } Create a Java file HelloWorldEndpoint.java with the following content and save the file in the APPLICATION_ROOT/src/main/java/com/example/logging/ directory: package com.example.logging; import jakarta.ws.rs.Path; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.GET; import jakarta.ws.rs.Produces; import org.jboss.logging.Logger; @Path("/hello") public class HelloWorldEndpoint { private static Logger log = Logger.getLogger(HelloWorldEndpoint.class.getName()); @GET @Produces("text/plain") public Response doGet() { log.debug("HelloWorldEndpoint.doGet called"); return Response.ok("Hello from XP bootable jar!").build(); } } Create a CLI script, such as logging.cli , and save it in an accessible directory in the bootable JAR, such as the APPLICATION_ROOT /scripts directory, where APPLICATION_ROOT is the root directory of your Maven project. The script must contain the following commands: Add the following configuration extract to the plug-in <configuration> element: <cli-sessions> <cli-session> <script-files> <script>scripts/logging.cli</script> </script-files> </cli-session> </cli-sessions> This example shows the logging.cli CLI script, which modifies the server logging configuration file to enable JSON logging for your application. Package the application as a bootable JAR. Optional : To run the application on a JBoss EAP bare-metal platform, follow the steps outlined in Using a bootable JAR on a JBoss EAP bare-metal platform , but with the following difference: Start the application: Verification: You can access the application by specifying the following URL in your browser: http://127.0.0.1:8080/hello . Expected output: You can view the JSON-formatted logs, including the com.example.logging.HelloWorldEndpoint debug trace, in the application console. Optional : To run the application on a JBoss EAP OpenShift platform, complete the following steps: Add the <cloud/> element to the plug-in configuration. For example: <plugins> <plugin> ... <!-- You must evolve the existing configuration with the <cloud/> element --> <configuration > ... <cloud/> </configuration> </plugin> </plugins> Rebuild the application: Log in to your OpenShift instance using the oc login command. Create a new project in OpenShift. For example: Enter the following oc commands to create an application image: 1 Creates the target/openshift subdirectory. The packaged application is copied into the openshift subdirectory. 2 Imports the latest OpenJDK 17 imagestream tag and image information into the OpenShift project. 3 Creates a build configuration based on the logging directory and the OpenJDK 17 imagestream. 4 Uses the target/openshift subdirectory as the binary input to build the application. Deploy the application: Get the URL of the route. Access the application in your web browser using the URL returned from the command. For example: Verification: Issue the following command to view a list of OpenShift pods available, and to check the pods build statuses: Access a running pod log of your application. Where APP_POD_NAME is the name of the running pod logging application. Expected outcome: The pod log is in JSON format and includes the com.example.logging.HelloWorldEndpoint debug trace. Additional resources For information about using a bootable JAR on OpenShift, see Using a bootable JAR on a JBoss EAP OpenShift platform . For information about specifying the JBoss EAP JAR Maven for your project, see Specifying Galleon layers for your bootable JAR server . For information about creating CLI scripts, see CLI scripts . 11.5.5. Enabling web session data storage for multiple bootable JAR instances You can build and package a web-clustering application as a bootable JAR. Prerequisites You have checked the latest Maven plug-in version, such as 9.minor.micro.Final-redhat-XXXXX , where 9 is the major version, minor is the minor version, micro micro version and X is the Red Hat build number. For example: 9.0.1.Final-redhat-00009 . You have created a Maven project, and added dependencies for creating a web-clustering application. See Creating a bootable JAR Maven project . Important When setting up the Maven project, you must specify values in the Maven archetype configuration. For example: USD mvn archetype:generate \ -DgroupId=com.example.webclustering \ -DartifactId=web-clustering \ -DarchetypeGroupId=org.apache.maven.archetypes \ -DarchetypeArtifactId=maven-archetype-webapp \ -DinteractiveMode=false cd web-clustering Note The examples shown in the procedure specify the following properties: USD{bootable.jar.maven.plugin.version} for the Maven plug-in version. You must set these properties in your project. For example: <properties> <bootable.jar.maven.plugin.version>9.0.1.Final-redhat-00009</bootable.jar.maven.plugin.version> </properties> Procedure Add the following content to the <build> element of the pom.xml file. For example: <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>USD{bootable.jar.maven.plugin.version}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> <layers> <layer>datasources-web-server</layer> <layer>web-clustering</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> Note This example makes use of the web-clustering Galleon layer to enable web session sharing. Update the web.xml file in the src/main/webapp/WEB-INF directory with the following configuration: <?xml version="1.0" encoding="UTF-8"?> <web-app version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"> <distributable/> </web-app> The <distributable/> tag indicates that this servlet can be distributed across multiple servers. Create the directory to store Java files: Where APPLICATION_ROOT is the directory containing the pom.xml configuration file for the application. Create a Java file MyServlet.java with the following content and save the file in the APPLICATION_ROOT /src/main/java/com/example/webclustering/ directory. package com.example.webclustering; import java.io.IOException; import java.io.PrintWriter; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @WebServlet(urlPatterns = {"/clustering"}) public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("text/html;charset=UTF-8"); long t; User user = (User) request.getSession().getAttribute("user"); if (user == null) { t = System.currentTimeMillis(); user = new User(t); request.getSession().setAttribute("user", user); } try (PrintWriter out = response.getWriter()) { out.println("<!DOCTYPE html>"); out.println("<html>"); out.println("<head>"); out.println("<title>Web clustering demo</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Session id " + request.getSession().getId() + "</h1>"); out.println("<h1>User Created " + user.getCreated() + "</h1>"); out.println("<h1>Host Name " + System.getenv("HOSTNAME") + "</h1>"); out.println("</body>"); out.println("</html>"); } } } The content in MyServlet.java defines the endpoint to which a client sends an HTTP request. Create a Java file User.java with the following content and save the file in the APPLICATION_ROOT /src/main/java/com/example/webclustering/ directory. package com.example.webclustering; import java.io.Serializable; public class User implements Serializable { private final long created; User(long created) { this.created = created; } public long getCreated() { return created; } } Package the application: Optional : To run the application on a JBoss EAP bare-metal platform, follow the steps outlined in Using a bootable JAR on a JBoss EAP bare-metal platform , but with the following difference: On a JBoss EAP bare-metal platform, you can use the java -jar command to run multiple bootable JAR instances, as demonstrated in the following examples: Verification : You can access the application on the node 1 instance: http://127.0.0.1:8080/clustering . Note the user session ID and the user-creation time. After you kill this instance, you can access the node 2 instance: http://127.0.0.1:8090/clustering . The user must match the session ID and the user-creation time of the node 1 instance. Optional : To run the application on a JBoss EAP OpenShift platform, follow the steps outlined in Using a bootable JAR on a JBoss EAP OpenShift platform , but complete the following steps: Add the <cloud/> element to the plug-in configuration. For example: <plugins> <plugin> ... <!-- You must evolve the existing configuration with the <cloud/> element --> <configuration > ... <cloud/> </configuration> </plugin> </plugins> Rebuild the application: Log in to your OpenShift instance using the oc login command. Create a new project in OpenShift. For example: To run a web-clustering application on a JBoss EAP OpenShift platform, authorization access must be granted for the service account that the pod is running in. The service account can then access the Kubernetes REST API. The following example shows authorization access being granted to a service account: Enter the following oc commands to create an application image: 1 Creates the target/openshift sub-directory. The packaged application is copied into the openshift sub-directory. 2 Imports the latest OpenJDK 17 imagestream tag and image information into the OpenShift project. 3 Creates a build configuration based on the web-clustering directory and the OpenJDK 17 imagestream. 4 Uses the target/openshift sub-directory as the binary input to build the application. Deploy the application: Important You must use the KUBERNETES_NAMESPACE environment variable to view other pods in the current OpenShift namespace; otherwise, the server attempts to retrieve the pods from the default namespace. Get the URL of the route. Access the application in your web browser using the URL returned from the command. For example: Note the user session ID and user creation time. Scale the application to two pods: Issue the following command to view a list of OpenShift pods available, and to check the pods build statuses: Kill the oldest pod using the oc delete pod web-clustering- POD_NAME command, where POD_NAME is the name of your oldest pod. Access the application again: Expected outcome: The session ID and the creation time generated by the new pod match those of the of the terminated pod. This indicates that web session data storage is enabled. Additional resources For information about distributable web session management profiles, see The distributable-web subsystem for Distributable Web Session Configurations in the Development Guide . For information about configuring the JGroups protocol stack, see Configuring a JGroups Discovery Mechanism in the Getting Started with JBoss EAP for OpenShift Container Platform guide. 11.5.6. Enabling HTTP authentication for bootable JAR with a CLI script You can enable HTTP authentication for the bootable JAR with a CLI script. This script adds a security realm and a security domain to your server. Prerequisites You have checked the latest Maven plug-in version, such as 9.minor.micro.Final-redhat-XXXXX , where 9 is the major version, minor is the minor version, micro micro version and X is the Red Hat build number. For example: 9.0.1.Final-redhat-00009 . You have created a Maven project, and added dependencies for creating an application that requires HTTP authentication. See Creating a bootable JAR Maven project . Important When setting up the Maven project, you must specify HTTP authentication values in the Maven archetype configuration. For example: USD mvn archetype:generate \ -DgroupId=com.example.auth \ -DartifactId=authentication \ -DarchetypeGroupId=org.apache.maven.archetypes \ -DarchetypeArtifactId=maven-archetype-webapp \ -DinteractiveMode=false cd authentication Note The examples shown in the procedure specify the following properties: USD{bootable.jar.maven.plugin.version} for the Maven plug-in version. You must set these properties in your project. For example: <properties> <bootable.jar.maven.plugin.version>9.0.1.Final-redhat-00009</bootable.jar.maven.plugin.version> </properties> Procedure Add the following content to the <build> element of the pom.xml file. For example: <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>USD{bootable.jar.maven.plugin.version}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> <layers> <layer>datasources-web-server</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> The example shows the inclusion of the datasources-web-server Galleon layer that contains the elytron subsystem. Update the web.xml file in the src/main/webapp/WEB-INF directory. For example: <?xml version="1.0" encoding="UTF-8"?> <web-app version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"> <login-config> <auth-method>BASIC</auth-method> <realm-name>Example Realm</realm-name> </login-config> </web-app> Create the directory to store Java files: Where APPLICATION_ROOT is the root directory of your Maven project. Create a Java file TestServlet.java with the following content and save the file in the APPLICATION_ROOT/src/main/java/com/example/authentication/ directory. package com.example.authentication; import jakarta.servlet.annotation.HttpMethodConstraint; import jakarta.servlet.annotation.ServletSecurity; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet(urlPatterns = "/hello") @ServletSecurity(httpMethodConstraints = { @HttpMethodConstraint(value = "GET", rolesAllowed = { "Users" }) }) public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { PrintWriter writer = resp.getWriter(); writer.println("Hello " + req.getUserPrincipal().getName()); writer.close(); } } Create a CLI script, such as authentication.cli , and save it in an accessible directory in the bootable JAR, such as the APPLICATION_ROOT /scripts directory. The script must contain the following commands: Add the following configuration extract to the plug-in <configuration> element: <cli-sessions> <cli-session> <script-files> <script>scripts/authentication.cli</script> </script-files> </cli-session> </cli-sessions> This example shows the authentication.cli CLI script, which configures the default undertow security domain to the security domain defined for your server. Note You have the option to execute the CLI script at runtime instead of packaging time. To do so, skip this step and proceed to step 10. In the root directory of your Maven project create a directory to store the properties files that the JBoss EAP JAR Maven plug-in adds to the bootable JAR: USD mkdir -p APPLICATION_ROOT/extra-content/standalone/configuration/ Where APPLICATION_ROOT is the directory containing the pom.xml configuration file for the application. This directory stores files such as bootable-users.properties and bootable-groups.properties files. The bootable-users.properties file contains the following content: The bootable-groups.properties file contains the following content: Add the following extra-content-content-dirs element to the existing <configuration> element: <extra-server-content-dirs> <extra-content>extra-content</extra-content> </extra-server-content-dirs> The extra-content directory contains the properties files. Package the application as a bootable JAR. Start the application: If you have chosen to skip step 6 and not execute the CLI script during build, launch the application with the following command: mvn wildfly-jar:run -Dwildfly.bootable.arguments=--cli-script=scripts/authentication.cli Call the servlet, but do not specify credentials: Expected output: Call the server and specify your credentials. For example: A HTTP 200 status is returned that indicates HTTP authentication is enabled for your bootable JAR. For example: Additional resources For information about enabling HTTP authentication for the undertow security domain, see Enable HTTP Authentication for Applications Using the CLI Security Command in the How to Configure Server Security . 11.6. Helm chart use case Helm is an open source package manager that enables you to build, deploy, and maintain your JBoss EAP XP 5.0 applications on OpenShift. You can use Helm chart with JBoss EAP XP 5.0 to: Build your application from a Maven project hosted on a Git repository using OpenShift Source-to-Image (S2I). Deploy an application image on OpenShift with deep integration using an OpenShift cluster (TLS configuration, public route to expose the application, and so on). Build your application image with Helm chart and use the JBoss EAP XP operator to deploy the image. Build an application image for JBoss EAP XP using other methods and use the Helm chart. Important You can build your Java application with JBoss EAP XP 5.0 to create a Bootable Jar or a Jakarta deployment (similar to JBoss EAP 8.0). If your Java application is a Bootable Jar, the Helm Chart for JBoss EAP XP 5.0 can be used to build the application image (using its default build.mode set to bootable-jar ). If your Java application is a Jakarta deployment, you can build the application image using source-to-Image (similarly to JBoss EAP 8.0) by setting the Helm Chart's build.mode to s2i 11.6.1. Building and deploying JBoss EAP XP applications using Helm chart You can build your JBoss EAP XP application using Helm chart by configuring the build and deploy values. You must provide a URL to the Git repository that hosts your application code in your build configuration, the output is an ImageStreamTag resource that contains the built application image. To deploy your application, you must provide an ImageStreamTag resource that contains your built application image. The output is your deployed application and other related resources you can use to access your application from inside and outside OpenShift. Prerequisites You have access to the OpenShift Development Console. You have the source code of your JBoss EAP XP application hosted in a Git repository. Your application is a Maven project. You have configured your application to use the org.jboss.eap.plugins:eap-maven-plugin to provision your JBoss EAP XP 5.0 server. Note This procedure focuses only on using the OpenShift Development Console. Some form sections are collapsed by default. Click > to expand and view its content.Additionally, you do not need to updated these sections to proceed. Procedure Log in to OpenShift Development Console. On the dropdown menu, click on Helm . On the the top right corner click create and then click on Helm Release . Select JBoss EAP XP 5. Click create and select configure via YAML view . Build your application image from the source repository: Optional: Enter the secret in the build section with the sourceSecret key: Verification If your application has been successfully deployed, you should see a deployed badge to the Helm release on OpenShift Development Console. 11.6.1.1. Using Helm chat with Source-to-Image on JBoss EAP XP Use the eap-maven-plugin from the application pom.xml to provision your JBoss EAP server. Ensure that this plugin is configured in the OpenShift profile, the default profile, or any other active profile, with the OpenShift profile taking precedence over all others. Important You must set build.mode to S2I. This is because the default value is bootable-jar for JBoss EAP XP Helm chart. Note The build.s2i.featurePacks , build.s2i.galleonLayers and build.s2i.channels fields have been deprecated. 11.6.1.2. Using Helm chart with Bootable JAR on JBoss EAP XP In JBoss EAP XP 5.0 you can build your application as a Bootable JAR for more information about how you can do this see The Bootable JAR . Additionally, in JBoss EAP XP 5.0 you can configure Helms Chart for JBoss EAP XP 5.0 to build an application based on Bootable JAR. Prerequisites You have logged into the OpenShift Development Console. You have the source code of your JBoss EAP XP application hosted in a Git repository. Your application is a Maven project. You have configured your application to create a bootable JAR using Maven plugin org.wildfly.plugins:wildfly-jar-maven-plugin . To learn more see Creating a bootable JAR Maven project . 11.6.1.2.1. Building your application image using Bootable JAR You can build your JBoss EAP XP application image with Bootable using Helms chart by configuring the build section on the OpenShift Development Console. Note If you are building the application with the Helm chart, you must specify the build.url field with the Git URL that references your Git repository. You must set the build.mode field to bootable-jar . 11.6.2. OpenShift volumes for persistent data storage in Helm chart for JBoss EAP XP OpenShift volumes enable containers to store and share data from various sources, including cloud storage, network file systems (NFS), or host machines. You can use Helm chart, an OpenShift package manager, to deploy applications in a consistent and reproducible manner. By adding a volume mount to a Helm chart, you can enable your application to persist data across deployments. 11.6.2.1. Mounting a volume with a Helm chart on JBoss EAP XP This procedure explains how to mount a secret as a volume using a Helm chart on JBoss EAP XP. Additionally, you can also use it to mount a ConfigMap . This action enables the application to securely access and use the data, protecting it from unauthorized access or tampering. For example, by mounting a secret as a volume, the sensitive data that you store in the secret appears as a file in the POD running the deployment where the secret has been mounted. Prerequisites You have access to the OpenShift Development Console You have created a secret . For example, you have created a secret named eap-app-secret that refers to a file like keystore.jks . You have identified a location where to mount the secret in the container's file system. For example, the directory /etc/jgroups-encrypt-secre-secret-volume is where the secret file, such as keystore.jks is mounted. The source code of your JBoss EAP XP application hosted in a Git repository. Your application is a Maven project. You have configured your application to use the org.jboss.eap.plugins:eap-maven-plugin to provision your JBoss EAP XP 5.0 server. Procedure Log in to OpenShift Development Console. On the dropdown menu, click on Helm . On the the top right corner click create and then click on Helm Release . Select JBoss EAP XP 5. Click create and select configure via YAML view . Edit the YAML file specifying the volume in the deploy.volumes field and configure the secret to be used. You must provide the name of the volume and the secretName of the secret: Mount the volume on the file system using the deploy.volumeMounts in the deployment configuration: When the pod starts, the container mounts the keystore.jks file at /etc/jgroups-encrypt-secret-volume/keystore.jks location. 11.6.3. Additional resources Helm chart on JBoss EAP 8 . Value file examples . 11.7. Observability in JBoss EAP If you're a developer or system administrator, observability is a set of practices and technologies you can use to determine, based on certain signals from your application, the location and source of a problem in your application. The most common signals are metrics, events, and tracing. JBoss EAP uses OpenTelemetry for observability . 11.7.1. OpenTelemetry in JBoss EAP OpenTelemetry is a set of tools, application programming interfaces (APIs), and software development kits (SDKs) you can use to instrument, generate, collect, and export telemetry data for your applications. Telemetry data includes metrics, logs, and traces. Analyzing an application's telemetry data helps you to improve your application's performance. JBoss EAP provides OpenTelemetry capability through the opentelemetry subsystem. Note Red Hat JBoss Enterprise Application Platform 8.0 provides only OpenTelemetry tracing capabilities. Important OpenTelemetry is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process. For more information about the support scope of Red Hat Technology Preview features, see https://access.redhat.com/support/offerings/techpreview . Additional resources OpenTelemetry Documentation 11.7.2. OpenTelemetry configuration in JBoss EAP You configure a number of aspects of OpenTelemetry in JBoss EAP using the opentelemetry subsystem. These include exporter, span processor, and sampler. exporter To analyze and visualize traces, you export them to a collector such as the OpenTelemetry Collector (OTLP). You can configure JBoss EAP to use any collector that supports the OpenTelemetry protocol. span processor You can configure the span processor to export spans either as they are produced or in batches. You can also configure the number of traces to export. sampler You can configure the number of traces to record by configuring the sampler. Example configuration The following XML is an example of the full OpenTelemetry configuration, including default values. JBoss EAP does not persist the default values when you make changes, so your configuration might look different. <subsystem xmlns="urn:wildfly:opentelemetry:1.0" service-name="example"> <exporter type="otlp" endpoint="http://localhost:4317"/> <span-processor type="batch" batch-delay="4500" max-queue-size="128" max-export-batch-size="512" export-timeout="45"/> <sampler type="on"/> </subsystem> Note You cannot use an OpenShift route object to connect with a OpenTelemetry Collector endpoint. Instead, use http:// <ip_address> : <port> or http:// <service_name> : <port> . Additional resources OpenTelemetry subsystem attributes 11.7.3. OpenTelemetry tracing in JBoss EAP JBoss EAP provides OpenTelemetry tracing to help you track the progress of user requests as they pass through different parts of your application. By analyzing traces, you can improve your application's performance and debug availability issues. OpenTelemetry tracing consists of the following components: Trace A collection of operations that a request goes through in an application. Span A single operation within a trace. It provides request, error, and duration (RED) metrics and contains a span context. Span context A set of unique identifiers that represents a request that the containing span is a part of. JBoss EAP automatically traces REST calls to your Jakarta RESTful Web Services applications and container-managed Jakarta RESTful Web Services client invocations. JBoss EAP traces REST calls implicitly as follows: For each incoming request: JBoss EAP extracts the span context from the request. JBoss EAP starts a new span, then closes it when the request is completed. For each outgoing request: JBoss EAP injects span context into the request. JBoss EAP starts a new span, then closes it when the request is completed. In addition to implicit tracing, you can create custom spans by injecting a Tracer instance into your application for granular tracing. 11.7.4. Enabling OpenTelemetry tracing in JBoss EAP To use OpenTelemetry tracing in JBoss EAP you must first enable the opentelemetry subsystem. Prerequisites JBoss EAP 8.0 with JBoss EAP XP 5.0 is installed. Procedure Add the OpenTelemetry extension using the management CLI. Enable the opentelemetry subsystem using the management CLI. Reload JBoss EAP. Additional resources Configuring the opentelemetry subsystem 11.7.5. Configuring the opentelemetry subsystem You can configure the opentelemetry subsystem to set different aspects of tracing. Configure these based on the collector you use for observing the traces. Prerequisites You have enabled the opentelemetry subsystem. For more information, see Enabling OpenTelemetry tracing in JBoss EAP . Procedure Set the exporter type for the traces. Syntax Example Set the endpoint at which to export the traces. Syntax Example Set the service name under which the traces are exported. Syntax Example 11.8. Reference 11.8.1. MicroProfile Config reference 11.8.1.1. Default MicroProfile Config attributes The MicroProfile Config specification defines three ConfigSources by default. ConfigSources are sorted according to their ordinal number. If a configuration must be overwritten for a later deployment, the lower ordinal ConfigSource is overwritten before a higher ordinal ConfigSource . Table 11.3. Default MicroProfile Config attributes ConfigSource Ordinal System properties 400 Environment variables 300 Property files META-INF/microprofile-config.properties found on the classpath 100 11.8.1.2. MicroProfile Config SmallRye ConfigSources The microprofile-config-smallrye project defines more ConfigSources you can use in addition to the default MicroProfile Config ConfigSources . Table 11.4. Additional MicroProfile Config attributes ConfigSource Ordinal config-source in the Subsystem 100 ConfigSource from the Directory 100 ConfigSource from Class 100 An explicit ordinal is not specified for these ConfigSources . They inherit the default ordinal value found in the MicroProfile Config specification. 11.8.2. MicroProfile Fault Tolerance reference 11.8.2.1. MicroProfile Fault Tolerance configuration properties SmallRye Fault Tolerance specification defines the following properties in addition to the properties defined in the MicroProfile Fault Tolerance specification. Table 11.5. MicroProfile Fault Tolerance configuration properties Property Default value Description io.smallrye.faulttolerance.mainThreadPoolSize 100 Maximum number of threads in the thread pool. io.smallrye.faulttolerance.mainThreadPoolQueueSize -1 (unbounded) Size of the queue that the thread pool should use. 11.8.3. MicroProfile JWT reference 11.8.3.1. MicroProfile Config JWT standard properties The microprofile-jwt-smallrye subsystem supports the following MicroProfile Config standard properties. Table 11.6. MicroProfile Config JWT standard properties Property Default Description mp.jwt.verify.publickey NONE String representation of the public key encoded using one of the supported formats. Do not set if you have set mp.jwt.verify.publickey.location . mp.jwt.verify.publickey.location NONE The location of the public key, may be a relative path or URL. Do not be set if you have set mp.jwt.verify.publickey . mp.jwt.verify.issuer NONE The expected value of any iss claim of any JWT token being validated. Example microprofile-config.properties configuration: 11.8.4. MicroProfile OpenAPI reference 11.8.4.1. MicroProfile OpenAPI configuration properties In addition to the standard MicroProfile OpenAPI configuration properties, JBoss EAP supports the following additional MicroProfile OpenAPI properties. These properties can be applied in both the global and the application scope. Table 11.7. MicroProfile OpenAPI properties in JBoss EAP Property Default value Description mp.openapi.extensions.enabled true Enables or disables registration of an OpenAPI endpoint. When set to false , disables generation of OpenAPI documentation. You can set the value globally using the config subsystem, or for each application in a configuration file such as /META-INF/microprofile-config.properties . You can parameterize this property to selectively enable or disable microprofile-openapi-smallrye in different environments, such as production or development. You can use this property to control which application associated with a given virtual host should generate a MicroProfile OpenAPI model. mp.openapi.extensions.path /openapi You can use this property for generating OpenAPI documentation for multiple applications associated with a virtual host. Set a distinct mp.openapi.extensions.path on each application associated with the same virtual host. mp.openapi.extensions.servers.relative true Indicates whether auto-generated server records are absolute or relative to the location of the OpenAPI endpoint. Server records are necessary to ensure, in the presence of a non-root context path, that consumers of an OpenAPI document can construct valid URLs to REST services relative to the host of the OpenAPI endpoint. The value true indicates that the server records are relative to the location of the OpenAPI endpoint. The generated record contains the context path of the deployment. When set to false , JBoss EAP XP generates server records including all the protocols, hosts, and ports at which the deployment is accessible. 11.8.5. MicroProfile Reactive Messaging reference 11.8.5.1. MicroProfile reactive messaging connectors for integrating with external messaging systems The following is a list of reactive messaging property key prefixes required by the MicroProfile Config specification: mp.messaging.incoming.[channel-name].[attribute]=[value] mp.messaging.outgoing.[channel-name].[attribute]=[value] mp.messaging.connector.[connector-name].[attribute]=[value] Note that channel-name is either the @Incoming.value() or the @Outgoing.value() . For clarification, look at this example of a pair of connector methods: In this example, the required property prefixes are as follows: mp.messaging.incoming.from . This defines the receive() method. mp.messaging.outgoing.to . This defines the send() method. Remember that this is an example. Because different connectors recognize different properties, the prefixes you indicate depend on the connector you want to configure. 11.8.5.2. Example of the data exchange between reactive messaging streams and user-initialized code The following is an example of data exchange between reactive messaging streams and code that a user triggered through the @Channel and Emitter constructs: In-line details: 1 Wraps the constructor-injected publisher. 2 You need this empty constructor to satisfy the Contexts and Dependency Injection (CDI) for Java specification. 3 Subscribe to the delegate. 4 Wrap the delegate in a publisher that can handle multiple subscriptions. 5 The wrapping publisher forwards data from the delegate. 6 Unsubscribe from the reactive messaging-provided publisher. In this example, MicroProfile Reactive Messaging is listening to the my-stream memory stream, so messages sent through the Emitter are received on this injected publisher. Note, though, that the following conditions must be true for this data exchange to succeed: There must be an active subscription on the channel before you call Emitter.send() . In this example, notice that the subscribeAndAllowMultipleSubscriptions() method called by the constructor ensures that there's an active subscription by the time the bean is available for user code calls. You can have only one Subscription on the injected Publisher . If you want to expose the receiving publisher with a REST call, where each call to the poll() method results in a new subscription to the dest publisher, you have to implement your own publisher to broadcast data from the injected to each client. 11.8.5.3. The Apache Kafka user API You can use the Apache Kafka user API to get more information about messages Kafka received, and to influence how Kafka handles messages. This API is stored in the io/smallrye/reactive/messaging/kafka/api package, and it consists of the following classes: IncomingKafkaRecordMetadata . This metadata contains the following information: The Kafka record key , represented by a Message . The Kafka topic and partition used for the Message , and the offset within those. The Message timestamp and timestampType . The Message headers . These are pieces of information that the application can attach on the producing side, and receive on the consuming side. OutgoingKafkaRecordMetadata . With this metadata, you can specify or override how Kafka handles messages. It contains the following information: The key . which Kafka treats as the message key. The topic you want Kafka to use. The partition . The timestamp , if you don't want the one that Kafka generates. headers . KafkaMetadataUtil contains utility methods to write OutgoingKafkaRecordMetadata to a Message , and to read IncomingKafkaRecordMetadata from a Message . Important If you write OutgoingKafkaRecordMetadata to a Message sent to a channel that's not mapped to Kafka, the reactive messaging framework ignores it. Conversely, if you read IncomingKafkaRecordMetadata from a Message from a channel that's not mapped to Kafka, that message returns as null . Example of how to write and read a message key Example of Kafka mapping in a microprofile-config.properties file Note You must specify the key.serializer for the outgoing channel and the key.deserializer for the incoming channel. 11.8.5.4. Example MicroProfile Config properties file for the Kafka connector This is an example of a simple microprofile-config.properties file for a Kafka connector. Its properties correspond to the properties in the example in "MicroProfile reactive messaging connectors for integrating with external messaging systems." Table 11.8. Discussion of entries Entry Description to , from These are "channels." send , receive These are "methods." Note that the to channel is on the send() method and the from channel is on the receive() method. kafka.bootstrap.servers=kafka:9092 This specifies the URL of the Kafka broker that the application must connect to. You can also specify a URL at the channel level, like this: mp.messaging.outgoing.to.bootstrap.servers=kafka:9092 mp.messaging.outgoing.to.connector=smallrye-kafka This indicates that you want the to channel to receive messages from Kafka. SmallRye reactive messaging is a framework for building applications. Note that the smallrye-kafka value is SmallRye reactive messaging-specific. If you're provisioning your own server using Galleon, you can enable the Kafka integration by including the microprofile-reactive-messaging-kafka Galleon layer. mp.messaging.outgoing.to.topic=my-topic This indicates that you want to send data to a Kafka topic called my-topic . A Kafka "topic" is a category or feed name that messages are stored on and published to. All Kafka messages are organized into topics. Producer applications write data to topics and consumer applications read data from topics. mp.messaging.outgoing.to.value.serializer=org.apache.kafka.common.serialization.IntegerSerializer This tells the connector to use IntegerSerializer to serialize the values that the send() method outputs when it writes to a topic. Kafka provides serializers for standard Java types. You can implement your own serializer by writing a class that implements org.apache.kafka.common.serialization.Serializer , and then include that class in your deployment. mp.messaging.incoming.from.connector=smallrye-kafka This indicates that you want to use the from channel to receive messages from Kafka. Again, the smallrye-kafka value is SmallRye reactive messaging-specific. mp.messaging.incoming.from.topic=my-topic This indicates that your connector should read data from the Kafka topic called my-topic . mp.messaging.incoming.from.value.deserializer=org.apache.kafka.common.serialization.IntegerDeserializer This tells the connector to use IntegerDeserializer to deserialize the values from the topic before calling the receive() method. You can implement your own deserializer by writing a class that implements org.apache.kafka.common.serialization.Deserializer , and then include that class in your deployment. Note This list of properties is not comprehensive. See the SmallRye Reactive Messaging Apache Kafka documentation for more information. Mandatory MicroProfile Reactive Messaging prefixes The MicroProfile Reactive Messaging specification requires the following method property key prefixes for Kafka: mp.messaging.incoming.[channel-name].[attribute]=[value]` mp.messaging.outgoing.[channel-name].[attribute]=[value]` mp.messaging.connector.[connector-name].[attribute]=[value]` Note that channel-name is either the @Incoming.value() or the @Outgoing.value() . Now consider the following method pair example: In this method pair example, note the following required property prefixes: mp.messaging.incoming.from . This prefix selects the property as your configuration of the receive() method. mp.messaging.outgoing.to . This prefix selects the property as your configuration of the send() method. 11.8.5.5. Example MicroProfile Config properties file for the AMQP connector This is an example of a simple microprofile-config.properties file for an Advanced Message Queuing Protocol (AMQP) connector. Its properties correspond to the properties in the example in MicroProfile reactive messaging connectors for integrating with external messaging systems . Table 11.9. Discussion of entries Entry Description to , from These are "channels." send , receive These are "methods." Note that the to channel is on the send() method and the from channel is on the receive() method. amqp-host=localhost This specifies the URL of the AMQP broker that the application must connect to. You can also specify a URL at the channel level, like this: mp.messaging.outgoing.to.host=localhost .The value defaults to localhost when no URL is specified. amqp-port=5672 This specifies the port of the AMQP broker. mp.messaging.outgoing.to.connector=smallrye-amqp This indicates that you want the channel to send messages to AMQP. SmallRye reactive messaging is a framework for building applications. Note that the smallrye-amqp value is SmallRye reactive messaging specific. If you're provisioning your own server using Galleon, you can enable the AMQP integration by including the microprofile-reactive-messaging-amqp Galleon layer. mp.messaging.outgoing.to.address=my-topic This indicates that you want to send data to an AMQP queue on the address my-topic . If you do not specify a value for mp.messaging.outgoing.to.address , the value will default to the channel, which in this example is "to". mp.messaging.incoming.from.connector=smallrye-amqp This indicates that you want to use the from channel to receive messages from the AMQP broker. Again, the smallrye-amqp value is SmallRye reactive messaging-specific. mp.messaging.incoming.from.address=my-topic This indicates that you want to read data from the AMQP queue my-topic on the from channel. For a complete list of properties supported by the SmallRye Reactive Messaging's AMQP connector, see SmallRye Reactive Messaging AMQP Connector Configuration Reference . Connecting to a secure AMQP broker To connect with an AMQ broker secured with SSL/TLS and Simple Authentication and Security Layer (SASL), define the client-ssl-context to be used for the connection, in the microprofile-config.properties file. You can do this on connector level and also on channel level. Example of connector level client-ssl-context definition The attribute mp.messaging.connector.smallrye-amqp.wildfly.elytron.ssl.context is only required when you use self-signed certificates. Important Do not use self-signed certificates in a production environment. Use only the certificates signed by a certificate authority (CA). You can also specify the client-ssl-context for a channel as follows: Example of channel-level client-ssl-context definition In the example, the exampleSSLContext is associated only with the incoming channel from . Table 11.10. Discussion of entries Entry Description amqp-use-ssl This specifies that we want to use a secure connection when connecting to the broker. mp.messaging.connector.smallrye-amqp.wildfly.elytron.ssl.context You do not need to specify this attribute if the AMQ broker is secured with a Certificate Authority (CA)-signed certificate. If you use a self-signed certificate, specify the SSLContext that is defined in the Elytron subsystem under /subsystem=elytron/client-ssl-context=* in the management model. Important Do not use self-signed certificates in a production environment. Use only the certificates signed by a certificate authority (CA). You can define client-ssl-context by using the following management CLI command: For more information, see Configuring a trust store and a trust manager for client certificates , Configuring a server certificate for two-way SSL/TLS in the Configuring SSL/TLS in JBoss EAP guide. 11.8.6. OpenTelemetry reference 11.8.6.1. OpenTelemetry subsystem attributes You can modify opentelemetry subsystem attributes to configure its behavior. The attributes are grouped by the aspect they configure: exporter, sampler, and span processor. Table 11.11. Exporter attribute group Attribute Description Default value endpoint The URL to which OpenTelemetry pushes traces. Set this to the URL where your exporter listens. http://localhost:14250/ exporter-type The exporter to which traces are sent. It can be one of the following: jaeger . The exporter you use is Jaeger. otlp . The exporter you use works with the OpenTelemetry protocol. jaeger Table 11.12. Sampler attribute group Attribute Description Default value ratio The ratio of traces to export. The value must be between 0.0 and 1.0 . For example, to export one trace in every 100 traces created by an application, set the value to 0.01 . This attribute takes effect only if you set the attribute sampler-type as ratio . Table 11.13. Span processor attribute group Attribute Description Default value batch-delay The interval in milliseconds between two consecutive exports by JBoss EAP. This attribute only takes effect if you set the attribute span-processor-type as batch . 5000 export-timeout The maximum amount of time in milliseconds to allow for an export to complete before being cancelled. 30000 max-export-batch-size The maximum number of traces that are published in each batch. This number should be should be lesser or equal to the value of max-queue-size . You can set this attribute only if you set the attribute span-processor-type as batch . 512 max-queue-size The maximum number of traces to queue before exporting. If an application creates more traces, they are not recorded. This attribute only takes effect if you set the attribute span-processor-type as batch . 2048 span-processor-type The type of span processor to use. The value can be one of the following: batch : JBoss EAP exports traces in batches that are defined using the following attributes: batch-delay max-export-batch-size max-queue-size simple : JBoss EAP exports traces are as soon as they finish. batch Additional resources OpenTelemetry in JBoss EAP

Commands:
java -jar target/myapp-bootable.jar
<configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> </configuration>
<configuration> <feature-packs> <feature-pack> <location>org.jboss.eap.xp:wildfly-galleon-pack</location> </feature-pack> <feature-pack> <location>org.jboss.eap:eap-datasources-galleon-pack</location> </feature-pack> </feature-packs> </configuration>
<properties> <bootable.jar.maven.plugin.version>9.0.1.Final-redhat-00009</bootable.jar.maven.plugin.version> </properties>
<plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>USD{bootable.jar.maven.plugin.version}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> <layers> <layer>jaxrs-server</layer> <layer>jpa-distributed</layer> </layers> <excluded-layers> <layer>jpa</layer> </excluded-layers> </configuration> </plugin> </plugins>
<packaging>war</packaging>
<packaging>pom</packaging>
<properties> <bootable.jar.maven.plugin.version>9.0.1.Final-redhat-00009</bootable.jar.maven.plugin.version> </properties>
<plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>USD{bootable.jar.maven.plugin.version}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> <layers> <layer>jaxrs-server</layer> <layer>microprofile-platform</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins>
mvn package
NAME="foo" java -jar target/microprofile-config-bootable.jar
http://localhost:8080/config/json
curl http://localhost:8080/config/json
result: Hello foo
<plugins> <plugin> <configuration> <!-- This example configuration does not show a complete plug-in configuration --> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> <hollow-jar>true</hollow-jar> </configuration> </plugin> </plugins>
mvn clean package
java -jar target/microprofile-config-bootable.jar --deployment=target/microprofile-config.war
--deployment=<PATH_NAME>
curl http://localhost:8080/microprofile-config/config/json
java -jar myapp-bootable.jar --cli-scipt=my-scli-scipt.cli
<properties> <bootable.jar.maven.plugin.version>9.0.1.Final-redhat-00009</bootable.jar.maven.plugin.version> </properties>
<plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>USD{bootable.jar.maven.plugin.version}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> <layers> <layer>jaxrs-server</layer> <layer>microprofile-platform</layer> </layers> <cloud/> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins>
mvn package
oc new-project bootable-jar-project
mkdir target/openshift && cp target/microprofile-config-bootable.jar target/openshift 1 oc import-image ubi8/openjdk-17 --from=registry.redhat.io/ubi8/openjdk-17 --confirm 2 oc new-build --strategy source --binary --image-stream openjdk-17 --name microprofile-config-app 3 oc start-build microprofile-config-app --from-dir target/openshift 4
oc get pods
oc get is microprofile-config-app
oc new-app microprofile-config-app oc expose svc/microprofile-config-app
oc new-app <_IMAGESTREAM_> -e JAVA_OPTS_APPEND="-Xlog:gc*:file=/tmp/gc.log:time -Dwildfly.statistics-enabled=true"
curl http://USD(oc get route microprofile-config-app --template='{{ .spec.host }}')/config/json
result: Hello jim
JAVA_OPTS_APPEND="-Xlog:gc*:file=/tmp/gc.log:time -Dwildfly.statistics-enabled=true"
mkdir scripts
config.path=/etc/config config.ordinal=200
config map /subsystem=microprofile-config-smallrye/config-source=os-map:add(dir={path=USD{config.path}}, ordinal=USD{config.ordinal})
<cli-sessions> <cli-session> <properties-file> scripts/cli.properties </properties-file> <script-files> <script>scripts/mp-config.cli</script> </script-files> </cli-session> </cli-sessions>
mvn package
mkdir target/openshift
cp target/microprofile-config-bootable.jar target/openshift
oc start-build microprofile-config-app --from-dir target/openshift
oc create configmap microprofile-config-map --from-literal=name="Name comes from Openshift ConfigMap"
oc set volume deployments/microprofile-config-app --add --name=config-volume --mount-path=/etc/config --type=configmap --configmap-name=microprofile-config-map
curl http://USD(oc get route microprofile-config-app --template='{{ .spec.host }}')/config/json
result: Hello Name comes from Openshift ConfigMap
mvn archetype:generate -DgroupId=GROUP_ID -DartifactId=ARTIFACT_ID -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
<repositories> <repository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories>
<dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.bom</groupId> <artifactId>jboss-eap-ee</artifactId> <version>8.0.2.GA-redhat-00007</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <scope>provided</scope> </dependency>
mvn archetype:generate -DgroupId=com.example.logging -DartifactId=logging -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false cd logging
<properties> <bootable.jar.maven.plugin.version>9.0.1.Final-redhat-00009</bootable.jar.maven.plugin.version> </properties>
<dependencies> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <scope>provided</scope> </dependency> </dependencies>
<plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>USD{bootable.jar.maven.plugin.version}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-packs> <feature-pack> <location>org.jboss.eap.xp:wildfly-galleon-pack</location> </feature-pack> </feature-packs> <layers> <layer>jaxrs-server</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins>
mkdir -p APPLICATION_ROOT/src/main/java/com/example/logging/
package com.example.logging; import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; @ApplicationPath("/") public class RestApplication extends Application { }
package com.example.logging; import jakarta.ws.rs.Path; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.GET; import jakarta.ws.rs.Produces; import org.jboss.logging.Logger; @Path("/hello") public class HelloWorldEndpoint { private static Logger log = Logger.getLogger(HelloWorldEndpoint.class.getName()); @GET @Produces("text/plain") public Response doGet() { log.debug("HelloWorldEndpoint.doGet called"); return Response.ok("Hello from XP bootable jar!").build(); } }
/subsystem=logging/logger=com.example.logging:add(level=ALL) /subsystem=logging/json-formatter=json-formatter:add(exception-output-type=formatted, pretty-print=false, meta-data={version="1"}, key-overrides={timestamp="@timestamp"}) /subsystem=logging/console-handler=CONSOLE:write-attribute(name=level,value=ALL) /subsystem=logging/console-handler=CONSOLE:write-attribute(name=named-formatter, value=json-formatter)
<cli-sessions> <cli-session> <script-files> <script>scripts/logging.cli</script> </script-files> </cli-session> </cli-sessions>
mvn package
mvn wildfly-jar:run
<plugins> <plugin> ... <!-- You must evolve the existing configuration with the <cloud/> element --> <configuration > <cloud/> </configuration> </plugin> </plugins>
mvn clean package
oc new-project bootable-jar-project
mkdir target/openshift && cp target/logging-bootable.jar target/openshift 1 oc import-image ubi8/openjdk-17 --from=registry.redhat.io/ubi8/openjdk-17 --confirm 2 oc new-build --strategy source --binary --image-stream openjdk-17 --name logging 3 oc start-build logging --from-dir target/openshift 4
oc new-app logging oc expose svc/logging
oc get route logging --template='{{ .spec.host }}'
http://ROUTE_NAME/hello
oc get pods
oc logs APP_POD_NAME
mvn archetype:generate -DgroupId=com.example.webclustering -DartifactId=web-clustering -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false cd web-clustering
<properties> <bootable.jar.maven.plugin.version>9.0.1.Final-redhat-00009</bootable.jar.maven.plugin.version> </properties>
<plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>USD{bootable.jar.maven.plugin.version}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> <layers> <layer>datasources-web-server</layer> <layer>web-clustering</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins>
<?xml version="1.0" encoding="UTF-8"?> <web-app version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"> <distributable/> </web-app>
mkdir -p APPLICATION_ROOT /src/main/java/com/example/webclustering/
package com.example.webclustering; import java.io.IOException; import java.io.PrintWriter; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @WebServlet(urlPatterns = {"/clustering"}) public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("text/html;charset=UTF-8"); long t; User user = (User) request.getSession().getAttribute("user"); if (user == null) { t = System.currentTimeMillis(); user = new User(t); request.getSession().setAttribute("user", user); } try (PrintWriter out = response.getWriter()) { out.println("<!DOCTYPE html>"); out.println("<html>"); out.println("<head>"); out.println("<title>Web clustering demo</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Session id " + request.getSession().getId() + "</h1>"); out.println("<h1>User Created " + user.getCreated() + "</h1>"); out.println("<h1>Host Name " + System.getenv("HOSTNAME") + "</h1>"); out.println("</body>"); out.println("</html>"); } } }
package com.example.webclustering; import java.io.Serializable; public class User implements Serializable { private final long created; User(long created) { this.created = created; } public long getCreated() { return created; } }
mvn package
java -jar target/web-clustering-bootable.jar -Djboss.node.name=node1 java -jar target/web-clustering-bootable.jar -Djboss.node.name=node2 -Djboss.socket.binding.port-offset=10
<plugins> <plugin> ... <!-- You must evolve the existing configuration with the <cloud/> element --> <configuration > <cloud/> </configuration> </plugin> </plugins>
mvn clean package
oc new-project bootable-jar-project
oc policy add-role-to-user view system:serviceaccount:USD(oc project -q):default
mkdir target/openshift && cp target/web-clustering-bootable.jar target/openshift 1 oc import-image ubi8/openjdk-17 --from=registry.redhat.io/ubi8/openjdk-17 --confirm 2 oc new-build --strategy source --binary --image-stream openjdk-17 --name web-clustering 3 oc start-build web-clustering --from-dir target/openshift 4
oc new-app web-clustering -e KUBERNETES_NAMESPACE=USD(oc project -q) oc expose svc/web-clustering
oc get route web-clustering --template='{{ .spec.host }}'
http://ROUTE_NAME/clustering
oc scale --replicas=2 deployments web-clustering
oc get pods
http://ROUTE_NAME/clustering
mvn archetype:generate -DgroupId=com.example.auth -DartifactId=authentication -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false cd authentication
<properties> <bootable.jar.maven.plugin.version>9.0.1.Final-redhat-00009</bootable.jar.maven.plugin.version> </properties>
<plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>USD{bootable.jar.maven.plugin.version}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-xp-5.0</artifactId> </manifest> </channel> </channels> <feature-pack-location>org.jboss.eap.xp:wildfly-galleon-pack</feature-pack-location> <layers> <layer>datasources-web-server</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins>
<?xml version="1.0" encoding="UTF-8"?> <web-app version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"> <login-config> <auth-method>BASIC</auth-method> <realm-name>Example Realm</realm-name> </login-config> </web-app>
mkdir -p APPLICATION_ROOT/src/main/java/com/example/authentication/
package com.example.authentication; import jakarta.servlet.annotation.HttpMethodConstraint; import jakarta.servlet.annotation.ServletSecurity; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet(urlPatterns = "/hello") @ServletSecurity(httpMethodConstraints = { @HttpMethodConstraint(value = "GET", rolesAllowed = { "Users" }) }) public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { PrintWriter writer = resp.getWriter(); writer.println("Hello " + req.getUserPrincipal().getName()); writer.close(); } }
/subsystem=elytron/properties-realm=bootable-realm:add(users-properties={relative-to=jboss.server.config.dir, path=bootable-users.properties, plain-text=true}, groups-properties={relative-to=jboss.server.config.dir, path=bootable-groups.properties}) /subsystem=elytron/security-domain=BootableDomain:add(default-realm=bootable-realm, permission-mapper=default-permission-mapper, realms=[{realm=bootable-realm, role-decoder=groups-to-roles}]) /subsystem=undertow/application-security-domain=other:write-attribute(name=security-domain, value=BootableDomain)
<cli-sessions> <cli-session> <script-files> <script>scripts/authentication.cli</script> </script-files> </cli-session> </cli-sessions>
mkdir -p APPLICATION_ROOT/extra-content/standalone/configuration/
testuser=bootable_password
testuser=Users
<extra-server-content-dirs> <extra-content>extra-content</extra-content> </extra-server-content-dirs>
mvn package
mvn wildfly-jar:run
mvn wildfly-jar:run -Dwildfly.bootable.arguments=--cli-script=scripts/authentication.cli
curl -v http://localhost:8080/hello
HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="Example Realm"
curl -v -u testuser:bootable_password http://localhost:8080/hello
HTTP/1.1 200 OK . Hello testuser
build: uri: <git repository URL of your application> mode: s2i
build: uri: <git repository URL of your application> mode: s2i sourceSecret: <name of secret login to your Git repository>
volumes: - name: eap-jgroups-keystore-volume secret: secretName: eap-app-secret
volumeMounts: - name: eap-jgroups-keystore-volume mountPath: /etc/jgroups-encrypt-secret-volume readOnly: true
<subsystem xmlns="urn:wildfly:opentelemetry:1.0" service-name="example"> <exporter type="otlp" endpoint="http://localhost:4317"/> <span-processor type="batch" batch-delay="4500" max-queue-size="128" max-export-batch-size="512" export-timeout="45"/> <sampler type="on"/> </subsystem>
/extension=org.wildfly.extension.opentelemetry:add
/subsystem=opentelemetry:add
reload
/subsystem=opentelemetry:write-attribute(name=exporter-type, value= <exporter_type> )
/subsystem=opentelemetry:write-attribute(name=exporter-type, value=otlp)
/subsystem=opentelemetry:write-attribute(name=endpoint, value= <URL:port> )
/subsystem=opentelemetry:write-attribute(name=endpoint, value=http://localhost:4317)
/subsystem=opentelemetry:write-attribute(name=service-name, value= <service_name> )
/subsystem=opentelemetry:write-attribute(name=service-name, value=exampleOpenTelemetryService)
mp.jwt.verify.publickey.location=META-INF/public.pem mp.jwt.verify.issuer=jwt-issuer
@Outgoing("to") public int send() { int i = // Randomly generated return i; } @Incoming("from") public void receive(int i) { // Process payload }
@Path("/") @ApplicationScoped class MyBean { @Inject @Channel("my-stream") Emitter<String> emitter; 1 Publisher<String> dest; public MyBean() { 2 } @Inject public MyBean(@Channel("my-stream") Publisher<String> dest) { this.dest = subscribeAndAllowMultipleSubscriptions(dest); } private Publisher subscribeAndAllowMultipleSubscriptions(Publisher delegate) { } 3 4 5 @POST public PublisherBuilder<String> publish(@FormParam("value") String value) { return emitter.send(value); } @GET public Publisher poll() { return dest; } @PreDestroy public void close() { 6 } }
@Inject @Channel("from-user") Emitter<Integer> emitter; @Incoming("from-user") @Outgoing("to-kafka") public Message<Integer> send(Message<Integer> msg) { // Set the key in the metadata OutgoingKafkaRecordMetadata<String> md = OutgoingKafkaRecordMetadata.<String>builder() .withKey("KEY-" + i) .build(); // Note that Message is immutable so the copy returned by this method // call is not the same as the parameter to the method return KafkaMetadataUtil.writeOutgoingKafkaMetadata(msg, md); } @Incoming("from-kafka") public CompletionStage<Void> receive(Message<Integer> msg) { IncomingKafkaRecordMetadata<String, Integer> metadata = KafkaMetadataUtil.readIncomingKafkaMetadata(msg).get(); // We can now read the Kafka record key String key = metadata.getKey(); // When using the Message wrapper around the payload we need to explicitly ack // them return msg.ack(); }
kafka.bootstrap.servers=kafka:9092 mp.messaging.outgoing.to-kafka.connector=smallrye-kafka mp.messaging.outgoing.to-kafka.topic=some-topic mp.messaging.outgoing.to-kafka.value.serializer=org.apache.kafka.common.serialization.IntegerSerializer mp.messaging.outgoing.to-kafka.key.serializer=org.apache.kafka.common.serialization.StringSerializer mp.messaging.incoming.from-kafka.connector=smallrye-kafka mp.messaging.incoming.from-kafka.topic=some-topic mp.messaging.incoming.from-kafka.value.deserializer=org.apache.kafka.common.serialization.IntegerDeserializer mp.messaging.incoming.from-kafka.key.deserializer=org.apache.kafka.common.serialization.StringDeserializer
kafka.bootstrap.servers=kafka:9092 mp.messaging.outgoing.to.connector=smallrye-kafka mp.messaging.outgoing.to.topic=my-topic mp.messaging.outgoing.to.value.serializer=org.apache.kafka.common.serialization.IntegerSerializer mp.messaging.incoming.from.connector=smallrye-kafka mp.messaging.incoming.from.topic=my-topic mp.messaging.incoming.from.value.deserializer=org.apache.kafka.common.serialization.IntegerDeserializer
@Outgoing("to") public int send() { int i = // Randomly generated return i; } @Incoming("from") public void receive(int i) { // Process payload }
amqp-host=localhost amqp-port=5672 amqp-username=artemis amqp-password=artemis mp.messaging.outgoing.to.connector=smallrye-amqp mp.messaging.outgoing.to.address=my-topic mp.messaging.incoming.from.connector=smallrye-amqp mp.messaging.incoming.from.address=my-topic
amqp-use-ssl=true mp.messaging.connector.smallrye-amqp.wildfly.elytron.ssl.context=exampleSSLContext
mp.messaging.incoming.from.wildfly.elytron.ssl.context=exampleSSLContext
/subsystem=elytron/client-ssl-context=exampleSSLContext:add(key-manager=exampleServerKeyManager,trust-manager=exampleTLSTrustManager)