# WildFly ## Events ### [events/wmc-202511.adoc](/events/wmc-202511.html) ### [events/wmc-202503.adoc](/events/wmc-202503.html) ### [events/wmc-202411.adoc](/events/wmc-202411.html) ### [events/wmc-202403.adoc](/events/wmc-202403.html) ## Posts ### [WildFly 41 is released!](/news/2026/07/16/WildFly-41-is-released/) I’m happy to announce that the new WildFly, WildFly EE 10 and WildFly Preview 41.0.0.Final releases are available for download at https://wildfly.org/downloads. The Galleon feature-packs for WildFly 41 are available in Maven Central. New and Notable We feature-boxed the WildFly 40 release in order to deliver EE 11 support, which meant it was released over a month later than our normal January/April/July/October cadence. We wanted to get back to the normal cadence for WildFly 41. This meant the development cycle for 41 was quite short, but we were still able to provide quite a lot of new goodies: Bootable jars We’ve enhanced the wildfly-cloud-galleon-pack and the wildfly-maven-plugin to support bootable jar packaging on the cloud. You can now take advantage of the cloud optimizations provided by the wildfly-cloud-galleon-pack when using a bootable jar. JDK 25 images We have introduced a JDK 25 variant of our container image, S2I builder image and runtime image. These JDK 25 images replace the previous JDK 17 images, which are no longer being updated. UBI 10 images We also shifted our images from basing on ubi9-minimal to ubi10-minimal. We promoted a number of existing features to a higher stability level, making them newly available in servers that are limited to that stability level: In WildFly 32, we added preview stability support for configuring additional scope values for OpenID Connect authentication requests. This feature is now provided at the community stability level. In WildFly 33, we added preview stability elytron-oidc-client subsystem support for authentication requests sent as a signed and encrypted request object. This feature is now provided at the community stability level. In WildFly 39 we added community stability support for TLS configuration for TCP-based JGroups transport protocols. This feature is now provided at the default stability level. In WildFly 40 we added preview stability support for logging out of an application secured with OIDC. This feature is now provided at the default stability level. We also introduced a couple of notable behavior improvements in the HA/clustering and transaction management areas: Infinispan cache stores now default to non-segmented storage, changing the previous default behavior. The JGroups FD_SOCK2 failure detection ports were moved out of the OS ephemeral port range to prevent conflicts, with the port_range set to 0 for deterministic binding. We added a new transactions-recovery-graceful-shutdown attribute in the transactions subsystem. When set to wait, this allows transaction recovery to continue operating during a WildFly graceful shutdown, helping avoid data loss for in-flight transactions. Work on transaction recovery and graceful shutdown is ongoing. Finally, we updated a wide range of dependencies to their latest versions, improving performance, stability, and security. Notable upgrades include: Apache MINA SSHD 2.18.0, addressing CVE-2026-48827 Apache Artemis 2.54, addressing CVE-2026-32642 Apache CXF 4.1.8-jbossorg-1, addressing numerous CVEs Jackson 2.21.5, addressing numerous CVEs and GHSA-mhm7-754m-9p8w Netty 4.1.136, addressing numerous CVEs Hibernate ORM 7.4.5 in standard WildFly and WildFly Preview Hibernate Search 8.4.0 in standard WildFly and WildFly Preview WildFly EE 10 Variant The WildFly 41 release includes an update of the "WildFly EE 10" variant that we introduced with WildFly 40. While standard WildFly and WildFly Preview have moved on to EE 11, the WildFly EE 10 variant still supports the EE 10 specifications. The purpose of WildFly EE 10 is to give our users a bit more time to migrate to EE 11 following standard WildFly 40’s move to EE 11, while still getting the bug fixes and non-EE-specific features that come with keeping up with the latest release. For more on WildFly EE 10, please see: Our Using the WildFly EE 10 Feature-pack step-by-step guide to using WildFly EE 10. The Different Flavors of WildFly document, which delves more deeply into the differences between standard WildFly, WildFly EE 10 and WildFly Preview. The WildFly Maven Plugin Guide which explains more about how to use WildFly EE 10 when configuring provisioning in your pom.xml. The Galleon Provisioning Guide, for those who use the Galleon CLI tool to provision. Important WildFly EE 10 is a temporary addition to the set of WildFly variants. We plan to produce a WildFly EE 10 variant for 40.0.0.Final, 40.0.1.Final, 41.0.0.Final and 41.0.1.Final. We will discontinue the variant with WildFly 42, which is planned for the fall of 2026. Supported Specifications Jakarta Standard WildFly 41 supports the EE 11 Platform as well as the Web Profile and the Core Profile. WildFly is EE 11 Platform, Web Profile and Core Profile compatible when running on Java SE 17 and Java SE 21. Evidence demonstrating our compatibility is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence EE 11 Full Platform SE 17 SE 21 EE 11 Web Profile SE 17 SE 21 EE 11 Core Profile SE 17 SE 21 WildFly EE 10 41 supports the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly EE 10 is EE 10 Platform, Web Profile and Core Profile compatible when running on Java SE 17 and Java SE 21. Evidence demonstrating our compatibility is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence EE 10 Full Platform SE 17 SE 21 EE 10 Web Profile SE 17 SE 21 EE 10 Core Profile SE 17 SE 21 MicroProfile WildFly 41 supports the MicroProfile Platform 7.1 specifications, along with several other MicroProfile specifications that are not part of the MicroProfile Platform. The full listing is available in the Getting Started Guide. Compatibility evidence for the specifications that are part of MicroProfile 7.1 can be found in the WildFly Certifications repository on GitHub. WildFly Preview For the 41 release, standard WildFly and WildFly Preview are providing implementations of the same set of standards, although there are other differences between the two, as outlined in the Different Flavors of WildFly document. Beginning with WildFly Preview 42, we hope to begin bringing early milestone releases of EE 12 APIs and implementations into WildFly Preview. Important The WildFly project makes no claims about the compatibility of WildFly Preview with the Jakarta and MicroProfile specifications it implements. Java SE Support Our recommendation is that you run standard WildFly 41 and WildFly Preview 41 on Java SE 25, since that is the latest LTS JDK release. For WildFly EE 10 our recommendation is that you run on Java SE 21. This is not because of any significant issues we are aware of with running on SE 25, other than if you run with the Java SecurityManager enabled. SE 25 does not support enabling the SecurityManager. The EE 10 specifications require support for the SecurityManager in some contexts. Note We do not claim to be compatible with EE 11 on SE 25. We are satisfied with what we see when running the TCKs on SE 25, so we are comfortable making SE 25 our recommended SE version for standard WildFly 41. However, if running WildFly on an SE version where it passes the EE TCKs is important to you, we suggest using SE 21 or 17. All three WildFly 41 variants — standard WildFly, WildFly EE 10 and WildFly Preview — are heavily tested and run well on Java 25, 21 and 17. Our recommendation of a later SE version over SE 21 or SE 17 is solely because as a general principle we recommend being on later LTS releases, not because of any problems with WildFly on the other supported LTS versions. While we recommend using LTS releases outside of development environments, we believe WildFly runs well on SE 26, which is the most recent non-LTS release, released this March. By runs well, I mean the main WildFly nightly testsuite jobs produce results equivalent to what we see with SE 17, SE 21 and SE 25. We want developers who are trying to evaluate what SE 26 means for their applications to be able to look to WildFly as a useful development platform. Please note that WildFly runs in classpath mode. Warning It is likely that WildFly will withdraw support for SE 17 in some release in the next year. We do not plan to do so in WildFly 42 though, unless some required components stop supporting SE 17. In any case, we recommend that users on SE 17 migrate their workloads to SE 21 or 25. Incompatible Changes There are some incompatible changes in WildFly 41 that may affect some users: As discussed in the New and Notable section, container images are available for JDK 21 and 25 on UBI 10 minimal. There is no longer a container image for JDK 17 (the JDK 21 image can safely replace its usage). The latest tag now points to the JDK 25 image. We also added a JDK 25 variant of our S2I builder image and runtime image, and stopped producing new JDK 17 variants. The existing JDK 17 images can still work with WildFly 41, but they are seriously out-of-date when it comes to security vulnerability patches. Users are strongly encouraged to move to the current images. We deprecated support for the AJP listener in the undertow subsystem. Including the ajp-listener in your configuration will result in a WARN message in the log. The AJP listener is deprecated due to its inherent security deficiencies (no encryption, no authentication, CVEs), its inability to support modern protocols (WebSocket, HTTP/2), and protocol stagnation (no development since 2001). Users should migrate to HTTP proxying which offers all the same functionality with proper TLS and mutual authentication support. We have stopped deploying tar.gz files to Maven Central for our pre-built installations (e.g. org.wildfly:wildfly-dist). Maven Central quite reasonably imposes limits on the size of upload bundles used when publishing a release, and the size of the WildFly release bundles was far over the limit, particularly since the introduction of WildFly EE 10 and its pre-built installations. We needed to go on a diet, both to avoid needing to ask for permission to exceed the limit and, more importantly, to avoid placing an unnecessary burden on Maven Central and the people who maintain it. So, we stopped deploying the tar.gz files. The zip artifacts are still available. You can still get tar.gz files from https://wildfly.org/downloads or the GitHub release page for a release. New and Noteworthy Contributors WildFly gets great contributions from so many people. Time to thank a few of them! @aidentZhang made their first contribution in #20107 @christosderetzis made their first contribution in #20096 @xfocus3 made their first contribution in #20158 @NiasSt90 made their first contribution in #20130 @cruiztorresj made their first PR contribution to main code base in #20194 and made a number of other helpful contributions during over the last few months. @Ohifeme made their first WildFly Core contribution in #6806 Thank you, all! It’s great to see so many new contributors! Rado Husar did great stuff all over the place, from driving the JGroups TLS support feature promotion, to finding and resolving critical bugs, to clearing lots of technical debt, to being the key person keeping our PR queue (somewhat) under control. Thank you, Rado! Release Notes The full WildFly 41 release notes are available in GitHub. Issues fixed in the underlying WildFly Core 33.0.0 release are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. Best regards, Brian ### [A2A Jakarta 1.0.0.CR2 is released!](/news/2026/06/29/A2A-Jakarta-1-0-0-CR2-is-released/) I am happy to announce the 1.0.0.CR2 release of A2A Jakarta. This release upgrades to a2a-java 1.1.0.Final and includes several improvements of its own. a2a-java 1.1.0.Final The headline feature of a2a-java 1.1.0.Final is a new Task Authorization SPI (TaskAuthorizationProvider) that enables per-user task authorization — particularly useful for multi-tenant deployments. It also includes several bug fixes such as disabling HTML escaping in protobuf JSON serialization, CDI request context handling improvements, and more. See the a2a-java 1.1.0.Final release announcement for full details. Task Authorization Tests Building on the new Task Authorization SPI from a2a-java, this release adds comprehensive authorization integration tests across all transports (JSON-RPC, REST, and gRPC), including v0.3 compatibility and multiversion variants. Simplified Multiversion Routing The multiversion routing architecture has been significantly simplified. Six -web and multiversion- modules have been replaced with @PreMatching filters in http-common that discover A2AVersionProvider beans via CDI and rewrite request URIs to version-prefixed internal paths. This makes the module structure cleaner and reduces the number of dependencies needed for multiversion deployments. Hardened HTTP Common Module The http-common module has been hardened with RFC 8259-compliant JSON escaping for control characters, improved charset handling and exception chaining, deterministic version ordering, and unit tests for all filters and version resolution. ITK Module A new ITK (Interoperability Test Kit) module has been added for cross-SDK interoperability testing, helping to ensure that A2A Jakarta works correctly with other A2A implementations. Get Involved If you have any issues with the project, please open an issue. Also, pull requests are welcome! ### [New WildFly 41 Beta release](/news/2026/06/26/New-WildFly-41-Beta-release/) I am pleased to announce that the WildFly 41 Beta release is now available and ready for download. We normally have a three month interval between our Beta releases but due to the delays releasing WildFly 40 Beta this time we had less than two months. I am pleased to confirm we have the following features and promotions in this release: WFLY-17742 [Default] Support Transactions during WildFly’s graceful shutdown WFLY-19496 [Community] Promote OIDC scope attribute from Preview to community stability level WFLY-20037 [Community] Promote ability to specify that the OIDC Authentication Request should include request and request_uri parameters to community stability level WFLY-20810 WildFly Maven Plugin, bootable JAR packaging for the cloud WFLY-21473 [Default] Promote "TLS support to JGroups TCP transport" WFLY-21989 [DEFAULT] Promote OIDC Logout to default stability These features are a small representation of the changes, many more changes made to WildFly. Preparing the release notes GitHub tells me 28 people contributed to this release and that does not include all of the people working on the components that make WildFly possible so we thank everyone for your contributions. I would also like to thank the following first time contributors this release: @aidentZhang made their first contribution in #20107 @christosderetzis made their first contribution in #20096 @xfocus3 made their first contribution in #20158 @NiasSt90 made their first contribution in #20130 We encourage you to explore the full list of changes in the official release notes. How to Get Involved This is a beta release, so we don’t recommend it for production environments. Your feedback is crucial to help us identify and fix issues before the final release. Download WildFly 41 Beta 1 from https://wildfly.org/downloads or provision a WildFly 41 Beta 1 server using a tool like the wildfly-maven-plugin Report a bug or enhancement request on our issue tracker Ask a question Google Group or reach us on Zulip. We look forward to hearing your feedback and working together to complete WildFly 41 Final. ### [WildFly 40.0.1 is released!](/news/2026/06/19/WildFly-40-0-1-is-released/) WildFly 40.0.1.Final is now available for download. The full release notes are available in GitHub. Provide any feedback in the WildFly google group, Zulip or JIRA. Enjoy! ### [A2A Jakarta 1.0.0.CR1 is released!](/news/2026/06/11/A2A-Jakarta-1-0-0-CR1-is-released/) I am pleased to announce the 1.0.0.CR1 release of A2A Jakarta (formerly the A2A Java SDK for Jakarta). This release supports version 1.0 of the A2A Protocol Specification and is built on top of a2a-java 1.0.0.Final, whose highlights are covered in its release announcement. This post also covers the highlights from the 1.0.0.Beta1 release, which did not have its own announcement. New Repository Name and Coordinates The repository has been renamed from wildfly-extras/a2a-java-sdk-server-jakarta to wildfly-extras/a2a-jakarta. Alongside this, the Maven artifact IDs and Java package names have been simplified: Artifact IDs now use the a2a-jakarta- prefix instead of a2a-java-sdk-jakarta-. For example, a2a-java-sdk-jakarta-jsonrpc becomes a2a-jakarta-jsonrpc. Java packages now use org.wildfly.a2a.jakarta as the root package. The groupId remains org.wildfly.a2a. If you are upgrading from a previous release, you will need to update your Maven dependencies and Java imports accordingly. For example, to use the JSON-RPC module: <dependency> <groupId>org.wildfly.a2a</groupId> <artifactId>a2a-jakarta-jsonrpc</artifactId> <version>1.0.0.CR1</version> </dependency> v0.3 Protocol Compatibility Layer The headline feature of this release is a compatibility layer for version 0.3 of the A2A Protocol. As the protocol evolved from v0.3 to v1.0, there were significant breaking changes. The compatibility layer lets you support v0.3 clients without maintaining a separate codebase. The key design principle is that you only need a single AgentExecutor implementation. The compatibility layer intercepts incoming v0.3 requests, converts them to v1.0 format, and delegates to your existing executor. This means you write your agent logic once against the v1.0 API, and v0.3 support comes for free. There are three deployment modes: Standalone v0.3 If you need to deploy an application that only speaks v0.3, use the compat-0.3 modules instead of the v1.0 ones. The dependency names follow the same pattern with a compat-0.3 prefix: org.wildfly.a2a:a2a-jakarta-compat-0.3-jsonrpc and a2a-jakarta-compat-0.3-jsonrpc-web for JSON-RPC org.wildfly.a2a:a2a-jakarta-compat-0.3-grpc for gRPC org.wildfly.a2a:a2a-jakarta-compat-0.3-rest and a2a-jakarta-compat-0.3-rest-web for REST Multiversion (v0.3 + v1.0) The most interesting mode is serving both protocol versions from the same deployment. To do this, you add the v0.3 compat dependencies alongside your v1.0 ones, plus the multiversion dispatching modules (a2a-jakarta-compat-0.3-multiversion-jsonrpc and a2a-jakarta-compat-0.3-multiversion-rest). These modules register JAX-RS resources that inspect incoming requests and route them to the correct protocol handler — v0.3 requests go through the compatibility conversion layer while v1.0 requests are handled directly. You can see how the project’s own TCK sets this up with a Maven profile in the tck/pom.xml. As with the other modes, only a single AgentExecutor is needed. The one additional requirement is that you provide agent cards for both protocol versions — typically one is your "real" card and the other is either a stub or derived from it. See the README for detailed instructions and examples. Agent Card Compatibility When serving both protocol versions, the v1.0 AgentCard is what clients receive. To ensure v0.3 clients can parse it, the card needs some backward-compatibility fields. You can either set these manually or use the Compat03Fields.addCompat03FieldsIfAvailable() utility method. Other Highlights a2a-java 1.0.0.Final — We are now aligned with the final release of the upstream a2a-java SDK. gRPC Feature Pack 0.2.0 — Upgraded to the latest WildFly gRPC Feature Pack. WildFly 40 — The TCK now runs on WildFly 40. CI on Windows — The CI pipeline now runs on both Linux and Windows. Get Involved If you have any issues with the project, please open an issue. Also, pull requests are welcome! ### [WildFly 40 is released!](/news/2026/05/21/WildFly-40-is-released/) It’s taken longer than our normal three months, but I’m thrilled to announce that the new WildFly, WildFly EE 10 and WildFly Preview 40.0.0.Final releases are available for download at https://wildfly.org/downloads. The Galleon feature-packs for WildFly 40 are available in Maven Central. New and Notable Here’s what’s new: Support for EE 11 — The standard WildFly distributions and feature-packs, the ones most people use, now provide the EE 11 APIs! For more on this, see the EE 11 Support section below. New WildFly EE 10 variant — Since standard WildFly has moved on to EE 11, we’ve introduced, for a limited time only, a new WildFly EE 10 variant of the server, one that continues to provide the EE 10 APIs. For more on this, see the New WildFly EE 10 Variant section below. Hashicorp Vault — On the security front many users have been asking for an integration with Hashicorp Vault, and we are excited to announce that this is available in the form of a new feature-pack. Please visit Diana Křepinská’s blog post for more details on how to get started with this integration. This feature is provided at the community stability level. Logout support for OIDC — WildFly now supports logging out of an application secured with OIDC using RP-Initiated Logout, Front-Channel Logout, and Back-Channel Logout. This feature is provided at the preview stability level. Brute force authentication attack mitigation — Starting from WildFly 39.0.1 by default all security realms are wrapped by a new utility to add brute force protection to help mitigate against brute force attacks. After 10 consecutive failed authentication attempts an identity will be disabled for 15 minutes. This feature is provided at the default stability level. Prospero update to a specific version — Users of the Prospero provisioning tool and WildFly Channels can now use Prospero to perform an update/downgrade of their server installation to an arbitrary version of a WildFly channel. This feature is provided at the default stability level. Note We’re hoping to expand the visibility of the Prospero tool and WildFly Channels over the next year. We promoted a number of existing features to a higher stability level, making them newly available in servers that are limited to that stability level: In WildFly 32, we added support for an SSLContext that can dynamically delegate to different SSL contexts based on destination’s host and port. This feature is now provided at the default stability level. In WildFly 33, the undertow subsystem began supporting configuring the AJP listener to accept custom AJP request headers. This feature is now provided at the default stability level. In WildFly 33, the undertow subsystem began supporting configuring the reverse proxy handler to reuse and append to any X-Forwarded HTTP headers and to rewrite the Host header. This feature is now provided at the default stability level. In WildFly 35, we added support for Jakarta Data 1.0 to standard WildFly. This feature is now provided at the community stability level. We’ve also updated a wide range of dependencies to their latest versions, improving performance, stability, and security. Besides the many components updated due to the move from EE 10 to EE 11, notable upgrades include: Apache Artemis 2.53, addressing CVE-2026-32642 Hibernate 7.3.2 Jackson 2.21.1, addressing CVE-2026-29062 Micrometer 1.16 Netty 4.1.133, addressing numerous CVEs Undertow 2.4.0, addressing CVE-2026-28367, CVE-2026-28368 and CVE-2026-28369 Vert.x 4.5.24, addressing CVE-2026-1002 WildFly Elytron 2.9.0 and Elytron Web 4.2.0 WildFly Glow 2.0.0 WildFly OpenSSL 2.3.0 EE 11 Support After incubating it in WildFly Preview since WildFly Preview 32, with WildFly 40 we’ve moved standard WildFly to EE 11. The key improvements in EE 11 are: Support for the repository pattern in your data persistence tier with Jakarta Data, in WildFly’s case backed by Hibernate Data Repositories. Many improvements in Jakarta Persistence 3.2. Note In the original version of this post I stated that standard WildFly 40 supports the use of virtual threads in Jakarta Concurrency services. This is incorrect. Support for virtual threads is an optional feature in Jakarta Concurrency 3.1, the spec version included in EE 11 and supported by standard WildFly. But we do not yet support their use in WildFly. My apologies for getting this wrong. Note EE 11 removed a number of specifications in the XML and Webservices area from the EE platform. However, those specifications still exist as standalone Jakarta specifications, and WildFly continues to support them. This includes continuing to have the subsystems that provide them present in our out-of-the-box configuration files. New WildFly EE 10 Variant While for most applications moving to EE 11 should be straightforward, we recognize that users may want some time to complete their migration after standard WildFly first introduces support. But, they still want the bug fixes and non-EE-specific features that come with keeping up with the latest release. To help support these users, we’ve introduced a new wildfly-ee-10 feature-pack (Maven GAV org.wildfly:wildfly-ee-10-feature-pack:40.0.0.Final) along with pre-built server zips and tars that use it. If you are using pre-built server zips or tars, the WildFly EE 10 files are available from https://wildfly.org/downloads right next to the standard WildFly ones. The new feature-pack is an alternative to the wildfly-ee feature-pack that has long provided most of the functionality in a standard WildFly installation. In WildFly 40 the wildfly-ee feature-pack has moved on to providing EE 11, while the new wildfly-ee-10 feature-pack still provides EE 10. Non-EE-specific functionality is common between the two feature-packs. Most WildFly users who use our Galleon tooling for provisioning a server use the wildfly feature-pack, which implicitly depends on wildfly-ee and adds "expansion" functionality, like MicroProfile, to it. If you use the wildfly feature-pack you get wildfly-ee without needing to explicitly declare. You can still use the wildfly feature-pack with wildfly-ee-10; you just additionally need to declare explicitly in your provisioning configuration the wildfly-ee-10 feature-pack. This lets the tooling know you want to use the alternative to the default wildfly-ee. For more on this, please see: Our new Using the WildFly EE 10 Feature-pack step-by-step guide to using WildFly EE 10. The Different Flavors of WildFly document, which delves more deeply into the differences between standard WildFly, WildFly EE 10 and WildFly Preview. The WildFly Maven Plugin Guide which explains more about how to use WildFly EE 10 when configuring provisioning in your pom.xml. The Galleon Provisioning Guide, for those who use the Galleon CLI tool to provision. Important WildFly EE 10 is a temporary addition to the set of WildFly variants. We plan to produce a WildFly EE 10 variant for 40.0.0.Final, 40.0.1.Final, 41.0.0.Final and 41.0.1.Final. We expect to discontinue the variant with WildFly 42, which is planned for the fall of 2026. Supported Specifications Jakarta Standard WildFly 40 supports the EE 11 Platform as well as the Web Profile and the Core Profile. WildFly is EE 11 Platform, Web Profile and Core Profile compatible when running on Java SE 17 and Java SE 21. Evidence demonstrating our compatibility is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence Jakarta EE 11 Full Platform SE 17 SE 21 Jakarta EE 11 Web Profile SE 17 SE 21 Jakarta EE 11 Core Profile SE 17 SE 21 WildFly EE 10 40 supports the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly EE 10 is EE 10 Platform, Web Profile and Core Profile compatible when running on Java SE 17 and Java SE 21. Evidence demonstrating our compatibility is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence Jakarta EE 10 Full Platform SE 17 SE 21 Jakarta EE 10 Web Profile SE 17 SE 21 Jakarta EE 10 Core Profile SE 17 SE 21 MicroProfile WildFly 40 supports the MicroProfile Platform 7.1 specifications, along with several other MicroProfile specifications that are not part of the MicroProfile Platform. The full listing is available in the Getting Started Guide. Compatibility evidence for the specifications that are part of MicroProfile 7.1 can be found in the WildFly Certifications repository on GitHub. WildFly Preview Beginning with the WildFly 32 release, we used WildFly Preview to provide an early look at our evolving support for EE 11. With WildFly 40 that work is completed, and standard WildFly now supports EE 11. Therefore, for the 40 release, standard WildFly and WildFly Preview are providing implementations of the same set of standards, although there are other differences between the two, as outlined in the Different Flavors of WildFly document. Beginning with WildFly Preview 41, we expect to begin bringing early milestone releases of EE 12 APIs and implementations into WildFly Preview. Important The WildFly project makes no claims about the compatibility of WildFly Preview with the Jakarta and MicroProfile specifications it implements. Java SE Support Our recommendation is that you run standard WildFly 40 and WildFly Preview 40 on Java SE 25, since that is the latest LTS JDK release. This is a change from WildFly 39, where we recommended SE 21. We’ve changed our recommendation because we have completed the full set of testing we like to do before recommending a particular SE version. For WildFly EE 10 our recommendation is that you run on Java SE 21. This is not because of any significant issues we are aware of with running on SE 25, other than if you run with the Java SecurityManager enabled. SE 25 does not support enabling the SecurityManager. We recommend SE 21 because part of our qualification criteria for recommending a particular SE version is getting acceptable results when running the EE TCKs using that version. The EE 10 specifications require support for the SecurityManager in some contexts, and the EE 10 TCKs are written assuming the SecurityManager can be enabled. As a result, we haven’t gotten useful information when running the EE 10 TCKs on SE 25. Note We do not claim to be compatible with EE 11 on SE 25. We are satisfied with what we see when running the TCKs on SE 25, so we are comfortable making SE 25 our recommended SE version for standard WildFly 40. However, if running WildFly on an SE version where it passes the EE TCKs is important to you, we suggest using SE 21 or 17. All three WildFly 40 variants — standard WildFly, WildFly EE 10 and WildFly Preview — are heavily tested and run well on Java 25, 21 and 17. Our recommendation of a later SE version over SE 21 or SE 17 is solely because as a general principle we recommend being on later LTS releases, not because of any problems with WildFly on the other supported LTS versions. While we recommend using LTS releases outside of development environments, we believe WildFly runs well on SE 26, which is the most recent non-LTS release, released this March. By runs well, I mean the main WildFly nightly testsuite jobs produce results equivalent to what we see with SE 17, SE 21 and SE 25. We want developers who are trying to evaluate what SE 26 means for their applications to be able to look to WildFly as a useful development platform. Please note that WildFly runs in classpath mode. Warning It is likely that WildFly will withdraw support for SE 17 in some release in the next year. Certainly not in WildFly 41, though. We recommend that users on SE 17 migrate their workloads to SE 21 or 25. Incompatible Changes There are some incompatible changes in WildFly 40 that may affect some users: A standard WildFly or WildFly Preview server will fail to start if the Java SecurityManager is enabled, regardless of whether the underlying Java SE version still supports the SecurityManager. The EE 11 specifications do not require the SecurityManager and many libraries WildFly integrates to provide EE 11 support have removed logic that allow them to work properly with the SM enabled. So, since we cannot function correctly with the SM enabled, we abort the server boot. Apache Artemis changed the Maven groupId for its artifacts from org.apache.activemq to org.apache.artemis. This may impact users relying on our boms for dependency management. As part of the move to EE 11, standard WildFly removed support for EE ManagedBeans, an old EE programming model using the @ManagedBean annotation that has long been superseded by CDI. If you are impacted by this, please let us know. There is some possibility these could still be supported if there is real world demand. Note that these are still supported in WildFly EE 10. New and Noteworthy Contributors WildFly gets great contributions from so many people. Time to thank a few of them! Rhuan Hianc provided some outstanding information regarding high memory consumption seen when migrating from WildFly 24. This led to some significant improvements in the handling of deployments using Jakarta Enterprise Beans. James Perkins and Scott Marlow were tireless in their work enabling WildFly to pass the EE 11 TCKs. Get some well deserved rest, guys! Diana Křepinská, Ken Wills, Honza Kašík, Darran Lofthouse and Jason Lee delivered Hashicorp Vault integration via the new vault feature-pack. Rebecca Searls, as a parting gift before heading off into retirement, brought us the OIDC logout support feature. Enjoy your retirement, Rebecca, and thank you for your many years of contributions to WildFly! Darran Lofthouse does everything, plus goes to meetings. ;-) This time that everything includes lots of efforts for the three previous items, plus bringing our EE 11 implementations of Jakarta Authentication, Jakarta Authorization and Jakarta Security. Thank you, Darran! Release Notes The full WildFly 40 release notes are available in GitHub. Issues fixed in the underlying WildFly Core 32.0.0 release are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. Phew! That was a lot to write! Best regards, Brian ### [Introducing wado - WildFly Admin Containers](/news/2026/05/12/Introducing-wado-WildFly-Admin-Containers/) If you’ve ever needed to test WildFly across multiple versions, you know the drill: write docker commands by hand, calculate port offsets so containers don’t collide, come up with consistent naming, and repeat for every version you care about. When I’m working on the HAL management console, I regularly need to spin up five or more WildFly versions side by side to verify that changes work across releases. That’s a lot of repetitive container plumbing. I built wado (WildFly admin containers) to take care of all that. It’s a command-line tool written in Rust that builds and runs WildFly containers with sensible defaults for naming, ports, and credentials — so you can focus on the actual work. Installation wado is available via Homebrew or Cargo: brew install hpehl/tap/wado or cargo install wado Prebuilt binaries for macOS, Linux, and Windows are also available on the releases page. Quick Start Start a WildFly 39 standalone server: wado start 39 That’s it. wado pulls the image from quay.io/wado, creates a container named wado-sa-390, and publishes HTTP on port 8390 and management on port 9390. A default admin user and allowed origins for local development are already configured. See what’s running: wado ps Open the management console in your browser: wado console 39 Or connect the CLI: wado cli 39 Stop everything: wado stop 39 Version Expressions Where wado really shines is when you need multiple versions at once. Version expressions support ranges, multipliers, and enumerations: # Start WildFly 36 through 39 wado start 36..39 # Start three instances of WildFly 39 wado start 3x39 # Mix and match wado start 28,30..32,2x37 Each container gets a unique name and non-colliding ports automatically. No more mental arithmetic. The full grammar is described as a BNF in the README. See supported versions for the complete list of available WildFly versions. As soon as a new WildFly version gets released, wado will be updated. Domain Mode wado also supports domain mode. Start a domain controller: wado dc start 39 Then connect two host controllers to it: wado hc start 2x39 wado takes care of the networking between them. This makes it straightforward to set up domain topologies that would otherwise require quite a bit of manual configuration. Topology For more complex setups, you can define a complete domain topology in a YAML file and launch it with a single command: name: my-topology version: 39 hosts: - name: dc domain-controller: true - name: host1 servers: - name: server-one auto-start: true - name: server-two group: other-server-group - name: host2 version: 38 servers: - name: server-one Then start the entire topology: wado topology start my-topology.yaml This creates the domain controller and all host controllers with the specified servers, server groups, and port offsets — all wired together automatically. Customization All three modes — standalone, domain controller, and host controller — support further customization. Bootstrap Operations Use --operations to run management operations when the server starts. For example, to change the root log level to DEBUG: wado start 39 \ --operations /subsystem=logging/root-logger=ROOT:write-attribute(name=level,value=DEBUG) Server Configuration Domain and host controllers support the --server flag to define servers with server groups, port offsets, and auto-start: wado dc start 39 \ --server server-one:main-server-group:start \ --server server-two:other-server-group:200 WildFly Parameters You can pass parameters directly to the WildFly server using --. For example, to use a different server configuration: wado start 39 -- --server-config=standalone-microprofile.xml Dev Containers If you’re a WildFly contributor working on the server itself or the HAL console, wado can build containers directly from source: wado build dev wado start dev This clones the WildFly and HAL repositories, builds them, and creates a container image with your local changes. Dev containers use ports 8000 and 9000. Dev container images are built and pushed to quay.io by a nightly CI job, so they always reflect the latest state of the WildFly and HAL main branches. When you start a dev container, wado automatically pulls the latest image before starting it. Images wado uses prebuilt container images hosted at quay.io/wado. These images are based on the official WildFly images but come preconfigured for development and testing: Default admin credentials Allowed origins for localhost development (ports 1234, 8888, 9090) Access for the online HAL console You can list the images available locally: wado images Get Involved wado is open source and contributions are welcome! There are several areas where help would be appreciated: Bug reports and feature requests — if you use wado and run into issues or have ideas, please open an issue. Pull requests — whether it’s a bug fix, a new feature, or documentation improvements. You can find wado on GitHub and crates.io. Give it a try, and let us know what you think! ### [Next-Gen Management Console for WildFly](/news/2026/05/12/Next-Gen-Management-Console-for-WildFly/) We’re excited to share that we’ve been working on a next-generation management console for WildFly. At its core is HAL Foundation — a shared foundation that provides the building blocks for WildFly’s management console implementations. Built on top of HAL Foundation, halOP (HAL On Premise) is the next-gen management console and will be the successor to the existing HAL management console you know and love. halOP is a complete rewrite, built from the ground up using modern technologies like Java 21, J2CL (Java to JavaScript transpilation), Crysknife CDI, PatternFly Java, and Elemento. The result is a fresh, modern user experience that makes managing your WildFly instances easier and more enjoyable. The next-gen management console was also introduced at the WildFly Community Call on December 18. If you prefer a live walkthrough, you can watch the recording or browse the slides. What’s New The new console comes with a number of exciting features and improvements: Dashboard The new dashboard gives you an at-a-glance overview of your WildFly instance. It shows key information like the server status, WildFly and JVM version, management model version, and stability level — all in one place. We have lots of ideas for the dashboard and are actively looking for feedback. If you have suggestions for what you’d like to see on the dashboard, please join the discussion at #71. Themes and Accessibility halOP supports both light and dark themes, along with a contrast selector — making it more accessible and comfortable to use in different environments. Stability Level Indicators Resources, attributes, operations, and parameters now display their stability levels directly in the UI. This helps you quickly understand which features are stable, preview, or experimental. Use Case-Centric Tasks A brand-new top-level Tasks category lets you complete complex management tasks quickly. Tasks combine multiple steps and operations that involve configuring different subsystems and resources. For example, the "Statistics" task lets you manage the statistics-enabled attribute across multiple resources, with filtering and expression assignment capabilities. We’re planning to add more tasks over time. If you have ideas for tasks that would make your life easier, please let us know at #189. Enhanced Model Browser The model browser has received significant improvements: Resizable tree navigation for a more flexible layout Forward and backward history navigation to move between resources quickly Search functionality for addresses, resource types, and names Direct resource navigation via resource address input Breadcrumb navigation reflecting the current address Clipboard copy to copy the current resource address and paste it into the CLI Capability reference following to jump between related resources On-the-fly dependent resource creation to create dependent resources without losing context Improved Attribute and Operation Management Working with attributes and operations is now more powerful: Filtering by name, status (defined/undefined, required/not required, deprecated/not deprecated), and mode (configuration/runtime, read-write/read-only/metric) Attribute descriptions available as popovers Capability links for referenced capabilities Nested attribute support for both simple and complex types Allowed values information and expression syntax highlighting Operation filtering by name, signature, and deprecation status Toggleable global operations display For a full overview of all new features — including screencasts of the statistics task and on-the-fly dependent resource creation — check out the What’s New page. What’s Already Available halOP is already usable today! Here’s what’s ready: The dashboard as the new starting page The model browser with all the enhancements described above Theme support (light and dark) with contrast settings Stability level indicators across the UI The new Tasks category with the statistics task How to Try It Out There are several ways to get started with halOP — pick whichever works best for you. Bundled with WildFly halOP can be added to WildFly using the Galleon feature-pack org.jboss.hal:hal-op-feature-pack, which is available on Maven Central. To provision a WildFly server with halOP, use the Galleon CLI: galleon.sh provision provision.xml \ --dir=wildfly \ --stability-level=experimental Then create a management user and start the server: cd wildfly bin/add-user.sh -u admin -p admin --silent bin/standalone.sh --stability=experimental Once the server is running, halOP is available at http://localhost:9990/halop. See the HAL Foundation README for the full provisioning details including the provision.xml configuration. Standalone Mode You can also run halOP as a standalone single-page application that connects to any running WildFly instance. There are multiple options: JBang (Quickest Way) jbang hal-op@hal That’s it — no installation required! The console will be available at http://localhost:9090. Container podman run -p 9090:9090 quay.io/halconsole/hal-op JVM Download the pre-built Uber-Jar from Maven Central and run it: java -jar hal-op-<version>-runner.jar Native Binary Native binaries are available for Linux, macOS, and Windows — offering the fastest startup times. You can download them from the GitHub releases page, where they are attached to each release. Get Involved WildFly and the management console are open-source projects, and we’d love your help! Whether you want to report a bug, request a feature, or contribute code — every bit of help is welcome. Browse and file issues on GitHub Issues Check out the contribution guidelines to get started with development Watch the HAL Foundation repository to stay up to date We’re building this console for the WildFly community, and your input shapes what it becomes. We look forward to hearing from you! References HAL Foundation — the foundation for the next-gen management console What’s New — full overview of new features with screenshots and screencasts GitHub Issues — report bugs, request features, or browse open issues Contributing — guidelines for contributing to the project WildFly Community Call (December 2025) — live introduction and demo of the next-gen management console: recording | slides ### [New WildFly 40 Beta release](/news/2026/05/01/New-WildFly-40-Beta-release/) I am excited to announce the release of WildFly 40 Beta 1, this release has taken is a little longer than expected, but we hope you appreciate the changes it brings. In our previous releases we have been adding our EE 11 implementations to the WildFly Preview distribution, we have now brought our EE 11 integration into the default WildFly Distribution. This means that you can now use the latest EE 11 features in your applications without needing to switch to a separate distribution. At the same time, we understand many of you are invested in your EE10 installations, so we have you covered with a new WildFly EE10 Distribution available from the downloads page. On the security front many users have been asking for an integration with Hashicorp Vault, and we are pleased to announce that this is also available for WildFly 40 in the form of a feature-pack. Please visit the blog post for more details on how to get started with this integration. These are just a couple of the highlights with many more changes made to WildFly. Preparing the release notes GitHub tells me over 30 people contributed to this release and that does not include all of the people working on the components that make WildFly possible so we thank everyone for your contributions. We encourage you to explore the full list of changes in the official release notes. How to Get Involved This is a beta release, so we don’t recommend it for production environments. Your feedback is crucial to help us identify and fix issues before the final release. Download WildFly 40 Beta 1 from https://wildfly.org/downloads or provision a WildFly 40 Beta 1 server using a tool like the wildfly-maven-plugin Report a bug or enhancement request on our issue tracker Ask a question Google Group or reach us on Zulip. We look forward to hearing your feedback and working together to make WildFly 40 the best release yet! ### [The HashiCorp Vault integration is available for provisioning with WildFly 40 Beta](/news/2026/05/01/The-HashiCorp-Vault-integration-is-available-for-provisioning-with-WildFly-40-Beta/) ### [Upcoming HashiCorp Vault feature-pack updates](/news/2026/02/13/Upcoming-HashiCorp-Vault-feature-pack-updates/) ### [WildFly 39.0.1 is released!](/news/2026/02/12/WildFly-39-0-1-is-released/) I am very happy to announce that WildFly 39.0.1.Final is now released and available for download (or to be provisioned by Galleon, fetched as Container images on Quay, or obtained by whichever distribution mechanism you prefer). The complete WildFly 39.0.1.Final release notes are available on GitHub. I want to highlight great work of our community users during this maintenance release. Rhuan H. found a memory leak issue and did absolutely amazing work analyzing, debugging and verifying the fix. Cody L. found and promptly reported an issue where max-post-size in Undertow was not being properly applied, capping uploads at 2 MB. Give it a try, upgrade and give us your feedback, in the WildFly google group, Zulip or Jira. Best regards, Rado ### [A2A Java SDK for Jakarta 1.0.0.Alpha1 is released!](/news/2026/01/20/A2A-Java-SDK-for-Jakarta-1-0-0-Alpha1-is-released/) I am pleased to announce the 1.0.0.Alpha1 release of the A2A Java SDK for Jakarta. It supports version 1.0 of the A2A Protocol Specification. Note that version 1.0 of the A2A Protocol is not totally finalized yet, so there will likely be some more Alphas and Betas until we have a final release. The release builds on the 1.0.0.Alpha1 release of the a2a-java SDK. This introduces some improvements, and some breaking changes, which you can read about here. There are some changes to the dependencies in a2a-java, so take a look at how the example is packaged, and also see how the deployments are packaged with Shrinkwrap in the tests. Future Plans Note that while we pass all the tests 'inherited' from the a2a-java SDK, we don’t currently pass the TCK. The TCK is undergoing big changes too, in order to support the 1.0 specification. So the next step will be to get the TCK passing. Get involved If you have any issues with the SDK, please open an issue. Also, pull requests are welcome! ### [WildFly 39 is released!](/news/2026/01/16/WildFly-39-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 39.0.0.Final releases are available for download at https://wildfly.org/downloads, The Galleon feature-packs for WildFly 39 are available in Maven Central. New and Notable Here’s what’s new: Clustering: We’ve added a couple new things in the clustering/high-availability area: WildFly now supports TLS configuration for TCP-based transport protocols. This can be used to effectively replace ASYM_ENCRYPT with AUTH protocols in the existing JGroups stack. WildFly now supports idle time-based eviction for distributable HttpSessions. This provides administrators with more flexible resource management options, which is particularly useful when distributed state objects have highly variable sizes. The new configuration allows eviction based on how long a state object has been idle, complementing the existing count-based eviction mechanism. Jakarta RESTful Web Services: A new attribute, resteasy-original-webapplicationexception-behavior has been added to the jaxrs subsystem. It was previously only available by configuring the equivalent context parameter at a deployment level. Configuring this at the subsystem level will apply it to all deployments, unless the deployment itself explicitly sets the parameter. Java EE 11 Integration: In WildFly Preview, we’ve updated our implementations of Jakarta Authentication, Jakarta Concurrency, Jakarta Security, Jakarta Servlet, and Jakarta Websockets. Galleon provisioning: Our Galleon tooling has added preview capabilities that will make it possible for users who want to use a feature-pack to choose which of a compatible set of dependency feature-packs to use. There’s no practical end-user benefit to this yet, but it will be helpful in the future as the feature-packs we produce make use of this capability. A typical example will be letting users of something like the AI feature-pack choose which "base" feature-pack that provides EE to use — wildfly-ee, wildlfy-preview or a planned wildfly-ee-10. Note: If you plan to develop a feature-pack that depends on WildFly 39, be sure to use WildFly Galleon Plugins 8.1.0 or later. We always recommend you use the same Galleon plugin version that WildFly used to build its own feature-packs. Component Upgrades: We’ve updated a wide range of dependencies to their latest versions, improving performance, stability, and security. Notable upgrades include: Jackson 2.20 Infinispan 16.0 JGroups 5.5 Apache Artemis 2.44 Narayana 7.3 WildFly Core 31 WildFly Clustering 9.0 lz4-java 1.10.1, addressing CVE-2025-12183 and CVE-2025-66566. Undertow 2.3.22, addressing CVE-2024-3884, CVE-2024-4027 and CVE-2025-12543. Supported Specifications Jakarta Standard WildFly 39 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly is EE 10 Platform, Web Profile and Core Profile compatible when running on Java SE 17 and Java SE 21. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence EE 10 Full Platform SE 17 SE 21 EE 10 Web Profile SE 17 SE 21 EE 10 Core Profile SE 17 SE 21 MicroProfile Standard WildFly 39 supports MicroProfile Platform 7.1, along with several other MicroProfile specifications that are not part of MicroProfile Platform. The full listing is available in the Getting Started Guide. Compatibility evidence for the specifications that are part of MicroProfile 7.1 can be found in the WildFly Certifications repository on GitHub. WildFly Preview and EE 11 Since the WildFly 32 release, we have been using WildFly Preview to provide a look at what we’re doing for EE 11 support. We continued to make progress on this during the WildFly 39 cycle, with new integrations of implementations of Jakarta Authentication, Jakarta Concurrency, Jakarta Security, Jakarta Servlet and Jakarta Websocket. For Jakarta Pages we are still offering the EE 10 implementation. Our goal is shift to the EE 11 implementation in WildFly Preview 40. The EE 11 Platform and Web Profile went GA last summer. We are working on completing our implementation of these in WildFly Preview, for eventual incorporation in standard WildFly. Full details on the EE specification versions provided by WildFly Preview can be found in the WildFly 39 documentation. Java SE Support Our recommendation is that you run WildFly 39 on Java SE 21, as that is the latest LTS JDK release where we have completed the full set of testing we like to do before recommending a particular SE version. WildFly 39 also is heavily tested and runs well on Java 17. Our recommendation of SE 21 over SE 17 is solely because as a general principle we recommend being on later LTS releases, not because of any problems with WildFly on SE 17. While we recommend using SE 21 or SE 17, we believe WildFly runs well on SE 25, which is the most recent LTS release, released last September. By runs well, I mean the main WildFly nightly testsuite jobs produce results equivalent to what we see with SE 17 and SE 21. We want developers who are trying to evaluate what SE 25 means for their applications to be able to look to WildFly as a useful development platform. Since SE 25 is an LTS release, we aim in a future WildFly version to include it in the list of recommended SE releases. To do this there is further qualifying work to be done, beyond the good WildFly testsuite results we are seeing today. We’re working to validate the SE 25 compatibility of key components we include in WildFly, and we’re using the EE 11 TCK as a further set of tests of how well we run on SE 25. (The EE 11 TCK was not written for SE 25, so there may be some tests that won’t work on it. However, using the EE 10 TCK to help qualify SE 21 worked well.) In both of these areas we made good progress during the WildFly 39 development period. Please note that WildFly runs in classpath mode. Incompatible Changes There are a couple of incompatible changes in WildFly 39 that may affect some users: The require-host-http11 attribute on undertow subsystem listener resources no longer has any effect. The server behavior is now always as if this were set to true, i.e. we now require that HTTP 1.1 or later requests include a Host header, as is mandated by the HTTP standards. Previously this was configurable and had a default value of false, meaning we did not require such a header. It was reported to us that not requiring this was a security flaw, so we changed this behavior. Previously, when using HTTP to upload a deployment to our management interface, we imposed no limit on the size of the deployment. Now we impose a limit of 1GB. If you have deployments larger than that, you can use the org.wildfly.management.upload.limit system property to configure a different limit, with a value set to the number of bytes. Maven Publication Changes The main WildFly project has begun deploying its release content directly to Maven Central. This is a change from the project’s decades-old practice of deploying to JBoss Nexus, from which our content later would be synced to Maven Central. JBoss Nexus serves as a proxy for Maven Central, so this content will still be available via JBoss Nexus. Our expectation is this change will be transparent to our users. If you encounter problems, please let us know! New and Noteworthy Contributors WildFly gets great contributions from so many people. Let’s thank a few of them. Jian-Fong Yu, Christian Voss and Ilias Bourdakos made their first contributions to the main WildFly repository, while Rafael Rosa made his first contribution to WildFly Core. Thank you, Jian-Fong, Christian, Ilias and Rafael! Paul Ferraro and Rado Husar did excellent work on our clustering capabilities. Rado was also on fire in general, doing all sorts of the kinds of unsung work that helps keep an OSS project moving. Thank you, Paul and Rado! Flavia Rainone and Bartosz Baranowski worked very hard to deliver a number of security and other improvements in our web tier for WildFly 39. Thank you, Flavia and Bartosz! Release Notes The full WildFly 39 release notes are available in GitHub. Issues fixed in the underlying WildFly Core 30.0.0 and 30.0.1 releases are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. Best regards, Brian ### [New WildFly 39 Beta release](/news/2025/12/19/New-WildFly-39-Beta-release/) We’re pleased to announce the release of WildFly 39 Beta 1. This version contains updates, new features, and bug fixes, paving the way for the planned January final release. This beta version is a crucial step in our development cycle, allowing the community to test and provide feedback on the latest changes. What’s New and Noteworthy? Here’s a quick rundown of the highlights: Clustering: We’ve added a couple new things in the clustering/high-availability area: WildFly now supports TLS configuration for TCP-based transport protocols. This can be used to effectively replace ASYM_ENCRYPT with AUTH protocols in the existing JGroups stack. WildFly now supports idle time-based eviction for distributable HttpSessions, Stateful EJBs, and EJB Timers. This provides administrators with more flexible resource management options, which is particularly useful when distributed state objects have highly variable sizes. The new configuration allows eviction based on how long a state object has been idle, complementing the existing count-based eviction mechanism. Jakarta RESTful Web Services: A new attribute, resteasy-original-webapplicationexception-behavior has been added to the jaxrs subsystem`. It was previously only available by configuring the equivalent context parameter at a deployment level. Configuring this at the subsystem level will apply it to all deployments, unless the deployment itself explicitly sets the parameter. Java EE 11 Integration: In WildFly Preview, we’ve updated our implementations of Jakarta Authentication, Jakarta Concurrency, Jakarta Security, Jakarta Servlet, and Jakarta Websockets. Galleon provisioning: Our Galleon tooling has added preview capabilities that will make it possible for users who want to use a feature-pack to choose which of a compatible set of dependency feature-packs to use. There’s no practical end-user benefit to this yet, but it will be helpful in the future as the feature-packs we produce make use of this capability. A typical example will be letting users of something like the AI feature-pack choose which "base" feature-pack that provides EE to use — wildfly-ee, wildlfy-preview or a planned wildfly-ee-10. Note: If you plan to develop a feature-pack that depends on WildFly 39 Beta, be sure to use WildFly Galleon Plugins 8.1.0.Beta4 or later. We always recommend you use the same Galleon plugin version that WildFly used to build its own feature-packs. Component Upgrades: We’ve updated a wide range of dependencies to their latest versions, improving performance, stability, and security. Notable upgrades include: Jackson 2.20 Infinispan 16.0 JGroups 5.5 Apache Artemis 2.44 Narayana 7.3 WildFly Core 31.0.0.Beta3 WildFly Clustering 9.0.0.CR3 lz4-java 1.10.1, addressing CVE-2025-12183 and CVE-2025-66566. Important Bug Fixes We’ve tackled several bugs to ensure a more stable experience. Significant ones include: Resolved a problem with not-recovered transactions after a crash of a server that deployed MDBs. Resolved a memory leak issue with Jakarta Web Services client proxies. Resolved a problem where requesting a session that was invalidated by a concurrent request can cause a memory leak. We encourage you to explore the full list of changes in the official release notes. Maven Publication Changes The main WildFly project has begun deploying its release content directly to Maven Central. This is a change from the project’s decades-old practice of deploying to JBoss Nexus, from which our content later would be synced to Maven Central. JBoss Nexus serves as a proxy for Maven Central, so this content will still be available via JBoss Nexus. Our expectation is this change will be transparent to our users. If you encounter problems, please let us know! How to Get Involved This is a beta release, so we don’t recommend it for production environments. Your feedback is crucial to help us identify and fix issues before the final release. Download WildFly 39 Beta 1 from https://wildfly.org/downloads or provision a WildFly 39 Beta 1 server using a tool like the wildfly-maven-plugin Report a bug or enhancement request on our issue tracker Ask a question in the Google Group or reach us on Zulip. We look forward to hearing your feedback! ### [WildFly 38.0.1 is released!](/news/2025/11/17/WildFly-38-0-1-is-released/) WildFly 38.0.1.Final is now available for download. The full WildFly 38.0.1.Final release notes are available in GitHub. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. Enjoy! ### [A2A Java SDK for Jakarta 0.3.0.Final is released!](/news/2025/11/06/A2A-Java-SDK-for-Jakarta-0-3-0-Final-is-released/) I am pleased to announce the 0.3.0.Final release of the A2A Java SDK for Jakarta. You can find the release here, and it supports version 0.3.0 of the A2A Protocol Specification. Since the 0.3.0.Beta1 release, there haven’t been big changes on our side, but we are now aligned with version 0.3.2.Final of the A2A Java SDK. A lot of work has taken place there since the previous version of the A2A Java SDK we aligned with which was 0.3.0.Beta1. You can find the changes between versions 0.3.0.Beta2 and 0.3.2.Final of the A2A Java SDK here. Please see the A2A Java SDK for Jakarta 0.3.0.Beta1 release announcement for how to get started with the SDK. Future Plans We will continue to align with the A2A SDK for Java, which is currently working towards supporting 0.4.0 of the A2A Protocol Specification. Note that the work on version 0.4.0 of the specification is still in progress. Also, it is worth pointing out that for WildFly users, the A2A Java SDK for Jakarta currently relies on bundling the jars from the two SDKs, as well as their dependencies, into your application deployment archive. We would like to create a WildFly feature-pack for this, which would follow the normal WildFly pattern of enabling a subsystem which would make all the A2A libraries available automatically to deployments, thus removing the need to bundle them in your application. However, we have decided that the wildfly-extras/a2a-java-sdk-server-jakarta repository is not the correct place for such a feature-pack, since it is meant to be used by people wanting to integrate in other Jakarta runtimes. Instead, we are considering adding it to the WildFly AI Feature-Pack. This will be announced separately when it happens. Get involved If you have any issues with the SDK, please open an issue. Also, pull requests are welcome! ### [WildFly 38 is released!](/news/2025/10/16/WildFly-38-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 38.0.0.Final releases are available for download at https://wildfly.org/downloads, The Galleon feature-packs for WildFly 38 are available in the JBoss Maven repository. Note We’ve encountered problems syncing the WildFly 38 artifacts and other Maven content from the JBoss Maven repository to Maven Central. This problem is currently under investigation. We recommend Maven users include https://repository.jboss.org/nexus/content/groups/public-jboss/ in their Maven repositories configuration. This is a general best practice when provisioning a WildFly server, as some WildFly components may not be available in Maven Central. New and Notable MicroProfile 7.1 In the main server, the biggest new thing in WildFly 38 is support for the MicroProfile Platform 7.1 specifications, updating from the MicroProfile 7.0 specs supported in WildFly 37. This included updates to two specs: MicroProfile OpenAPI 4.1 MicroProfile Telemetry 2.1 WildFly Preview In WildFly Preview, something I encourage users to try out is the implementation of EE 11 JPA and CDI integration. EE 11 includes requirements that implementations expose as CDI beans instances of a number of Jakarta Persistence types, including EntityManager and EntityManagerFactory. This makes possible injection of those types into other beans using @Inject. Jakarta is aiming to make the EE platform more CDI-centric; this is a step in that direction. Provisioning and documentation Feature-packs that are used to provision WildFly now provide generated documentation that describes the feature-pack and its layers, along with the management API reference for the management resources provided by the feature-pack. We’re making use of this new capability in a couple of ways: The WildFly catalog of feature-packs and layers is online. It allows you to browse the Management API Reference (and associated Galleon features) of each feature-pack as well as the layers they contain (with their management model). The catalog currently contains an initial set of feature-packs that is going to evolve. The catalog content and features will be covered in detail in a future blog entry. We’ve also revamped a section of our documentation that provides the automatically generated detailed documentation of WildFly’s administrative API. We’ve replaced the longstanding "wildscribe" documentation that only covered our management API (i.e. what you’d work with when using jboss-cli) with much richer documentation describing what our main wildfly feature-pack provides. If you’re looking for the management API-focused documentation previously found at places like https://docs.wildfly.org/37/wildscribe/ (for WildFly 37), you can find equivalent (but better!) content at https://docs.wildfly.org/38/feature-pack/doc/reference/index.html. Supported Specifications Jakarta Standard WildFly 38 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly is EE 10 Platform, Web Profile and Core Profile compatible when running on Java SE 17 and Java SE 21. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence EE 10 Full Platform SE 17 SE 21 EE 10 Web Profile SE 17 SE 21 EE 10 Core Profile SE 17 SE 21 MicroProfile As noted above, standard WildFly 38 supports MicroProfile Platform 7.1, along with several other MicroProfile specifications that are not part of MicroProfile Platform. The full listing is available in the Getting Started Guide. Compatibility evidence for the specifications that are part of MicroProfile 7.1 can be found in the WildFly Certifications repository on GitHub. WildFly Preview and EE 11 Since the WildFly 32 release, we have been using WildFly Preview to provide a look at what we’re doing for EE 11 support. We continued to make progress on this during the WildFly 38 cycle, particularly in the aforementioned Jakarta Persistence + CDI integration and in updates to our Jakarta Authorization implementation. However, for a number of specifications that made changes for EE 11 we are still offering the EE 10 implementation. Our goal is shift those to the EE 11 implementation in WildFly Preview 39. The EE 11 Core Profile specification went GA last November and WildFly Preview 38 supports that profile. The EE 11 Platform and Web Profile went GA earlier this summer. We are working on completing our implementation of these in WildFly Preview, for eventual incorporation in standard WildFly. Full details on the EE specification versions provided by WildFly Preview can be found in the WildFly 38 documentation. Java SE Support Our recommendation is that you run WildFly 38 on Java SE 21, as that is the latest LTS JDK release where we have completed the full set of testing we like to do before recommending a particular SE version. WildFly 38 also is heavily tested and runs well on Java 17. Our recommendation of SE 21 over SE 17 is solely because as a general principle we recommend being on later LTS releases, not because of any problems with WildFly on SE 17. While we recommend using SE 21 or SE 17, I do believe WildFly runs well on SE 25, which is the most recent LTS release, released last month. By runs well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. As of the date of this release announcement there were no such issues. We want developers who are trying to evaluate what SE 25 means for their applications to be able to look to WildFly as a useful development platform. Since SE 25 is an LTS release, we aim in a future WildFly version to include it in the list of recommended SE releases. To do this there is further qualifying to be done, beyond the good WildFly testsuite results we are seeing today. We’re working to validate the SE 25 compatibility of key components we include in WildFly, and we’ll try and use the EE 11 TCK as a further set tests of how well we run on SE 25. (The EE 11 TCK was not written for SE 25, so we’ll see how feasible this is. Using the EE 10 TCK to help qualify SE 21 worked well.) Please note that WildFly runs in classpath mode. New and Noteworthy Contributors WildFly gets great contributions from so many people. Let’s thank a few of them. Javier de Ros Villar, Akil Krishna and Sebastien Dionne made their first contributions to the main WildFly repository, while Marek Skácelík made his first contribution to WildFly Core. Thank you, Javier, Akil, Sebastien and Marek! Jeff Mesnil and Jean-François Denise did great work on the new feature-pack documentation capabilities and on the WildFly catalog. I’m excited to see where this goes in the future. Scott Marlow showed great perseverance in working through the many tricky cases involved with the Jakarta Persistence + CDI integration in WildFly Preview. Thank you, Scott! Release Notes The full WildFly 38 release notes are available in GitHub. Issues fixed in the underlying WildFly Core 30.0.0 release are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. Best regards, Brian ### [resteasy-grpc 1.0.0.Beta1 is available](/news/2025/10/13/resteasy-grpc-1-0-0-Beta1-is-available/) ### [New WildFly 38 Beta release](/news/2025/10/02/New-WildFly-38-Beta-release/) We’re excited to announce the release of WildFly 38 Beta 1! This version contains updates, new features, and bug fixes, paving the way for the upcoming final release. This beta version is a crucial step in our development cycle, allowing the community to test and provide feedback on the latest changes. What’s New and Noteworthy? This release focuses heavily on component upgrades, MicroProfile 7.1 support, and enhancements to the WildFly Preview distribution. Here’s a quick rundown of the highlights: Java EE 11 Integration: A key new feature is the implementation of EE 11 JPA and CDI integration in WildFly Preview, bringing us closer to full support for the latest Jakarta specifications. MicroProfile 7.1: WildFly 38 Beta 1 supports the MicroProfile 7.1 specifications, including an update to the latest versions of MicroProfile OpenAPI and MicroProfile Telemetry. This upgrade ensures that developers can leverage the newest features and improvements in the MicroProfile ecosystem. Component Upgrades: We’ve updated a wide range of dependencies to their latest versions, improving performance, stability, and security. Notable upgrades include: Hibernate ORM 6.6.29.Final (and 7.1.1.Final in WildFly Preview) Infinispan 15.2.6.Final Apache Artemis 2.42.0 Netty 4.1.127.Final, addressing several security vulnerabilities. WildFly Core 30.0.0.Beta3 JGit 7.3.0.202506031305-r. addressing CVE-2025-4949. SmallRye Jandex 3.5.0 angus-mail 2.0.4, addressing CVE-2025-7962. Important Bug Fixes We’ve tackled several bugs to ensure a more stable experience: Resolved a memory leak issue with distributed cache listeners on suspend/resume. Corrected a bug where the TransactionUtil.isInTx method returned an incorrect state. Addressed multiple intermittent test failures related to OpenTelemetry and Fault Tolerance. Fixed an issue where the integration test in the OpenAPI quickstart was ineffective. We encourage you to explore the full list of changes in the official release notes. How to Get Involved This is a beta release, so we don’t recommend it for production environments. Your feedback is crucial to help us identify and fix issues before the final release. Download WildFly 38 Beta 1 from https://wildfly.org/downloads or provision a WildFly 38 Beta 1 server using a tool like the wildfly-maven-plugin Report a bug or enhancement request on our issue tracker Ask a question Google Group or reach us on Zulip. We look forward to hearing your feedback and working together to make WildFly 38 the best release yet! ### [Hacktoberfest 2025 is here!](/news/2025/09/26/Hacktoberfest-2025-is-here/) It’s that time of year again! Hacktoberfest is back, calling on developers, contributors, and open-source enthusiasts from around the globe to come together for a month-long celebration of collaboration. Whether you’re a seasoned coder or just starting your journey, Hacktoberfest is the perfect opportunity to give back to the community, learn new skills, and make a real impact, one pull request at a time. What is Hacktoberfest? Hacktoberfest is a month-long event in October that encourages Open Source contributors and developers worldwide to give back to the global tech community. It’s a fantastic opportunity for the contributors to showcase their skills and get to know about other Open Source communities. To participate you simply need to: Register: The first step is to sign up on the official Hacktoberfest website. Registration is open from September 15 to October 31. Once you register, you’ll unlock your digital badge! Find Projects: You can contribute to any public project hosted on GitHub or GitLab that has the hacktoberfest topic. This makes it easy to find repositories that are actively looking for contributors. You can also check out the below WildFly-related projects which are already picked and ready for you. Contribute: Between October 1 and October 31, submit at least 6 high-quality pull or merge requests. Remember, for your contributions to count, they must be accepted by the project maintainers. Always read the project’s CONTRIBUTING.md file for guidelines before you start. Quality over quantity is key! Rewards for 2025 This year’s rewards are designed to celebrate your commitment to open source. Holopin Digital Badge: As soon as you register, you’ll receive a unique digital badge from Holopin. With each accepted PR/MR, your badge will level up, showcasing your progress throughout the month. Exclusive T-Shirt: Become a 'Super Contributor' by getting 6 accepted PRs/MRs. The first 10,000 participants to achieve this will receive an exclusive Hacktoberfest 2025 t-shirt! (Terms and Conditions apply). Make the World Greener: For every contributor who earns the t-shirt reward, Hacktoberfest will make a contribution to Treenation to plant a tree. Your code can help the planet! Get started with our projects This list features an exciting variety of projects under the WildFly umbrella, just waiting for your contributions. Whether your expertise lies in Java, TypeScript, Containers or Ansible, there’s a project here for everyone to dive into and make an impact. WildFly: WildFly is a powerful, modular, and lightweight application server that empowers you to build amazing applications. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. WildFly Core: WildFly Core provides the core runtime that is used by the WildFly application server. This includes modular class loading, unified management including domain mode, basic deployment architecture, and a CLI for management. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. Ansible Middleware: Ansible Middleware is a suite of supported content that combines the power of Ansible automation with Red Hat’s Middleware portfolio. It allows organizations to meet their business demands and automate the installation, configuration, and management of Enterprise Middleware. Here are the GitHub repositories, Contributing Guide, and Hacktoberfest Issues link. A2A Java: The A2A Java project provides a Java SDK for the Agent2Agent (A2A) protocol. The A2A protocol is an open standard initially developed by Google and is now part of the Linux Foundation. It enables AI agents to communicate and collaborate with one another, regardless of each agent’s underlying framework, language, or vendor. This is very important, as it’s paving the way for polyglot multi-agent systems. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. WildFly Elytron: WildFly Elytron is a set of APIs and SPIs for application server security and client side security. Within the WildFly server, WildFly Elytron is used to secure applications deployed to the server as well as management access to the server. It is a standalone library that can also be used in other Java server environments. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. Berg Hal console TS: The Berg is TS for the HAL project. It is based on the Cypess test framework. Create tests, debug them visually, and automatically run them in your continuous integration builds. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. Undertow: Undertow is a versatile and high-performance web server that provides both blocking and non-blocking APIs based on NIO. Its modular architecture allows you to build a web server tailored to your needs, from a full Java EE servlet container to a low-level non-blocking handler. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. PatternFly Java: PatternFly Java is a 💯 Java implementation of PatternFly without any JavaScript dependencies. Its goal is to provide an easy-to-use, elegant, and efficient API to build complex web applications with PatternFly in Java. PatternFly Java works with both GWT and J2CL. PatternFly Java is used for the next-gen WildFly management console. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. Narayana LRA: Long Running Actions (abbreviated as LRA ) is a MicroProfile specification that introduces APIs for services to coordinate activities. Narayana LRA is an implementation of the specification and is included in both Quarkus and WildFly. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. Intersmash: Intersmash is a Java library that makes it easy to automate the provisioning and execution of tests in cloud-native environments. It helps the user prototype and test complex interoperability scenarios on kubernetes compliant cloud-native environments and platforms, most notably OpenShift. (Other Kubernetes implementations will be supported in the future.) Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. Arquillian Cube: Arquillian Cube is an Arquillian extension that can be used to run tests on Docker containers, on Kubernetes and on OpenShift…​ the Arquillian way! You can start an application server Docker container, and deploy a given application within it and execute Arquillian tests. Or you can easily build your application image, run it on Kubernetes or OpenShift and execute tests against it. And that’s not just about applications. Arquillian Cube can deploy any required services, like databases, mail servers, etc. replacing the need for mocking fake objects. Annotations are available to inject relevant resources directly into your test classes, and you can use Arquillian Cube APIs to orchestrate your tested services lifecycle. Whatever the platform that you use in production, your tests will be executed against it, making them even more real, effective and meaningful than before. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. Questions or Need Help? Got a question or need some help getting started with a contribution? We’re here for you! Please join our Hacktoberfest Zulip chatroom to connect directly with our mentors and fellow contributors. It’s the best place to get assistance and ensure your Hacktoberfest journey is a smooth one. Every contribution, big or small, makes a difference. Let’s work together to make Hacktoberfest 2025 a huge success! ### [A2A Java SDK for Jakarta 0.3.0.Beta1 is released!](/news/2025/09/19/A2A-Java-SDK-for-Jakarta-0-3-0-Beta1-is-released/) Following the release of version 0.3.0.Beta1 of the A2A Java SDK, I am excited to announce the release of the corresponding 0.3.0.Beta1 release of the A2A Java SDK for Jakarta. A2A stands for Agent2Agent Protocol, which is a protocol hosted under the Linux Foundation to enable seamless communication and collaboration between AI Agents implemented using any language/technology stack. The A2A Java SDK for Jakarta consumes the A2A Java SDK. The reason for the split is that the A2A Java SDK is meant to be server agnostic. While it provides an implementation for Quarkus as its reference implementation, so that it has something to run tests and the A2A Protocol TCK against, it was decided that integrations with other runtimes should be developed externally. These are listed in the 'Server integrations' section of the A2A Java SDK README. What is new The change list can be found here. We have done a lot of reorganisation of both projects so they are more modular. Also, following some upgrades to our internal infrastructure, we are now able to deploy the artifacts to Maven Central under the org.wildfly.a2a groupId. Aside from that the major new features are the inclusion of the transports introduced in version 0.3.0 of the A2A Protocol specification: * [gRPC] - This relies on the WildFly gRPC Feature-Pack. * [HTTP+JSON] - Also referred to as REST. We pass the TCK for both these new transports, as well as the original JSON-RPC transport. A simple example showing how to package an agent for use with both transports can be found here. How to use Rather than going into a full example here, the starting point is to include one or both of the following dependencies in your application: * org.wildfly.a2a:a2a-java-sdk-jakarta-jsonrpc:0.3.0.Beta1 - to enable the JSON-RPC protocol * org.wildfly.a2a:a2a-java-sdk-jakarta-grpc:0.3.0.Beta1 - to enable the gRPC protocol. * org.wildfly.a2a:a2a-java-sdk-jakarta-rest:0.3.0.Beta1 - to enable the HTTP+JSON protocol. The simple example provides more guidance for how to manage the dependencies. Additionally, you need to provide CDI beans which provide the AgentCard and AgentExecutor implementations for your Agent as per the A2A specification. Note that the simple example is more of a "Hello world" type application focused on how to package your application for use with the A2A Java SDK for Jakarta. Once you have packaged your application, see the examples in the A2A Java SDK repository, and the Java samples in the a2a-samples repository for how to actually implement agents that communicate with each other. You can then, for example, try to replace one of those agents with one running on WildFly. To help with integrating LLMs in WildFly applications, we have the WildFly AI Feature-Pack which leverages Langchain4j to interact with the LLM. For more background information about the A2A Java SDK, and the A2A Java SDK for Jakarta, see our previous blog posts. Note that the blog posts are written using various versions of the SDK, so you will likely need to make some adjustments. Building your First A2A Agent Getting Started with Quarkus and A2A Java SDK 0.3.0 Getting Started with Quarkus and the A2A Java SDK A2A Java SDK: Support for the REST Transport is Now Here (announcement of the 0.3.0.Beta1 release of the A2A Java SDK) What is coming next? We would like to investigate if we can provide the dependencies in a nicer way so all the exclusions seen in the current version of the sample are no longer required. Additionally, we will continue improving the implementations in both repositories, and of course keep up as the A2A Protocol specification evolves. ### [WildFly Community Calls, starting on Thursday Sept. 18th](/news/2025/09/11/WildFly-Community-Calls-starting-on-Thursday-Sept-18th/) Starting next Thursday , Sept 18th, WildFly will hold Community calls open to any community members — users and developers alike. These biweekly calls are an opportunity to meet and discuss about WildFly, its community, and its development. All information to join the call is published in the WildFly Calendar. We prepared the agenda in advance. There is also a tab to suggest topics for future meetings. For anyone that can not attend the call, we will upload their recordings on our YouTube channel so that you can watch them at your own leisure. See you on Thursday! ### [WildFly 37.0.1 is released!](/news/2025/09/04/WildFly-37-0-1-is-released/) WildFly 37.0.1.Final is now available for download. I am pleased to announce that the WildFly 37.0.1.Final release is now available for download. The following issues were resolved in 37.0.1: Bugs [WFLY-20787] - java:comp/UserTransaction resource not found during CDI Startup event Component Upgrades [WFLY-20808] - Upgrade wildfly-clustering to 7.0.12.Final [WFLY-20832] - [CVE-2025-7962] org.eclipse.angus:angus-mail from 2.0.3 to 2.0.4 [WFLY-20841] - Upgrade to jboss-parent 50; drop pom settings now provided by JBoss Parent [WFLY-20846] - [CVE-2025-55163] Upgrade Netty to 4.1.124.Final [WFLY-20848] - Upgrade wildfly-bom-builder-plugin to 2.0.9 [WFLY-20856] - Upgrade Apache CXF to 4.0.9 [WFLY-20859] - Upgrade Hibernate ORM to 6.6.26 [WFLY-20877] - Upgrade Infinispan to 15.2.5.Final [WFLY-20878] - Upgrade JGroups to 5.4.9.Final [WFLY-20880] - Upgrade wildfly-core to 29.0.1.Final The following issues were also resolved in the version of WildFly Core contained within this release: Bugs [WFCORE-7319] - Maven warning: found duplicate declaration of plugin org.apache.maven.plugins:maven-gpg-plugin Tasks [WFCORE-7321] - Replace wildfly-component-matrix-plugin with wildfly-bom-builder-plugin Component Upgrades [WFCORE-7306] - Upgrade commons-lang3 to 3.18 (relates to CVE-2025-48924) [WFCORE-7330] - Upgrade wildfly-bom-builder-plugin to 2.0.9 [WFCORE-7342] - Upgrade wildfly-bom-builder-plugin to 2.0.10 Enjoy! ### [Vlog: Getting started with WildFly using Gemini CLI](/news/2025/08/08/Vlog-Getting-started-with-WildFly-using-Gemini-CLI/) In this demonstration, we are using the Gemini CLI to get started with WildFly using its MCP server. By pointing the Gemini CLI to a war file and asking high-level questions, we can provision a server, deploy the application, run the server, and access the WildFly web console. ### [Building your First A2A Agent](/news/2025/08/07/Building-your-First-A2A-Agent/) The new Agent2Agent (A2A) Protocol establishes an open standard for universal interoperability, allowing AI agents built by different vendors or on separate frameworks to communicate and collaborate effectively. By providing a standardized method for exchanging information and coordinating actions, A2A empowers businesses to create a unified, multi-agent ecosystem that breaks down data silos and automates complex workflows across their entire enterprise.The specifications of this protocol are available online, and you can find SDKs for different languages and tools on the A2A Github Organization. You can watch this introduction to the Agent2Agent Protocol. This article guides you through building your first A2A-enabled agent in WildFly. We will leverage the A2A Java SDK for Jakarta Servers (providing EE integration for the A2A Java SDK) and the WildFly AI Feature-Pack to create a powerful, LLM-powered agent. This agent is compliant with version 0.2.5 of the A2A specifications and uses a simple Model Context Protocol tool written in Python. Prerequisites Before diving in, make sure you have: JDK 17+ Apache Maven 3.8+ A Java IDE (e.g., Apache NetBeans, IntelliJ, VS Code) A Google AI Studio API Key Python 3.10+ uv, which is required to execute our MCP Tool written in Python. Create the Weather Agent We will write an agent that provides forecasts and severe weather alerts based on a human language query. This agent will rely on a Python MCP tool that exposes two functions: get_alerts and get_forecast. Let’s create a simple LangChain4J service that uses a Python MCP tool: package org.wildfly.ai.a2a.weather; import dev.langchain4j.service.SystemMessage; import dev.langchain4j.service.UserMessage; import io.smallrye.llm.spi.RegisterAIService; import jakarta.enterprise.context.ApplicationScoped; @RegisterAIService(toolProviderName = "mcp-stdio", chatModelName = "gemini", scope = ApplicationScoped.class) public interface WeatherAgent { @SystemMessage(""" You are a specialized weather forecast assistant. Your primary function is to utilize the provided tools to retrieve and relay weather information in response to user queries. You must rely exclusively on these tools for data and refrain from inventing information. Ensure that all responses include the detailed output from the tools used and are formatted in Markdown. """ ) String chat(@UserMessage String question); } This interface defines a chat method. The @RegisterAIService annotation instructs WildFly to create a proxy for this service, enabling interaction with the configured LLM. The @SystemMessage and @UserMessage annotations provide instructions to the LLM. Define the Agent To expose your agent to the A2A Protocol, you need to define: An Agent Card: According to version 0.2.5 of the A2A specification, each A2A Server must have an agent card accessible at the /.well-known/agent.json resource. This card supports the discovery phase for A2A clients by providing complete information on how to access the agent and its capabilities. An Agent Executor: This is the code that handles A2A requests and calls the agent’s code. To convert our AI application into an A2A agent, we are using the A2A Java SDK for Jakarta Servers, which expects an instance of io.a2a.server.agentexecution.AgentExecutor and io.a2a.spec.AgentCard to be available via CDI. Note We need to define this dependency in our pom.xml as follows: <dependency> <groupId>org.wildfly.a2a</groupId> <artifactId>a2a-java-sdk-server-jakarta</artifactId> <version>${version.io.a2a.sdk}</version> </dependency> Agent Card We will instantiate a CDI producer for an io.a2a.spec.AgentCard as follows: package org.wildfly.ai.a2a.weather; import java.util.Collections; import java.util.List; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; import io.a2a.spec.AgentCapabilities; import io.a2a.spec.AgentCard; import io.a2a.spec.AgentSkill; import io.a2a.server.PublicAgentCard; @ApplicationScoped public class WeatherAgentCardProducer { @Produces @PublicAgentCard public AgentCard agentCard() { return new AgentCard.Builder() .name("Weather Agent") .description("Helps with weather") .url("http://host.containers.internal:8080") .version("1.0.0") .protocolVersion("0.2.5") .capabilities(new AgentCapabilities.Builder() .streaming(true) .pushNotifications(false) .stateTransitionHistory(false) .build()) .defaultInputModes(Collections.singletonList("text")) .defaultOutputModes(Collections.singletonList("text")) .skills(Collections.singletonList(new AgentSkill.Builder() .id("weather_search") .name("Search weather") .description("Helps with weather in a city or state") .tags(Collections.singletonList("weather")) .examples(List.of("weather in LA, CA", "Quelle est la météo à Los Angeles, Californie ?")) .build())) .build(); } } As you can see, we are primarily providing metadata about our agent. We set the url to http://host.containers.internal:8080, the standard URL that Podman exposes for the host (at least on machines where it uses a VM internally). This URL is used to connect to the A2A agent, and you would typically set it to your agent’s public URL. Agent Executor We will instantiate a CDI producer for an io.a2a.server.agentexecution.AgentExecutor as follows: package org.wildfly.ai.a2a.weather; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; import jakarta.inject.Inject; import java.util.List; import io.a2a.server.agentexecution.AgentExecutor; import io.a2a.server.agentexecution.RequestContext; import io.a2a.server.events.EventQueue; import io.a2a.server.tasks.TaskUpdater; import io.a2a.spec.JSONRPCError; import io.a2a.spec.Message; import io.a2a.spec.Part; import io.a2a.spec.Task; import io.a2a.spec.TaskNotCancelableError; import io.a2a.spec.TaskState; import io.a2a.spec.TextPart; @ApplicationScoped public class WeatherAgentExecutorProducer { public WeatherAgentExecutorProducer(){ } //Injecting the LLM service @Inject WeatherAgent weatherAgent; @Produces public AgentExecutor agentExecutor() { return new WeatherAgentExecutor(weatherAgent); } private static class WeatherAgentExecutor implements AgentExecutor { private final WeatherAgent weatherAgent; public WeatherAgentExecutor(WeatherAgent weatherAgent) { this.weatherAgent = weatherAgent; } @Override public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { TaskUpdater updater = new TaskUpdater(context, eventQueue); // mark the task as submitted and start working on it if (context.getTask() == null) { updater.submit(); } updater.startWork(); // extract the text from the message String userMessage = extractTextFromMessage(context.getMessage()); // call the weather agent with the user's message String response = weatherAgent.chat(userMessage); // create the response part TextPart responsePart = new TextPart(response, null); List<Part<?>> parts = List.of(responsePart); // add the response as an artifact and complete the task updater.addArtifact(parts, null, null, null); updater.complete(); } private String extractTextFromMessage(Message message) { StringBuilder textBuilder = new StringBuilder(); if (message.getParts() != null) { for (Part part : message.getParts()) { if (part instanceof TextPart textPart) { textBuilder.append(textPart.getText()); } } } return textBuilder.toString(); } @Override public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { Task task = context.getTask(); if (task.getStatus().state() == TaskState.CANCELED) { // task already cancelled throw new TaskNotCancelableError(); } if (task.getStatus().state() == TaskState.COMPLETED) { // task already completed throw new TaskNotCancelableError(); } // cancel the task TaskUpdater updater = new TaskUpdater(context, eventQueue); updater.cancel(); } } } The extractTextFromMessage method extracts the content from the A2A message, which is then used as the payload for the AI service. Exposing the Agent To expose the agent’s endpoints from the A2A Java SDK for Jakarta Servers library, we need to register a JAX-RS application as shown below: package org.wildfly.ai.a2a.weather; import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; @ApplicationPath("/") public class RestApplication extends Application { } Deploy and Test Your Agent Setting Up the A2A-Inspector Tool To test our agent, we will use Google’s A2A-inspector tool in a container. First, clone the repository locally, build the container image, and then run it. git clone https://github.com/a2aproject/a2a-inspector.git cd a2a-inspector podman build -t a2a-inspector . podman run -d --rm --name a2a-inspector -p 5001:8080 a2a-inspector Verify that the inspector is running by navigating to http://localhost:5001/. Build and Run the A2A Agent The pom.xml file is straightforward and relies on WildFly Glow to provision the server with all the necessary components. <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.jboss</groupId> <artifactId>jboss-parent</artifactId> <version>49</version> </parent> <groupId>org.wildfly.generative-ai</groupId> <artifactId>weather-agent</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <jakartaee>10.0.0</jakartaee> <version.wildfly.maven.plugin>5.1.3.Final</version.wildfly.maven.plugin> <version.wildfly.server>36.0.1.Final</version.wildfly.server> <version.wildfly.ai.feature.pack>1.0.0-SNAPSHOT</version.wildfly.ai.feature.pack> <version.dev.langchain4j>1.1.0</version.dev.langchain4j> <version.dev.langchain4j.embeddings>1.1.0-beta7</version.dev.langchain4j.embeddings> <version.io.smallrye.llm>0.0.6</version.io.smallrye.llm> <version.compiler.plugin>3.13.0</version.compiler.plugin> <version.war.plugin>3.4.0</version.war.plugin> <version.io.a2a.sdk>0.2.5</version.io.a2a.sdk> </properties> <dependencies> <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-api</artifactId> <version>${jakartaee}</version> <scope>provided</scope> </dependency> <dependency> <groupId>io.smallrye.llm</groupId> <artifactId>smallrye-llm-langchain4j-core</artifactId> <version>${version.io.smallrye.llm}</version> <scope>provided</scope> </dependency> <dependency> <groupId>io.smallrye.llm</groupId> <artifactId>smallrye-llm-langchain4j-portable-extension</artifactId> <version>${version.io.smallrye.llm}</version> <scope>provided</scope> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j</artifactId> <version>${version.dev.langchain4j}</version> <scope>provided</scope> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-core</artifactId> <version>${version.dev.langchain4j}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.wildfly.a2a</groupId> <artifactId>a2a-java-sdk-server-jakarta</artifactId> <version>${version.io.a2a.sdk}</version> </dependency> </dependencies> <build> <plugins> <!--Configuration of the maven-compiler-plugin --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${version.compiler.plugin}</version> <configuration></configuration> </plugin> <!--Filtering the jboss-cli script --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>3.3.1</version> <configuration> <outputDirectory>${basedir}/target/scripts</outputDirectory> <resources> <resource> <directory>src/scripts</directory> <filtering>true</filtering> </resource> </resources> </configuration> </plugin> <!--Build configuration for the WAR plugin --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>${version.war.plugin}</version> <configuration> <!-- EE doesn't require web.xml, Maven needs to catch up! --> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <discoverProvisioningInfo> <spaces> <space>incubating</space> </spaces> <version>${version.wildfly.server}</version> <suggest>true</suggest> </discoverProvisioningInfo> <name>ROOT.war</name> <extraServerContentDirs> <extraServerContentDir>extra-content</extraServerContentDir> </extraServerContentDirs> <packagingScripts> <packaging-script> <scripts> <script>${basedir}/target/scripts/configure_mcp.cli</script> </scripts> </packaging-script> </packagingScripts> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project> git clone git@github.com:ehsavoie/a2a-weather.git cd a2a-weather mvn clean package export GEMINI_CHAT_MODEL_NAME=gemini-2.5-flash export GEMINI_API_KEY=******************************* ./target/server/bin/standalone.sh -b 0.0.0.0 Figure 1. A2A Inspector - Agent Card Now, if we ask for the weather in Los Angeles, California, we get the following response: Figure 2. A2A Inspector - Agent Execution Our agent is now up and running and can be consumed by any A2A-compliant agent or client, not just the inspector. Conclusion Transforming an AI application into an A2A agent requires minimal effort. This enables your agent to communicate with other AI agents, allowing them to collaborate, share information, and coordinate actions regardless of their underlying frameworks or vendors. ### [WildFly 37 is released!](/news/2025/08/04/WildFly-37-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 37.0.0.Final releases are available for download at https://wildfly.org/downloads, The Galleon feature-packs for WildFly 37 are available in the JBoss Maven repository. Note We expect it will be another day before the 37 artifacts are available in Maven Central. New and Notable This quarter was primarily devoted to bug fixing and clearing of technical debt. A lot of our focus was on working on the transition of WildFly to Commonhaus sponsorship as well as adapting to the transition to Nexus 3 in the Maven repository where we deploy most WildFly artifacts. The latter in particular has been a major effort. We did add one small feature this quarter: The messaging-activemq subsystem added the scale-down-commit-interval attribute to its ha-policy resource to let users define the number of messages in a transaction batch when transferring them to another node during a scale down. This setting can help avoid OOME issues during scale down. Supported Specifications Jakarta Standard WildFly 37 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly is EE 10 Platform, Web Profile and Core Profile compatible when running on Java SE 17 and Java SE 21. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence EE 10 Full Platform SE 17 SE 21 EE 10 Web Profile SE 17 SE 21 EE 10 Core Profile SE 17 SE 21 MicroProfile Standard WildFly 37 supports MicroProfile Platform 7.0, along with several other MicroProfile specifications that are not part of MicroProfile Platform. The full listing is available in the Getting Started Guide. Compatibility evidence for the specifications that are part of MicroProfile 7.0 can be found in the WildFly Certifications repository on GitHub. WildFly Preview and EE 11 Since the WildFly 32 release, we are using WildFly Preview to provide a look at what we’re doing for EE 11 support. The EE 11 Platform and Web Profile specifications won’t go GA before later this year. But there are milestone, Release Candidate and Final releases of many EE 11 specs and implementations available, so we are providing those in WildFly Preview. This means for a number of EE APIs, WildFly Preview no longer provides an EE 10 compatible implementation. However, for a number of specifications that are planning changes for EE 11 we are still offering the EE 10 variant. In future releases we’ll shift those to the EE 11 variants. The EE 11 Core Profile specification went GA last November and WildFly Preview 37 supports that profile. The EE 11 Platform and Web Profile went GA earlier this year. We are working on completing our implementation of these in WildFly Preview, for eventual incorporation in standard WildFly. Full details on the EE specification versions provided by WildFly Preview can be found in the WildFly 37 documentation. Java SE Support Our recommendation is that you run WildFly 37 on Java SE 21, as that is the latest LTS JDK release where we have completed the full set of testing we like to do before recommending a particular SE version. WildFly 37 also is heavily tested and runs well on Java 17. Our recommendation of SE 21 over SE 17 is solely because as a general principle we recommend being on later LTS releases, not because of any problems with WildFly on SE 17. While we recommend using an LTS JDK release, I do believe WildFly runs well on SE 24. By runs well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. We’ve also had good results with tests on Linux of an EA release of SE 25 (Oracle 25-ea+10-1084). Please note that WildFly runs in classpath mode. Incompatible Changes There are a few incompatible changes in WildFly 37 that may affect some users: We removed the jgroups-udp-fd and jgroups-tcp-fd socket bindings from our out-of-the-box configuration files in favor of a single jgroups-fd socket binding. If you are customizing our standard configs you may need to adapt your customization. If you develop low-level management clients for WildFly, you may be affected by a change to the ModelControllerClient interface. We’ve changed the return type from the executeAsync and executeOperationAsync methods from the org.jboss.threads.AsyncFuture interface to Java SE’s java.util.concurrent.CompletableFuture. Both of those are java.util.concurrent.Future sub-interfaces, so if all you were using was the Future API this may not affect you. You can manage a WildFly instance with Java Mission Control by integrating our jboss-client.jar into your JMC installation, typically by dropping the jar in your JMC installation’s Eclipse/dropins folder. The mechanism JMC provides for this integration changed incompatibly between JMC 8 and JMC 9, and it’s not possible for us to support both in the same jboss-client.jar. For WildFly 37 we switched to supporting the JMC 9+ mechanism, so the 37 jar can’t be integrated into JMC 8. However, a JMC 8 installation using an older version of jboss-client.jar will work fine for managing a WildFly 37 server. A JMC 9 integration can manage an older WildFly as well. New and Noteworthy Contributors WildFly gets great contributions from so many people. Let’s thank a few of them. Cody Lerum provided an excellent reproducer for WFLY-20646 / HHH-19476, a problem that had been troubling a number of Hibernate users. The reproducer quickly led to a fix. Beyond this, Cody always provides great feedback. You’re the best, Cody! David Hladky has been going way above and beyond working through the transition of repository.jboss.org to Nexus 3. Thank you, David! Paul Ferraro provided great inputs about how WildFly and other projects should deploy to the new repository.jboss.org. Paul’s also been doing yeoman’s work on transitioning a number of our subsystem implemenations to the modernized subsystem development framework he created. Thank you, Paul! Jason Lee migrated this website from Jekyll to the rockin' Quarkus Roq. Much appreciated, Jason! Release Notes The full WildFly 37 release notes are available in GitHub. Issues fixed in the underlying WildFly Core 29.0.0 release are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. Onward to WildFly 38! Best regards, Brian ### [Join us on July 24 for a discussion of WildFly Governance!](/news/2025/07/17/Join-us-on-July-24-for-a-discussion-of-WildFly-Governance/) We’re working hard on adopting a new governance model for the WildFly projects, and we’d love to have your input. To that end, we’ll be hosting a call (Google meet) a week from today, July 24, 9 AM EDT, to discuss the topic. It would be great to see you there and hear your thoughts! The call is shown on the events page. Details: Meeting link Agenda and discussion document I encourage you to have a look at my call-for-input from a couple weeks ago and the draft document I discussed there. The more that people are familiar with the background the more we can focus on the call on moving things forward. Discussion in advance, either here on the wildfly-dev thread or in comments on the governance doc draft are more than welcome. See you there! Brian] ### [Testing WildFly applications on OpenShift with Arquillian Cube](/news/2025/07/07/Testing-WildFly-applications-on-OpenShift-with-Arquillian-Cube/) Recently we blogged about testing WildFly on Kubernetes effectively and easily, thanks to Arquillian Cube, now it’s time to see how it can be done on OpenShift! In the Testing WildFly applications on Kubernetes with Arquillian Cube article we saw how an Arquillian Cube test can be implemented to set up an automated integration test for a WildFly application that should be run on Kubernetes. We’ll now see how a modern WildFly Bootable JAR application can be tested on OpenShift, with Arquillian Cube taking care of all the aspects, starting from the resources creation to the application image build and deployment, and finally to the test lifecycle management. Use case A simple WildFly Jakarta REST based Bootable JAR application that exposes an endpoint for greeting the user will be our starting point, and our goal is to have a test class that will deploy it on OpenShift and then verify that it’s up and running. Steps Create the getting-started application As usual, we’ll assume that Java and Maven are available already in our local configuration. Then cd to a directory of your choice and create the example application with the following command: mvn archetype:generate -DarchetypeGroupId=org.wildfly.archetype -DarchetypeArtifactId=wildfly-getting-started-archetype You’ll be prompted for either entering or accepting the default values for the application configuration, let’s hit the Enter key, in order to use the defaults: Confirm properties configuration: defaultClassPrefix: GettingStarted groupId: org.wildfly.examples artifactId: getting-started package: org.wildfly.examples version: 1.0.0-SNAPSHOT Y: Once done, a new getting-started directory is created, with the following contents: $ ls -l total 16 -rw-r--r--. 1 fburzigo fburzigo 10469 May 23 13:51 pom.xml -rw-r--r--. 1 fburzigo fburzigo 1045 May 23 13:51 README.adoc drwxr-xr-x. 1 fburzigo fburzigo 16 May 23 13:51 src This is all we need for now, feel free to inspect the POM and see how the WildFly Maven Archetype provided a ready-to-use configuration which will allow for us to leverage EE components, like for instance the Jakarta REST API implementation: <dependencyManagement> <dependencies> <!-- JBoss distributes a complete set of EE APIs including a Bill of Materials (BOM). A BOM specifies the versions of a "stack" (or a collection) of artifacts. We use this here so that we always get the correct versions of artifacts (you can read this as the WildFly stack of the EE APIs, with some extras tools for your project, such as Arquillian for testing) --> <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>wildfly-ee-with-tools</artifactId> <version>${version.wildfly.bom}</version> <type>pom</type> <scope>import</scope> </dependency> <!--Define the JUnit5 bom. WildFly BOM still contains JUnit4, so we have to declare a version here --> <dependency> <groupId>org.junit</groupId> <artifactId>junit-bom</artifactId> <version>${version.junit5}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- Import the CDI API, we use provided scope as the API is included in WildFly --> <dependency> <groupId>jakarta.enterprise</groupId> <artifactId>jakarta.enterprise.cdi-api</artifactId> <scope>provided</scope> </dependency> <!-- Import the Jakarta REST API, we use provided scope as the API is included in WildFly --> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <scope>provided</scope> <dependency> Also, we can see that the src directory contains already the required classes that implement JAX-RS based application $ tree src src ├── main │   ├── java │   │   └── org │   │   └── wildfly │   │   └── examples │   │   ├── GettingStartedApplication.java │   │   ├── GettingStartedEndpoint.java │   │   └── GettingStartedService.java ... └── test ├── java │   └── org │   └── wildfly │   └── examples │   ├── GettingStartedApplicationIT.java │   └── GettingStartedServiceIT.java └── resources └── arquillian.xml As you can see test sources have been generated as well, and an arquillian.xml file is provided, which includes the configuration for starting an Arquillian WildFly container and run tests locally. Let’s see how everything works with no changes by running the following command: mvn clean install The above command will: Build the application and generate a WAR deployment Start the WildFly Arquillian container which will run the server locally and deploy the application Execute the tests against it As a final result we should see a build success, with 2 tests passing: [INFO] [INFO] Results: [INFO] [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] [INFO] --- failsafe:3.5.3:verify (default) @ getting-started --- [INFO] [INFO] --- install:3.1.2:install (default-install) @ getting-started --- Downloading from central: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-xml/3.0.0/plexus-xml-3.0.0.jar Downloaded from central: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-xml/3.0.0/plexus-xml-3.0.0.jar (93 kB at 1.2 MB/s) [INFO] Installing /home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/pom.xml to /home/fburzigo/.m2/repository/org/wildfly/examples/getting-started/1.0.0-SNAPSHOT/getting-started-1.0.0-SNAPSHOT.pom [INFO] Installing /home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/target/ROOT.war to /home/fburzigo/.m2/repository/org/wildfly/examples/getting-started/1.0.0-SNAPSHOT/getting-started-1.0.0-SNAPSHOT.war [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 01:49 min [INFO] Finished at: 2025-05-23T14:35:11+02:00 [INFO] ------------------------------------------------------------------------ Enough for running the tests locally, now let’s see how to use Arquillian Cube and make some changes to automate the deployment of the same application to OpenShift, and have a test which will run against a cloud native version of the example application. Generate a WildFly Bootable JAR for OpenShift Let’s start by adding a set of properties to our project POM, which will be used in the new configuration: <properties> <!-- ... --> <arquillian-cube.version>2.1.0.Alpha2</arquillian-cube.version> <wildfly-jar-maven-plugin.version>12.0.0.Final</wildfly-jar-maven-plugin.version> <jkube-openshift-maven-plugin.version>1.18.1</jkube-openshift-maven-plugin.version> </properties> For OpenShift, we’d need a Bootable JAR, since Arquillian Cube will use the internal JKube OpenShift Maven plugin integration, which includes a default generator, that in turn works by default with Bootable JAR. Nothing really difficult, we just need to replace the wildfly-maven-plugin declaration and the related configuration with a very similar one for the wildfly-jar-maven-plugin: <!-- The WildFly JAR Maven plugin creates a runnable JAR that contains the server and the deployed application --> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>${wildfly-jar-maven-plugin.version}</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.wildfly.bom}</location> </feature-pack> </feature-packs> <layers> <!-- layers may be used to customize the server to provision--> <layer>cloud-server</layer> </layers> <excluded-layers> <layer>deployment-scanner</layer> </excluded-layers> <cloud/> <plugin-options> <jboss-fork-embedded>true</jboss-fork-embedded> </plugin-options> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> As you can see we added something, compared to the original example wildfly-maven-plugin configuration: We added an excluded layer, i.e. the deployment-scanner layer, since that is not needed by a Bootable JAR application We added the <cloud/> element, which is responsible for configuring the generated Bootable JAR application for the Cloud, e.g.: it will enrich the deployment with health probes configuration We set the jboss-fork-embedded plugin option to true to avoid conflicts with the wildfly-maven-plugin execution Then we’ll remove the JUnit5 bom declaration from the <dependencyManagment> section <dependency> <groupId>org.junit</groupId> <artifactId>junit-bom</artifactId> <version>${version.junit5}</version> <type>pom</type> <scope>import</scope> </dependency> and the following test dependencies, too: <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.junit5</groupId> <artifactId>arquillian-junit5-container</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.wildfly.arquillian</groupId> <artifactId>wildfly-arquillian-container-managed</artifactId> <scope>test</scope> </dependency> <!-- ... --> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>commons-logging-jboss-logging</artifactId> <scope>test</scope> </dependency> The resteasy-client test dependency must be kept since it provides the APIs implementation for the test class to perform an HTTP client call to the WildFly application After that, we can add our Arquillian Cube bom to the <dependencyManagement> section: <dependency> <groupId>org.arquillian.cube</groupId> <artifactId>arquillian-cube-bom</artifactId> <version>${arquillian-cube.version}</version> <type>pom</type> <scope>import</scope> </dependency> and finally the required test dependencies: <dependency> <groupId>org.arquillian.cube</groupId> <artifactId>arquillian-cube-openshift-starter</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.arquillian.cube</groupId> <artifactId>arquillian-cube-openshift</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-core</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> Introducing the JKube OpenShift Maven plugin We’ll add a JKube OpenShift Maven plugin declaration in order to have some configuration in place, and then we’ll have Arquillian Cube drive its execution when running the tests, thanks to the internal integration: <plugin> <groupId>org.eclipse.jkube</groupId> <artifactId>openshift-maven-plugin</artifactId> <version>${jkube-openshift-maven-plugin.version}</version> <executions> <!-- Do not execute when packaging. The Arquillian Cube/JKube OpenShift Maven plugin integration will handle that in the integration-tests phase, see the Maven Failsafe plugin configuration below. <execution> <goals> <goal>resource</goal> <goal>build</goal> </goals> </execution> --> </executions> <configuration> <enricher> <config> <jkube-service> <name>hello-world-svc</name> </jkube-service> </config> </enricher> </configuration> </plugin> As said we’ve commented out executions because we’ll let Arquillian Cube do the job for us, but we’ve provided a configuration for adding a named Service - i.e. hello-world-svc - which can be injected and referenced by our test class. Time to add what’s needed to kick Arquillian Cube tests off. Configuring Arquillian Cube execution for OpenShift The first thing we’ll need to do is to edot the arquillian.xml file, and replace its contents with the following configuration: <?xml version="1.0"?> <arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://jboss.org/schema/arquillian" xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd"> <extension qualifier="openshift"> <property name="enableImageStreamDetection">false</property> </extension> </arquillian> As you can see we’ve configured the openshift extension and set the only one property, i.e.: enableImageStreamDetection to false, because we don’t want the creation of the application image stream which is produced by the OpenShift build to block Arquillian Cube from replacing it. And now the last bit, let’s configure the Maven Failsafe plugin to provide properties that will drive the JKube OpenShift Maven plugin execution: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <configuration> <systemPropertyVariables> <version.cube>${arquillian-cube.version}</version.cube> <cube.fmp.build>true</cube.fmp.build> <cube.fmp.debug.output>false</cube.fmp.debug.output> <cube.fmp.logs>true</cube.fmp.logs> <cube.fmp.system.properties>jkube.docker.push.registry,image-registry.openshift-image-registry.svc:5000,jkube.docker.pull.registry,image-registry.openshift-image-registry.svc:5000</cube.fmp.system.properties> <cube.fmp.local.maven>true</cube.fmp.local.maven> </systemPropertyVariables> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <skip>true</skip> </configuration> </plugin> In the above configuration we also skip the Maven Surefire plugin execution, since we just want for Failsafe to run. Let’s explain the system properties that we’re setting for the test execution: version.cube - Set the Arquillian Cube version, as it’s used by the JKube OpenShift Maven Plugin internal integration cube.fmp.build - Whether to drive the JKube OpenShift Maven plugin execution to build required resources cube.fmp.debug.output - Whether to produce verbose output cube.fmp.logs - Whether to stream the OpenShift operations logs cube.fmp.system.properties - System properties to be passed to the JKube OpenShift Maven plugin execution, here we specifically set the docker registry for pulling and pushing images to the OpenShift internal registry cube.fmp.local.maven - Whether to let the JKube OpenShift Maven plugin use a local Maven binary to perform the build. That should be all about the configuration, now it’s time to add a specific test class - i.e. GettingStartedOpenShiftApplicationIT.java - with the following contents: package org.wildfly.examples; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.core.Response; import org.apache.http.HttpStatus; import org.arquillian.cube.openshift.impl.enricher.RouteURL; import org.arquillian.cube.requirement.ArquillianConditionalRunner; import org.awaitility.Awaitility; import org.junit.Test; import org.junit.runner.RunWith; import java.net.URI; import java.net.URL; import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.assertEquals; @RunWith(ArquillianConditionalRunner.class) public class GettingStartedOpenShiftApplicationIT { @RouteURL("hello-world-svc") private URL url; @Test public void helloEndpointShouldReplyWithHttp200() { // The OpenShift Route resource for the application to be available outside the cluster will take some time to be ready Awaitility.await() .atMost(60, TimeUnit.SECONDS) .until( () -> { Response statusResponse = RestAssured.given() .when() .get(serviceUrl); return statusResponse.statusCode() == HttpStatus.SC_OK; } ); try (Client client = ClientBuilder.newClient()) { jakarta.ws.rs.core.Response response = client .target(URI.create(url.toString())) .path("/hello/World") .request() .get(); assertEquals(200, response.getStatus()); assertEquals("Hello 'World'.", response.readEntity(String.class)); } } } And…​ Done! Don’t forget to remove the original example test classes (GettingStartedServiceIT.java and GettingStartedApplicationIT.java), since those won’t compile with the updated configuration. Run the test You’ll need an OpenShift cluster at hand to run the tests, or try one of the following options in case you don’t: Red Hat OpenShift Local (formerly Red Hat CodeReady Containers) Red Hat Developer Sandbox Once you have an OpenShift cluster up and running, make sure you log in into it, with something like: oc login --token=<YOUR_OCP_TOKEN> --server=https://api.my-cluster.com:6443 Finally, in order to run integration tests to verify the application, issue the following command: mvn clean package verify -Dmaven.home=$(which mvn) Note: The -Dmaven.home=$(which mvn) property is required by the JKube OpenShift Maven plugin, in order to run the build with a local Maven binary, rather than downloading one from the Internet, which can randomly cause some issues. Arquillian Cube will use the internal JKube OpenShift Maven plugin integration to generate resources and stream the application binaries to OpenShift, for an s2i build to generate the application image, which in turn will be executed as a cluster workload and exposed externally via a Route. Tests are run against the remote WildFly application service which is orchestrated by OpenShift: ... [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running org.wildfly.examples.GettingStartedOpenShiftApplicationIT Jun 19, 2025 3:41:00 PM org.arquillian.cube.openshift.impl.CubeOpenshiftExtension register INFO: Registering CubeOpenshiftExtension... ... CubeKubernetesConfiguration: namespace = itest-3abe449b namespace.lazy.enabled = true namespace.cleanup.enabled = true namespace.cleanup.timeout = 0 namespace.cleanup.confirm.enabled = false namespace.destroy.enabled = true namespace.destroy.confirm.enabled = false namespace.destroy.timeout = 0 wait.enabled = true wait.timeout = 480000 wait.poll.interval = 5000 ansi.logger.enabled = true env.init.enabled = true logs.copy = false cube.api.version = v1 cube.trust.certs = true cube.fmp.build = true cube.fmp.build.disable.for.mvn = false cube.fmp.pom.path = pom.xml cube.fmp.debug.output = false cube.fmp.logs = true cube.fmp.system.properties = [jkube.docker.push.registry, image-registry.openshift-image-registry.svc:5000, jkube.docker.pull.registry, image-registry.openshift-image-registry.svc:5000] cube.fmp.build.options = CubeOpenShiftConfiguration: keepAliveGitServer = false autoStartContainers = [] portForwardBindAddress = 127.0.0.1 openshiftRouterHttpPort = 80 openshiftRouterHttpsPort = 443 enableImageStreamDetection = false routerSniPort = 443 templateProcess = true startupTimeout = 600 httpClientTimeout = 120 awaitRouteRepetitions = 1 Initializing Session:3abe449b ... Creating project: itest-3abe449b To switch to the new project: oc project itest-3abe449b ================================================================= === Embedded Maven build started: getting-started/pom.xml === ================================================================= [DEBUG] Using maven.home of: '/home/fburzigo/.sdkman/candidates/maven/current'. [DEBUG] Executing: /bin/sh -c cd '/home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started' && '/home/fburzigo/.sdkman/candidates/maven/3.9.6/bin/mvn' '-D' 'jkube.docker.push.registry=image-registry.openshift-image-registry.svc:5000' '-D' 'jkube.docker.pull.registry=image-registry.openshift-image-registry.svc:5000' '-D' 'jkube.namespace=itest-3abe449b' '-D' 'skipTests=true' 'package' 'oc:build' 'oc:resource' [WARN] Maven will be executed in interactive mode, but no input stream has been configured for this MavenInvoker instance. -> [INFO] Scanning for projects... -> [INFO] -> [INFO] -------< org.wildfly.examples:wildfly-getting-started-cube-ocp >-------- -> [INFO] Building getting-started 1.0.0-SNAPSHOT -> [INFO] from pom.xml -> [INFO] --------------------------------[ war ]--------------------------------- -> [INFO] -> [INFO] --- resources:3.3.1:resources (default-resources) @ wildfly-getting-started-cube-ocp --- -> [INFO] skip non existing resourceDirectory /home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/src/main/resources -> [INFO] -> [INFO] --- compiler:3.14.0:compile (default-compile) @ wildfly-getting-started-cube-ocp --- -> [INFO] Nothing to compile - all classes are up to date. -> [INFO] -> [INFO] --- resources:3.3.1:testResources (default-testResources) @ wildfly-getting-started-cube-ocp --- -> [INFO] Copying 1 resource from src/test/resources to target/test-classes -> [INFO] -> [INFO] --- compiler:3.14.0:testCompile (default-testCompile) @ wildfly-getting-started-cube-ocp --- -> [INFO] Nothing to compile - all classes are up to date. -> [INFO] -> [INFO] --- surefire:3.2.2:test (default-test) @ wildfly-getting-started-cube-ocp --- -> [INFO] Tests are skipped. -> [INFO] -> [INFO] --- war:3.4.0:war (default-war) @ wildfly-getting-started-cube-ocp --- -> [INFO] Packaging webapp -> [INFO] Assembling webapp [wildfly-getting-started-cube-ocp] in [/home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/target/ROOT] -> [INFO] Processing war project -> [INFO] Copying webapp resources [/home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/src/main/webapp] -> [INFO] Building war: /home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/target/ROOT.war -> [INFO] -> [INFO] --- wildfly-jar:12.0.0.Final:package (default) @ wildfly-getting-started-cube-ocp --- -> [INFO] Cloud support is enabled -> [INFO] Provisioning server configuration based on the set of configured layers -> [INFO] Building server based on [[org.wildfly:wildfly-galleon-pack:36.0.1.Final inherit-packages=false inheritConfigs=false]] galleon feature-packs -> [INFO] Resolving feature-packs -> [INFO] Installing packages -> [INFO] Resolving artifacts -> [INFO] Generating configurations -> [INFO] Delayed generation, waiting... -> [INFO] CLI executions are done in forked process -> [INFO] Executing CLI, Server configuration -> [INFO] CLI scripts execution done. -> [INFO] Stored CLI script executed to update server configuration in /home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/target/bootable-jar-build-artifacts/generated-cli-script.txt file. -> [INFO] -> [INFO] --- oc:1.18.1:build (default-cli) @ wildfly-getting-started-cube-ocp --- -> [INFO] oc: Using OpenShift build with strategy S2I -> [INFO] oc: Running generator wildfly-jar -> [INFO] oc: wildfly-jar: Using Docker image quay.io/jkube/jkube-java:0.0.26 as base / builder -> [INFO] oc: [wildfly-getting-started-cube-ocp:latest] "wildfly-jar": Created docker source tar /home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/target/docker/wildfly-getting-started-cube-ocp/latest/tmp/docker-build.tar -> [INFO] oc: Creating BuildServiceConfig wildfly-getting-started-cube-ocp-s2i for Source build -> [INFO] oc: Creating ImageStream wildfly-getting-started-cube-ocp -> [INFO] oc: Starting Build wildfly-getting-started-cube-ocp-s2i -> [INFO] oc: Waiting for build wildfly-getting-started-cube-ocp-s2i-1 to complete... -> [INFO] oc: Adding cluster TLS certificate authority to trust store -> [INFO] oc: Receiving source from STDIN as archive ... -> [INFO] oc: Adding cluster TLS certificate authority to trust store -> [INFO] oc: Adding cluster TLS certificate authority to trust store -> [INFO] oc: time="2025-06-19T13:43:09Z" level=info msg="Not using native diff for overlay, this may cause degraded performance for building images: kernel has CONFIG_OVERLAY_FS_REDIRECT_DIR enabled" -> [INFO] oc: I0619 13:43:09.645235 1 defaults.go:112] Defaulting to storage driver "overlay" with options [mountopt=metacopy=on]. -> [INFO] oc: Caching blobs under "/var/cache/blobs". -> [INFO] oc: Trying to pull quay.io/jkube/jkube-java:0.0.26... -> [INFO] oc: Getting image source signatures -> [INFO] oc: Copying blob sha256:4995ccf10f8a18910697bc957f9f00998673074f8cb24c70992f4e380beafecb -> [INFO] oc: Copying blob sha256:5871471db7a8c7f61bce8c90a4927db327c29ba060adddfaa216635cb8ecc2f2 -> [INFO] oc: Copying blob sha256:273b281ad871b855285c711b480ad49a5f5c47d8397599dd44e43ed390112f4f -> [INFO] oc: Copying config sha256:36aa194b45654bd4fe53853924d7e5968f13e30658ad40f241467c1d3bbde85a -> [INFO] oc: Writing manifest to image destination -> [INFO] oc: Generating dockerfile with builder image quay.io/jkube/jkube-java:0.0.26 -> [INFO] oc: Adding transient rw bind mount for /run/secrets/rhsm -> [INFO] oc: STEP 1/9: FROM quay.io/jkube/jkube-java:0.0.26 -> [INFO] oc: STEP 2/9: LABEL "io.openshift.build.image"="quay.io/jkube/jkube-java:0.0.26" "io.openshift.build.source-location"="/tmp/build/inputs" "io.openshift.s2i.destination"="/tmp" -> [INFO] oc: STEP 3/9: ENV AB_PROMETHEUS_OFF="true" AB_JOLOKIA_OFF="true" JAVA_OPTIONS="-Djava.net.preferIPv4Stack=true" AB_OFF="true" JAVA_APP_DIR="/deployments" OPENSHIFT_BUILD_NAME="wildfly-getting-started-cube-ocp-s2i-1" OPENSHIFT_BUILD_NAMESPACE="itest-3abe449b" -> [INFO] oc: STEP 4/9: USER root -> [INFO] oc: STEP 5/9: COPY upload/src /tmp/src -> [INFO] oc: STEP 6/9: RUN chown -R 1000:0 /tmp/src -> [INFO] oc: STEP 7/9: USER 1000 -> [INFO] oc: STEP 8/9: RUN /usr/local/s2i/assemble -> [INFO] oc: INFO S2I source build with plain binaries detected -> [INFO] oc: INFO S2I binary build from fabric8-maven-plugin detected -> [INFO] oc: INFO Copying binaries from /tmp/src/deployments to /deployments ... -> [INFO] oc: ROOT-bootable.jar -> [INFO] oc: INFO Copying deployments from deployments to /deployments... -> [INFO] oc: '/tmp/src/deployments/ROOT-bootable.jar' -> '/deployments/ROOT-bootable.jar' -> [INFO] oc: INFO Cleaning up source directory (/tmp/src) -> [INFO] oc: STEP 9/9: CMD /usr/local/s2i/run -> [INFO] oc: COMMIT temp.builder.openshift.io/itest-3abe449b/wildfly-getting-started-cube-ocp-s2i-1:438a56ec -> [INFO] oc: Getting image source signatures -> [INFO] oc: Copying blob sha256:f78d563114cad564510fe57424fa8f01903eb28721f5dd564d2605650391372e -> [INFO] oc: Copying blob sha256:0a2281db0c787d2736209eba769e6ae4ba1576c4406518d37801af9cb9a3c52a -> [INFO] oc: Copying blob sha256:1855389a719d5af60cf16c74123e25ef78c6d1a42faf549d1ebbded8ddbc506a -> [INFO] oc: Copying blob sha256:597b46961ff45b828ca25ee0d3618d6079f324790b8a8a4bf69c74f2144293ee -> [INFO] oc: Copying config sha256:0868f1c3f111137b05829094ea128d01ca810eb1f1de66c7ed18a5d20f60f245 -> [INFO] oc: Writing manifest to image destination -> [INFO] oc: --> 0868f1c3f111 -> [INFO] oc: Successfully tagged temp.builder.openshift.io/itest-3abe449b/wildfly-getting-started-cube-ocp-s2i-1:438a56ec -> [INFO] oc: 0868f1c3f111137b05829094ea128d01ca810eb1f1de66c7ed18a5d20f60f245 -> [INFO] oc: -> [INFO] oc: Pushing image image-registry.openshift-image-registry.svc:5000/itest-3abe449b/wildfly-getting-started-cube-ocp:latest ... -> [INFO] oc: Getting image source signatures -> [INFO] oc: Copying blob sha256:597b46961ff45b828ca25ee0d3618d6079f324790b8a8a4bf69c74f2144293ee -> [INFO] oc: Copying blob sha256:5871471db7a8c7f61bce8c90a4927db327c29ba060adddfaa216635cb8ecc2f2 -> [INFO] oc: Copying blob sha256:273b281ad871b855285c711b480ad49a5f5c47d8397599dd44e43ed390112f4f -> [INFO] oc: Copying blob sha256:4995ccf10f8a18910697bc957f9f00998673074f8cb24c70992f4e380beafecb -> [INFO] oc: Copying config sha256:0868f1c3f111137b05829094ea128d01ca810eb1f1de66c7ed18a5d20f60f245 -> [INFO] oc: Writing manifest to image destination -> [INFO] oc: Successfully pushed image-registry.openshift-image-registry.svc:5000/itest-3abe449b/wildfly-getting-started-cube-ocp@sha256:78807e57be5c95ce875ba819f169334a1e1b2fe6a9b4dae460d5c372d249562b -> [INFO] oc: Push successful -> [INFO] oc: Build wildfly-getting-started-cube-ocp-s2i-1 in status Complete -> [INFO] oc: Found tag on ImageStream wildfly-getting-started-cube-ocp tag: sha256:78807e57be5c95ce875ba819f169334a1e1b2fe6a9b4dae460d5c372d249562b -> [INFO] oc: ImageStream wildfly-getting-started-cube-ocp written to /home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/target/wildfly-getting-started-cube-ocp-is.yml -> [INFO] -> [INFO] --- oc:1.18.1:resource (default-cli) @ wildfly-getting-started-cube-ocp --- -> [INFO] oc: Using container image name of namespace: itest-3abe449b -> [INFO] oc: Running generator wildfly-jar -> [INFO] oc: wildfly-jar: Using Docker image quay.io/jkube/jkube-java:0.0.26 as base / builder -> [INFO] oc: Using resource templates from /home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/src/main/jkube -> [INFO] oc: jkube-controller: Adding a default Deployment -> [INFO] oc: jkube-service: Adding a default service 'hello-world-svc' with ports [8080] -> [INFO] oc: jkube-healthcheck-wildfly-jar: Adding readiness probe on port 9990, path='/health/ready', scheme='HTTP', with initial delay 10 seconds, with period 10 seconds -> [INFO] oc: jkube-healthcheck-wildfly-jar: Adding liveness probe on port 9990, path='/health/live', scheme='HTTP', with initial delay 60 seconds, with period 10 seconds -> [INFO] oc: jkube-openshift-deploymentconfig: Converting Deployment to DeploymentConfig -> [INFO] oc: jkube-service-discovery: Using first mentioned service port '8080' -> [INFO] oc: jkube-service-discovery: Using first mentioned service port '8080' -> [INFO] oc: jkube-service-discovery: Using first mentioned service port '8080' -> [INFO] oc: jkube-revision-history: Adding revision history limit to 2 -> [INFO] oc: validating /home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/target/classes/META-INF/jkube/openshift/hello-world-svc-service.yml resource -> [WARNING] Unknown keyword serializer - you should define your own Meta Schema. If the keyword is irrelevant for validation, just use a NonValidationKeyword or if it should generate annotations AnnotationKeyword -> [WARNING] Unknown keyword deserializer - you should define your own Meta Schema. If the keyword is irrelevant for validation, just use a NonValidationKeyword or if it should generate annotations AnnotationKeyword -> [INFO] oc: validating /home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/target/classes/META-INF/jkube/openshift/wildfly-getting-started-cube-ocp-deploymentconfig.yml resource -> [INFO] oc: validating /home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/target/classes/META-INF/jkube/openshift/hello-world-svc-route.yml resource -> [INFO] ------------------------------------------------------------------------ -> [INFO] BUILD SUCCESS -> [INFO] ------------------------------------------------------------------------ -> [INFO] Total time: 02:21 min -> [INFO] Finished at: 2025-06-19T15:43:26+02:00 -> [INFO] ------------------------------------------------------------------------ ================================================================= === Embedded Maven build stopped: getting-started/pom.xml === ================================================================= Applying kubernetes configuration from: file:/home/fburzigo/projects/git/fabiobrz/testing-wfly-on-ocp-with-cube/getting-started/target/classes/META-INF/jkube/openshift.yml Processing template. No parameters file has been specified, processing without external parameters! Replication controller: [wildfly-getting-started-cube-ocp-1] Pod: [wildfly-getting-started-cube-ocp-s2i-1-build] Status: [Succeeded] Service: [hello-world-svc] IP: [172.122.251.63] Ports: [ 8080 ] Jun 19, 2025 3:43:32 PM org.arquillian.cube.openshift.impl.CEEnvironmentProcessor createEnvironment INFO: Creating environment for org.wildfly.examples.GettingStartedOpenShiftApplicationIT Jun 19, 2025 3:43:32 PM org.arquillian.cube.kubernetes.impl.resources.KubernetesResourcesApplier applyKubernetesResourcesAtClassScope INFO: Creating environment for org.wildfly.examples.GettingStartedOpenShiftApplicationIT Jun 19, 2025 3:43:32 PM org.arquillian.cube.openshift.impl.CEEnvironmentProcessor createOpenShiftResource INFO: Creating environment for org.wildfly.examples.GettingStartedOpenShiftApplicationIT method public void org.wildfly.examples.GettingStartedOpenShiftApplicationIT.helloEndpointShouldReplyWithHttp200() Jun 19, 2025 3:43:32 PM org.arquillian.cube.kubernetes.impl.resources.KubernetesResourcesApplier applyKubernetesResourcesAtMethodScope INFO: Creating environment for org.wildfly.examples.GettingStartedOpenShiftApplicationIT method helloEndpointShouldReplyWithHttp200 Jun 19, 2025 3:43:48 PM org.arquillian.cube.openshift.impl.CEEnvironmentProcessor deleteOpenShiftResource INFO: Deleting environment for org.wildfly.examples.GettingStartedOpenShiftApplicationIT method helloEndpointShouldReplyWithHttp200 Jun 19, 2025 3:43:48 PM org.arquillian.cube.kubernetes.impl.resources.KubernetesResourcesApplier removeKubernetesResourcesAtMethodScope INFO: Deleting environment for org.wildfly.examples.GettingStartedOpenShiftApplicationIT method helloEndpointShouldReplyWithHttp200 Jun 19, 2025 3:43:48 PM org.arquillian.cube.openshift.impl.resources.OpenShiftResourceFactory deleteEnvironment INFO: Deleting environment for org.wildfly.examples.GettingStartedOpenShiftApplicationIT Jun 19, 2025 3:43:49 PM org.arquillian.cube.kubernetes.impl.resources.KubernetesResourcesApplier removeKubernetesResourcesAtClassScope INFO: Deleting environment for org.wildfly.examples.GettingStartedOpenShiftApplicationIT [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 169.2 s -- in org.wildfly.examples.GettingStartedOpenShiftApplicationIT Deleting project: itest-3abe449b... Project: itest-3abe449b, successfully deleted Destroying Session:3abe449b [INFO] [INFO] Results: [INFO] [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] [INFO] --- failsafe:3.5.3:verify (default) @ wildfly-getting-started-cube-ocp --- [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 03:22 min [INFO] Finished at: 2025-06-19T15:43:50+02:00 [INFO] ------------------------------------------------------------------------ In conclusion Testing a WildFly application directly on OpenShift will make the test more effective, and will allow prototyping and make debugging easier. Arquillian Cube provides an easy and effective way to test on OpenShift, with almost no configuration and instrumentation changes with respect to existing Arquillian based tests. The code for the example application which is described in this article is available here: https://github.com/fabiobrz/wildfly-getting-started-cube-ocp Fabio Burzigotti ### [New WildFly 37 Beta release](/news/2025/06/26/New-WildFly-37-Beta-release/) We’re excited to announce the release of WildFly 37.0.0.Beta1! This beta release, available for download from https://wildfly.org/downloads, includes new features and several enhancements, alongside numerous component upgrades. Key Highlights in this Beta Release: New Features: Artemis commit-interval attribute for scaledown: WildFly 37 Beta 1 exposes the Artemis commit-interval attribute for scaledown. The /core-service=platform-mbean resources have been evolved to expose new platform MXBeans, attributes and operations. Enhancements: The tasks-jsf quickstart now uses Glow. GPG detached signatures are now included with uploads at release time. The following commands demonstrate how to verify the GPG signature of the WildFly distribution: $ gpg --keyserver keyserver.ubuntu.com --recv-keys E85C11F6 $ gpg --verify wildfly-37.0.0.Beta1-src.tar.gz.asc wildfly-37.0.0.Beta1-src.tar.gz gpg: Signature made Wed 25 Jun 2025 14:33:44 BST gpg: using EDDSA key 245404A11575A55D6A41107E2D52D4ACE85C11F6 gpg: Good signature from "Darran Andrew Lofthouse <darran.lofthouse@jboss.com>" [unknown] gpg: aka "Darran Andrew Lofthouse <darran.lofthouse@redhat.com>" [unknown] gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. Primary key fingerprint: 2454 04A1 1575 A55D 6A41 107E 2D52 D4AC E85C 11F6 Contributors to WildFly publish their GPG keys on the Contributor PGP Information, which includes the fingerprint to aid verification. Component Upgrades: This release includes a significant number of component upgrades, ensuring WildFly remains current with the latest technologies and provides improved performance and security. Some notable upgrades include: Vert.x to 4.5.15. Hibernate ORM to 6.6.18.Final (and 7.0.2.Final for WildFly Preview). Micrometer to 1.15.0. EclipseLink to 4.0.6. SmallRye Fault Tolerance to 6.9.1. Apache Santuario XML Security for Java to 3.0.6. JBoss Universe Producers to 1.3.14. JBoss Metadata to 16.1.0.Final. Netty to 4.1.122.Final. Velocity Engine to 2.4.1. WildFly Clustering to 7.0.5.Final. Infinispan to 15.2.4.Final. JGroups to 5.4. Apache Artemis to 2.41.0. WildFly Core to 29.0.0.Beta6. HAL to 3.7.12.Final. Byteman to 4.0.25. JBossWS-CXF to 7.3.3.Final. Narayana to 7.2.2.Final. zstd-jni to 1.5.7-3. WildFly Licenses Plugin to 2.4.2.Final. FasterXML Jackson to 2.18.4. SmallRye Common to 2.12.0. Hibernate Search to 8.0.0.Final (in WildFly preview). Weld to 5.1.6.Final and 6.0.3.Final. Hibernate Validator to 9.0.1.Final (in WildFly preview). Expressly to 6.0.0 (in WildFly preview). Apache CXF to 4.0.8. Commons-Beanutils to 1.11.0, which resolves CVE-2025-48734. WildFly Channel Maven Plugin to 1.0.25. WildFly HTTP Client to 2.1.1.Final. Narayana LRA to 1.0.1.Final. Arquillian BOM to 1.9.5.Final. Arquillian Testcontainers to 1.0.0.Alpha4. Caffeine to 3.2.1. Apache Kafka to 3.9.1. SmallRye OpenAPI to 4.0.11. Nimbus Jose JWT to 10.3. Artemis WildFly Integration to 2.0.4.Final. MVC Krazo integration to 2.0.0.Final. OWASP Dependency Check Plugin to 12.1.3. For a complete list of bug fixes, tasks, sub-tasks, and other changes, please refer to the full release notes. We encourage the community to test this beta release and provide feedback to help us stabilize WildFly 37. ### [WildFly 36.0.1 is released!](/news/2025/05/15/WildFly-36-0-1-is-released/) WildFly 36.0.1.Final is now available for download. I am pleased to announce that the WildFly 36.0.1.Final release is now available for download. The following issues were resolved in 36.0.1: Bugs [WFLY-19970] - Jakarta MVC from Wildfly 34 built with Galleon on stability level preview cannot find custom template engines in an EAR [WFLY-20564] - Deploying postgresql-42.7.5.jar causes NPE when upgrading from wildfly 35→36 [WFLY-20617] - Deployment fails due to NullPointerException in ExpirationMetaData.getLastAccessTime() Component Upgrades [WFLY-20584] - Upgrade SmallRye Fault Tolerance from 6.9.0 to 6.9.1 [WFLY-20596] - Upgrade Velocity Engine to 2.4.1 [WFLY-20604] - Upgrade wildfly-clustering to 6.0.4.Final [WFLY-20608] - [36.0.1.Final] Upgrade HAL to 3.7.11.Final [WFLY-20619] - Upgrade WildFly Core to 28.0.1.Final Tasks [WFLY-20606] - Correct the release version to 36.0.1.Final-SNAPSHOT in various pom.xml The following issues were also resolved in the version of WildFly Core contained within this release: Bugs [WFCORE-7210] - Unescaped characters throw a NPE although allowed in settings Component Upgrades [WFCORE-7218] - Upgrade WildFly Elytron to 2.6.3.Final [WFCORE-7219] - Upgrade Elytron Web to 4.1.2.Final [WFCORE-7248] - Upgrade WildFly Elytron to 2.6.4.Final Enjoy! ### [Exposing WASM binaries as MCP tools](/news/2025/05/05/Exposing-WASM-binaries-as-MCP-tools/) WebAssembly (WASM) has emerged as a powerful technology for running high-performance code in various environments. In this article, we’ll explore how to expose WASM binaries as Model Context Protocol (MCP) tools in WildFly. With WildFly AI Feature-Pack 0.5.0 we have introduced a new subsystem to expose WASM WebAssembly System Interface (WASI) binaries via CDI, and since we also support MCP tools declaration via CDI, just exposing those binaries as MCP tools was a small step forward. What are MCP tools? The Model Context Protocol (MCP) defines a standard way for systems (like an IDE or a CLI) to interact with MCP servers. These servers expose tools (functions that can be executed remotely with specific inputs) and resources (data sources that can be accessed). This allows the client system to leverage the server’s capabilities and data for various tasks. Benefits of WASM-based MCP tools Near-native performance for compute-intensive operations Ability to reuse existing tools written in languages like C, C++, or Rust Secure execution within WildFly’s sandbox environment Cross-platform compatibility without recompilation Defining WASM Binaries for MCP Tool Integration Before a WASM module can be exposed as an MCP tool, it needs to be defined within WildFly’s WASM subsystem. This subsystem acts as a registry for your WASM modules. It is based on the chicory-sdk, an experimental Java SDK using the JVM-native Chicory runtime. Configuration Methods You can configure these binaries using either the WildFly CLI or by directly editing the XML configuration (standalone.xml). Using CLI Add a WASM module definition via the CLI like this: /subsystem=wasm/wasm-tool=my-wasm-tool:add(path="/path/to/your/binary.wasm") my-wasm-tool: A unique name for this binary definition. path: The location of the .wasm file. This path can be absolute (as in the example above) or relative to the additional relative-to attribute. Using XML Configuration Alternatively, add the definition within the <subsystem xmlns="urn:wildfly:wasm:1.0"> element in your configuration file: <subsystem xmlns="urn:jboss:domain:wasm:1.0"> <wasm-tool name="my-wasm-tool" path="path/relative/to/module/root/binary.wasm"/> <!-- Other binary definitions --> </subsystem> Next Step: CDI Integration Once defined in the WASM subsystem, these binaries can be injected using CDI. The first way you can use them is to get them by name as an org.wildfly.wasm.api.WasmInvoker using the @WasmTool annotation. This very basic interface wraps the call to the binary, passing the parameters as a byte array and getting the result as a byte array. @Inject @WasmTool(value = "my-wasm-tool") org.wildfly.wasm.api.WasmInvoker greet; public String greet(String person) { // "greet" is the name of the exported method of the WASM module byte[] output = greet.call("greet", person.getBytes(StandardCharsets.UTF_8)); return new String(output, StandardCharsets.UTF_8); } A second way is to use the @WasmToolService over an interface to create a dynamic proxy wrapping the call to the WASM module and providing a way to serialize and deserialize your arguments to the byte array required by the invoker. @WasmToolService(wasmToolConfigurationName = "pizza", wasmMethodName = "retrievePizzeriaAddresses", argumentSerializer = CityJsonSerializer.class) public interface Pizza { public String pizzas(String city); } Here you can see that we are calling the exported method retrievePizzeriaAddresses on the WASM module registered with the name pizza in WildFly configuration and the `CityJsonSerializer`class is in charge with converting the java.lang.String city to a JSON object to be consumed by the WASM module. Once defined in the WASM subsystem, these binaries can be injected using CDI and subsequently exposed as MCP tools, which we’ll cover in the next step. Next Step: MCP Integration Well this is the simplest part as we 'just' have to use our MCP annotations and WildFly Glow will provision the MCP server for us. Note also that WildFly MCP server support is SSE only (no stdio). Our WASM service now becomes: import org.wildfly.mcp.api.Tool; import org.wildfly.mcp.api.ToolArg; import org.wildfly.wasm.api.WasmToolService; @WasmToolService(wasmToolConfigurationName = "pizza", wasmMethodName = "retrievePizzeriaAddresses", argumentSerializer = CityJsonSerializer.class) public interface Pizza { @Tool(name="pizzaRetriever", description = "Get the address for the best hawaian pizzas") public String pizzas(@ToolArg(description = "The city where we are looking for Hawaian pizza") String city); } And now there is a new pizzaRetriever MCP tool available :) The source for this example is here. Deploying Wasm binaries in WildFly and exposing them as MCP tools ### [WildFly joins Commonhaus](/news/2025/04/30/WildFly-joins-Commonhaus/) I’m pleased to announce that WildFly has joined the Commonhaus Foundation as a member project. WildFly is a well-established project that wishes to continue to grow and develop. We believe being associated with Commonhaus can help us: Grow our contributor and user communities by associating the project with a vendor-neutral foundation. Update our governance model to incorporate current open source best practices. Continue to improve our openness when it comes to roadmaps, designs and solution discussions. We want to continue to evolve and improve, but we also have a lot of experience running a successful and very complex project. We believe Commonhaus’ guiding principles around honoring project and community identity and offering guidance instead of mandates, with its “community-first” governance model, make it an excellent fit for WildFly. For more on the thinking that led to us joining Commonhaus, you can have a look at the February news post about moving to a foundation, watch a recording of the WildFly Mini Conference session on this last month, or have a look at the session slides. Moving a project to a foundation primarily consists of transferring intellectual property associated with the project (logos, trademarks, domain names, etc., currently owned by WildFly’s sponsor, Red Hat) to the foundation, and adapting the project’s governance and operations to the requirements of the foundation. We’ve begun the process of doing that — what Commonhaus calls 'onboarding'. I expect this will take some time to complete. If you’re interested in following this process, keep an eye on the wildfly-dev mail list, where I’m sure there will be many threads about this move. I don’t expect most of the details of onboarding to be particularly impactful to end users of WildFly, or even to most WildFly developers. But definitely something that will be impactful will be updating WildFly’s formal governance model from one based on sponsorship by Red Hat to one appropriate for a project in a vendor-neutral foundation. I expect over the coming weeks we’ll have a number of discussions on the wildfly-dev list about what an updated governance model should look like. I’m really looking forward to those discussions and I encourage everyone in the WildFly community to participate. Community Feedback We’d love to hear your thoughts on this. Let us know what you’re thinking either on the developer mail list, in the WildFly google group or in Zulip. Best regards, Brian ### [Introduction to a GUI wizard to configure TLS in WildFly](/news/2025/04/17/Introduction-to-a-GUI-wizard-to-configure-TLS-in-WildFly/) ### [WildFly 36 is released!](/news/2025/04/10/WildFly-36-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 36.0.0.Final releases are available for download at https://wildfly.org/downloads, The Galleon feature-packs for WildFly 36 are available in Maven. New and Notable This quarter we had some exciting innovation outside the main appserver itself: You can now run a WildFly application from JBang. To learn more about this feature, please read the JBang integration section in the WildGly Glow documentation. This feature is provided at the experimental stability level. The WildFly AI feature-pack evolved rapidly during the quarter. Learn more by checking out Emmanuel Hugonnet’s talks at last month’s WildFly Mini Conference or at JDConf. This feature-pack is currently incubating and will likely continue to change rapidly. Of course, there’s new stuff in the main appserver as well: The micrometer extension has been modified to add support for the Prometheus Registry, allowing for pull-based scraping of metrics information for deployments, if that is preferred. This much-requested feature is provided at the community stability level. The JBoss EJB Client library and the ejb3 subsystem now support use of the remote+tls protocol for remote EJB invocations. When configuring WildFly to act as a reverse proxy, the undertow subsystem now supports configuring the reverse proxy handler to reuse and append to any X-Forwarded HTTP headers and to rewrite the Host header. This feature is provided at the community stability level. Previously this had been supported at preview stability. The promotion to community stability means this feature is now available out of the box in standard WildFly. The undertow subsystem now allows configuring the AJP listener to accept custom AJP request headers. This feature is provided at the community stability level. Previously this had been supported at preview stability. The promotion to community stability means this feature is now available out of the box in standard WildFly. Within the WildFly Preview distribution we also upgraded to a beta of Hibernate ORM 7 and an alpha of Hibernate Search 8. Finally, we did some long overdue improvements to the main landing page for our docs. We plan to continue improving there, particularly by giving greater emphasis to the growing ecosystem of Galleon feature-packs that WildFly provides. Your feedback is very much wanted! Supported Specifications Jakarta EE Standard WildFly 36 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly is EE 10 Platform, Web Profile and Core Profile compatible when running on Java SE 17 and Java SE 21. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence Jakarta EE 10 Full Platform SE 17 SE 21 Jakarta EE 10 Web Profile SE 17 SE 21 Jakarta EE 10 Core Profile SE 17 SE 21 MicroProfile Standard WildFly 36 supports MicroProfile Platform 7.0, along with several other MicroProfile specifications that are not part of MicroProfile Platform. The full listing is available in the Getting Started Guide. Compatibility evidence for the specifications that are part of MicroProfile 7.0 can be found in the WildFly Certifications repository on GitHub. WildFly Preview and EE 11 Since the WildFly 32 release, we are using WildFly Preview to provide a look at what we’re doing for Jakarta EE 11 support. The EE 11 Platform and Web Profile specifications won’t go GA before later this year. But there are milestone, Release Candidate and Final releases of many EE 11 specs and implementations available, so we are providing those in WildFly Preview. This means for a number of EE APIs, WildFly Preview no longer provides an EE 10 compatible implementation. However, for a number of specifications that are planning changes for EE 11 we are still offering the EE 10 variant. In future releases we’ll shift those to the EE 11 variants. The EE 11 Core Profile specification went GA last November and WildFly Preview 36 supports that profile. Full details on the EE specification versions provided by WildFly Preview can be found in the WildFly 36 documentation. Java SE Support Our recommendation is that you run WildFly 36 on Java SE 21, as that is the latest LTS JDK release where we have completed the full set of testing we like to do before recommending a particular SE version. WildFly 36 also is heavily tested and runs well on Java 17. Our recommendation of SE 21 over SE 17 is solely because as a general principle we recommend being on later LTS releases, not because of any problems with WildFly on SE 17. While we recommend using an LTS JDK release, I do believe WildFly runs well on SE 24. By runs well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. We’ve also had good results with tests on Linux of an EA release of SE 25 (Oracle 25-ea+10-1084). Please note that WildFly runs in classpath mode. New and Noteworthy Contributors WildFly gets great contributions from so many people. I’m going to start using this section of the release announcement to thank a few of them. Andrew Golding reported an issue with how WildFly Glow dealt with Maven proxies and provided the fix. Thank you, Andrew! Jason Lee slew the dragon of Prometheus support with Micrometer. Thank you, Jason! Jeff Mesnil showed great innovative initiative by driving the new ability to run a source-only WildFly application using JBang. Thank you, Jeff! Same for Emmanuel Hugonnet, who is on fire with new improvements to the incubating WildFly AI feature-pack. Go Emmanuel! Release Notes The full WildFly 36 release notes are available in GitHub. Issues fixed in the underlying WildFly Core 28.0.0 release are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. I hope you enjoy WildFly 36 as much as we’ve enjoyed bringing it to you! Best regards, Brian ### [WildFly 36 Beta is released!](/news/2025/03/27/WildFly-36-Beta-is-released/) I’m pleased to announce that the new WildFly 36.0.0.Beta1 release is available for download at https://wildfly.org/downloads. As can be seen from the Release Notes a lot of issues were resolved in this release but I would also like to call out some of the following highlights: [WFLY-18582] — Add a prometheus endpoint to the micrometer extension [WFCORE-5718] — Support remote+tls with EJBClient and remote-outbound-connection [WFLY-20476] — Promote ajp-listener AJP_ALLOWED_REQUEST_ATTRIBUTES_PATTERN to community stability [WFLY-20477] — Promote undertow subsystem’s reuse-x-forwarded and rewrite-host header configurability to community stability Within the WildFly Preview distribution we also upgraded to a beta of Hibernate ORM 7 and an alpha of Hibernate Search 8. We’ve also enhanced WildFly Glow, so it is now possible to run a source-only WildFly application using JBang! Please try out this release and let us know how you get on. ### [Vlog: WildFly AI - monitor and troubleshoot a WildFly server with the WildFly chatbot.](/news/2025/03/21/Vlog-WildFly-AI-monitor-and-troubleshoot-a-WildFly-server-with-the-WildFly-chatbot/) ### [Save the Date: WildFly Mini Conference on March 25th, 2025](/news/2025/03/19/Save-the-Date-WildFly-Mini-Conference-on-March-25th-2025/) Hello, WildFly Community! We are excited to announce that the WildFly Mini Conference is scheduled for March 25th, 2025! Building on the success of our previous events, we’re looking forward to another day of insightful discussions, community engagement, and deep dives into the latest in enterprise Java and WildFly development. This year’s conference will focus on key topics shaping the future of WildFly and enterprise Java, including: Quick Prototyping with WildFly – Learn how to efficiently build and test applications using WildFly. WildFly Day One Operations with Ansible Automation – Discover best practices for deploying and managing WildFly with Ansible. Everything about Jakarta EE TCKs in twenty minutes – A concise session covering the essentials of Jakarta EE compatibility testing. WildFly in a Vendor-Neutral Foundation – Exploring the ecosystem and collaboration opportunities for WildFly. WildFly AI Feature-Pack: Deploying an MCP Server – Learn how the WildFly AI Feature-Pack enables intelligent middleware capabilities and enhances application deployments with AI-driven optimizations. 📅 Date: Tuesday, March 25, 2025 ⏰ Time: 14:00 - 18:00 UTC 🔗 Live stream: YouTube Live Make sure to click "Notify me" on YouTube to receive reminders before the event starts. This conference is a great opportunity for Java developers, middleware engineers, and open-source enthusiasts to explore the future of WildFly and enterprise Java. For more details, checkout our conference page. We look forward to seeing you online for another great WildFly Mini Conference! ### [Testing WildFly applications on Kubernetes with Arquillian Cube](/news/2025/03/06/Testing-WildFly-applications-on-Kubernetes-with-Arquillian-Cube/) Recently we blogged about testing WildFly on Docker effectively and easily, thanks to Arquillian Cube, now it’s time to make it Kubernetes! In the Testing WildFly applications on Docker with Arquillian Cube article we saw how an Arquillian Cube test can be implemented to automate the build and execution of a Docker image that contains a WildFly deployment, and to run tests against it. This time we’ll see how a very similar process can be used to set up an automated integration test for a WildFly application that should instead be run on Kubernetes. Our goal is to provide an automated solution to replace the final part of the WildFly Java Microservice - PART 2: Kubernetes guide. Use case The WildFly Java Microservice - PART 2: Kubernetes guide uses an existing Docker image, pushes it to Quay.io, and then shows how to create Kubernetes resources, namely a Deployment that manages the WildFly application workload, and a NodePort type Service that exposes it externally. That’s cool!…​ but still, it is based on manual steps. In order to automate this, we’ll modify the example application that we showcased in our previous article, to add a JUnit test, powered by Arquillian Cube, that will automate the Kubernetes resources creation, starting from existing YAML definitions, and use APIs and annotations at the test class level. Step by step changes As said, we will to start from the Testing WildFly applications on Docker with Arquillian Cube article, so make sure to go through it, and maybe create a separate Git repo, or branch if you want to keep working on both examples, then…​ Kubernetes resources definition Let’s copy/paste the YAML definition which is used in WildFly Java Microservice - PART 2: Kubernetes into a kubernetes.yaml file, that we’ll place in our project test/resources folder. We’ll modify the Deployment name, but it is basically the same as the one in the guide: apiVersion: apps/v1 kind: Deployment metadata: name: my-jaxrs-app-deployment labels: app: my-jaxrs-app spec: replicas: 1 selector: matchLabels: app: my-jaxrs-app template: metadata: labels: app: my-jaxrs-app spec: containers: - name: my-jaxrs-app image: quay.io/tborgato/my-jaxrs-app ports: - containerPort: 8080 - containerPort: 9990 livenessProbe: httpGet: path: /health/live port: 9990 readinessProbe: httpGet: path: /health/ready port: 9990 startupProbe: httpGet: path: /health/started port: 9990 Then - similarly to what is manually done in the WildFly miniseries guide - let’s add a Kubernetes Service resource definition, by appending it to the same file. Here as well, we’ll use a meaningful name: apiVersion: v1 kind: Service metadata: name: my-jaxrs-app-service spec: ports: - port: 80 protocol: TCP targetPort: 8080 selector: app: my-jaxrs-app The whole kubernetes.yaml file will now look like this: apiVersion: v1 kind: Service metadata: name: my-jaxrs-app-service spec: ports: - port: 80 protocol: TCP targetPort: 8080 selector: app: my-jaxrs-app --- apiVersion: apps/v1 kind: Deployment metadata: name: my-jaxrs-app-deployment labels: app: my-jaxrs-app spec: replicas: 1 selector: matchLabels: app: my-jaxrs-app template: metadata: labels: app: my-jaxrs-app spec: containers: - name: my-jaxrs-app image: quay.io/tborgato/my-jaxrs-app ports: - containerPort: 8080 - containerPort: 9990 livenessProbe: httpGet: path: /health/live port: 9990 readinessProbe: httpGet: path: /health/ready port: 9990 startupProbe: httpGet: path: /health/started port: 9990 and, rather than applying it manually to our Minikube instance via a kubectl command, we’ll let Arquillian Cube do the job! Specifically, Arquillian Cube provides several ways to automate your Kubernetes tests - including a jkube_kubernetes_openshift_maven_plugin_integration_with_cube">JKube plugin integration - but we’ll use the most common approach in this example, i.e. using a _kubernetes.yaml definition in the classpath. If such a definition exists, then Arquillian Cube will apply it to the cluster, and it will provide us with APIs and annotations at the class level that we’ll use to wire the test logic up, as we’ll see later on. Update the example project POM A few changes, provided we started from the previous article about Testing WildFly applications on Docker with Arquillian Cube. The first thing we need to do is to add a couple more properties for two new dependencies that we’ll need to add; details are explained later: <fabric8.kubernetes-client.version>6.9.2</fabric8.kubernetes-client.version> <undertow-core.version>1.3.33.Final</undertow-core.version> <resteasy-client.version>6.2.11.Final</resteasy-client.version> Then, in order to make our project POM more readable, we should remove the code that we commented out in the above-mentioned article, so let’s start by removing the following block in the <dependencyManagment> section, i.e.: <!-- Arquillian Cube still using JUnit 4 by default --> <!-- <!–Define the JUnit5 bom. WildFly BOM still contains JUnit4, so we have to declare a version here –>--> <!-- <dependency>--> <!-- <groupId>org.junit</groupId>--> <!-- <artifactId>junit-bom</artifactId>--> <!-- <version>${version.junit5}</version>--> <!-- <type>pom</type>--> <!-- <scope>import</scope>--> <!-- </dependency>--> then, let’s remove the commented out fragments in the <build>/<dependencies> section: <!-- Test scope dependencies --> <!-- Arquillian Cube still using JUnit 4 by default --> <!-- <dependency>--> <!-- <groupId>org.junit.jupiter</groupId>--> <!-- <artifactId>junit-jupiter</artifactId>--> <!-- <scope>test</scope>--> <!-- </dependency>--> <!-- Not needed anymore because the test uses a standalone Docker container --> <!-- <dependency>--> <!-- <groupId>org.wildfly.arquillian</groupId>--> <!-- <artifactId>wildfly-arquillian-container-managed</artifactId>--> <!-- <scope>test</scope>--> <!-- </dependency>--> Done with removals. Now, onto the dependencyManagment section, which also contains a definition of the wildfly-ee BOM, used in our previous example. We can comment that out now: <!-- The wildfly-ee BOM isn't needed, since we will not build any WildFly application, but rather use an existing image on Quay.io --> <!--<!– JBoss distributes a complete set of Jakarta EE APIs including a Bill of Materials (BOM). A BOM specifies the versions of a "stack" (or a collection) of artifacts. We use this here so that we always get the correct versions of artifacts (you can read this as the WildFly stack of the Jakarta EE APIs, with some extras tools for your project, such as Arquillian for testing) –> <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>wildfly-ee</artifactId> <version>${version.wildfly.bom}</version> <type>pom</type> <scope>import</scope> </dependency>--> Let’s move to the dependencies section, where we’ll first comment the Jakarta EE dependencies out: <!-- No Jakarta EE application is built, so we don't need the dependencies that WildFly is meant to provide --> <!--<!– Import the CDI API, we use provided scope as the API is included in WildFly –> <dependency> <groupId>jakarta.enterprise</groupId> <artifactId>jakarta.enterprise.cdi-api</artifactId> <scope>provided</scope> </dependency> <!– Import the JAX-RS API, we use provided scope as the API is included in WildFly –> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <scope>provided</scope> </dependency>--> The next one is quite important from the Arquillian perspective: we’ll replace the dependency from the Arquillian Cube Docker extension with the Arquillian Cube Kubernetes extension, so we’ll keep the following commented out block in the example sources for clarity: <!-- Here we'll depend on arquillian-cube-kubernetes, in order to test on Kubernetes, so let's remove arquillian-cube-docker... --> <!--<dependency> <groupId>org.arquillian.cube</groupId> <artifactId>arquillian-cube-docker</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-container</artifactId> <scope>test</scope> </dependency>--> <!-- ... and depend on arquillian-cube-kubernetes instead, in order to test on Kubernetes. --> <dependency> <groupId>org.arquillian.cube</groupId> <artifactId>arquillian-cube-kubernetes</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.arquillian.cube</groupId> <artifactId>arquillian-cube-kubernetes-starter</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.fabric8</groupId> <artifactId>kubernetes-client</artifactId> <version>${fabric8.kubernetes-client.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>io.undertow</groupId> <artifactId>undertow-core</artifactId> <version>${undertow-core.version}</version> <scope>test</scope> </dependency> As you can see we added the arquillian-cube-kubernetes-starter and kubernetes-client dependencies, too. The former is needed to let Arquillian Cube automatically start the Kubernetes "container" (broader meaning here). The latter provides us with all the Kubernetes APIs, which we’ll use in the test class, as we’ll see below. We had to lock the undertow-core dependency version too, since we need one that is compatible with Arquillian Cube 2.0. Let’s remove the following JBoss Logging dependency, as it will not be used: <!--See https://issues.redhat.com/browse/WFLY-19779 and https://github.com/wildfly/quickstart/pull/957/ httpclient needs commons-logging yet the server uses this instead, to be fully compatible on apps we need to add this dependency whenever commons-logging is needed, but on testing clients like this we could use commons-logging instead <dependency> <groupId>org.jboss.logging</groupId> <artifactId>commons-logging-jboss-logging</artifactId> <scope>test</scope> </dependency> --> One last thing in the test dependencies section, let’s give a version to the RESTEasy client dependency, since we removed the wildfly—​ee BOM from the dependencyManagment section: <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-client</artifactId> <!-- Add a version to the resteasy-client dependency, as the WildFly EE BOM has been removed from the dependencyManagement section --> <version>${resteasy-client.version}</version> <scope>test</scope> </dependency> Now, onto the <build>/<plugins> section. First off we don’t need for the maven-clean-plugin to clean up any Docker files; in fact we’ll remove those from our project sources later on, since this test will not build nor run any Docker images. Let’s comment the section as follows: <!-- No Docker resources are used in the test, so we don't need to clean up anything else --> <!--<!– Let's remove ./docker-build/server, too –> <configuration> <filesets> <fileset> <directory>${project.basedir}/docker-build/server</directory> </fileset> </filesets> </configuration>--> Then we should remove the WildFly Maven plugin definition, too, as this a Kubernetes test, which will rely on an image that is deployed to Quay.io already, as per the WildFly Java Microservice - PART 2: Kubernetes original example. Let’s comment the whole plugin configuration out: <!-- Not needed here, the test relies on an existing docker image which is deployed to Quay.io --> <!--<!– The WildFly plugin deploys your war to a local JBoss AS container –> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <!– We need for the server to be provisioned in ./docker-build/server, as required by the Dockerfile –> <provisioningDir>${project.basedir}/docker-build/server</provisioningDir> <overwriteProvisionedServer>true</overwriteProvisionedServer> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.wildfly.bom}</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:7.0.2.Final</location> </feature-pack> </feature-packs> <layers> <!– layers may be used to customize the server to provision–> <layer>cloud-server</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin>--> Finally, let’s comment the following section properties, too, since they’re no longer relevant nor used: <!-- Wildfly dependencies are not used directly, as the test is using an existing WildFly application image --> <!--<!– JBoss dependency versions –> <version.wildfly.maven.plugin>5.1.1.Final</version.wildfly.maven.plugin> <version.wildfly.bom>35.0.0.Final</version.wildfly.bom>--> and similarly with the JUnit 5 related property, since we’re using JUnit 4: <!-- We don't need JUnit5, and this property is not used --> <!--<!–Use JUnit 5 here - the WildFly bom still brings 4.x –> <version.junit5>5.10.1</version.junit5>--> And that’s it, we’re done with the POM, and feel free to check your version against the example sources on GitHub, where you can find a "minified" version, too. Let’s get to the arquillian.xml file now, and see how should be modified. Update arquillian.xml configuration A simple update will do, start by removing or commenting the docker extension part out: easy, we don’t need a wildfly container anymore, so let’s remove it, and add a kubernetes extension declaration, which we’ll keep empty. <!--<extension qualifier="docker"> <property name="dockerContainersFile">./docker-compose.yml</property> </extension>--> <extension qualifier="kubernetes"> </extension> The last part is about the test class itself, let’s dive in…​ Remove the application sources Again, we’re not building any application here. We rely on a Docker image on Quay that contains the application already; therefore we don’t need the application sources, which can be safely removed: $ rm -rf src/main/java/org $ rm -rf src/main/webapp Create a test class for testing on Kubernetes We must actually delete the existing Docker test, first: $ rm src/test/java/org/wildfly/examples/GettingStartedDockerIT.java and - as anticipated previously, we’ll now remove the Docker related resources, too: $ rm -rf docker-build $ rm docker-compose.yml There we go, now it’s time to create a new GettingStartedKubernetesIT.java class, with the following contents: package org.wildfly.examples; import io.fabric8.kubernetes.api.model.Service; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.core.Response; import org.arquillian.cube.kubernetes.annotations.Named; import org.arquillian.cube.kubernetes.annotations.PortForward; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import java.net.URISyntaxException; import java.net.URL; import static junit.framework.TestCase.assertFalse; import static org.junit.Assert.assertNotNull; /** * Run integration tests on Kubernetes with Arquillian Cube! */ @RunWith(Arquillian.class) public class GettingStartedKubernetesIT { @Named("my-jaxrs-app-service") @ArquillianResource private Service myJaxrsAppService; @Named("my-jaxrs-app-service") @PortForward @ArquillianResource private URL url; @Test public void shouldFindServiceInstance() { assertNotNull(myJaxrsAppService); assertNotNull(myJaxrsAppService.getSpec()); assertNotNull(myJaxrsAppService.getSpec().getPorts()); assertFalse(myJaxrsAppService.getSpec().getPorts().isEmpty()); } @Test public void shouldShowHelloWorld() throws URISyntaxException { assertNotNull(url); try (Client client = ClientBuilder.newClient()) { final String name = "World"; Response response = client .target(url.toURI()) .path("/hello/" + name) .request() .get(); Assert.assertEquals(200, response.getStatus()); Assert.assertEquals(String.format("Hello '%s'.", name), response.readEntity(String.class)); } } } As you can see, the test didn’t change much from the one in the Testing WildFly applications on Docker with Arquillian Cube example: we verify that the service - which is implemented by a Kubernetes workload - returns HTTP 200 and the expected response body when it is called via its URL. And that is where Arquillian Cube comes in handy because, thanks to it, we could inject such a URL in our test class url field just by using an annotation. Similarly, we have injected an io.fabric8.kubernetes.api.model.Service instance which represents the Kubernetes service resource that we Arquillian Cube creates based on the kubernetes.yaml definition. Run the test That’s it, we can run our Kubernetes integration test. Arquillian Cube will use the information stored in the ~/.kube/config file to connect to a Kubernetes cluster, or let you provide parameters. For this example, starting a minikube instance will be enough: minikube start and then issue the following command: mvn clean install and we’ll see how Arquillian Cube will gather the kubernetes extension configuration, then summarize the container definition, trace the resources creation on the cluster, and eventually run the test: [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running org.wildfly.examples.GettingStartedKubernetesIT ... CubeKubernetesConfiguration: namespace = itest-4d12b880 master.url = https://192.168.39.213:8443/ namespace.lazy.enabled = true namespace.cleanup.enabled = true namespace.cleanup.timeout = 0 namespace.cleanup.confirm.enabled = false namespace.destroy.enabled = true namespace.destroy.confirm.enabled = false namespace.destroy.timeout = 0 wait.enabled = true wait.timeout = 480000 wait.poll.interval = 5000 ansi.logger.enabled = true env.init.enabled = true logs.copy = false cube.api.version = v1 cube.trust.certs = true cube.fmp.build = false cube.fmp.build.disable.for.mvn = false cube.fmp.pom.path = pom.xml cube.fmp.debug.output = false cube.fmp.logs = true Initializing Session:4d12b880 Using Kubernetes at: https://192.168.39.213:8443/ Creating namespace: itest-4d12b880... To switch to the new namespace: kubectl config set-context `kubectl config current-context` --namespace=itest-4d12b880 Applying kubernetes configuration from: file:/home/fburzigo/Projects/git/fabiobrz/wfly-mini-k8s-cube/getting-started/target/test-classes/kubernetes.yaml ReplicaSet: [my-jaxrs-app-deployment-56bbc54bf9] Pod: [my-jaxrs-app-deployment-56bbc54bf9-zsc2m] Status: [Running] Service: [my-jaxrs-app-service] IP: [10.111.189.164] Ports: [ 80 ] Jan 31, 2025 4:49:45 PM org.arquillian.cube.kubernetes.impl.resources.KubernetesResourcesApplier applyKubernetesResourcesAtClassScope INFO: Creating environment for org.wildfly.examples.GettingStartedKubernetesIT Jan 31, 2025 4:49:45 PM org.arquillian.cube.kubernetes.impl.resources.KubernetesResourcesApplier applyKubernetesResourcesAtMethodScope INFO: Creating environment for org.wildfly.examples.GettingStartedKubernetesIT method shouldShowHelloWorld Jan 31, 2025 4:49:45 PM org.xnio.Xnio <clinit> INFO: XNIO version 3.8.16.Final Jan 31, 2025 4:49:45 PM org.xnio.nio.NioXnio <clinit> INFO: XNIO NIO Implementation Version 3.8.16.Final Jan 31, 2025 4:49:46 PM org.jboss.threads.Version <clinit> INFO: JBoss Threads version 2.4.0.Final Jan 31, 2025 4:49:46 PM org.arquillian.cube.kubernetes.impl.resources.KubernetesResourcesApplier removeKubernetesResourcesAtMethodScope INFO: Deleting environment for org.wildfly.examples.GettingStartedKubernetesIT method shouldShowHelloWorld Jan 31, 2025 4:49:46 PM org.arquillian.cube.kubernetes.impl.resources.KubernetesResourcesApplier applyKubernetesResourcesAtMethodScope INFO: Creating environment for org.wildfly.examples.GettingStartedKubernetesIT method shouldFindServiceInstance Jan 31, 2025 4:49:46 PM org.arquillian.cube.kubernetes.impl.resources.KubernetesResourcesApplier removeKubernetesResourcesAtMethodScope INFO: Deleting environment for org.wildfly.examples.GettingStartedKubernetesIT method shouldFindServiceInstance Jan 31, 2025 4:49:46 PM org.arquillian.cube.kubernetes.impl.resources.KubernetesResourcesApplier removeKubernetesResourcesAtClassScope INFO: Deleting environment for org.wildfly.examples.GettingStartedKubernetesIT [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 15.05 s -- in org.wildfly.examples.GettingStartedKubernetesIT Deleting namespace: itest-4d12b880... Namespace: itest-4d12b880, successfully deleted Destroying Session:4d12b880 [INFO] [INFO] Results: [INFO] [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 ... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 18.281 s [INFO] Finished at: 2025-01-31T16:49:47+01:00 [INFO] ------------------------------------------------------------------------ In conclusion Testing a WildFly application directly on Kubernetes will make the test more effective, and will allow prototyping and make debugging easier. Arquillian Cube provides an easy and effective way to test on Kubernetes, with almost no configuration and instrumentation changes with respect to existing Arquillian based tests. The code for the example application which is described in this article is here: https://github.com/fabiobrz/wildfly-mini-series-k8s-cube Fabio Burzigotti ### [WildFly and Red Hat's middleware strategy](/news/2025/03/05/WildFly-and-Red-Hat-s-middleware-strategy/) Hi, Red Hat announced significant changes to its middleware strategy last month, and I wanted to give the WildFly community some context about those changes and how they affect WildFly. The Red Hat announcement can be found on the Red Hat blog: Evolving our middleware strategy Some key points there are: Red Hat’s Middleware and Integration Engineering and Products teams are moving to IBM in May 2025. Red Hat will continue to sell and support its Middleware and Integration offerings as they do today; this will not be impacted. All transitioning Red Hat technology will remain open source and continue to follow an upstream-first development model. Red Hat has sponsored the WildFly project (fka JBoss AS) since 2006, when it bought JBoss, Inc. Now, Red Hat’s participation in and support for WildFly is being transferred to IBM. WildFly has a vibrant, healthy community with different kinds of contributions from people from various companies all over the world. Still, it’s undoubtedly the case that the bulk of our code contributions come from Red Hat employees working on the middleware product teams that are moving to IBM. However, I don’t expect this change to have a significant impact on the WildFly project, beyond the inevitable temporary disruption as the people who are moving focus some of their energy on the move. WildFly is the upstream project for Red Hat’s JBoss Enterprise Application Platform (EAP) product. EAP will continue to be sold and supported through Red Hat, and will continue to be developed following an upstream-first development model. That model means that features and fixes for EAP will land first in WildFly’s main branch or in the main branches of the components integrated into WildFly. IBM and Red Hat leaders have clearly stated that current and future contributions to WildFly are a key component of their middleware strategy. So, we’ll continue to work on behalf of the WildFly community, striving to improve WildFly. Some things we’ll be doing: We’ll have another WildFly Mini Conference soon. Watch this space for more details! We’re hard at work on WildFly 36, with its final release expected around April 10. After that, we move on to WildFly 37, which is expected in July. We intend to continue producing feature releases quarterly, followed by a bug fix release about a month later. Work continues on EE 11 support in WildFly Preview and eventually in standard WildFly. We’ll continue to innovate outside of the Jakarta and MicroProfile areas, including AI and WildFly Glow. We’ll continue to keep up with advancements in Java SE, with an aspiration of having each WildFly feature release run well on the latest SE release available when it comes out, and being able to recommend the latest LTS SE release as the preferred option as soon as possible after it comes out. Last month, I posted about transitioning the WildFly project to a vendor-neutral software foundation. I intend to continue with this process. Note that our interest in moving to an open source foundation was not triggered by Red Hat’s strategy change. We’d been thinking about a move to a foundation since well before we learned about the move to IBM. Personally, I’ll be sorry to leave Red Hat, which has been a fantastic place to work. Back in 2006, I was sorry to leave JBoss, Inc for the much bigger Red Hat, too, but it worked out very well. I think combining forces with Java teams at IBM makes a lot of sense and will be good for the middleware projects and products. There’s a lot of growth and innovation potential in the middleware technologies we offer and I’m looking forward to being part of a larger team excited about and focused on that potential. Best regards, Brian Stansberry WildFly Project Lead ### [Vlog: Admin your WildFly with LLM and MCP](/news/2025/02/13/Vlog-Admin-your-WildFly-with-LLM-and-MCP/) ### [An introduction to use the domain mode of the current release of WildFly](/news/2025/02/12/An-introduction-to-use-the-domain-mode-of-the-current-release-of-WildFly/) I recently tried to play with the domain mode in the current release of WildFly, version 35, while writing this blog post. According to the blog post written by Brian Stansberry[1], there are some breaking backward-compatibility changes in the security configuration part related to Elytron since WildFly 25: A key focus in WildFly 25 has been completing our migration away from the legacy security layer that dates back to JBoss AS and onto the WildFly Elytron based security layer introduced in WildFly 11. SE 17 does not provide packages that legacy security heavily relies upon, so the time has come to complete the transition off of legacy security. Nevertheless, the resources I could find are mostly outdated or don’t contain the step-by-step walkthrough about the minimal configuration to be done for using the domain mode of WildFly. I have written a book before, explaining the domain mode usage of WildFly[2]. There is also a relative document about the domain mode setup[3]. All these materials are outdated on the domain configuration topic, so I’d like to update the knowledge on this topic in this blog post, showing how to configure the domain mode for the most recent version of WildFly server, which is version 35 when I’m writing this blog post. I won’t cover all the detail usages of the domain mode in this blog post, but it will be a good start to follow the instructions in this blog posts for the further studies. Here is my local environment setup to use the domain mode of the WildFly server: As the deployment diagram shows above, I used two machines to run the WildFly server in domain mode. In the above setup, the WildFly server running on Machine A acts as a domain controller, and the WildFly server on Machine B will be connected to Machine A accepting the management from the domain server. The host name of the WildFly server running on Machine A will be configured to primary(this will be defined in the name property in the host.xml), and the host name of the WildFly server running on Machine B will be configured to secondary. Both WildFly servers, running on two different machines, will be configured to run a managed server (defined in the server section of the host.xml) within the same server group, named other-server-group. The Primary Host Controller will define a server-three managed server, while the Secondary Host Controller will define a server-two managed server, both belonging to the other-server-group server group. In this way, the Domain Controller can manage the server group and deploy user applications to the managed servers within it, even though the managed servers are running on different hosts. The first step is to download the current version of WildFly. I will use version 35.0.0.Final version in this blog post which is the newest final version when I’m writing this blog post. Here is the release page: Release 35.0.0.Final · wildfly/wildfly ❯ wget https://github.com/wildfly/wildfly/releases/download/35.0.0.Final/wildfly-35.0.0.Final.zip After the WildFly server zip file is downloaded and extracted into both machines, I can do the configuration work. The extracted WildFly server directory has some of the configuration files out-of-box. Here are the domain configurations provided: ❯ ls wildfly-35.0.0.Final/domain/configuration/ application-roles.properties host-secondary.xml application-users.properties host.xml default-server-logging.properties logging.properties domain.xml mgmt-groups.properties host-primary.xml mgmt-users.properties From the above command output, we can see in the wildfly-35.0.0.Final/domain/configuration/ directory, it contains host-primary.xml and host-secondary.xml files. I will use host-secondary.xml with some modifications in Machine B. However, I’ll use the host.xml instead of host-primary.xml in Machine A, because host-primary.xml has removed all the servers configuration, but we need these servers configuration in our setup. However, I still need to configure a Managed Server in Machine A for demonstration purposes. First, let’s check the host.xml on Machine A to fit the requirement. In host.xml, the host name is set to primary by default: <host xmlns="urn:jboss:domain:community:20.0" name="primary"> This is what I expect, so I don’t need to change it. Instead of directly editing the configuration file, we can use the jboss-cli.sh to connect to the server to edit the configuration file in a more controllable way. To do this, we can first run the jboss-cli.sh: ❯ pwd /Users/weli/works/wildfly-35.0.0.Final/bin weli@192 ~/works/wildfly-35.0.0.Final/bin ❯ ./jboss-cli.sh You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands. [disconnected /] After entering the CLI, run the following command to connect to the host controller: [disconnected /] embed-host-controller [domain@embedded /] The above command will run the domain server in offline-mode(To learn about the detailed usages of the above command, you can read this blog post[4]). And we can now configure the server in the CLI, and all the changes will be persisted into the host controller configuration file(by default it’s host.xml). Now we can use the CLI to read the host name: [domain@embedded /] /:read-attribute(name=local-host-name) { "outcome" => "success", "result" => "primary" } It’s preferred to use CLI command instead of directly operating on the host controller configuration file. In the rest of this blog post, I’ll introduce both the content of the host controller file, and the way to use the CLI command to modify it. Now we can see the host.xml file has two servers settings by default: <server name="server-one" group="main-server-group"/> <server name="server-two" group="main-server-group" auto-start="true"> <jvm name="default"/> <socket-bindings port-offset="150"/> </server> <server name="server-three" group="other-server-group" auto-start="false"> <jvm name="default"/> <socket-bindings port-offset="250"/> </server> I’ll use only server-three in this blog post, so I comment out the server-one and the server-two definitions and only leave the server-three definition here. Here are the commands to disable the server-one and server-two from auto-starting: [domain@embedded /] /host=primary/server-config=server-one:write-attribute(name=auto-start, value=false) { "outcome" => "success", "result" => undefined, "server-groups" => undefined } [domain@embedded /] /host=primary/server-config=server-two:write-attribute(name=auto-start, value=false) { "outcome" => "success", "result" => undefined, "server-groups" => undefined } [domain@embedded /] Alternatively, you can use these commands to remove the server-one and server-two directly: /host=primary/server-config=server-one:remove /host=primary/server-config=server-two:remove In addition, there are several interface properties defined in the host.xml file that we need to override during runtime. Here is the interfaces section in the host.xml: <interfaces> <interface name="management"> <inet-address value="${jboss.bind.address.management:127.0.0.1}"/> </interface> <interface name="public"> <inet-address value="${jboss.bind.address:127.0.0.1}"/> </interface> </interfaces> I checked my IP address of Machine A, and it’s 192.168.0.115, so I started the WildFly Server on Machine A by running the following commands in the bin directory of WildFly: $ pwd /wildfly-35.0.0.Final/bin $ ./domain.sh --host-config=host.xml -Djboss.bind.address.management=192.168.0.115 -Djboss.bind.address=192.168.0.115 -Djboss.domain.primary.address=192.168.0.115 Please note that the host.xml is the default value for the --host-config argument. So in this specific case we don’t have to add it. And I can see the server is started and here is the server log output of the above command: ========================================================================= JBoss Bootstrap Environment JBOSS_HOME: /wildfly-35.0.0.Final JAVA: .sdkman/candidates/java/current/bin/java JAVA_OPTS: -Xms64m -Xmx512m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true -Djdk.serialFilter="maxbytes=10485760;maxdepth=128;maxarray=100000;maxrefs=300000" --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldaps=ALL-UNNAMED --add-exports=jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED -Djava.security.manager=allow ========================================================================= 17:06:49,064 INFO [org.jboss.modules] (main) JBoss Modules version 2.1.6.Final 17:06:49,405 INFO [org.jboss.threads] (main) JBoss Threads version 2.4.0.Final 17:06:49,428 INFO [org.jboss.as.process.Host Controller.status] (main) WFLYPC0018: Starting process 'Host Controller' 17:06:49,896 INFO [org.jboss.as.process.Host Controller.system.stdout] (stdout for Host Controller) [Host Controller] 17:06:49,875 INFO [org.jboss.modules] (main) JBoss Modules version 2.1.6.Final [Host Controller] 17:06:50,385 INFO [org.jboss.msc] (main) JBoss MSC version 1.5.5.Final [Host Controller] 17:06:50,393 INFO [org.jboss.threads] (main) JBoss Threads version 2.4.0.Final [Host Controller] 17:06:50,441 INFO [org.jboss.as] (MSC service thread 1-2) WFLYSRV0049: WildFly 35.0.0.Final (WildFly Core 27.0.0.Final) starting [Host Controller] 17:06:50,806 INFO [org.wildfly.security] (Controller Boot Thread) ELY00001: WildFly Elytron version 2.6.0.Final [Host Controller] 17:06:51,088 INFO [org.jboss.as.host.controller] (Controller Boot Thread) WFLYHC0003: Creating http management service using network interface (management) port (9990) securePort (-1) [Host Controller] 17:06:51,099 INFO [org.xnio] (MSC service thread 1-3) XNIO version 3.8.16.Final [Host Controller] 17:06:51,103 INFO [org.xnio.nio] (MSC service thread 1-3) XNIO NIO Implementation Version 3.8.16.Final [Host Controller] 17:06:51,139 INFO [org.jboss.remoting] (MSC service thread 1-7) JBoss Remoting version 5.0.30.Final [Host Controller] 17:06:52,510 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0062: Http management interface listening on http://192.168.0.115:9990/management and https://192.168.0.115:-1/management [Host Controller] 17:06:52,510 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0053: Admin console listening on http://192.168.0.115:9990 and https://192.168.0.115:-1 [Host Controller] 17:06:52,546 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly 35.0.0.Final (WildFly Core 27.0.0.Final) (Host Controller) started in 3066ms - Started 70 of 71 services (14 services are lazy, passive or on-demand) - Host Controller configuration files in use: domain.xml, host.xml - Minimum feature stability level: community From the above server log output, I can see the server-bound address is 192.168.0.115 instead of the default 127.0.0.1. Then I opened another terminal window and ran the following command in the bin directory of the WildFly server: $ ./add-user.sh -u admin -p 123 Added user 'admin' to file '/wildfly-35.0.0.Final/standalone/configuration/mgmt-users.properties' Added user 'admin' to file '/wildfly-35.0.0.Final/domain/configuration/mgmt-users.properties' From the above command output, we can see the admin user is added and its password is 123. This added user will be used on the Secondary Host Controller to connect to the Primary Host controller. Please note that the above command didn’t generate a secret value related to the generated admin user as described you may find in the other online materials, which is already deprecated since WildFly 25. So the following secret configuration on the Secondary Host Controller is already deprecated: <server-identities> <secret value="..." /> </server-identities> As the Primary Host Controller is started on Machine A, now we can check the WildFly server configuration on Machine B. As planned, the Host Controller is named secondary, and it will be connected to the Primary Host Controller on Machine A, which acts as the domain controller. Now we can check the configuration on the Secondary Host Controller. The Secondary Host Controller on Machine B will use the host-secondary.xml file as its configuration file. Please note that to edit the host-secondary.xml file in CLI, you should use this command to connect to the embedded server and use the correct host controller file: [disconnected /] embed-host-controller --host-config=host-secondary.xml [domain@embedded /] We need to make some modifications to this file. First I need to add the name property to the host section: <host xmlns="urn:jboss:domain:community:20.0" name="secondary"> Here is the method to use the CLI command to modify the host controller name: $ ./wildfly-35.0.0.Final/bin/jboss-cli.sh You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands. [disconnected /] embed-host-controller --host-config=host-secondary.xml [domain@embedded /] /host=unknown-host.unknown-domain:write-attribute(name=name,value=secondary) { "outcome" => "success", "result" => undefined, "server-groups" => undefined, "response-headers" => {"process-state" => "reload-required"} } [domain@embedded /] /host=unknown-host.unknown-domain:reload(admin-only=true) {"outcome" => "success"} Please note that if you use tab complete, it should autocomplete your default host name. Giving the host a name can help to analyze the server log output later. So I need to define this authentication-context in the elytron subsystem. This configuration is different from the legacy authentication. Here are the details: <profile> <subsystem xmlns="urn:jboss:domain:core-management:1.0"/> <subsystem xmlns="urn:wildfly:elytron:community:18.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto" register-jaspi-factory="false"> <authentication-client> <authentication-configuration sasl-mechanism-selector="DIGEST-MD5" name="myConfig" authentication-name="admin" realm="ManagementRealm"> <credential-reference clear-text="123"/> </authentication-configuration> <authentication-context name="myCtx"> <match-rule match-host="${jboss.domain.primary.address}" authentication-configuration="myConfig"/> </authentication-context> </authentication-client> ... </subsystem> ... </profile> Here is the equivalent CLI command to do the configuration: [domain@embedded /] /host=secondary/subsystem=elytron/authentication-configuration=myConfig:add(sasl-mechanism-selector=DIGEST-MD5, authentication-name=admin, realm=ManagementRealm, credential-reference={clear-text="123"}) {"outcome" => "success"} [domain@embedded /] /host=secondary/subsystem=elytron/authentication-context=myCtx:add(match-rules=[{match-host="${jboss.domain.primary.address}", authentication-configuration=myConfig}]) {"outcome" => "success"} The above configuration shows how to configure the elytron subsystem to provide user admin and its password 123 for usage. The authentication-configuration section is added, and the authentication context myCtx is using this configuration. Please note this is only one way to provide username and password via the Elytron subsystem, and you can avoid using clear-text to provide the password. I won’t dig into more details on how to use Elytron in this blog post, but you can always refer to its document to learn its usage[5]. Then I need to add modify configuration of the domain-controller: <domain-controller> <remote authentication-context="myCtx"> <discovery-options> <static-discovery name="primary" protocol="${jboss.domain.primary.protocol:remote+http}" host="${jboss.domain.primary.address}" port="${jboss.domain.primary.port:9990}"/> </discovery-options> </remote> </domain-controller> As the configuration is shown above, I defined the authentication-context to be used as myCtx. Here is the equivalent CLI command to do the configuration: /host=secondary:write-attribute(name=domain-controller.remote.authentication-context, value=myCtx) { "outcome" => "success", "result" => undefined, "server-groups" => undefined, "response-headers" => {"process-state" => "reload-required"} } After configuring the authentication part in the host-secondary.xml file on Machine B, the last thing is that I disabled the server-one and left only server-two in the configuration: <servers> <!-- <server name="server-one" group="main-server-group"/> --> <server name="server-two" group="other-server-group"> <socket-bindings port-offset="150"/> </server> </servers> Again it’s better to use the CLI command to do the configuration: /host=secondary/server-config=server-one:remove Until now all the configurations are done, and then I can start the WildFly server on Machine B with the following command: ❯ ./domain.sh --host-config=host-secondary.xml -Djboss.bind.address.management=192.168.0.113 -Djboss.bind.address=192.168.0.113 -Djboss.domain.primary.address=192.168.0.115 In the above command, I assign the value host-secondary.xml to the host-config property, and I assign values of jboss.bind.address.management and jboss.bind.address as 192.168.0.113, which is the IP address of Machine B itself. I assigned the value of jboss.domain.primary.address as 192.168.0.115, which is the IP address of Machine A. On Machine A, there is a WildFly server running as a domain controller as described above. Now we can see the server log output of the above command from Machine B: ========================================================================= JBoss Bootstrap Environment JBOSS_HOME: /wildfly-35.0.0.Final JAVA: .sdkman/candidates/java/current/bin/java JAVA_OPTS: -Xms64m -Xmx512m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true -Djdk.serialFilter="maxbytes=10485760;maxdepth=128;maxarray=100000;maxrefs=300000" --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldaps=ALL-UNNAMED --add-exports=jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED -Djava.security.manager=allow ========================================================================= 17:17:30,558 INFO [org.jboss.modules] (main) JBoss Modules version 2.1.6.Final 17:17:30,668 INFO [org.jboss.threads] (main) JBoss Threads version 2.4.0.Final 17:17:30,677 INFO [org.jboss.as.process.Host Controller.status] (main) WFLYPC0018: Starting process 'Host Controller' 17:17:30,855 INFO [org.jboss.as.process.Host Controller.system.stdout] (stdout for Host Controller) [Host Controller] 17:17:30,847 INFO [org.jboss.modules] (main) JBoss Modules version 2.1.6.Final [Host Controller] 17:17:31,008 INFO [org.jboss.msc] (main) JBoss MSC version 1.5.5.Final [Host Controller] 17:17:31,010 INFO [org.jboss.threads] (main) JBoss Threads version 2.4.0.Final [Host Controller] 17:17:31,026 INFO [org.jboss.as] (MSC service thread 1-1) WFLYSRV0049: WildFly 35.0.0.Final (WildFly Core 27.0.0.Final) starting [Host Controller] 17:17:31,158 INFO [org.wildfly.security] (Controller Boot Thread) ELY00001: WildFly Elytron version 2.6.0.Final [Host Controller] 17:17:31,270 INFO [org.jboss.as.host.controller] (Controller Boot Thread) WFLYHC0003: Creating http management service using network interface (management) port (9990) securePort (-1) [Host Controller] 17:17:31,275 INFO [org.xnio] (MSC service thread 1-7) XNIO version 3.8.16.Final [Host Controller] 17:17:31,278 INFO [org.xnio.nio] (MSC service thread 1-7) XNIO NIO Implementation Version 3.8.16.Final [Host Controller] 17:17:31,289 INFO [org.jboss.remoting] (MSC service thread 1-7) JBoss Remoting version 5.0.30.Final [Host Controller] 17:17:32,666 INFO [org.jboss.as.host.controller] (Controller Boot Thread) WFLYHC0148: Connected to the domain controller at remote+http://192.168.0.115:9990 [Host Controller] 17:17:32,692 INFO [org.jboss.as.host.controller] (Controller Boot Thread) WFLYHC0023: Starting server server-two 17:17:32,800 INFO [org.jboss.as.process.Server:server-two.status] (ProcessController-threads - 3) WFLYPC0018: Starting process 'Server:server-two' [Host Controller] 17:17:33,442 INFO [org.jboss.as.host.controller] (management task-1) WFLYHC0021: Server [Server:server-two] connected using connection [Channel ID 20a1192c (inbound) of Remoting connection 79a44d09 to 192.168.0.113/192.168.0.113:61942 of endpoint "secondary:MANAGEMENT" <6894739b>] [Host Controller] 17:17:33,452 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0062: Http management interface listening on http://192.168.0.113:9990/management and https://192.168.0.113:-1/management [Host Controller] 17:17:33,452 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0054: Admin console is not enabled [Host Controller] 17:17:33,453 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly 35.0.0.Final (WildFly Core 27.0.0.Final) (Host Controller) started in 2754ms - Started 70 of 71 services (14 services are lazy, passive or on-demand) - Host Controller configuration file in use: host-secondary.xml - Minimum feature stability level: community [Host Controller] 17:17:33,453 INFO [org.jboss.as.host.controller] (server-registration-threads - 1) WFLYHC0020: Registering server server-two From the above server log output on Machine B, we can see the WildFly server is started and server-two is started. In addition, it’s connected to the Domain Controller on Machine A. Here is the server log output from the WildFly server on Machine A: [Host Controller] 17:17:32,549 INFO [org.jboss.as.domain.controller] (Host Controller Service Threads - 23) WFLYHC0019: Registered remote secondary host "secondary", JBoss WildFly 35.0.0.Final (WildFly 27.0.0.Final) From the above Primary Host Controller log output, I can see the secondary host is connected, so it starts to accept the management of Primary Host Controller, which acts as the domain controller. Now I can open the web browser on Machine A to access the WildFly server admin console: http://192.168.0.115:9990 Please note that I can’t use the IP address 127.0.0.1 here, because the WildFly server is listening to the public IP address of Machine A, which we have assigned to the jboss.bind.address.management property during the server startup process. Here is the screenshot of the admin page of the WildFly server: We need to enter admin as the username and 123 as the password, which is the user we added as the management user above. And then we can enter the admin page of the server: As we have entered the WildFly admin page, we can try to deploy an example application. There is a helloworld project in the WildFly Quickstart project: https://github.com/wildfly/quickstart/tree/35.0.0.Final/helloworld The above project is a simple application that just contains a servlet that will respond with the text <h1>Hello World!</h1> to the request. So I cloned the WildFly Quickstart project into my local environment and then built the helloworld project to generate the helloworld.war: $ pwd /wildfly-quickstart/helloworld $ mvn install ... [INFO] BUILD SUCCESS ... ❯ ls target/*.war target/helloworld.war As the project is built, I can deploy the above WAR file into the WildFly server group. So I go back to the WildFly admin page, and then I can click the Deployments on the top menu and click the Upload Deployment: From the above screenshot, you can see that I tried to deploy the sample project into the other-server-group. I use this server group because I have configured servers on both Primary Host Controller and Secondary Host Controller hosts into this server group. Here is the deployment diagram for the server group: As the diagram shown above, I will use the domain controller’s admin page to deploy helloworld.war into the other-server-group, so the project will be deployed to server-two and server-three, because they both belong to other-server-group. Coming back to the WildFly admin page, I drag and drop the helloworld.war into the deployment page: Then I clicked Next and left the deployment configuration fields as default: Then I clicked Finished and reached the Deployment successful page: Now the helloworld.war is deployed to all the managed servers in the other-server-group. Now I click the Deployments on the top menu of the admin page, and then click the other-server-group, we can see that the helloworld.war is deployed into the server group: As the helloworld project is deployed, we can check the statuses of the two Host Controllers. I clicked the Runtime on top of the menu of the admin page, and then clicked the primary host tab, then I saw that server-three has not started yet: This is because the auto-start property is configured to false in the host.xml of the primary host: <server name="server-three" group="other-server-group" auto-start="false"> <jvm name="default"/> <socket-bindings port-offset="250"/> </server> So I need to click the Start button of the server-three: After a while the server-three is started: Because we didn’t configure the auto-start to false on the Secondary Host Controller, so it’s already started: From the above screenshots, we can see that the URL of server-two is http://192.168.0.113:8230, and the URL of server-three is http://192.168.0.115:8330. Their ports are different because the port-offset property settings are different. For server-three, the port-offset is configured like this: <server name="server-three" group="other-server-group" auto-start="false"> <jvm name="default"/> <socket-bindings port-offset="250"/> </server> Because the port-offset is set to 250 for server-three, and the default HTTP port setting is 8080, so 8080+250=8330. For server-two, the configuration is like this: <server name="server-two" group="other-server-group"> <socket-bindings port-offset="150"/> </server> As the port-offset setting is 150, the calculated HTTP port is 8080+150=8330, which is expected. Now we can use the curl command to do the requests to both the Machine A and the Machine B to see if the helloworld project is deployed on two both of the machines: ❯ curl http://192.168.0.115:8330/helloworld/HelloWorld <html><head><title>helloworld</title></head><body> <h1>Hello World!</h1> </body></html> ❯ curl http://192.168.0.113:8230/helloworld/HelloWorld <html><head><title>helloworld</title></head><body> <h1>Hello World!</h1> </body></html> From the above command output, we can see that the helloworld project is deployed two both hosts. Though they are running on two different machines, because these two hosts are in the same other-server-group and they are managed by the domain controller, so the project is deployed to both hosts. I hope this blog post can be helpful to update your knowledge base to see how to use the domain mode in the most current WildFly release. For convenience, I have put the host.xml of the Primary Host Controller and the host-secondary.xml of the Secondary Host Controller online for reference[6]. References 1. WildFly 25 is released! 2. JBoss EAP6 High Availability | Programming | eBook 3. https://docs.wildfly.org/35/Admin_Guide.html#Domain_Setup 4. Running an Embedded WildFly Host Controller in the CLI 5. WildFly Elytron Security 6. WildFly Domain Mode Configuration Files ### [Making WildFly Glow with Intelligence](/news/2025/02/10/Making-WildFly-Glow-with-Intelligence/) In WildFly 35 Beta, WildFly Glow has also received a new feature to introduce spaces to structure discovered Galleon feature-packs, this allows feature-packs to be grouped into spaces such as an incubating space to reflect the stability of the feature-pack and to allow users to select which spaces they want to use. One of the first feature-pack to take advantage of that is the WildFly AI Feature-Pack using the new incubating space. In this article I will show you how you can take advantage of this to provision a Generative AI server. WildFly AI Feature-Pack Since my first article the WildFly AI Feature-Pack has evolved quite a bit. Of course we are following LangChain4J and smallrye-llm evolutions. We have also added support for streaming tokens making the interaction lot more lively. Now, it is providing OpenTelemetry support to track your LLM usage and integrating with WildFly Glow to provide a default configuration on provisioning a lot easier. Let’s dive into this new feature. WildFly AI Feature-Pack layers Currently the feature-pack provides 18 Galleon layers that build upon each other : Support for chat models to interact with a LLM: mistral-ai-chat-model ollama-chat-model groq-chat-model (same as openai-chat-model but targeting Groq) openai-chat-model Support for embedding models: in-memory-embedding-model-all-minilm-l6-v2 in-memory-embedding-model-all-minilm-l6-v2-q in-memory-embedding-model-bge-small-en in-memory-embedding-model-bge-small-en-q in-memory-embedding-model-bge-small-en-v15 in-memory-embedding-model-bge-small-en-v15-q in-memory-embedding-model-e5-small-v2 in-memory-embedding-model-e5-small-v2-q ollama-embedding-model Support for embedding stores: in-memory-embedding-store neo4j-embedding-store weaviate-embedding-store Support for content retriever for RAG: default-embedding-content-retriever: default content retriever using an in-memory-embedding-store and in-memory-embedding-model-all-minilm-l6-v2 for embedding model. web-search-engines For more details on these you can take a look at LangChain4J and Smallrye-llm. Provisioning the server with Glow We are going to use the chabot example of the WildFly MCP. The initial way to provision our server was to define the layers in the pom.xml like this: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.wildfly.server}</location>* </feature-pack> <feature-pack> <location>org.wildfly:wildfly-ai-feature-pack:${version.wildfly.ai.feature.pack}</location> </feature-pack> </feature-packs> <layers> <layer>ee-core-profile-server</layer> <layer>jaxrs</layer> <layer>ollama-chat-model</layer> <layer>groq-chat-model</layer> <layer>openai-chat-model</layer> <layer>default-embedding-content-retriever</layer> </layers> <name>ROOT.war</name> <bootableJar>true</bootableJar> <packagingScripts> <packaging-script> <scripts> <script>./src/scripts/configure_server.cli</script> </scripts> </packaging-script> </packagingScripts> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> But using WildFly Glow we can make that way simpler: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <discoverProvisioningInfo> <version>${version.wildfly.server}</version> <spaces> <space>incubating</space> </spaces> </discoverProvisioningInfo> <name>ROOT.war</name> <bootableJar>true</bootableJar> <packagingScripts> <packaging-script> <scripts> <script>./src/scripts/configure_server.cli</script> </scripts> </packaging-script> </packagingScripts> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> AS you can see we are using the discoverProvisioningInfo element to define which version of WildFly server we want to start from. AS you can see we have added an incubating space which enables the discovery of the WildFly AI Feature-Pack. Now when we run Apache Maven we can see the following traces : As you can see, Glow discovered the use of the following LLMs: ollama-chat-model openai-chat-model groq-chat-model How did Glow found those ? How Glow works under the hood for the WildFly AI Feature-Pack ? Here is where the magic is happening : @ServerEndpoint(value = "/chatbot", configurator = CustomConfigurator.class) public class ChatBotWebSocketEndpoint { private static final Logger logger = Logger.getLogger(ChatBotWebSocketEndpoint.class.getName()); @Inject @Named(value = "ollama") ChatLanguageModel ollama; @Inject @Named(value = "openai") ChatLanguageModel openai; @Inject @Named(value = "groq") ChatLanguageModel groq; //@Inject Instance<ChatLanguageModel> instance; private PromptHandler promptHandler; private Bot bot; private List<McpClient> clients = new ArrayList<>(); private final List<McpTransport> transports = new ArrayList<>(); private Session session; private final ExecutorService executor = Executors.newFixedThreadPool(1); private final BlockingQueue<String> workQueue = new ArrayBlockingQueue<>(1); // It starts a Thread that notifies all sessions each second @PostConstruct public void init() { ... } ... } As you can see, we inject dev.langchain4j.model.chat.ChatLanguageModel in the org.wildfly.ai.chatbot. ChatBotWebSocketEndpoint using a @Named annotation. This is the rule that Glow uses to detect what the application is using. You can see the Glow rule here. <prop name="org.wildfly.rule.annotated.type" value="dev.langchain4j.model.chat.ChatLanguageModel,jakarta.inject.Named[value=ollama]"/> So this explain why Glow is detecting that the WildFly MCP application is using Groq,OpenAI and Ollama. Of course, similar rules exist for the embedding models and embedding store. In conclusion As you could see, developping a Generative AI application using WildFly Glow and the WildFly AI Feature-Pack is, as Duke Nukem used to say, a piece of cake. ### [WildFly 35.0.1 is released!](/news/2025/02/06/WildFly-35-0-1-is-released/) WildFly 35.0.1.Final is now available for download. I am pleased to announce that the WildFly 35.0.1.Final release is now available for download. The following issues were resolved in 35.0.1: Bugs [WFLY-20261] - NPE in race condition between a thread committing a transaction and another thread performing recovery. [WFLY-20290] - CLI command "server=name:import-journal" for messaging subsystem throws "NoClassDefFoundError:" in Java 17 [WFLY-20329] - Incorrect module identifier handling in WeldDeploymentProcessor Component Upgrades [WFLY-20303] - Upgrade Arquillian from 1.9.2.Final to 1.9.3.Final [WFLY-20306] - Upgrade Wiremock to 3.10.0 [WFLY-20307] - (WF 35) Upgrade HAL to 3.7.8.Final [WFLY-20309] - Upgrade RESTEasy MicroProfile 3.0.0.Final to 3.0.1.Final [WFLY-20323] - Upgrade openjdk-orb to 10.1.1.Final [WFLY-20324] - Upgrade Narayana to 7.2.0.Final [WFLY-20341] - Upgrade Apache Mime4j from 0.8.11 to 0.8.12 [WFLY-20355] - Upgrade WildFly Core to 27.0.1.Final [WFLY-20358] - Upgrade Infinispan to 15.0.13.Final [WFLY-20085] - Upgrade cxf from 4.0.5 to 4.0.6 Tasks [WFLY-20272] - Update microprofile-certification.sh to reflect that WildFly is now MP 7 compatible [WFLY-20273] - Adapt microprofile-certification.sh to play nicely with the MicroProfile Telemetry TCK processing [WFLY-20275] - Remove XercesUsageTestCase [WFLY-20339] - Suppress CVE-2024-4109 as triaged as not a security vulnerability Sub Tasks [WFLY-20259] - MP REST Client TCK is never run with the security manager The following issues were also resolved in the version of WildFly Core contained within this release: Bugs [WFCORE-7153] - CVE-2025-23367 org.wildfly.core/wildfly-server: Wildfly improper RBAC permission. Component Upgrades [WFCORE-7131] - Upgrade JBoss Marshalling to 2.2.2.Final Enjoy! ### [WildFly in a Foundation](/news/2025/02/03/WildFly-in-a-Foundation/) In the last two years we’ve been putting a lot of effort into improving how the WildFly project interacts with our community, including adding new communication channels like our Mini Conferences, adding new user guides and creating a transparent feature development process. WildFly has been a successful project for a long time now, and I believe that’s largely because we are passionate about serving our community. To help us continue on this path, we are considering moving WildFly to a vendor-neutral software foundation. Our hope is that by doing this we could further expand our community, improve our openness and transparency, refresh our governance model, and encourage more participation by contributors not affiliated with Red Hat. Important Considerations Moving to a foundation is not a trivial task, so it’s critical that the choice we make is a net benefit to our community. To help ensure this, there are a number of key factors we’re looking at when evaluating what foundation would be the best fit: Flexibility to continue shipping third-party components using a wide array of Open Source Initiative (OSI)-approved Open Source licences. Maintain as much as possible our current release processes. Retain independence in decision making, particularly on technical matters. Support and Alignment with Red Hat Values Red Hat is dedicated to participating in and supporting vendor-neutral collaboration projects, such as the Linux kernel, Kubernetes, and OpenJDK; doing so is part of the company’s DNA. Red Hat business leaders are fully supportive of this move. Community Feedback We’d love to hear your thoughts on this. Let us know what you’re thinking either on the developer mail list, in the WildFly google group or in Zulip Best regards, Brian ### [Testing WildFly applications on Docker with Arquillian Cube](/news/2025/01/27/Testing-WildFly-applications-on-Docker-with-Arquillian-Cube/) Recently we resumed the Arquillian Cube project as a way to test on containerized environments, such as Docker, Kubernetes, and OpenShift. The last (pre)release is 2.0.0.Alpha1, and it aims at filling the gap with the 1.18.2 release, by running against more recent versions of target environments (again, Docker, Kubernetes and OpenShift). This example provides the guidance to set up an automated integration test for a WildFly application that should be run on Docker. In order to do so, we’ll start from the WildFly Java Microservice - PART 1: Docker Image guide, which will be modified to show how to implement a JUnit test that will use an existing Dockerfile to automate the image build and execution. Use case The original article uses Maven archetypes to provide the reader with a ready-to-use WildFly application project. And it works great, definitely! But in the last section, the user is instructed on how to build the Docker image, and about testing it manually. This article is all about this: using Arquillian Cube to automate the image build, and the Docker container setup and execution, while leveraging annotations and APIs at the test class level, to let the developer focus on the actual test logic. In the following sections we’ll see which steps we need to take in order to modify the original example and achieve what above. Step by step changes As said, we need to start from the WildFly Java Microservice - PART 1: Docker Image article, so make sure to go through it, then…​ Docker compose and Dockerfile resources Let’s start and create a new docker-build directory at the project root: mkdir docker-build and put the Dockerfile - i.e. the one we created in the original article - inside it. We’ll need to change just one line, i.e. we should replace the path target/server with just server, we’ll see why later on. As you can see, we reused the Dockerfile which we created in the original example, which defines how the image should be built. Then we should create a docker-compose.yml file at the project root, as well, with the following contents: version: '2' services: wildfly: build: context: docker-build ports: - "9991:9990" - "8081:8080" networks: - front-tier networks: front-tier: Here we’ve defined how the Docker container should run the image created previously. Specifically, we can see that a container named wildfly will be started, building an image as per the Dockerfile which is in the docker-build sub-directory, and exposing the container 8080 and 9990 ports via the host’s 8081 and 9991 ones, respectively. That’s all about what we need on the Docker side. Arquillian Cube will automate the docker compose build that will use the Dockerfile which was created already to build and run the WildFly application image. In the following section we’ll modify the project POM to use Arquillian Cube. Update the example project POM First off, let’s add the following properties to define some required versions: <arquillian-cube.version>2.0.0.Alpha1</arquillian-cube.version> <arquillian-core.version>1.8.0.Final</arquillian-core.version> <junit.version>4.13.2</junit.version> <slf4j.version>2.0.16</slf4j.version> Then we need to comment out, or remove, the following declaration of the JUnit 5 BOM off the dependencyManagement section, since Arquillian Cube will use JUnit 4 instrumentation by default: <!-- Arquillian Cube still using JUnit 4 by default --> <!-- <!–Define the JUnit5 bom. WildFly BOM still contains JUnit4, so we have to declare a version here –>--> <!-- <dependency>--> <!-- <groupId>org.junit</groupId>--> <!-- <artifactId>junit-bom</artifactId>--> <!-- <version>${version.junit5}</version>--> <!-- <type>pom</type>--> <!-- <scope>import</scope>--> <!-- </dependency>--> and finally let’s add the following dependencies to the dependencyManagment section, which are what we need to use Arquillian Cube: <!-- We need to lock Arquillian Cube dependencies to 2.0.0.Alpha1 --> <dependency> <groupId>org.arquillian.cube</groupId> <artifactId>arquillian-cube-bom</artifactId> <type>pom</type> <scope>import</scope> <version>${arquillian-cube.version}</version> </dependency> <!-- And Arquillian Core one to the 1.8.0. version, which is the one that Arquillian Cube 2.0.0.Alpha1 is using --> <dependency> <groupId>org.jboss.arquillian</groupId> <artifactId>arquillian-bom</artifactId> <type>pom</type> <scope>import</scope> <version>${arquillian-core.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-bom</artifactId> <version>${slf4j-api.version}</version> <scope>test</scope> </dependency> Once this is done, we actually need to depend on Arquillian Cube and related artifacts, which we’ll do by adding the following to the dependencies section: <!-- We need Arquillian Cube to run our WildFly instance in a Docker container --> <dependency> <groupId>org.arquillian.cube</groupId> <artifactId>arquillian-cube-docker</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-container</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-standalone</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <!-- Slf4j is used by Arquillian Cube Docker --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <scope>test</scope> </dependency> while we’ll have to remove the following ones: <!-- Test scope dependencies --> <!-- Arquillian Cube still using JUnit 4 by default --> <!-- <dependency>--> <!-- <groupId>org.junit.jupiter</groupId>--> <!-- <artifactId>junit-jupiter</artifactId>--> <!-- <scope>test</scope>--> <!-- </dependency>--> <!-- Not needed anymore because the test uses a standalone Docker container --> <!-- <dependency>--> <!-- <groupId>org.wildfly.arquillian</groupId>--> <!-- <artifactId>wildfly-arquillian-container-managed</artifactId>--> <!-- <scope>test</scope>--> <!-- </dependency>--> Last moves with our POM, let’s add the following to the wildfly-maven-plugin configuration: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <!-- We need for the server to be provisioned in ./docker-build/server, as required by the Dockerfile --> <provisioningDir>${project.basedir}/docker-build/server</provisioningDir> <overwriteProvisionedServer>true</overwriteProvisionedServer> and let the maven-clean-plugin take care of such directory when cleaning things up, too: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-clean-plugin</artifactId> <version>3.3.2</version> <!-- Let's remove ./docker-build/server, too --> <configuration> <filesets> <fileset> <directory>${project.basedir}/docker-build/server</directory> </fileset> </filesets> </configuration> </plugin> That’s it, we’re done with the POM, let’s move on and see how the arquillian.xml file should be configured. Update arquillian.xml configuration This is easy, we don’t need a wildfly container anymore, so let’s remove it. <!-- <container default="true" qualifier="managed"> --> <!-- <configuration> --> <!-- <property name="jbossHome">target/server</property> --> <!-- </configuration> --> <!-- </container> --> Then we need to configure the docker extension, specifically we’ll just set the dockerContainersFile property, i.e. the path for the docker-compose.yml file: <extension qualifier="docker"> <property name="dockerContainersFile">./docker-compose.yml</property> </extension> With all the above in place, the only thing left is the test class. Create a test class for testing on Docker Add the following contents to a new GettingStartedDockerIT.java class: package org.wildfly.examples; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.core.Response; import org.arquillian.cube.HostIp; import org.arquillian.cube.HostPort; import org.jboss.arquillian.junit.Arquillian; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import java.net.URI; /** * Run integration tests with Arquillian to be able to test CDI beans */ @RunWith(Arquillian.class) public class GettingStartedDockerIT { @HostIp private String wildflyIp; @HostPort(containerName = "wildfly", value = 8080) int wildflyPort; @Test public void testHelloEndpoint() { try (Client client = ClientBuilder.newClient()) { final String name = "World"; Response response = client .target(URI.create("http://" + wildflyIp + ":" + wildflyPort + "/")) .path("/hello/" + name) .request() .get(); Assert.assertEquals(200, response.getStatus()); Assert.assertEquals(String.format("Hello '%s'.", name), response.readEntity(String.class)); } } } As you can see, it’s similar to the existing GettingStartedApplicationIT.java test class that the Maven archetype execution created for us in the original example, but we use a different runner, and inject the Docker container IP address and the host port which is mapping the exposed 8080 port. At this point we can remove the two existing test classes, i.e. GettingStartedServiceIT and GettingStartedApplicationIT.java. Run the test That’s it, we can run Docker integration test by issuing the following command: mvn clean install and we’ll see how Arquillian Cube will gather the docker extension configuration, then summarize the container definition, and eventually run the test: [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running org.wildfly.examples.GettingStartedDockerIT ... Jan 20, 2025 6:06:06 PM org.arquillian.cube.docker.impl.client.CubeDockerConfigurationResolver resolveSystemDefaultSetup INFO: Connected to docker (fburzigo-thinkpadp1gen3.rmtit.csb) using default settings version: 24.0.5 kernel: 6.11.4-201.fc40.x86_64 CubeDockerConfiguration: serverUri = unix:///var/run/docker.sock tlsVerify = false dockerServerIp = localhost definitionFormat = COMPOSE clean = false removeVolumes = true dockerContainers = containers: wildfly: alwaysPull: false buildImage: dockerfileLocation: docker-build noCache: true remove: true killContainer: false manual: false networkMode: front-tier networks: - front-tier portBindings: !!set 9991->9990/tcp: null 8081->8080/tcp: null readonlyRootfs: false removeVolumes: true networks: front-tier: driver: bridge [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 16.69 s -- in org.wildfly.examples.GettingStartedDockerIT In conclusion Testing a WildFly application directly on Docker will make the test more similar to the actual environment where it will be run. Arquillian Cube provides an easy and effective way to test on Docker, with almost no configuration and instrumentation changes with respect to existing Arquillian based tests. The code for the example application which is described in this article is here: https://github.com/fabiobrz/wildfly-mini-series-docker-cube Fabio Burzigotti ### [WildFly 35 is released!](/news/2025/01/09/WildFly-35-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 35.0.0.Final releases are available for download at https://wildfly.org/downloads. New and Notable This quarter we had a heavy focus on MicroProfile, particularly MicroProfile 7.0, which I’m pleased to say WildFly 35 fully supports. Improvements in the MicroProfile area include: WildFly now supports MicroProfile Fault Tolerance 4.1. WildFly now supports MicroProfile OpenAPI 4.0. Standard WildFly now supports MicroProfile REST Client 4.0. This was previously supported in WildFly Preview. Standard WildFly now supports MicroProfile Telemetry 2.0. This was previously supported in WildFly Preview. Our MicroProfile Reactive Messaging subsystem has added OpenTelemetry tracing integration for Kafka connectors and AMQP connectors. There’s plenty of new things beyond MicroProfile area as well, though: WildFly Preview is a compatible implementation of the Jakarta EE 11 Core Profile, which was released in November, independent of the work-in-progress EE 11 Platform and Web Profile specifications. WildFly Preview was one of the compatible implementations used to ratify the specification, and WildFly Preview 35 is also a compatible implementation, on both Java 17 and Java 21. WildFly now includes supported systemd units in the bin/systemd directory, replacing the old, unsupported docs/contrib/scripts/systemd files. The new units include support for a managed domain. The jaxrs subsystem now provides JSON merge patch support. This feature allows the client to send a JSON http request with Content-Type "application/merge-patch+json", and the JSON content will be directly merged to the target resource. We added support for Jakarta Data 1.0 to standard WildFly. This was previously included in WildFly Preview 34; now it is available in standard WildFly as well. This feature is provided at the preview stability level. WildFly Preview has a new vertx subsystem and Galleon layer, intended to give users greater control over the configuration of Vert.x instances running in the server. This feature is provided at the preview stability level. We added a new Jakarta RESTful Web Services Helloworld quickstart and a new Deploying High-Availability Messaging with WildFly and AMQ 7 on OpenShift guide. Another big thing that’s new is, as I announced in October, WildFly now requires a minimum of Java SE 17, and thus no longer supports running on Java 11. Supported Specifications Jakarta EE Standard WildFly 35 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly is EE 10 Platform, Web Profile and Core Profile compatible when running on Java SE 17 and Java SE 21. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence Jakarta EE 10 Full Platform SE 17 SE 21 Jakarta EE 10 Web Profile SE 17 SE 21 Jakarta EE 10 Core Profile SE 17 SE 21 MicroProfile Standard WildFly 35 supports MicroProfile Platform 7.0, along with several other MicroProfile specifications that are not part of MicroProfile Platform. WildFly’s MicroProfile support includes implementations of the following specifications in our "full" (e.g. standalone-full.xml) and "default" (e.g standalone.xml) configurations as well as our "microprofile" configurations (e.g. standalone-microprofile.xml): MicroProfile Technology WildFly Full/Default Configurations WildFly MicroProfile Configuration MicroProfile Config 3.1 X X MicroProfile Fault Tolerance 4.1  —  X MicroProfile Health 4.0  —  X MicroProfile JWT Authentication 2.1 X X MicroProfile LRA 2.0  —  X MicroProfile OpenAPI 4.0  —  X MicroProfile Reactive Messaging 3.0  —   —  MicroProfile Reactive Streams Operators 3.0  —   —  MicroProfile Rest Client 4.0 X X MicroProfile Telemetry 2.0  —  X Compatibility evidence for the above specifications that are part of MicroProfile 7.0 can be found in the WildFly Certifications repository on GitHub. WildFly Preview and EE 11 As I noted in the WildFly 32 release announcement, beginning with that release we are using WildFly Preview to provide a look at what we’re doing for Jakarta EE 11 support. The EE 11 Platform and Web Profile specifications won’t go GA before later this year. But there are milestone, Release Candidate and Final releases of many EE 11 specs and implementations available, so we are providiong those in WildFly Preview. This means for a number of EE APIs, WildFly Preview no longer provides an EE 10 compatible implementation. However, for a number of specifications that are planning changes for EE 11 we are still offering the EE 10 variant. In future releases we’ll shift those to the EE 11 variants. As I mentioned earlier, the EE 11 Core Profile specification did go GA in November and WildFly Preview 35 is a compatible implementation of that profile. Full details on the EE specification versions provided by WildFly Preview can be found in the WildFly 35 documentation. Java SE Support Our recommendation is that you run WildFly 35 on Java SE 21, as that is the latest LTS JDK release where we have completed the full set of testing we like to do before recommending a particular SE version. WildFly 35 also is heavily tested and runs well on Java 17. Our recommendation of SE 21 over SE 17 is solely because as a general principle we recommend being on later LTS releases, not because of any problems with WildFly on SE 17. While we recommend using an LTS JDK release, I do believe WildFly runs well on SE 23. By runs well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. We’ve also had good results with tests on Linux of an EA release of SE 24 (Oracle 24-ea+15-1658). Please note that WildFly runs in classpath mode. Incompatible Changes Beginning with the WildFly 35 release, standard WildFly no longer supports running in a Java SE 11 environment. Users should run WildFly 35 on SE 21 or SE 17. The default name of the bootable jar produced by WildFly’s maven tooling has changed from a fixed name of server-bootable.jar to the dynamic name ${project.artifactId}-bootable.jar where project.artifactId is the maven artifact id of the module producing the jar. If this default value isn’t wanted, the bootable jar name can be configured. Release Notes The full WildFly 35 release notes are available in GitHub. Issues fixed in the underlying WildFly Core 27.0.0 release are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. And, with that, I’m moving on to what I think will be a very busy WildFly 36! Best regards, Brian ### [PKCS#12 with WildFly Elytron's Credential Store](/news/2025/01/06/PKCS-12-with-WildFly-Elytron-apos-s-Credential-Store/) The default credential store used in WildFly from WildFly Elytron is the KeyStoreCredentialStore which is backed by a Java KeyStore to hold the credentials. This in turn defaults to using the JCEKS KeyStore format, this blog post is to illustrate how we can configure this to use a PKCS#12 store instead both in WildFly and when using the elytron-tool CLI tool directly. ### [Using the management console on OpenShift](/news/2024/12/18/Using-the-management-console-on-OpenShift/) In this blog post I’d like to show how you can use the management console (aka HAL) for WildFly instances running on OpenShift. Prerequisites The console is an integral part of WildFly and is activated by default when running on-premise. For instances running on OpenShift, the console is not available by default, though. To use the console on OpenShift, you need a WildFly image that meets the following requirements: Management user: The management console is protected by default and requires a management user added with the add-user.sh script. Public route to the management interface: The management interface has to be publicly available from the outside. Allowed origin: The console uses the fetch API to talk to the management interface of a running WildFly instance. In an OpenShift environment, the origins of the public route and the management interface itself are different. That’s why we need to tell WildFly that it is ok to make requests to the management interface from another origin (see CORS policies for more details). You can build such an image on your own based on the official WildFly images available at quay.io/wildfly/wildfly (see "Extending the image"). Another way is to use the pre-built images from quay.io/halconsole/wildfly. These images are mainly meant for HAL development and testing but already meet these requirements, which makes them suitable for our use case. In particular the images add a management user admin:admin and have a list of preconfigured allowed origins. Warning The additions in the quay.io/halconsole/wildfly images are only meant for development and testing purposes. Under no circumstances must this be used in production! Do not rely on the management user admin:admin or the preconfigured allowed origins. To add the allowed origin for the public route, we make use of the jboss-cli kubectl plugin. This plugin makes it straightforward to connect to a WildFly instance running on OpenShift and execute CLI commands. Please visit https://github.com/jmesnil/kubectl-jboss-cli/ to find out how to install and use the plugin. Instructions The steps below assume you have access to an OpenShift cluster and installed kubectl and the jboss-cli plugin. Create application oc new-app quay.io/halconsole/wildfly oc create route edge --service wildfly --port 9990 Add allowed origin Use oc get pods to find the name of the pod to connect to and oc get routes to get the hostname of the public route to the management interface. kubectl jboss-cli -p <pod> Login using admin:admin and execute these CLI commands: /core-service=management/management-interface=http-interface:list-add(name=allowed-origins,value=https://<hostname>) reload exit Open the management console at https://<hostname> and login using admin:admin. Online version of the management console As an alternative to adding the allowed origin, you can also use the online version of the management console available at https://hal.github.io/console. This URL ships the latest version of the management console. Note The management console is a single-page application (SPA) without any server side dependencies. As such, it can run on its own and connect to an arbitrary management interface. The online version of the console makes use of this fact. See https://hal.github.io/documentation/get-started/#standalone-mode for more details. Create the application as above and find the hostname of the public route using oc get routes. Open https://hal.github.io/console Add a management interface to the public route: Give an arbitrary name, select https as a scheme, enter the hostname of the public route without https and port 80: Click Add and then Connect Login using admin:admin Things to keep in mind Please note that the above instructions are just a workaround to access the OpenShift management console as long as there is no more compatible, container-friendly way. In particular, the approach ignores some principles that should not be applied in a cloud environment: Changing the management configuration of a pod is an antipattern as it will not outlive a pod restart. At that point, you’ll have to reconfigure the allowed origin. With a route, you are accessing pods behind a service. If your deployments have multiple pods, it’s complex and hacky to access a specific pod or configure all pods. Do not use the quay.io/halconsole/wildfly images in production under any circumstances. They contain preconfigured, insecure credentials and are meant only for development and testing purposes. Outlook We’re currently working on the next-gen management console. This version will also support a dedicated variant for OpenShift that will integrate with the OpenShift management console and addresses the limitations mentioned above. For more information you can watch the talk on the next-gen management console from the last WildFly mini conference, get the slides or reach out to us in the HAL Zulip channel. ### [Thanks for a great 2024!](/news/2024/12/18/Thanks-for-a-great-2024/) We are almost at the end of 2024 and we wanted to take this opportunity to thank all our community members for their help on WildFly this year. 2024 was a busy year for WildFly and a lot was accomplished. We continued with our quarterly releases and delivered 4 Major versions (31, 32, 33, 34) and 5 micro updates. WildFly 35 Beta also just came out last week. There were many developments done this year but here are some of the highlights from our release notes: Stability levels The WildFly project has high standards related to quality, stability and backwards compatibility. A key way an open source project like WildFly can ensure high standards are met is by "community bake", allowing interested users to have access to features that are still undergoing a hardening process, while not forcing users who are not interested in such things to consume them. To better facilitate this, WildFly 31 introduced the notion of formal "stability levels" that can be associated with functionality. MicroProfile 7.0 We have added support for MicroProfile 7.0 with inclusion of updated specifications for MicroProfile Fault Tolerance, MicroProfile OpenAPI, MicroProfile REST Client and MicroProfile Telemetry. Jakarta EE 11 Work on support of Jakarta EE 11 is ongoing with inclusion of preview stability support for Jakarta Data in both standard WildFly and WildFly Preview, in addition to the updates of Jakarta EE 10 APIs in WildFly Preview. WildFly Glow The WildFly Glow tools (a CLI application and a Maven plugin) will analyze your application artifact, determine what WildFly feature-packs and Galleon layers are needed to run your application, and make suggestions about other features (e.g. TLS support) that you may want to include in your optimized WildFly installation. You can take the information WildFly Glow provides and use it in your own provisioning configuration, or you can have WildFly Glow provision a server, bootable jar or Docker image for you. Jakarta MVC We have added a preview stability extension and subsystem for Jakarta MVC. Vert.x extension We have added a preview stability extension and subsystem for Vert.x to configure and share the Vert.x instance within WildFly server for other subsystems which need it. WildFly AI We have created a Feature-Pack for Generative AI that simplifies the integration of AI in WildFly applications. Overall, more than 300 feature, enhancement and bug issues were resolved in our main code by more than 60 contributors, and if you include task and component upgrade issues we resolved over 700. This is not counting all the work done in the components integrated in WildFly. We have updated our release process with an emphasis on WildFly Proposals to enhance and expand WildFly. We continued to expand our guides to cover more use cases. We also organized two mini conferences around WildFly in March and November: Live stream of the March conference Live stream of the November conference We will start 2025 with the release of WildFly 35 and we have a lot of exciting news for the future of WildFly! Thanks all for of your for your work and help in making WildFly a successful Open Source project. We are looking forward to continuing working with you next year! Best wishes from the WildFly team and Happy New Year 🎉🎊! Brian ### [Introducing Vertx Subsystem in WildFly Preview](/news/2024/12/17/Introducing-Vertx-Subsystem-in-WildFly-Preview/) I’m excited to announce the integration of the WildFly Vertx Feature-Pack into WildFly Preview from WildFly 35 Beta release. This feature-pack introduces Vertx configuration capabilities through the WildFly management model, making it easier to manage and integrate Vertx with existing WildFly subsystems. Note In the 35 release, the vertx subsystem is only available in WildFly Preview, and not in standard WildFly. It is provided at the preview stability level, which is enabled out-of-the-box in WildFly Preview. Eclipse Vert.x Overview Eclipse Vert.x is an open-source toolkit designed for building event-driven, asynchronous applications. Currently, Vertx instances have been used by opentelemetry and microprofile-reactive-messaging-smallrye subsystems within WildFly to provide features powered by vertx components underneath, but there was no central mechanism to configure them. Key Features of the WildFly Vertx Feature-Pack This feature-pack provides centralized configuration and management of the Vertx instance, so administrators now have a unified way to define and manage the Vertx instance. Following the recommendation from the Vert.x team, it is good to have a single Vertx instance for everything, which ensures optimal efficiency and simplicity. Configurable VertxOptions: Administrators can define Vertx configurations using the WildFly management model, ensuring consistency across subsystems. Expose the Vertx Instance to CDI container: When administrators set up a Vertx instance in the vertx subsystem, it is exposed to the CDI container with a fixed qualifier, so other subsystems like opentelemetry and microprofile-reactive-messaging-smallrye can use it using CDI API. Configuring Vertx instance in WildFly Preview Vertx instance in WildFly Preview is configured using the new vertx subsystem. This subsystem isn’t included in any of WildFly Preview’s out-of-the-box configuration files, so to use it you’ll need to add it to your configuration. If you’re using a complete WildFly Preview installation, like the ones available from the WildFly downloads page, then you can use the JBoss CLI to add the vertx extension and subsystem to your configuration: $ /extension=org.wildfly.extension.vertx:add $ /subsystem=vertx:add Once vertx subsystem is added, you can define some VertxOptions and set up the Vertx instance to refer to the options you just configured: $ /subsystem=vertx/vertx-option=vo:add(event-loop-pool-size=20, max-eventloop-execute-time=5, max-eventloop-execute-time-unit=SECONDS) $ /subsystem=vertx/vertx=vertx:add(option-name=vo) You will see the configuration like: standalone.xml <subsystem xmlns="urn:wildfly:vertx:preview:1.0"> <vertx option-name="vo"/> <vertx-options> <vertx-option name="vo" event-loop-pool-size="20" max-eventloop-execute-time="5" max-eventloop-execute-time-unit="SECONDS"/> </vertx-options> </subsystem> For more configuration, please refer to the Configuration-Guide in the wildfly-vertx-feature-pack Wiki page. Use Cases With above configuration, there is a Vertx instance exposed in CDI container with a qualifier, which has been integrated to opentelemetry subsystem (microprofile-reactive-messaging-smallrye subsystem soon) by setting the associated configuration item internally. So when you play opentelemetry-tracing quickstart with the vertx configuration above, you will see a log message: [org.wildfly.extension.vertx] (default task-1) WFLYVTX0008: Use Vertx instance from vertx subsystem which indicates that the Vertx instance from the vertx subsystem is used underneath. The Vertx instance has 20 event loop threads set, and it will log a warning if it detects that event loop threads haven’t returned within 5 seconds. Future plan There is a plan to increase the stability level to community and finally to the default level to be used in the standalone WildFly distributions. Now the vertx subsystem is integrated internally whenever it is available, maybe it is better to give the decisions to the administrators so that they can configure the opentelemetry subsystem and microprofile-reactive-messaging-smallrye subsystem to use or not the vertx instance coming from the vertx subsystem. When this vertx subsystem becomes mature enough and higher stability level, we also consider to move it to WildFly codebase to align the release cycles. Please try out the vertx subsystem in WildFly Preview and give us your feedback! We’ll continue to work on the integration, with a goal of including it in standard WildFly in one of the next couple of releases. ### [WildFly 35 Beta is released!](/news/2024/12/12/WildFly-35-Beta-is-released/) I’m pleased to announce that the new WildFly 35.0.0.Beta1 release is available for download at https://wildfly.org/downloads. New and Notable This quarter we had a heavy focus on MicroProfile, particularly MicroProfile 7.0. WildFly now supports MicroProfile Fault Tolerance 4.1. WildFly now supports MicroProfile OpenAPI 4.0. Standard WildFly now supports MicroProfile REST Client 4.0. This was previously supported in WildFly Preview. Standard WildFly now supports MicroProfile Telemetry 2.0. This was previously supported in WildFly Preview. Our MicroProfile Reactive Messaging subsystem has added OpenTelemetry tracing integration for Kafka connectors and AMQP connectors. There’s plenty of new things beyond MicroProfile area as well, though: WildFly now includes supported systemd units in the bin/systemd directory, replacing the old, unsupported docs/contrib/scripts/systemd files. The new units include support for a managed domain. The jaxrs subsystem now provides JSON merge patch support. This feature allows the client to send a JSON http request with Content-Type "application/merge-patch+json", and the JSON content will be directly merged to the target resource. We added support for Jakarta Data 1.0 to standard WildFly. This was previously included in WildFly Preview 34; now it is available in standard WildFly as well. This feature is provided at the preview stability level. WildFly Preview has a new vertx subsystem and Galleon layer, intended to give user’s greater control over the configuration of Vert.x instances running in the server. This feature is provided at the preview stability level. WildFly Glow has also received a new feature to introduce spaces to structure discovered Galleon feature-packs, this allows feature-packs to be grouped into spaces such as an incubating space to reflect the stability of the feature-pack and to allow users to select which spaces they want to use. For further details please see the detailed 35.0.0.Beta1 Release Notes in GitHub. As we approach the end of 2024 this is the time of the year where we release the Beta release of the major version just before we wrap up for the end of the year and will follow up with the Final release once we return in the new year. Please take this time as an opportunity to try out this release and provide us with any feedback. Finally I would like to thank everyone who has contributed to making this release happen, both via direct contributions to WildFly as well as the countless contributions to the projects that WildFly depends upon. We also had a couple of first time contributors this release so I would like to thank Peter Major for taking on one of our good-first-issue Jira issues to remove redundant code from our application client implementation and Pedro Hos for contributing updates to our testsuite to move tests to a more appropriate location. ### [A kubectl plugin to run WildFly management operations on Kubernetes](/news/2024/12/12/A-kubectl-plugin-to-run-WildFly-management-operations-on-Kubernetes/) ### [WildFly 34.0.1 is released!](/news/2024/11/22/WildFly-34-0-1-is-released/) WildFly 34.0.1.Final is now available for download. It’s been about a month since the WildFly 34 release, so we have done a small bug fix update, WildFly 34.0.1. This includes an update to WildFly Preview. The following issues were resolved in 34.0.1: Bugs [WFLY-19891] - ISPN000299: Unable to acquire lock…​ when cancelling a persistent timer in @PostConstruct on a suspended node [WFLY-19909] - Wrong routing of EJB calls in cluster Component Upgrades [WFLY-19927] - Upgrade RESTEasy to 6.2.11.Final [WFLY-19928] - Upgrade RESTEasy to 7.0.0.Alpha4 (WF preview) [WFLY-19964] - Upgrade Netty to 4.1.115.Final [WFLY-19977] - Upgrade wildfly-clustering to 1.1.3.Final Enjoy! ### [Using the maven-wildfly-plugin to provision the WildFly to use the PostgreSQL datasource.](/news/2024/11/14/Using-the-maven-wildfly-plugin-to-provision-the-WildFly-to-use-the-PostgreSQL-datasource/) Recently I needed to configure a WildFly server to use a PostgreSQL datasource for some testings, and I’d like to use the`wildfly-maven-plugin` to automate the server provision process, so I invested some time into the topic and finally made it work. To sum up what I have learned, I have put the usage example in this PR: jberet-examples / add postgresql based repository example #8 From the above pull request, we can see that the wildfly-datasources-galleon-pack feature-pack[1] is added into the plugin configuration: <feature-pack> <location>org.wildfly:wildfly-datasources-galleon-pack:8.0.1.Final</location> </feature-pack> And this layer is used: <layers> <layer>postgresql-driver</layer> </layers> The above layer will just add the PostgreSQL driver into the provisioned WildFly server, and it won’t add any datasource by default. If I run the provisioned server with the above feature-pack and layer added into the configuration with the following command in the example: $ mvn clean wildfly:dev -Ppostgres I can see from the server log that the PostgreSQL driver is enabled during the server startup process: 22:11:00,626 INFO [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 42) WFLYJCA0005: Deploying non-JDBC-compliant driver class org.postgresql.Driver (version 42.5) 22:11:00,631 INFO [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-6) WFLYJCA0018: Started Driver service with driver-name = postgresql So the feature-pack and the layer will prepare the provisioned WildFly server to connect to the PostgreSQL driver, and then we can configure the datasource in the server. In the above example, there are scripts that will add the PostgreSQL datasource[2]: xa-data-source add --name=batch_db --enabled=true --use-java-context=true --use-ccm=true --jndi-name=java:jboss/jsr352/batch_db --xa-datasource-properties={"URL"=>"jdbc:postgresql://localhost:5432/batch_db"} --driver-name=postgresql --password=123 --user-name=batch_user --same-rm-override=false --no-recovery=true /subsystem=batch-jberet/jdbc-job-repository=batch_db:add(data-source=batch_db) /subsystem=batch-jberet/:write-attribute(name=default-job-repository,value=batch_db) The above configuration add the PostgreSQL datasource I need, and then it configures the batch subsystem to use the datasource as its job store, and is used in the wildfly-maven-plugin configuration section: <scripts> <script>${configure.ds.script}</script> </scripts> The configure.ds.script property is configured in the postgresql profile: <profile> <id>postgres</id> <activation> <property> <name>postgres</name> </property> </activation> <properties> <configure.ds.script>${project.basedir}/add-postgresql-ds.cli</configure.ds.script> </properties> </profile> With the script execution during the server startup, I can see from the server log that the datasource is bound: 17:47:36,063 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-6) WFLYJCA0001: Bound data source [java:jboss/jsr352/batch_db] Please note that the script section configuration can be used with the provision goal(and it can be used in other goals as well like dev): <execution> <goals> <goal>provision</goal> </goals> </execution> If you want to use the script with the package goal: <execution> <goals> <goal>package</goal> </goals> </execution> Then you should configure the script like this: <packaging-scripts> <packaging-script> <scripts> <script>${configure.ds.script}</script> </scripts> <!-- Expressions resolved during server execution --> <resolve-expressions>false</resolve-expressions> </packaging-script> </packaging-scripts> Here is an example that is showing the above configuration method: WildFly Maven Plugin – wildfly:package#packagingScripts To sum up, if you want to play with the jberet-example as noted in above by using a PostgreSQL back-end DB, you can use podman(or Docker) to start a container that runs a PostgreSQL database: $ podman run -it -e POSTGRES_PASSWORD=123 -e POSTGRES_USER=batch_user -e POSTGRES_DB=batch_db -p 5432:5432 postgres Then run: $ mvn clean wildfly:dev -Dpostgres You should be able to play with the example. Above is the introduction to the script configuration. Besides the postgresql-driver layer, the wildfly-datasources-galleon-pack also provide other layers as described in the document[3]: postgresql-default-datasource: Provision the PostgreSQLDS non xa datasource and configures it as the default one. Depends on postgresql-datasource layer. postgresql-datasource: Provision the PostgreSQLDS non xa datasource. Depends on postgresql-driver layer. postgresql-driver: Provision the postgresql driver. This layer installs the JBoss Modules module org.postgresql.jdbc. As the document described above, the postgresql-datasource and the postgresql-default-datasource layers define a PostgreSQLDS datasource in the provisioned server by default. In addition, the default PostgreSQLDS datasource uses some built-in parameters to connect to the underlying PostgreSQL database. Here are the parameters that must be defined: POSTGRESQL_DATABASE POSTGRESQL_PASSWORD POSTGRESQL_URL POSTGRESQL_USER In the example, it also contains a profile called postgres-ds that showing the usage of the postgresql-datasource layer: <layers> <layer>postgresql-datasource</layer> </layers> In the profile it defines the following properties for the PostgreSQLDS datasource: <env> <POSTGRESQL_JNDI>java:jboss/jsr352/batch_db</POSTGRESQL_JNDI> <POSTGRESQL_DATABASE>batch_db</POSTGRESQL_DATABASE> <POSTGRESQL_PASSWORD>123</POSTGRESQL_PASSWORD> <POSTGRESQL_URL>jdbc:postgresql://localhost:5432/batch_db</POSTGRESQL_URL> <POSTGRESQL_USER>batch_user</POSTGRESQL_USER> </env> After the above configuration is used, and if the provisioned server is run by mvn clean wildfly:dev -Ppostgres-ds, we can check the datasource by using the CLI tool to connect to the WildFly server: ./jboss-cli.sh --connect [standalone@localhost:9990 /] And then we can check the configured datasource in the server: [standalone@localhost:9990 /] /subsystem=datasources:read-resource { "outcome" => "success", "result" => { "data-source" => {"PostgreSQLDS" => undefined}, "jdbc-driver" => {"postgresql" => undefined}, "xa-data-source" => undefined } } You can see the PostgreSQLDS is now the configured datasource. Then we can check the default-job-repository used by the batch-jberet subsystem: [standalone@localhost:9990 /] /subsystem=batch-jberet:read-resource { "outcome" => "success", "result" => { "restart-jobs-on-resume" => true, "security-domain" => "ApplicationDomain", "default-job-repository" => "batch_db", "default-thread-pool" => "batch", "in-memory-job-repository" => {"in-memory" => undefined}, "jdbc-job-repository" => {"batch_db" => undefined}, "thread-factory" => undefined, "thread-pool" => {"batch" => undefined} } } As the output shown above, the default-job-repository is configured to use the batch_db. Finally, we can check the definition of the batch_db: [standalone@localhost:9990 /] /subsystem=batch-jberet/jdbc-job-repository=batch_db:read-resource { "outcome" => "success", "result" => { "data-source" => "PostgreSQLDS", "execution-records-limit" => undefined } } It’s clear that the used data-source is PostgreSQLDS. This configuration is done by the enable-jdbc-job-repo.cli: /subsystem=batch-jberet/jdbc-job-repository=batch_db:add(data-source=PostgreSQLDS) /subsystem=batch-jberet/:write-attribute(name=default-job-repository,value=batch_db) And the above script is configured to be executed in the postgres-ds profile of the example: <properties> <configure.ds.script>${project.basedir}/enable-jdbc-job-repo.cli</configure.ds.script> </properties> If you check the configuration by running the example with the -Ppostgres profile. You can see the following output from the CLI: [standalone@localhost:9990 /] /subsystem=batch-jberet/jdbc-job-repository=batch_db:read-resource { "outcome" => "success", "result" => { "data-source" => "batch_db", "execution-records-limit" => undefined } } Which is expected, because we configured the data-source manually by using the postgresql-driver layer. Above is the introduction to the usage of the wildfly-datasources-galleon-pack in the maven-wildfly-plugin. An alternative way to do the configuration to use the add-resources goal in the wildfly-maven-plugin. The document of the WildFly Maven Plugin shows its usage: WildFly Maven Plugin – Adding Resources Examples With the above configuration, the datasource is deployed during the add-resource goal running process. Because this method depends on the add-resource goal, so it needs server to be run firstly, and then deploy the PostgreSQL driver(The PostgreSQL driver need to be added into the dependencies section for it to be deployed). In addition, there is another way to do the PostgreSQL datasource configuration by using the Glow[4] in the wildfly-maven-plugin. Here is the relative document to describe its usage: Integrating with a PostgreSQL database Please note that the batch-processing example[5] in the WildFly Quickstart uses the above Glow solution to do the datasource configuration, and here is a relative pull request that contains the discussion related with the Glow usage: WFLY-19790 Replaces -ds.xml deprecated filed with Jakarta’s DataSou… by emmartins · Pull Request #973 · wildfly/quickstart In the above pull request, it also contains the example usage of the jakarta.annotation.sql.DataSourceDefinition class that eliminates the usage of the CLI script to configure the datasource[6]. Personally I prefer to use the wildfly-datasources-galleon-pack to configure the datasource because I can either use the default datasource layer configuration or manually configure it by choosing different layers, but you can always choose a solution that best fits your own project’s requirement. References 1. wildfly-extras/wildfly-datasources-galleon-pack 2. https://github.com/jberet/jberet-examples/blob/main/deployment/add-postgresql-ds.cli 3. https://github.com/wildfly-extras/wildfly-datasources-galleon-pack/blob/main/doc/postgresql/README.md 4. wildfly/wildfly-glow:Galleon Layers Output from War: Automatic discover of WildFly provisioning information from an application. 5. quickstart/batch-processing at main · wildfly/quickstart 6. WFLY-19790 Replaces -ds.xml deprecated filed with Jakarta’s DataSou… by emmartins · Pull Request #973 · wildfly/quickstart ### [Next WildFly Mini Conference](/news/2024/11/12/Next-WildFly-Mini-Conference/) The WildFly team organizes the next WildFly mini conference. It will take place on Wednesday, November 20, 2024. It starts at 14:00 UTC and includes four sessions with topics related to WildFly. All sessions will be streamed live on YouTube. For more information, please take a look at the conference page at https://www.wildfly.org/conference/ We’re looking forward to seeing you there! ### [Playing with Generative AI with WildFly](/news/2024/11/04/Playing-with-Generative-AI-with-WildFly/) This blog post provides information on how to use the AI Galleon Feature-Pack to write generative AI applications. Please note that this feature-pack is currently a proof of concept and is not ready for production. You can access the release org.wildfly:wildfly-ai-galleon-pack:0.1.0 to follow the examples provided here. What’s in this feature-pack ? This feature-pack is work in progress so we will only cover what is already available as of today. It relies on configuring and exposing LangChain4J via smallrye-llm to your application. It provides a way to inject some basic elements to make creating a Retrieval-Augmented Generation (RAG) application easy. It helps by configuring and providing all the required elements for such an application. What is RAG ? As its name indicates, RAG is about retrieving relevant elements from pieces of information in your data and using them to enrich the prompt before sending the whole query (initial prompt + relevant data) to the LLM. The goal is to provide sufficient context to the LLM so that it can use those pieces of information and not hallucinate. The core elements of RAG As you can see on the schema below, you need a few elements to provide a RAG functionality: some components to get relevant pieces of information. We will focus on using a 'semantic' search approach, a.k.a. vector search, so we will need: an embedding model to create embeddings (aka semantic vectors) from the user query thus creating an embedding query. an embedding store containing all the embeddings and the associated segments of data and against which/ the embedding query will be run. a client to the LLM to send the enriched query against. RAG with LangChain4j The current feature-pack provides a basic integration with the library LangChain4J. That means that currently we are exposing the LangChain4J API to the application. So it provides: dev.langchain4j.model.embedding.EmbeddingModel dev.langchain4j.store.embedding.EmbeddingStore dev.langchain4j.rag.content.retriever.ContentRetriever dev.langchain4j.model.chat.ChatLanguageModel So you can configure instances of these objects via the WildFly management API to be injected via CDI into your application. We also support partially LangChain4J AI Services using RegisterAIService from smallrye-llm. Please note that this will change in the future as this project is quite new. The feature-pack The feature-pack is composed of a subsystem and a CDI extension. It supports several layers based on what you are trying to acheive. The list is not exhaustive and may vary in the future. The layers This feature-pack provides several layers to choose from when provisioning your server: Support for chat models to interact with a LLM via ChatModelLanguage: mistral-ai-chat-model: provides integration with Mistral AI ollama-chat-model: provides integration with Ollama openai-chat-model: provides integration with OpenAI (current configuration target Groq) Support for embedding models via EmbeddingModel: in-memory-embedding-model-all-minilm-l6-v2 in-memory-embedding-model-all-minilm-l6-v2-q in-memory-embedding-model-bge-small-en in-memory-embedding-model-bge-small-en-q in-memory-embedding-model-bge-small-en-v15 in-memory-embedding-model-bge-small-en-v15-q in-memory-embedding-model-e5-small-v2 in-memory-embedding-model-e5-small-v2-q ollama-embedding-model: using Ollama to compute embeddings. Support for embedding stores via EmbeddingStore: in-memory-embedding-store: provides integration with an in memory embedding store (for demo purpose only). weaviate-embedding-store: provides integration with Weaviate. Support for content retriever as ContentRetriever for RAG: default-embedding-content-retriever: default content retriever using an in-memory-embedding-store and in-memory-embedding-model-all-minilm-l6-v2 for embedding model. web-search-engines: provides support for Google and Tavily search engine. The layers will provide the required management resources, operations and modules. Provisioning the feature-pack For example: <!-- The WildFly plugin deploys your war to a local WildFly container --> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.wildfly.bom}</location> </feature-pack> <feature-pack> <location>org.wildfly:wildfly-ai-galleon-pack:0.1.0</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>ollama-chat-model</layer> <layer>default-embedding-content-retriever</layer> <!-- default-embedding-content-retriever provides the following layers --> <!-- <layer>in-memory-embedding-model-all-minilm-l6-v2</layer> <layer>in-memory-embedding-store</layer> --> <!-- Existing layers that can be used instead--> <!-- <layer>ollama-embedding-model</layer> <layer>openai-chat-model</layer> <layer>mistral-ai-chat-model</layer> <layer>weaviate-embedding-store</layer> <layer>web-search-engines</layer> --> </layers> <name>ROOT.war</name> <extraServerContentDirs> <extraServerContentDir>extra-content</extraServerContentDir> </extraServerContentDirs> <packagingScripts> <packaging-script> <scripts> <script>./src/scripts/configure_llm.cli</script> </scripts> </packaging-script> </packagingScripts> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> In our example we are provisioning everything via layers. The script configure_llm.cli provides sample commands to further configure the subsystem manually. Please note that all modules might not be provisionned so you need to add the corresponding layers in the pom.xml. ###Embedding Models # Adding the SentenceTransformers all-MiniLM-L6-v2 EmbeddingModel that runs within the server JVM. #/subsystem=ai/embedding-model=myembedding:add(module=dev.langchain4j.embeddings.all-minilm-l6-v2, embedding-class=dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel) # Adding an Ollama EmbeddingModel connecting to http://192.168.1.11:11434 using the model llama3:8b. #/subsystem=ai/ollama-embedding-model=test:add(base-url="http://192.168.1.11:11434", model-name="llama3:8b") ###Chat Language Models # Adding an OpenAI REST ChatLanguageModel connecting to Groq using the model llama3-8b-8192. #/subsystem=ai/openai-chat-model=mychat:add(base-url="https://api.groq.com/openai/v1", api-key="${env.GROQ_API_KEY}", log-requests="true", log-responses="true", model-name="llama3-8b-8192") ### Mistral #/subsystem=ai/mistral-ai-chat-model=test:add(api-key="${env.MISTRAL_API_KEY}", base-url="https://api.mistral.ai/v1", log-requests="true", log-responses="true", model-name="mistral-small-latest") # Adding an Ollama ChatLanguageModel connecting to http://127.0.0.1:11434 using the model llama3:8b. #/subsystem=ai/ollama-chat-model=mychat:add(model-name="llama3.1:8b", base-url="http://127.0.0.1:11434", log-requests="true", log-responses="true", temperature="0.9") #/subsystem=ai/ollama-chat-model=mychat:add(model-name="mistral", base-url="http://127.0.0.1:11434", log-requests="true", log-responses="true", temperature="0.9") #/subsystem=ai/openai-chat-model=mychat:add(base-url="https://api.groq.com/openai/v1", api-key="${env.GROQ_API_KEY}",model-name="llama3:8b") ###Embedding Stores # Adding Weaviate as an embedding store # podman run --rm -p 8090:8080 -p 50051:50051 -e AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED="true" -v $SOME_PATH/volumes/weaviate/_data:/data --name=weaviate cr.weaviate.io/semitechnologies/weaviate:1.24.10 #/socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=weaviate:add(host=localhost, port=8090) #/subsystem=ai/weaviate-embedding-store=mystore:add(socket-binding=weaviate, ssl-enabled=false, object-class=Simple, metadata=[url,language,parent_url,file_name,file_path,title,subtitle]) #/subsystem=logging/logger=io.weaviate.client.client:add(level=TRACE) # Adding in memory embedding store loading form a json file #/subsystem=ai/in-memory-embedding-store=mystore:add(file=/home/ehugonne/dev/AI/crawler/crawler/wildfly-admin-embeddings.json) ###Content retrievers # Adding a content retriever using embeddings #/subsystem=ai/embedding-store-content-retriever=myretriever:add(embedding-model=myembedding,embedding-store=mystore, max-results=2, min-score=0.7) # Adding a content retriever using Tavily search engine #/subsystem=ai/web-search-content-retriever=myretriever:add(tavily={api-key=${env.TAVILY_API_KEY}, base-url=https://api.tavily.com, connect-timeout=20000, exclude-domains=[example.org], include-domains=[example.com], include-answer=true}) Putting it all together: The WebChat example To put it all together we are going to execute a sample RAG application with a web interface. It will use embeddings that were previously computed using WildFly documentation. If you want to check the code of the application used to create embeddings out of WildFly documentation and store the results you can look at https://github.com/ehsavoie/crawler. It can be used to fill either a JSON file or a weaviate embedding store.The embeddings were computed using the All-MiniLM-L6-v2 EmbeddingModel, so we need to use the same model in our RAG application. This embedding model will be used to compute the embedding of the user query and then the application will search for the nearest contents in the in-memory embedding store. The content retriever will retrieve and append those contents to the user query to create the prompt that will be sent to the LLM we are connected to, via the ChatLanguageModel. Running Ollama locally podman run -d --rm --name ollama --replace --pull=always -p 11434:11434 -v ollama:/root/.ollama --stop-signal=SIGKILL docker.io/ollama/ollama Execute the following command to select the expected model (type /bye to quit the ollama prompt): podman exec -it ollama ollama run llama3.1:8b Configuring the server We will use the following layers: default-embedding-content-retriever ollama-chat-model So the pom.xml should look like this: <!-- The WildFly plugin deploys your war to a local JBoss AS container --> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.wildfly.bom}</location> </feature-pack> <feature-pack> <location>org.wildfly:wildfly-ai-galleon-pack:0.1.0</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>default-embedding-content-retriever</layer> <layer>ollama-chat-model</layer> </layers> <name>ROOT.war</name> <packagingScripts> <packaging-script> <scripts> <script>./src/main/resources/scripts/configure_llm.cli</script> </scripts> </packaging-script> </packagingScripts> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> The code The code itself is quite straightforward: @ServerEndpoint(value = "/websocket/chatbot", configurator = org.wildfly.ai.websocket.CustomConfigurator.class) public class RagChatBot { @Inject @Named(value = "ollama") ChatLanguageModel chatModel; @Inject @Named(value = "embedding-store-retriever") ContentRetriever retriever; private static final String PROMPT_TEMPLATE = "You are a WildFly expert who understands well how to administrate the WildFly server and its components\n" + "Objective: answer the user question delimited by ---\n" + "\n" + "---\n" + "{{userMessage}}\n" + "---" + "\n Here is some data to help you:\n" + "{{contents}}"; @OnMessage public String sayHello(String question, Session session) throws IOException { ChatMemory chatMemory = MessageWindowChatMemory.builder().id(session.getUserProperties().get("httpSessionId")).maxMessages(3).build(); ConversationalRetrievalChain chain = ConversationalRetrievalChain.builder() .chatLanguageModel(chatModel) .chatMemory(chatMemory) .retrievalAugmentor(createBasicRag()) .build(); String result = chain.execute(question).replace("\n", "<br/>"); return result; } private RetrievalAugmentor createBasicRag() { return DefaultRetrievalAugmentor.builder() .contentRetriever(retriever) .contentInjector(DefaultContentInjector.builder() .promptTemplate(PromptTemplate.from(PROMPT_TEMPLATE)) .build()) .queryRouter(new DefaultQueryRouter(retriever)) .build(); } } The dev.langchain4j.rag.content.retriever.ContentRetriever called embedding-store-retriever defined in the subsystem is injected into our WebSocket endpoint using the the @Named annotation. It is used to instantiate a dev.langchain4j.rag.RetrievalAugmentor which is in charge of retrieving the contents and enriching the prompt with them. In the same way, the dev.langchain4j.model.chat.ChatLanguageModel called ollama defined in the subsystem is injected into our WebSocket endpoint using the @Named annotation. With those two elements, a dev.langchain4j.chain.ConversationalRetrievalChain is created and used to interact with the LLM and send back the answer to the client using the WebSocket. The final code of the application is a bit more complex than what is exposed here as it tries to keep some context between user queries. Building and Running the application First you need to clone it from https://github.com/ehsavoie/webchat and select the branch 0.1.x. In a console execute the following commands: git clone https://github.com/ehsavoie/webchat.git cd webchat git checkout 0.1.x mvn clean install ./target/server/bin/standalone.sh Now that the server is started, you can access the application. You need to open the WebSocket connection and then you can ask your questions. For example you can ask "How do you configure a connection factory to a remote Artemis server ?". If you look into the server log file you will see the effective prompt sent to the LLM as well as the answer from it. Going further This feature-pack is currently just a proof of concept and is quite limited. If you look at the code you can easily tweak it to try several scenarios like using a Weaviate Embedding Store with metadata. Also you can try OpenAI or Groq instead of Ollama. All the source code of the feature-pack is available on Github and can be improved by extending the components that may be of use. ### [Save the Date: WildFly Mini Conference on Nov 20th](/news/2024/10/28/Save-the-Date-WildFly-Mini-Conference-on-Nov-20th/) Hello, WildFly Community! We are happy to announce that the next WildFly Mini Conference is scheduled for November 20th, 2024! Building on the success of our previous mini conference event, we are eager to bring together our community for another day of insightful discussions and online networking. As you know, a few weeks ago we sent a request for feedback. Based on the feedback we received, the most voted topics were: Jakarta EE11: Dive deep into the latest advancements and explore how Jakarta EE11 is shaping the future of enterprise Java. Latest News on WildFly: Stay updated with the latest news on WildFly DevOps Related Topics: Discover best practices and innovative approaches to integrating WildFly within your DevOps pipelines. We are committed to not only covering these popular topics but also addressing the suggestions submitted by our community. Your input is invaluable, and we’re dedicated to crafting a conference agenda that reflects your interests and needs. Stay tuned for upcoming announcements regarding the detailed schedule and our lineup of expert speakers. We are looking forward to another successful event and can’t wait to connect with all of you on November 20th! Best regards, Flavia ### [WildFly 35 moves to SE 17, drops SE 11](/news/2024/10/28/WildFly-35-moves-to-SE-17-drops-SE-11/) As I noted in the WildFly 34 release announcement, our plan is that WildFly 34.x will be the final release series that would run on Java SE 11. Beginning with the WildFly 35 release, the minimum Java SE version for a WildFly server will be SE 17. We have now executed on this plan by updating the WildFly 'main' branch to build SE 17 binaries. If you are consuming WildFly nightly builds or building WildFly snapshots, you will need to move to an SE 17 baseline in those workflows. Any WildFly 35 releases will require SE 17 as a minimum. Note We recommend that you run WildFly on SE 21, as that is the latest supported LTS release. Note The WildFly 34.0.1 release will support SE 11. If we do any further releases in the 34.x series, they will support SE 11. The primary driver for this change is the fact that libraries we integrate are beginning to withdraw SE 11 support in their feature development branches and the availability of bug fix releases in older branches is increasingly uncertain. We also don’t wish to continue to act as an innovation constraint on projects we integrate that are looking to move past SE 11. We recognize that changing SE versions can be a significant task for some users, so we didn’t make this decision lightly. I hope that the fact that WildFly has supported SE 17 since the WildFly 25 release has made it easier for our users to prepare for this change. Best regards, Brian ### [WildFly 34 is released!](/news/2024/10/17/WildFly-34-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 34.0.0.Final releases are available for download at https://wildfly.org/downloads. New and Notable This quarter we had a heavy focus on WildFly Preview. WildFly Preview now includes support for Jakarta Data 1.0. This feature is provided at the preview stability level. WildFly Preview now supports MicroProfile REST Client 4.0. WildFly Preview now supports MicroProfile Telemetry 2.0. As part of a general reorganization of our end user BOMs, we introduced new BOMs for WildFly Preview. org.wildfly.bom:wildfly-ee-preview is the WildFly Preview analogue to the existing standard WildFly org.wildfly.bom:wildfly-ee BOM. org.wildfly.bom:wildfly-expansion-preview is the WildFly Preview analogue to the standard WildFly BOM formerly known as org.wildfly.bom:wildfly-microprofile, now renamed to org.wildfly.bom:wildfly-expansion. Previously under WFCORE-6825 four system properties with default values were added to enable configuration of constraints affecting the HTTP management interface. In WildFly 35 four new attributes have been added to the HTTP management interface configuration (backlog, connection-high-water, connection-low-water, no-request-timeout) to allow these constraints to be configured directly in the management model. This feature is provided at the community stability level. We updated our Hibernate ORM version from the 6.4 series to 6.6. Along with that we updated Hibernate Search from the 7.1 series to 7.2. Supported Specifications Jakarta EE Standard WildFly 34 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly is EE 10 Platform, Web Profile and Core Profile compatible when running on Java SE 11, Java SE 17 and Java SE 21. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence Jakarta EE 10 Full Platform SE 11 SE 17 SE 21 Jakarta EE 10 Web Profile SE 11 SE 17 SE 21 Jakarta EE 10 Core Profile SE 11 SE 17 SE 21 MicroProfile WildFly supports numerous MicroProfile specifications. Because we no longer support MicroProfile Metrics, WildFly 34 cannot claim to be a compatible implementation of the MicroProfile 6.1 specification. However, WildFly’s MicroProfile support includes implementations of the following specifications in our "full" (e.g. standalone-full.xml) and "default" (e.g standalone.xml) configurations as well as our "microprofile" configurations (e.g. standalone-microprofile.xml): MicroProfile Technology WildFly Full/Default Configurations WildFly MicroProfile Configuration MicroProfile Config 3.1 X X MicroProfile Fault Tolerance 4.0  —  X MicroProfile Health 4.0  —  X MicroProfile JWT Authentication 2.1 X X MicroProfile LRA 2.0  —  X MicroProfile OpenAPI 3.1  —  X MicroProfile Reactive Messaging 3.0  —   —  MicroProfile Reactive Streams Operators 3.0  —   —  MicroProfile Rest Client 3.0 X X MicroProfile Telemetry 1.1  —  X Compatibility evidence for the above specifications that are part of MicroProfile 6.1 can be found in the WildFly Certifications repository on GitHub. As noted in the New and Notable section, instead of the version listed above, WildFly Preview 34 now supports later releases of two MicroProfile specifications: MicroProfile REST Client 4.0 MicroProfile Telemetry 2.0 WildFly Preview, EE 11 and SE 17 As I noted in the WildFly 32 release announcement, beginning with that release we are using WildFly Preview to provide a look at what we’re doing for Jakarta EE 11 support. EE 11 won’t go GA before later this year, and we don’t expect standard WildFly to support EE 11 before the WildFly 36 release. But there are milestone, Release Candidate and Final releases of many EE 11 specs and implementations available, so we are providiong those in WildFly Preview. This means for a number of EE APIs, WildFly Preview no longer provides an EE 10 compatible implementation. However, for a number of specifications that are planning changes for EE 11 we are still offering the EE 10 variant. In future releases we’ll shift those to the EE 11 variants. As a result of this shift to EE 11 APIs, WildFly Preview no longer supports running on Java SE 11. If you want to use WildFly Preview you’ll need to use SE 17 or higher. A number of EE 11 APIs no longer produce SE 11 compatible binaries, which means an EE 11 runtime can no longer support SE 11. The following table lists the various Jakarta EE technologies offered by WildFly Preview 34, along with information about which EE platform version the specification relates to. Note that a number of Jakarta specifications are unchanged between EE 10 and EE 11, while other EE technologies that WildFly offers are not part of EE 11. Jakarta EE Technology WildFly Preview Version EE Version Jakarta Activation 2.1 10 & 11 Jakarta Annotations 3.0 11 Jakarta Authentication 3.0 10 Jakarta Authorization 3.0 11 Jakarta Batch 2.1 10 & 11 Jakarta Concurrency 3.1 11 Jakarta Connectors 2.1 10 & 11 Jakarta Contexts and Dependency Injection 4.1 11 Jakarta Data (preview stability only) 1.0 11 2 Jakarta Debugging Support for Other Languages 2.0 10 & 11 Jakarta Dependency Injection 2.0 10 & 11 Jakarta Enterprise Beans 4.0 10 & 11 Jakarta Enterprise Web Services 2.0 10 1 Jakarta Expression Language 6.0 11 Jakarta Faces 4.1 11 Jakarta Interceptors 2.2 11 Jakarta JSON Binding 3.0 10 & 11 Jakarta JSON Processing 2.1 10 & 11 Jakarta Mail 2.1 10 & 11 Jakarta Messaging 3.1 10 & 11 Jakarta MVC (preview stability only) 2.1 N/A 3 Jakarta Pages 3.1 10 Jakarta Persistence 3.2.0 11 Jakarta RESTful Web Services 4.0 11 Jakarta Security 4.0.0 11 Jakarta Servlet 6.1.0 11 Jakarta SOAP with Attachments 3.0 10 1 Jakarta Standard Tag Library 3.0 10 & 11 Jakarta Transactions 2.0 10 & 11 Jakarta Validation 3.1.0 11 Jakarta WebSocket 2.2.0 11 Jakarta XML Binding 4.0 10 1 Jakarta XML Web Services 4.0 10 1 Notes: This Jakarta EE 10 technology is not part of EE 11 but is still provided by WildFly. Jakarta Data is a new specification in EE 11. Jakarta MVC is not part of the Jakarta EE Platform or the Web or Core Profile. Java SE Support Our recommendation is that you run WildFly 34 on Java SE 21, as that is the latest LTS JDK release where we have completed the full set of testing we like to do before recommending a particular SE version. WildFly 34 also is heavily tested and runs well on Java 17 and Java 11. Our recommendation of SE 21 over earlier LTS releases is solely because as a general principle we recommend being on later LTS releases, not because of any problems with WildFly on SE 17 or SE 11. However, one reason to use later SE versions is because it gets you ahead of the curve as WildFly and other projects begin to move on from supporting older SE releases. This is certainly happening, and we do not intend to support SE 11 in WildFly in WildFly 35! Warning The WildFly 34 series will be the last to support SE 11, so if you are running WildFly on SE 11 you should move to SE 17 or 21 as soon as possible. WildFly Preview no longer supports SE 11, as the baseline for Jakarta EE 11 is SE 17. While we recommend using an LTS JDK release, I do believe WildFly runs well on SE 23. By runs well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. Please note that WildFly runs in classpath mode. Incompatible Changes We changed the Maven artifactId of the org.wildfly.bom:wildfly-microprofile user BOM to org.wildfly.bom:wildfly-expansion, so users of this BOM will need to update their poms. This BOM is intended to help developers develop applications that can run in a server provisioned using the wildfly feature-pack, but which can’t run in a server only using its wildfly-ee feature-pack dependency. (The org.wildfly.bom:wildfly-ee BOM is used for the wildfly-ee feature-pack dependencies.) For a while now the additional functionality in the wildfly feature-pack has gone beyond MicroProfile, to include things like Micrometer, so we’ve updated to the more general 'expansion' term that we use to describe this feature-pack. Release Notes The full WildFly 34 release notes are available in GitHub. Issues fixed in the underlying WildFly Core 26.0.0 and 26.0.1 releases are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. And, with that, I’m moving on to what I think will be a very busy WildFly 35! Best regards, Brian ### [Introducing Jakarta Data in WildFly Preview](/news/2024/10/10/Introducing-Jakarta-Data-in-WildFly-Preview/) I’m excited that in the 34 Beta release we were able to introduce support for Jakarta Data into WildFly Preview. It was a bit of an unexpected last minute thing that we were able to do this, which left us without time to much in the way of documentation. We’ll correct that for WildFly 35, but in the meantime I’ll use this blog post as a way to introduce the basics. Note In the 34 release, Jakarta Data is only available in WildFly Preview, and not in standard WildFly. It is provided at the preview stability level, which is enabled out-of-the-box in WildFly Preview. Jakarta Data Overview My purpose in this post isn’t to dive much into the details of Jakarta Data itself; there are other resources that do a good job of covering that. I want to focus here on how the WildFly Preview and Hibernate ORM integration of Jakarta Data works, so users can get going with using Jakarta Data in a WildFly server. So this next bit is very brief and high level. Jakarta Data brings the repository pattern to the Jakarta ecosystem. As explained in the Jakarta Data 1.0 Specification a repository is a mediator between an application’s domain logic and the underlying data storage, be it a relational database, NoSQL database, or any other data source. In Jakarta Data, a Repository provides a structured and organized way to interact with data. It abstracts data storage and retrieval complexities, allowing you to work with domain-specific objects and perform common operations on data without writing low-level database queries. An application developer defines a repository by providing an interface annotated with the Jakarta Data @Repository annotation. The repository interface declares methods used for data retrieval and modification of a particular entity type. A repositoy interface can include different methods that deal with different entity types, giving application authors flexibility to define repositories that fit the needs of their application domain. Following is an example repository: @Repository interface Publishing { @Find Book book(String isbn); @Find Author author(String ssn); @Insert void publish(Book book); @Insert void create(Author author); // query methods ... } Book and Author are typical entity classes. The repository interface methods are annotated with various Jakarta Data annotations (@Insert, @Find, etc) that define the expected persistence behavior of the method. There’s much more to the Jakarta Data programming model than this; for all the details see: The Jakarta Data 1.0 specification The Hibernate Data Repositories documentation Gavin King’s excellent blog posts on Jakarta Data A Jakarta Data implementation like WildFly Preview can support one or more Jakarta Data providers. A provider understands one or more Java annotation types that are used to define entities, and it understands how to interact with a particular type of back end datastore. WildFly Preview’s Jakarta Data implementation supports the Hibernate Data Repositories provider, which uses Hibernate ORM to interact with a variety of different relational databases. Hibernate Data Repositories supports the jakarta.persistence.Entity annotation as the mechanism for application authors to define entities. Using Hibernate Data Repositories in Your Application There are two key things to understand in order to use WildFly Preview’s Hibernate Data Repositories provider: How to configure build time generation of the implementation of your @Repository interfaces. How to configure the runtime behavior of the Hibernate ORM instance that will interact with the database. Build-time Generation of Repository Implementations An application author using Jakarta Data simply writes an interface for their repository, but of course for that to work at runtime there must be an actual implementation of that interface. It’s the responsibility of the Jakarta Data provider to provide that implementation. Hibernate Data Repositories does this by generating the implementation classes as part of the build of your application. So, to use Jakarta Data with WildFly Preview you need to configure the generation of those classes as part of your application build. In a Maven build this is done by configuring the Maven compiler plugin to use the org.hibernate.orm:hibernate-jpamodelgen artifact as an annotation processor: <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <!-- 3.12 or later is necessary for proper dependency management in annotationProcessorPaths --> <version>3.12.1</version> <configuration> <annotationProcessorPaths> <path> <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-jpamodelgen</artifactId> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build> Note that there is no version element in the org.hibernate.orm:hibernate-jpamodelgen declaration above. You could provide one, but best practice is to control the version in your pom’s dependencyManagement. Importing the org.wildfly.bom:wildfly-ee-preview-with-tools BOM lets you align the version of Hibernate artifacts with what’s used in your target WildFly Preview runtime: <dependencyManagement> <dependencies> <!-- importing the ee-with-tools BOM adds specs and other useful artifacts as managed dependencies --> <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>wildfly-ee-preview-with-tools</artifactId> <version>34.0.0.Beta1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> Warning Some users may have learned to configure Hibernate annotation processing by declaring org.hibernate.orm:hibernate-jpamodelgen as a provided dependency in their pom. With the Hibernate version used with WildFly, this will likely fail. Use the maven-compiler-plugin configuration approach described above. If you’re using Gradle, you’ll need to use annotationProcessor: annotationProcessor 'org.hibernate.orm:hibernate-jpamodelgen:6.6.1' The generated repository implementation classes internally use various Hibernate ORM classes, so to compile the generated code you’ll need to add a dependency on Hibernate: <dependencies> <dependency> <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-core</artifactId> <scope>provided</scope> </dependency> </dependencies> Configuring Hibernate ORM Under the covers, your repository implementation will use Hibernate ORM to interact with the database. You configure ORM by providing a META-INF/persistence.xml file, the same as you would with a Jakarta Persistence application: <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd" version="3.0"> <persistence-unit name="Publisher"> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <properties> <property name="hibernate.hbm2ddl.auto" value="create"/> <property name="hibernate.show_sql" value="false"/> </properties> </persistence-unit> </persistence> The jta-data-source value should match the value of the jndi-name attribute in a datasource you’ve declared in the WildFly Preview datasources or datasources-agroal subsystem configuration. Configuring WildFly Preview to Support Jakarta Data Jakarta Data in WildFly Preview is configured using the new jakarta-data subsystem. This subsystem isn’t included in any of WildFly Preview’s out-of-the-box configuration files, so to use it you’ll need to add it to your configuration. If you’re using a complete WildFly Preview installation, like the ones available from the WildFly downloads page, then you can use the JBoss CLI to add the Jakarta Data extension and subsystem to your configuration: $ /extension=org.wildfly.extension.jakarta.data:add $ /subsystem=jakarta-data:add If you’re using Galleon to provision a slimmed WildFly Preview installation, you’ll need to specify the jakarta-data Galleon layer. For example if you are using the WildFly Maven Plugin to provision a server that supports a Jakarta REST application interacting with a Postgresql database, the configuration in your application’s pom.xml might look like this: <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <configuration> <feature-packs> <feature-pack> <location>wildfly-preview@maven(org.jboss.universe:community-universe)</location> </feature-pack> <feature-pack> <groupId>org.wildfly</groupId> <artifactId>wildfly-datasources-preview-galleon-pack</artifactId> <version>8.0.1.Final</version> </feature-pack> </feature-packs> <layers> <layer>jaxrs-server</layer> <layer>jakarta-data</layer> <layer>postgresql-datasource</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> The subsystem itself is very simple and doesn’t expose any configuration attributes. Note that for the jakarta-data subsystem to work, the jpa subsystem must be present in your configuration. It’s present in our out-of-the-box configurations and will be included if you provision a server using the jakarta-data Galleon layer. Please try out Jakarta Data in WildFly Preview and give us your feedback! We’ll continue to work on the integration, with a goal of including it in standard WildFly in one of the next couple of releases. ### [Announcement for the Upcoming WildFly Mini Conference!](/news/2024/10/07/Announcement-for-the-Upcoming-WildFly-Mini-Conference/) = Hello, WildFly Community! We are excited to share that after the success of our first WildFly Mini Conference earlier this year, we are planning a new edition for November! The inaugural conference was an incredible experience, bringing together WildFly developers and the entire community for productive discussions and learning. We are eager to replicate this success, and we want your help to make the next event even better. We would love to hear which topics you would like to see covered in the conference sessions. Your feedback is crucial to us, and we want to ensure the event meets everyone’s expectations and interests. Please take a moment to share your suggestions by filling out our form. We will be collecting responses until next Monday, October 14th. We look forward to hearing from you and seeing everyone at the next WildFly Mini Conference! Best regards, Flavia ### [Debug a provisioned WildFly server with the help of the wildfly-maven-plugin](/news/2024/10/04/Debug-a-provisioned-WildFly-server-with-the-help-of-the-wildfly-maven-plugin/) Sometimes I need to debug my project in a customized WildFly server. The requirements are: I need to use a specific version of WildFly server. I need to override the version of some artifacts used in modules inside the WildFly server. I need to run the WildFly server in debug mode, so I can use IDE tools to remotely debug the code. With the use of the wildfly-maven-plugin, the above goals can be achieved in an automated way. Here is an example of the configuration to show the use of the plugin to achieve the above goals: jberet-examples/deployment/pom.xml at main · jberet/jberet-examples The wildfly-maven-plugin configuration in the above pom.xml looks like this: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.maven.wildfly.plugin}</version> <configuration> <provisioning-dir>${jboss.home}</provisioning-dir> <galleon-options> <jboss-fork-embedded>${galleon.fork.embedded}</jboss-fork-embedded> </galleon-options> <feature-packs> <feature-pack> <groupId>${server.test.feature.pack.groupId}</groupId> <artifactId>${server.test.feature.pack.artifactId}</artifactId> <version>${wildfly.version}</version> <inherit-configs>false</inherit-configs> <included-configs> <config> <model>standalone</model> <name>standalone-full.xml</name> </config> <config> <model>standalone</model> <name>standalone.xml</name> </config> </included-configs> <excluded-packages> <name>docs.schema</name> <name>appclient</name> <name>domain</name> </excluded-packages> </feature-pack> </feature-packs> <channels> <channel> <manifest> <groupId>org.jberet</groupId> <artifactId>jberet-channel-manifest</artifactId> <version>${version.jberet}</version> </manifest> </channel> </channels> </configuration> ... </plugin> In the above configuration, the feature-packs section specifies the feature-packs to be used by the provisioned server(there is no default feature-pack that would be used if this wasn’t set), and the channels section is using the jberet-channel-manifest channel to override the batch-jberet module to be used in the provisioned server. Please note that you need to use the channels with the feature-packs together. Here are the properties used by the configuration: <properties> ... <version.jberet>3.0.0.Final</version.jberet> ... <version.maven.wildfly.plugin>5.0.1.Final</version.maven.wildfly.plugin> <jboss.home>${project.build.directory}${file.separator}wildfly</jboss.home> <wildfly.version>33.0.2.Final</wildfly.version> <server.test.feature.pack.groupId>org.wildfly</server.test.feature.pack.groupId> <server.test.feature.pack.artifactId>wildfly-ee-galleon-pack</server.test.feature.pack.artifactId> ... </properties> In the above way, I can define the WildFly version to be used and the JBeret version to be used in the provisioned WildFly server. The jberet-channel-manifest is provided by the JBeret project itself: jsr352/jberet-manifest at main · jberet/jsr352 The above subproject provides the JBeret module that can be used in the WildFly server. It uses the concept of WildFly Channel to achieve this goal. It can be used to override the version of some artifacts used in modules inside the WildFly server. I won’t explain the concept of WildFly Channel in this blog post. If you are interested in this topic, these articles are worth reading: An Introduction To The Prospero Usage WildFly Glow, an evolution of WildFly provisioning What’s new in WildFly provisioning With the above configuration, the 3.0.0.Final version of that manifest specifies use of JBeret 3.0.0 while WildFly 33.0.2 used 2.2.1. If I run the following command in the above example project, the output showing the relative provision process: $ mvn wildfly:run ... [INFO] Resolving channel metadata from Maven artifact org.jberet:jberet-channel-manifest:3.0.0.Final [INFO] Provisioning server in /Users/weli/works/jberet-examples/deployment/target/wildfly [INFO] Resolving feature-packs [INFO] Installing packages [INFO] 6 of 523 (1.1%) [INFO] Resolving artifacts [INFO] 11 of 491 (2.2%) ... [INFO] Generating configurations [INFO] Delayed generation, waiting... [INFO] Resolving channel metadata from Maven artifact org.jberet:jberet-channel-manifest:3.0.0.Final ... [INFO] --- wildfly:5.0.1.Final:start (wildfly-start) @ batch-deployment-examples --- [INFO] Provisioning default server in /Users/weli/works/jberet-examples/deployment/target/server Downloading from jboss-public-repository-group: https://repository.jboss.org/nexus/content/groups/public/org/wildfly/wildfly-galleon-pack/33.0.2.Final/wildfly-galleon-pack-33.0.2.Final.zip ... From the above output, we can see that org.jberet:jberet-channel-manifest:3.0.0.Final is used for provision, and the wildfly-galleon-pack-33.0.2.Final.zip is downloaded. If I check the generated WildFly server directory, I can see that JBeret 3.0.0.Final is used in the provisioned WildFly server: $ pwd /Users/weli/works/jberet-examples/deployment/target/wildfly $ find modules -name "*jberet*" modules/system/layers/base/org/wildfly/extension/batch/jberet modules/system/layers/base/org/wildfly/extension/batch/jberet/main/wildfly-batch-jberet-33.0.2.Final.jar modules/system/layers/base/org/jberet modules/system/layers/base/org/jberet/jberet-core modules/system/layers/base/org/jberet/jberet-core/main/jberet-core-3.0.0.Final.jar To run the provisioned WildFly server in debug mode, the wildfly-maven-plugin provide options to support the debug mode. To check the usages of wildfly-maven-plugin, I can run the following command in the above example project to do so: $ mvn wildfly:help -Ddetail=true The above command will output the full document of the wildfly-maven-plugin. Following are the relative parts of the document: wildfly:dev Description: Starts a standalone instance of WildFly and deploys the application to the server. The deployment type must be a WAR. Once the server is running, the source directories are monitored for changes. If required the sources will be compiled and the deployment may be redeployed. Note that changes to the POM file are not monitored. If changes are made the POM file, the process will need to be terminated and restarted. Note that if a WildFly Bootable JAR is packaged, it is ignored by this goal. Implementation: org.wildfly.plugin.dev.DevMojo Language: java Bound to phase: package Available parameters: ... debug (Default: false) User property: wildfly.debug Starts the server with debugging enabled. debugHost (Default: *) User property: wildfly.debug.host Sets the hostname to listen on for debugging. An * means all hosts. debugPort (Default: 8787) User property: wildfly.debug.port Sets the port the debugger should listen on. debugSuspend (Default: false) User property: wildfly.debug.suspend Indicates whether the server should suspend itself until a debugger is attached. ... wildfly:run Description: Starts a standalone instance of WildFly and deploys the application to the server. This goal will block until cancelled or a shutdown is invoked from a management client. Note that if a WildFly Bootable JAR is packaged, it is ignored by this goal. Implementation: org.wildfly.plugin.server.RunMojo Language: java Before this goal executes, it will call: Phase: 'package' Available parameters: ... debug (Default: false) User property: wildfly.debug Starts the server with debugging enabled. debugHost (Default: *) User property: wildfly.debug.host Sets the hostname to listen on for debugging. An * means all hosts. debugPort (Default: 8787) User property: wildfly.debug.port Sets the port the debugger should listen on. debugSuspend (Default: false) User property: wildfly.debug.suspend Indicates whether the server should suspend itself until a debugger is attached. As the document written in above, both the wildfly:dev and the wildfly:run goals support the debug mode, and the property to activate it is the wildfly.debug option. Note If you want to check the help text of a specific goal of the plugin, taking the wildfly:dev goal for example, you can use this command to do so: mvn wildfly:help -Ddetail=true -Dgoal=dev In addition, instead of reading the embedded help text, you can also refer to the online documentation of wildfly-maven-plugin here: WildFly Maven Plugin (wildfly-maven-plugin) With the above information, I can run the provisioned WildFly server in debug mode: $ mvn wildfly:run -Dwildfly.debug=true And from the server output I can see the debug options are added: [INFO] JAVA_OPTS : -Xms64m -Xmx512m -Djava.net.preferIPv4Stack=true -Djava.awt.headless=true -Djboss.modules.system.pkgs=org.jboss.byteman -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8787 --add-exports=java.base/sun.nio.ch=ALL-UNNAMED --add-exports=jdk.unsupported/sun.reflect=ALL-UNNAMED --add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED --add-modules=java.se As the output shows above, the debug options are added and the remote debug port is set as 8787 by default. This means the WildFly server is ready to accept the remote debug requests. In addition, the customized version of the WildFly server codebase and the overridden version of the JBeret module codebase can be used for debugging now. I won’t introduce the way to use an IDE to debug the WildFly server in this blog post. If you’d like to learn about the way to do so, I have written a personal blog post on this topic before: Troubleshooting the Wildfly startup process Enjoy :D ### [WildFly 34 Beta is released!](/news/2024/09/26/WildFly-34-Beta-is-released/) I’m pleased to announce that the new WildFly 34.0.0.Beta1 release is available for download at https://wildfly.org/downloads. As can be seen from the Release Notes a lot of maintenance and component upgrades have been included in this release but I would also like to call out some of the following highlights: [WFLY-19306] — move from ORM 6.4.x to 6.6.x [WFLY-19632] — Hibernate Search 7.1.x to 7.2.x [WFLY-19298] — FasterXML Jackson from 2.15.x to 2.17.x Within the WildFly Preview distribution we also have: [WFLY-19397] — Jakarta Data [WFLY-19589] — MP REST Client 4.0 [WFLY-19464] — User boms for WildFly Preview Please try out this release and let us know how you get on. ### [Hacktoberfest 2024](/news/2024/09/23/Hacktoberfest-2024/) Hacktoberfest is back, offering the perfect opportunity to showcase your Open Source expertise. This annual event brings together developers at all levels—from seasoned professionals to eager newcomers—in a unified effort to contribute to Open Source projects and foster collaboration within the global software community. Join us for this month-long celebration of innovation and teamwork, as we work together to make meaningful contributions, one pull request at a time. What is Hacktoberfest? Hacktoberfest is a month-long event in October that encourages Open Source contributors and developers worldwide to give back to the global tech community. It’s a fantastic opportunity for the contributors to showcase their skills and get to know about other Open Source communities. To participate you simply need to: Register: Sign up on the official Hacktoberfest website, anytime between September 23rd and October 31st to get started. Discover Projects: Explore the Hacktoberfest website to find a project that sparks your interest. You can also check out the curated list of projects we’ve prepared for you. Follow the Project guidelines: Read the respective Contributing Guide, Code of Conduct, and follow best practices like forking the repository, creating a new branch, and making a meaningful contribution. Contribute: Select an issue that matches your interest and start working on it. Choose an issue that aligns with your interests and begin contributing. Your goal is to submit four well-crafted pull or merge requests between October 1st and October 31st. For these to count toward your total, they must be accepted by the project maintainers. Rewards: Upon registering for Hacktoberfest, you’ll earn a digital badge, which will be upgraded as you complete and have four of your pull or merge requests accepted throughout the event. Get started with our projects This list features an exciting variety of projects under the WildFly umbrella, just waiting for your contributions. Whether your expertise lies in Java, Docker, or Ansible, there’s a project here for everyone to dive into and make an impact. WildFly: WildFly is a powerful, modular, and lightweight application server that empowers you to build amazing applications. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. WildFly Elytron: WildFly Elytron is a set of APIs and SPIs for application server security and client side security. Within the WildFly server, WildFly Elytron is used to secure applications deployed to the server as well as management access to the server. It is a standalone library that can also be used in other Java server environments. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. For more details, check out WildFly Elytron’s Hacktoberfest page. Ansible Middleware: Ansible Middleware is a suite of supported content that combines the power of Ansible automation with Red Hat’s Middleware portfolio. It allows organizations to meet their business demands and automate the installation, configuration, and management of Enterprise Middleware. Here are the GitHub repositories, Contributing Guide, and Hacktoberfest Issues link. Undertow: Undertow is a versatile and high-performance web server that provides both blocking and non-blocking APIs based on NIO. Its modular architecture allows you to build a web server tailored to your needs, from a full Java EE servlet container to a low-level non-blocking handler. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. WildFly Core: WildFly Core provides the core runtime that is used by the WildFly application server. This includes modular class loading, unified management including domain mode, basic deployment architecture, and a CLI for management. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. Narayana: Narayana is a transactions toolkit that provides support for applications using various standards-based transaction protocols. It’s an essential component of the WildFly application server and continues to be developed as a standalone transaction manager. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. Intersmash: Intersmash is a Java library that makes it easy to automate the provisioning and execution of tests in cloud-native environments. It helps the user prototype and test complex interoperability scenarios on kubernetes compliant cloud-native environments and platforms, most notably OpenShift. (Other Kubernetes implementations will be supported in the future.) Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. PatternFly Java: PatternFly Java is a 💯 Java implementation of PatternFly without any JavaScript dependencies. Its goal is to provide an easy-to-use, elegant, and efficient API to build complex web applications with PatternFly in Java. PatternFly Java works with both GWT and J2CL. PatternFly Java is used for the next-gen WildFly management console. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. WildFly GitHub Bot: WildFly GitHub Bot is a small easy-to-start application that we utilize to manage the workflow of WildFly’s Pull Requests. It, for instance, requires reviews from relevant reviewers or sets labels based on the PR’s state. We have a lot of ideas that you can start implementing. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. WildFly Docker Images: The WildFly Docker project provides Docker images for running the WildFly application server with support for various JDK versions. It allows easy customization of server configurations, application deployment, and management in both standalone and domain modes. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. Berg: Berg is a test-suite for the HAL Management Console based on Cypress UI test automation. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. How to reach out to us for Hacktoberfest related queries? Please join our Hacktoberfest Zulip chatroom and reach out to us if you have any queries or need assistance. We’re here to ensure a smooth journey for you. Let’s make Hacktoberfest 2024 the most exciting and impactful one yet! Every contribution counts, and together, we can create something truly meaningful. ### [WildFly 33.0.2 is released!](/news/2024/09/17/WildFly-33-0-2-is-released/) WildFly 33.0.2.Final is now available for download. Typically after a major release of WildFly we follow up with one small bug fix release in the coming weeks before moving on to the next major release, however due to the nature of the issues fixed in this release we have decided to release one more release so I am pleased to confirm WildFly 33.0.2.Final is now available. The following issues were resolved in 33.0.2: Component Upgrade [WFLY-19705] - Upgrade WildFly Core to 25.0.2.Final [WFLY-19730] - CVE-2024-8391 Upgrade Vert.x to 4.5.10 Issues resolved in the WildFly Core update included with WildFly 33.0.2 were: Component Upgrade [WFCORE-6968] - Upgrade WildFly Elytron to 2.5.2.Final [WFCORE-6973] - CVE-2024-7885 Upgrade Undertow to 2.3.17.Final Issues resolved in the WildFly Elytron upgrade were: Bug [ELY-2797]- NullPointerException in OidcClientConfiguration.resolveUrls if parameter "request_parameter_supported" is not present in openid-configuration. Enjoy! ### [Automate WildFly's subsystems configuration using Ansible!](/news/2024/09/10/Automate-WildFly-s-subsystems-configuration-using-Ansible/) In this brief demonstration, we’ll see how to use Ansible to fully automate the deployment of a WildFly instance, including the configuration of its subsystems. In particular, we’ll illustrate how to set up messaging queues and deploy JDBC drivers. For readers not familiar with Ansible, the article with starts with the instructions on how to set it up and install the required extension (a collection, in Ansible lexicon) for WildFly. Install Ansible and its collection for WildFly On a Linux system using a package manager, installing Ansible is pretty straightforward: $ sudo dnf install ansible-core Note: this demonstration assumes you are running both the Ansible controller and the target (same machine in our case) on a Linux system. However, it should work on a different OS (bearing a few adjustments). Please refer to the documentation available online for installation on other operating systems. Before going further, double check that you are running a recent enough version of Ansible (2.16 or above will do): $ ansible --version ansible [core 2.16.0] config file = /etc/ansible/ansible.cfg configured module search path = ['/home/rpelisse/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /home/rpelisse/.local/lib/python3.12/site-packages/ansible ansible collection location = /home/rpelisse/.ansible/collections:/usr/share/ansible/collections executable location = /usr/bin/ansible python version = 3.12.3 (main, Apr 17 2024, 00:00:00) [GCC 13.2.1 20240316 (Red Hat 13.2.1-7)] (/usr/bin/python3) jinja version = 3.1.4 libyaml = True The next and last step to ensure your Ansible environment is ready to be used is to install the Ansible collection for WildFly on the controller (the machine that will run Ansible): # ansible-galaxy collection install middleware_automation.wildfly Starting collection install process Downloading https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/middleware_automation-wildfly-1.5.2.tar.gz to /root/.ansible/tmp/ansible-local-85_kfluuxm/tmpztz1ds3y/middleware_automation-wildfly-1.5.2-veisxadr Installing 'middleware_automation.wildfly:1.5.2' to '/root/.ansible/collections/ansible_collections/middleware_automation/wildfly' ownloading https://console.redhat.com/api/automation-hub/v3/plugin/ansible/content/641409-synclist/collections/artifacts/ansible-posix-1.5.4.tar.gz to /root/.ansible/tmp/ansible-local-85_kfluuxm/tmpztz1ds3y/ansible-posix-1.5.4-it7fl_gz middleware_automation.wildfly:1.5.2 was installed successfully Installing 'ansible.posix:1.5.4' to '/root/.ansible/collections/ansible_collections/ansible/posix' Downloading https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/middleware_automation-common-1.2.1.tar.gz to /root/.ansible/tmp/ansible-local-85_kfluuxm/tmpztz1ds3y/middleware_automation-common-1.2.1-0tzs6cy9 ansible.posix:1.5.4 was installed successfully Installing 'middleware_automation.common:1.2.1' to '/root/.ansible/collections/ansible_collections/middleware_automation/common' middleware_automation.common:1.2.1 was installed successfully Downloading https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/fedora-linux_system_roles-1.82.0.tar.gz to /root/.ansible/tmp/ansible-local-85_kfluuxm/tmpztz1ds3y/fedora-linux_system_roles-1.82.0-5rfvn8a7 Installing 'fedora.linux_system_roles:1.82.0' to '/root/.ansible/collections/ansible_collections/fedora/linux_system_roles' Downloading https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/containers-podman-1.15.3.tar.gz to /root/.ansible/tmp/ansible-local-85_kfluuxm/tmpztz1ds3y/containers-podman-1.15.3-brqeuvs6 fedora.linux_system_roles:1.82.0 was installed successfully Installing 'containers.podman:1.15.3' to '/root/.ansible/collections/ansible_collections/containers/podman' containers.podman:1.15.3 was installed successfully Downloading https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/community-general-9.1.0.tar.gz to /root/.ansible/tmp/ansible-local-85_kfluuxm/tmpztz1ds3y/community-general-9.1.0-1ute58rg Installing 'community.general:9.1.0' to '/root/.ansible/collections/ansible_collections/community/general' community.general:9.1.0 was installed successfully To verify that the installation was successful, let’s run again the ansible-galaxy command, this time asking it to list the installed collection: $ ansible-galaxy collection list $ /home/rpelisse/.ansible/collections/ansible_collections Collection Version ----------------------------- ------- ansible.posix 1.5.4 community.general 9.1.0 containers.podman 1.15.3 fedora.linux_system_roles 1.82.0 middleware_automation.common 1.2.1 middleware_automation.wildfly 1.5.2 Define Ansible’s Inventory Ansible is an automation tool designed to manage, if necessary, thousands of machines. Thus, to work, it needs a list of the targets systems (the ones Ansible are in charge of). There are several ways to provide such an inventory, but the simplest, especially for the demonstration of this article to be easily reproduced, is to use a simple file. Also, for practicality’s sake, we will not set up a remote machine, but just ask Ansible to leverage the local system as a target: [all] localhost ansible_connection=local Because we utilize localhost as a target, we also don’t need to use SSH (and setup the appropriate credentials). For more detail on Ansible inventory, please refer to the following documentation. To verify that everything works as expected and that Ansible is ready to be used, we are going to ask the tool to gather all the information it can on its targets, which, in our case, is only localhost: # ansible -m setup -i inventory all localhost | SUCCESS => { "ansible_facts": { ... The output of the command does not really matter (in the context of this article). The only important item is that Ansible runs successfully and can gather information on the target (localhost). Our system is now ready for the demonstration. Ansible Playbook to Install WildFly Now that Ansible and the required collection are both properly installed, we can start working on our playbook. To make it simple to follow, we are going to proceed step by step. First, we’ll set up WildFly on the target, without any special configuration to its subsystems. Then, we’ll modify the playbook below to add the necessary elements in order to adjust the instance resources (messaging queues and data sources). Here is the playbook we’ll use to deploy our clusters. Its content is relatively self-explanatory, at least if you are somewhat familiar with the Ansible syntax. - name: "WildFly installation and configuration" hosts: all become: yes vars: wildfly_install_workdir: '/opt/' wildfly_config_base: 'standalone.xml' wildfly_version: '30.0.1.Final' wildfly_java_package_name: 'java-11-openjdk-headless.x86_64' wildfly_home: "/opt/wildfly-{{ wildfly_version }}" collections: - middleware_automation.wildfly roles: - role: wildfly_install - role: wildfly_systemd In short, this playbook calls the Ansible collection for WildFly to, first, install the appserver by utilizing the wildfly_install role. This will download all the artifacts, create the needed system groups and users, install dependency (unzip) and so on. At the end of its execution, all the tidbits required to run WildFly on the target host are in place, but the server is not yet started. That’s what happening with the next role. There is indeed another role configured in our playbook called wildfly_systemd. This role will take care of integrating WildFly onto the target as a regular system service handled by the service manager. Run the playbook ! Now, let’s run our Ansible playbook and observe its output: $ ansible-playbook -i inventory playbook.yml PLAY [WildFly installation and configuration] ********************************** TASK [Gathering Facts] ********************************************************* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Validating arguments against arg spec 'main'] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure prerequirements are fullfilled.] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/prereqs.yml for localhost TASK [middleware_automation.wildfly.wildfly_install : Validate credentials] **** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Validate existing zipfiles wildfly-30.0.1.Final.zip for offline installs] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Validate patch version for offline installs] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Validate existing additional zipfiles {{ eap_archive_filename }} for offline installs] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Validate node identifier length] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check that required packages list has been provided.] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Add JDK package java-11-openjdk-headless.x86_64 to packages list] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Add selinux package java-11-openjdk-headless.x86_64 to packages list] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Install required packages (7)] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure required local user exists.] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/user.yml for localhost TASK [middleware_automation.wildfly.wildfly_install : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Set wildfly group] ******* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure group wildfly exists.] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure user wildfly exists.] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure required directories exists.] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/prepdirs.yml for localhost TASK [middleware_automation.wildfly.wildfly_install : Check if work directory /opt/ exists] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check if work directory /opt/ is readable] *** ok: [localhost] => { "changed": false, "msg": "Archive directory /opt/ is readable" } TASK [middleware_automation.wildfly.wildfly_install : Create archive_dir /opt/, if not exists.] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check if archive directory /opt/ exists] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check if archive directory /opt/ is readable] *** ok: [localhost] => { "changed": false, "msg": "Archive directory /opt/ is readable" } TASK [middleware_automation.wildfly.wildfly_install : Create archive_dir /opt/, if not exists.] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure server is installed] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/install.yml for localhost TASK [middleware_automation.wildfly.wildfly_install : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check local download archive path] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Set download paths] ****** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check target archive: /opt//wildfly-30.0.1.Final.zip] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Retrieve archive from website: https://github.com/wildfly/wildfly/releases/download] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/install/web.yml for localhost TASK [middleware_automation.wildfly.wildfly_install : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Download zipfile from https://github.com/wildfly/wildfly/releases/download/30.0.1.Final/wildfly-30.0.1.Final.zip into /work/wildfly-30.0.1.Final.zip] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Retrieve archive from RHN] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Install server using RPM] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check downloaded archive] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Copy archive to target nodes] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check target archive: /opt//wildfly-30.0.1.Final.zip] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Verify target archive state: /opt//wildfly-30.0.1.Final.zip] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Read target directory information: /opt/wildfly-30.0.1.Final] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Extract files from /opt//wildfly-30.0.1.Final.zip into /opt/.] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Note: decompression was not executed] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Read information on server home directory: /opt/wildfly-30.0.1.Final] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check state of server home directory: /opt/wildfly-30.0.1.Final] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Deploy custom configuration] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Deploy configuration] **** changed: [localhost] TASK [Apply latest cumulative patch] ******************************************* skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure required parameters for elytron adapter are provided.] *** skipping: [localhost] TASK [Install elytron adapter] ************************************************* skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Install server using Prospero] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check wildfly install directory state] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Validate conditions] ***** ok: [localhost] TASK [Ensure firewalld configuration allows server port (if enabled).] ********* skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Validating arguments against arg spec 'main'] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Validate node identifier length] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Ensure that version is correct for yaml config extension] *** skipping: [localhost] TASK [Ensure required local user and group exists.] **************************** TASK [middleware_automation.wildfly.wildfly_install : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Set wildfly group] ******* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure group wildfly exists.] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure user wildfly exists.] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check if PID directory exists] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Create PID directory path if not exists] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Ensure server configuration and systemd configuration are set] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_systemd/tasks/systemd.yml for localhost TASK [middleware_automation.wildfly.wildfly_systemd : Create basedir /opt/wildfly-30.0.1.Final/standalone for instance: wildfly] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Create deployment directories for instance: wildfly] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Ensure configuration directory exists] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Find properties for colocated instance] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy properties for colocated instance] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy configuration] **** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy custom configuration] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Include YAML configuration extension] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check YAML configuration is disabled] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy service instance configuration: /etc/sysconfig/wildfly.conf] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy Systemd unit for service: /etc/systemd/system/wildfly.service] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Perform daemon-reload to ensure the changes are picked up] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Ensure service is started] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_systemd/tasks/service.yml for localhost TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set instance wildfly state to started] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Ensure server's apps are deployed] *** skipping: [localhost] RUNNING HANDLER [middleware_automation.wildfly.wildfly_systemd : Restart Wildfly] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_systemd/tasks/service.yml for localhost RUNNING HANDLER [middleware_automation.wildfly.wildfly_systemd : Check arguments] *** ok: [localhost] RUNNING HANDLER [middleware_automation.wildfly.wildfly_systemd : Set instance wildfly state to restarted] *** changed: [localhost] RUNNING HANDLER [middleware_automation.wildfly.wildfly_install : Execute restorecon] *** skipping: [localhost] PLAY RECAP ********************************************************************* localhost : ok=61 changed=11 unreachable=0 failed=0 skipped=24 rescued=0 ignored=0 Check that everything worked as expected The easiest way to confirm that the playbook did indeed install WildFly (and started the appserver) is to use the systemctl command to check the associate services state: ● wildfly.service - JBoss EAP (standalone mode) Loaded: loaded (/etc/systemd/system/wildfly.service; enabled; preset: disabled) Active: active (running) since Thu 2024-07-04 13:04:59 UTC; 6min ago Main PID: 1173 (standalone.sh) Tasks: 86 (limit: 1638) Memory: 379.4M CPU: 17.479s CGroup: /system.slice/wildfly.service ├─1173 /bin/sh /opt/wildfly-30.0.1.Final/bin/standalone.sh -c wildfly.xml -b 0.0.0.0 -bmanagement 127.0.0.1 -Djboss.bind.address.private=127.0.0.1 -Djboss.default.multicast.address=230.0.0.4 -Djboss.server.config.dir=/opt/wildfly-30.0.1.Final/standalone/configuration/ -Djboss.server.base.dir=/opt/wildfly-30.0.1.Final/standalone -Djboss.tx.node.id=localhost -Djboss.node.name=wildfly -Djboss.socket.binding.port-offset=0 -Dwildfly.statistics-enabled=false └─1316 /etc/alternatives/jre_11/bin/java "-D[Standalone]" "-Djdk.serialFilter=maxbytes=10485760;maxdepth=128;maxarray=100000;maxrefs=300000" -Xmx1024M -Xms512M --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldaps=ALL-UNNAMED --add-exports=jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED --add-opens=java.base/com.sun.net.ssl.internal.ssl=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.bas> Jul 04 13:05:02 e32fad81e375 standalone.sh[1316]: 13:05:02,460 INFO [org.wildfly.extension.undertow] (MSC service thread 1-7) WFLYUT0006: Undertow HTTP listener default listening on [0:0:0:0:0:0:0:0]:8080 Jul 04 13:05:02 e32fad81e375 standalone.sh[1316]: 13:05:02,585 INFO [org.jboss.as.ejb3] (MSC service thread 1-8) WFLYEJB0493: Jakarta Enterprise Beans subsystem suspension complete Jul 04 13:05:02 e32fad81e375 standalone.sh[1316]: 13:05:02,585 INFO [org.wildfly.extension.undertow] (MSC service thread 1-2) WFLYUT0006: Undertow HTTPS listener https listening on [0:0:0:0:0:0:0:0]:8443 Jul 04 13:05:02 e32fad81e375 standalone.sh[1316]: 13:05:02,641 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-8) WFLYJCA0001: Bound data source [java:jboss/datasources/ExampleDS] Jul 04 13:05:02 e32fad81e375 standalone.sh[1316]: 13:05:02,730 INFO [org.jboss.as.server.deployment.scanner] (MSC service thread 1-8) WFLYDS0013: Started FileSystemDeploymentService for directory /opt/wildfly-30.0.1.Final/standalone/deployments Jul 04 13:05:02 e32fad81e375 standalone.sh[1316]: 13:05:02,788 INFO [org.jboss.ws.common.management] (MSC service thread 1-6) JBWS022052: Starting JBossWS 7.0.0.Final (Apache CXF 4.0.0) Jul 04 13:05:02 e32fad81e375 standalone.sh[1316]: 13:05:02,920 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server Jul 04 13:05:02 e32fad81e375 standalone.sh[1316]: 13:05:02,926 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management Jul 04 13:05:02 e32fad81e375 standalone.sh[1316]: 13:05:02,926 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990 Jul 04 13:05:02 e32fad81e375 standalone.sh[1316]: 13:05:02,928 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 30.0.1.Final (WildFly Core 22.0.2.Final) started in 2998ms - Started 280 of 522 services (317 services are lazy, passive or on-demand) - Server configuration file in use: wildfly.xml Deploy Queues Using the Yaml Config Feature Now that we have a working instance of WildFly, let’s look at the configuration of its subsystems. We have two requirements we want to implement: datasources and messaging queues. We’ll start with the latter, as the setup of these resources is a bit simpler than datasources, which we’ll give ourselves an opportunity to get familiar with the Yaml configuration feature before discussing how to handle the datasources. Here are the messaging requirements: the WildFly instance needs to have two queues and one topic, both ready to be used and already configured. This can be achieved using the JBoss CLI with the following queries: jms-queue --profile=full add --queue-address=FirstQueue --entries=["java:/jms/queue/first"] jms-queue --profile=full add --queue-address=SecondQueue --entries=["java:/jms/queue/second"] jms-topic --profile=full add --topic-address=Topic --entries=["java:/jms/topic/Topic"] Before we see how to implement these modifications using the Ansible collection and the Yaml config feature, let’s point out that we cannot (easily) automate those changes utilizing the JBoss CLI queries above. First of all, the CLI is not idempotent, which means that the first time the queries are run, it will create the resources, but the next times, it will fail, stating (quite correctly) that the resources already exist. Also, even if we bundle those queries into a batch, each time a server is set up, the CLI client will need to be started and the script executed before the instance is ready. All in all, it’s not ideal. Fortunately, this is where the Yaml Config feature comes in and nicely implements the modification in a Ansible-friendly manner (or rather in an idempotent fashion). In essence, the feature allows specifying changes in the server subsystem in a simple YAML file. As an example, here is how one can express the messaging requirements we discussed above using this format: wildfly-configuration: subsystem: messaging-activemq: server: default: jms-queue: FirstQueue: entries: - 'java:/jms/queue/first' SecondQueue: entries: - 'java:/jms/queue/second' jms-topic: TheTopic: entries: - topic/TheTopic - java:jboss/exported/topic/TheTopic With this file created; we can modify our playbook now to use the Yaml Config feature and configure accordingly the server’s subsystem: ... wildfly_config_base: 'standalone.xml' wildfly_version: '30.0.1.Final' wildfly_java_package_name: 'java-11-openjdk-headless.x86_64' wildfly_home: "/opt/wildfly-{{ wildfly_version }}" wildfly_enable_yml_config: True wildfly_yml_configs: - 'article.yml.j2' Let’s run again the playbook with this new configuration file. Note that Ansible will ensure the functionality is activated in the server and triggers a restart of WildFly so that the changes applied with the Yaml Config feature are, indeed, live: ... TASK [middleware_automation.wildfly.wildfly_systemd : Deploy YAML configuration files: ['article.yml.j2']] ***************************** changed: [localhost] => (item=article.yml.j2) ... RUNNING HANDLER [middleware_automation.wildfly.wildfly_systemd : Set instance wildfly state to restarted] ****************************** changed: [localhost] RUNNING HANDLER [middleware_automation.wildfly.wildfly_install : Execute restorecon] *************************************************** skipping: [localhost] PLAY RECAP ***************************************************************************************************************************** localhost : ok=73 changed=3 unreachable=0 failed=0 skipped=35 rescued=0 ignored=0 This configuration above simply adds the required resources (the queues and a topic); however, real-life scenarios are rarely as clear cut. Let’s introduce a bit of complexity for the sake of making our example closer to a real use case. FirstQueue is actually a legacy system, employed by a few, non-critical older apps and for this reason it has been decided it should not be durable. Also, because it is utilized by systems that are not yet updated, it needs to be associated with a legacy entry: /subsystem=messaging-activemq/server=default/jms-queue=FirstQueue:read-resource { "outcome" => "success", "result" => { "durable" => false, "entries" => ["java:/jms/queue/first"], "legacy-entries" => ["java:/jms/legacy/queue/old"], "selector" => undefined } } Let’s modify our Yaml Config file to reflect those extra requirements: ... FirstQueue: entries: - 'java:/jms/queue/first' durable: false legacy-entries: - 'java:/jms/legacy/queue/old' SecondQueue: ... It’s already quite nice to be able to express our changes to the subsystem configuration inside a simple text file, but, thanks to Ansible we can go further than that. Currently, the resource settings are somewhat hard-coded in this file; however, we can do better here. Ansible can easily generate the content of this file using its templating mechanism. Which means that we can even abstract part of the configuration and not have all the value hard-coded in the file. Let’s assume, for instance, that FirstQueue is not durable when deployed on staging systems. We can employ a template so that Ansible can create the appropriate configuration depending on the target system. Relying on the internal convention that any staging system as the suffix '. stating' in the machine hostname, Ansible be able to change the default value of durable from true to false: wildfly-configuration: subsystem: messaging-activemq: server: default: jms-queue: FirstQueue: entries: - 'java:/jms/queue/first' {% if '.staging' in ansible_nodename %} durable: false {% endif %} legacy-entries: - 'java:/jms/legacy/queue/old' SecondQueue: entries: - 'java:/jms/queue/second' jms-topic: TheTopic: entries: - topic/TheTopic - java:jboss/exported/topic/TheTopic While this templating feature is quite powerful, a balance needs to be found when it is leveraged. Generating the entire template, based on rather complex data structure is not advisable, for instance. The Yaml Config file is already a configuration artifact, that can be used as a source of truth. In short, when designing the way WildFly’s setup will be provisioned, it’s important to determine what needs to be added directly to the default configuration (standalone.xml or standalone-full.xml) utilized as a base and what can be parameterized using the Yaml configuration feature, employing or not, the templating functionality of Ansible. To help make these decisions, here are a few rules of thumb to keep in mind: Large alteration of the subsystems (adding one or several, or simply rewriting entirely the default configuration) are most likely easier to achieve by providing a modified base configuration. Small changes to the subsystem configuration, adding a few, straightforward resources are most likely easy enough to implement. Changes in the configuration linked to the target environments can be achieved using the templating feature of Ansible. No matter what, remember the KISS principle (Keep It Stupid Simple). Let’s run again the playbook. As in the above example run, Ansible will notice the change to the Yaml configuration file and consequently update the target’s subsystems configuration, before restarting the server. With these first requirements in place, we now move to the deployment of our JDBC drivers and datasources. Deploy JDBC drivers and datasources The deployment of JDBC drivers and datasources on the target system is a somewhat more elaborated use case than the one we just saw with the messaging subsystem. Indeed, to add a JDBC driver to a WildFly server an entire module must be created; it’s not just a configuration change in the standalone.xml that needs to be performed in an idempotent manner. Fortunately, here again, the Ansible collection for WildFly does most of the heavy lifting. In fact, the default playbook we used already comes with the setup of two JDBC drivers: ... collections: - middleware_automation.wildfly tasks: - name: Install second driver with wildfly_driver role ansible.builtin.include_role: name: wildfly_driver when: jdbc_drivers is defined and jdbc_drivers | length > 0 vars: wildfly_driver_module_name: "{{ item.name }}" wildfly_driver_version: "{{ item.version }}" wildfly_driver_jar_filename: "{{ item.jar_file }}" wildfly_driver_jar_url: "{{ item.url }}" loop: "{{ jdbc_drivers }}" ... As shown above, the collection provides a generic role that takes care of creating the file hierarchy associated to a JDBC driver, but also downloading the required artifacts (jar file) along with generating the needed descriptor (module.xml). The driver’s specific values are stored in the vars.yml, imported by Ansible when executing this playbook: postgres_driver_version: 9.4.1212 mariadb_driver_version: 3.2.0 jdbc_drivers: - { version: "{{ postgres_driver_version }}", name: 'org.postgresql', jar_file: "postgresql-{{ postgres_driver_version }}.jar", url: "https://repo.maven.apache.org/maven2/org/postgresql/postgresql/{{ postgres_driver_version }}/postgresql-{{ postgres_driver_version }}.jar" } - { version: "{{ mariadb_driver_version }}", name: 'org.mariadb', jar_file: "mariadb-java-client-{{ mariadb_driver_version }}.jar", url: "https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/{{ mariadb_driver_version }}/mariadb-java-client-{{ mariadb_driver_version }}.jar" } Note: The Ansible collection for WildFly comes with a default template to generate the module.xml of a custom module. Obviously, this template might not be a good fit for ALL the drivers that users may have to install in a WildFly setup. For this reason, the template itself can easily be replaced by another one, provided by the user. While this role ensures the modules are ready to be utilized, it does not; however, activate them. To make them available to use for datasources, we will add their definition to our Yaml configuration file: wildfly-configuration: subsystem: ... datasources: jdbc-driver: postgresql: driver-name: postgresql driver-xa-datasource-class-name: org.postgresql.xa.PGXADataSource driver-module-name: org.postgresql ... As we already have a datastructure with most of the required information, we are going to adopt a more dynamic approach, where the drivers configuration is automatically generated by the content of the existing array: ... datasources: {% if jdbc_drivers is defined and jdbc_drivers | length > 0 %}jdbc-driver: {% for driver in jdbc_drivers %} {{ driver.name | regex_replace('^org.', '') }}: driver-name: {{ driver.name | regex_replace('^org.', '') }} driver-xa-datasource-class-name: {{ driver.class_name }} driver-module-name: {{ driver.name }} {% endfor %} {% endif %} Note: the jinja2 template above is there to demonstrate how much flexibility the ability to turn the Yaml Config file into a template brings to the user. It is; however, debatable if such an intricate approach is the most reasonable, or even recommended. The variable provided by the default playbook does not contain the JDBC driver classname, so we need to add that information to the vars.yml file: jdbc_drivers: - { version: "{{ postgres_driver_version }}", name: 'org.postgresql', jar_file: "postgresql-{{ postgres_driver_version }}.jar", url: "https://repo.maven.apache.org/maven2/org/postgresql/postgresql/{{ postgres_driver_version }}/postgresql-{{ postgres_driver_version }}.jar", class_name: 'org.postgresql.xa.PGXADataSource' } - { version: "{{ mariadb_driver_version }}", name: 'org.mariadb', jar_file: "mariadb-java-client-{{ mariadb_driver_version }}.jar", url: "https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/{{ mariadb_driver_version }}/mariadb-java-client-{{ mariadb_driver_version }}.jar", class_name: 'org.mariadb.jdbc.Driver' } We can now run again the playbook and simply check, after it ran successfully, that the drivers have been properly added: [standalone@localhost:9990 /] /subsystem=datasources/jdbc-driver=mariadb:read-resource { "outcome" => "success", "result" => { "deployment-name" => undefined, "driver-class-name" => undefined, "driver-datasource-class-name" => undefined, "driver-major-version" => undefined, "driver-minor-version" => undefined, "driver-module-name" => "org.mariadb", "driver-name" => "mariadb", "driver-xa-datasource-class-name" => "org.mariadb.jdbc.Driver", "jdbc-compliant" => undefined, "module-slot" => undefined, "profile" => undefined } } [standalone@localhost:9990 /] /subsystem=datasources/jdbc-driver=postgresql:read-resource { "outcome" => "success", "result" => { "deployment-name" => undefined, "driver-class-name" => undefined, "driver-datasource-class-name" => undefined, "driver-major-version" => undefined, "driver-minor-version" => undefined, "driver-module-name" => "org.postgresql", "driver-name" => "postgresql", "driver-xa-datasource-class-name" => "org.postgresql.xa.PGXADataSource", "jdbc-compliant" => undefined, "module-slot" => undefined, "profile" => undefined } } With the drivers in place, we have just one more requirement to implement: setting up the datasources. The parameters vary depending on the target system. When WildFly is running on Red Hat Enterprise Linux 8 (RHEL8), the server is still using Postrgesql as a default datasources; however, when running on RHEL9, it should be utilizing MariaDB. Here again, we are going to leverage the templating system of Ansible, to set up the right default datasource, with the appropriate driver on the targets. ... wildfly-configuration: subsystem: ... data-source: DefaultDS: enabled: true jndi-name: java:jboss/datasources/DefaultDS max-pool-size: {{ default_ds_max_size }} min-pool-size: {{ default_ds_min_size }} connection-url: "jdbc:{% if ansible_distribution_major_version == 9 %}mariadb{% else %}postgresql{% endif %}://localhost/default_ds" driver-name: {% if ansible_distribution_major_version == 9 %}mariadb{% else %}postgresql{% endif %} Conclusion We have now fulfilled all the requirements and fully automated our set-up of WildFly. In doing so, we hopefully demonstrated how to use the Yaml Configuration feature of the Java server in conjunction with the Ansible collection for WildFly. Leveraging the latter with Ansible gives an efficient way to provision and manages hundreds, if not thousands of servers, without any manual intervention. ### [Configuring The WildFly To Use The JBeret JDBC Job Repository (Part 2)](/news/2024/09/02/Configuring-The-WildFly-To-Use-The-JBeret-JDBC-Job-Repository-Part-2/) In the previous blog post on this topic, I have introduced how to manually edit the configuration file of WildFly to configure the batch-jberet module to use the JDBC repository. In this article, I’d like to introduce how to use the CLI Command Tool and the Admin Console to do the task. ### [WildFly 33.0.1 is released!](/news/2024/08/22/WildFly-33-0-1-is-released/) WildFly 33.0.1.Final is now available for download. It’s been about four weeks since the WildFly 33 release, so we’ve done a small bug fix update, WildFly 33.0.1. This includes an update to WildFly Preview. The following issues were resolved in 33.0.1: Bugs [WFLY-19549] - OIDCSecurityContext deserialization issue [WFLY-19577] - Undertow ServerAdd could not detect referenced capabilities [WFLY-19583] - Deployment-related undertow metrics are not exported [WFLY-19610] - @PostConstruct on Servlet may be called twice [WFLY-19613] - Performance regression with HttpSession.getAttribute Component Upgrades [WFLY-19572] - Upgrade Arquillian 1.9.1.Final, Arquillian Jakarta to 10.0.0.Final and WildFly Arquillian to 5.1.0.Beta4 [WFLY-19576] - Upgrade CXF to 4.0.5 [WFLY-19600] - Upgrade RESTEasy to 6.2.10.Final [WFLY-19611] - Upgrade OpenSAML to 4.3.0 [WFLY-19637] - Upgrade WildFly Core to 25.0.1.Final [WFLY-19652] - Upgrade jboss-ejb-client to 5.0.7.Final [WFLY-19654] - Upgrade RESTEasy to 7.0.0.Alpha3 in WildFly Preview Issues resolved in the WildFly Core update included with WildFly 33.0.1 were: Bugs [WFCORE-6953] - java.lang.ClassNotFoundException: java.util.logging.Logger from Module "org.bouncycastle.bcpg" Component Upgrades [WFCORE-6952] - Upgrade WildFly Elytron to 2.5.1.Final Enjoy! ### [WildFly 33 is released!](/news/2024/07/23/WildFly-33-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 33.0.0.Final releases are available for download at https://wildfly.org/downloads. New and Notable Individual Features There a number of new features in WildFly 33, but before getting into the specific items I want to mention again the capabilities introduced in WildFly 31 to introduce features at different stability levels. Features can be introduced at one of four stability levels — experimental, preview, community or default — with the ideal outcome being that we promote them in subsequent releases to higher levels. The goal here is to allow users who want to look at features in earlier stages of the development lifecycle to easily do so, without leaving users who are not interested in that in a situation where they may inadvertently use those features. So, here’s what’s new: WildFly’s support for overriding base configuration settings using a YAML file has been enhanced with the addition of support for using the YAML file to add unmanaged deployments to the configuration. An unmanaged deployment is one where the server does not make an internal copy of the deployment content for its use; instead it directly uses the configured content. For more on this concept, see Managed and Unmanaged Deployments in the WildFly documentation. This feature is provided at the default stability level. The core-management subsystem now allows you to enable scanning of your deployments for usage of classes/methods in the SmallRye and Hibernate libraries annotated with org.hibernate.Incubating and io.smallrye.common.annotation.Experimental. These annotations indicate that those API elements are subject to change at any time, so users may wish to be made aware if their applications use them, or even fail deployment if they are used. The goal here is not to discourage such use; rather it’s part of our overall effort to allow users to take advantage in a controlled manner of newer, perhaps less stable, functionality. This feature itself is provided at the preview stability level. When configuring WildFly to act as a reverse proxy, the undertow subsystem now supports configuring the reverse proxy handler to reuse and append to any X-Forwarded HTTP headers and to rewrite the Host header. This feature is provided at the preview stability level. The undertow subsystem now allows configuring the AJP listener to accept custom AJP request headers. Previously such configuration could only be done by via a system property. This feature is provided at the preview stability level. The elytron-oidc-client subsystem now allows authentication requests to be sent as a signed and encrypted request object using the request and request_uri authenication request parameters. This feature is provided at the preview stability level. Utilities to reload a server to a different stability level in the testsuite are now available. The primary audience for this feature is the developers of WildFly itself or people writing extensions to WildFly. This follows up on a similar feature reload a server to a different stability level added in WildFly 32. This feature is provided at the community stability level. WildFly, EE 10 and SE 21 I am very happy to be able to announce that standard WildFly 33 is a compatible implementation of the Jakarta EE 10 Web Profile and Full Platform when running on Java SE 21. WildFly has been able to certify as a compatible EE 10 Core Profile, Web Profile and Full Platform implementation when running on SE 11 and SE 17 since the WildFly 27 release. We’ve also been able to certify as EE 10 Core Profile compatible on SE 21 since WildFly 30. What’s new is the ability to add Web Profile and Full Platform on SE 21 to the compatibility matrix. My thanks to Scott Marlow for driving this effort and to James Perkins for his invaluable help. And kudos to the Jakarta EE community in general for making this possible. It has been a Jakarta EE goal since EE 9.1 that vendors should be able to certify as compatible when running on SE releases that didn’t even exist when the EE version went GA. This doesn’t happen by magic; certifying as EE compatible requires passing a number of large TCKs, and like any large piece of software, adaptations to the TCKs are sometimes needed to allow proper execution on a new Java SE version. Those adaptations require volunteer effort from the community of developers who work on Jakarta EE. My thanks to Paul Nicolucci, Gurunandan Rao, Jason Mehrens, Lance Andersen and Arjan Tims for your hard work on Jakarta EE in this area! And my thanks and apologies to anyone else involved who I’ve neglected to mention. Supported Specifications Jakarta EE Standard WildFly 33 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly is EE 10 Platform, Web Profile and Core Profile compatible when running on Java SE 11, Java SE 17 and Java SE 21. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence Jakarta EE 10 Full Platform SE 11 SE 17 SE 21 Jakarta EE 10 Web Profile SE 11 SE 17 SE 21 Jakarta EE 10 Core Profile SE 11 SE 17 SE 21 MicroProfile WildFly supports numerous MicroProfile specifications. Because we no longer support MicroProfile Metrics, WildFly 33 cannot claim to be a compatible implementation of the MicroProfile 6.1 specification. However, WildFly’s MicroProfile support includes implementations of the following specifications in our "full" (e.g. standalone-full.xml) and "default" (e.g standalone.xml) configurations as well as our "microprofile" configurations (e.g. standalone-microprofile.xml): MicroProfile Technology WildFly Full/Default Configurations WildFly MicroProfile Configuration MicroProfile Config 3.1 X X MicroProfile Fault Tolerance 4.0  —  X MicroProfile Health 4.0  —  X MicroProfile JWT Authentication 2.1 X X MicroProfile LRA 2.0  —  X MicroProfile OpenAPI 3.1  —  X MicroProfile Reactive Messaging 3.0  —   —  MicroProfile Reactive Streams Operators 3.0  —   —  MicroProfile Rest Client 3.0 X X MicroProfile Telemetry 1.1  —  X Compatibility evidence for the above specifications that are part of MicroProfile 6.1 can be found in the WildFly Certifications repository on GitHub. WildFly Preview, EE 11 and SE 17 As I noted in the WildFly 32 release announcement, beginning with that release we are using WildFly Preview to provide a look at what we’re doing for Jakarta EE 11 support. EE 11 won’t go GA before later this year, and we don’t expect standard WildFly to support EE 11 before the WildFly 35 release. But there are milestone, Release Candidate and Final releases of many EE 11 specs and implementations available, so we are providiong those in WildFly Preview. This means for a number of EE APIs, WildFly Preview no longer provides an EE 10 compatible implementation. However, for a number of specifications that are planning changes for EE 11 we are still offering the EE 10 variant. In future releases we’ll shift those to the EE 11 variants. As a result of this shift to EE 11 APIs, WildFly Preview no longer supports running on Java SE 11. Going forward, if you want to use WildFly Preview you’ll need to use SE 17 or higher. A number of EE 11 APIs no longer produce SE 11 compatible binaries, which means an EE 11 runtime can no longer support SE 11. The following table lists the various Jakarta EE technologies offered by WildFly Preview 33, along with information about which EE platform version the specification relates to. Note that a number of Jakarta specifications are unchanged between EE 10 and EE 11, while other EE technologies that WildFly offers are not part of EE 11. Jakarta EE Technology WildFly Preview Version EE Version Jakarta Activation 2.1 10 & 11 Jakarta Annotations 3.0.0 11 Jakarta Authentication 3.0 10 Jakarta Authorization 3.0.0 11 Jakarta Batch 2.1 10 & 11 Jakarta Concurrency 3.1.0 11 Jakarta Connectors 2.1 10 & 11 Jakarta Contexts and Dependency Injection 4.1.0 11 Jakarta Debugging Support for Other Languages 2.0 10 & 11 Jakarta Dependency Injection 2.0 10 & 11 Jakarta Enterprise Beans 4.0 10 & 11 Jakarta Enterprise Web Services 2.0 10 1 Jakarta Expression Language 6.0.0 11 Jakarta Faces 4.1.0 11 Jakarta Interceptors 2.2.0 11 Jakarta JSON Binding 3.0 10 & 11 Jakarta JSON Processing 2.1 10 & 11 Jakarta Mail 2.1 10 & 11 Jakarta Messaging 3.1 10 & 11 Jakarta MVC (preview stability only) 2.1 N/A 2 Jakarta Pages 3.1 10 Jakarta Persistence 3.2.0 11 Jakarta RESTful Web Services 4.0 11 Jakarta Security 4.0.0 11 Jakarta Servlet 6.1.0 11 Jakarta SOAP with Attachments 3.0 10 1 Jakarta Standard Tag Library 3.0 10 & 11 Jakarta Transactions 2.0 10 & 11 Jakarta Validation 3.1.0 11 Jakarta WebSocket 2.2.0 11 Jakarta XML Binding 4.0 10 1 Jakarta XML Web Services 4.0 10 1 Notes: This Jakarta EE 10 technology is not part of EE 11 but is still provided by WildFly. Jakarta MVC is not part of the Jakarta EE Platform or the Web or Core Profile Java SE Support Recommended SE Versions Our recommendation is that you run WildFly 33 on Java SE 21, as that is the latest LTS JDK release where we have completed the full set of testing we like to do before recommending a particular SE version. WildFly 33 also is heavily tested and runs well on Java 17 and Java 11. Our recommendation of SE 21 over earlier LTS releases is solely because as a general principle we recommend being on later LTS releases, not because of any problems with WildFly on SE 17 or SE 11. One reason to use later SE versions is because it gets you ahead of the curve as WildFly and other projects begin to move on from supporting older SE releases. However, WildFly Preview no longer supports SE 11, as the baseline for Jakarta EE 11 is SE 17. We’re continuing to evaluate our plans around SE 11 support in standard WildFly, and I’ll be sure to post here as we make decisions. I do encourage WildFly users to prepare now for any eventual change to move off of SE 11. While we recommend using an LTS JDK release, I do believe WildFly runs well on JDK 22. By runs well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. Please note that WildFly runs in classpath mode. Incompatible Changes Running WildFly Preview 33 with the Java SecurityManager enabled is no longer allowed. In WildFly Preview 32 it was noted as being unsupported, but with 33 booting a WildFly Preview server will fail if the SecurityManager is enabled. This is because the Jakarta EE 11 specifications no longer support the SecurityManager, and it is not possible for WildFly to provide a consistent, reliable SecurityManager experience once the spec APIs and implementation projects we integrate no longer support it. As noted above, WildFly Preview no longer supports running on Java SE 11. Known Issues The Arquillian version specified in the WildFly 33 end user wildfly-ee-with-tools BOM results in test failures with JUnit 5. Users can work around this problem by directly controlling the Arquillian version and using Arquillian 1.9.0. <dependency> <groupId>org.jboss.arquillian.container</groupId> <artifactId>arquillian-container-test-spi</artifactId> <version>1.9.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-container</artifactId> <version>1.9.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.protocol</groupId> <artifactId>arquillian-protocol-servlet-jakarta</artifactId> <version>1.9.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.junit5</groupId> <artifactId>arquillian-junit5-container</artifactId> <version>1.9.0</version> <scope>test</scope> </dependency> Release Notes The full WildFly 33 release notes are available in GitHub. Issues fixed in the underlying WildFly Core 25 release are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. And, with that, onward to WildFly 34! Best regards, Brian ### [Vlog: Secure communication for WildFly microservices by using TLS on OpenShift](/news/2024/06/05/Vlog-Secure-communication-for-WildFly-microservices-by-using-TLS-on-OpenShift/) ### [How to Connect with the WildFly Community](/news/2024/05/31/How-to-Connect-with-the-WildFly-Community/) WildFly is an open-source, production-ready, flexible and lightweight application server, offering all the necessary features to run and deploy Java applications. Connecting with the WildFly community can provide valuable support, enhance your understanding of the server, and offer opportunities to contribute to the project. Here’s how you can get involved: Get an Idea about WildFly Explore the WildFly Website Visit WildFly’s official website to access comprehensive documentations, guides, downloads, and the latest news. The website serves as your primary resource for understanding and using WildFly effectively. Get Started with WildFly Begin by downloading WildFly and following the getting started guide on the website. This guide walks you through installation, initial configuration, and deploying a sample application, setting you up for success with your first WildFly server. Fork the WildFly Repository on GitHub and Play with It Explore WildFly’s source code by forking the repository on GitHub. Clone your forked repository to your local machine, experiment with the code, and understand the inner workings of WildFly. This hands-on approach can deepen your knowledge and potentially lead to contributions to the project. You can also go through the article on How to contribute to WildFly. Engage with the WildFly Community Engage in the WildFly Forums Participate in the WildFly Google Group to ask questions, share knowledge, and engage with other users and developers. The forum is a valuable platform for seeking help, providing answers, and staying updated with announcements and community discussions. You can also chat with the WildFly community members as well as with contributors via our official Zulip chatroom and for discussions about using WildFly, try the wildfly-user stream in the chatroom. Follow WildFly on Social Media Stay informed and connected by following WildFly on social media platforms. Follow us on X and Mastodon for quick updates, announcements, and subscribe to the WildFly YouTube channel for video tutorials, webinars, and conference talks. Use WildFly RSS Feeds Stay updated with the latest news, releases, and blog posts by subscribing to WildFly’s RSS feed. This ensures you never miss important announcements and updates from the WildFly project. Attend WildFly Community Events Participate in WildFly community events such as mini-conferences and webinars. These events offer learning opportunities through sessions and workshops by experts, networking with other users and developers, and community-building activities. Keep an eye on the WildFly website and social media channels for announcements about upcoming events. Provide and Receive Support Ask for Help Don’t hesitate to seek support through forums, mailing lists, or social media channels. The WildFly community is active and responsive, making it a great resource for troubleshooting and advice. Offer Help Share your knowledge and expertise to help others in the community. By answering questions and providing guidance, you contribute to the collective knowledge base. Submit Code or Contribute to Documentation WildFly uses JIRA for issue tracking. You can find the list of issues and tasks on the WildFly JIRA dashboard. If you’ve made improvements or fixed bugs in your forked repository, consider submitting pull requests to contribute back to the WildFly project. You can also visit the WildFly official documentation and feel free to suggest improvements, or directly contributing updates and corrections. Your contributions can help improve WildFly for everyone. Connecting with the WildFly community enriches your experience with the platform. By exploring the website, engaging in forums, following on social media, attending events, and participating in support and contributions, you become an integral part of the vibrant WildFly ecosystem. Join the community today and help shape the future of enterprise Java applications! ### [WildFly 32.0.1 is released!](/news/2024/05/31/WildFly-32-0-1-is-released/) WildFly 32.0.1.Final is now available for download. It’s been about five weeks since the WildFly 32 release, so we’ve done a small bug fix update, WildFly 32.0.1. This includes an update to WildFly Preview. The following issues were resolved in 32.0.1: Bugs [WFLY-19305] - ClassCastException when running live-only HA policy in messaging-activemq subsystem [WFLY-19326] - LinkageError: loader constraint violation for class io.netty.* [WFLY-19355] - Deploying multiple OpenAPI endpoints can result in a NoSuchElementException [WFLY-19366] - OpenTelemetryDependencyProcessor should add io.smallrye.opentelemetry to deployment classpath Tasks [WFLY-18217] - Add LICENSE and other community documents to widfly-archetypes [WFLY-19341] - Make the testsuite/galleon tests appropriately scoped Component Upgrades [WFLY-19278] - Upgrade Infinispan to 14.0.28.Final [WFLY-19279] - Upgrade JGroups to 5.2.25.Final [WFLY-19353] - Upgrade RESTEasy to 6.2.9.Final [WFLY-19364] - Upgrade WildFly Core to 24.0.1.Final Issues resolved in the WildFly Core update included with WildFly 32.0.1 were: Bugs [WFCORE-6825] - [CVE-2024-4029] wildfly-domain-http: wildfly: No timeout for EAP management interface may lead to Denial of Service (DoS) Tasks [WFCORE-6792] - Rename Installer.Builder.async() -> Installer.Builder.blocking() Component Upgrades [WFCORE-6797] - Upgrade BouncyCastle from 1.78 to 1.78.1 [WFCORE-6831] - Upgrade WildFly Elytron to 2.4.2.Final [WFCORE-6833] - Upgrade XNIO to 3.8.15.Final Enjoy! ### [Blog: WildFly 32 Delivers Preview of Jakarta EE 11 and Final Version of WildFly Glow](/news/2024/05/27/Blog-WildFly-32-Delivers-Preview-of-Jakarta-EE-11-and-Final-Version-of-WildFly-Glow/) Shaaf Syed, Principal Architect at Red Hat, has written a comprehensive article on WildFly Glow. A must read! ### [Dynamic client SSL context that automatically delegates to different SSLContexts based on the host and port of the peer](/news/2024/05/07/Dynamic-client-SSL-context-that-automatically-delegates-to-different-SSLContexts-based-on-the-host-and-port-of-the-peer/) WildFly 32 introduces the ability to configure a dynamic client SSL context. The dynamic client SSL context will dynamically switch between different SSL contexts based on the host and port of the peer. The host and port rules can be specified in the authentication context. This blog post demonstrates how to use this new resource. ### [Caching realm now automatically tries to authenticate users with the underlying realm if authentication with cached credentials fails](/news/2024/05/06/Caching-realm-now-automatically-tries-to-authenticate-users-with-the-underlying-realm-if-authentication-with-cached-credentials-fails/) WildFly provides a caching security realm that allows you to cache the results of a credential lookup from a security realm. WildFly 32+ will automatically attempt to verify credentials with the underlying realm if an authentication fails with the cached credentials. If this authentication succeeds, the obsolete credential is replaced with the updated credential. This functionality is useful if the credentials have been updated externally of WildFly. ### [Vlog: WildFly Glow, WildFly 32 deployment to OpenShift with database access](/news/2024/04/30/Vlog-WildFly-Glow-WildFly-32-deployment-to-OpenShift-with-database-access/) In this video we are using WildFly Glow 1.0 to deploy the todo-backend quickstart application to OpenShift with automatic connection to a PostgreSQL database. No configuration needed! ### [WildFly 32 is released!](/news/2024/04/25/WildFly-32-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 32.0.0.Final releases are available for download at https://wildfly.org/downloads. There’s a lot to talk about this time, so let’s get going! New and Notable WildFly Glow 1.0 Final Ever since the introduction of Galleon several years back, a major WildFly focus has been tooling to improve our users' ability to easily provision an optimal WildFly installation, on-premise and particularly for the cloud. I’m very excited to announce Final availability of a major advance in this area — the set of provisioning tools we call WildFly Glow. The WildFly Glow tools (a CLI application and a wildfly-maven-plugin integration) analyze your application artifact, determine what WildFly feature-packs and Galleon layers are needed to run your application, and make suggestions about other features (e.g. TLS support) that you may want to include in your optimized WildFly installation. You can take the information WildFly Glow provides and use it in your own provisioning configuration, or you can have WildFly Glow provision a server, bootable jar or Docker image for you. WildFlow Glow also provides a Maven plugin to help you automate provisioning when using Arquillian. The WildFly Glow documentation gives you a good sense of what WildFly Glow is about. But to really help you understand WildFly Glow’s benefits, I encourage you to read or watch the various posts and videos that the WildFly community has published this year: Articles WildFly Glow, an evolution of WildFly provisioning Using WildFly Glow to provision a WildFly server for a RESTEasy based project WildFly testing with WildFly Glow Mastertheboss tutorial WildFly Glow: Next-Gen Evolution in Provisioning Presentations Jean Francois Denise presented WildFly Glow during the March WildFly Mini Conference Slides are here. Jean Francois' talk starts at the 2:47:52 mark of the WildFly Mini Conference recording. Videos Introduction to WildFly Glow WildFly Glow, direct deployment to OpenShift Also, keep an out here or on the WildFly channel on YouTube channel for an upcoming post from Jean Francois on using WildFly Glow to help with automatic connection to a database when deploying on OpenShift. User Guides We’ve added a new Guides page to the wildly.org site. Each guide will show the steps to accomplish a specific, focused task, with links to guides showing any prerequisites and to guides for related tasks. This is something WildFly has long needed, and we’re very excited to see it happening! We’re now up to 10 guides in a variety of topic areas. Please have a look and give us your feedback and suggestions for other guides you’d like to see. Individual Features There a number of new individual features in WildFly 32, but before getting into the individual items I want to highlight again the capabilities introduced in WildFly 31 to introduce features at different stability levels. Features can be introduced at one of four stability levels — experimental, preview, community or default — with the ideal outcome being that we promote them in subsequent releases to higher levels. The goal here is to allow users who want to look at features in earlier stages of the development lifecycle to easily do so, without leaving users who are not interested in that in a situation where they may inadvertently use those features. We introduced this capability in WildFly 31, and added one feature at community stability, but in WildFly 32 we’ve significantly expanded our use of the concept, and added support in our provisioning tooling for it. I’ll talk more about feature stability levels below, but first let’s talk about the new features. Security For outbound requests, we’ve added support for an SSLContext that can dynamically delegate to different SSL contexts based on destination’s host and port. This feature is provided at the community stability level. The elytron-oidc-client subsystem has added the ability to configure additional scope values for OpenID Connect authentication requess. This feature is provided at the preview stability level. Authentication using credentials updated outside of WildFly will now succeed, and credentials and attributes in the cache will be automatically updated upon such authentication. This feature is provided at the default stability level. Provisioning The WildFly provisioning tooling has been evolved to support the feature stability concept. See below for more on this. This feature is provided at the community stability level. The WildFly Channels project adds ability to create channels defining component versions used to provision WildFly that can be maintained separately from WildFly’s feature-packs. This ability has been used for a while now in component testing and by provisioning projects like the wildfly-maven-plugin and Prospero. WildFly has now begun publishing channel manifests as part of each release to make such use easier. This feature is provided at the community stability level. We’ll continue to make further use of WildFly Channels in upcoming WildFly releases. To learn more about Prospero and WildFly Channels, have a look at the following articles. An Introduction to Prospero Usage Installing additional feature-packs in WildFly WildFly development The following two features are focused on people who are developing either WildFly itself or extensions to it. Subsystem development enhancements previously used in the wildfly-clustering-common Maven module have been ported to WildFly Core to make them more broadly usable. Utilities to reload a server to a different stability level in the testsuite are now available. This feature is provided at the community stability level. Other Goodies Standard WildFly now supports Jakarta MVC via a new mvc-krazo subsystem. This capability was previously introduced in WildFly Preview 31; now it is available in standard WildFly. This feature is provided at the preview stability level. When you start WildFly, instead of always typing long things like -c standalone-microprofile-ha.xml, now you can use short aliases for the standard configuration files. This feature is provided at the community stability level. For all you asciiart fans, when you start WildFly with the --stability=experimental flag, now you get a cool boot message. This feature is provided at the experimental stability level. WildFly Preview, EE 11 and SE 17 The 32 release introduces a significant inflection in how we are using WildFly Preview. Beginning with this release we are starting to use WildFly Preview to provide a look at what we’re doing for Jakarta EE 11 support. EE 11 won’t go GA before this summer, and standard WildFly won’t support EE 11 before the WildFly 34 release, at earliest. But when we wrapped up 32 development there were milestone, Release Candidate and Final releases of many EE 11 specs and implementations available, so we decided to provide those in WildFly Preview. This means for a number of EE APIs, WildFly Preview no longer provides an EE 10 compatible implementation. However, for a number of specifications that are planning changes for EE 11 we are still offering the EE 10 variant. In future releases we’ll shift those to the EE 11 variants. As a result of this shift to EE 11 APIs, WildFly Preview no longer supports running on Java SE 11. Going forward, if you want to use WildFly Preview you’ll need to use SE 17 or higher. A number of EE 11 APIs no longer produce SE 11 compatible binaries, which means an EE 11 runtime can no longer support SE 11. Note This removal of support for SE 11 has no impact on standard WildFly. Standard WildFly 32 continues to support running on SE 11. We do, however, encourage users to move to SE 17 or later, as the general Java ecosystem is moving away from SE 11 support, and eventually standard WildFly will as well. The following table lists the various Jakarta EE technologies offered by WildFly Preview 32, along with information about which EE platform version the specification relates to. Note that a number of Jakarta specifications are unchanged between EE 10 and EE 11, while other EE technologies that WildFly offers are not part of EE 11. Jakarta EE Technology WildFly Preview Version EE Version Jakarta Activation 2.1 10 & 11 Jakarta Annotations 3.0.0 11 Jakarta Authentication 3.0 10 Jakarta Authorization 3.0.0-M2 11 Jakarta Batch 2.1 10 & 11 Jakarta Concurrency 3.1.0-M1 11 Jakarta Connectors 2.1 10 & 11 Jakarta Contexts and Dependency Injection 4.1.0 11 Jakarta Debugging Support for Other Languages 2.0 10 & 11 Jakarta Dependency Injection 2.0 10 & 11 Jakarta Enterprise Beans 4.0 10 & 11 Jakarta Enterprise Web Services 2.0 10 1 Jakarta Expression Language 6.0.0 11 Jakarta Faces 4.1.0-M1 11 Jakarta Interceptors 2.2.0 11 Jakarta JSON Binding 3.0 10 & 11 Jakarta JSON Processing 2.1 10 & 11 Jakarta Mail 2.1 10 & 11 Jakarta Messaging 3.1 10 & 11 Jakarta MVC (preview stability only) 2.1 N/A 2 Jakarta Pages 3.1 10 Jakarta Persistence 3.2.0-M2 11 Jakarta RESTful Web Services 3.1 10 Jakarta Security 4.0.0-M2 11 Jakarta Servlet 6.1.0-M2 11 Jakarta SOAP with Attachments 3.0 10 1 Jakarta Standard Tag Library 3.0 10 & 11 Jakarta Transactions 2.0 10 & 11 Jakarta Validation 3.1.0-M2 11 Jakarta WebSocket 2.2.0-M1 11 Jakarta XML Binding 4.0 10 1 Jakarta XML Web Services 4.0 10 1 Notes: This Jakarta EE 10 technology is not part of EE 11 but is still provided by WildFly. Jakarta MVC is not part of the Jakarta EE Platform or the Web or Core Profile Warning Jakarta EE 11 no longer supports running with a Java SecurityManager enabled. As a result, individual Jakarta specification projects may have removed SecurityManager calls from the API jars WildFly Preview integrates, and the associated implementation artifacts may have done the same. As a result, WildFly Preview should not be run with the SecurityManager enabled. Future releases will prohibit use with the SecurityManager enabled if EE 11 APIs are used. Feature Stability Levels As I noted above, WildFly now provides new features at different stability levels ---- experimental, preview, community or default. Out of the box, standard WildFly allows use of features at community or default stability, while WildFly Preview allows preview, community or default. If you wish to allow lower stability level features than the out-of-the-box setting, this can be done using the stability command line parameter: bin/standalone.sh --stability=experimental In WildFly 32 we’ve introduced features at all four stability levels. You can identify the stability level of new features by looking at the title of the Jira issue in the "Feature Request" section of the release notes. For features at anything other than default stability, the issue title will be prefaced by one of [Experimental], [Preview] or [Community]. Tooling Support for Feature Stability Levels Our Galleon-based provisioning tooling has also had updates related to feature stability levels: we’ve added configuration options to allow you to control the stability level of features in your installation. This can be used to do things like: Prevent the provisioning of lower stability features, so they are not available for use even when the --stability server start param is used. Enable the inclusion of lower stability features in the configuration files the provisioning tool generates, avoiding the need to use a post-provisioning tool like the WildFly CLI to incorporate them into the configuration. To limit your installation level to the highest stability features, you would include the following in your maven plugin configuration: <galleon-options> <stability-level>default</stability-level> </galleon-options> To allow Galleon to include lower stability features in your installation’s generated configuration files, you could do something like: <galleon-options> <stability-level>preview</stability-level> </galleon-options> Note If one wants to have different values for configuration files and packages (i.e. filesystem resources like JBoss Modules modules), then the <config-stability-level> and <package-stability-level> options should be used instead of <stability-level>. The use case for using config-stability-level and package-stability-level as an alternative to stability-level is when the user wishes to generate configurations with features at a given stability level while allowing provisioning of packages at a lower level. The presence of the lower stability level packages allows subsequent update of the configuration, e.g. with the WildFly CLI, to enable lower stability features. The latest wildfly-maven-plugin, wildfly-jar-maven-plugin (for bootable jars) and the WildFly Glow and Galleon tools all support these stability level configuration options. I encourage you to try them out. Supported Specifications Jakarta EE Standard WildFly 32 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly is EE 10 Platform, Web Profile and Core Profile compatible when running on both Java SE 11 and Java SE 17. WildFly is also a compatible EE 10 Core Profile implementation when running on SE 21. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence Jakarta EE 10 Full Platform SE 11 SE 17 Jakarta EE 10 Web Profile SE 11 SE 17 Jakarta EE 10 Core Profile SE 11 SE 17 SE 21 MicroProfile WildFly supports numerous MicroProfile specifications. Because we no longer support MicroProfile Metrics, WildFly 32 cannot claim to be a compatible implementation of the MicroProfile 6.1 specification. However, WildFly’s MicroProfile support includes implementations of the following specifications in our "full" (e.g. standalone-full.xml) and "default" (e.g standalone.xml) configurations as well as our "microprofile" configurations (e.g. standalone-microprofile.xml): MicroProfile Technology WildFly Full/Default Configurations WildFly MicroProfile Configuration MicroProfile Config 3.1 X X MicroProfile Fault Tolerance 4.0  —  X MicroProfile Health 4.0  —  X MicroProfile JWT Authentication 2.1 X X MicroProfile LRA 2.0  —  X MicroProfile OpenAPI 3.1  —  X MicroProfile Reactive Messaging 3.0  —   —  MicroProfile Reactive Streams Operators 3.0  —   —  MicroProfile Rest Client 3.0 X X MicroProfile Telemetry 1.1  —  X Compatibility evidence for the above specifications that are part of MicroProfile 6.1 can be found in the WildFly Certifications repository on GitHub. Java SE Support Recommended SE Versions I’m pleased to be able to say that our recommendation is that you run WildFly 32 on Java SE 21, as that is the latest LTS JDK release where we have completed the full set of testing we like to do before recommending a particular SE version. WildFly 32 also is heavily tested and runs well on Java 17 and Java 11. This recommendation to run on SE 21 is a shift from previous releases, where we recommended SE 17. This is because during the WildFly 32 development cycle we completed the qualification exercise that we go through before recommending an LTS SE release. Our recommendation of SE 21 over earlier LTS releases is solely because as a general principle we recommend being on later LTS releases, not because of any problems with WildFly on SE 17 or SE 11. One reason to use later SE versions is because it gets you ahead of the curve as WildFly and other projects begin to move on from supporting older SE releases. In the WildFly 30 release announcement I indicated that WildFly 30 would likely be the last feature release to support SE 11. Obviously, that is not the case as we still support SE 11 in standard WildFly 32. However, as noted above, WildFly Preview no longer supports SE 11. We’re continuing to evaluate our plans around SE 11 support, and I’ll be sure to post here as we make decisions. I do encourage WildFly users to prepare now for any eventual change to move off of SE 11. While we recommend using an LTS JDK release, I do believe WildFly runs well on JDK 22. By runs well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. Please note that WildFly runs in classpath mode. Incompatible Changes We removed the deprecated Narayana compensations module from WildFly 32. We suggest any users of this functionality investigate WildFly’s support for MicroProfile LRA. As noted above, WildFly Preview no longer supports running on Java SE 11. Users also should not run WildFly Preview 32 with a Java SecurityManager enabled. Release Notes The full WildFly 32 release notes are available in GitHub. Issues fixed in the underlying WildFly Core 24 release are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. Meanwhile, we’re busy at work on WildFly 33! Best regards, Brian ### [WildFly 32 Beta is released!](/news/2024/04/08/WildFly-32-Beta-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 32.0.0.Beta1 releases are available for download at https://wildfly.org/downloads. This is our usual single beta that we release a couple of weeks before the 32 Final release. We typically don’t do much of a release announcement post for the beta release, but there are a number of things happening with WildFly 32 that users of our betas should know about and that we encourage people who usually don’t look at our betas to try out. Feature Stability Levels There a number of new features in WildFly 32 Beta1. I’ll wait for the Final release announcement to describe them all; for now I’ll just direct you to the release notes. Something that’s pretty new in 32 Beta though is that we’ve started to take advantage of the capabilities introduced in WildFly 31 to introduce features at different stability levels. The goal here is to allow users who want to look at features in earlier stages of the development lifecycle to easily do so, without leaving users who are not interested in that in a situation where they may inadvertently use those features. As noted in the documentation, new features are offered at one of four stability levels: experimental, preview, community and default. Most features in both standard WildFly and WildFly Preview are at default stability, but increasing numbers of new features will be introduced at the other levels, and hopefully will be promoted in later releases up to community or default. Out of the box, standard WildFly allows use of features at community or default stability, while WildFly Preview allows preview, community or default. If you wish to allow lower stability level features than the out-of-the-box setting, this can be done using the stability command line parameter: bin/standalone.sh --stability=experimental In WildFly 32 Beta we’ve introduced features at all four stability levels. You can identify the stability level of new features by looking at the title of the Jira issue in the release notes. For features at anything other than default stability, the issue title will be prefaced by one of [Experimental], [Preview] or [Community]. Tooling Support for Feature Stability Levels Our Galleon-based provisioning tooling has also had updates related to feature stability levels: we’ve added configuration options to allow you to control the stability level of features in your installation. This can be used to do things like: Prevent the provisioning of lower stability features, so they are not available for use even when the --stability server start param is used. Enable the inclusion of lower stability features in the configuration files the provisioning tool generates, avoiding the need to use a post-provisioning tool like the WildFly CLI to incorporate them into the configuration. To limit your installation level to the highest stability features, you would include the following in your maven plugin configuration: <galleon-options> <stability-level>default</stability-level> </galleon-options> To allow Galleon to include lower stability features in your installation’s generated configuration files, you could do something like: <galleon-options> <stability-level>preview</stability-level> </galleon-options> Note If one wants to have different values for configuration files and packages (i.e. filesystem resources like JBoss Modules modules), then the <config-stability-level> and <package-stability-level> options are to be used instead of <stability-level>. The use case for using config-stability-level and package-stability-level as an alternative to stability-level is when the user wishes to generate configurations with features at a given stability level while allowing provisioning of packages at a lower level. The presence of the lower stability level packages allows subsequent update of the configuration, e.g. with the WildFly CLI, to enable lower stability features. The wildfly-maven-plugin 5.0.0.Beta5, wildfly-jar-maven-plugin 11.0.0.Beta2 (for bootable jars) and the Galleon 6.0.0.Beta6 tools all support these stability level configuration options. I encourage you to try them out. WildFly Glow We’ve also continued to make improvements in WildFly Glow. Please try out the 1.0.0.Beta13 release and give us your feedback as we head toward the finish line and WildFly Glow 1.0.0.Final. WildFly Preview, EE 11 and SE 17 The 32 Beta release introduces a significant inflection in how we are using WildFly Preview. Beginning with this release we are starting to use WildFly Preview to provide a look at what we’re doing for Jakarta EE 11 support. EE 11 won’t go GA before this summer, and standard WildFly won’t support EE 11 before the WildFly 34 release, at earliest. But when we wrapped up 32 Beta development there were milestone up to release candidate releases of many EE 11 specs and implementations available, so we decided to provide those in WildFly Preview. This means for a number of EE APIs, Preview no long provides an EE 10 compatible implementation. However, for a number of specifications that are planning changes for EE 11 we are still offering the EE 10 variant. In future releases we’ll shift those to the EE 11 variants. As a result of this shift to EE 11 APIs, WildFly Preview no longer supports running on Java SE 11. Going forward, if you want to use WildFly Preview you’ll need to use SE 17 or higher. A number of EE 11 APIs no longer produce SE 11 compatible binaries, which means an EE 11 runtime can no longer support SE 11. Note This removal of support for SE 11 has no impact on standard WildFly. Standard WildFly 32 continues to support running on SE 11. We do, however, encourage users to move to SE 17 or later, as the general Java ecosystem is moving away from SE 11 support, and eventually standard WildFly will as well. The following table lists the various Jakarta EE technologies offered by WildFly Preview 32 Beta, along with information about which EE platform version the specification relates to. Note that a number of Jakarta specifications are unchanged between EE 10 and EE 11, while other EE technologies that WildFly offers are not part of EE 11. Jakarta EE Technology WildFly Preview Version EE Version Jakarta Activation 2.1 10 & 11 Jakarta Annotations 3.0.0-M1 11 Jakarta Authentication 3.0 10 Jakarta Authorization 3.0.0-M2 11 Jakarta Batch 2.1 10 & 11 Jakarta Concurrency 3.1.0-M1 11 Jakarta Connectors 2.1 10 & 11 Jakarta Contexts and Dependency Injection 4.1.0.RC1 11 Jakarta Debugging Support for Other Languages 2.0 10 & 11 Jakarta Dependency Injection 2.0 10 & 11 Jakarta Enterprise Beans 4.0 10 & 11 Jakarta Enterprise Web Services 2.0 10 1 Jakarta Expression Language 4.1.0-M1 11 Jakarta Interceptors 2.2.0-RC1 11 Jakarta JSON Binding 3.0 10 & 11 Jakarta JSON Processing 2.1 10 & 11 Jakarta Mail 2.1 10 & 11 Jakarta Messaging 3.1 10 & 11 Jakarta MVC (preview stability only) 2.1 N/A 2 Jakarta Persistence 3.2.0-M2 11 Jakarta RESTful Web Services 3.1 10 Jakarta Security 4.0.0-M2 11 Jakarta Faces 4.1.0-M1 11 Jakarta Server Pages 3.1 10 Jakarta Servlet 6.1.0-M2 11 Jakarta SOAP with Attachments 1.3 10 1 Jakarta Standard Tag Library 3.0 10 & 11 Jakarta Transactions 2.0 10 & 11 Jakarta Validation 3.1.0-M2 11 Jakarta WebSocket 2.2.0-M1 11 Jakarta XML Binding 4.0 10 1 Jakarta XML Web Services 4.0 10 1 Notes: This Jakarta EE 10 technology is not part of EE 11 but is still provided by WildFly. Jakarta MVC is not part of the Jakarta EE Platform or the Web or Core Profile Please try all of this out and give us your feedback while we finish up WildFly 32 Final! Best regards, Brian ### [Vlog: WildFly Glow, direct deployment to OpenShift](/news/2024/03/28/Vlog-WildFly-Glow-direct-deployment-to-OpenShift/) ### [WildFly Mini Conference Recap](/news/2024/03/19/WildFly-Mini-Conference-Recap/) Many thanks to all participants of the first WildFly Mini Conference! Our first WildFly Mini Conference took place on March 6. We had four talks on the agenda and many interesting questions and feedback. The feedback we have received so far has been very positive and has encouraged us to organize similar events for the community in the future. Stay tuned! If you have missed the conference, you can watch the recording at https://www.youtube.com/watch?v=_8g1rZ80u2A If you haven’t done so far, please let us know how you liked the conference using our feedback form. For those who want to take a look at the slides, here are the links. Introduction to WildFly and how to get started fast Deploying WildFly applications to bare-metal and the cloud What is new in WildFly and roadmap for future releases WildFly Glow You’ll find the links also on the conference page and in the description of the recording. ### [Trying Out An Upcoming Security Feature for WildFly on OpenShift](/news/2024/03/13/Trying-Out-An-Upcoming-Security-Feature-for-WildFly-on-OpenShift/) A future release of WildFly will include the ability to add additional scope values when securing applications using OpenID Connect (OIDC). This blog post demonstrates how to secure a WildFly application using OpenID Connect and configure scope values to request additional claims using an in-progress version of the feature. This feature adds the ability to specify additional scope values in the authentication request for applications secured using OIDC. For updates on the status of the feature, please keep an eye on WFLY-16532. We will also walk through how to deploy this feature on the cloud using OpenShift. ### [Hosting a React Application on WildFly](/news/2024/03/08/Hosting-a-React-Application-on-WildFly/) As part of an upcoming development item I am going to be working with a React application deployed to the WildFly application server and invoking Jakarta RESTful Web Service endpoints to interact with the server side of the application. I thought others might find it useful to see the steps I have taken. This blog post describes my steps up until the point I have the default React application deployed to WildFly, I may then follow up with some blogs of my subsequent steps. ### [WildFly - The GitOps Way](/news/2024/03/07/WildFly-The-GitOps-Way/) ### [How to contribute to WildFly](/news/2024/03/01/How-to-contribute-to-WildFly/) Welcome to the world of WildFly contributions, a place where your skills can make a real impact! If you’re eager to dive in but not sure where to start, this guide is here to simplify the process for you. Whether you’re new to open source or just getting acquainted with WildFly, we’ve got your back. In the upcoming sections, we’ll walk you through the essential steps, providing insights into the WildFly ecosystem and equipping you with the tools and knowledge needed to actively participate in its development. From setting up your development environment to engaging with the vibrant community, each step is a gateway to not only enhancing your technical skills but also fostering connections within a community passionate about open-source excellence. Join us as we explore how you can navigate the wild and make your mark in the world of WildFly contributions. Get Acquainted with WildFly The first step in contributing to WildFly is to familiarize yourself with the project. Visit the WildFly GitHub repository. Explore the project structure, review the source code, and read the latest documentation available in the repository. The documentation provides valuable insights into building, configuring, and deploying applications with WildFly. Set Up Your Development Environment and Install WildFly Before installing the latest version of WildFly, there are a few prerequisites: Check that you have a JDK on your machine—JDK 11 or higher recommended to start WildFly. You can use the open source JDK called OpenJDK. Once you install the JDK, set the JAVA_HOME environment variable. Ensure you have Maven 3.6.0 or higher installed. You can download Maven from here and set the environment variables. After loading both the variables, check the versions of JDK and Maven like below. $ java -version openjdk version “11.0.9” 2020-10-20 OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.9+11) OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.9+11, mixed mode) $ mvn -version Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) Maven home: /usr/share/maven Java version: 11.0.9, vendor: AdoptOpenJDK, runtime: /usr/lib64/adoptopenjdk Default locale: en_US, platform encoding: UTF-8 OS name: “linux”, version: “5.9.1”, arch: “amd64”, family: “unix” There are many ways you can install WildFly, including unzipping our traditional download zip, provisioning a custom installation using Galleon, or building a bootable jar. The official installation guide helps you identify the kind of WildFly installation that best fits your application’s deployment needs. Create an Issue or Follow the JIRA WildFly uses JIRA for issue tracking. You can find the list of issues and tasks on the WildFly JIRA dashboard. If you encounter a bug, have a feature request, spot something in the documentation that could be improved or spot something missing in the documentation, or want to contribute in any way, create a new issue on JIRA. Alternatively, you can pick an existing issue or go through good first issues that aligns with your interests or skills. Select an Issue and Send a Pull Request: Once you’ve identified an issue you’d like to work on, fork the WildFly repository, create a new branch, and start working on the issue. Make your changes, commit them, and push the changes to your forked repository. Finally, submit a pull request to the main WildFly repository. For better understanding you can also follow the official getting started guide. Make sure to follow the code of conduct and contribution guidelines to ensure a smooth review process. Participate in Code Review Code review is a crucial aspect of any open-source project. Engage in discussions with other contributors, address feedback, and iterate on your changes. This collaborative process helps maintain code quality and ensures that contributions align with the project’s standards. Engage with the Community WildFly has a diverse and active community of developers, users, and contributors. Join the discussion on the WildFly google group - wildfly@googlegroups.com or via the Zulip wildfly-user, wildfly-developer channels. We are also present on X and YouTube, you can follow us there as well. Participate in community events, webinars, and conferences related to WildFly. Engaging with the community not only enhances your understanding of the project but also opens doors for collaboration and mentorship. Contributing to WildFly is a rewarding experience that allows you to be part of a thriving open-source community. By following these steps, you can make meaningful contributions to the project, enhance your skills, and connect with like-minded individuals who share a passion for open-source development. Remember, every contribution, no matter how small, makes a valuable impact on the success of the WildFly project. ### [Vlog: Securing WildFly Apps with Okta on OpenShift](/news/2024/02/29/Vlog-Securing-WildFly-Apps-with-Okta-on-OpenShift/) ### [WildFly 31.0.1 is released!](/news/2024/02/28/WildFly-31-0-1-is-released/) WildFly 31.0.1.Final is now available for download. It’s been about five weeks since the WildFly 31 release, so we’ve done a small bug fix update, WildFly 31.0.1. This includes an update to WildFly Preview. The following issues were resolved in 31.0.1: Bugs [WFLY-18700] - java.lang.OutOfMemoryError: Direct buffer memory [WFLY-18959] - Mail Quickstart maven dependencies have wrong scope [WFLY-18969] - Give the Apache Lucene module access to jdk.unsupported [WFLY-19010] - SSL Client context not loaded with AMQP Connector used in bootable jar [WFLY-19019] - Exception that happened during deployment is being hidden [WFLY-19020] - JakartaEE application client: module "org.hibernate" is not added to classpath [WFLY-19040] - Regression due to SSLHandshakeException affecting HotRod client when connecting to remote Infinispan Tasks [WFLY-19029] - Hibernate ORM 6.4+ should export services to consumer classpath Component Upgrades [WFLY-18946] - Upgrade Infinispan to 14.0.22.Final [WFLY-18977] - Upgrade jgroups-kubernetes to 2.0.2.Final [WFLY-18989] - Upgrade to Hibernate 6.4.4.Final release [WFLY-19003] - Upgrade Netty to 4.1.106 [WFLY-19032] - Upgrade Snappy Java to 1.1.10.5 (CVEs CVE-2023-34453, CVE-2023-34454, CVE-2023-34455, CVE-2023-43642) [WFLY-19034] - Upgrade nimbus-jose-jwt to 9.37.3 [CVE-2023-52428] [WFLY-19042] - Upgrade HAL to 3.7.0.Final (WildFly 31.0.1.Final) [WFLY-19045] - Upgrade Infinispan to 14.0.24.Final [WFLY-19046] - Upgrade JGroups to 5.2.22.Final [WFLY-19048] - Upgrade WildFly Core to 23.0.2.Final [WFLY-19058] - Upgrade WildFly Core to 23.0.3.Final Enhancements [WFLY-18956] - Add sha1 to Quickstart’s dist module Issues resolved in the WildFly Core updates included with WildFly 31.0.1 were: Component Upgrades [WFCORE-6695] - CVE-2023-4639 Upgrade Undertow to 2.3.11.Final [WFCORE-6707] - CVE-2024-1635 Upgrade XNIO to 3.8.13.Final [WFCORE-6708] - CVE-2024-1635 Upgrade JBoss Remoting to 5.0.28.Final [WFCORE-6709] - CVE-2023-5379 CVE-2024-1459 CVE-2024-1635 Upgrade Undertow to 2.3.12.Final Enjoy! ### [WildFly Mini Conference](/news/2024/02/12/WildFly-Mini-Conference/) The WildFly team organizes a conference. The conference will take place on Wednesday, March 6, 2024. It starts at 14:00 UTC and includes four sessions with topics related to WildFly. All sessions will be streamed live on YouTube. For more information, please take a look at the conference page at https://www.wildfly.org/conference/ We’re looking forward to seeing you there! ### [Vlog: Introduction to WildFly Glow](/news/2024/02/05/Vlog-Introduction-to-WildFly-Glow/) ### [Using WildFly Glow to provision a WildFly server for a RESTEasy based project](/news/2024/02/05/Using-WildFly-Glow-to-provision-a-WildFly-server-for-a-RESTEasy-based-project/) ### [WildFly testing with WildFly Glow](/news/2024/02/05/WildFly-testing-with-WildFly-Glow/) This blog post provides information on how to use WildFly Glow to produce a WildFly server in order to test the applications you are developing for WildFly. Note Reading this blog post that provides detailed information on WildFly provisioning in general and WildFly Glow in particular is a good pre-requisite to this blog post. The main goal of the WildFly Glow project is to help you produce a trimmed server that will properly execute your deployments. The trimmed WildFly server can be produced to run your tests or execute your final deployments. This blog post focuses on the testing phase. Provisioning approaches for your tests To install a server to execute your tests, you can: Download and install a WildFly distribution. This approach is outside the scope of executing tests with a trimmed server. This would apply when executing your applications inside a full WildFly server. Provisioning a WildFly server using the WildFly Maven Plugin (with WildFly Glow support enabled) during test execution. This approaches addresses simple applications composed of a single deployment. Use the WildFly Arquillian Adapter and WildFly Glow to provision a server to test more complex use-cases. Important The server used by the tests should contain the same content as the one used in production (with some configuration adjustments to cope with each context). So testing with a full WildFly distribution and then using a trimmed server in production will hide issues. We strongly advise that you use provisioning in the first place and execute tests with a trimmed server. Ok, so you are ready to provision a trimmed server, but what is the provisioning configuration you need to provide to the provisioning tooling to produce a WildFly server that will properly execute your tests? Testing using the WildFly Maven Plugin to provision a server This is the simplest approach that applies to a single application deployed into WildFly. The WildFly quickstarts cover this approach with the provisioned-server profile. Each quickstart defines this profile as you can find in the quickstarts source code. The WildFly quickstarts have been ported to rely on WildFly Glow. You can clone the following quickstart branch and play with the quickstarts of your choice. The package goal of the WildFly Maven Plugin scans the application, discovers the provisioning configuration then provisions the server and deploy the application. The server is started (wildfly:start goal) then the tests are executed to interact with the application deployed in the server. For example: cd helloworld mvn clean package -Pprovisioned-server mvn wildfly:start mvn verify -Pintegration-testing -Dserver.host=http://localhost:8080 mvn wildfly:shutdown In some cases you need to run tests from inside the server or you want to tests multiple deployments, that is where the WildFly Arquillian Adapter is needed. Testing using the WildFly Arquillian Adapter Arquillian deployments When using Arquillian, the deployments to be deployed to the WildFly server are created by static Java methods annotated with the @org.jboss.arquillian.container.test.api.Deployment annotation. These deployments are created and deployed during test execution by Arquillian. WildFly Glow Arquillian Maven Plugin Details on how to use and configure the plugin can be found in the plugin documentation. In this blog post we are introducing its usage. The WildFly Glow Arquillian Maven plugin scans all the @Deployment annotated static methods, and invokes them to obtain each deployment. It then scans these deployments to discover the required Galleon layers. A provisioning.xml file containing the discovered layers and feature-packs is generated. This Galleon configuration file is then used by the actual provisioning tooling (Galleon Maven Plugin, WildFly Maven Plugin, WildFly JAR Maven Plugin) to provision the test server. In order to validate that what the scanning has discovered is what you are expecting, you can configure the wildfly-glow-arquillian-plugin maven plugin to contain the element <expected-discovery>. For example: <expected-discovery>[cdi, ee-integration, ejb, ejb-lite, elytron-oidc-client, naming, servlet]==>ee-core-profile-server,ejb,elytron-oidc-client</expected-discovery> The left part of the arrow contains the list of the discovered layers according to the scanning. The right part is what will get provisioned. Composed of a base layer (always ee-core-profile-server) and a list of the discovered layers not contained in the base layer. During plugin execution, the discovered layers are printed. If that is valid with respect to your tests, you can copy and paste this output as the <expected-discovery> value. If that is not valid (e.g.: some layers should not be present), you can enable <verbose>true</verbose> to see why a layer was selected. WildFly Glow is based on rules contained in the Wildfy Galleon layers. If a rule matches, the layer is included. The set of rules contained in WildFly layers is documented in this documentation. An example of output: ... layers inclusion rules * ee-core-profile-server - BASE_LAYER * ee-concurrency - JAVA_TYPE: [jakarta.enterprise.concurrent.*] * undertow-https - ADD_ON ... This output means: ee-core-profile-server is a base layer (always included). ee-concurrency layer is included because a Java class located in the java package jakarta.enterprise.concurrent has been found. undertow-https is included because it is bound to an included add-on (in this case ssl). BTW: The WildFly integration tests contain a lot of examples of WildFly Glow scanning executions that you could use as a starting-point. Simple pom.xml example In this example, both the wildfly-glow-arquillian-plugin and wildfly-maven-plugin are bound to the test-compile phase (run after the test classes have been compiled). The wildfly-glow-arquillian-plugin execution produces the file target/glow-scan/provisioning.xml that is then consumed by the wildfly-maven-plugin to provision the server (in the directory target/server). ... <build> <plugins> <plugin> <groupId>org.wildfly.glow</groupId> <artifactId>wildfly-glow-arquillian-plugin</artifactId> <version>1.0.0.Beta7</version> <executions> <execution> <id>scan</id> <goals> <goal>scan</goal> </goals> <phase>test-compile</phase> </execution> </executions> </plugin> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>5.0.0.Beta2</version> <configuration> <provisioning-file>${project.build.directory}/glow-scan/provisioning.xml</provisioning-file> </configuration> <executions> <execution> <id>test-provisioning</id> <goals> <goal>provision</goal> </goals> <phase>test-compile</phase> </execution> </executions> </plugin> </plugins> </build> The provisioned server is then started by Arquillian and tests are executed. As you can see the provisioning aspects are fully handled by the tooling, allowing you to focus on the testing. For more advanced usage (e.g.: selecting a WildFly version, an execution profile, adding add-ons, selecting specific surefire executions to provision multiple servers) you should check the WildFly Glow documentation. We hope that you will see how useful WildFly Glow can be for your WildFly application testing. Your feedback would be very valuable to evolve WildFly Glow in the right direction. Feel free to log issues in the project. Thank-you! Jean-Francois Denise ### [What's new in WildFly provisioning](/news/2024/01/31/What-s-new-in-WildFly-provisioning/) This blog post provides information on recent evolutions that have occurred at the WildFly provisioning level. WildFly Glow tooling This new approach to WildFly provisioning has been covered in details in this blog post and in this video published on the WildFly Youtube Channel. We are expecting more content to be published on this topic; stay tuned! WildFly Bootable JAR support in the WildFly Maven Plugin From version 5.0.0.Beta2, the WildFly Maven Plugin allows you to provision a WildFly server as a Wildfly Bootable JAR. The package goal configuration has been evolved with the following options: <bootable-jar>true|false</bootable-jar>: to enable generation of a Bootable JAR. <bootable-jar-name>name of the jar<bootable-jar-name>: to set a specific JAR name. By default it is named server-bootable.jar In addition, a new goal start-jar has been introduced to start the generated JAR. The shutdown goal can be used to shutdown a bootable JAR. The WildFly JAR Maven plugin will stay, but the WildFly Maven Plugin becomes the preferred way to build a WildFly Bootable JAR and provision a WildFly server for the cloud. WildFly Bootable JAR and cloud execution limitations When using the WildFly JAR Maven Plugin, you have the ability to set the <cloud/> option. This option has not been migrated to the WildFly Maven Plugin. The reasons are: Part of the content (the set of bash scripts that are run at server startup) packaged in the org.wildfly.cloud:wildfly-cloud-galleon-pack that is used for the cloud context is not usable when the server is packaged as a Bootable JAR. In a cloud context, the kind of packaging is not really relevant. WildFly servers are not directly started. Containers are started whatever the kind of installed WildFly server. So the JAR produced by the WildFly Maven Plugin is not expected to be used in a cloud context. For cloud we advise provisioning a WildFly server. To do so: Use WildFly Glow support (<context>cloud</context>) that will automatically retrieve the required Galleon feature-packs or If not using WildFly Glow, add the org.wildfly.cloud:wildfly-cloud-galleon-pack feature-pack to the feature-packs list. Galleon Upward compatibility WildFly provisioning tooling heavily relies on Galleon technology. Galleon uses the WildFly feature-packs to provision a WildFly server. One issue that we have been facing in the past is that, when the structural content of a feature-pack changes (due to an evolution of Galleon core library or new XML schema), the provisioning tooling must be upgraded to be able to handle the new format. The failure occurs during provisioning, printing an hard to understand error message. The root cause of this problem is that a WildFly feature-pack can require a specific version of the Galleon core library to be properly provisioned, and this version can differ from the version that the provisioning tooling (Galleon CLI or Maven Plugin, WildFly Maven Plugin, WildFly Bootable JAR Maven Plugin, WildFly Glow) directly depends on. To solve this problem we have evolved Galleon. WildFly Galleon feature-pack build time When using WildFly Galleon Maven Plugin 7.0.0.Beta1, the Galleon version used to build the feature-pack is included in the feature-pack. A check is done at build time to validate that the content of the feature-pack is valid with respect to the Galleon version in use. If some content is not supported, the build fails, and an upgrade of the WildFly Galleon Maven Plugin is required. WildFly provisioning time We have been introducing a new Galleon tooling API that isolates the provisioning tooling from the Galleon Core version. The API implementation detects the core version required by the feature-packs and uses it. So we should now be protected at provisioning time from incompatible changes. This API is backward compatible with older WildFly feature-packs. The following provisioning tools have been ported to the new API: Galleon CLI and Maven Plugin 6.0.0.Beta1 WildFly Maven Plugin 5.0.0.Beta2 WildFly Bootable JAR Maven Plugin 11.0.0.Beta1 WildFly Glow 1.0.0.Beta7 In addition, the Galleon CLI now checks for the latest version of Galleon at startup and advises you if a new version is available. This Galleon evolution is currently present in Galleon 6.0.0.Beta1. WildFly 31 has not yet switched to use it, but upgrading your provisioning tooling today would prepare you for the next major WildFly release. We plan to have Final releases prior to the WildFly 32 release. Thank-you! Jean-Francois Denise ### [WildFly Glow, an evolution of WildFly provisioning](/news/2024/01/29/WildFly-Glow-an-evolution-of-WildFly-provisioning/) We are introducing an evolution of WildFly provisioning by means of the WildFly Glow project. What is WildFly provisioning? Even though WildFly provisioning has been available for some time now, a quick summary seems useful to put WildFly Glow in context. WildFly provisioning is: The ability to create a WildFly server installation on the fly. The ability to choose the set of features you want to see in the created server. The ability to extend the capabilities of the WildFly server (e.g.: datasources, Keycloak SAML). The produced server has a smaller size than a full installation and the server process has a smaller memory footprint. Trimming comes with some benefits: Reduced resource consumption. Smaller attack surface. Simpler server configuration. Galleon is the technology used by WildFly provisioning. How is provisioning performed? WildFly provisioning uses two kinds of tooling: Command Line tools: Galleon CLI Maven Plugins: Galleon Maven Plugin WildFly Maven Plugin WildFly Bootable JAR Maven Plugin What are the main concepts of WildFly provisioning? Galleon feature-packs: contain metadata on how to build a WildFly server. Galleon layers: contain metadata of a high level server feature (eg: jaxrs, ejb, jsf, …​). If you want to deep dive into Galleon concepts, you can have a look at its documentation. In the context of WildFly Glow, feature-packs and layers are really all you need to know about. Provisioning a WildFly server is mainly selecting Galleon feature-packs and Galleon layers. WildFly provisioning diagram The above shows a simplified representation of what provisioning is. Let’s look at the complexity that comes with such flexibility. Current WildFly provisioning has a complex configuration The issues we are currently facing are mainly located at the user configuration level. It is not that trivial to build up a proper WildFly server to run your applications. Known issues: How to know about available Galleon feature-packs? How to discover the Galleon layers that my application requires to properly work? Current solutions: Use WildFly documentation, look at WildFly quickstarts, search for blogs and/or github projects to discover extra feature-packs. Use WildFly base layers (aggregators for the main application use cases) such as cloud-server or jaxrs-server layers. Something to note is that when using these aggregators the set of features that you are provisioning may not be optimal. More content is usually provisioned than what your application requires. Furthermore these layers don’t contain everything, and, to meet your application’s requirements, you may need to add some more layers (e.g.: microprofile-config, ejb, jsf, …​). To summarize we need a way to discover all the extra Galleon feature-packs that would provide interesting features and a way to link the deployed application(s) to the set of required Galleon layers. This is what WildFly Glow is all about, a provisioning time bridge between the deployment and the WildFly server. WildFly Glow Glow stands for “Galleon Layers Output from War”. By inspecting your deployments(s), WildFly Glow can determine the set of Galleon feature-packs and layers that your application requires. Note Despite the "War" used in the acronym that led to WildFly Glow’s name, it can analyze all Jakarta EE deployment types, not just .war files. WildFly Glow knows the set of feature-packs compatible with a given WildFly version. It understands the connection that exists between Galleon layers and your application: Java types and annotations in use XML descriptors, Properties files, … WildFly Glow can suggest interesting features not directly required by your application but meaningful. For example: SSL when Undertow is in use, Microprofile OpenAPI when Jakarta REST is in use, WildFly CLI tools (all CLI launch scripts located in the WILDFLY_HOME/bin directory), …​ WildFly Glow goes one step further than pure provisioning by identifying potential errors. And, when errors are identified, it can suggest ways to fix them (eg: add a missing datasource, add a missing access to a JMS broker). To summarize, WildFly Glow can build the server from your deployments and helps you discover additional WildFly server features that you are perhaps not aware of. The WildFly documentation site includes detailed documentation of WildFly Glow. WildFly Glow Features A set of Tooling WildFly Glow CLI, a standalone tool to scan your deployment to produce a WildFly server, a WildFly Bootable JAR or a docker image. Integration into the WildFly Maven Plugin 5.x — no more need for explicit feature-packs and layers in the plugin configuration. WildFly Glow Arquillian Maven plugin to scan your tests to produce a WildFly server required to execute your tests. Handling of High Availability WildFly Glow allows you to enable an “ha” profile to produce a High Availablity WildFly server. Handling of 2 execution contexts bare-metal (the default). cloud, to execute on Openshift and/or Kubernetes. In addition to fine tuning the server configuration for cloud execution, WildFly Glow discovers and advertises the WildFly env variables usable to configure the server at startup. Handling of datasources Identify missing datasources and suggest datasources that you can use to connect to databases. Knowledge of extra Feature-Packs A centralized knowledge (located in the wildfly-galleon-feature-packs github project) of extra Galleon feature-packs compatible with WildFly. The WildFly features defined in these extra feature-packs are included in the provisioned server when WildFly Glow detects a need for them. The set of extra features supported are: Cloud features Support for the major datasources (PostgreSQL, MySQL, MariaDB, MSSQLServer, Oracle) Keycloak SAML GRPc MyFaces Microprofile-GraphQL Support for WildFly Preview WildFly Glow allows you to choose to provision a WildFly Preview server instead of a WildFly server. Note Don’t know about WildFly Preview? To learn more, see the WildFly documentation. How WildFly Glow operates WildFly Glow is used from provisioning tooling: the WildFly Glow command line tool or the WildFly Maven Plugin (starting with version 5.0.0 Beta). Java classes and file descriptors located in your deployments are scanned to identify the required set of galleon layers. It leverages Galleon provisioning artifacts (Feature-Packs and Layers). It relies on rules included in each Galleon Layer. Rules capture the content expected inside the deployment for the layer to be required. Rules express the High Availability capability of a layer. Rules classify some layers as add-on that can be explicitly included. add-ons are advertised according to the set of layers discovered in the deployments. e.g.: SSL, embedded/remote JMS brokers, datasources, WildFly CLI (jboss-cli, add-users, elytron tooling, .,..). It knows about High Availability profile, and will automatically include HA Galleon layers. WildFly Glow rules You can find documentation on the rules contained in WildFly Galleon layers in this documentation. WildFly Glow Provisioning diagram Provisioning tooling usage comparison WildFly Maven plugin Simple server Configuration without WildFly Glow support ... <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.server}</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>ejb</layer> </layers> ... Configuration with support for WildFly Glow The XML element <discover-provisioning-info> enables the support for WildFly Glow (starting with WildFly Maven Plugin version 5 Beta). ... <discover-provisioning-info/> ... The provisioning configuration is fully delegated to WildFly Glow. It will include and exclude Galleon layers according to what has been discovered (exclusion of layers can be required when provisioning an HA server). HA server for cloud execution with support for a PostgreSQL datasource Configuration without WildFly Glow support ... <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.server}</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:${version.cloud}</location> </feature-pack> <feature-pack> <location>org.wildfly:wildfly-datasources-galleon-pack:${version.ds}</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>ejb</layer> <layer>ejb-dist-cache</layer> <layer>jpa-distributed</layer> <layer>postgresql-driver</layer> </layers> <excludedLayers> <layer>ejb-local-cache</layer> <layer>jpa</layer> </excludedLayers> ... You can notice that some Galleon layers have been excluded and their HA counter parts have been included. Configuration with support for WildFly Glow The XML element <discover-provisioning-info> is evolved with the ha profile, cloud context and the postgresql add-on. ... <discover-provisioning-info> <profile>ha</profile> <context>cloud</context> <add-ons> <add-on>postgresql</add-on> </add-ons> </discover-provisioning-info> ... And What about WildFly Bootable JAR? The WildFly Bootable JAR Maven Plugin has not been evolved to support WildFly Glow. Instead, we have evolved the WildFly Maven Plugin to also produce a WildFly Bootable JAR. So you can benefit from WildFly Glow and build WildFly executable JARs by using the same Maven plugin. To enable Bootable JAR packaging, set the <bootable-jar>true</bootable-jar> plugin option. Details on how to produce WildFly Bootable JAR from the WildFly Maven Plugin will come in a following blog post. Galleon CLI vs WildFly Glow CLI Server with support for postgresql datasource Galleon CLI galleon.sh install wildfly --layers=cloud-server,ejb,jsf --dir=server galleon.sh install org.wildfly:wildfly-datasources-galleon-pack:6.0.0.Final --layers=postgresql-datasource --dir=server You will then have to deploy your application into the provisioned server. WildFly Glow CLI wildfly-glow.sh scan myapp.war --add-ons=postgresql --provision=SERVER Note The provisioned server contains the deployment that has been scanned. By specifying --provision=BOOTABLE_JAR you can produce a WildFly bootable JAR. By specifying --provision=DOCKER_IMAGE you can produce a Docker image. If you don’t use the --provision parameter at all, WildFly Glow will simply output a report of what it has discovered. Here’s an example of producing a Docker image for cloud execution: wildfly-glow.sh scan myapp.war --add-ons=postgresql --provision=DOCKER_IMAGE --cloud Output example WildFly Glow CLI output shows what it has discovered, for example: wildfly-glow.sh scan myapp.war Wildfly Glow is scanning... context: bare-metal enabled profile: none galleon discovery - feature-packs org.wildfly:wildfly-galleon-pack:30.0.1.Final - layers ee-core-profile-server jpa ejb-lite jaxrs jsf h2-driver Some suggestions have been found. You could enable suggestions with --suggest option (if using the WildFly Glow CLI) or <suggest>true</suggest> (if using the WildFly Maven Plugin). If you had included a --provision option to the scan command, after outputting this report, WildFly Glow will continue on to provisioning your WildFly server, bootable jar or Docker image. Understanding why a Galleon layer has been selected WildFly Glow is based on rules contained in the WildFly Galleon layers. If a rule matches, the layer is included. The set of rules contained in WildFly layers is documented in this documentation. If verbose mode is enabled (--verbose option with the WildFly Glow CLI, <verbose>true</verbose> option for the maven plugin), WildFly Glow will output for each layer the rules that matched. An example of output: ... layers inclusion rules * ee-core-profile-server - BASE_LAYER * ee-concurrency - JAVA_TYPE: [jakarta.enterprise.concurrent.*] * undertow-https - ADD_ON ... This output means: ee-core-profile-server is a base layer (always included). ee-concurrency layer is included because a Java class located in the java package jakarta.enterprise.concurrent has been found. undertow-https is included because it is bound to an included add-on (in this case ssl). Trimming numbers with WildFly Glow We have measured the Disk usage and Memory consumption of some WildFly quickstarts (using the WildFly Glow branch vs the main branch). We have observed a reduction of 5% to 55% for disk usage and 5% to 32% for memory consumption. Variation is bound to the complexity of the quickstart. If the quickstart requires all the Galleon layers present in an aggregator layer (eg: cloud-server or jaxrs-server) then the gain is lower. My colleague Kabir Khan has written an interesting project and is going to publish a Vlog on the WildFly Channel that will showcase the gain you can expect with WildFly Glow. Stay tuned! Datasources support, missing datasource detection If WildFly Glow detects that your deployment uses datasources, it will abort asking you to take an action to fix the problem. It will suggest the set of known add-ons allowing WildFly to connect to a database. You will have to choose one of the proposed add-ons. An example of a reported error when using the WildFly Glow CLI: wildfly-glow scan todo-backend.war Wildfly Glow is scanning... context: bare-metal enabled profile: none galleon discovery - feature-packs org.wildfly:wildfly-galleon-pack:30.0.1.Final - layers ee-core-profile-server ejb-lite jpa jaxrs identified errors * unbound datasources error: java:jboss/datasources/ToDos To correct this error, enable one of the following add-ons: - mariadb - mssqlserver - mysql - oracle - postgresql Some suggestions have been found. You could enable suggestions with --suggest option (if using the WildFly Glow CLI) or <suggest>true</suggest> (if using the WildFly Maven Plugin). To enable add-ons, add the --add-ons=<list of add-ons> option to the scan command Some errors have been reported. You should fix them prior provisioning a server with the --provision option of the scan command Datasources support, setting a datasource add-on We will use the postgresql add-on to fix the reported error. wildfly-glow scan todo-backend.war --add-ons=postgresql Wildfly Glow is scanning... context: bare-metal enabled profile: none galleon discovery - feature-packs org.wildfly:wildfly-galleon-pack:30.0.1.Final org.wildfly:wildfly-datasources-galleon-pack:6.0.0.Final - layers ee-core-profile-server ejb-lite jpa jaxrs postgresql-datasource enabled add-ons - postgresql : Documentation in https://github.com/wildfly-extras/wildfly-datasources-galleon-pack strongly suggested configuration postgresql-datasource environment variables: - POSTGRESQL_DATABASE=Defines the database name to be used in the datasource’s `connection-url` property. - POSTGRESQL_JNDI=java:jboss/datasources/ToDos - POSTGRESQL_PASSWORD=Defines the password for the datasource. - POSTGRESQL_USER=Defines the username for the datasource. WildFly Glow detects that the postgresql datasource has to be configured with environment variables and advertises the set of environment variables to be used when starting the server. Example of a server started with environment variables set: POSTGRESQL_DATABASE=test \ POSTGRESQL_JNDI=java:jboss/datasources/ToDos \ POSTGRESQL_PASSWORD=test \ POSTGRESQL_USER=test \ sh ./bin/target/server/bin/standalone.sh Experimenting with WildFly Glow Using the WildFly Glow CLI To get started with the WildFly Glow CLI, you can download the latest release. To scan a deployment you plan to deploy to WildFly, call: wildfly-glow.sh scan <your deployment> You can report issues/suggestions as Issues in the WildFly Glow project. Using the WildFly Maven Plugin The WildFly quickstarts have been ported to rely on WildFly Glow. You can clone the quickstart glow-preview branch and play with the quickstarts of your choice. For example: cd helloworld mvn clean package -Pprovisioned-server To produce a WildFly Bootable JAR call: cd microprofile-config mvn clean package -Pbootable-jar Status For WildFly 31, WildFly Glow is at a Beta level of quality. Some facts: Latest WildFly Glow version is currently 1.0.0.Beta7. WildFly Maven Plugin 5.0.0.Beta2 supports WildFly Glow and the ability to produce a WildFly Bootable JAR. All WildFly quickstarts have been ported to use WildFly Glow in this preview branch. The WildFly 31 testsuite has been enhanced to use WildFly Glow everywhere it is practical. WildFly Galleon feature-packs registry is open to contribute more extra feature-packs compatible with WildFly. Final level of quality is expected for WildFly 32 WildFly Glow Final. WildFly Quickstarts main branch migrated to WildFly Glow. We hope that you will find interest in this simplified approach to provisioning WildFly servers. Your feedback would be very valuable to evolve WildFly Glow in the right direction. Feel free to log issues in the project. Thank-you! Jean-Francois Denise ### [WildFly Guides](/news/2024/01/26/WildFly-Guides/) We have recently published a first collection of guides on the WildFly homepage. You can find the guides in the top-level navigation under Guides. They are divided into different categories. Currently, we have guides for "Get Started", "Observability", "Security", "MicroProfile", and "Automation". What to expect The guides address one topic of a specific use case in more detail. Unlike the reference documentation, the guides describe step by step how a specific task can be approached and solved. All guidelines have a common structure, clearly list the prerequisites and provide an estimate of the time required for completing the task. We need your feedback We would liek to get your feedback about the guides. Please use the forum or the chat and let us know how you like them. What’s next? Expect more guides to come in the next months. If you’re missing a topic or even would like to contribute to the guides, please let us know! ### [WildFly 31 is released!](/news/2024/01/25/WildFly-31-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 31.0.0.Final releases are available for download at https://wildfly.org/downloads. New and Notable This quarter there’s a lot to talk about beyond new things in the core server itself, but I’ll start with what’s new in the server. Application Server Features MicroProfile updates — We’ve updated our MicroProfile subsystems to the versions in MicroProfile 6.1. (We don’t support MicroProfile Metrics, so we are not a compatible MicroProfile 6.1 Platform implementation, but otherwise we do aim to keep up with the platform). Hibernate — I always hear a lot of community demand for updates to our Hibernate integration, so I’m pleased that in WildFly 31 we were able to move from Hibernate ORM 6.2 up to the 6.4.2 release, the latest available ORM version. Along with that we were able to move to Hibernate Search 7.0. Jakarta MVC 2.1 — In WildFly Preview we added support for Jakarta MVC, using the implementation provided by the Eclipse Krazo project. WildFly Preview provides a new mvc-krazo subsystem, along with a new mvc-krazo Galleon layer that you can add to your provisioning configuration. Please try it out and give us feedback. We hope to bring this subsystem to standard WildFly later this year. AMQP and Reactive Messaging — The MicroProfile Reactive Messaging subsystem now allows exchanging of messages with an AMQP broker via version 1.0 of the AMQP protocol. Subsystem authoring — WildFly Core 23 now includes two new Maven modules, subsystem and service. Both of these aim to make developing and maintaining WildFly extensions easier and more productive. The subsystem module library assists you in writing a proper subsystem configuration model and management API, while the service module helps you properly integrate your subsystem with WildFly’s service container. Stability levels — WildFly 31 introduces the notion of server functionality having four different stability levels (experimental, preview, community, default), with users having the ability when starting WildFly to opt into making less stable features available, or to restrict WildFly to only providing the most stable features. This is part of the overall feature development strategy I outlined last November. In WildFly 31 we’re just getting started with this — introducing the core capability to the server and adding one new feature at the community stability level…​. Configuration export — That community level feature allows you to use the CLI to export a WildFly server’s configuration to a file that can then be used for another server. WildFly has long allowed you to read the server configuration in the CLI, but the presentation format was not well suited to taking the information and using it elsewhere. This has been enhanced. A particular use case for this would be exporting a domain-mode server’s configuration, where the resulting file can be used to run an equivalent standalone server. Moving on from what’s new in the server itself, we come to…​ WildFly Glow Ever since the introduction of Galleon several years back, a major WildFly focus has been tooling to improve our users' ability to easily provision an optimal WildFly installation, on-premise and particularly for the cloud. I’m very excited to announce Beta availability of a major advance in this area — the set of provisioning tools we call WildFly Glow. The WildFly Glow tools (a CLI application and a Maven plugin) will analyze your application artifact, determine what WildFly feature-packs and Galleon layers are needed to run your application, and make suggestions about other features (e.g. TSL support) that you may want to include in your optimized WildFly installation. You can take the information WildFly Glow provides and use it in your own provisioning configuration, or you can have WildFly Glow provision a server, bootable jar or Docker image for you. The WildFly Glow documentation gives you a good sense of what WildFly Glow is about. But to really help you understand WildFly Glow’s benefits, Jean Francois Denise has several excellent news posts about WildFly Glow and WildFly provisioning in general that will begin appearing here early next week. So be sure to keep an eye out for those, and be sure to try it out! Easier Learning Making it easier to use WildFly was a major focus for the WildFly developer community last year, and during the WildFly 31 cycle those efforts bore a lot of fruit. Getting Started For WildFly 30 we introduced a new Getting Started maven archetype, and for WildFly 31 we’ve made use of that archetype in a new Get Started page on wildfly.org. The guide on that page was an initial step in an effort to improve WildFly documentation by going beyond reference material with the addition of focused, task-oriented…​ User Guides This section is a bit of a "preview of coming attractions". The "Get Started with WildFly" guide I just mentioned is the first in a set of user guides that we’ll be publishing shortly in a new "Guides" section of this site. The first batch will focus on logging, security, MicroProfile Config, and Ansible, with more to come. Each guide will show the steps to accomplish a specific, focused task, with links to guides showing any prerequisites and to guides for related tasks. This is something WildFly has long needed, and we’re very excited to see it happening! Quickstart Enhancements There are a number of new things in the WildFly Quickstarts. Common enhancements — Eduardo Martins led a massive effort to improve our dozens of quickstarts: All quickstarts demonstrate provisioning a WildFly server or bootable jar with the quickstart deployment included, as an alternative to the traditional method of deploying the quickstart to an externally managed WildFly instance. The quickstart README files use consistent instructions for how to do this. For any quickstart where it is technically possible (i.e the large majority), the quickstart is able to run on OpenShift, using a Helm chart to deploy. The quickstart README files also use consistent instructions for how to do this. Quickstarts all include basic smoke and quickstart-specific tests, with the tests able to run against an externally managed WildFly server, against the server or bootable jar provisioned by the quickstart, and against the quickstart application + server deployed on OpenShift. New Quickstarts — We’ve also introduced two new quickstarts: Micrometer MicroProfile LRA Browsable Quickstarts — The traditional expected use of quickstarts is the user clones the Quickstart git repository, builds the quickstarts and then explores them locally. However, users may also want to browse the quickstart documents and source code online. Browsing the quickstart GitHub repo is not very friendly for that, as it shows raw adoc files, not the rendered html. So, beginning with WildFly 31 we now publish the rendered documentation for the latest releases quickstarts on the WildFly documentation site. You can easily read the quickstart instructions and browse into the quickstart source code. This portion of the documentation site will be updated with each .Final release of the quickstarts. Easy Quickstart Download — Another old school way of consuming quickstarts is to download a zip with all the quickstart source, unzipping and going from there. Beginning with WildFly 31 we’ll make this easier by including a link to a downloadable quickstart zip in each release’s section on the downloads page. Feature Analyses For a long time now the WildFly developers have been writing analysis documents whenever we introduce new features. You may have seen links to the documents in previous release announcements, as I often link to them when discussing new features. They are meant to provide a feature overview and discuss use cases, clearly enumerate requirements, and provide various other high-level information about the feature. There’s a lot of good information in these documents, so we’ve begun publishing them on the WildFly documentation site. Have a look and you may learn something new about your favorite WildFly feature! What’s displayed there are the analyses for merged features; if you’re interested in following what may be coming in the future, keep an eye on the wildfly-proposals GitHub repo. Supported Specifications Jakarta EE WildFly 31 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly is EE 10 Platform, Web Profile and Core Profile compatible when running on both Java SE 11 and Java SE 17. WildFly is also a compatible EE 10 Core Profile implementation when running on SE 21. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence Jakarta EE 10 Full Platform SE 11 SE 17 Jakarta EE 10 Web Profile SE 11 SE 17 Jakarta EE 10 Core Profile SE 11 SE 17 SE 21 MicroProfile WildFly supports numerous MicroProfile specifications. Because we no longer support MicroProfile Metrics, WildFly 31 cannot claim to be a compatible implementation of the MicroProfile 6.1 specification. However, WildFly’s MicroProfile support includes implementations of the following specifications in our "full" (e.g. standalone-full.xml) and "default" (e.g standalone.xml) configurations as well as our "microprofile" configurations (e.g. standalone-microprofile.xml): MicroProfile Technology WildFly Full/Default Configurations WildFly MicroProfile Configuration MicroProfile Config 3.1 X X MicroProfile Fault Tolerance 4.0  —  X MicroProfile Health 4.0  —  X MicroProfile JWT Authentication 2.1 X X MicroProfile LRA 2.0  —  X MicroProfile OpenAPI 3.1  —  X MicroProfile Reactive Messaging 3.0  —   —  MicroProfile Reactive Streams Operators 3.0  —   —  MicroProfile Rest Client 3.0 X X MicroProfile Telemetry 1.1  —  X Compatibility evidence for the above specifications that are part of MicroProfile 6.1 can be found in the WildFly Certifications repository on GitHub. Java SE Support Recommended SE Versions Our recommendation is that you run WildFly 31 on Java SE 17, as that is the latest LTS JDK release where we have completed the full set of testing we like to do before recommending a particular SE version. WildFly 31 also is heavily tested and runs well on Java 11. One reason to use later SE versions is because it gets you ahead of the curve as WildFly and other projects begin to move on from supporting older SE releases. In the WildFly 30 release announcement I indicated that WildFly 30 would likely be the last feature release to support SE 11. Obviously, that is not the case as we still support SE 11. We’re continuing to evaluate our plans around SE 11 support, and I’ll be sure to post here as we make decisions. I do encourage WildFly users to prepare now for any eventual change move off of SE 11. Please note that WildFly runs in classpath mode. Java SE 21 WildFly 31 also runs well on SE 21, the latest LTS release. By "runs well" I mean that we get the same results on SE 21 when running WildFly’s and WildFly Core’s own extensive test suites as we do when running SE 17 or SE 11. As noted above, we also pass the Jakarta EE 10 Core Profile TCK when running on SE 21, as well as the MicroProfile TCKs for the various specifications we support. We do not yet include SE 21 in the preceding "Recommended SE Versions" section because: We have not completed our program of seeing how WildFly on SE 21 does on the Jakarta EE Full Platform and Web Profile TCKs. We need to do further investigation into how the projects producing the various libraries we integrate are testing on SE 21. We made good progress on these points during the WildFly 31 development cycle, and continuing to do so is a major priority for the WildFly project in 2024. If you are trying to evaluate what SE 21 means for your applications, I encourage you to look to WildFly as your evaluation platform. WildFly Mini-Conference!!! We are busy at work on preparations for a WildFly online mini-conference in the coming weeks. We’d love to see you there! Keep an eye on this space, @WildFlyAS on X or @wildflyas on fosstodon for information about dates and the conference agenda! Release Notes The full WildFly 31 release notes are available in GitHub. Issues fixed in the underlying WildFly Core 23 releases are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. Meanwhile, we’re busy at work on WildFly 32! Best regards, Brian ### [Deploying a WildFly 30.0.1.Final cluster using Ansible](/news/2024/01/18/Deploying-a-WildFly-30-0-1-Final-cluster-using-Ansible/) In this brief demonstration, we’ll set up and run three instances of WildFly on the same machine (localhost). Together they will form a cluster. It’s a rather classic setup, where the appservers needs to synchronize the content of their application’s session to ensure fail over if one of the instances fails. This configuration guarantees that, if one instance fails while processing a request, another one can pick up the work without any data loss. Note that we’ll use a multicast to discover the members of the cluster and ensure that the cluster’s formation is fully automated and dynamic. Install Ansible and its collection for WildFly On a Linux system using a package manager, installing Ansible is pretty straightforward: $ sudo dnf install ansible-core Please refer to the documentation available online for installation on other operating system. Note that this demonstration assumes you are running both the Ansible controller and the target (same machine in our case) on a Linux system. However, it should work on any other operating system with a few adjustements. Before going further, double check that you are running a recent enough version of Ansible (2.14 or above will do, but 2.9 is the bare minimum): ansible [core 2.15.3] config file = /etc/ansible/ansible.cfg configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3.11/site-packages/ansible ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections executable location = /usr/bin/ansible python version = 3.11.2 (main, Jun 6 2023, 07:39:01) [GCC 8.5.0 20210514 (Red Hat 8.5.0-18)] (/usr/bin/python3.11) jinja version = 3.1.2 libyaml = True The next, and last, step to ready your Ansible environment is to install the Ansible collection for WildFly on the controller (the machine that will run Ansible): # ansible-galaxy collection install middleware_automation.wildfly Starting galaxy collection install process Process install dependency map Starting collection install process Downloading https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/middleware_automation-wildfly-1.4.3.tar.gz to /root/.ansible/tmp/ansible-local-355dkk9kf5/tmpc2qtag11/middleware_automation-wildfly-1.4.3-9propr_x Downloading https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/ansible-posix-1.5.4.tar.gz to /root/.ansible/tmp/ansible-local-355dkk9kf5/tmpc2qtag11/ansible-posix-1.5.4-pq0cq2mn Installing 'middleware_automation.wildfly:1.4.3' to '/root/.ansible/collections/ansible_collections/middleware_automation/wildfly' middleware_automation.wildfly:1.4.3 was installed successfully Installing 'ansible.posix:1.5.4' to '/root/.ansible/collections/ansible_collections/ansible/posix' Downloading https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/middleware_automation-common-1.1.4.tar.gz to /root/.ansible/tmp/ansible-local-355dkk9kf5/tmpc2qtag11/middleware_automation-common-1.1.4-nks7pvy7 ansible.posix:1.5.4 was installed successfully Installing 'middleware_automation.common:1.1.4' to '/root/.ansible/collections/ansible_collections/middleware_automation/common' middleware_automation.common:1.1.4 was installed successfully Set up the WildFly cluster For simplicity’s sake and to allow you to reproduce this demonstration on a single machine (physical or virtual) or even a container, we opted to deploy our three instances on one target. We chose localhost as a target, so that the demonstration can even be performed without a remote host. There are essentially two steps to set up the WildFly cluster: Install WildFly on the targeted hosts (here just localhost). This means downloading the archive from this website and decompressing the archive in the appropriate directory (JBOSS_HOME). These tasks are handled by the wildfly_install role supplied by Ansible collection for WildFly. Create the configuration files to run several instances of WildFly. Because we’re running multiple instances on a single host, you also need to ensure that each instance has its own subdirectories and set of ports, so that the instances can coexist and communicate. Fortunately, this functionality is provided by a role within the Ansible collection called wildfly_systemd. Ansible playbook to install WildFly Here is the playbook we’ll use to deploy our clusters. Its content is relatively self-explanitory, at least if you are somewhat familiar with the Ansible syntax. - name: "WildFly installation and configuration" hosts: "{{ hosts_group_name | default('localhost') }}" become: yes vars: wildfly_install_workdir: '/opt/' wildfly_config_base: standalone-ha.xml wildfly_version: 30.0.1.Final wildfly_java_package_name: java-11-openjdk-headless.x86_64 wildfly_home: "/opt/wildfly-{{ wildfly_version }}" instance_http_ports: - 8080 - 8180 - 8280 app: name: 'info-1.2.war' url: 'https://drive.google.com/uc?export=download&id=13K7RCqccgH4zAU1RfOjYMehNaHB0A3Iq' collections: - middleware_automation.wildfly roles: - role: wildfly_install tasks: - name: "Set up for WildFly instance {{ item }}." ansible.builtin.include_role: name: wildfly_systemd vars: wildfly_config_base: 'standalone-ha.xml' wildfly_instance_id: "{{ item }}" instance_name: "wildfly-{{ wildfly_instance_id }}" wildfly_config_name: "{{ instance_name }}.xml" wildfly_basedir_prefix: "/opt/{{ instance_name }}" service_systemd_env_file: "/etc/wildfly-{{ item }}.conf" service_systemd_conf_file: "/usr/lib/systemd/system/wildfly-{{ item }}.service" loop: "{{ range(0,3) | list }}" - name: "Wait for each instance HTTP ports to become available." ansible.builtin.wait_for: port: "{{ item }}" loop: "{{ instance_http_ports }}" - name: "Checks that WildFly server is running and accessible." ansible.builtin.get_url: url: "http://localhost:{{ port }}/" dest: "/opt/{{ port }}" loop: "{{ instance_http_ports }}" loop_control: loop_var: port In short, this playbook uses the Ansible collection for WildFly to, first, install the appserver by using the wildfly_install role. This will download all the artifacts, create the required system groups and users, install dependency (unzip) and so on. At the end of its execution, all the tidbits required to run WildFly on the target host are installed, but the server is not yet running. That’s what happening in the next step. In the tasks section of the playbook, we then call on another role provided by the collection: wildfly_systemd. This role will take care of integrating WildFly, as a regular system service, into the service manager. Here, we use a loop to ensure that we create not one, but three different services. Each one will have the same configuration (standalone-ha.xml) but runs on different ports, using a different set of directories to store its data. Run the playbook! Now, let’s run our Ansible playbook and observe its output: $ ansible-playbook -i inventory playbook.yml PLAY [WildFly installation and configuration] ********************************** TASK [Gathering Facts] ********************************************************* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Validating arguments against arg spec 'main'] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure prerequirements are fullfilled.] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/prereqs.yml for localhost TASK [middleware_automation.wildfly.wildfly_install : Validate credentials] **** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Validate existing zipfiles wildfly-30.0.1.Final.zip for offline installs] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Validate patch version for offline installs] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Validate existing additional zipfiles {{ eap_archive_filename }} for offline installs] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check that required packages list has been provided.] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Prepare packages list] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Add JDK package java-11-openjdk-headless.x86_64 to packages list] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Install required packages (5)] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure required local user exists.] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/user.yml for localhost TASK [middleware_automation.wildfly.wildfly_install : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Set wildfly group] ******* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure group wildfly exists.] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure user wildfly exists.] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure workdir /opt/ exists.] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure archive_dir /opt/ exists.] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure server is installed] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/install.yml for localhost TASK [middleware_automation.wildfly.wildfly_install : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check local download archive path] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Set download paths] ****** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check target archive: /opt//wildfly-30.0.1.Final.zip] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Retrieve archive from website: https://github.com/wildfly/wildfly/releases/download] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/install/web.yml for localhost TASK [middleware_automation.wildfly.wildfly_install : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Download zipfile from https://github.com/wildfly/wildfly/releases/download/30.0.1.Final/wildfly-30.0.1.Final.zip into /work/wildfly-30.0.1.Final.zip] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Retrieve archive from RHN] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Install server using RPM] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check downloaded archive] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Copy archive to target nodes] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check target archive: /opt//wildfly-30.0.1.Final.zip] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Verify target archive state: /opt//wildfly-30.0.1.Final.zip] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Read target directory information: /opt/wildfly-30.0.1.Final] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Extract files from /opt//wildfly-30.0.1.Final.zip into /opt/.] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Note: decompression was not executed] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Read information on server home directory: /opt/wildfly-30.0.1.Final] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check state of server home directory: /opt/wildfly-30.0.1.Final] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Set instance name] ******* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Deploy custom configuration] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Deploy configuration] **** changed: [localhost] TASK [Apply latest cumulative patch] ******************************************* skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure required parameters for elytron adapter are provided.] *** skipping: [localhost] TASK [Install elytron adapter] ************************************************* skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Install server using Prospero] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Check wildfly install directory state] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Validate conditions] ***** ok: [localhost] TASK [Ensure firewalld configuration allows server port (if enabled).] ********* skipping: [localhost] TASK [Set up for WildFly instance {{ item }}.] ********************************* TASK [middleware_automation.wildfly.wildfly_systemd : Validating arguments against arg spec 'main'] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check current EAP patch installed] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments for yaml configuration] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check if YAML configuration extension is supported in WildFly] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check if YAML configuration extension is supported in EAP] *** skipping: [localhost] TASK [Ensure required local user and group exists.] **************************** TASK [middleware_automation.wildfly.wildfly_install : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Set wildfly group] ******* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure group wildfly exists.] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure user wildfly exists.] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set destination directory for configuration] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set instance destination directory for configuration] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set base directory for instance] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] => { "changed": false, "msg": "All assertions passed" } TASK [middleware_automation.wildfly.wildfly_systemd : Set instance name] ******* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set instance name] ******* skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set bind address] ******** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Create basedir /opt/wildfly-00 for instance: wildfly-0] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Create deployment directories for instance: wildfly-0] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy custom configuration] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy configuration] **** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Include YAML configuration extension] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check YAML configuration is disabled] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set systemd envfile destination] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set systemd unit file destination] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy service instance configuration: /etc/wildfly-0.conf] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/wildfly-0.service] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Perform daemon-reload to ensure the changes are picked up] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Ensure service is started] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_systemd/tasks/service.yml for localhost TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set instance wildfly-0 state to started] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Validating arguments against arg spec 'main'] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check current EAP patch installed] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments for yaml configuration] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check if YAML configuration extension is supported in WildFly] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check if YAML configuration extension is supported in EAP] *** skipping: [localhost] TASK [Ensure required local user and group exists.] **************************** TASK [middleware_automation.wildfly.wildfly_install : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Set wildfly group] ******* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure group wildfly exists.] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure user wildfly exists.] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set destination directory for configuration] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set instance destination directory for configuration] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set base directory for instance] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] => { "changed": false, "msg": "All assertions passed" } TASK [middleware_automation.wildfly.wildfly_systemd : Set instance name] ******* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set instance name] ******* skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set bind address] ******** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Create basedir /opt/wildfly-11 for instance: wildfly-1] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Create deployment directories for instance: wildfly-1] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy custom configuration] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy configuration] **** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Include YAML configuration extension] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check YAML configuration is disabled] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set systemd envfile destination] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set systemd unit file destination] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy service instance configuration: /etc/wildfly-1.conf] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/wildfly-1.service] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Perform daemon-reload to ensure the changes are picked up] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Ensure service is started] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_systemd/tasks/service.yml for localhost TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set instance wildfly-1 state to started] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Validating arguments against arg spec 'main'] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check current EAP patch installed] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments for yaml configuration] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check if YAML configuration extension is supported in WildFly] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check if YAML configuration extension is supported in EAP] *** skipping: [localhost] TASK [Ensure required local user and group exists.] **************************** TASK [middleware_automation.wildfly.wildfly_install : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Set wildfly group] ******* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure group wildfly exists.] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_install : Ensure user wildfly exists.] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set destination directory for configuration] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set instance destination directory for configuration] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set base directory for instance] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] => { "changed": false, "msg": "All assertions passed" } TASK [middleware_automation.wildfly.wildfly_systemd : Set instance name] ******* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set instance name] ******* skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set bind address] ******** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Create basedir /opt/wildfly-22 for instance: wildfly-2] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Create deployment directories for instance: wildfly-2] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy custom configuration] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy configuration] **** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Include YAML configuration extension] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Check YAML configuration is disabled] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set systemd envfile destination] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set systemd unit file destination] *** skipping: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy service instance configuration: /etc/wildfly-2.conf] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/wildfly-2.service] *** changed: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Perform daemon-reload to ensure the changes are picked up] *** ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Ensure service is started] *** included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_systemd/tasks/service.yml for localhost TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] ********* ok: [localhost] TASK [middleware_automation.wildfly.wildfly_systemd : Set instance wildfly-2 state to started] *** changed: [localhost] TASK [Wait for each instance HTTP ports to become available.] ****************** ok: [localhost] => (item=8080) ok: [localhost] => (item=8180) ok: [localhost] => (item=8280) TASK [Checks that WildFly server is running and accessible.] ******************* changed: [localhost] => (item=8080) changed: [localhost] => (item=8180) changed: [localhost] => (item=8280) PLAY RECAP ********************************************************************* localhost : ok=105 changed=26 unreachable=0 failed=0 skipped=46 rescued=0 ignored=0 Note that the playbook is not that long, but it does a lot for us. It performs almost 100 different tasks! Starting by automatically installing the dependencies, including the JVM required by WildFly, along with downloading its binaries. And the wildfly_systemd role does even more, effortlessly setting up three distinct services, each with its own set of ports and directory layout to store instance-specific data. Even better, the WildFly installation is NOT duplicated. All of the binaries live under the /opt/wildfly-27.0.1 directory, but all the data files of each instance are stored in separate folders. This means that we just need to update the binaries, once, and then restart the instances, to deploy a patch or upgrade to a new version of WildFly. On top of everything, we configured the instances to use the standalone-ha.xml configuration as the baseline, so they are already set up for clustering. Check that everything worked as expected The easiest way to confirm that the playbook did indeed install WildFly and started three instances of the appserver is to use the systemctl command to check the associate services state: # systemctl status wildfly-0 ● wildfly-0.service - JBoss EAP (standalone mode) Loaded: loaded (/usr/lib/systemd/system/wildfly-0.service; enabled; vendor preset: disabled) Active: active (running) since Thu 2024-01-18 07:01:44 UTC; 5min ago Main PID: 884 (standalone.sh) Tasks: 89 (limit: 1638) Memory: 456.3M CGroup: /system.slice/wildfly-0.service ├─ 884 /bin/sh /opt/wildfly-30.0.1.Final/bin/standalone.sh -c wildfly-0.xml -b 0.0.0.0 -bmanagement 127.0.0.1 -Djboss.bind.address.private=127.0.0.1 -Djboss.default.multicast.address=230.0.0.4 -Djboss.server.config.dir=/opt/wildfly-30.0.1.Final/standalone/configuration/ -Djboss.server.base.dir=/opt/wildfly-00 -Djboss.tx.node.id=wildfly-0 -Djboss.socket.binding.port-offset=0 -Djboss.node.name=wildfly-0 -Dwildfly.statistics-enabled=false └─1044 /etc/alternatives/jre_11/bin/java -D[Standalone] -Djdk.serialFilter=maxbytes=10485760;maxdepth=128;maxarray=100000;maxrefs=300000 -Xmx1024M -Xms512M --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldaps=ALL-UNNAMED --add-exports=jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED --add-opens=java.base/com.sun.net.ssl.internal.ssl=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED -Dorg.jboss.boot.log.file=/opt/wildfly-00/log/server.log -Dlogging.configuration=file:/opt/wildfly-30.0.1.Final/standalone/configuration/logging.properties -jar /opt/wildfly-30.0.1.Final/jboss-modules.jar -mp /opt/wildfly-30.0.1.Final/modules org.jboss.as.standalone -Djboss.home.dir=/opt/wildfly-30.0.1.Final -Djboss.server.base.dir=/opt/wildfly-00 -c wildfly-0.xml -b 0.0.0.0 -bmanagement 127.0.0.1 -Djboss.bind.address.private=127.0.0.1 -Djboss.default.multicast.address=230.0.0.4 -Djboss.server.config.dir=/opt/wildfly-30.0.1.Final/standalone/configuration/ -Djboss.server.base.dir=/opt/wildfly-00 -Djboss.tx.node.id=wildfly-0 -Djboss.socket.binding.port-offset=0 -Djboss.node.name=wildfly-0 -Dwildfly.statistics-enabled=false Jan 18 07:01:47 7c4a5dd056d1 standalone.sh[1044]: 07:01:47,090 INFO [org.jboss.modcluster] (ServerService Thread Pool -- 84) MODCLUSTER000032: Listening to proxy advertisements on /224.0.1.105:23364 Jan 18 07:01:47 7c4a5dd056d1 standalone.sh[1044]: 07:01:47,148 INFO [org.wildfly.extension.undertow] (MSC service thread 1-4) WFLYUT0006: Undertow HTTPS listener https listening on [0:0:0:0:0:0:0:0]:8443 Jan 18 07:01:47 7c4a5dd056d1 standalone.sh[1044]: 07:01:47,149 INFO [org.jboss.as.ejb3] (MSC service thread 1-3) WFLYEJB0493: Jakarta Enterprise Beans subsystem suspension complete Jan 18 07:01:47 7c4a5dd056d1 standalone.sh[1044]: 07:01:47,183 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-2) WFLYJCA0001: Bound data source [java:jboss/datasources/ExampleDS] Jan 18 07:01:47 7c4a5dd056d1 standalone.sh[1044]: 07:01:47,246 INFO [org.jboss.as.server.deployment.scanner] (MSC service thread 1-2) WFLYDS0013: Started FileSystemDeploymentService for directory /opt/wildfly-00/deployments Jan 18 07:01:47 7c4a5dd056d1 standalone.sh[1044]: 07:01:47,285 INFO [org.jboss.ws.common.management] (MSC service thread 1-5) JBWS022052: Starting JBossWS 7.0.0.Final (Apache CXF 4.0.0) Jan 18 07:01:47 7c4a5dd056d1 standalone.sh[1044]: 07:01:47,383 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server Jan 18 07:01:47 7c4a5dd056d1 standalone.sh[1044]: 07:01:47,388 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management Jan 18 07:01:47 7c4a5dd056d1 standalone.sh[1044]: 07:01:47,388 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990 Jan 18 07:01:47 7c4a5dd056d1 standalone.sh[1044]: 07:01:47,390 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 30.0.1.Final (WildFly Core 22.0.2.Final) started in 2699ms - Started 311 of 708 services (497 services are lazy, passive or on-demand) - Server configuration file in use: wildfly-0.xml Deploy an application to the Wildlfy cluster Now, our three WildFly are running, but the cluster has yet to form. Indeed, with no apps there is no reason for the cluster to exist. Let’s modify our Ansible playbook to deploy a simple application to all instances; this will allow us to check that the cluster is working as expected. To achieve this, we’ll leverage another role provided by the WildFly collection: wildfly_utils. In our case, we will use the jboss_cli.yml task file, which encapsulates the running of JBoss command-line interface (CLI) queries: … post_tasks: - name: "Ensures webapp {{ app.name }} has been retrieved from {{ app.url }}." ansible.builtin.get_url: url: "{{ app.url }}" dest: "{{ wildfly_install_workdir }}/{{ app.name }}" - name: "Deploy webapp" ansible.builtin.include_role: name: wildfly_utils tasks_from: jboss_cli.yml vars: jboss_home: "{{ wildfly_home }}" query: "'deploy --force {{ wildfly_install_workdir }}/{{ app.name }}'" jboss_cli_controller_port: "{{ item }}" loop: - 9990 - 10090 - 10190 Now, we will once again execute our playbook so that the web application is deployed on all instances. Once the automation completes successfully, the deployment will trigger the formation of the cluster. Verify that the WildFly cluster is running and the app is deployed You can verify the cluster formation by looking at the log files of any of the three instances: … 2022-12-23 15:02:08,252 INFO [org.infinispan.CLUSTER] (thread-7,ejb,jboss-eap-0) ISPN000094: Received new cluster view for channel ejb: [jboss-eap-0] (3) [jboss-eap-0, jboss-eap-1, jboss-eap-2] … Using the Ansible collection as an installer for Wildfly Last remark: while the collection is designed to be used inside a playbook, you can also use the provided playbook to directly install Wildfly: $ ansible-playbook -i inventory middleware_automation.wildfly.playbook Conclusion Here you go, with a short and simple playbook, we have fully automated the deployment of a WildFly cluster! This playbook can now be used against one, two, three remote machine or even hundreds of them! I hope this will post will have been informative and that it’ll have convinced you to use Ansible to set up your own WildFly servers! ### [Configuring The WildFly To Use The JBeret JDBC Job Repository](/news/2024/01/15/Configuring-The-WildFly-To-Use-The-JBeret-JDBC-Job-Repository/) ### [Thanks for a great 2023!](/news/2023/12/22/Thanks-for-a-great-2023/) We are almost at the end of 2023 and we wanted to take this opportunity to thank all our community members for their help on WildFly this year. 2023 was a busy year for WildFly, with: 3 Major versions — 28, 29, 30. And 31 Beta just came out yesterday. New extensions for MicroProfile Telemetry and MicroProfile LRA. Implementations of most of MicroProfile 6.0, with updates to 6.1 coming in WildFly 31. Java 21 support. More than 2000 issues and enhancements resolved in our main code and this does not count all the work done in the components integrated in WildFly. A change of the WildFly code base to Apache License 2.0. A lot of work around on improving documentation and tooling related how to get start with and use WildFly. More on that when WildFly 31 comes out in January! We will start 2024 with the WildFly 31 release and with a great online mini-conference — a day dedicated to presentations and discussions about WildFly with our community. We will announce the conference date later, but it will likely be in February. Thanks all for of your for your work and help in making WildFly a successful Open Source project. We are looking forward to continuing working with you next year! Best wishes from the WildFly team and Happy New Year! Brian ### [Vlog: Securing WildFly Apps with Auth0 on OpenShift](/news/2023/12/20/Vlog-Securing-WildFly-Apps-with-Auth0-on-OpenShift/) ### [Securing WildFly Apps with Auth0 on OpenShift](/news/2023/12/12/Securing-WildFly-Apps-with-Auth0-on-OpenShift/) ### [Shaping the Future of WildFly Community Social Media!](/news/2023/12/07/Shaping-the-Future-of-WildFly-Community-Social-Media/) Greetings, WildFly Community Members! We trust this message finds you in the best of health and spirits as we embark on an exciting journey to enhance your experience within our vibrant WildFly community. Your engagement and feedback are invaluable to us, and to better understand your preferences, we’ve created a comprehensive poll covering both social media platforms and content types. Your choices will guide us in creating a more tailored and engaging experience for all members. Exploring New Horizons: Currently, we have established our presence on X, YouTube, and Mastodon, but we’re keen on expanding and refining our strategy. To better understand your preferences, we invite you to participate in a brief poll that aims to identify the social media platforms that resonate most with you. Your choices will guide our efforts to create a more tailored and engaging experience. Check this Link to fill out the survey. Understanding Your Preferences: In addition to selecting the social media platforms that resonate with you, we’re keen to learn about the types of content that capture your interest. The poll includes a variety of content categories, ranging from tutorials and updates to deep dives into WildFly technologies. Your choices will help us curate content that adds value to your experience within the WildFly Community. Why Now? The landscape of social media and online interactions is dynamic, with new platforms emerging and existing ones evolving. The WildFly Community has always thrived on staying ahead of the curve, and this poll comes at a pivotal moment in our growth. In the ever-evolving landscape of social media and content creation, your preferences are at the forefront of our considerations. Thank you for being a vital part of our Community. By taking a few minutes to share your insights in the poll, you’re playing a pivotal role in defining the WildFly Community’s presence. We look forward to creating an even more enriching experience for everyone. ### [WildFly 30.0.1 is released!](/news/2023/12/05/WildFly-30-0-1-is-released/) WildFly 30.0.1.Final is now available for download. It’s been about five weeks since the WildFly 30 release, so we’ve done a small bug fix update, WildFly 30.0.1. This includes an update to WildFly Preview. The following issues were resolved in 30.0.1: Bugs [WFLY-18295] - WildFly vs WildFly Preview document needs update [WFLY-18384] - [CLUSTERING] File containing session data is never shrunk or deleted [WFLY-18533] - Simplest JAXRS app is failing when deployed in server provisioned with jaxrs [WFLY-18702] - In WildFly Preview jaxrs-server layer does not provision MP Rest Client [WFLY-18727] - ATTRIBUTE granularity distributed sessions should always replicate on setAttribute(…​) [WFLY-18740] - On cache writes, Infinispan store=hotrod throws ISE: Only byte[] instances are supported currently Tasks [WFLY-18642] - Reevalute test exclusions in the integration/microprofile module Component Upgrades [WFLY-18630] - Upgrade Infinispan to 14.0.20.Final [WFLY-18679] - Upgrade jaxbintros from 2.0.0 to 2.0.1 [WFLY-18680] - [WildFly 30.x] Upgrade HAL to 3.6.16.Final [WFLY-18685] - Upgrade santuario to 3.0.3 (addresses CVE-2023-44483) [WFLY-18704] - Upgrade Artemis to 2.31.2 (resolves CVE-2023-46604) [WFLY-18713] - Upgrade RESTEasy to 6.2.6.Final [WFLY-18725] - Upgrade WildFly Http Client to 2.0.6.Final Issues resolved in the WildFly Core update included with WildFly 30.0.1 were: Component Upgrades [WFCORE-6578] - [CVE-2023-3171] WildFly heap exhaustion via deserialization [WFCORE-6592] - NPE in ThreadFactoryService Enjoy! ### [Introduction to the various Java based Kubernetes/OpenShift tools and their usages in WildFly related projects](/news/2023/11/30/Introduction-to-the-various-Java-based-Kubernetes-OpenShift-tools-and-their-usages-in-WildFly-related-projects/) There are various Java based Kubernetes/OpenShift related tools that have different functions, and some of their functions are overlapping. Here is the (partial) list of these tools: Dekorate eclipse/jkube: Build and Deploy java applications on Kubernetes fabric8io/kubernetes-client: Java client for Kubernetes & OpenShift fabric8io/docker-maven-plugin GoogleContainerTools/jib wildfly-maven-plugin: WildFly Application Server Maven Plugin All the above tools can be used as Maven plugin, and they can be used together if necessary(Which is determined by the requirements). In this article I’d like to give a brief introduction to these tools and see their usages in some WildFly related projects as examples. Firstly we can go through these projects. Dekorate From its website the project introduction is written as: Dekorate is a one-stop jar to Kubernetes manifest generation that works for all jvm languages regardless of your build tool. It makes generating Kubernetes manifests as easy as adding a dependency to the classpath. Stop wasting time editing xml, json and yml and customize the kubernetes manifests as you configure your java application. In general, the dekorate allows users to generate k8s manifest file according to the annotations it provided. For example, it provides the annotation @KubernetesApplication that can trigger the manifest file generation. In addition, it also provides annotation @DockerBuild that can trigger the docker build. Please note that Dekorate does not generate Dockerfile. It expects to find one in the root of the module, and it will call the docker command to build the image by using the installed local docker daemon. There is an article that introduces its usage[1]. Eclipse JKube The Eclipse JKube can generate Dockerfile and do the docker image build, and it can generate Kubernetes/OpenShift manifests, and do the k8s/openshift deployment. There is an article from developers.redhat.com [2] that describes the history of the project, and here is part of the text quoted from the article: This project was not built from scratch. It’s just a refactored and rebranded version of the Fabric8 Maven plugin, which was a Maven plugin used in the Fabric8 ecosystem. Although the Fabric8 project was liked and appreciated by many people in the open source community, due to unfortunate reasons it could not become successful, and the idea of Fabric8 as an integrated development platform on top of Kubernetes died. Although the main project is archived, there are still active repositories used by the community, such as the Fabric8 Docker Maven plugin, the Fabric8 Kubernetes client, and of course the Fabric8 Maven plugin. As maintainers of the Fabric8 Maven plugin, we started decoupling the Fabric8 ecosystem related pieces from the plugin to make a general-purpose Kubernetes/OpenShift plugin. We also felt there was a need for rebranding because most people were confused about whether this plugin had something to do with Fabric8. Hence, we decided to rebrand it, and fortunately, someone from the Eclipse foundation approached us to take in our project. Now, the project is being renamed to Eclipse JKube and can be found in the Eclipse Foundation repos on GitHub. And here is its design: Eclipse JKube can be seen as a reincarnation of the Fabric8 Maven plugin. It contains the good parts of this plugin and offers a clean and smooth workflow with the tooling it provides. We refactored this plugin into three components: The JKube Kit The Kubernetes Maven plugin The OpenShift Maven plugin Unlike the Dekorate project, which focus on k8s manifest file generation, and provide fine-grained annotations to control the generation process, JKube run as a maven plugin can help to generate a simple Dockerfile based on the project used frameworks[3]. In addition, the JKube can generate k8s manifest files and do the k8s/openshift deployments. I have written a blog post showing its usage[4]. Comparing with other tools, the JKube can do various tasks, which is very convenient. Nevertheless, other tools may focus on more specific task and provide some more fine grain controls to the task it takes. Fabric8 Docker Maven plugin As already introduced in above Eclipse JKube section, the Fabric8 Docker Maven plugin is part of the Fabric8 ecosystem. This project is focusing on the Docker image related tasks. It can define a docker image in its maven plugin configuration without having a Dockerfile, and it can do the container deployment/undeployment during the Maven integration test phase. We will see this plugin usage later. Fabric8 Kubernetes Client As the name suggests, this project provides Java based client to interact with the Kubernetes and OpenShift services. The functions of this Java based client is similar to the kubectl and oc commands. So this tool is convenient to use for writing k8s and OpenShift related tests. jib jib is a tool provided by Google, and it can be used to build images without Docker daemon installed, so it can produce a docker image standalone. After introducing the above tools, I’ll give an introduction to see their usages in some WildFly related projects as examples. wildfly-maven-plugin The wildfly-maven-plugin integrates the Galleon features which can build a provisioned WildFly server on-the-fly during the Maven package or testing phases, and it can control the start/stop of the provisioned server and the deployment of the host project. In addition, the plugin can be used to build a docker image that includes the provisioned WildFly server and the deployed project. To see more of the details on the usages of the plugin, you can check these related articles: WildFly Maven Plugin – Package your application WildFly Maven Plugin – Build and push your application in a container image Use the wildfly-maven-plugin to create a Docker image of your application Usage of the above tools in WildFly related projects Next we can see the wildfly-cloud-tests [5] project(Currently it has an Alpha release: wildfly-cloud-tests / 1.0.0.Alpha2). It is a good material to learn how to test WildFly under cloud based environment, and what tools it used. I have written a personal blog post[6] describing its usage. Firstly, this project uses the docker-maven-plugin to do the test images build[7]: <plugin> <groupId>io.fabric8</groupId> <artifactId>docker-maven-plugin</artifactId> <executions> <execution> <id>build-server</id> <phase>process-test-classes</phase> <goals> <goal>build</goal> </goals> <configuration> <skip>${wildfly.cloud.test.skip.image}</skip> <images> <image> <name>wildfly-cloud-test-image/${project.name}:latest</name> <alias>server</alias> <build> <from>${image.name.wildfly.runtime}</from> <assembly> <mode>dir</mode> <user>jboss:root</user> <targetDir>/opt/server</targetDir> <inline> <formats> <format>dir</format> </formats> <fileSets> <fileSet> <directory>target/server</directory> <outputDirectory>/</outputDirectory> <includes> <include>**</include> </includes> </fileSet> </fileSets> </inline> </assembly> </build> </image> </images> </configuration> </execution> </executions> </plugin> Secondly, this project uses Dekorate to generate the k8s manifest[8]: <dependency> <groupId>io.dekorate</groupId> <artifactId>dekorate-bom</artifactId> <version>${version.io.decorate.dekorate}</version> <type>pom</type> <scope>import</scope> </dependency> Thirdly, the project uses the io.fabric8:kubernetes-client to interact with k8s/OpenShift in its test cases[9]: <dependency> <groupId>io.fabric8</groupId> <artifactId>kubernetes-client</artifactId> <version>${version.io.fabric8.kubernetes-client}</version> </dependency> I won’t go into details of these component usages here, if you are interested how these components are used in the project, you can check the next section of this article. The last project to learn about is jbossws-cxf. Currently, the project is using docker-maven-plugin to generate the Docker image[10]: <plugin> <groupId>io.fabric8</groupId> <artifactId>docker-maven-plugin</artifactId> <executions> <execution> <id>build-wildfly-images</id> <phase>pre-integration-test</phase> <goals> <goal>build</goal> <goal>push</goal> </goals> <configuration> <images> <image> <name>localhost:5000/wildfly-webservice:latest</name> <build> <from>quay.io/wildfly/wildfly-runtime:latest</from> <assembly> <mode>dir</mode> <user>jboss:root</user> <targetDir>/opt/server</targetDir> <inline> <formats> <format>dir</format> </formats> <fileSets> <fileSet> <directory>target/server</directory> <outputDirectory>/</outputDirectory> <includes> <include>**</include> </includes> </fileSet> </fileSets> </inline> </assembly> </build> </image> </images> </configuration> </execution> </executions> </plugin> In addition, it uses the kubernetes-client to deploy the image to the k8s/openshift platform. In the project team blog there is an article describes its cloud based test[11]. In addition, you can check the project CI[12] to see how the cloud based tests are running in GitHub CI environment. At last the project also contains profile that is using the jib to build the docker image[13]: <profile> <id>jib</id> <activation> <property> <name>image.builder</name> <value>jib</value> </property> </activation> <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <configuration> <feature-packs> <feature-pack> <location>org.jboss.ws.cxf:jbossws-cxf-feature-pack:${project.version}</location> </feature-pack> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${jboss.version}</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>webservices</layer> </layers> <filename>${warName}.war</filename> </configuration> <executions> <execution> <phase>pre-integration-test</phase> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <configuration> <from> <image>quay.io/wildfly/wildfly-runtime:latest</image> </from> <to> <image>${imageName}:${imageTag}</image> </to> <extraDirectories> <paths> <path> <from>target/server</from> <into>/opt/server</into> </path> </paths> <permissions> <permission> <file>/opt/server/**/*</file> <mode>770</mode> </permission> </permissions> </extraDirectories> <container> <user>root</user> </container> </configuration> <executions> <execution> <phase>pre-integration-test</phase> <goals> <goal>dockerBuild</goal> </goals> </execution> </executions> </plugin> </plugins> Until now, we have checked the usages of these tools in several projects. Some notes on the implementation of the wildfly-cloud-tests project The wildfly-cloud-tests uses these tools to do complex WildFly based tests, so it’s a good material to learn about how to use these tools in depth. One internal class that may worth checking is the WildFlyCommonExtension [14]. Here is its class diagram: It works as a JUnit extension that take cares of the image deployment to k8s/openshift. For example, it provides methods to deploy/undeploy the k8s resources(please note these internal implementations may change in the future, and it’s shown here just for expressing the idea): private void startResourcesInList(ExtensionContext context, KubernetesResource kubernetesResource, KubernetesList resourceList) { KubernetesClient client = getKubernetesClient(context); resourceList.getItems().stream() .forEach(i -> { client.resourceList(i).createOrReplace(); System.out.println("Created: " + i.getKind() + " name:" + i.getMetadata().getName() + "."); }); List<HasMetadata> waitables = resourceList.getItems().stream().filter(i -> i instanceof Deployment || i instanceof Pod || i instanceof ReplicaSet || i instanceof ReplicationController).collect(Collectors.toList()); long started = System.currentTimeMillis(); System.out.println("Waiting until ready (" + kubernetesResource.readinessTimeout() + " ms)..."); try { waitUntilCondition(context, waitables, i -> Readiness.getInstance().isReady(i), kubernetesResource.readinessTimeout(), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { throw new IllegalStateException("Gave up waiting after " + kubernetesResource.readinessTimeout()); } long ended = System.currentTimeMillis(); System.out.println("Waited: " + (ended - started) + " ms."); //Display the item status waitables.stream().map(r -> client.resource(r).fromServer().get()) .forEach(i -> { if (!Readiness.getInstance().isReady(i)) { readinessFailed(context); System.out.println(i.getKind() + ":" + i.getMetadata().getName() + " not ready!"); } }); if (hasReadinessFailed(context)) { throw new IllegalStateException("Readiness Failed"); } else if (kubernetesResource.additionalResourcesCreated().length > 0) { long end = started + kubernetesResource.readinessTimeout(); Map<String, ResourceGetter> resourceGetters = new HashMap<>(); for (org.wildfly.test.cloud.common.Resource resource : kubernetesResource.additionalResourcesCreated()) { if (resourceGetters.put(resource.name(), ResourceGetter.create(client, resource)) != null) { throw new IllegalStateException(resource.name() + " appears more than once in additionalResourcesCreated()"); } } Map<String, HasMetadata> additionalWaitables = new HashMap<>(); while (System.currentTimeMillis() < end) { for (Map.Entry<String, ResourceGetter> entry : resourceGetters.entrySet()) { if (!additionalWaitables.containsKey(entry.getKey())) { ResourceGetter getter = entry.getValue(); HasMetadata hasMetadata = getter.getResource(); if (hasMetadata != null) { additionalWaitables.put(entry.getKey(), hasMetadata); } } } if (additionalWaitables.size() == resourceGetters.size()) { break; } try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.interrupted(); throw new IllegalStateException(e); } } if (additionalWaitables.size() != resourceGetters.size()) { throw new IllegalStateException("Could not start all items in " + kubernetesResource.readinessTimeout()); } try { waitUntilCondition(context, additionalWaitables.values(), i -> Readiness.getInstance().isReady(i), end - System.currentTimeMillis(), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { throw new IllegalStateException("Gave up waiting after " + (System.currentTimeMillis() - started)); } waitables.stream().map(r -> client.resource(r).fromServer().get()) .forEach(i -> { if (!Readiness.getInstance().isReady(i)) { readinessFailed(context); System.out.println(i.getKind() + ":" + i.getMetadata().getName() + " not ready!"); } }); if (hasReadinessFailed(context)) { throw new IllegalStateException("Readiness Failed"); } } } Here is the method that will be called after the test running: private void cleanupKubernetesResources(ExtensionContext context, WildFlyIntegrationTestConfig config, WildFlyTestContext testContext) { if (config.getKubernetesResources().isEmpty()) { return; } List<KubernetesResource> kubernetesResources = config.getKubernetesResources(); for (int i = kubernetesResources.size() - 1 ; i >= 0 ; i--) { KubernetesResource kubernetesResource = kubernetesResources.get(i); KubernetesList resourceList = null; try { try (InputStream in = getLocalOrRemoteKubernetesResourceInputStream(kubernetesResource.definitionLocation())) { resourceList = Serialization.unmarshalAsList(in); } } catch (Exception e) { throw toRuntimeException(e); } List<HasMetadata> list = resourceList.getItems(); Collections.reverse(list); list.stream().forEach(r -> { System.out.println("Deleting: " + r.getKind() + " name:" + r.getMetadata().getName() + ". Deleted:" + getKubernetesClient(context).resource(r).cascading(true).delete()); }); } } Though these are the internal implementations and the code may change in the future, it’s a good material to understand how these tools are worked together. References 1. Using Dekorate to generate Kubernetes manifests for Java applications / Red Hat Developer 2. Introduction to Eclipse JKube: Java tooling for Kubernetes and Red Hat OpenShift | Red Hat Developer 3. jkube/jkube-kit at master · eclipse/jkube 4. Using JKube To Do Kubernetes Deployment 5. WildFly Cloud Testsuite 6. Using the wildfly-cloud-tests project as an example to see how to deploy WildFly based project in cloud based environment 7. https://github.com/wildfly-extras/wildfly-cloud-tests/blob/main/images/pom.xml#L105 8. wildfly-cloud-tests/common/bom/pom.xml at main · wildfly-extras/wildfly-cloud-tests 9. https://github.com/wildfly-extras/wildfly-cloud-tests/blob/main/common/bom/pom.xml#L116 10. https://github.com/jbossws/jbossws-cxf/blob/main/modules/testsuite/cloud-tests/k8s/images/pom.xml#L78-L98 11. The New JBossWS Kubernetes/OpenShift Test Common Utilities 12. https://github.com/jbossws/jbossws-cxf/blob/main/.github/workflows/cloud-build.yml / Relative build process: JBWS-4383 Improve the common utility to check the WFLY readiness in… jbossws/jbossws-cxf@9334492 13. jbossws-cxf/modules/testsuite/cloud-tests/container/pom.xml at main · jbossws/jbossws-cxf 14. https://github.com/wildfly-extras/wildfly-cloud-tests/blob/main/common/junit-extension/src/main/java/org/wildfly/test/cloud/common/WildFlyCommonExtension.java ### [Using distributed realm ignore-unavailable-realms attribute in Elytron](/news/2023/11/29/Using-distributed-realm-ignore-unavailable-realms-attribute-in-Elytron/) ### [Installing additional feature-packs in WildFly](/news/2023/11/27/Installing-additional-feature-packs-in-WildFly/) Introduction In a previous article, you learnt how to install and use Prospero to provision a WildFly server. In this article, you will learn how to use Prospero to modify an existing server and extends its capabilities by adding a MariaDB datasource. For the purpose of this article, we assume the existing server has been installed from a downloaded WildFly zip archive. However the process works for servers installed using Prospero. In such case, simply skip the Registering WildFly server with Prospero section and start with Creating feature-pack channel section. Additional feature-packs for WildFly Galleon feature-packs provide a mechanism to extend WildFly server capabilities. An example of feature-packs contributed by the WildFly community are wildfly-datasources-galleon-pack, and wildfly-myfaces-galleon-pack. The first one can be used to add support for a database, while the latter can replace default JSF implementation with MyFaces. The additional feature-packs can be installed in existing servers either using Galleon or Prospero tools. Prerequisites Download WildFly 30.0.0.Final and unzip it in /tmp folder: cd /tmp wget https://github.com/wildfly/wildfly/releases/download/30.0.0.Final/wildfly-30.0.0.Final.zip unzip -q wildfly-30.0.0.Final.zip Download and unzip Prospero in /tmp folder cd /tmp wget https://github.com/wildfly-extras/prospero/releases/download/1.2.0.Final/prospero-1.2.0.Final.zip unzip -q prospero-1.2.0.Final.zip cd /tmp/prospero-1.2.0.Final Registering WildFly server with Prospero The first step to install additional feature-packs in an existing WildFly server, is to subscribe the server to WildFly channels. This allows Prospero to apply updates for WildFly and modify the installation. ./bin/prospero.sh update subscribe \ --dir /tmp/wildfly-30.0.0.Final \ --product wildfly \ --version 30.0.0.Final The update subscribe command generates a manifest based on selected version of WildFly server and registers the server to a channel using this manifest: ./bin/prospero.sh channel list --dir /tmp/wildfly-30.0.0.Final The command will output the channels that the server is subscribed to: Server /tmp/wildfly-30.0.0.Final is subscribed to following channels: ---- # wildfly manifest: file:/tmp/wildfly-30.0.0.Final/.installation/manifest-wildfly-30.0.0.Final.yaml repositories: id: central url: https://repo1.maven.org/maven2/ id: jboss-public url: https://repository.jboss.org/nexus/content/groups/public/ id: mrrc url: https://maven.repository.redhat.com/ga/ Creating feature-pack channel All additional feature-packs installed on top of WildFly have to be registered in a channel. We’re going to create a new manifest for this. echo "schemaVersion: 1.0.0 streams: - groupId: org.wildfly artifactId: wildfly-datasources-galleon-pack version: 6.0.0.Final " > /tmp/datasources-manifest.yaml Then we can register WildFly to receive updates from a new channel: ./bin/prospero.sh channel add \ --channel-name datasources \ --manifest /tmp/datasources-manifest.yaml \ --repositories central::https://repo1.maven.org/maven2 \ --dir /tmp/wildfly-30.0.0.Final Install wildfly-datasource-galleon-pack Finally to install the MariaDB database driver from wildfly-datasource-galleon-pack: ./bin/prospero.sh feature-pack add \ --fpl org.wildfly:wildfly-datasources-galleon-pack \ --layers mariadb-datasource \ --dir /tmp/wildfly-30.0.0.Final After running the command, you will be asked to confirm the changes, and the feature-pack will be downloaded and installed. Installing feature-pack `org.wildfly:wildfly-datasources-galleon-pack` in server `/tmp/wildfly-30.0.0.Final` Continue adding the feature-pack? [y/N]:y Applying changes Feature-packs resolved. Packages installed. Downloaded artifacts. JBoss modules installed. Configurations generated. JBoss examples installed. Operation completed in 19.62 seconds. After running this command, a new module org.mariadb.jdbc:main will be created in the server modules directory and the standalone/configuration/standalone.xml will be updated with a new driver and datasource configuration. Updating mariadb driver version Steps above installed a default version of MariaDB driver, but using prospero and WildFly channels we are able to update that. First, let’s add the desired version of the driver to the datasources manifest: echo " - groupId: org.mariadb.jdbc artifactId: mariadb-java-client version: 3.3.0 " >> /tmp/datasources-manifest.yaml Next, we just need to let prospero perform an update: ./bin/prospero.sh update perform --dir /tmp/wildfly-30.0.0.Final The command will report available updates - in this case showing the changed mariadb driver - and ask you to confirm the changes. Updates found: org.mariadb.jdbc:mariadb-java-client 3.2.0 ==> 3.3.0 Continue with update [y/N]: y Building updates Feature-packs resolved. Packages installed. Downloaded artifacts. JBoss modules installed. Configurations generated. JBoss examples installed. Build update complete! Applying updates Update complete! Operation completed in 25.48 seconds. Now we can check that the org.mariadb.jdbc:main module: ls /tmp/wildfly-30.0.0.Final/modules/org/mariadb/jdbc/main and see the updated driver: mariadb-java-client-3.3.0.jar module.xml Starting the server Before starting the server with the new datasource, we need to provide the MariaDB connection information. Those can either be added to the server configuration as WildFly system properties, or as OS environment variables. For the purpose of this article, we will assume that the MariaDB database called testdb is available on localhost:3306 and is secured using test/password credentials. The detailed description of available configuration options can be found in the datasource feature-pack documentation, eg. MariaDB configuration. Managing WildFly system properties is described in the WildFly Admin Guide Let’s try to set the required configuration using environment variables and start the server: export MARIADB_USER=test export MARIADB_PASSWORD=password export MARIADB_DATABASE=testdb /tmp/wildfly-30.0.0.Final/bin/standalone.sh Note that for this example, we are using a MariaDB database available at the default address localhost:3306. If your environment is different, you can change those values using MARIADB_HOST and MARIADB_PORT environment variables. Looking at the startup logs, we can see that mariadb driver and a new data source java:jboss/datasources/MariaDBDS are made available. ========================================================================= JBoss Bootstrap Environment JBOSS_HOME: /tmp/wildfly-30.0.0.Final JAVA: /opt/java/jdk-11.0.20.jdk/Contents/Home/bin/java JAVA_OPTS: -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldaps=ALL-UNNAMED --add-exports=jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED ========================================================================= 12:24:22,095 INFO [org.jboss.modules] (main) JBoss Modules version 2.1.2.Final 12:24:22,300 INFO [org.jboss.msc] (main) JBoss MSC version 1.5.2.Final 12:24:22,303 INFO [org.jboss.threads] (main) JBoss Threads version 2.4.0.Final 12:24:22,348 INFO [org.jboss.as] (MSC service thread 1-1) WFLYSRV0049: WildFly Full 30.0.0.Final (WildFly Core 22.0.1.Final) starting [...] 12:24:22,909 INFO [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 44) WFLYJCA0004: Deploying JDBC-compliant driver class org.mariadb.jdbc.Driver (version 3.3) 12:24:22,915 INFO [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-6) WFLYJCA0018: Started Driver service with driver-name = mariadb [...] 12:24:23,067 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-7) WFLYJCA0001: Bound data source [java:jboss/datasources/MariaDBDS] [...] 12:24:23,161 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 30.0.0.Final (WildFly Core 22.0.1.Final) started in 1201ms - Started 288 of 530 services (318 services are lazy, passive or on-demand) - Server configuration file in use: standalone.xml Conclusion In this article, we learned how to use Prospero to extend WildFly server with additional capabilities using feature-packs. In particular we used wildfly-datasources-galleon-pack to install and update a MariaDB datasource, but the same technique can be used to install other feature-packs contributed by the community. If you want to learn more about Prospero or available feature-packs, please take a look at the GitHub projects below: https://github.com/wildfly-extras/prospero https://github.com/wildfly-extras/wildfly-datasources-galleon-pack https://github.com/wildfly-extras/wildfly-myfaces-feature-pack If you would like to learn more about extending WildFly using feature-packs, please take a looke at: https://docs.wildfly.org/galleon-plugins/#_building_a_custom_feature_pack_example https://docs.wildfly.org/galleon/ ### [WildFly Feature Development Process](/news/2023/11/22/WildFly-Feature-Development-Process/) Some of the developers of WildFly have been thinking about how to clarify and formalize some of the processes we use when developing WildFly, and I want to make the broader WildFly community aware of the discussion. This post basically duplicates one I recently made on the wildfly-dev mail list. I’d love to hear your thoughts about this on that mail thread or in Zulip Overview The WildFly project has some pretty high standards around quality, stability and backwards compatibility, and those heavily influence how we go about bringing new features into WildFly. WildFly developers like me who also work on Red Hat JBoss EAP are aware of EAP’s policies and processes for doing new feature development, and we bring those to how we do our work on WildFly, but WildFly has its own needs and would benefit from more formalized processes of its own. This thread and other related discussions are intended to drive creation of these kinds of policies, and to work through technical issues that stand in the way. I’m hoping we can make good progress on this this month, and get something finalized by the end of Q1 next year. Goals of this effort include: Making it clear to the WildFly developer community how to go about getting new features into WildFly. Providing a path for getting 'bake' for new features by making them available to those interested in newer, less stable things, while not exposing them to other users who only want more stable features. Encouraging new or less frequent contributors to consider proposing new features by making it possible to choose an acceptable tradeoff between how broadly their feature will be visible versue the level of effort that fits what they can offer. Skip ahead to the Developing the Process section if you’re not interested in background / context discussion. Background WildFly is the upstream project from which Red Hat’s JBoss EAP product is derived. Like most software products, EAP has processes that are meant to govern how new functionality gets introduced into the product, in order to ensure the high quality and long-term supportability of the product. EAP is derived from WildFly, and a high percentage of the development work on WildFly is performed by Red Hat engineers who also work on EAP, so it’s natural that the EAP processes have affected how those engineers do their work on WildFly. This has brought a ton of benefit to WildFly, primarily because the EAP requirements help ensure that people other than the developer coding up a feature are involved in the identification of the use cases for and requirements of the feature, and also help ensure the feature is properly documented and tested. People with quality engineering and documentation expertise are involved in the development of the feature, which is very much a good thing. However, there are downsides to using EAP processes to guide a lot of WildFly development: The EAP processes are meant for EAP and are not visible to the WildFly community. An open source software community should be able to see and understand how development work is done. A project with the scope and complexity of WildFly needs processes to ensure quality, but those processes should be WildFly’s own and should be publicly visible. Quasi-borrowing EAP processes doesn’t meet this goal. The EAP processes can lead to an “all or nothing” effect. They require the involvement of people from different groups within Red Hat before a feature is merged. This is great in general but it can lead to situations where people not being able to prioritize a particular feature blocks it, even though the development of the feature has reached a point where it can offer real value to some WildFly users. If the feature is blocked, those users don’t benefit, and the WildFly developers don’t get the benefit of feedback on the feature from those users or other WildFly developers who would only encounter it once it’s merged. Developing the Process So, what are we doing about this? The goal is to define the various requirements for what constitutes a high quality feature, and to define a path people working on that feature can follow. The path should include a way for the feature to be made available to some users before it reaches its final form, without exposing it to users who only want finalized features. Note that the main focus of this post is on coming up with a suitable process, but there are technical tasks that need to be done to make it practical to expose features to some but not all users and to allow them to best control what they can use in their WildFly installation. A great example of that kind of thing Paul Ferraro’s work on the management API. For the process itself, back in September I created a working document to try and capture some of the elements that would go into a possible process: WildFly Feature Development Process working document The gist of that document is the notion from Paul Ferraro’s work that features can be merged with different initial quality/stability/maturity levels (we plan to use 'stablity' as the formal term), as represented by columns in the table, with a given feature expected to be ‘promoted’ over time from columns to the left toward columns to the right. The rows in the table represent different aspects of ensuring a feature is at a particular stability level. The cells in the table then are quick notes on what requirements would have to be met for a given aspect in order for the feature to be merged at a given stability level. What I’m hoping is discussion the wildfly-dev mail list and on Zulip about all this can help flesh out what’s in that document, rework it as necessary, and eventually lead to a more formal process document. Some details on the stability levels: Experimental — This level would be for real bleeding edge stuff. No WildFly distribution zip/tar would enable this level by default. Preview — This would be the level for features at a sufficient level to be available by default[1] in WildFly Preview, but not in standard WildFly. Community-- This would be the level for features at a sufficient level to be available by default in standard WildFly. Default — Features at this level have gone through additional vetting to ensure they are suitable for the long-term compatibility expectations of the feature-pack that provides them. (See Relationship to Feature-Packs for more on this.) [1] Note that ‘available by default’ could but often wouldn’t mean ‘enabled by default’, i.e. turned on in a standard OOTB configuration. It just means a user could turn it on if they so choose using the current configuration mechanisms. Some details on the feature aspects: Feature Team — This aspect relates to what people need to be involved with the feature. Requirements Analysis — This relates to ensuring the user stories and technical requirements for the feature are thought through and written down. We’ve been doing these for a long time now via the documents in the wildfly-proposals repo. Implementation — The production code aspect of the feature. Domain transformation — A specialized production code aspect, related to allowing a current version Domain Controller to manage Host Controllers and servers running an earlier version. Test plan — Thinking about and writing down what needs to be tested and how. Test development — Writing the tests. Test verification — Test review, and verification that the test plan was implemented and that the tests pass. Documentation — Proper documentation of the feature. Note that it is likely that the set of rows in the table will need expansion, e.g. to capture requirements for things like the HAL web console, cloud images, tooling like WildFly Glow etc. Relationship to Feature-Packs The main WildFly code base produces three different feature-packs, and the main reason there are three and not just one relates to some of the same stability/long-term compatibility concepts that are a key part of the feature development process I’m hoping we create. It’s important that we think carefully about how the feature development process relates to the feature-packs, so to help with that I want to talk a bit about how feature-packs are meant to work. Ideally for any feature-pack, the documentation of that feature-pack would include somewhere ‘lifecycle’ information that can help users decide if the feature-pack is suitable for their needs. This would cover key elements like: The basic scope of the feature-pack. A likely release cadence for the feature-pack. The expected long-term maintainability and compatibility for the feature-pack. Different expectations for those key elements are prime reasons for creating a new feature-pack versus adding functionality to an existing one, or for choosing one feature-pack over another for a feature. Honestly, the WildFly project does a poor job of documenting these things for its feature-packs, which is my fault, and is why I need to write some of this in this already looooong post! Anyway… WildFly produces three feature-packs from its main repository. All share the same expected release cadence (currently a new feature release roughly quarterly and one bug fix release about a month after a feature release.) The scope of all three is similar and broad — they provide functionality to run in, manage or act as a client to an application server process. Their primary differences relate to long-term maintainability and compatibility: wildfly-ee — We don’t talk about this feature-pack a lot, often treating it as an internal detail and not producing any downloadable zip/tar built solely using it, but it’s an important piece of our ecosystem. The defining characteristic of this feature-pack is that it integrates technologies where we have the highest confidence in our ability to provide them in a largely compatible way for many years. We’re not perfect about this, we made some mistakes in the early iterations of this feature-pack, and we can and will break compatibility if necessary. But we try not to and try to give advance warning if we will. For example, this feature-pack provides the Elytron security layer, which was introduced as a replacement for the Picketbox security layer many years before we removed support for the Picketbox layer. wildfly — This feature-pack depends upon wildfly-ee and adds functionality in addition to what’s in wildfly-ee. The traditional standard WildFly server zip is built using this feature-pack. The primary reason we put things in this feature-pack instead of wildfly-ee is because what we’re integrating is more likely to change in incompatible ways over a relatively short time period. For example, MicroProfile specifications are comfortable introducing breaking changes on an annual basis, making them not a great fit for wildfly-ee. The observability space, particularly metrics and tracing, is evolving rapidly, so our Micrometer and OpenTelemetry extensions are not in wildfly-ee. wildfly-preview — This feature-pack is all about the fact that it provides no long term guarantees and can change significantly from release. We need to think more about how feature stability levels relate to this, but here are a few thoughts: Just because a user wants to use a particular preview or experimental level feature doesn’t mean they want to use an entire preview level feature-pack like wildfly-preview. In other words, there is a use case for preview or experimental features in standard WildFly. On the other hand, we can use WildFly Preview to showcase functionality whose scope is not tied to a particular reasonably scoped ‘feature’. Using it for EE 9 is an obvious example. Not having an embedded messaging broker in the OOTB configs is not a ‘feature’. IOW there is a use case for WildFly Preview even if standard WildFly has preview features. What we mean by the ‘Community’ and ‘Default’ levels is “relative to” the generally expected long-term maintainability and compatibility level of the feature-pack that provides it. In other words, just because a feature provided by the wildfly feature-pack has been vetted as suitable for the ‘Default’ level doesn’t mean it comes with higher expectations than the feature-pack as a whole. If we provide a specification, and we integrate it in a way that is highly stable and very well tested, but then the spec changes in a year in a significantly incompatible way, then we may have to as well. Next Steps I’d love to hear your thoughts and questions, either on the wildfly-dev mail list thread, in Zulip or in comments on the WildFly Feature Development Process working document I discussed above. I also encourage you to have a look into Paul Ferraro’s work I mentioned above, as well as other technical work that will likely be happening over the next six months. As I noted at the start, I’m hoping we can have a solid process written and published by the end of Q1 next year, and that we can nail down some of the key concepts over the next few weeks well enough that we can integrate Paul’s work. Best regards, Brian ### [Change the default encoding of the audit log file in WildFly](/news/2023/11/16/Change-the-default-encoding-of-the-audit-log-file-in-WildFly/) ### [Identity Propagation with OpenID Connect](/news/2023/11/15/Identity-Propagation-with-OpenID-Connect/) ### [Manual GitHub Actions Workflow in WildFly](/news/2023/11/13/Manual-GitHub-Actions-Workflow-in-WildFly/) GitHub actions workflow is a valuable tool that automates development process and continuous integration. While it’s great to see every pull request can be verified automatically upon submission, sometimes we also like the flexibility to tweak which OS, JDK distribution and version to use, which tests to run, which maven options to specify, or which system properties to apply. Basically, a more customizable build environment and testing plan targeted for a particular issue at hand. This is what a manual workflow is for. This post will walk you through how to do this in WildFly. Use cases for manual workflow A pull request in WildFly usually triggers more than 10 CI jobs, and some of them take hours to complete. The Manual workflow in WildFly can greatly reduce the duration and resource consumption via parameterization, and perform the desired verification without the overhead of a full-blown CI cycle. And below are some more occasions where manual workflow is a good fit: The build takes too long on your local machine. You want to reproduce certain failures that only occur in GitHub CI settings, but not on your local machine. You want to build and test WildFly on certain combination of OS and JDK versions not readily available locally. You want to test your WildFly code changes in a clean environment, without the interference fom other projects. How to start manual workflow First thing to consider is where to run the manual workflow. It depends on your role and permission within WildFly project. If you are in maintainer role, you can run it in upstream WildFly repository, or your fork of it. Other WildFly contributors and watchers are free to run it in their own fork. In either case, navigate to the Actions tab of WildFly repository, choose Manual Build and Test from the list of workflows on the left panel, and then click Run workflow dropdown on the right-side panel. The following is a sample screenshot of various configurations available in the dropdown menu: Manual workflow parameters Branch: Choose the branch your wish to run against, typically a topic branch containing some new code you want to verify. It defaults to main branch. This is the standard GitHub branch selector with quick filtering. OS: Choose the runner operating system, either ubuntu-latest or windows-latest. It defaults to ubuntu-latest. JDK Distribution: Choose the JDK distribution to build and test WildFly. It defaults to temurin and supports the following distributions. For more information, see setup-java action docs. temurin: Eclipse Temurin semeru: IBM Semeru Runtime Open Edition microsoft: Microsoft Build of OpenJDK oracle: Oracle JDK zulu: Azul Zulu OpenJDK corretto: Amazon Corretto Build of OpenJDK liberica: Liberica JDK jdk-version: Enter JDK version, a string value that is an exact version or a version range using SemVer notation. It’s a required parameter with no default. For more information, see setup-java action docs args: Enter optional, additional maven command options. It defaults to -Dquickly. Some common args are: -Dquickly: activates the quick-build maven profile, which skips steps like testing, javadoc generation and checkstyle, For more information, see its definition in pom.xml -DskipTests: a maven option to skip running tests -DallTests: activates the maven profile that runs all suitable tests other system properties or maven options timeout: Enter number of minutes beyond which the workflow job will time out. It’s an optional parameter and defaults to 120 minutes. How to choose a good timeout value depends largely on the previous parameter, args, which determines which maven profile to activate, which tests to run, or which build steps to execute. ### [Securing WildFly Apps with OIDC on OpenShift](/news/2023/11/10/Securing-WildFly-Apps-with-OIDC-on-OpenShift/) ### [Adding Support for Integrity Checking to an Existing Filesystem Realm](/news/2023/11/09/Adding-Support-for-Integrity-Checking-to-an-Existing-Filesystem-Realm/) ### [Developing in the cloud with Eclipse Che](/news/2023/11/07/Developing-in-the-cloud-with-Eclipse-Che/) Eclipse Che is a cloud IDE that promises to get rid of the cumbersome setup of your local environment by providing automated setup in the cloud. It can be run easily on Kubernetes or its derivative like OpenShift. The purpose of this blog entry is not to setup Eclipse Che. In this blog entry we will show you in a first step how you can use Eclipse Che for regular development. On a second step we will resuse the same application and deploy it on Kubernetes. For the video and demo purpose we used Eclipse Che installation on Minikube following the instructions with the chectl management tool. In order to setup our project environment we will use a simple getting-started project which contains only a single REST endpoint and an integration test. In this project we provide also: a devfile.yaml to setup and configure the Che workspace. You may learn more about it on https://devfile.io . a ContainerFile to describe how to build our runtime image to be deployed on Kubernetes. a ingress.yaml file that can server as an example to expose our running service. Regular development on the cloud Creating our workspace The first step is of course to create our workspace, for this you have to paste the following URL https://github.com/wildfly-extras/wildfly-devfile-examples/tree/simple-cloud . As you can see this repository is quite simple and provides at its root the devfile.yaml that will configure our workspace. Let’s do a quick analysis of this file content: it has a single component using a Universal Developer Image to bring in all the tools that a cloud developer might need. it defines the debug port and the ports that can be exposed there is also a volume where the downloaded maven artefacts will be stored to keep them between restarts The we have several commands to provide shortcuts to commands a developer might need. They are quite standard and make development life easier but of course you can type them in a terminal if you’s rather do it that way. Taking a look at the code The code consists of a very basic REST endpont with an index.html page to call it and display the result. There is also an integration test that will call that endpoint and checks that it returns properly. If you take a look at the Apache Maven pom.xml you can see that it uses the WildFly Maven Plugin. <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.jboss.bom}</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:${version.cloud.fp}</location> </feature-pack> </feature-packs> <layers> <!-- layers may be used to customize the server to provision--> <layer>cloud-server</layer> </layers> <javaOpts></javaOpts> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> We use this plugin to provision a server and deploy our application to it. As you can see, we are installing the cloud-server layer from the wildfly-cloud-galleon-pack as it makes WildFly behave better in the cloud. Building and debugging As you can see on the demo, we provide three commands for reglar development ('InnerLoop') : the first one builds the application, provisions the server and executes the integration test the second one provisions and starts the server with the application in dev mode: this means that whenever the code changes the server is automatically updated. It is covered in more details here. the third one provisions and starts the server with the application in dev mode with debug enabled so you can debug the application and also take advantage of the dev mode. Note Note you can use a terminal to execute those commands or your own. For example you can start the provisionned server with the regular standalone.sh in target/server/bin. YouTube video player Deploying to the cloud Creating the secret Because we need to make our image available to be deployed on Kubernetes we have to provide the credentials and details on where to push it. In order to do that we need to create a secret in the namespace you are running your workspace on (in my case it is admin-che). On the devfile the target registry is quay.io, you may change that if you want to use your own image registry. kubectl delete secret quay-secret --namespace admin-che kubectl create secret generic quay-secret \ --namespace admin-che \ --from-literal=IMAGE_REGISTRY_PASSWORD=**** \ --from-literal=IMAGE_REGISTRY_LOGIN=mylogin@quay.io \ --from-literal=IMAGE_REGISTRY_NAMESPACE=mylogin kubectl label secret quay-secret \ --namespace admin-che \ controller.devfile.io/mount-to-devworkspace=true \ controller.devfile.io/watch-secret=true kubectl annotate secret quay-secret --namespace admin-che controller.devfile.io/mount-as='env' The label and the annotation are here so that the secret will be automounted by the Che workspace on start. So you will need to restart the workspace if you created it as in the first part of this article. Building the image For this task we are going to use Podman and a very simple ContainerFile that will take the output of the provisionning task a copy it to a wildfly-runtime image: FROM quay.io/wildfly/wildfly-runtime:latest COPY --chown=jboss:root target/server $JBOSS_HOME RUN chmod -R ug+rwX $JBOSS_HOME Once that image is built we need to push it. Tagging and pushing the image Here again we are going to use Podman to tag the image we just built and push it to our image registry. This task is the the that uses the content of the secret we created. Otherwise it is just regular Podman commands. Deploying the image on Kubernetes Now we are going to deploy the image we have built and pushed on Kubernetes. In order to do this we are going to use WildFly Helm Charts. The first step is to register the WildFly helm charts then execute helm install with a few values to customize our deployment: --set build.enabled=false : this indicates that we are using an image that has already been built (in Openshift you can use s2i to automate what we just did before). in the .charts/helm.yaml file you will notice that there is a deploy.route.enabled set to false this is again to override an Openshift feature where the route to the service is automatically added. In Kubernetes you will have to create the Ingress resource manually (until now at least). Now that the image has been deployed and the service created, you need to expose it by creating the ingress resource. kind: Ingress apiVersion: networking.k8s.io/v1 metadata: name: getting-started-ingress namespace: admin-che spec: ingressClassName: nginx rules: - host: hello-world.info http: paths: - path: / pathType: ImplementationSpecific backend: service: name: getting-started port: number: 8080 You may want to change the target host name. In my example I added an entry in my hosts configuration file mapping hello-world.info to the minikube IP address. Now you can access the service on http://hello-world.info Undeploying the image We provide again a simple command that does a helm uninstall thus removing the deployment. YouTube video player ### [Open Source Day 2023 Recap](/news/2023/10/23/Open-Source-Day-2023-Recap/) ### [WildFly 30 is released!](/news/2023/10/18/WildFly-30-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 30.0.0.Final releases are available for download at https://wildfly.org/downloads. New and Notable An important focus of our work for this release was preparing for the arrival of Java SE 21, the latest LTS JDK release. While we still recommend that you run WildFly on SE 17 or 11 (see Java SE Support below for more on why), we do believe WildFly 30 is a great choice for evaluating how your applications run on SE 21. In particular, I’m pleased that WildFly 30 is able to certify as a compatible Jakarta EE 10 Core Profile implementation when running on SE 21! We’re also able to pass the TCKs for the MicroProfile specifications we support when running on SE 21. Special thanks to Richard Opalka, James Perkins and Scott Marlow for all the hard work they put into this. Supported Specifications Jakarta EE WildFly 30 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly is EE 10 compatible when running on both Java SE 11 and Java SE 17. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence Jakarta EE 10 Full Platform SE 11 SE 17 Jakarta EE 10 Web Profile SE 11 SE 17 Jakarta EE 10 Core Profile SE 11 SE 17 SE 21 MicroProfile WildFly supports numerous MicroProfile specifications. Because we no longer support MicroProfile Metrics, WildFly 30 cannot claim to be a compatible implementation of the MicroProfile 6.0 specification. However, WildFly’s MicroProfile support includes implementations of the following specifications in our "full" (e.g. standalone-full.xml) and "default" (e.g standalone.xml) configurations as well as our "microprofile" configurations (e.g. standalone-microprofile.xml): MicroProfile Technology WildFly Full/Default Configurations WildFly MicroProfile Configuration MicroProfile Config 3.0 X X MicroProfile Fault Tolerance 4.0  —  X MicroProfile Health 4.0  —  X MicroProfile JWT Authentication 2.1 X X MicroProfile LRA 2.0  —  X MicroProfile OpenAPI 3.1  —  X MicroProfile Open Telemetry 1.0  —  X MicroProfile Reactive Messaging 3.0  —   —  MicroProfile Reactive Streams Operators 3.0  —   —  MicroProfile Rest Client 3.0 X X Compatibility evidence for the above specifications that are part of MicroProfile 6.0 can be found in the WildFly Certifications repository on GitHub. Java SE Support Recommended SE Versions Our recommendation is that you run WildFly 30 on Java SE 17, as that is the latest LTS JDK release where we have completed the full set of testing we like to do before recommending a particular SE version. WildFly 30 also is heavily tested and runs well on Java 11. Our recommendation of SE 17 over 11 is solely because we recommend as a general principle being on later LTS releases, not because of any problems with WildFly on SE 11. One reason to use later SE versions is because it gets you ahead of the curve as WildFly and other projects begin to move on from supporting older SE releases. At this point it is likely that WildFly 30 will be the last release where support SE 11. There is some possibility we will continue to support SE 11 in WildFly 31, but we have no plans to support it beyond then. As our focus and the focus of the broader Java ecosystem moves toward SE 21 and later, we need to shift focus away from SE 11. Please note that WildFly runs in classpath mode. Java SE 21 I am very pleased to be able to say that WildFly 30 runs well on SE 21, the latest LTS release. By "runs well" I mean that we get the same results on SE 21 when running WildFly’s and WildFly Core’s own extensive test suites as we do when running SE 17 or SE 11. As noted above, we also pass the Jakarta EE 10 Core Profile TCK when running on SE 21, as well as the MicroProfile TCKs for the various specifications we support. We do not yet include SE 21 in the preceding "Recommended SE Versions" section because: We have not completed our program of seeing how WildFly on SE 21 does on the Jakarta EE Full Platform and Web Profile TCKs. We need to do further investigation into how the projects producing the various libraries we integrate are testing on SE 21. If you are trying to evaluate what SE 21 means for your applications, I encourage you to look to WildFly 30 as your evaluation platform. Move to ASL 2.0 During the WildFly 30 development cycle we moved the main WildFly source code and the WildFly Core source code from the Lesser General Public License 2.1 to the Apache Software License 2.0. This is something we’ve long wanted to do, and started doing in WildFly Core many years ago. So I’m very pleased that we’ve been able to take this step. Please note that when you run WildFly you are running software provided by a large number of component libraries that WildFly integrates, with those components licensed under a variety of open source licenses. The components provided by the WildFly and WildFly Core projects that we’ve shifted to ASL 2.0 are just a subset of what we integrate. The complete set of licensing information about the libraries found in a WildFly installation can be found in the docs/licenses/licenses.html folder in the WildFly installation, along with the same information in XML format and a copy of all of the relevant licenses. Release Notes The full release notes for the release are in the WildFly JIRA. Issues fixed in the underlying WildFly Core 22 releases are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. Meanwhile, we’re busy at work on WildFly 31! Best regards, Brian ### [Hacktoberfest 2023](/news/2023/09/27/Hacktoberfest-2023/) Hacktoberfest is back, and it’s time to channel your inner Open Source superhero! This annual event unites developers of all levels, from seasoned pros to enthusiastic beginners, in a shared mission to contribute to Open Source projects and celebrate the spirit of collaboration in software development. Join us for this month-long celebration of contributions as we work together, one pull request at a time. What is Hacktoberfest? Hacktoberfest is a month-long event in October that encourages Open Source contributors and developers worldwide to give back to the global tech community. It’s a fantastic opportunity for the contributors to showcase their skills and get to know about other Open Source communities. To participate you simply need to: Register: Sign up on the official Hacktoberfest website to get started. Discover Projects: Explore the Hacktoberfest website to find a project that sparks your interest. You can also check out the curated list of projects we’ve prepared for you. Follow the Project guidelines: Read the respective Contributing Guide, Code of Conduct, and follow best practices like forking the repository, creating a new branch, and making a meaningful contribution. Contribute: Select an issue that matches your interest and start working on it. You’ll have the option to have a tree planted in your name and a unique digital reward as a token of appreciation. Get started with our projects This list contains some really interesting projects that are under the WildFly umbrella, waiting for your magic touch. There’s something for everyone from Java to Ansible. WildFly: WildFly is a powerful, modular, and lightweight application server that empowers you to build amazing applications. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. WildFly Elytron: WildFly Elytron is a set of APIs and SPIs for application server security and client side security. Within the WildFly server, WildFly Elytron is used to secure applications deployed to the server as well as management access to the server. It is a standalone library that can also be used in other Java server environments. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. For more details, check out WildFly Elytron’s Hacktoberfest page. Ansible Middleware: Ansible Middleware is a suite of supported content that combines the power of Ansible automation with Red Hat’s Middleware portfolio. It allows organizations to meet their business demands and automate the installation, configuration, and management of Enterprise Middleware. Here are the GitHub repositories, Contributing Guide, and Hacktoberfest Issues link. Undertow: Undertow is a versatile and high-performance web server that provides both blocking and non-blocking APIs based on NIO. Its modular architecture allows you to build a web server tailored to your needs, from a full Java EE servlet container to a low-level non-blocking handler. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. WildFly Core: WildFly Core provides the core runtime that is used by the Wildfly application server. This includes Modular class loading, Unified management including domain mode, Basic deployment architecture, and CLI for management. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. Narayana: Narayana is a transactions toolkit that provides support for applications using various standards-based transaction protocols. It’s an essential component of the WildFly application server and continues to be developed as a standalone transaction manager. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. WildFly GitHub Bot: WildFly GitHub Bot is a small easy-to-start application that we utilize to manage the workflow of WildFly’s Pull Requests. It, for instance, requires reviews from relevant reviewers or sets labels based on the PR’s state. We have a lot of ideas that you can start implementing. Here are the GitHub repository, Contributing Guide, and Hacktoberfest Issues link. How to reach out to us for Hacktoberfest related queries? Please join our Hacktoberfest Zulip chatroom and reach out to us if you have any queries or need assistance. We’re here to ensure a smooth journey for you. Let’s make Hacktoberfest 2023 the most exciting and impactful one yet! Your contributions matter, and together, we can make a difference. ### [Using the resteasy-grpc feature together with the WildFly gRPC subsystem](/news/2023/09/13/Using-the-resteasy-grpc-feature-together-with-the-WildFly-gRPC-subsystem/) ### [Vlog: Join us at Open Source Day on September 22, 2023 and Make Meaningful Contributions](/news/2023/09/13/Vlog-Join-us-at-Open-Source-Day-on-September-22-2023-and-Make-Meaningful-Contributions/) ### [WildFly and the Twelve-factor App Methodology](/news/2023/09/13/WildFly-and-the-Twelve-factor-App-Methodology/) ### [Vlog: Join us at Open Source Day on September 22nd, 2023 and Level Up Your Skills](/news/2023/09/08/Vlog-Join-us-at-Open-Source-Day-on-September-22nd-2023-and-Level-Up-Your-Skills/) ### [Vlog: Begin your Open Source Journey with the WildFly Elytron Project at Open Source Day](/news/2023/09/06/Vlog-Begin-your-Open-Source-Journey-with-the-WildFly-Elytron-Project-at-Open-Source-Day/) ### [Securing WildFly Apps with SAML on OpenShift](/news/2023/09/06/Securing-WildFly-Apps-with-SAML-on-OpenShift/) ### [Vlog: Begin your Open Source Journey with the WildFly Elytron Project at Open Source Day](/news/2023/08/29/Vlog-Begin-your-Open-Source-Journey-with-the-WildFly-Elytron-Project-at-Open-Source-Day/) ### [WildFly 29.0.1 is released!](/news/2023/08/23/WildFly-29-0-1-is-released/) WildFly 29.0.1.Final is now available for download. It’s been about five weeks since the WildFly 29 release, so we’ve done a small bug fix update, WildFly 29.0.1. This includes an update to WildFly Preview. The following issues were resolved in 29.0.1: Bugs [WFLY-18296] - Wildfly 29: does not start on JRE, works on JDK. Worked in WFLY28 [WFLY-18330] - [29.x] Upgrade com.squareup.okio to 3.4.0 (resolves CVE-2023-3635) [WFLY-18350] - The testsuite/galleon tests are too unconstrained as to what channel is tested [WFLY-18366] - Problems with upgrade of resteasy-microprofile and CDI Enhancements [WFLY-18388] - Move 29.x Quickstarts to BOMs and Server 29.0.1.Final Tasks [WFLY-18341] - Restore incorrectly updated copyright dates in Jipijapa Component Upgrades [WFLY-18294] - [WildFly 29] Upgrade HAL to 3.6.12.Final [WFLY-18376] - Upgrade RESTEasy to 6.2.5.Final [WFLY-18378] - Upgrade resteasy-microprofile to 2.1.3.Final [WFLY-18379] - Upgrade WildFly Core to 21.1.1.Final Issues resolved in the WildFly Core update included with WildFly 29.0.1 were: Component Upgrades [WFCORE-6444] - Upgrade BouncyCastle to 1.76 Enjoy! ### [Securing the WildFly Management Console with OpenID Connect](/news/2023/07/24/Securing-the-WildFly-Management-Console-with-OpenID-Connect/) ### [WildFly 29 is released!](/news/2023/07/21/WildFly-29-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 29.0.0.Final releases are available for download at https://wildfly.org/downloads. New and Notable During the WildFly 29 development cycle the WildFly contributors were heavily focused on bug fixing, plus a lot internal housekeeping that needed doing after all the recent work toward Jakarta EE 10. But we do have some new goodies: It is now possible to secure the management console with WildFly’s native support for OpenID Connect. You can use Galleon to add Keycloak’s SAML adapter to your WildFly installation using the new Keycloak SAML Adapter feature-pack. You can use Galleon to add MyFaces 4 support to your WildFly installation using the 1.0.0.Beta1 release of the new WildFly MyFaces feature-pack. (Note that the feature-pack is still a Beta.) The elytron subsystem’s new Distributed Realm attribute ignore-unavailable-realms enables a user to switch to ignoring unavailable realms during search and continue searching in subsequent realms. Supported Specifications Jakarta EE WildFly 29 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the Core Profile. WildFly is EE 10 compatible when running on both Java SE 11 and Java SE 17. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Specification Compatibility Evidence Jakarta EE 10 Full Platform SE 11 SE 17 Jakarta EE 10 Web Profile SE 11 SE 17 Jakarta EE 10 Core Profile SE 11 SE 17 MicroProfile WildFly supports numerous MicroProfile specifications. Because we no longer support MicroProfile Metrics, WildFly 28 cannot claim to be a compatible implementation of the MicroProfile 6.0 specification. However, WildFly’s MicroProfile support includes implementations of the following specifications in our "full" (e.g. standalone-full.xml) and "default" (e.g standalone.xml) configurations as well as our "microprofile" configurations (e.g. standalone-microprofile.xml): MicroProfile Technology WildFly Full/Default Configurations WildFly MicroProfile Configuration MicroProfile Config 3.0 X X MicroProfile Fault Tolerance 4.0  —  X MicroProfile Health 4.0  —  X MicroProfile JWT Authentication 2.1 X X MicroProfile LRA 2.0  —  X MicroProfile OpenAPI 3.1  —  X MicroProfile Open Telemetry 1.0  —  X MicroProfile Reactive Messaging 3.0  —   —  MicroProfile Reactive Streams Operators 3.0  —   —  MicroProfile Rest Client 3.0 X X Compatibility evidence for the above specifications that are part of MicroProfile 6.0 can be found in the WildFly Certifications repository on GitHub. Java SE Support Our recommendation is that you run WildFly on the most recent long-term support Java SE release, i.e. on SE 17 for WildFly 29. While we do do some testing of WildFly on JDK 20, we do considerably more testing of WildFly itself on the LTS JDKs, and we make no attempt to ensure the projects producing the various libraries we integrate are testing their libraries on anything other than JDK 11 or 17. WildFly 29 also is heavily tested and runs well on Java 11. We anticipate continuing to support Java 11 at least through WildFly 30, and perhaps beyond. We do, however, anticipate removing support for SE 11 sometime in the next 12 to 18 months. While we recommend using an LTS JDK release, I do believe WildFly runs well on JDK 20. By runs well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. Please note that WildFly runs in classpath mode. Migration Issues In this section of these release announcements I’ll note issues users may experience when migrating from a previous version of WildFly. Galleon Tooling We’ve added additional metadata to the files WildFly’s Galleon layers provide to the Galleon tooling, with the aim of providing exciting new provisioning capabilities. (Keep an eye out for more on those new capabilities in a future WildFly release.) This addition, however necessitates that in order to provision WildFly 29 users must update the versions of Galleon-related tooling they use. For those who use the Galleon CLI tool to provision WildFly, version 5.2.0.Final or later is required. Version 5.2.0.Final or later is also required for users of the Galleon Maven Plugin For those who use the WildFly Maven Plugin to provision WildFly, version 4.2.0.Final or later is required. For users who use the WildFly JAR Maven Plugin to produce a bootable jar: version 10.0.0.Final or later is required. We are working to add improved forward compatibility to our tooling to help reduce the likelihood that future improvements will require users to update their tooling versions in order to work with newer releases of WildFly. Release Notes The full release notes for the release are in the WildFly JIRA. Issues fixed in the underlying WildFly Core 21.0.0 release are listed in the WildFly Core JIRA. Please try it out and give us your feedback, in the WildFly google group, Zulip or JIRA. Meanwhile, we’re busy at work on WildFly 30! Best regards, Brian ### [Remote EJB Client for Batch Application](/news/2023/07/21/Remote-EJB-Client-for-Batch-Application/) ### [Using Certificate Based Authentication with Mutual TLS without Roles](/news/2023/06/26/Using-Certificate-Based-Authentication-with-Mutual-TLS-without-Roles/) ### [Deploy on Kubernetes with Helm](/news/2023/06/16/Deploy-on-Kubernetes-with-Helm/) Helm is a tool that helps define, install and upgrade complex applications on Kubernetes clusters. In this post, we will use the Wildfly chart from https://github.com/wildfly/wildfly-charts/ to deploy a simple Wildfly application: Create a simple Java application Use the wildfly-maven-plugin’s image goal to create a Docker image straight from Maven Push that image in a container registry (eg quay.io or ghcr.io) Use Helm to deploy that image in a Kubernetes cluster (e.g. using kind) Note: for the purpose of this article we will use 'kind' as a tool for running local Kubernetes cluster (see more about kind). Prerequisites Helm installed Docker or Podman A kubernetes cluster A public container registry where to push and pull your image (e.g. on quay.io or ghcr.io) Create a simple Java application We will use the helloworld WildFly quickstart as an example: $ git clone https://github.com/wildfly/quickstart $ cd quickstart/helloworld Install Helm and have access to a Kubernetes cluster. Please refer to Installing Helm page to install Helm in your environment. We will use kind as our Kubernetes cluster. Install Helm Repository for WildFly Chart The wildfly Chart can be installed from the https://docs.wildfly.org/wildfly-charts/ repository $ helm repo add wildfly https://docs.wildfly.org/wildfly-charts/ "wildfly" has been added to your repositories $ helm search repo wildfly NAME CHART VERSION APP VERSION DESCRIPTION wildfly/wildfly 2.3.1 Build and Deploy WildFly applications on OpenShift wildfly/wildfly-common 2.1.0 A library chart for WildFly-based applications Make sure your application pom contains the wildfly-maven-plugin plugin In our helloworld quickstart the wildfly-maven-plugin plugin is already present under the 'openshift' profile. Add it if you don’t have it in your pom.xml. <profiles> ... <profile> <id>openshift</id> <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.server}</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:${version.cloud.fp}</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> </layers> <filename>${project.artifactId}-${project.version}.war</filename> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> ... </profiles> Build the docker image with the wildfly-maven-plugin plugin Note: In this example we use 'docker', but 'podman' works as well. $ mvn package wildfly:image -Popenshift [INFO] Scanning for projects... [INFO] [INFO] -----------------< org.wildfly.quickstarts:helloworld >----------------- [INFO] Building Quickstart: helloworld 29.0.0.Alpha1-SNAPSHOT [INFO] --------------------------------[ war ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ helloworld --- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory /home/msappegr/workspace/test/helloworld/src/main/resources [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ helloworld --- [INFO] Changes detected - recompiling the module! [WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent! [INFO] Compiling 2 source files to /home/msappegr/workspace/test/helloworld/target/classes [INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ helloworld --- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] Copying 1 resource [INFO] [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ helloworld --- [INFO] Changes detected - recompiling the module! [WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent! [INFO] Compiling 2 source files to /home/msappegr/workspace/test/helloworld/target/test-classes [INFO] [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ helloworld --- [INFO] [INFO] --- maven-war-plugin:3.2.3:war (default-war) @ helloworld --- [INFO] Packaging webapp [INFO] Assembling webapp [helloworld] in [/home/msappegr/workspace/test/helloworld/target/helloworld-29.0.0.Alpha1-SNAPSHOT] [INFO] Processing war project [INFO] Copying webapp resources [/home/msappegr/workspace/test/helloworld/src/main/webapp] [INFO] Webapp assembled in [38 msecs] [INFO] Building war: /home/msappegr/workspace/test/helloworld/target/helloworld-29.0.0.Alpha1-SNAPSHOT.war [INFO] [INFO] --- wildfly-maven-plugin:4.1.0.Final:package (default) @ helloworld --- [INFO] Provisioning server in /home/msappegr/workspace/test/helloworld/target/server [INFO] Resolving feature-packs [INFO] Installing packages [INFO] Resolving artifacts [INFO] Generating configurations Jul 07, 2023 5:10:53 PM org.wildfly.core.embedded.LoggerContext$JBossLoggingModuleLogger greeting INFO: JBoss Modules version 2.1.0.Final Jul 07, 2023 5:10:54 PM org.jboss.msc.service.ServiceContainerImpl <clinit> INFO: JBoss MSC version 1.5.0.Final Jul 07, 2023 5:10:54 PM org.jboss.threads.Version <clinit> INFO: JBoss Threads version 2.4.0.Final Jul 07, 2023 5:10:54 PM org.jboss.as.server.ApplicationServerService start INFO: WFLYSRV0049: WildFly Full 28.0.1.Final (WildFly Core 20.0.2.Final) starting Jul 07, 2023 5:10:54 PM org.jboss.as.patching.installation.InstallationManagerService start INFO: WFLYPAT0050: WildFly Full cumulative patch ID is: base, one-off patches include: none Jul 07, 2023 5:10:54 PM org.jboss.as.server.suspend.SuspendController resume INFO: WFLYSRV0212: Resuming server Jul 07, 2023 5:10:54 PM org.jboss.as.server.BootstrapListener printBootStatisticsMessage INFO: WFLYSRV0025: WildFly Full 28.0.1.Final (WildFly Core 20.0.2.Final) started in 868ms - Started 29 of 32 services (3 services are lazy, passive or on-demand) - Server configuration file in use: standalone.xml Jul 07, 2023 5:10:55 PM org.wildfly.security.Version <clinit> INFO: ELY00001: WildFly Elytron version 2.1.0.Final Jul 07, 2023 5:10:56 PM org.jboss.as.server.ApplicationServerService stop INFO: WFLYSRV0050: WildFly Full 28.0.1.Final (WildFly Core 20.0.2.Final) stopped in 4ms [INFO] Copy deployment /home/msappegr/workspace/test/helloworld/target/helloworld-29.0.0.Alpha1-SNAPSHOT.war to /home/msappegr/workspace/test/helloworld/target/server/standalone/deployments/helloworld-29.0.0.Alpha1-SNAPSHOT.war [INFO] [INFO] --- wildfly-maven-plugin:4.1.0.Final:image (default-cli) @ helloworld --- [INFO] A server already exists in /home/msappegr/workspace/test/helloworld/target/server, skipping image of org.wildfly.quickstarts:helloworld [INFO] Generating Dockerfile /home/msappegr/workspace/test/helloworld/target/Dockerfile from base image quay.io/wildfly/wildfly-runtime:latest [INFO] Building application image helloworld:latest using docker. [INFO] Executing the following command to build application image: 'docker build -t helloworld:latest .' [INFO] #1 [internal] load build definition from Dockerfile [INFO] #1 transferring dockerfile: 351B done [INFO] #1 DONE 0.0s [INFO] [INFO] #2 [internal] load .dockerignore [INFO] #2 transferring context: 2B done [INFO] #2 DONE 0.0s [INFO] [INFO] #3 [internal] load metadata for quay.io/wildfly/wildfly-runtime:latest [INFO] #3 DONE 0.7s [INFO] [INFO] #4 [1/4] FROM quay.io/wildfly/wildfly-runtime:latest@sha256:841dcb723e1dd55c86c5762a19f190967c7f5382c2b1896ab34e033091b2d1b1 [INFO] #4 DONE 0.0s [INFO] [INFO] #5 [internal] load build context [INFO] #5 transferring context: 148.55MB 0.8s done [INFO] #5 DONE 0.8s [INFO] [INFO] #4 [1/4] FROM quay.io/wildfly/wildfly-runtime:latest@sha256:841dcb723e1dd55c86c5762a19f190967c7f5382c2b1896ab34e033091b2d1b1 [INFO] #4 CACHED [INFO] [INFO] #6 [2/4] COPY --chown=jboss:root server /opt/server [INFO] #6 DONE 0.5s [INFO] [INFO] #7 [3/4] RUN chmod -R ug+rwX /opt/server [INFO] #7 DONE 2.0s [INFO] [INFO] #8 [4/4] COPY --chown=jboss:root helloworld-29.0.0.Alpha1-SNAPSHOT.war /opt/server/standalone/deployments/helloworld-29.0.0.Alpha1-SNAPSHOT.war [INFO] #8 DONE 0.1s [INFO] [INFO] #9 exporting to image [INFO] #9 exporting layers [INFO] #9 exporting layers 0.8s done [INFO] #9 writing image sha256:cb47ca7e7baccc74e877087f98659509e14d70c91030d0234245ffaa481f7cbc done [INFO] #9 naming to docker.io/library/helloworld:latest done [INFO] #9 DONE 0.8s [INFO] Successfully built application image helloworld:latest [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 17.841 s [INFO] Finished at: 2023-07-07T17:11:05+02:00 [INFO] ------------------------------------------------------------------------ And then make sure you have it in your docker images $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE helloworld latest 6d404b584da2 32 seconds ago 686MB Push the just created image to a container registry (e.g. quay.io, ghcr.io or hub.docker.com) In this article we will use Quay.io as a container registry. If you don’t have an account you can start a free trial on https://quay.io/ or create an account on dockerhub. Login to your container registry (see how to get started here) Tag the new image with the proper format 'quay.io/username/reponame' Note: make sure to replace the 'username' (your account username) and the 'reponame' (your image name) accordingly! If you use ghcr.io you have to change 'quay.io/username/reponame' with ghcr.io/NAMESPACE/IMAGE_NAME If you use hub.docker.com you have to change 'quay.io/username/reponame' with username/image_name $ docker login quay.io $ docker tag helloworld quay.io/username/helloworld Check that your image has been tagged: $ docker images helloworld latest 6d404b584da2 56 minutes ago 686MB quay.io/username/helloworld latest 6d404b584da2 56 minutes ago 686MB Push the image in your registry: $ docker push quay.io/username/helloworld Using default tag: latest The push refers to repository [quay.io/username/helloworld] ad91a69a4efb: Pushed f454069ae0d4: Pushed b21a08aa50a4: Pushed 4fc9e93f9cc1: Pushed 55ea6d5a354e: Pushed latest: digest: sha256:1d72e7b4f8dd75414a2b1dc8da3505906b0211ac6962e871b84f2c8ead43cb3a size: 1377 Now your image is available in your container registry (in my case it is available at https://quay.io/repository/rh_ee_msappegr/helloworld) Note: make sure your registry is public in order to pull it from the cluster. Otherwise you will need to create a docker-registry secret . Create the YAML value file under the charts folder In our example the charts folder already exists under quickstart/helloworld/charts, so move to that directory and create a file named values.yaml $ cd charts $ touch values.yaml and paste the following inside the values.yaml image: name: quay.io/rh_ee_msappegr/helloworld # change it with the image you have just pushed build: enabled: false # The build part is not needed since we have already built our application with the wildfly-maven-plugin plugin deploy: route: enabled: false # the route can be enabled, but only for OpenShift clusters Deploy the Application on Kubernetes Once the wildfly Chart is added, we can install a Helm release by using the helm install command with the name of the release as well as a YAML configuration file that contains all the settings to build and deploy the application: $ helm install helloworld-app \ wildfly/wildfly \ -f charts/values.yaml NAME: helloworld-app LAST DEPLOYED: Wed Jun 14 18:45:38 2023 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: To follow the deployment of your application, run: $ kubectl get deployment helloworld-app -w As you can read above, the output of the helm install command contains instructions to follow the installation of the application. We can watch its deployment by running: $ kubectl get deployment helloworld-app -w NAME READY UP-TO-DATE AVAILABLE AGE helloworld-app 1/1 1 1 30s The application is now available and we can query it (you might need to wait some seconds to see our application up and running). In order to reach your application from the browser you could port-forward port 8080 to your host: $ kubectl port-forward $(oc get pod -l app.kubernetes.io/instance=helloworld-app -o name) 8080:8080 Forwarding from 127.0.0.1:8080 -> 8080 ... Note: If your application has a different name you can retrieve your pod name by executing: $ kubectl get pod Then in the output you will see your pod name. Using the 'pod name' execute: $ kubectl port-forward your_pod_name 8080:8080 Now open your browser and browse URL 'localhost:8080', your application will respond: Hello World! Alternately you can curl it from your terminal: $ curl localhost:8080 <!-- JBoss, Home of Professional Open Source Copyright 2015, Red Hat, Inc. and/or its affiliates, and individual contributors by the @authors tag. See the copyright.txt in the distribution for a full listing of individual contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!-- Plain HTML page that kicks us into the app --> <html> <head> <meta http-equiv="Refresh" content="0; URL=HelloWorld"> </head> </html> The application is up and running. Conclusion It is possible to run your application with very simple steps. All that is necessary is to: have the wildfly-maven-plugin plugin in your root pom generate your image and to push it to your registry install the helm chart More about Helm Chart More documentation about it can be found at wildfly Chart documentation. More information Helm - The package manager for Kubernetes wildfly-charts Project Page Wildfly Chart documentation ### [grpc and WildFly - Part I](/news/2023/06/12/grpc-and-WildFly-Part-I/) We are pleased to announce the first release of support for gRPC services in WildFly[1]. gRPC, a Google project, is, as its name suggests, a Remote Procedure Call framework. In some ways, it is a competitor to Jakarta RESTFul Web Services, but it has different semantics and a different performance profile. gRPC rests on another Google project, protobuf, which is, according to the website, "a language-neutral, platform-neutral extensible mechanism for serializing structured data." It consists of 1) a programming language independent data definition language and 2) a compressed wire protocol for transmitting data. Moreover, protobuf data is transported over HTTP/2, and taken together, gRPC is well positioned for speedy transmission. On the other hand, the most common data format in the Jakarta REST world is the more readable but more verbose JSON, and there is evidence (Evaluating Performance of REST vs. gRPC) that gRPC transmission can be considerably faster than Jakarta REST transmission. Of course, your mileage may vary. Given that this is a WildFly blog, and given that RESTEasy, as an implementation of Jakarta RESTful Web Services, is a foundational technology in WildFly, we will assume that the reader is familiar with Jakarta REST but not necessarily familiar with gRPC, and so we’ll take a minute to introduce the latter. What is gRPC? gRPC is a modern iteration in a long history of RPC frameworks, a notable example of which is CORBA. In particular, as one smart guy said[2], "gRPC is to CORBA what REST is to SOAP", which should be a relief to anyone proposing to learn gRPC. A gRPC application begins with a language neutral description of data types and procedure calls. Consider, for example, the following, which comes from the helloworld example in the wildfly-grpc-feature-pack project (https://github.com/wildfly-extras/wildfly-grpc-feature-pack): syntax = "proto3"; option java_multiple_files = true; option java_package = "org.wildfly.extension.grpc.example.helloworld"; option java_outer_classname = "HelloWorldProto"; option objc_class_prefix = "HLW"; package helloworld; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; } Here, HelloRequest and HelloReply are message types, and SayHello is a procedure call that sends the former and receives the latter. This file can be compiled into any number of programming languages, including C++, Python, and, of course, Java. Given that the configuration parameter java_multiple_files is set to true, each of HelloRequest and HelloResponse is compiled to a somewhat opaque Java class with roughly 600 lines, not really meant for human consumption. An additional class generated by the gRPC compiler, GreeterGrpc, has the client and server side infrastructure. For the client there is GreeterBlockingStub, which allows the client to make calls to the server, something like this: ManagedChannelchannel = ManagedChannelBuilder .forTarget("localhost:9555") .usePlaintext() .build(); GreeterGrpc.GreeterBlockingStub blockingStub = GreeterGrpc.newBlockingStub(channel); HelloRequest request = HelloRequest.newBuilder().setName("Bill").build(); HelloReply response = blockingStub.sayHello(request); System.out.println(response.getMessage()); For the server side, there is the inner class GreeterGrpc.GreeterImplBase, which, for each procedure call, has a method that throws an exception. Implementing the service, then, is a matter of overriding each such method with real content, as in GreeterServiceImpl @Override public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) { String name = request.getName(); String message = "Hello " + name; responseObserver.onNext(HelloReply.newBuilder().setMessage(message).build()); responseObserver.onCompleted(); } By virtue of implementing io.grpc.BindableService, GreeterServiceImpl is a gRPC service, and it is installed as follows: io.grpc.Server server = ServerBuilder.forPort(9555) .addService(new GreeterServiceImpl()) .build() .start(); gRPC in WildFly The previous snippet can be used to set up a free standing gRPC server, but we’re here to talk about the new gRPC subsystem in WildFly. It is packaged in the form of a galleon feature-pack, and it can be installed in WildFly as follows galleon.sh install wildfly:current --dir=wildfly galleon.sh install org.wildfly.extras.grpc:wildfly-grpc-feature-pack:0.1.0.Final --layers=grpc --dir=wildfly An instance of WildFly with the grpc feature-pack will recognize any deployment with one or more instances of io.grpc.BindableService, will install them all, and will start listening on a port which defaults to 9555. The grpc subsystem has over 20 configurable parameters which can be discovered by way of the jboss-cli interface: [standalone@localhost:9990 /] cd subsystem=grpc [standalone@localhost:9990 subsystem=grpc] ls flow-control-window=undefined permit-keep-alive-time=undefined handshake-timeout=undefined permit-keep-alive-without-calls=undefined initial-flow-control-window=undefined protocol-provider=undefined keep-alive-time=undefined server-host=localhost keep-alive-timeout=undefined server-port=9555 key-manager-name=key-manager-afcdd1f8-d1a7-4137-aa13-c45237e32428 session-cache-size=undefined max-concurrent-calls-per-connection=undefined session-timeout=undefined max-connection-age=undefined shutdown-timeout=3 max-connection-age-grace=undefined ssl-context-name=undefined max-connection-idle=undefined start-tls=undefined max-inbound-message-size=undefined trust-manager-name=key-manager-trust-store-eeeecd12-36f9-4156-92c7-a889383f17a1 max-inbound-metadata-size=undefined Most of these are technical parameters used by io.grpc.netty.NettyServerBuilder. Some of the more prominent parameters are server-port, key-manager-name, and trust-manager-name. The latter two parameters are used to configure the SSL properties of the connections between the gRPC clients and the server. gRPC over SSL connections SSL connections are configured by way of the elytron subsystem. First, note that if you want a plaintext connection, the key-manager-name property should be set to null. Otherwise, consider the following fragment from a standalone.xml file, which is configured for identities to be verified on both the server and the client: <subsystem xmlns="urn:wildfly:elytron:17.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto"> ... <tls> <key-stores> ... <key-store name="key-store-afcdd1f8-d1a7-4137-aa13-c45237e32428"> <credential-reference clear-text="secret"/> <implementation type="JKS"/> <file required="false" path="server.keystore.jks" relative-to="jboss.server.config.dir"/> </key-store> <key-store name="trust-store-eeeecd12-36f9-4156-92c7-a889383f17a1"> <credential-reference clear-text="secret"/> <implementation type="JKS"/> <file required="false" path="server.truststore.jks" relative-to="jboss.server.config.dir"/> </key-store> </key-stores> <key-managers> ... <key-manager name="key-manager-afcdd1f8-d1a7-4137-aa13-c45237e32428" key-store="key-store-afcdd1f8-d1a7-4137-aa13-c45237e32428"> <credential-reference clear-text="secret"/> </key-manager> </key-managers> <trust-managers> <trust-manager name="key-manager-trust-store-eeeecd12-36f9-4156-92c7-a889383f17a1" key-store="trust-store-eeeecd12-36f9-4156-92c7-a889383f17a1"/> </trust-managers> </tls> </subsystem> <subsystem xmlns="urn:wildfly:grpc:1.0" key-manager-name="key-manager-afcdd1f8-d1a7-4137-aa13-c45237e32428" trust-manager-name="key-manager-trust-store-eeeecd12-36f9-4156-92c7-a889383f17a1"/> Note that the grpc parameter key-manager-name is set to "key-manager-afcdd1f8-d1a7-4137-aa13-c45237e32428", which refers to a key-manager configured in elytron. That key-manager refers to a keystore named "key-store-afcdd1f8-d1a7-4137-aa13-c45237e32428, which refers to file "server.keystore.jks" in the standalone/configuration directory (the value of "jboss.server.config.dir"). So, "server.keystore.jks" should be there. Next, note that the grpc parameter trust-manager-name is set to "key-manager-trust-store-eeeecd12-36f9-4156-92c7-a889383f17a1", which is the name of a trust-manager that refers to keystore "trust-store-eeeecd12-36f9-4156-92c7-a889383f17a1", which refers to file "server.truststore.jks" in standalone/configuration. Again, that file should be present. So, there is a keystore and a truststore on the server, and there must be a matching truststore and keystore on the client. Those can be used as follows by the client: ClassLoader classLoader = GreeterClient.class.getClassLoader(); InputStream trustStore = classLoader.getResourceAsStream("client.truststore.pem"); InputStream keyStore = classLoader.getResourceAsStream("client.keystore.pem"); InputStream key = classLoader.getResourceAsStream("client.key.pem"); ChannelCredentials creds = TlsChannelCredentials .newBuilder() .trustManager(trustStore) .keyManager(keyStore, key) .build(); ManagedChannel channel = Grpc.newChannelBuilderForAddress("localhost", 9555, creds).build(); GreeterClient client = new GreeterClient(channel); client.greet("world"); A more common scenario would be where only the server is required to present credentials to the client, in which case the grpc subsystem would need just a key-manager-name, associated with a keystore, and trust-manager-name is null. Downloading The wildfly-grpc-feature-pack jar can be downloaded from https://central.sonatype.com/artifact/org.wildfly.extras.grpc/wildfly-grpc-feature-pack/0.1.0.Final The source code for the subsystem and examples is found here: https://github.com/wildfly-extras/wildfly-grpc-feature-pack A more detailed discussion can be found here: https://github.com/wildfly-extras/wildfly-grpc-feature-pack/blob/main/docs/guide/index.adoc References 1. Also, see Part II: https://resteasy.dev/2023/06/11/grpc-in-wildfly-pt2/ 2. Stuart Douglas, email ### [Using MicroProfile LRA in WildFly](/news/2023/05/24/Using-MicroProfile-LRA-in-WildFly/) MicroProfile Long Running Actions (LRA) is a specification that defines the protocol and an API for the distributed transactions based on the saga pattern and user-defined compensations. In WildFly 28.0.0.Final, we introduced the integration of Narayana LRA which implements this specification. In this guide, we look into how you can enable LRA in your WildFly distribution and how you can use LRA in your applications. Overview of the LRA protocol We provide only a high-level overview of the LRA protocol in this post. The full overview of the protocol is available at https://download.eclipse.org/microprofile/microprofile-lra-2.0/microprofile-lra-spec-2.0.html. In LRA, the specification API utilizes annotations from the org.eclipse.microprofile.lra.annotation package. The main annotation is the @LRA which controls the life cycle of the LRA. It’s use might seem similar to the use of @Transactional annotation from JTA, however, the transaction characteristics differ greatly. If you are interested in the comparison of the saga pattern to the ACID transactions, you can find an explanation in this talk from DevoxxUK - https://www.youtube.com/watch?v=7DI4xXv1xGU. The Narayana implementation utilizes the coordinator orchestration of the LRAs. The LRA coordinator is a standalone service that is responsible for the management operations of the LRAs started in the system. When any LRA participant (user service) wants to start a new LRA, it contacts the LRA coordinator that in turn returns the LRA ID of the newly started LRA that can be propagated by the LRA participant to any other services. When an LRA-aware service receives the LRA ID, it can optionally enlist within the same LRA which is again done by the enlistment call to the coordinator. When the LRA finishes (success or failure), the LRA coordinator is responsible for invocations of the completions or the compensations callbacks of all enlisted LRA participants. Enabling MicroProfile LRA subsystems The integration of the LRA specification is included in two separate subsystems: microprofile-lra-coordinator - The LRA coordinator responsible for starting, managing, and recovery of the LRAs. microprofile-lra-participant - The client library utilized in user deployments to participate in the distributed LRAs and define compensation and completition callbacks. Required extensions and subsystems configuration The LRA extensions are not included in the standard configurations included with WildFly application server. They need to be explitcly enabled either in the configuration XML or by using CLI operations: [standalone@localhost:9990 /] /extension=org.wildfly.extension.microprofile.lra-coordinator:add {"outcome" => "success"} [standalone@localhost:9990 /] /subsystem=microprofile-lra-coordinator:add { "outcome" => "success", "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } } [standalone@localhost:9990 /] /extension=org.wildfly.extension.microprofile.lra-participant:add {"outcome" => "success"} [standalone@localhost:9990 /] /subsystem=microprofile-lra-participant:add { "outcome" => "success", "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } } [standalone@localhost:9990 /] reload Running LRA coordinator in a Docker container The LRA coordinator is also provided as a standalone Docker image that you can simply run with the following command: $ docker run -p 8080:8080 quay.io/jbosstm/lra-coordinator Using LRA in user deployments The @LRA annotation can be placed on any JAX-RS method to declare that the LRA should be started before the method is entered and closed (finished successfully) when the method ends. By default, if the JAX-RS method returns any of the 4xx or 5xx error HTTP status codes the LRA will be cancelled instead. @LRA @GET @Path("/doInLRA") public Response doInLRA(@HeaderParam(LRA.LRA_HTTP_CONTEXT_HEADER) String lraId) { LOG.info("Work LRA ID = " + lraId); ... When LRA closes successfully, the LRA coordinator calls the completion callback if the participant defined it: @Complete @PUT @Path("/complete") public Response complete(@HeaderParam(LRA.LRA_HTTP_CONTEXT_HEADER) String lraId) { LOG.info("Complete ID = " + lraId); ... Or, in the case of LRA cancel, the compensation callback will be invoked instead: @Compensate @PUT @Path("/compensate") public Response compensate(@HeaderParam(LRA.LRA_HTTP_CONTEXT_HEADER) String lraId) { LOG.info("Compensate ID = " + lraId); ... The full example is available at https://github.com/xstefank/lra-wildfly-example. If you deploy this application to WildFly (28.0.0+) with both microprofile-lra-coordinator and microprofile-lra-participant subsystems enabled, you can make the following HTTP invocation to see how the coordinator invokes the complete callbacks or the compensation callbacks of the two defined participants: $ curl localhost:8080/lra-participant/lra-participant-1/doInLRA # in WFLY console log 15:14:50,128 INFO [io.xstefank.LRAParticipant1] (default task-1) Work LRA ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_14 15:14:50,158 INFO [io.xstefank.LRAParticipant2] (default task-2) Work LRA ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_14 15:14:50,183 INFO [io.xstefank.LRAParticipant1] (default task-3) Complete ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_14 15:14:50,191 INFO [io.xstefank.LRAParticipant2] (default task-3) Complete ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_14 $ curl "localhost:8080/lra-participant/lra-participant-1/doInLRA?fail=true" # in WFLY console log 15:15:33,516 INFO [io.xstefank.LRAParticipant1] (default task-1) Work LRA ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_1c 15:15:33,531 INFO [io.xstefank.LRAParticipant2] (default task-2) Work LRA ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_1c 15:15:33,543 INFO [io.xstefank.LRAParticipant1] (default task-3) Compensate ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_1c 15:15:33,550 INFO [io.xstefank.LRAParticipant2] (default task-3) Compensate ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_1c You can also always check the currently active LRAs with a direct call to the coordinator API: $ curl localhost:8080/lra-coordinator/lra-coordinator []% Conclusion In this post, we showed you how to configure and use the MicroProfile LRA specification in your WildFly applications. LRA provides a very broad feature set which we can’t cover here. If you are interested in learning more, you can find the full specification at https://download.eclipse.org/microprofile/microprofile-lra-2.0/microprofile-lra-spec-2.0.html. ### [WildFly 28.0.1 is released!](/news/2023/05/23/WildFly-28-0-1-is-released/) WildFly 28.0.1.Final is now available for download. It’s been about five weeks since the WildFly 28 release, so we’ve done a small bug fix update, WildFly 28.0.1. This includes an update to WildFly Preview. The following issues were resolved in 28.0.1: Bugs [WFLY-17016] - todo-backend QS has outdated Readme instructions [WFLY-17921] - Add missing org.jboss.vfs to RESTEasy Spring deployments [WFLY-17947] - todo-backend Readme OpenShift instructions results in a non-functional QS app [WFLY-17960] - LRA causes a failure in the ContextPropagationTestCase [WFLY-18002] - ExpirationMetaData.isExpired() test does not conform to logic in LocalScheduler [WFLY-18011] - Add java.base/java.net package to recommended client side JPMS settings [WFLY-18012] - The JaxrsIntegrationProcessor should not attempt to get the RESTEasy configuration when not a REST deployment. Component Upgrades [WFLY-17955] - Upgrade to Smallrye opentelemetry 2.3.2 [WFLY-18005] - Upgrade RESTEasy to 6.2.4.Final [WFLY-18007] - Upgrade xalan to 2.7.3 (CVE-2022-34169) [WFLY-18010] - Upgrade jose4j to 0.9.3 [WFLY-18022] - WildFly Core to 20.0.2.Final Issues resolved in the WildFly Core update included with WildFly 28.0.1 were: Bugs [WFCORE-6344] - Changes to json-formatter meta-data never take effect [WFCORE-6346] - module java.base does not "opens java.net" to unnamed module Tasks [WFCORE-6326] - Add back the org.jboss.vfs module as a dependency on deployments Component Upgrades [WFCORE-6302] - CVE-2022-1259 Upgrade Undertow to 2.3.6.Final Enjoy! ### [Configuring the Digest Mechanism to Make Use of Additional Algorithms](/news/2023/05/16/Configuring-the-Digest-Mechanism-to-Make-Use-of-Additional-Algorithms/) ### [WildFly Release Plans](/news/2023/05/11/WildFly-Release-Plans/) As the WildFly project continues to move on from the major effort involved with integrating Jakarta EE 10, it’s time to go back to the roughly time-boxed development and release model that worked so well from WildFly 12 until WildFly 26. During that period, the WildFly project followed a roughly time-boxed development model. Roughly every three months we produced a new WildFly major release, with a large set of features, enhancements and bug fixes. We didn’t operate on a strict time schedule, but we tried to avoid significant schedule delays just to bring in particular feature or set of features. If a feature didn’t make a particular release it could just go in the next one a few months later. At the beginning of 2022, I announced a temporary shift away from that development model and toward a feature-boxed approach. We did this because it was a more effective way to implement the transition to EE 10. But with that work behind us, the consensus among the WildFly developers is that moving back to the old time-boxed apprach will allow more effective delivery of new features and fixes to our users. Our aim is to produce feature releases in January, April, July and October. Experience has shown us that those months work best for not having development work overly disrupt summer or year end holidays. We’ll continue with our practice of releasing a Beta two weeks before the Final release, except for the January release, where the beta will be out somewhat earlier to avoid doing any release work in the latter part of December. 2023 - 2024 Release Schedule The following is a rough schedule of when we intend to do feature releases over the remainder of 2023 and through 2024. Please note that these dates are subject to change. Version Beta Release Final Release WildFly 29 June 29, 2023 July 13, 2023 WildFly 30 September 28, 2023 October 12, 2023 WildFly 31 December 14, 2023 January 11, 2024 WildFly 32 March 28, 2024 April 11, 2024 WildFly 33 June 27, 2024 July 11, 2024 WildFly 34 September 26, 2024 October 10, 2024 WildFly 35 December 12, 2024 January 9, 2025 WildFly is only roughly time boxed. We are certainly willing to delay a release to ensure adequate quality, and we would consider delaying a couple of weeks to include features of large enough significance. For example if a new MicroProfile release comes out in June and we need a bit more time to incorporate it in WildFly 29 we would consider delaying the WildFly 29 release somewhat. If we delayed a release we would not intend to then delay the next release; the next release would just have a shorter development window. The general idea though is to not block releasing waiting for features, as a quarterly cycle means a feature that misses a release can appear soon enough. Micro Releases When we release each major we also create a new branch specific to that major. That branch is used to produce one micro (primarily bug fix) release for the major, with the micro usually released about a month after the major. This too is roughly time-boxed. Work on the WildFly 28.0.1 release, coordinated by Farah Juma, is currently in progress. The number of changes in the micro is typically small compared to what’s gone into main in the same period, as we want to be particularly conservative about introducing bugs or behavior changes in the micro. We’ve been consistently producing these micros since WildFly 17.0.1, and had done a few prior to that as well. Questions? If you have questions or want to provide feedback, I encourage you to post on the WildFly forum, on the wildfly-dev mail list or in Zulip chat. I will be starting a thread on the forum about this topic. Best regards, Brian ### [Using Custom Principals with Elytron](/news/2023/04/25/Using-Custom-Principals-with-Elytron/) ### [WildFly 28 is released!](/news/2023/04/20/WildFly-28-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 28.0.0.Final releases are available for download at https://wildfly.org/downloads. New and Notable Observability The biggest changes in WildFly 28 relate to the observability space. The micrometer subsystem has been added to standard WildFly, bringing Micrometer support. As part of this work, we’ve added support for Micrometer integration with our MicroProfile Fault Tolerance implementation. The micrometer subsystem was first introduced in WildFly Preview in WildFly 27. Note that the subsystem has been updated from what was in WildFly Preview 27 to switch to pushing metric data via OTLP to a remote collector, instead of supporting polling of data on the WildFly server’s management interface. (Server and JVM metrics can still be pulled from the management endpoint if the base metrics subsystem is configured.) We’ve also added support for MicroProfile Telemetry via a new microprofile-telemetry subsystem. We’ve removed support for MicroProfile Metrics, except for a stub system limited to 'admin-only' mode that’s been kept to facilitate configuration migration. MicroProfile Metrics users are encouraged to use the new micrometer subsystem. We’ve removed support for MicroProfile OpenTracing, except for a stub system limited to 'admin-only' mode that’s been kept to facilitate configuration migration. MicroProfile OpenTracing users are encouraged to use the new microprofile-telemetry subsystem, or the opentelemetry subsystem upon which it is based. MicroProfile Besides the changes in the observability space noted above, there are a couple of important changes in WildFly 28’s MicroProfile support: We’ve added support for MicroProfile LRA via new microprofile-lra-coordinator and microprofile-lra-participant subsystems. Except for MicroProfile Metrics and OpenTracing, which have been removed, we’ve updated our support for the other MicroProfile Platform specifications to the MicroProfile Platform 6 versions. Because we no longer support MicroProfile Metrics, WildFly 28 cannot claim to be a compatible implementation of the MicroProfile 6.0 specification. However, WildFly’s MicroProfile support includes implementations of the following specifications in our "full" (e.g. standalone-full.xml) and "default" (e.g standalone.xml) configurations as well as our "microprofile" configurations (e.g. standalone-microprofile.xml): MicroProfile Technology WildFly Full/Default Configurations WildFly MicroProfile Configuration MicroProfile Config 3.0 X X MicroProfile Fault Tolerance 4.0  —  X MicroProfile Health 4.0  —  X MicroProfile JWT Authentication 2.1 X X MicroProfile LRA 2.0  —  X MicroProfile OpenAPI 3.1  —  X MicroProfile Open Telemetry 1.0  —  X MicroProfile Reactive Messaging 3.0  —   —  MicroProfile Reactive Streams Operators 3.0  —   —  MicroProfile Rest Client 3.0 X X Provisioning We’ve added a new ee-core-profile-server Galleon layer to make it easy to provision a server based on the new Jakarta EE Core Profile introduced in EE 10. Related to this we’ve introduced new ee-concurrency and ee-integration and servlet Galleon layers. These layers allow a more tailored configuration compared to the existing ee and web-server layers. Also, separate from WildFly itself, to help users in their migration from Jakarta EE 8 to EE 10 we’ve introduced a separate WildFly Extras project that provides a new Galleon feature-pack. The wildfly-deployment-transformer-feature-pack allows you to integrate into a standard WildFly installation the EE 8 to EE 9 deployment transformation functionality that we’ve provided in WildFly Preview since its first release. See the wildfly-deployment-transformer-feature-pack README for documentation on how to use this new feature-pack. Quickstarts Eduardo Martins and the teams working on server provisioning and cloud have done a significant enhancement to the WildFly quickstarts to deliver a set of Quickstarts which showcase WildFly major enhancements with respect to provisioning, cloud and testing. We’ve also added a new quickstart that demonstrates connecting to a remote Artemis messaging broker. Other Treats The server kernel team has added support for configuration customization using YAML. YAML-based configuration customization is a nice alternative to using CLI scripts to tailor a stock configuration for a particular environment, as there is no need start a CLI process to apply the customization. This makes it well suited to workflows like deploying WildFly using Ansible. The clustering team has added support for Infinispan query, counters, locks, and CDI. The clustering and web teams have added support for configuration of an arbitrary cookie to use for web request affinity. The RESTEasy team has added support for including request tracing information in HTTP response headers. The messaging-activemq subsystem now supports integrating an SSLContext provided by the elytron subsystem. When you use OIDC, the security team has added support for identity propagation from a WAR to an EJB in an EAR. The web team has added default values for the read-timeout and write-timeout settings for Undertow listeners. We’ve updated Hibernate ORM from the ORM 6.1 release to 6.2.1. Jakarta EE 10 Support WildFly 28 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the new Core Profile. WildFly is EE 10 compatible when running on both Java SE 11 and Java SE 17. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Jakarta EE 10 Full Platform SE 11 SE 17 Jakarta EE 10 Web Profile SE 11 SE 17 Jakarta EE 10 Core Profile SE 11 SE 17 Java SE Support Our recommendation is that you run WildFly on the most recent long-term support Java SE release, i.e. on SE 17 for WildFly 28. While we do do some testing of WildFly on JDK 20, we do considerably more testing of WildFly itself on the LTS JDKs, and we make no attempt to ensure the projects producing the various libraries we integrate are testing their libraries on anything other than JDK 11 or 17. WildFly 28 also is heavily tested and runs well on Java 11. We plan to continue to support Java 11 at least through WildFly 29, and likely beyond. We do, however, anticipate removing support for SE 11 sometime in the next 12 to 18 months. While we recommend using an LTS JDK release, I do believe WildFly runs well on JDK 20. By runs well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. Please note that WildFly runs on Java 11 and later in classpath mode. Known Issues Spring and RESTEasy Spring In WildFly 27, pending the final release of Spring 6, RESTEasy Spring support was removed from standard WildFly, and was only provided with WildFly Preview. With WildFly 28 we have reintroduced RESTEasy Spring support to standard WildFly. However, we’ve learned of a bug in WildFly 28 that will prevent Spring deployments, including those using RESTEasy Spring, from working. Until this is resolved in WildFly 28.0.1, users can work around this issue by adding a jboss-deployment-structure.xml file to their deployment that declares a dependency on the org.jboss.vfs module. Release Notes The full release notes for the release are in the WildFly JIRA. Issues fixed in the underlying WildFly Core 20.0.0 and 20.0.1 releases are listed in the WildFly Core JIRA. Please try it out and give us your feedback, while we get to work on WildFly 29! Best regards, Brian ### [Using The RESTEasy Tracing Feature In WildFly](/news/2023/04/20/Using-The-RESTEasy-Tracing-Feature-In-WildFly/) ### [An Introduction To Server Connector for IntelliJ](/news/2023/04/13/An-Introduction-To-Server-Connector-for-IntelliJ/) Server Connector for IntelliJ, also known as IntelliJ-rsp is a tool for acquiring, locating, installing, starting, stopping, and deloying artifacts to Application Servers like WildFly and EAP. TheThe project’s source code can be found here: GitHub - IntelliJ-rsp / Server Connector for IntelliJ The project had it’s first public-ready release this week, at version 0.7.0. For people who have used JBossTools or the VS Code Server Connector Extensions, the UI and general workflows should be mostly familiar. Installation This long-awaited public release can be installed either by opening the Settings window in IntelliJ (Press Ctrl+Alt+S to open the IDE settings), selecting Plugins, and searching for Server Connector, or by going to the marketplace entry for the project and downloading the selected version for a local installation. Demo Video A short demo can be found at the marketplace entry for the extension or at YouTube directly, and we encourage you all to check it out! What’s an RSP? The Server Connector extension for IntelliJ, much like the Server Connector extension for VS Code, works similar to a Language Server Protocol (or LSP) server. LSP Servers separate all of the logic for handling language-specific features like syntax coloring, code completion, and many other, away from the user’s IDE and into a background process. This background process can be re-used in multiple IDE’s, so long as each IDE has a thin integration layer that would allow the UI to integrate with the background server. Similar to an LSP, this Server Connector extension separates out all the common logic of dealing with, locating, starting, stopping, and deploying to Application Servers like WildFly and EAP into a background process that we call an RSP, or Runtime Server Protocol. With a thin UI layer customized for each IDE, this can extend support for these servers to other IDEs, like IntelliJ. What’s Different? What’s the Same? For users of our VS Code extension, there are some small differences. The IntelliJ extension does not bundle the background RSP, but does provide an action to download the newest release of each. This update menu item will also investigate whether it should be enabled or not, or if there’s been a new release of the underlying RSP, on each restart of the IDE. Despite some other small UI differences, the VS Code tool and the IntelliJ tool look and behave almost identically. Ok, it’s installed. Now what? Once installed, you should notice a RSP Servers view on the left of your workspace. Once selected, you should see two different RSP types. One, Community Server Connector by Red Hat, and the other Red Hat Server Connector. The former exposes support for many community servers like Apache Felix, Karaf, Tomcat, Glassfish, Jetty and Websphere Liberty. The latter provides support for WildFly and EAP. If you right-click on the Red Hat Server Connector, you can execute the Download / Update RSP action item to install the background RSP. The RSP can then be started. Once started, you can right-click on the RSP and see two new action items: Create Server and Download Server. The former will begin a workflow that allows you to create a descriptor for a local server already on your disk, complete with optional and required attributes. The latter will first assist you in downloading and extracting the server before doing the same. With a server defined, you can see the following actions in its context menu: * Delete Server - Delete the selected server adapter (but not its underlying files). Start Server (run) - Start the given server in run mode Start Server (debug) - Start the given server in debug mode and, if possible, connect a remote debugger. Restart Server (run) - Restart the selected server in run mode Restart Server (debug) - Restart the given server in debug mode and, if possible, connect a remote debugger. Stop Server - Request the server stop. Terminate Server - Request the server be terminated if possible. Add Deployment - Add a deployable file or folder to the server to be published. Remove Deployment from Server - Remove a selected deployment from the server. Publish Server (Full) - Publish the server, synchronizing the content of deployments from your workspace to the server. Publish Server (Incremental) - Publish the server with recent changes, synchronizing the content of deployments from your workspace to the server. Edit Server - View a JSON representation of your server in an editor, and submit any changed properties back to the RSP. Server Actions - Some server types may expose to the user arbitrary actions that the user may invoke, such as changing some configuration options, opening a web browser, or editing a configuration file. These server-contributed actions have few restrictions placed on them by the framework other than what may be done on the client-side. Modifying the Server Descriptor To get a look at what data the RSP is keeping to interact with your server, you can right-click the server object and select Edit Server. Here you’ll be able to see the JSON descriptor that is stored, and make any changes to properties that you might want to tweak. You can see more details about what properties are available for addition or modification over at the project’s documentation page. Many of these properties relate to modifying the program arguments or vm arguments when launching the runtime, or ensuring a certain environment is passed through to the server when it starts. Conclusion Going through each of these features one-by-one would be a bit overkill for a blog post. However, if you’re a user of WildFly and EAP, and have been using Red Hat’s existing tools for interacting with these Application Servers in Eclipse or VS Code, but wished you could do so more effectively while using IntelliJ, we encourage you to watch the Demo listed above, try out the tools, and chat with us on Gitter about what you like and what you don’t like. [1] IntelliJ Marketplace page: https://plugins.jetbrains.com/plugin/16072-server-connector-by-red-hat [2] Source / Github: https://github.com/redhat-developer/intellij-rsp/ [3] Gitter: https://gitter.im/redhat-developer/server-connector ### [An Introduction To The Prospero Usage](/news/2023/04/05/An-Introduction-To-The-Prospero-Usage/) Prospero is a tool provided by the WildFly community: GitHub - wildfly-extras/prospero: Prospero is a tool combining Galleon feature-packs and wildfly-channels to provision and update Wildfly server. The purpose of the project can be quoted from the README of the above project link: Prospero is a tool combining Galleon feature-packs and wildfly-channels to provision and update Wildfly server. Briefly speaking, you can use the tool to do the version management of your WildFly installation. Note The wildfly-channels projects defines the Channel, which allow separation of artifact versioning from the Galleon feature-pack, allowing artifact versions to be managed independently. In the project, it contains a spec doc that describes the Channel model: wildfly-channel/spec.adoc at main · wildfly-extras/wildfly-channel · GitHub In the next section, let’s see the basic usage of prospero-cli. Basic Usage Of The Prospero CLI Tool To use the tool, firstly you can clone the project to your local environment: $ git clone https://github.com/wildfly-extras/prospero.git Then you can enter the project directory, and build the project as mentioned in the project README: $ mvn clean install After the project is built, then we can use the built tool to install a provisioned WildFly locally. The tool uses the wildfly-channel config files(which are called Wildfly Channels and Wildfly Channel Manifests) to manage the components versions. And the project provides some example configuration files already in its examples directory: ➤ ls examples README.md wildfly-27.0.0.Alpha2-manifest.yaml wildfly-26.0.0.Final-channel.yaml wildfly-core-channel.yaml wildfly-26.0.0.Final-manifest.yaml wildfly-core-manifest.yaml wildfly-27.0.0.Alpha2-channel.yaml To use one of the above manifest files, here is an example command: $ ./prospero install --fpl=org.wildfly:wildfly-galleon-pack --dir=wfly-26 --channel=examples/wildfly-26.0.0.Final-channel.yaml The above command will use the channel defined in the wildfly-26.0.0.Final-channel.yaml to provision the components versions listed in wildfly-26.0.0.Final-channel.yaml and install a WildFly into the wfly-26 directory. In addition, the -fpl option defines the Galleon Feature-Pack to use. Note The channel files contain repositories and reference to the manifest, while manifest only contains the versions of artifacts. Here is the running process of the above command: $ ./prospero install --fpl=org.wildfly:wildfly-galleon-pack --dir=wfly-26 --channel=examples/wildfly-26.0.0.Final-channel.yaml Installing feature-pack: org.wildfly:wildfly-galleon-pack Using channels: # manifest: file:examples/wildfly-26.0.0.Final-manifest.yaml repositories: id: central url: https://repo1.maven.org/maven2/ id: jboss-public url: https://repository.jboss.org/nexus/content/groups/public/ id: mrrc url: https://maven.repository.redhat.com/ga/ Feature-packs resolved. Packages installed. Downloaded artifacts. JBoss modules installed. Configurations generated. Server created in /Users/weli/works/prospero/wfly-26 Operation completed in 29.46 seconds. After the above process, a provisioned WildFly is installed at the wfly-26 directory: ➤ ls wfly-26/ LICENSE.txt bin domain standalone README.txt copyright.txt jboss-modules.jar welcome-content appclient docs modules The above installation is provisioned by the prospero tool. Next we can check the content of the channel metadata files. WildFly Channel Metadata Here is the content of the examples/wildfly-26.0.0.Final-channel.yaml file: schemaVersion: "2.0.0" repositories: - id: "central" url: "https://repo1.maven.org/maven2/" - id: "jboss-public" url: "https://repository.jboss.org/nexus/content/groups/public/" - id: "mrrc" url: "https://maven.repository.redhat.com/ga/" manifest: url: "file:examples/wildfly-26.0.0.Final-manifest.yaml" The above channel file defines the repositories to be used for downloading components. In addition, it includes a manifest file: manifest: url: "file:examples/wildfly-26.0.0.Final-manifest.yaml" Here is part of the contents of examples/wildfly-26.0.0.Final-manifest.yaml: ➤ head -n 20 examples/wildfly-26.0.0.Final-manifest.yaml --- schemaVersion: "1.0.0" name: "Manifest for org.wildfly:wildfly-ee-galleon-pack:pom:26.0.0.Final feature-pack." id: "org.wildfly:wildfly-ee-galleon-pack" description: "Generated by org.wildfly.galleon-plugins:wildfly-galleon-maven-plugin\ \ at 2023-03-21T13:03:11.512702Z" streams: - groupId: "antlr" artifactId: "antlr" version: "2.7.7" - groupId: "com.fasterxml" artifactId: "classmate" version: "1.5.1" - groupId: "com.fasterxml.jackson.core" artifactId: "jackson-annotations" version: "2.12.3" - groupId: "com.fasterxml.jackson.core" artifactId: "jackson-core" version: "2.12.3" - groupId: "com.fasterxml.jackson.core" As the command output shown above, the above manifest file defines the component versions. Combining the repositories and the component versions, the prospero tool knows how to provision a WildFly server, and the component versions in the WildFly installation is managed by the tool. Next we’ll see how to use the prospero to update or rollback the provisioned WildFly distribution. Other Usages Of The Tool The prospero tool itself contains help to its usage: ➤ ./prospero Welcome to prospero CLI! This tool enables you to provision and manage instances of the Wildfly application server. Usage: prospero [-hv] [COMMAND] Options: -h, --help Displays the help information for the command. -v, --version Prints the version of prospero and exits. Commands: install Installs a new instance of the application server. update Updates a server instance with the latest patches. print-licenses Prints licenses and additional agreements required to install the server. history Lists all the previous installation states. revert Reverts the server to a previous installation state. channel Manages the channels used by the server to get the latest updates. completion Generates a bash completion script. To enable auto-completion use the command `source <(prospero completion)`. clone Exports installation details required to recreate a server. Exit codes: 0 Successful program execution. 1 Failed operation. 2 Invalid input arguments. Use `prospero <COMMAND> --help` to show help information for the command. In the above command output, it has a list of the commands supported. Firstly we can try to use its update command. We can update one of the component versions defined in the manifest file examples/wildfly-26.0.0.Final-manifest.yaml: - groupId: "io.undertow" artifactId: "undertow-core" version: "2.2.14.Final" We can update the above undertow-core version from 2.2.14.Final to 2.2.18.Final, and then run the following command to update the provisioned server: ./prospero update perform --dir=wfly-26 And here is the running process of the above command: ➤ ./prospero update perform --dir=wfly-26 Updates found: io.undertow:undertow-servlet 2.2.14.Final ==> 2.2.18.Final Continue with update [y/N]: y Applying updates Feature-packs resolved. Packages installed. Downloaded artifacts. JBoss modules installed. Configurations generated. Build update complete! Update complete! Operation completed in 39.00 seconds. From the above running process, we can see the undertow-servlet component inside the WildFly installation is updated, and prospero will help us to manage this version change. Note Updating a component by manually editing the manifest is under user responsibility if the changes of this manifest don’t come from an "official" manifest. For example, one manifest generated from a more recent version, you could break your server installation. We can use the history command to see the change history of the provisioned server: ➤ ./prospero history --dir=wfly-26 [fc78b239] 2023-03-23T16:48:24Z - update [file:examples/wildfly-26.0.0.Final-manifest.yaml::27d5125a2220e0885b13f7f0b740bfb3bd06aac6] [84b35ad5] 2023-03-23T16:43:37Z - install [file:examples/wildfly-26.0.0.Final-manifest.yaml::aa9100d88292532da7fa8936611765c71a63af36] From the above command output, we can see the initial installation and the update are all managed in the history. Now we can try to rollback the update with the following command: ➤ ./prospero revert perform --dir=wfly-26 --revision=84b35ad5 With above command, we revert our WildFly server back to the revision 84b35ad5, which is the initial installation of the server. Here is the command output: Feature-packs resolved. Packages installed. Downloaded artifacts. JBoss modules installed. Configurations generated. Updates found: [*]io.undertow:undertow-servlet 2.2.18.Final ==> 2.2.14.Final [*] The update list contain one or more artifacts with lower versions then currently installed. Proceed with caution. Continue with update [y/N]: y Operation completed in 27.16 seconds. From the above command output we can see the prospero asked us if we want to downgrade the component versions. Because we revert our WildFly server back to the initial installation, so just write y and proceed the process, and the WildFly server is reverted back to the initial installation. Now we can check the provision history of the server again: ➤ ./prospero history --dir=wfly-26 [310f6f37] 2023-03-23T16:50:03Z - rollback [file:examples/wildfly-26.0.0.Final-manifest.yaml::aa9100d88292532da7fa8936611765c71a63af36] [fc78b239] 2023-03-23T16:48:24Z - update [file:examples/wildfly-26.0.0.Final-manifest.yaml::27d5125a2220e0885b13f7f0b740bfb3bd06aac6] [84b35ad5] 2023-03-23T16:43:37Z - install [file:examples/wildfly-26.0.0.Final-manifest.yaml::aa9100d88292532da7fa8936611765c71a63af36] We can see there is a new rollback revision added instead of just reverting to the original revision. This design helps us to preserve all the change histories. To see the changes in the revision, we can use this command to do so: ➤ ./prospero history --dir=wfly-26 --revision=310f6f37 And here is the output of the command: ➤ ./prospero history --dir=wfly-26 --revision=310f6f37 Updates: [Updated artifact] io.undertow:undertow-servlet: 2.2.18.Final ==> 2.2.14.Final From the above command output, we can see the changed components versions in the update. The Usage Of The -profile Option In this article we have used the -fpl option to do the installation o the WildFly, and there is another -profile option that can be used for provision. The -profile option is actually a combination of Galleon Feature-Pack and WildFly Channel, and it is defined by the YAML file too. The default wildfly profile is defined here: prospero-known-combinations.yaml The content of the above file is shown in below: --- - name: "wildfly" galleonConfiguration: "classpath:wildfly-provisioning.xml" channels: - schemaVersion: "2.0.0" name: "wildfly" repositories: - id: "central" url: "https://repo1.maven.org/maven2/" - id: "jboss-public" url: "https://repository.jboss.org/nexus/content/groups/public/" - id: "mrrc" url: "https://maven.repository.redhat.com/ga/" manifest: null As the content shown above, the profile file defines the channel similar to a channel file. In addition, it contains a galleonConfiguration item that defines a Galleon config file location, which is wildfly-provisioning.xml. Here is the content of the wildfly-provisioning.xml: <?xml version="1.0" ?> ... <installation xmlns="urn:jboss:galleon:provisioning:3.0"> <feature-pack location="org.wildfly:wildfly-galleon-pack::zip"/> </installation> As the content shown above, it’s a Galleon config file contains a feature-pack location. In conclusion, the wildfly profile combines the channel definition and the feature-pack definition. So we can use this profile file directly with the manifest file. Here is the command to do so: $ ./prospero install --profile=wildfly --dir=wfly-26 --manifest=examples/wildfly-26.0.0.Final-manifest.yaml As the command shown above, we have used the -profile option instead of the -fpl option, so we don’t need the channel file anymore. Here is the output of the above command: $ ./prospero install --profile=wildfly --dir=wfly-26 --manifest=examples/wildfly-26.0.0.Final-manifest.yaml Installing profile: wildfly Using channels: # manifest: file:/Users/weli/works/prospero/examples/wildfly-26.0.0.Final-manifest.yaml repositories: id: central url: https://repo1.maven.org/maven2/ id: jboss-public url: https://repository.jboss.org/nexus/content/groups/public/ id: mrrc url: https://maven.repository.redhat.com/ga/ Feature-packs resolved. Packages installed. Downloaded artifacts. JBoss modules installed. Configurations generated. Server created in /Users/weli/works/prospero/wfly-26 Operation completed in 16.44 seconds. From the above command output, we can see the channels definition are loaded from the profile directly, and we used the --manifest option to define the manifest file directly, and we don’t need to use the --channnel option to define the channel by ourselves. Conclusion In this article, I introduced the basic usages of the Prospero, and if you want to know more of the project, please check the source code of the project, and also the links provided in the references. References The Prospero uses the WildFly Channel Manifests defined in the wildfly-channel project as its configuration backend: GitHub - wildfly-extras/wildfly-channel: Library for WildFly Channel The Prospero uses the Galleon project to do the provision actions of the WildFly distribution: GitHub - wildfly/galleon If you want to understand how to generate the manifest file for the WildFly releases, here are the discussions on the topic: Add wildfly-ee-galleon-pack streams #1 blog post: An Introduction To The Prospero Usage by liweinan · Pull Request #401 · wildfly/wildfly.org · GitHub / Another discussion ### [WildFly 28 Beta1 is released!](/news/2023/03/30/WildFly-28-Beta1-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 28.0.0.Beta1 releases are available for download at https://wildfly.org/downloads. New and Notable Observability The biggest changes in WildFly 28 Beta1 relate to the observability space. The micrometer subsystem has been added to standard WildFly, bringing Micrometer support. As part of this work, we’ve added support for Micrometer integration with our MicroProfile Fault Tolerance implementation. The micrometer subsystem was first introduced in WildFly Preview in WildFly 27. Note that the subsystem has been updated from what was in WildFly Preview 27 to switch to pushing metric data via OTLP to a remote collector, instead of supporting polling of data on the WildFly server’s management interface. (Server and JVM metrics can still be pulled from the management endpoint if the base metrics subsystem is configured.) We’ve also added support for MicroProfile Telemetry via a new microprofile-telemetry-smallrye subsystem. We’ve removed support for MicroProfile Metrics, except for a stub system limited to 'admin-only' mode that’s been kept to facilitate configuration migration. MicroProfile Metrics users are encouraged to use the new micrometer subsystem. We’ve removed support for MicroProfile OpenTracing, except for a stub system limited to 'admin-only' mode that’s been kept to facilitate configuration migration. MicroProfile OpenTracing users are encouraged to use the new microprofile-telemetry-smallrye subsystem, or the opentelemetry subsystem upon which it is based. MicroProfile Besides the changes in the observability space noted above, there are a couple of important changes in WildFly 28’s MicroProfile support: We’ve added support for MicroProfile LRA via new microprofile-lra-coordinator and microprofile-lra-participant subsystems. Except for MicroProfile Metrics and OpenTracing, which have been removed, we’ve updated our support for the other MicroProfile Platform specifications to the MicroProfile Platform 6 versions. Provisioning We’ve added a new ee-core-profile-server Galleon layer to make it easy to provision a server based on the new Jakarta EE Core Profile introduced in EE 10. Related to this we’ve introduced new ee-concurrency and ee-integration and servlet Galleon layers. These layers allow a more tailored configuration compared to the existing ee and web-server layers. Other Treats The server kernel team has added support for configuration customization using YAML. To learn more, see the article Emmanuel Hugonnet wrote last year about a preview version of this feature. (This feature is now available by default; there is no longer any need to perform the activation step described in the article.) YAML-based configuration customization is a nice alternative to using CLI scripts to tailor a stock configuration for a particular environment, as there is no need start a CLI process to apply the customization. This makes it well suited to workflows like deploying WildFly using Ansible. The clustering team has added support for Infinispan query, counters, locks, and CDI. The clustering and web teams have added support for configuration of an arbitrary cookie to use for web request affinity. The RESTEasy team has added support for including request tracing information in HTTP response headers. The messaging-activemq subsystem now supports integrating an SSLContext provided by the elytron subsystem. When you use OIDC, the security team has added support for identity propagation from a WAR to an EJB in an EAR. The web team has added default values for the read-timeout and write-timeout settings for Undertow listeners. We’ve updated Hibernate ORM from the ORM 6.1 release to 6.2.0.CR4. Release Notes The full release notes for the release are in the WildFly JIRA. Issues fixed in the numerous underlying WildFly Core 20.0 beta releases are listed in the WildFly Core JIRA. Please try it out and give us your feedback, while we get to work on WildFly 28 Final! Our goal is for that to be available in mid April. Best regards, Brian ### [WildFly Maven Plugin](/news/2023/03/09/WildFly-Maven-Plugin/) The wildfly-maven-plugin has introduced a new dev goal. If you are familiar with the run goal, this goal is very similar. However, it watches for changes to source files. If changes are found, the WAR is rebuilt and redeployed. This new goal is available in version 4.1.0.Beta3 of the wildfly-maven-plugin. Using the dev Goal In its simplest form you enable the plugin like any other maven plugin: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly-maven-plugin}</version> </plugin> Once added to your POM you can simply execute mvn wildfly:dev on your project, and you should be up and running. With no configuration, a full server is provisioned in your projects build directory, e.g. target. Changes to source files are monitored. If required, the compile:compile goal will be invoked. If a resource needs to be copied, the resources:resources goal will be invoked. In some cases the deployment might also need to be redeployed. You can also configure the goal to provision a custom version of WildFly. Below is an example of configuring a cloud server with the cloud-server layer with an H2 database. <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly-maven-plugin}</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.server}</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:${version.cloud.fp}</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>h2-driver</layer> </layers> </configuration> </plugin> Full documentation for the goal can be found in the wildfly-maven-plugin documentation. Limitations There are currently a couple of limitations on this goal. The first is this goal will only work with WAR deployments. The other is changes to the POM file are not watched. If you change the POM you need to kill, CTRL+C, the job and restart the process. Conclusion Hopefully this goal is useful for more rapid development. If you’d like to see new features or have questions on how this new goal works, open a discussion on GitHub or in the forum. If you find a bug, feel free to report it in JIRA. ### [Using MicroProfile OpenAPI with RESTEasy](/news/2023/02/23/Using-MicroProfile-OpenAPI-with-RESTEasy/) ### [WildFly 26.1.3 is released](/news/2023/01/18/WildFly-26-1-3-is-released/) WildFly 26.1.3.Final is now available for download. We’ve received requests from members of our community to address a recent critical severity CVE in Apache CXF. The WildFly project generally doesn’t continue to produce bug-fix releases for older versions once a new major or minor release is out. But we recognize that the transition to WildFly 27 and EE 10 is likely to take our users longer than it does for most releases, so given the severity of CVE-2022-46364 we decided to do an additional limited payload bug fix release for the 26.1 series. The following issues were resolved in 26.1.3: Component Upgrades WFLY-17384 - Upgrade Jackson Databind 2.12.7.1 (addresses CVE-2022-42003 and CVE-2022-42004) WFLY-17474 - Upgrade CXF from 3.4.7 to 3.4.10 (addresses CVE-2022-46364) WFLY-17494 - Upgrade jaxb-ri to 2.3.3-b02-jbossorg-2 Tasks WFLY-17489 - Default to https://www.w3.org instead of http://www.w3.org to resolve XML Binding TCK failures Thank you for your support of WildFly. ### [Deploying a WildFly 27.0.1 cluster using Ansible](/news/2023/01/10/Deploying-a-WildFly-27-0-1-cluster-using-Ansible/) In this brief demonstration, we’ll set up and run three instances of WildFly on the same machine (localhost). Together they will form a cluster. It’s a rather classic setup, where the appservers needs to synchronize the content of their application’s session to ensure fail over if one of the instances fails. This configuration guarantees that, if one instance fails while processing a request, another one can pick up the work without any data loss. Note that we’ll use a multicast to discover the members of the cluster and ensure that the cluster’s formation is fully automated and dynamic. Install Ansible and its collection for WildFly On a Linux system using a package manager, installing Ansible is pretty straightforward: $ sudo dnf install ansible-core Please refer to the documentation available online for installation on other operating system. Note that this demonstration assumes you are running both the Ansible controller and the target (same machine in our case) on a Linux system. However, it should work on any other operating system with a few adjustements. Before going further, double check that you are running a recent enough version of Ansible (2.12 or above will do, but 2.9 is the bare minimum): $ ansible --version ansible [core 2.14.1] config file = /etc/ansible/ansible.cfg configured module search path = ['/home/rpelisse/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3.11/site-packages/ansible ansible collection location = /home/rpelisse/.ansible/collections:/usr/share/ansible/collections executable location = /usr/bin/ansible python version = 3.11.0 (main, Oct 24 2022, 00:00:00) [GCC 12.2.1 20220819 (Red Hat 12.2.1-2)] (/usr/bin/python3) jinja version = 3.0.3 libyaml = True The next, and last, step to ready your Ansible environment is to install the Ansible collection for WildFly on the controller (the machine that will run Ansible): $ ansible-galaxy collection install middleware_automation.wildfly Starting galaxy collection install process Process install dependency map Starting collection install process Downloading https://galaxy.ansible.com/download/middleware_automation-wildfly-1.2.2.tar.gz to /root/.ansible/tmp/ansible-local-25jj_dxqei/tmpvb6d55ho/middleware_automation-wildfly-1.2.2-33znbzkb Downloading https://galaxy.ansible.com/download/middleware_automation-redhat_csp_download-1.2.2.tar.gz to /root/.ansible/tmp/ansible-local-25jj_dxqei/tmpvb6d55ho/middleware_automation-redhat_csp_download-1.2.2-3apb_j2g Installing 'middleware_automation.wildfly:1.2.2' to '/root/.ansible/collections/ansible_collections/middleware_automation/wildfly' middleware_automation.wildfly:1.2.2 was installed successfully Downloading https://galaxy.ansible.com/download/community-general-6.1.0.tar.gz to /root/.ansible/tmp/ansible-local-25jj_dxqei/tmpvb6d55ho/community-general-6.1.0-rr64e3dg Installing 'middleware_automation.redhat_csp_download:1.2.2' to '/root/.ansible/collections/ansible_collections/middleware_automation/redhat_csp_download' middleware_automation.redhat_csp_download:1.2.2 was installed successfully Installing 'community.general:6.1.0' to '/root/.ansible/collections/ansible_collections/community/general' community.general:6.1.0 was installed successfully Set up the WildFly cluster For simplicity’s sake and to allow you to reproduce this demonstration on a single machine (physical or virtual) or even a container, we opted to deploy our three instances on one target. We chose localhost as a target, so that the demonstration can even be performed without a remote host. There are essentially two steps to set up the WildFly cluster: Install WildFly on the targeted hosts (here just localhost). This means downloading the archive from this website and decompressing the archive in the appropriate directory (JBOSS_HOME). These tasks are handled by the wildfly_install role supplied by Ansible collection for WildFly. Create the configuration files to run several instances of WildFly. Because we’re running multiple instances on a single host, you also need to ensure that each instance has its own subdirectories and set of ports, so that the instances can coexist and communicate. Fortunately, this functionality is provided by a role within the Ansible collection called wildfly_systemd. Ansible playbook to install WildFly Here is the playbook we’ll use to deploy our clusters. Its content is relatively self-explanitory, at least if you are somewhat familiar with the Ansible syntax. - name: "WildFly installation and configuration" hosts: "{{ hosts_group_name | default('localhost') }}" become: yes vars: wildfly_install_workdir: '/opt/' wildfly_config_base: standalone-ha.xml wildfly_version: 27.0.1.Final wildfly_java_package_name: java-11-openjdk-headless.x86_64 wildfly_home: "/opt/wildfly-{{ wildfly_version }}" instance_http_ports: - 8080 - 8180 - 8280 app: name: 'info-1.2.war' url: 'https://drive.google.com/uc?export=download&id=13K7RCqccgH4zAU1RfOjYMehNaHB0A3Iq' collections: - middleware_automation.wildfly roles: - role: wildfly_install tasks: - name: "Set up for WildFly instance {{ item }}." ansible.builtin.include_role: name: wildfly_systemd vars: wildfly_config_base: 'standalone-ha.xml' wildfly_instance_id: "{{ item }}" instance_name: "wildfly-{{ wildfly_instance_id }}" wildfly_config_name: "{{ instance_name }}.xml" wildfly_basedir_prefix: "/opt/{{ instance_name }}" service_systemd_env_file: "/etc/wildfly-{{ item }}.conf" service_systemd_conf_file: "/usr/lib/systemd/system/wildfly-{{ item }}.service" loop: "{{ range(0,3) | list }}" - name: "Wait for each instance HTTP ports to become available." ansible.builtin.wait_for: port: "{{ item }}" loop: "{{ instance_http_ports }}" - name: "Checks that WildFly server is running and accessible." ansible.builtin.get_url: url: "http://localhost:{{ port }}/" dest: "/opt/{{ port }}" loop: "{{ instance_http_ports }}" loop_control: loop_var: port In short, this playbook uses the Ansible collection for WildFly to, first, install the appserver by using the wildfly_install role. This will download all the artifacts, create the required system groups and users, install dependency (unzip) and so on. At the end of its execution, all the tidbits required to run WildFly on the target host are installed, but the server is not yet running. That’s what happening in the next step. In the tasks section of the playbook, we then call on another role provided by the collection: wildfly_systemd. This role will take care of integrating WildFly, as a regular system service, into the service manager. Here, we use a loop to ensure that we create not one, but three different services. Each one will have the same configuration (standalone-ha.xml) but runs on different ports, using a different set of directories to store its data. Run the playbook! Now, let’s run our Ansible playbook and observe its output: $ ansible-playbook -i inventory playbook.yml PLAY [Converge] **************************************************************** TASK [Gathering Facts] ********************************************************* ok: [localhost] TASK [wildfly_install : Validating arguments against arg spec 'main'] ********** ok: [localhost] TASK [wildfly_install : Ensures prerequirements are fullfilled.] *************** included: /work/roles/wildfly_install/tasks/prereqs.yml for localhost TASK [wildfly_install : Check that required packages list has been provided.] *** ok: [localhost] TASK [wildfly_install : Prepare packages list] ********************************* skipping: [localhost] TASK [wildfly_install : Add JDK package java-11-openjdk-headless to packages list] *** ok: [localhost] TASK [wildfly_install : Install required packages (4)] ************************* changed: [localhost] TASK [wildfly_install : Ensures required local user exists.] ******************* included: /work/roles/wildfly_install/tasks/user.yml for localhost TASK [wildfly_install : Check arguments] *************************************** ok: [localhost] TASK [wildfly_install : Set wildfly group] ************************************* ok: [localhost] TASK [wildfly_install : Ensure group wildfly exists.] ************************** changed: [localhost] TASK [wildfly_install : Ensure user wildfly exists.] *************************** changed: [localhost] TASK [wildfly_install : Ensure workdir /opt/wildfly/ exists.] ****************** changed: [localhost] TASK [wildfly_install : Ensure archive_dir /opt/wildfly/ exists.] ************** ok: [localhost] TASK [wildfly_install : Ensure server is installed] **************************** included: /work/roles/wildfly_install/tasks/install.yml for localhost TASK [wildfly_install : Check arguments] *************************************** ok: [localhost] TASK [wildfly_install : Check local download archive path] ********************* ok: [localhost] TASK [wildfly_install : Set download paths] ************************************ ok: [localhost] TASK [wildfly_install : Check target archive: /opt/wildfly//wildfly-27.0.0.Final.zip] *** ok: [localhost] TASK [wildfly_install : Retrieve archive from website: https://github.com/wildfly/wildfly/releases/download] *** included: /work/roles/wildfly_install/tasks/install/web.yml for localhost TASK [wildfly_install : Check arguments] *************************************** ok: [localhost] TASK [wildfly_install : Download zipfile from https://github.com/wildfly/wildfly/releases/download/27.0.0.Final/wildfly-27.0.0.Final.zip into /work/wildfly-27.0.0.Final.zip] *** ok: [localhost] TASK [wildfly_install : Retrieve archive from RHN] ***************************** skipping: [localhost] TASK [wildfly_install : Install server using RPM] ****************************** skipping: [localhost] TASK [wildfly_install : Check downloaded archive] ****************************** ok: [localhost] TASK [wildfly_install : Copy archive to target nodes] ************************** changed: [localhost] TASK [wildfly_install : Check target archive: /opt/wildfly//wildfly-27.0.0.Final.zip] *** ok: [localhost] TASK [wildfly_install : Read target directory information: /opt/wildfly/wildfly-27.0.0.Final/] *** ok: [localhost] TASK [wildfly_install : Check target directory state: /opt/wildfly/wildfly-27.0.0.Final/] *** ok: [localhost] TASK [wildfly_install : Extract files from /opt/wildfly//wildfly-27.0.0.Final.zip into /opt/wildfly/.] *** changed: [localhost] TASK [wildfly_install : Note: decompression was not executed] ****************** skipping: [localhost] TASK [wildfly_install : Read information on server home directory: /opt/wildfly/wildfly-27.0.0.Final/] *** ok: [localhost] TASK [wildfly_install : Check state of server home directory: /opt/wildfly/wildfly-27.0.0.Final/] *** ok: [localhost] TASK [wildfly_install : Set instance name] ************************************* ok: [localhost] TASK [wildfly_install : Deploy configuration] ********************************** changed: [localhost] TASK [wildfly_install : Ensure required parameters for cumulative patch application are provided.] *** skipping: [localhost] TASK [Apply latest cumulative patch] ******************************************* skipping: [localhost] TASK [wildfly_install : Ensure required parameters for elytron adapter are provided.] *** skipping: [localhost] TASK [Install elytron adapter] ************************************************* skipping: [localhost] TASK [wildfly_install : Check wildfly install directory state] ***************** ok: [localhost] TASK [wildfly_install : Validate conditions] *********************************** ok: [localhost] TASK [wildfly_systemd : Validating arguments against arg spec 'main'] ********** ok: [localhost] TASK [wildfly_systemd : Check arguments] *************************************** ok: [localhost] TASK [wildfly_systemd : Check current EAP patch installed] ********************* skipping: [localhost] TASK [wildfly_systemd : Check arguments for yaml configuration] **************** skipping: [localhost] TASK [Ensure required local user and group exists.] **************************** TASK [wildfly_install : Check arguments] *************************************** ok: [localhost] TASK [wildfly_install : Set wildfly group] ************************************* ok: [localhost] TASK [wildfly_install : Ensure group wildfly exists.] ************************** ok: [localhost] TASK [wildfly_install : Ensure user wildfly exists.] *************************** ok: [localhost] TASK [wildfly_systemd : Set destination directory for configuration] *********** ok: [localhost] TASK [wildfly_systemd : Set instance destination directory for configuration] *** ok: [localhost] TASK [wildfly_systemd : Check arguments] *************************************** skipping: [localhost] TASK [wildfly_systemd : Set base directory for instance] *********************** skipping: [localhost] TASK [wildfly_systemd : Check arguments] *************************************** skipping: [localhost] TASK [wildfly_systemd : Set instance name] ************************************* skipping: [localhost] TASK [wildfly_systemd : Set instance name] ************************************* skipping: [localhost] TASK [wildfly_systemd : Set bind address] ************************************** ok: [localhost] TASK [wildfly_systemd : Create basedir /opt/wildfly/wildfly-27.0.0.Final//standalone for instance: wildfly] *** ok: [localhost] TASK [wildfly_systemd : Create deployment directories for instance: wildfly] *** ok: [localhost] TASK [wildfly_systemd : Deploy configuration] ********************************** ok: [localhost] TASK [wildfly_systemd : Include YAML configuration extension] ****************** skipping: [localhost] TASK [wildfly_systemd : Check YAML configuration is disabled] ****************** ok: [localhost] TASK [wildfly_systemd : Set systemd envfile destination] *********************** ok: [localhost] TASK [wildfly_systemd : Determine JAVA_HOME for selected JVM RPM] ************** ok: [localhost] TASK [wildfly_systemd : Set systemd unit file destination] ********************* ok: [localhost] TASK [wildfly_systemd : Deploy service instance configuration: /etc//wildfly.conf] *** changed: [localhost] TASK [wildfly_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/wildfly.service] *** changed: [localhost] TASK [wildfly_systemd : Perform daemon-reload to ensure the changes are picked up] *** ok: [localhost] TASK [wildfly_systemd : Ensure service is started] ***************************** included: /work/roles/wildfly_systemd/tasks/service.yml for localhost TASK [wildfly_systemd : Check arguments] *************************************** ok: [localhost] TASK [wildfly_systemd : Set instance wildfly state to started] ***************** changed: [localhost] TASK [wildfly_driver : Validating arguments against arg spec 'main'] *********** ok: [localhost] TASK [wildfly_driver : Check arguments] **************************************** ok: [localhost] TASK [wildfly_driver : Check module directory: /opt/wildfly/wildfly-27.0.0.Final//modules/org/postgresql/main] *** ok: [localhost] TASK [wildfly_driver : Set up module dir for JDBC Driver: /opt/wildfly/wildfly-27.0.0.Final//modules/org/postgresql/main] *** changed: [localhost] TASK [wildfly_driver : Retrieve JDBC Driver from https://repo.maven.apache.org/maven2/org/postgresql/postgresql/9.4.1212/postgresql-9.4.1212.jar] *** changed: [localhost] TASK [wildfly_driver : Set source template path] ******************************* ok: [localhost] TASK [wildfly_driver : Deploy module.xml for JDBC Driver] ********************** changed: [localhost] TASK [wildfly_utils : Validating arguments against arg spec 'main'] ************ ok: [localhost] TASK [Install second driver with wildfly_driver role] ************************** TASK [wildfly_driver : Validating arguments against arg spec 'main'] *********** ok: [localhost] TASK [wildfly_driver : Check arguments] **************************************** ok: [localhost] TASK [wildfly_driver : Check module directory: /opt/wildfly/wildfly-27.0.0.Final//modules/org/mariadb/main] *** ok: [localhost] TASK [wildfly_driver : Set up module dir for JDBC Driver: /opt/wildfly/wildfly-27.0.0.Final//modules/org/mariadb/main] *** changed: [localhost] TASK [wildfly_driver : Retrieve JDBC Driver from https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/2.7.4/mariadb-java-client-2.7.4.jar] *** changed: [localhost] TASK [wildfly_driver : Set source template path] ******************************* ok: [localhost] TASK [wildfly_driver : Deploy module.xml for JDBC Driver] ********************** changed: [localhost] PLAY RECAP ********************************************************************* localhost : ok=70 changed=16 unreachable=0 failed=0 skipped=16 rescued=0 ignored=0 Note that the playbook is not that long, but it does a lot for us. It performs almost 100 different tasks! Starting by automatically installing the dependencies, including the JVM required by WildFly, along with downloading its binaries. And the wildfly_systemd role does even more, effortlessly setting up three distinct services, each with its own set of ports and directory layout to store instance-specific data. Even better, the WildFly installation is NOT duplicated. All of the binaries live under the /opt/wildfly-27.0.1 directory, but all the data files of each instance are stored in separate folders. This means that we just need to update the binaries, once, and then restart the instances, to deploy a patch or upgrade to a new version of WildFly. On top of everything, we configured the instances to use the standalone-ha.xml configuration as the baseline, so they are already set up for clustering. Check that everything worked as expected The easiest way to confirm that the playbook did indeed install WildFly and started three instances of the appserver is to use the systemctl command to check the associate services state: ● wildfly.service - JBoss EAP (standalone mode) Loaded: loaded (/usr/lib/systemd/system/wildfly.service; enabled; vendor preset: disabled) Active: active (running) since Tue 2023-01-10 09:24:21 UTC; 6h ago Main PID: 857 (standalone.sh) CGroup: /system.slice/wildfly.service ├─ 857 /bin/sh /opt/wildfly/wildfly-27.0.0.Final/bin/standalone.sh -c wildfly.xml -b 0.0.0.0 -bmanagement 127.0.0.1 -Djboss.bind.address.private=127.0.0.1 -Djboss.default.multicast.address=230.0.0.4 -Djboss.server.config.dir=/opt/wildfly/wildfly-27.0.0.Final//standalone/configuration/ -Djboss.server.base.dir=/opt/wildfly/wildfly-27.0.0.Final//standalone -Djboss.tx.node.id=wildfly -Djboss.node.name=wildfly -Dwildfly.statistics-enabled=false └─1001 /usr/lib/jvm/java-11-openjdk-11.0.17.0.8-2.el8_6.x86_64/bin/java -D[Standalone] -server -Xmx1024M -Xms512M --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldaps=ALL-UNNAMED --add-exports=jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED -Dorg.jboss.boot.log.file=/opt/wildfly/wildfly-27.0.0.Final/standalone/log/server.log -Dlogging.configuration=file:/opt/wildfly/wildfly-27.0.0.Final/standalone/configuration/logging.properties -jar /opt/wildfly/wildfly-27.0.0.Final/jboss-modules.jar -mp /opt/wildfly/wildfly-27.0.0.Final/modules org.jboss.as.standalone -Djboss.home.dir=/opt/wildfly/wildfly-27.0.0.Final -Djboss.server.base.dir=/opt/wildfly/wildfly-27.0.0.Final/standalone -c wildfly.xml -b 0.0.0.0 -bmanagement 127.0.0.1 -Djboss.bind.address.private=127.0.0.1 -Djboss.default.multicast.address=230.0.0.4 -Djboss.server.config.dir=/opt/wildfly/wildfly-27.0.0.Final//standalone/configuration/ -Djboss.server.base.dir=/opt/wildfly/wildfly-27.0.0.Final//standalone -Djboss.tx.node.id=wildfly -Djboss.node.name=wildfly -Dwildfly.statistics-enabled=false Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,504 INFO [org.wildfly.extension.undertow] (MSC service thread 1-6) WFLYUT0006: Undertow HTTPS listener https listening on [0:0:0:0:0:0:0:0]:8443 Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,549 INFO [org.jboss.as.ejb3] (MSC service thread 1-7) WFLYEJB0493: Jakarta Enterprise Beans subsystem suspension complete Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,623 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-8) WFLYJCA0001: Bound data source [java:jboss/datasources/ExampleDS] Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,691 INFO [org.jboss.as.patching] (MSC service thread 1-8) WFLYPAT0050: WildFly Full cumulative patch ID is: base, one-off patches include: none Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,696 INFO [org.jboss.as.server.deployment.scanner] (MSC service thread 1-5) WFLYDS0013: Started FileSystemDeploymentService for directory /opt/wildfly/wildfly-27.0.0.Final/standalone/deployments Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,755 INFO [org.jboss.ws.common.management] (MSC service thread 1-7) JBWS022052: Starting JBossWS 6.1.0.Final (Apache CXF 3.5.2.jbossorg-3) Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,905 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,910 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 27.0.0.Final (WildFly Core 19.0.0.Final) started in 3859ms - Started 290 of 563 services (357 services are lazy, passive or on-demand) - Server configuration file in use: wildfly.xml Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,913 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,914 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990 Deploy an application to the Wildlfy cluster Now, our three WildFly are running, but the cluster has yet to form. Indeed, with no apps there is no reason for the cluster to exist. Let’s modify our Ansible playbook to deploy a simple application to all instances; this will allow us to check that the cluster is working as expected. To achieve this, we’ll leverage another role provided by the WildFly collection: wildfly_utils. In our case, we will use the jboss_cli.yml task file, which encapsulates the running of JBoss command-line interface (CLI) queries: … post_tasks: - name: "Ensures webapp {{ app.name }} has been retrieved from {{ app.url }}." ansible.builtin.get_url: url: "{{ app.url }}" dest: "{{ wildfly_install_workdir }}/{{ app.name }}" - name: "Deploy webapp" ansible.builtin.include_role: name: wildfly_utils tasks_from: jboss_cli.yml vars: jboss_home: "{{ wildfly_home }}" query: "'deploy --force {{ wildfly_install_workdir }}/{{ app.name }}'" jboss_cli_controller_port: "{{ item }}" loop: - 9990 - 10090 - 10190 Now, we will once again execute our playbook so that the web application is deployed on all instances. Once the automation completes successfully, the deployment will trigger the formation of the cluster. Verify that the WildFly cluster is running and the app is deployed You can verify the cluster formation by looking at the log files of any of the three instances: … 2022-12-23 15:02:08,252 INFO [org.infinispan.CLUSTER] (thread-7,ejb,jboss-eap-0) ISPN000094: Received new cluster view for channel ejb: [jboss-eap-0] (3) [jboss-eap-0, jboss-eap-1, jboss-eap-2] … Using the Ansible collection as an installer for Wildfly Last remark: while the collection is designed to be used inside a playbook, you can also use the provided playbook to directly install Wildfly: $ ansible-playbook -i inventory middleware_automation.wildfly.playbook Conclusion Here you go, with a short and simple playbook, we have fully automated the deployment of a WildFly cluster! This playbook can now be used against one, two, three remote machine or even hundreds of them! I hope this will post will have been informative and that it’ll have convinced you to use Ansible to set up your own WildFly servers! ### [AMA Recap](/news/2022/12/22/AMA-Recap/) ### [WildFly 27.0.1 is released!](/news/2022/12/16/WildFly-27-0-1-is-released/) WildFly 27.0.1.Final is now available for download. It’s been about five weeks since the WildFly 27 release, so we’ve done a small bug fix update, WildFly 27.0.1. This includes an update to WildFly Preview. The following issues were resolved in 27.0.1: Bugs [WFLY-17186] - Wrong exception handling by ManagedScheduledExecutorService.schedule(…​) [WFLY-17287] - Cannot persist ejb timers into database [WFLY-17313] - Distributed TimerService fails when cache is configured with jdbc-store [WFLY-17350] - Custom mail providers are not loaded [WFLY-17352] - NoSuchElementException during scale up under load [WFLY-17362] - Messaging - Transaction remained in prepared state after failover [WFLY-17367] - NPE throws from WSEndpointMetrics Component Upgrades [WFLY-16807] - Upgrade RESTEasy Spring to 3.0.0.Final [WFLY-17285] - Upgrade Bootable JAR to 8.1.0.Final [WFLY-17341] - Upgrade Woodstox from 6.2.8 to 6.4.0 (resolves CVE-2022-40152) [WFLY-17359] - Update protobuf to 3.19.6 (resolves CVE-2022-3171) [WFLY-17363] - Upgrade artemis-wildfly-integration to 1.0.7 [WFLY-17374] - Upgrade to Xerces 2.12.0.SP05 [WFLY-17376] - Upgrade HAL to 3.6.5.Final (WildFly 27.0.1.Final) [WFLY-17406] - Upgrade WildFly Core to 19.0.1.Final [WFLY-17410] - Upgrade CXF from 3.5.2-jbossorg-3 to 3.5.2-jbossorg-4 (resolves CVE-2022-46364) Issues resolved in the WildFly Core update included with WildFly 27.0.1 were: Bugs [WFCORE-6145] - Unbound SocketChannels do not correctly register with SocketBindingManager [WFCORE-6146] - Socket binding "bind-address" and "bind-port" runtime attributes throw NPE if network channel is unbound [WFCORE-6168] - Wildfly does not start when non-ascii chars are used in configuration [WFCORE-6169] - Disable YAML deserialization in the YAML Configuration Extension Component Upgrades [WFCORE-6099] - Upgrade byteman to 4.0.20 [WFCORE-6110] - Upgrade Jandex to 3.0.3 [WFCORE-6111] - Upgrade Bootable JAR to 8.1.0.Final [WFCORE-6132] - Upgrade sshd-common from 2.8.0 to 2.9.2 to address CVE-2022-45047 Enjoy! ### [Ask Me Anything with the WildFly Elytron Team](/news/2022/12/14/Ask-Me-Anything-with-the-WildFly-Elytron-Team/) ### [New WildFly S2I and Runtime Multi-arch Images](/news/2022/12/10/New-WildFly-S2I-and-Runtime-Multi-arch-Images/) This article provides details on the new S2I and runtime multi-arch images. New WildFly S2I and Runtime Multi-arch Images These new multi-arch images (linux/arm64 in addition to linux/amd64) have a different naming scheme than the current WildFly images to better handle multiple JDK versions and align with the tag scheme used for the WildFly centos7 docker images (as explained in Updates on WildFly Docker Images blog post). Note The previous WildFly images are now deprecated and are no longer updated. The new multi-arch image names are: Runtime image: quay.io/wildfly/wildfly-runtime:<tag> S2I builder image: quay.io/wildfly/wildfly-s2i:<tag> This change is described in this Issue. In short, the WildFly image names used to contain the JDK version (e.g: wildfly/wildfly-s2i-jdk11) leading to some lack of flexibility: An increasing number of new images for each new JDK version. No ability to identify a pair of images supporting the latest LTS (Long Term Support) JDK. The JDK version has been removed from the image name and moved to the image tag. In addition we have introduced a latest tag that identifies the images supporting the latest LTS JDK. You can identify the exact images version supporting a given JDK version: quay.io/wildfly/wildfly-runtime:1.0.0-jdk11 used to be quay.io/wildfly/wildfly-runtime-jdk11:1.0.0 quay.io/wildfly/wildfly-runtime:1.0.0-jdk17 used to be quay.io/wildfly/wildfly-runtime-jdk17:1.0.0 quay.io/wildfly/wildfly-s2i:1.0.0-jdk11 used to be quay.io/wildfly/wildfly-s2i-jdk11:1.0.0 quay.io/wildfly/wildfly-s2i:1.0.0-jdk17 used to be quay.io/wildfly/wildfly-s2i-jdk17:1.0.0 You can identify the latest images supporting a given JDK version: quay.io/wildfly/wildfly-runtime:latest-jdk11 used to be quay.io/wildfly/wildfly-runtime-jdk11:latest quay.io/wildfly/wildfly-runtime:latest-jdk17 used to be quay.io/wildfly/wildfly-runtime-jdk17:latest quay.io/wildfly/wildfly-s2i:latest-jdk11 used to be quay.io/wildfly/wildfly-s2i-jdk11:latest quay.io/wildfly/wildfly-s2i:latest-jdk17 used to be quay.io/wildfly/wildfly-s2i-jdk17:latest You can now identify the latest image supporting the latest LTS JDK version (JDK 17 at the time of this writing): quay.io/wildfly/wildfly-runtime:latest quay.io/wildfly/wildfly-s2i:latest Note Relying on this image tag implies that the JDK version will get automatically updated when a new LTS JDK is released and supported by the WildFly images. Deprecated Snapshot Multi-arch Images Up to now, we were releasing multi-arch images as preview ones in the quay.io/wildfly-snapshots organization: quay.io/wildfly-snapshots/wildfly-runtime-jdk11-multi-arch:latest quay.io/wildfly-snapshots/wildfly-runtime-jdk17-multi-arch:latest quay.io/wildfly-snapshots/wildfly-s2i-jdk11-multi-arch:latest quay.io/wildfly-snapshots/wildfly-s2i-jdk17-multi-arch:latest These images are now deprecated and no longer updated. Deprecated WildFly Images The following single-arch images are now deprecated and are no longer updated: quay.io/wildfly/wildfly-runtime-jdk11:<tag> quay.io/wildfly/wildfly-runtime-jdk17:<tag> quay.io/wildfly/wildfly-s2i-jdk11:<tag> quay.io/wildfly/wildfly-s2i-jdk17:<tag> New OpenShift Image Streams The previous image streams (wildfly-runtime-jdk11, wildfly-runtime-jdk17, wildfly-s2i-jdk11, wildfly-s2i-jdk17) have been deprecated. The new image streams are: WildFly s2i builder: wildfl-s2i imagestream WildFly runtime: wildfly-runtime imagestream Impact on Helm Charts for WildFly Helm Chart for WildFly version 2.3.1 is required to use these new images. Helm Chart for WildFly now uses the quay.io/wildfly/wildfly-s2i:latest and quay.io/wildfly/wildfly-runtime:latest (latest LTS JDK) by default, used to be JDK11. If you have already installed the Helm Charts for WildFly, make sure to update your repository to the latest version. This is done by calling: helm repo update Using the Images The image naming change is transparent when using Helm Charts for WildFly. Usage of these images is covered by WildFly S2I examples, README, wildfly-s2i image description and wildfly-runtime image description. Summary With the introduction of these new multi-arch images, we are putting in place a long term tagging scheme to better support future JDK versions. You feedback as always is very welcome. Feel free to log these as new project issues. Thank-you! JF Denise ### [Using JBeret With Quarkus](/news/2022/12/09/Using-JBeret-With-Quarkus/) ### [Vlog: Filesystem Realm Integrity](/news/2022/12/07/Vlog-Filesystem-Realm-Integrity/) ### [Introducing The Java Batch Processing API And JBeret Implementation](/news/2022/11/18/Introducing-The-Java-Batch-Processing-API-And-JBeret-Implementation/) ### [Vlog: Git Tips on Upstream Repositories and Merge Conflicts](/news/2022/11/14/Vlog-Git-Tips-on-Upstream-Repositories-and-Merge-Conflicts/) ### [Distributed Jakarta Enterprise Bean Timers](/news/2022/11/10/Distributed-Jakarta-Enterprise-Bean-Timers/) The Jakarta Enterprise Bean Timer Service allows an application to schedule application callbacks for temporal events. WildFly 27 adds a new distributed TimerService implementation that improves the scalability and efficiency of Jakarta Enterprise Bean timers in a cluster by leveraging Infinispan for both timer availability/persistence and distribution of timer scheduling. In general, the distributed TimerService implementation has the following characteristics: Persistent auto-timers are created once per cluster, in accordance with section 12.2.2 of the Jakarta Enterprise Bean specification. Non-persistent auto-timers are created once per cluster member, in accordance with section 12.2.3 of the Jakarta Enterprise Bean specification. Manually created persistent timers will initially schedule locally on the cluster member that created it. Changes to cluster topology will initiate changes to the primary ownership of existing timers, such that timer execution will be shared relatively evenly by all cluster members on which the same Enterprise Java Bean is deployed. This means that a new cluster member will assume responsibility for a share of existing timers, while timers previously owned by a leaving member will be reassigned to surviving cluster members. Users can manipulate the nuances of timer distribution by modifying the number of segments owned by each cluster member (via Infinispan subsystem configuration). TimerService.getTimers() returns all active timers associated with a given bean, including those created on, or currently scheduled by, other cluster members. TimerService.getAllTimers() returns all active timers from all beans within a given module, including those created on, or currently scheduled by, other cluster members. Configuring Distributed Jakarta Enterprise Bean Timers Distributed Jakarta Enterprise Bean timers are configured via the ejb3 subsystem. The default "ha" and "full-ha" profiles are pre-configured to support distributed timers. e.g. <subsystem xmlns="urn:jboss:domain:ejb3:10.0"> <!-- ... --> <timer-service default-persistent-timer-management="persistent" default-transient-timer-management="transient"/> <!-- ... --> </subsystem> The default-persistent-timer-management and default-transient-timer-management attributes define the server-wide default timer management used for persistent and transient (i.e. non-persistent) timers, respectively. These attributes reference resources from the distributable-ejb subsystem (also new to WildFly 27). Applications can also override these values per-EJB or per-deployment (via wildcard) within the jboss-ejb3.xml deployment descriptor. e.g. <jboss:ejb-jar xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jboss="urn:jboss:jakartaee:1.0" xmlns:t="urn:timer-service:2.0" version="4.0"> <assembly-descriptor> <t:timer-service> <ejb-name>*</ejb-name> <t:persistent-timer-management>persistent</t:persistent-timer-management> <t:transient-timer-management>transient</t:transient-timer-management> </t:timer-service> </assembly-descriptor> </jboss:ejb-jar> Looking at the distributable-ejb subsystem, we see the configuration for the resources referenced above: e.g. <subsystem xmlns="urn:jboss:domain:distributable-ejb:1.0"> <!-- ... --> <infinispan-timer-management name="persistent" cache-container="ejb" cache="persistent" max-active-timers="10000"/> <infinispan-timer-management name="transient" cache-container="ejb" cache="transient" max-active-timers="10000"/> </subsystem> This configures two providers for timer management: one for persistent timers, and one for transient (i.e. non-persistent) timers. Here, users can configure the maximum number of timers (per TimerService) to retain in memory, and the marshaller implementation (JBoss Marshalling, by default) used to serialize the "info" associated with a given Timer. Both persistent and transient timer management are based on the same implementation and only differ by the Infinispan cache configuration they employ. The cache-container and cache attributes collectively reference resources within the Infinispan subsystem: <subsystem xmlns="urn:jboss:domain:infinispan:14.0"> <!-- ... --> <cache-container name="ejb" marshaller="PROTOSTREAM" modules="org.wildfly.clustering.ejb.infinispan"> <transport lock-timeout="60000"/> <!-- ... --> <local-cache name="transient"> <locking isolation="REPEATABLE_READ"/> <transaction mode="BATCH"/> <expiration interval="0"/> <file-store passivation="true" purge="true"/> </local-cache> <distributed-cache name="persistent"> <locking isolation="REPEATABLE_READ"/> <transaction mode="BATCH"/> <expiration interval="0"/> <file-store passivation="true"/> </distributed-cache> </cache-container> <!-- ... --> </subsystem> The "persistent" cache configuration uses a distributed cache configured with passivation to a file. Alternatively, persistent timers can instead use a replicated cache, or even an invalidation cache with a shared cache store, as these cache types support the requisite consistent hash semantics required to deterministically distribute timers among existing cluster members. The "transient" cache configuration uses a local cache configured with passivation to a file, but purges its store on restart (to conform to the non-persistent nature of these timers). Note that passivation thresholds are not configured by the cache configuration directly, but rather are configured by the associated timer-management configuration above (via max-active-timers). Users should also take care to retain the default transaction and locking configuration, as these semantics are crucial for preventing duplicate or missed timeouts as the result of server shutdown or topology changes. Demonstrating Distributed Jakarta Enterprise Bean Timers The ejb-timer quickstart is the easiest way to see this feature in action. This lets you easily observe how timer callbacks behave in response to new and dropped cluster members. Give us your feedback As always, please leverage the standard WildFly channels to provide feedback for, ask questions about, or file bugs for, this feature. ### [WildFly Bootable JAR 8.1 is released!](/news/2022/11/10/WildFly-Bootable-JAR-8-1-is-released/) The 8.1.0.Final version of the WildFly Bootable JAR Maven plugin has been released. For people who are not familiar with the WildFly Bootable JAR, I strongly recommend that you read this blog post that covers it in detail. This plugin version is to be used when building WildFly Bootable JAR for WildFly 27 (that has just been released). The latest documentation of the plugin can be found here. New features and examples JDK11 dependency When packaging an application with WildFly bootable JAR Maven plugin, JDK11 is now required as the minimal JDK version. Examples evolved to Jakarta EE 10 The examples have been evolved to depend on Jakarta EE 10 specification that WildFly 27 now supports. Remote dev watch Emmanuel Hugonnet described this new feature in this bog post when it was first released in the 8.0.0.Alpha2 plugin release. Dev watch improvements Ignore transient files This enhancement allows you to ignore some file updates that were initiating a repackaging/redeploy of your application. Hidden files and files ending with '~' (generally created by your IDE) are now ignored by default. You can use the plugin option ignorePatterns to ignore more files. Watch multiple source directories This enhancement has been reported by the community. The watcher now looks for directory paths defined in the ${project.compileSourceRoots} property. In case you are using maven-build-helper plugin to add more sources to be compiled, call mvn process-sources wildfly-jar:dev-watch to have the extra source roots to be watched. Optimized watch of web files This enhancement has been reported by the community. Updating html, xhtml, jsp, css files no more implies a redeploy of the application. Any change done to these files is immediately reflected in the deployed application. You can use the web-extensions plugin option in order to identify files that should benefit from this feature. Deprecation of the Keycloak OIDC client adapters The WildFly client adapters for keycloak have been deprecated. This blog post covers it in detail. The usage of the keycloak-adapter-galleon-pack Galleon feature-pack has been replaced by the elytron-oidc-client Galleon layer defined by WildFly. The keycloak example is superseded by the elytron-oidc-client one. To conclude Finally we would really appreciate if if you would keep us posted with your feedback and new requirements. (You can log these as new project issues.) This will help us evolve the WildFly Bootable JAR experience in the right direction. Thank-you! JF Denise ### [Enabling Integrity on Filesystem realms](/news/2022/11/10/Enabling-Integrity-on-Filesystem-realms/) ### [Updates on WildFly Docker Images](/news/2022/11/10/Updates-on-WildFly-Docker-Images/) In this article, we give an update on changes made to the WildFly Docker images to enhance their capabilities. Thanks to contributions from Henri-Laiho and Kris-Gerhard, we have updated the images to use the JDK images from Eclipse Temurin as their base images. This provides the following highly requested capabilities: Provides multiarch images. The WildFly images now support linux/arm64 in addition to linux/amd64 Supports Long-Term Support (LTS) JDK 11 & 17 Supports the latest non-LTS JDK (19 at the moment) Base images that are frequently updated to fix OS and JDK vulnerabilities We are using the centos7 variants of the Temurin images, so there are no Operating System changes compared to the existing images. Docker Images for WildFly 27 and future releases Now that WildFly publishes images to run the application server with different JDK versions, we are updating our tag convention to reflect that change: the tag of the image now identifies the version of WildFly as well as the JDK version. For each release of WildFly (e.g. 27.0.0.Final), there are fixed tags for each provided JDK version: quay.io/wildfly/wildfly:27.0.0.Final-jdk11 quay.io/wildfly/wildfly:27.0.0.Final-jdk17 There are also floating tags available to pull the latest release of WildFly on the various JDK: quay.io/wildfly/wildfly:latest-jdk11 quay.io/wildfly/wildfly:latest-jdk17 Finally, there is the latest tag that corresponds to the latest release of WildFly on the latest LTS JDK (17 at the moment). quay.io/wildfly/wildfly:latest Note This floating tag may correspond to a different JDK version in future releases of WildFly images. Instead of using this latest tag, we recommend to use the floating tag with the JDK version mention to guarantee the use of the same JDK version across WildFly releases (e.g. latest-jdk17). The tags page shows a visual representation of the tags that clearly identifies tags corresponding to the same image. Docker Images for WildFly 26 (and Jakarta EE 8) We are using these new tags starting with WildFly 27 releases which require applications to be built with Jakarta EE 10. However, there is also benefit to the new images for users that are staying on WildFly 26 (which is the last release of WildFly that supports Jakarta EE 8). We will also provide new images for WildFly 26 that leverages these new capabilities. The tags for WildFly 26 will be: quay.io/wildfly/wildfly:26.1.2.Final-jdk11 quay.io/wildfly/wildfly:26.1.2.Final-jdk17 Provide non-LTS JDK images With the move to the Temurin images, we are also able to provide images for non-LTS JDK versions. In order to help using the latest features of Java with WildFly, we will also provide images for the latest non-LTS JDK version tested by WildFly. At the time of writing, this is JDK 19. The tags for these images will be: quay.io/wildfly/wildfly:27.0.0.Final-jdk19 quay.io/wildfly/wildfly:latest-jdk19 These non-LTS images will have a shorter life: as soons as WildFly supports a more recent non-LTS JDK version, we will provide images for this version and stop producing images for the previous version. Summary WildFly now provides Docker images with highly requested features such as ARM architecture, multiple JDK versions and frequently updated base images that lets users pick and choose the best settings adapted to their Jakarta applications when they are deployed on the cloud. ### [Introduction to working on/with Jakarta EE Specifications for WildFly users](/news/2022/11/10/Introduction-to-working-on-with-Jakarta-EE-Specifications-for-WildFly-users/) Reasons to get involved with the Jakarta EE Specification teams You are a developer that uses the WildFly (Jakarta EE) application server to create/update applications that meet your users needs. Reason #1 is to participate in developing future Jakarta EE releases. From adding a new feature to a specification, to implementing that new feature. You can also help by adding TCK tests for new features as well. Whether you contribute a small or large amount of time, every contribution helps! The more that you participate in the Jakarta EE communities, the more you will understand how Jakarta EE releases are done. Sign the Eclipse contribution agreement (ECA) when you are ready to contribute a pull request. You will want to sign the ECA with the same email address as the one associated with your github account that you use for creating Jakarta EE pull requests. Browsing/joining the various Jakarta EE mailing lists Why join the various Jakarta EE specification mailing lists? Participate in discussions about each of the specifications. Learn of opportunities to contribute changes to the next Jakarta EE release. Be ready to ask questions on the subscribed email lists. Jakarta EE Mailing Lists lists all of the mailing lists. Note that each mailing list is archived in a web browsable format. Join the Jakarta EE Community list. Join the Platform which discusses the overall Jakarta EE Platform specifications that brings all of the individual EE technologies together for each EE release. Join the Activation specification discussions. Join the Annotations specification discussions. Join the Authentication specification discussions. Join the Authorization specification discussions. Join the Batch specification discussions. Join the Bean Validation specification discussions. Join the Concurrency specification discussions. Join the Connectors specification discussions. Join the Context and Dependency Injection specification discussions. Join the Enterprise Beans specification discussions. Join the Expression Language specification discussions. Join the Interceptors specification discussions. Join the JSON Binding specification discussions. Join the JSON Processing specification discussions. Join the Mail specification discussions. Join the Messaging specification discussions. Join the Persistence specification discussions. Join the RESTful Web Services specification discussions. Join the Security specification discussions. Join the Faces specification discussions. Join the Servlet specification discussions. Join the Standard Tag Library specification discussions. Join the Transactions specification discussions. Join the Websocket specification discussions. Join the Platform TCK discussions and help add/update tests. Accessing the specification documents (PDF/HTML) for various specifications Browse the jakarta.ee page. The jakarta.ee page contains many useful subpages, such as the specification with all the technology specifications (html/pdf document that describes the specification, javadoc). For example https://jakarta.ee/specifications/persistence/3.1 contains the Jakarta Persistence 3.1 specification documents, JavaDoc, Schema documents, Test Compatibility Kit, Maven coordinates. Another example, Jakarta RESTful Web Services shows the various releases of Jakarta RESTful Web Services but also note the project button link which shows you interesting information about that project such as the list of committers and who leads the project. The project committers are responsible for reviewing/merging pull requests (e.g. changes) to the Specification repository. Another important page to note is the Developer Resources page which has the Specification github repository link. You should fork a few of the various Jakarta EE Specification repositories such as github.com/jakartaee/rest which contain the source for the Jakarta RESTful Web Services API and SPEC documents. Forking a repository on https://github.com/YOUR_NAME means creating a copy of a repo in your personal github account. You can make EE Specification improvements with your fork and create a pull request for the upstream (original) repo that you forked. The next blog will give more details about contributing to Jakarta EE and how that can help WildFly + you. We’d love to hear feedback from you at the WildFly forum, the next blog in this series will try to answer any questions you post in response. ### [WildFly S2I (Source To Image) images](/news/2022/11/09/WildFly-S2I-Source-To-Image-images/) In April we announced the new WildFly architecture for the cloud. I strongly encourage you to read that post to get familiar with this new architecture. We have discontinued the release of WildFly s2i centos7 based images starting WildFly 26.1.2. For new features and bug fixes, we are now only releasing UBI8 based JDK11/JDK17 s2i builder and runtime images along with the Galleon wildfly-cloud-galleon-pack. The latest artifacts that form the WildFly cloud experience are: WildFly Source-to-Image (S2I) builder images (JDK11 and JDK17) WildFly runtime images (JDK11 and JDK17) WildFly Maven plugin 4.0.0.Final WildFly cloud Galleon feature-pack 2.0.0.Final WildFly datasources Galleon feature-pack 3.0.0.Final Helm Chart for WildFly 2.x New features overview Generation of an efficient WildFly s2i builder image. This feature, covered in detail in this blog post, is specified in this enhancement description. The environment variables that allow you to configure an S2I build to produce a WildFly S2I builder for a given WildFly server can be found here. cloud-server and postgresql-server WildFly s2i builders. The Maven projects cloud-server and postgresql-server define s2i builders maven projects and Helm chart for WildFly yaml files that you can re-use to build s2i builders. Such builders will then be usable to build your application images in an efficient way. This example highlights the usage of the generated builders. Support for automatically discovering and registering the deployments to be secured with OIDC. This support complies with this WildFly proposal. This support is based on the elytron-oidc-client subsystem. It is equivalent to the Keycloak OIDC support provided in the legacy images. The environment variables that allow you to configure the server can be found here. Overriding of simple server configuration attributes using environment variables. This feature, enabled by default in the WildFly s2i images, is specified by this proposal. WildFly on the cloud relies on container environment variables to customize its configuration for the container platform. It is difficult to change the value of a management attribute from the standalone configuration if the attribute does not provide a default value with an expression that can be resolved at runtime. This feature introduces a generic mechanism to let user override any simple management attribute using environment variables. Complex attributes (of type OBJECT, LIST, PROPERTY) are not impacted by this change. As an example, the user could set an env var when starting WildFly to change the value of a proxy-address-forwarding attribute with the env var SUBSYSTEM_UNDERTOW_SERVER_DEFAULT_SERVER_HTTP_LISTENER_DEFAULT__PROXY_ADDRESS_FORWARDING. Image streams that you can import in OpenShift and use with helm Charts: WildFly s2i builder, JDK11 imagestream WildFly s2i builder, JDK17 imagestream WildFly runtime, JDK11 imagestream WildFly runtime, JDK17 imagestream WildFly S2I builder generation One of the main areas feedback we got for this new architecture is that an s2i build takes more time compared to legacy WildFly s2i images. That is due to the maven resolution of the WildFly server artifacts (JBoss Modules modules jar retrieved from remote maven repositories) during provisioning. Although incremental-build (re-use of the maven cache from previous build) is enabled by default when using the Helm chart for WildFly, when building multiple applications incremental build is not an answer, as the maven local cache can’t be shared among different build configs. In order to provide an answer to this issue, we have made the WildFly s2i builder image able to generate an S2i builder image for a given trimmed server. Such a builder contains an installed WildFly server in $JBOSS_HOME (/opt/server) in which a deployment built during the next s2i phase is deployed. This kind of builder offers an efficient build phase, as no more provisioning is performed when building the application. The builder image size is also reduced compared to the legacy WildFly s2i builder image. The image contains only the needed trimmed server artifacts. Note An interesting aspect of generated builders is that they can be shared across the s2i builds of different application deployments that require the same server capabilities. The following diagrams covers the three S2I workflows. Legacy S2I workflow New WildFly S2I workflow 2 phases S2I build workflow based on generated builder When building such a WildFly s2i builder, the Maven and s2i environment variables that you would need to use (e.g. to configure maven repositories, set maven args, etc) need to be isolated in order not to collide with the same environment variables one could set when using the generated builder. For this isolation, you need to suffix any env variable with _WILDFLY_SERVER_BUILDER (for example MAVEN_ARGS_APPEND_WILDFLY_SERVER_BUILDER). The suffix is automatically removed during the build and the proper environment variable is exported. A WildFly s2i builder is built from sources (actually just a pom.xml file) located inside a maven project. The WildFly Maven Plugin is used to provision the server, configured with the Galleon layers of your choice (e.g. jaxrs-server, cloud-server+ejb, etc). The Galleon layers you can use are not limited to the WildFly Galleon layers. You can use different Galleon feature-packs to build-up your server. This pom.xml file contains the provisioning of a cloud-server plus a postgresql driver and datasource that the wildfly-datasources-galleon-pack defines. To make WildFly s2i builder generation possible using the Helm chart for WildFly, we have evolved it with support for the following: Ability to disable the chained build that produces an application image. That is done thanks to the new build.s2i.buildApplicationImage property. When set to false, the name of the generated image is the name of the chart. For example helm install cloud-server-builder -f helm.yaml wildfly/wildfly will produce an Openshift imagestream named cloud-server-builder. The suffix -build-artifacts that is appended when the chained build is enabled is not added. The generated imagestream is what will then be used when building your application using the generated builder. Ability to set a different kind of image for the s2i builder image and the runtime image. By default the WildFly s2i docker images are used for s2i build and chained build. In the context of a generated builder, the builder is of type imagestream (ImageStreamTag or ImageStreamImage). You can set the builder type using the build.s2i.builderKind property. This helm chart file shows how to configure an s2i build to produce a WildFly s2i builder. New Examples WildFly 27 supports only Jakarta EE 10, so the WildFly s2i examples have been migrated to jakarta EE 10. In addition to the set of examples that we introduced for WildFly 26, new examples have been included: Automatic discovery and registration of deployments secured with keycloak OIDC protocol example. A JMS broker, message provider and consumer example that relies on the new embedded-activemq Galleon layer that WildFly provides. An example to provision a postgresql driver and multiple datasources. An example that highlights the new "WildFly s2i builder" generation features. Enjoy! We hope that you will have an interest in these new features. As usual we need your feedback to evolve WildFly on the cloud in the right direction. Feel free to log these as new project issues. Thank-you! JF Denise ### [WildFly 27 Final is released!](/news/2022/11/09/WildFly-27-Final-is-released/) It gives me tremendous pleasure to announce that the new WildFly and WildFly Preview 27.0.0.Final releases are available for download at https://wildfly.org/downloads. Jakarta EE 10 Support For sure the biggest new thing in WildFly 27 is support for Jakarta EE 10. WildFly 27 is a compatible implementation of the EE 10 Platform as well as the Web Profile and the new Core Profile. WildFly is EE 10 compatible when running on both Java SE 11 and Java SE 17. Evidence supporting our certification is available in the WildFly Certifications repository on GitHub: Jakarta EE 10 Full Platform SE 11 SE 17 Jakarta EE 10 Web Profile SE 11 SE 17 Jakarta EE 10 Core Profile SE 11 SE 17 Jakarta EE 8 and EE 9.1 are no longer supported beginning with the WildFly 27 release. WildFly’s EE 10 support includes the following specifications in our "full" (e.g. standalone-full.xml) and "default" (e.g standalone.xml) configurations: Jakarta EE Platform Technology Jakarta EE Full Platform Jakarta EE Web Profile WildFly Full Configuration WildFly Default Configuration Jakarta Activation 2.1 X  —  X X Jakarta Annotations 2.1 X X X X Jakarta Authentication 3.0 X X X X Jakarta Authorization 2.1 X  —  X  —  Jakarta Batch 2.1 X  —  X X Jakarta Bean Validation 3.0 X X X X Jakarta Concurrency 3.0 X X X X Jakarta Connectors 2.1 X  —  X X Jakarta Contexts and Dependency Injection 4.0 X X X X Jakarta Debugging Support for Other Languages 2.0 X X X X Jakarta Dependency Injection 2.0 X X X X Jakarta Enterprise Beans 4.0 X X(Lite) X X(Lite) Jakarta Enterprise Web Services 2.0 Optional  —  X X Jakarta Expression Language 5.0 X X X X Jakarta Interceptors 2.1 X X X X Jakarta JSON Binding 3.0 X X X X Jakarta JSON Processing 2.1 X X X X Jakarta Mail 2.1 X  —  X X Jakarta Messaging 3.1 X  —  X  —  Jakarta Persistence 3.1 X X X X Jakarta RESTful Web Services 3.1 X X X X Jakarta Security 3.0 X X X X Jakarta Server Faces 4.0 X X X X Jakarta Server Pages 3.1 X X X X Jakarta Servlet 6.0 X X X X Jakarta SOAP with Attachments 1.3 Optional  —  X X Jakarta Standard Tag Library 3.0 X X X X Jakarta Transactions 2.0 X X X X Jakarta WebSocket 2.1 X X X X Jakarta XML Binding 4.0 Optional X X X Jakarta XML Web Services 4.0 Optional  —  X X WildFly Preview 27 also provides the EE 10 APIs, although at this time we have not chosen to certify compatibility. Unlike the previous major and minor releases, in the 27 releases the EE API and implementation libraries are the same between standard WildFly and WildFly Preview. (For more on the differences between WildFly and WildFly Preview, see the WildFly documentation.) The move to EE 10 was a truly massive undertaking and I’m full of appreciation and admiration for the tremendous group of WildFly and component project developers who have pulled this off, along with all of the hard-working participants in Jakarta. I’m also deeply grateful to the WildFly community for their support of and feeback on our efforts doing this journey. Other New and Notable Things Besides Jakarta EE 10 support, here are some of the other new features in this release. Observability We’ve added a new tech preview 'Micrometer' subsystem (WildFly Preview only) Cloud WildFly 27 brings with it significant changes to the WildFly images for OpenShift. Jean-Francois Denise explains what’s new in his What’s new for WildFly 27 in the cloud post. We’ve also made exciting updates to the WildFly docker images (multi-arch, SE 17 and SE 19 support; new base images). Jeff Mesnil explains the details in his Updates on WildFly Docker Images post. We’ve also made improvements in our bootable jar support. Additionally, for those of you who deploy WildFly on AWS, we’ve added support for the aws.S3_PING JGroups discovery prootocol. EJB We’ve added a new 'distributable-ejb' subsystem. Support for use of an Infinispan cache as an EJB timer store. Support for marshalling of Java record classes. Security Encryption support in the FileSystemSecurityRealm Identity integrity support in the FileSystemSecurityRealm Provisioning We’ve added a number of new Galleon layers: 'embedded-activemq' for embedded broker messaging. 'hibernate-search' to support use of Hibernate Search with the jpa layer. 'mod_cluster' for mod_cluster subsystem provisioning. 'singleton-local' and 'singleton-ha' for different configuration flavors using the singleton subsytem. Hibernate Search We’ve updated the version of Hibernate Search we integrate up to the 6.1 series. We’ve also made a couple of other changes in our Hibernate Search support: A number of modules formerly only intended for internal access by Hibernate Search have now been marked as public, allowing for direct application use of the APIs exposed by those modules. In WildFly Preview we’ve added support for Hibernate Search’s experimental feature alllowing coordinated indexing of entities from multiple instances of the same application. Major Component Upgrades vs WildFly 26.x There have been numerous component upgrades related to WildFly’s transition from EE 8 to EE 10; too many to list here. However, besides those EE 10 driven updates, there are a number of other major component updates in WildFly 27: Hibernate 6.1 replaces Hibernate 5.3 Hibernate Search 6.1 replaces Hibernate Search 5.10 Infinispan 14 replaces Infinispan 13 JGroups 5.2 replaces JGroups 4.2 RESTEasy 6.2 replaces RESTEasy 4.7 Weld 5 replaces Weld 3.1 MicroProfile Support WildFly’s MicroProfile support includes implementations of the following specifications in our "full" (e.g. standalone-full.xml) and "default" (e.g standalone.xml) configurations as well as our "microprofile" configurations (e.g. standalone-microprofile.xml): MicroProfile Technology WildFly Full/Default Configurations WildFly MicroProfile Configuration MicroProfile Config 3.0 X X MicroProfile Fault Tolerance 4.0  —  X MicroProfile Health 4.0  —  X MicroProfile JWT Authentication 2.0 X X MicroProfile Metrics 4.0 (deprecated in WildFly; will be replaced by Micrometer)  —  X MicroProfile OpenAPI 3.0  —  X MicroProfile OpenTracing 3.0 (deprecated; use OpenTelemetry) X X MicroProfile Reactive Messaging 3.0  —   —  MicroProfile Streams Operators 3.0  —   —  MicroProfile Rest Client 3.0 X X Note The MicroProfile APIs used in WildFly 27 build on a number of Jakarta EE 9.1 APIs, while WildFly provides the EE 10 versions of those APIs. For this reason, as of the time of writing the WildFly project has not sought certification of WildFly 27 compatibility with any MicroProfile specification. We do test our MicroProfile integration, including by running the MicroProfile TCKs. Note In WildFly 28 it is likely that we will be removing support for MicroProfile Metrics and MicroProfile OpenTracing, as we shift our focus to support for OpenTelemetry, MicroProfile Telemetry, and Micrometer. Java SE Support Our recommendation is that you run WildFly on the most recent long-term support SE release, i.e. on SE 17 for WildFly 27. While we do do some testing of WildFly on JDK 19, we do considerably more testing of WildFly itself on the LTS JDKs, and we make no attempt to ensure the projects producing the various libraries we integrate are testing their libraries on anything other than JDK 11 or 17. WildFly 27 also is heavily tested and runs well on Java 11. We plan to continue to support Java 11 at least through WildFly 28, and probably beyond. As I discussed in my WildFly Release Plans for 2022 post, Java SE 8 is no longer supported beginning with the WildFly 27 series. While we recommend using an LTS JDK release, I do believe WildFly runs well on JDK 19. By runs well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. Please note that WildFly runs on Java 11 and later in classpath mode. Other Incompatible Changes RESTEasy Spring For WildFly 27, RESTEasy Spring support has been removed from standard WildFly. RESTEasy Spring support only comes with WildFly Preview. Typically standard WildFly provides RESTEasy Spring support, but at the time of the WildFly 27 release the Spring libraries it integrates with had not yet produced final releases. So to avoid possible incompatible changes in a future standard WildFly release, support for RESTEasy Spring was moved to WildFly Preview only. We intend to re-introduce standard WildFly support for RESTEasy Spring in a future release. Weld Probe Please note that following the recommendation of the Weld maintainers, in WildFly 27 we have removed support for the Weld Probe development mode. Release Notes The release notes for the release are available in the WFLY project in JIRA. Issues fixed in the underlying WildFly Core 19.0 release are listed in the WildFly Core JIRA. Please try it out and give us your feedback, while we get to work on WildFly 28! Best regards, Brian ### [Grace Hopper Celebration Recap](/news/2022/10/31/Grace-Hopper-Celebration-Recap/) ### [Open Source Day 2022 Recap](/news/2022/10/14/Open-Source-Day-2022-Recap/) ### [Hacktoberfest Has Started](/news/2022/10/07/Hacktoberfest-Has-Started/) ### [WildFly 27 Beta1 is released!](/news/2022/09/29/WildFly-27-Beta1-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 27.0.0.Beta1 releases are available for download at https://wildfly.org/downloads. New and Notable As I noted in my last post, the key new thing in WildFly 27 is compatibility with the recently released Jakarta EE 10. Thanks so much to all the great WildFly contributors who worked so hard on our EE 10 journey! Besides Jakarta EE 10 support, here are some of the other new features in this release. Observability WFLY-14947 - A new tech preview 'Micrometer' subsystem (WildFly Preview only) EJB WFLY-14953 - A new 'distributable-ejb' subsystem WFLY-7628 — Support for use of an Infinispan cache as an EJB timer store Security WFLY-15075 - Encryption support in the FileSystemSecurityRealm WFLY-16179 - Identity integrity support in the FileSystemSecurityRealm Provisioning WFLY-13798 - A new 'embedded-activemq' Galleon layer for embedded broker messaging WFLY-17004 - A new 'hibernate-search' Galleon layer WFLY-16453 — New 'singleton-local' and 'singleton-ha' Galleon layers Major Component Upgrades vs WildFly 26.x There have been numerous component upgrades related to WildFly’s transition from the javax namespace EE 8 to the jakarta namespace EE 10; too many to list here. However, besides those EE 10 driven updates, there are a number of other major component updates in WildFly 27 Beta1: Hibernate 6.1 replaces Hibernate 5.3 Hibernate Search 6.1 replaces Hibernate Search 5.10 Infinispan 14 replaces Infinispan 13 JGroups 5.2 replaces JGroups 4.2 RESTEasy 6.2 replaces RESTEasy 4.7 Weld 5 replaces Weld 3.1 Removal of Support for EE 8 and SE 8 As I discussed in my WildFly Release Plans for 2022 post, Jakarta EE 8 and Jakarta SE 8 are no longer supported beginning with the WildFly 27 series. Use of SE 11 or later is required, with SE 17 recommended. Testing on SE 19 is in progress. Release Notes The release notes for the release are here. Note that this only covers the differences between 27 Beta1 and the recent 27 Alpha5; release notes for the 27 Alpha1 - 5 releases are available in the WildFly JIRA. Issues fixed in the numerous underlying WildFly Core 19.0 beta releases are listed in the WildFly Core JIRA. Please try it out and give us your feedback, while we get to work on WildFly 27 Final! Best regards, Brian ### [Jakarta EE 10 is released and WildFly is compatible!](/news/2022/09/22/Jakarta-EE-10-is-released-and-WildFly-is-compatible/) Congratulations to everyone involved with Jakarta EE for today’s announced general availability of Jakarta EE 10! It’s great to see continued advances in Jakarta EE, particularly Jakarta Contexts and Dependency Injection 4.0 with the new CDI Lite, along with the new Jakarta EE 10 Core Profile. I’m particularly happy to announce that our hard work in the WildFly community on EE 10 is paying off. Last week we released WildFly 27.0.0.Alpha5, and this week compatibility certification requests for EE 10 Full Platform and Web Profile were accepted at Jakarta. WildFly Preview has also been a compatible implementation of the EE 10 Core Profile since the 27.0.0.Alpha1 release. It’s great to see so many links to WildFly on the Jakarta EE download page. All of these certifications were for running on either Java SE 11 or Java SE 17. Compatibility Certification Information for 27.0.0.Alpha5 is available from the WildFly certifications GitHub repo: EE 10 Full Platform — SE 11 EE 10 Full Platform — SE 17 EE 10 Web Profile — SE 11 EE 10 Web Profile — SE 17 We’ll be sending EE 10 Core Profile compatibility certification requests to Jakarta for standard WildFly 27.0.0.Alpha5 shortly. (As noted above, WildFly Preview has been compatible since 27.0.0.Alpha1.) Our TCK results that will back those certification requests are as follows: EE 10 Core Profile — SE 11 EE 10 Core Profile — SE 17 Thank you to all the hard-working WildFly developers for your enormous efforts toward reaching this milestone. And thank you to our terrific user community for your support and feedback along the way. A special word of thanks to Scott Stark, who led the EE 10 release at Jakarta, and to Scott Marlow who played a critical role there, particularly on the TCK. Way, way back in the day Scott Stark was the first person from JBoss I ever met, when I took a JBoss, Inc. training course that he taught. It’s great to still be working with Scott almost twenty years later. Congratulations as well to the Glassfish, Payara and Open Liberty developers all of whom have released compatible implementations of one or more of the EE 10 profiles. A big goal at Jakarta has been to create an environment where it’s possible for multiple compatible implementations to be available on the day a new EE version becomes general available. It’s great to see that effort continuing to bear fruit. Looking forward, we’re hard at work on completing WildFly 27. Keep an eye out for more release announcement related to that over the next few weeks. Thank you for your continued support of WildFly. We’d love to hear from you at the WildFly forum. ### [FAQ for New Contributors](/news/2022/09/15/FAQ-for-New-Contributors/) ### [Remote dev-watch development with WildFly Jar Maven Plugin](/news/2022/09/14/Remote-dev-watch-development-with-WildFly-Jar-Maven-Plugin/) The 8.0.0.Alpha2 version of the WildFly bootable JAR Maven plugin has been released. This release is not yet Final, as it is only there to gather feedback on a new feature that simplifies development on the "cloud" using the dev-watch goal. For people who are not familiar with WildFly bootable JAR and its dev-watch goal, I strongly recommend that you read this blog post that covers it in details. Dev-watch goal The current dev-watch goal, although offering an efficient workflow to develop WildFly applications, requires the bootable application or server to run locally, in the same place as the project. The improvement made on this release is to allow the bootable application or server to run remotely so that it can be in an environment that is closer to the target runtime environment. We are going to use this example to see how we can work remotely. Important This application applies the script anonymous-management.cli which disable security on the Management API of WildFly, please make sure not to include it when going to production. Developping with a docker container. Build and run the application with docker The first step is to create the container image where the application is running. For this we are going to use a very simple Dockerfile: FROM registry.access.redhat.com/ubi8/openjdk-11:latest COPY --chown=jboss:root target/*.jar /deployments/. RUN chmod -R ug+rwX /deployments/. To build that container image we are executing: $ mvn clean install $ podman build -f Dockerfile -t remote-microprofile-config:latest And then we are going to run the container and expose the ports 8080 and 9990: $ podman run -p 8080:8080 -p 9990:9990 -it remote-microprofile-config:latest Develop and update this application Now we need to run the dev-watch goal and remotely attach to the Wildfly Management API. For this we need to execute the following command line: $ mvn org.wildfly.plugins:wildfly-jar-maven-plugin:8.0.0.Alpha2:dev-watch \ -Dwildfly.bootable.remote=true \ -Dwildfly.bootable.remote.username=admin \ -Dwildfly.bootable.remote.password=passW0rd! \ -Dwildfly.hostname=${container.ip.address} Check that the application is running properly : $ curl http://${container.ip.address}:8080 config1 = Value from Config1 comes from an env var in the DeploymentConfig config2 = Value for config2 comes from a properties file inside the application config3 = Default value for config3 comes from my code Once this is done you can edit the code and your changes will be automatically pushed to the remote container. For example: Change the config2 property value to be "Hello from dev-watch remote" in the file: src/main/resources/META-INF/microprofile-config.properties. Save your changes The application is redeployed and the new configuration will be taken into account: $ curl http://${container.ip.address}:8080 config1 = Value from Config1 comes from an env var in the DeploymentConfig config2 = Hello from dev-watch remote config3 = Default value for config3 comes from my code Developping on OpenShift. Build and run the application with OpenShift We first need to build the application : $ mvn clean install Then to deploy it you need to drag and drop the produced remote-microprofile-config-bootable.jar on the Topology page on OpenShift. Now we need to expose the management API of WilFly by first editing the service to add a TCP port for 9990, and then add a route to that port: $ oc create route edge management-remote-microprofile-config-bootable --service=remote-microprofile-config-bootable --port=9990 --insecure-policy='Redirect' Develop and update this application Now we need to run the dev-watch goal and remotely attach to the Wildfly Management API. For this we need to execute the following command line: $ mvn -P bootable-jar-remote -Dwildfly.hostname=$(oc get route management-remote-microprofile-config-bootable --template='{{ .spec.host }}') install You may also use a command like this one: $ mvn org.wildfly.plugins:wildfly-jar-maven-plugin:8.0.0.Alpha2:dev-watch \ -Dwildfly.bootable.remote=true \ -Dwildfly.port=443 \ -Dwildfly.bootable.remote.protocol=remote+https \ -Dwildfly.hostname=$(oc get route management-remote-microprofile-config-bootable --template='{{ .spec.host }}') Check that the application is running properly : $ curl https://$(oc get route remote-microprofile-config-bootable --template='{{ .spec.host }}') config1 = Value from Config1 comes from an env var in the DeploymentConfig config2 = Value for config2 comes from a properties file inside the application config3 = Default value for config3 comes from my code Once this is done you can edit the code and your changes will be automatically pushed to the OpenShift instance. For example: Change the config2 property value to be "Hello from dev-watch remote" in the file: src/main/resources/META-INF/microprofile-config.properties. Save your changes The application is redeployed and the new configuration will be taken into account: $ curl https://$(oc get route remote-microprofile-config-bootable --template='{{ .spec.host }}') config1 = Value from Config1 comes from an env var in the DeploymentConfig config2 = Hello from dev-watch remote config3 = Default value for config3 comes from my code Conclusion We hope that you are seeing the benefits of the new features that this release is bringing. We would really appreciate your feedback on the dev-watch goal. We aim toward a smooth and efficient first class WildFly developer experience and we need you there! Thank-you. ### [Bearer Token Support for the Elytron OIDC Client Subsystem](/news/2022/09/01/Bearer-Token-Support-for-the-Elytron-OIDC-Client-Subsystem/) ### [WildFly 26.1.2 is released!](/news/2022/08/31/WildFly-26-1-2-is-released/) WildFly 26.1.2.Final is now available for download. This is a bug fix release. The full list of issues resolved in WildFly 26.1.2 is available here. Issues resolved in the WildFly Core update included with WildFly 26.1.2 are available here. As I’ve discussed in various posts that touch on the WildFly project’s plans for 2022, beginning with the upcoming WildFly 27 release WildFly releases will no longer support Java SE 8, Jakarta EE 8 and MicroProfile 4.1. We’ll be moving on to Jakarta EE 10 and a minimum SE requirement of SE 11. We realize that moving applications to EE 10 will involve effort for our users, so we wanted to provide an extra bug fix release beyond the usual micro we produce about a month after each feature release. WildFly 26.1.2 is that release. My expectation is this will be the last WildFly release that supports SE 8 and EE 8. As part of this release we’ve also do a 26.1.2 release of WildFly Preview. Thank you for your continued support of WildFly. We’d love to hear your feedback at the WildFly forum. ### [Top 5 Reasons To Join Us At Open Source Day](/news/2022/08/31/Top-5-Reasons-To-Join-Us-At-Open-Source-Day/) ### [Using RHOSAK from WildFly](/news/2022/08/19/Using-RHOSAK-from-WildFly/) Introduction RHOSAK (full name: Red Hat OpenShift Streams for Apache Kafka) is a cloud service hosted by Red Hat which makes setting up, managing and scaling Apache Kafka instances very easy. Also, you get the peace of mind of knowing the instances are patched with the latest security fixes. Apache Kafka is an open-source, distributed streaming platform that enables (among other things) the development of real-time, event-driven applications. WildFly integrates with Apache Kafka via the MicroProfile Reactive Messaging subsystem, which implements the MicroProfile Reactive Messaging specification. In this blog we will see how to write a simple application which sends and receives messages to/from a Kafka instance. We will then point to how you would be able to run the application locally, using the configuration contained in the application. After that, we will set up a RHOSAK instance, create a topic and deploy our application into OpenShift. An interesting point here is that we will save the server url and the credentials needed to connect to it in an OpenShift secret. We then map the secret via the MicroProfile Config subsystem. The end result is that we override values hard coded in the application (i.e. the ones we used for the standalone case) from an external source. The source code for the example can found at https://github.com/kabir/blog-mp-reactive-messaging-rhosak. It contains a README for the RHOSAK steps covered here. Let’s get started! The Application The core part of the application is pretty straightforward, it is an @ApplicationScoped CDI bean called MessagingBean. The full source code can be found here. We will just outline the most important points below: @Inject @Channel("to-kafka") private Emitter<String> emitter; This injects a MicroProfile Reactive Messaging Emitter into the bean. The @Channel annotation comes from MicroProfile Reactive Messaging, and allows us to send messages to the MicroProfile Reactive Messaging stream in its name (in this case the name is ‘to-kafka’). We send messages in the following method: public Response send(String value) { System.out.println("Sending " + value); emitter.send(value); return Response.accepted().build(); } This method is called from a class called UserResource which handles POST requests to add data. Next we have a method using the @Incoming annotation, again from MicroProfile Reactive Messaging, which receives messages from the ‘from-kafka’ MicroProfile Reactive Messaging stream. @Incoming("from-kafka") public void receive(String value) { System.out.println("Received: " + value); synchronized (recentlyReceived) { if (recentlyReceived.size() > 3) { recentlyReceived.removeFirst(); } recentlyReceived.add(value); } } It adds the messages to a list containing the three most recent entries. UserResource contains a method handling GET requests which returns the contents of this list. Then we have a MicroProfile Config properties file at microprofile-config.properties file which does the mapping to Kafka. The contents of the file are as follows: # This will be overwritten by the entries set up in the initialize-server.cli script mp.messaging.connector.smallrye-kafka.bootstrap.servers=localhost:9092 # Configure the 'to-kafka' channel to write to. We write String entries to the Kafka topic 'testing' mp.messaging.outgoing.to-kafka.connector=smallrye-kafka mp.messaging.outgoing.to-kafka.topic=testing mp.messaging.outgoing.to-kafka.value.serializer=org.apache.kafka.common.serialization.StringSerializer # Configure the 'from-kafka' channel we receive messages from. We receive String entries from Kafka topic 'testing' mp.messaging.incoming.from-kafka.connector=smallrye-kafka mp.messaging.incoming.from-kafka.topic=testing mp.messaging.incoming.from-kafka.value.deserializer=org.apache.kafka.common.serialization.StringDeserializer # Configure Kafka group.id to prevent warn message - if not set, some default value is generated automatically. mp.messaging.connector.smallrye-kafka.group.id="microprofile-reactive-messaging-kafka-group-id" The formats of the property keys can be found in the WildFly documentation which also goes into more depth about what each entry means. In short we’re pointing to a Kafka instance running on localhost:9092, which is the default port Kafka will run on. We’re pointing the @Channel(“to-kafka”) annotated Emitter we saw earlier to Kafka’s testing topic, and pointing the @Incoming(“from-kafka”) annotated receive() method to the same testing topic. Since both are using the same underlying Kafka topic, messages sent via the Emitter will be received in the receive() method. Finally, since we are sending Strings, we need to tell Kafka to use the String serializer/deserializer. Running the Application Locally Since the intent of this article is to show integration with RHOSAK, we won’t go into too many details here, as it has been covered in this previous blog post. The steps are: Make sure WildFly is running, e.g. by one of the following two approaches Download the latest WildFly zip. Note: it must be AT LEAST WildFly 27.0.0.Alpha4 since this project uses Jakarta EE dependencies, and prior to 27.0.0.Alpha4 WildFly was using the legacy Java EE dependencies. Enable the MicroProfile Reactive Messaging and Reactive Streams Operators extensions/subsystems by running the following operations in a CLI session: batch /extension=org.wildfly.extension.microprofile.reactive-messaging-smallrye:add /extension=org.wildfly.extension.microprofile.reactive-streams-operators-smallrye:add /subsystem=microprofile-reactive-streams-operators-smallrye:add /subsystem=microprofile-reactive-messaging-smallrye:add run-batch reload Make sure you have a Kafka server running, for example by following steps 1 and 2 of the Kafka Quickstart. In a clone of https://github.com/kabir/blog-mp-reactive-messaging-rhosak run mvn package wildfly:deploy to build and deploy our application Finally post messages to the application, and read them again by running the following commands in a terminal $ curl -X POST http://localhost:8080/wildfly-microprofile-reactive-messaging-rhosak-1.0.0-SNAPSHOT/one $ curl -X POST http://localhost:8080/wildfly-microprofile-reactive-messaging-rhosak-1.0.0-SNAPSHOT/two $ curl http://localhost:8080/wildfly-microprofile-reactive-messaging-rhosak-1.0.0-SNAPSHOT [one, two] You may now stop WildFly and Kafka. Running WildFly in OpenShift with Kafka provided by RHOSAK Setting up a Kafka instance on RHOSAK and creating a secret with connection information First you need to set up a Kafka instance on RHOSAK. Since the rhoas line client is still under active development, the exact instructions how to do so might change. So rather than summarising everything you need to do here, see the prerequisites section of the example application repository for how to install the rhoas client. Once you have the rhoas client installed, follow the following steps (again from the example application repository) to perform the following steps. Login to RHOSAK Create a Kafka instance, and set it as the active instance Create a Kafka topic Create a service account used to authenticate with the Kafka instance, and grant it access to produce/consume messages on the Kafka instance Create an OpenShift secret called rhoas containing the address of the Kafka instance the service account details The secret will be called rhoas and contains the following entries: KAFKA_HOST - the address and port of the Kafka instance running on RHOSAK RHOAS_SERVICE_ACCOUNT_CLIENT_ID - the id of the service account used to authenticate with the Kafka instance RHOAS_SERVICE_ACCOUNT_CLIENT_SECRET - the secret used to log in the client RHOAS_SERVICE_ACCOUNT_OAUTH_TOKEN_URL - ignored in this example Additional application configuration to run in OpenShift and connect to RHOSAK Although we are not quite ready to deploy our application yet, it is worth knowing that we will be using Helm to deploy our application to OpenShift. To deploy an application using Helm, you use Helm Charts. The Helm chart for our application can be found at helm.yml, and has the following contents: build: uri: https://github.com/kabir/vlog-mp-reactive-messaging-rhosak.git mode: bootable-jar deploy: replicas: 1 volumeMounts: - name: rhoas mountPath: /etc/config/rhoas readOnly: true volumes: - name: rhoas secret: secretName: rhoas This tells it to build a bootable jar of WildFly, which is a single jar containing both the relevant parts of WildFly and our application. Further, it says to only create one pod running WildFly, and mounts the rhoas secret we created earlier under the directory /etc/config/rhoas on the pod running the server. This directory will contain a file for each entry in our secret. The file name will be the name of the entry, and the contents of the file will be the value of the entry. When deploying an application into OpenShift using Helm, it will look for a Maven profile called openshift in the application’s POM. The relevant part of our pom.xml is: <profile> <id>openshift</id> <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>${version.wildfly-jar.maven.plugin}</version> <configuration> <feature-pack-location>wildfly@maven(org.jboss.universe:community-universe)#${version.server.bootable-jar}</feature-pack-location> <layers> <layer>cloud-server</layer> <layer>microprofile-reactive-messaging-kafka</layer> </layers> <plugin-options> <jboss-fork-embedded>true</jboss-fork-embedded> </plugin-options> <cli-sessions> <cli-session> <!-- do not resolve expression as they reference env vars that --> <!-- can be set at runtime --> <resolve-expressions>false</resolve-expressions> <script-files> <script>src/main/scripts/initialize-server.cli</script> </script-files> </cli-session> </cli-sessions> <cloud/> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> The org.wildfly.plugins:wildfly-jar-maven-plugin plugin is used to create a bootable jar containing the application. We tell it to use the following Galleon layers when provisioning the server jar: microprofile-reactive-messaging-kafka - this provides the MicroProfile Reactive Messaging functionality and the Kafka connector, as well as other dependencies needed by the Reactive Messaging implementation such as CDI. We briefly mentioned this layer in the Running the Application Locally section. cloud-server - this is a trimmed down base server, whose main aim is to offer Jakarta RESTful Web Services functionality along with server dependencies needed to support those. The plugin will also run the src/main/scripts/initialize-server.cli WildFly CLI script when configuring the server. It’s contents are: echo "Adding the 'rhoas' secret volume mount as a MicroProfile Config source..." /subsystem=microprofile-config-smallrye/config-source=rhosak-binding:add(dir={path=/etc/config/rhoas}) echo "Adding the MicroProfile Config entries mapping the secret values..." /subsystem=microprofile-config-smallrye/\ config-source=reactive-messaging-properties:add(properties={\ mp.messaging.connector.smallrye-kafka.bootstrap.servers=${KAFKA_HOST},\ mp.messaging.connector.smallrye-kafka.security.protocol=SASL_SSL,\ mp.messaging.connector.smallrye-kafka.sasl.mechanism=PLAIN,\ mp.messaging.connector.smallrye-kafka.sasl.jaas.config="\n\ org.apache.kafka.common.security.plain.PlainLoginModule required\n\ username=\"${RHOAS_SERVICE_ACCOUNT_CLIENT_ID}\"\n\ password=\"${RHOAS_SERVICE_ACCOUNT_CLIENT_SECRET}\";"\ }, ordinal=500) First of all it is worth noting that we don’t need to enable the MicroProfile Reactive Messaging and Reactive Streams Operators extensions/subsystems in this case. This is unlike when we were using the downloaded WildFly zip archive earlier. This is because when a server is provisioned using Galleon, the microprofile-reactive-messaging-kafka layer takes care of that for us. The first thing the CLI script does is mount the path /etc/config/rhoas (i.e. where our Helm chart told OpenShift to mount our rhoas secret) as a MicroProfile Config ConfigSource (in this case as a FileSystem ConfigSource supported by our underlying SmallRye implementation of MicroProfile Config). After this config source is mounted, we can reference values from it in other places that can use MicroProfile Config values. This is what we are doing in the next block, where we tell WildFly’s MicroProfile Config subsystem to add the following properties: mp.messaging.connector.smallrye-kafka.bootstrap.servers uses KAFKA_HOST from our rhoas secret. Adding this here overrides the value that we hardcoded in the microprofile-config.properties earlier. mp.messaging.connector.smallrye-kafka.security.protocol and mp.messaging.connector.smallrye-kafka.sasl.mechanism are used to secure the connection and enable authentication via SASL since RHOSAK is secured. The Security chapter of the Kafka documentation explains these values in more detail. mp.messaging.connector.smallrye-kafka.sasl.jaas.config sets up JAAS configuration to provide the RHOAS_SERVICE_ACCOUNT_CLIENT_ID and RHOAS_SERVICE_ACCOUNT_CLIENT_SECRET from our rhoas secret to autheniticate with RHOSAK. So in short the above configuration makes values from our secret available to WildFly, overrides the location of the Kafka server, and adds more MicroProfile Config properties to enable SSL and authentication. Deploying our application Now that we have configured everything properly, it is time to test our application! First you will need to install helm, and use it to add the wildfly Helm repostory as outlined in https://docs.wildfly.org/wildfly-charts/ Then from the root folder of your local copy of the example repository, run: $ helm install rhosak-example -f ./helm.yml wildfly/wildfly This will return quickly but that does not mean the application is up and running yet. Check the application in the OpenShift console or using oc get deployment rhosak-example -w. Essentially what happens is it starts two pods. One for you application, and another which is doing the build of the bootable jar. Once the build one is done and has published the resulting image, the pod running the application can start properly. Accessing our application running on OpenShift First we need the URL of our application on OpenShift: $ oc get route NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD rhosak-example rhosak-example-kkhan1-dev.apps.sandbox.x8i5.p1.openshiftapps.com rhosak-example <all> edge/Redirect None In my case the URL is rhosak-example-kkhan1-dev.apps.sandbox.x8i5.p1.openshiftapps.com. You should of course substitute that with the URL of your application in the following steps. Next, let’s add some entries using Curl: $ curl -X POST https://rhosak-example-kkhan1-dev.apps.sandbox.x8i5.p1.openshiftapps.com/one $ curl -X POST https://rhosak-example-kkhan1-dev.apps.sandbox.x8i5.p1.openshiftapps.com/two These will be sent to Kafka, and received again by the application which will keep a list of the most recently received values. Note that the https:// is needed - if left out, the commands will appear to work, but no data will actually be posted. To read this list of recently received values, we can run Curl again: $ curl https://rhosak-example-kkhan1-dev.apps.sandbox.x8i5.p1.openshiftapps.com [one, two] Conclusion Compared to running locally the RHOSAK steps look a lot more involved. However, we have achieved a lot! If we break down what we have actually done, it looks simpler: Use rhoas to set up Kafka, a topic, and a service account authorised to publish/consume messages Create a secret called rhoas containing the location of the Kafka instance and credentials to access it Configure our application to use it by: Mounting the secret under /etc/config/rhoas in the Helm Chart Use org.wildfly.plugins:wildfly-jar-maven-plugin to provision a trimmed down server with the required functionality run a CLI script when building the server to mount the /etc/config/rhoas folder as a MicroProfile Config ConfigSource and use values from that to override the location of the server, and add properties to turn on SSL, SASL authentication, and provide the credentials from our secret to authenticate I hope this guide will be helpful to people wanting to try RHOSAK from WildFly for the first time. ### [WildFly 27 Alpha4 is released](/news/2022/08/05/WildFly-27-Alpha4-is-released/) Today we have released the 27.0.0.Alpha4 version of WildFly, now available on the downloads page. This release serves as a major milestone on our way toward support for Jakarta EE 10 in WildFly, as it is the first release of standard WildFly that is based on the Jakarta EE APIs that are planned for the upcoming Jakarta EE 10 release. Until this release, only WildFly Preview has offered any kind of support for Jakarta EE beyond EE 8. As discussed in my January WildFly Release Plans for 2022 post, the main focus of the WildFly developers as we work on WildFly 27 is implementing Jakarta EE 10 support. That work has now reached a point where it’s useful for our community to have an early look at our planned EE 10 implementation. We’ve also done a WildFly Preview 27.0.0.Alpha4 release. The differences between standard WildFly and WildFly Preview are currently rather minimal, as the EE 9+ support that’s been WildFly Preview’s biggest calling card has now been brought into standard WildFly. A major difference between WildFly Preview and standard WildFly is Preview retains the feature that will bytecode transform deployments that use the EE 8 javax.* APIs so that they instead use the analogous jakarta.* APIs. We do not intend to include that feature in standard WildFly, but we’re retaining it in WildFly Preview, at least for now. (See 'WildFly Preview Support for EE 8 Deployments' in the 2020 Jakarta EE 9 with WildFly Preview announcement for more on this feature.) Note that we have not added a 'Servlet-Only Distribution' variant of WildFly to the downloads page. The WildFly project is no longer producing that distribution. I encourage users looking for the kind of slimmer server installation formerly provided by the 'Servlet-Only Distribution' to use Galleon to produce a server installation tailored to your needs. We’re also not releasing quickstarts or cloud images for this release. What’s New? In a nutshell, what’s new is that standard WildFly provides the EE 10 variant of all the EE specifications it has traditionally offered. EE 8 is no longer provided. The full list of issues resolved in Alpha 4 is available in the WFLY JIRA project. Note that we’ve produced two other Alphas since I blogged about the 27 Alpha 1 release. Those alphas primarily provided additional milestones on the way to providing EE 10 support in WildFly Preview. The issues resolved in Alpha2 are available here, while those in Alpha3 are here. Java SE Support You can run 27.0.0.Alpha4 on Java SE 11 or Java SE 17. The WildFly project no longer supports Java SE 8 in our feature releases, although our planned 26.1.2 bug fix release will support SE 8. Standards Support The 27.0.0.Alpha4 release is not a certified compatible implementation of any Jakarta EE specification, nor is it a certified compatible implementation of any MicroProfile specification. This is a milestone release for which we have not yet pursued any certification. Upcoming Releases Over the next couple of weeks the WildFly developers will be finalizing plans for when we will release WildFly 27.0.0.Beta1, 27.0.0.Final, and 26.1.2.Final. Our intent is to release the latter later this month; we just need to work out precisely when. Personally, I think aiming for a WildFly 27.0.0.Final in the September timeframe would be good, with a single feature complete Beta released a couple of weeks before the Final. It’s possible we will do a 27.0.0.Alpha5 before we move on to Beta1; if so I don’t think it will be a major change from Alpha4. Enjoy! Thank you for your continued support of WildFly. We’d love to hear your feedback at the WildFly forum. ### [Use the wildfly-maven-plugin to create a Docker image of your application](/news/2022/08/04/Use-the-wildfly-maven-plugin-to-create-a-Docker-image-of-your-application/) In this article, we will explain how a developer using the Docker image for WildFly can take advantage of the new capabilities of the wildfly-maven-plugin and the new WildFly runtime image to build their container image. We will describe the changes required to move to this new architecture. Once the changes are done, we will provide some examples of the benefits that can be gained from this new architecture. WildFly, Docker, S2I and what are the synergies? WildFly provides a Docker image at quay.io/wildfly/wildfly that provides a vanilla WildFly server based on its default standalone configuration. WildFly also provides Source-to-image (S2I) images to be able to create an application image from the application source using tools targeting OpenShift. These two types of images, the "vanilla" Docker image and the OpenShift S2I images, have no connection and no synergy. A lot of work has been done in WildFly around provisioning. The S2I images benefitted from this effort but the Docker image did not…​ until now. While S2I is a good technology to build application images on OpenShift, we realized that we could achieve a more flexible solution that would benefit other container platforms (Kubernetes, Azure) as well as users running WildFly on premise. We decided to focus on a Maven-centric approach to provision WildFly so that Maven (and the user) would be in control of the complete runtime (including the user deployment as well as the WildFly runtime). This Maven-centric approach can also benefit the users of the vanilla Docker image for WildFly and help them move to a consolidated architecture. WildFly Docker image There are different ways to use the quay.io/wildfly/wildfly image to create an application image (that would contain both WildFly and your deployments) but the simplest one is to add the deployment archive to this base image and let WildFly deploy it when it starts. As an example, we will start from a simple Java application, the microprofile-config quickstart. For the purpose of this exercise, the Java application is a blackbox and we will not look at it. We just want to ensure that we can create an application image that can run it. Let’s clone the repository and build the application: git clone https://github.com/wildfly/quickstart.git cd quickstart/microprofile-config mvn clean package Once the Maven build is finished, the deployment archive has been created in target/microprofile-config.war. At this point, we can use the WildFly Docker image to create the application image with a simple Dockerfile: FROM quay.io/wildfly/wildfly ADD target/microprofile-config.war /opt/jboss/wildfly/standalone/deployments/ Let’s build a wildfly-app image from this Dockerfile and run it locally: docker build -t wildfly-app . docker run -p 8080:8080 wildfly-app That’s all we needed to run WildFly and the application from docker. We can verify that it is working with: curl http://localhost:8080/microprofile-config/ and it replies MicroProfile Config quickstart deployed successfully. You can find the available operations in the included README file. WildFly Provisioning Architecture Let’s now move to the new architecture for WildFly. Jean-Francois Denise extensively described it in the WildFly S2I new architecture is final! article and focused on the Source-to-Image (S2I) capabilities of the architecture. In this article, we will see that this architecture also benefits users who are not using S2I and want to keep control of the creation of their application images. With this new architecture, the provisioning of WildFly (which provides the ability to download and create a distribution of WildFly fit for the application requirements) is handled by the Maven plugin org.wildfly.plugins:wildfly-maven-plugin. We can add it to the <build> section of application’s pom.xml to provision WildFly when the package goal is executed by Maven: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>4.0.0.Beta2</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:26.1.1.Final</location> </feature-pack> </feature-packs> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> If we run again mvn clean package, the wildfly-maven-plugin will provision WildFly using its feature-pack. Once maven is finished, there will be a target/server directory that contains WildFly and the application deployment. This means that you can directly run WildFly from this directory with the application deployed in it: ./target/server/bin/standalone.sh ... 12:32:00,134 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0010: Deployed "microprofile-config.war" (runtime-name : "microprofile-config.war") ... 12:32:00,196 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 26.1.1.Final (WildFly Core 18.1.1.Final) started in 8929ms - Started 423 of 623 services (341 services are lazy, passive or on-demand) - Server configuration file in use: standalone.xml This is the fundamental change with this architecture: the provisioning, capability trimming and customization of WildFly is now controlled by the application’s pom.xml. In that sense, the application’s pom.xml controls the full runtime of the application. You no longer need to install WildFly, create the deployment and deploy it in WildFly. Instead, the WildFly installation and the deployment is done as part of the Maven build process. You can really see your pom.xml as the central point of your application which is composed of the WildFly runtime and your deployment archive. To leverage this change, we have developed a new image quay.io/wildfly/wildfly-runtime-jdk11 that contains everything needed to run WildFly with OpenJDK 11. If we want to create an application image, we can change the Dockerfile to use this runtime image and add the target/server to it: FROM quay.io/wildfly/wildfly-runtime-jdk11 COPY --chown=jboss:root target/server $JBOSS_HOME RUN chmod -R ug+rwX $JBOSS_HOME Let’s build again the wildfly-app image from this updated Dockerfile and run it: docker build -t wildfly-app . docker run -p 8080:8080 wildfly-app We can see that there is no change from a caller perspective and the application can still be queried with: curl http://localhost:8080/microprofile-config/ Moving from WildFly Docker image to Runtime image Let’s review what is needed to move from the vanilla Docker image to the new runtime image for WildFly: add the org.wildfly.plugins:wildfly-maven-plugin to the application’s pom.xml update the Dockerfile to use the new runtime image and add the target/server directory Now that we have moved to the new architecture, what are the benefits of it? Capability Trimming WildFly provides capability trimming with layers so that WildFly is provisioned with only the components (mostly Java archives) that are needed to run your application and nothing more. There are two key benefits with capability trimming: It reduces the security risk as you are not subject to security attacks if the affected components are not present in application at all. It reduces the size of the server runtime. In our example, our microprofile-config quickstart requires MicroProfile to run. WildFly provides a convenient microprofile-platform that provisions everything that is needed to run MicroProfile applications. We can trim our runtime to only this layer by updating the wildfly-maven-plugin: <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:26.1.1.Final</location> </feature-pack> </feature-packs> <layers> <layer>microprofile-platform</layer> </layers> </configuration> If we package again the application with mvn clean package, we can notice that the size of the target/server went from 250M to 73M and a lot of jars that were not needed to run the application are no longer present. Packaging Scripts The wildfly-maven-plugin also provides the ability to execute JBoss CLI commands when WildFly is provisioned. This allows you to substantially modify the standalone configuration to better fit the application requirements. It has no impact on the application image as these scripts are only invoked during provisioning. As a basic example, let’s say we want to support Cross-Origin Resource Sharing (CORS) that requires to add some resources to the undertow subsystem. To active CORS in our application, we need to write a CLI script that creates these resources and put them in the application project in the src/main/scripts/cors.cli: echo Adding Undertow Filters for CORS # Access-Control-Allow-Origin /subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Allow-Origin":add() /subsystem=undertow/configuration=filter/response-header="Access-Control-Allow-Origin":add(header-name="Access-Control-Allow-Origin",header-value="${env.CORS_ORIGIN:*}") # Access-Control-Allow-Methods /subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Allow-Methods":add() /subsystem=undertow/configuration=filter/response-header="Access-Control-Allow-Methods":add(header-name="Access-Control-Allow-Methods",header-value="GET, POST, OPTION, PUT, DELETE, PATCH") # Access-Control-Allow-Headers /subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Allow-Headers":add() /subsystem=undertow/configuration=filter/response-header="Access-Control-Allow-Headers":add(header-name="Access-Control-Allow-Headers",header-value="accept, authorization, content-type, x-requested-with") # Access-Control-Allow-Credentials /subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Allow-Credentials":add() /subsystem=undertow/configuration=filter/response-header="Access-Control-Allow-Credentials":add(header-name="Access-Control-Allow-Credentials",header-value="true") # Access-Control-Max-Age /subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Max-Age":add() /subsystem=undertow/configuration=filter/response-header="Access-Control-Max-Age":add(header-name="Access-Control-Max-Age",header-value="1") We can then add this script to the wildfly-maven-plugin by extending its configuration: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>4.0.0.Beta2</version> <configuration> ... <packaging-scripts> <packaging-script> <scripts> <script>${project.build.scriptSourceDirectory}/cors.cli</script> </scripts> </packaging-script> </packaging-scripts> ... </configuration> </plugin> Once the pom.xml is modified, when you run mvn package, you can notice the CLI commands that are invoked during the packaging of the application: mvn clean package ... [INFO] --- wildfly-maven-plugin:4.0.0.Beta2:package (default) @ microprofile-config --- [INFO] Provisioning server in /Users/jmesnil/Developer/quickstart/microprofile-config/target/server ... [standalone@embedded /] echo Adding Undertow Filters for CORS Adding Undertow Filters for CORS ... With the ability to run CLI scripts when WildFly is provisioned, you are in total control of the configuration of WildFly. Feature-Packs WildFly uses feature-packs as the building blocks to provision the server. The most important feature-pack is WildFly’s own feature-pack: org.wildfly:wildfly-galleon-pack:26.1.1.Final to control the installation of WildFly itself. We are also providing additional feature-packs to provide additional capabilities to WildFly. It is out of scope of this article to list all of them but let’s discuss two interesting ones: The wildfly-cloud-galleon-pack provides a set of additional features allowing you to configure a WildFly server to work on the cloud. It adapts WildFly to run on orchestration platforms in an optimized way. In particular, it automatically routes server logs to the console, it provisions the health subsystem to monitor the server health with healthiness probes, etc. The wildfly-datasources-galleon-pack provides JDBC drivers and datasources for various databases. If you include this feature-pack, you only need to specify the layer corresponding to the databases you want to use (e.g. postgresql-datasource). You then only need to specify a few environment variables (e.g. DB URL and credentials) at runtime to connect to the database when WildFly is running. Conclusion The wildfly-maven-plugin is currently at version 4.0.0.Beta2 with a Final release planned for WildFly 27. It builds on top of the experience we gained from the Bootable Jar and provides a compelling architecture to control the full runtime (WildFly + the application deployments) from the application’s pom.xml. The full customization of WildFly (using feature-packs, packaging scripts, etc.) is controlled by the developer so that the runtime fits the user’s application. Creating a container image from this provisioned server is then just a matter of putting it in a runtime image that contains OpenJDK to run the application. We will continue to deliver the vanilla Docker image for WildFly but we are focusing on the new architecture and the new images to expand the capabilities of WildFly. We are looking forward to our users trying this new approach and validate how it improves their workflow. We will also start an open conversation to bring additional synergies between the Docker and S2I images for WildFly that could benefit the whole community. In particular, we want to bring new capabilities such as additional architectures (in particular linux/arm64), newer versions of the JDK (with 17 being the priority), etc. to all our images. If you see any issue or improvements for this new architecture, please open issues on the WFLY issue tracker. ### [Vlog: Encrypting a Filesystem Realm](/news/2022/07/07/Vlog-Encrypting-a-Filesystem-Realm/) ### [Securing Jakarta Enterprise Beans with mutual TLS authentication](/news/2022/06/21/Securing-Jakarta-Enterprise-Beans-with-mutual-TLS-authentication/) ### [Vlog: WildFly gRPC](/news/2022/06/09/Vlog-WildFly-gRPC/) ### [Vlog: Interview with Farah Juma](/news/2022/06/06/Vlog-Interview-with-Farah-Juma/) ### [Vlog: Configure TLS in WildFly using Let’s Encrypt certificate authority](/news/2022/06/02/Vlog-Configure-TLS-in-WildFly-using-Let-s-Encrypt-certificate-authority/) ### [WildFly 26.1.1 is released!](/news/2022/05/19/WildFly-26-1-1-is-released/) WildFly 26.1.1.Final is now available for download. It’s been about five weeks since the WildFly 26.1 release, so we’ve done a small bug fix update, WildFly 26.1.1. This includes an update to WildFly Preview. The full list of issues resolved in WildFly 26.1.1 is available here. Issues resolved in the WildFly Core update included with WildFly 26.1.1 are available here. Note that the release artifacts are available in public maven in the jboss.org maven repo but at the time of writing we’re aware of some issues with syncing artifacts from there to Maven Central, so there may be some delays before the 26.1.1.Final artifacts can be resolved from there. Enjoy! ### [WildFly Preview 27 Alpha1 is released!](/news/2022/05/12/WildFly-Preview-27-Alpha1-is-released/) Today we have released a 27.0.0.Alpha1 version of WildFly Preview. This release serves as a milestone on our way toward support for Jakarta EE 10 in WildFly Preview, and eventually in standard WildFly. As discussed in my January WildFly Release Plans for 2022 post, the main focus of the WildFly developers as we work on WildFly 27 is implementing Jakarta EE 10 support. That work has now reached a point in WildFly Preview where it’s useful to evaluate WildFly Preview as a compatible implementation of the new Jakarta EE Core Profile. In order to help with bringing the EE 10 Core Profile specification to completion, we’ve released WildFly Preview 27.0.0.Alpha1. Note that we are not adding 27.0.0.Alpha1 binaries for standard WildFly to the downloads page. Standard WildFly is still built with the Jakarta EE 8 APIs, but we plan to switch to EE 10 in our main branch soon, and we will not be doing a standard WildFly 27 Final release that supports EE 8. So, there is not much purpose looking at 27.0.0.Alpha1 for standard WildFly. (Its binaries can be found in the jboss.org maven repository though.) We’re also not releasing quickstarts or cloud images for this release. What’s New? A couple of noteworthy items in this release are support for CDI 4.0 (via Weld 5), including CDI Lite, along with the much-asked-for transition from Hibernate 5.3 to Hibernate 6. The full list of issues resolved is available in the WFLY JIRA project. Java SE Support You can run 27.0.0.Alpha1 on Java SE 11 or Java SE 17. The WildFly project no longer supports Java SE 8 in our feature releases, although our planned 26.1.1 and 26.1.2 bug fix releases will support SE 8. Standards Support The 27.0.0.Alpha1 release is not a compatible implementation of Jakarta EE 8 or 9.1, nor is it a compatible implementation of MicroProfile Platform 4.1 or 5. Strict specification compliance wasn’t a focus of this alpha release, other than a desire to be compatible with the EE 10 Core Profile once that specification is released. Upcoming Changes As discussed in my January WildFly Release Plans for 2022 post, WildFly 26.1 was the last WildFly feature release that will support Java SE 8, Jakarta EE 8 and MicroProfile 4.1, while WildFly Preview 26.1 was the last release that will support Jakarta EE 9.1. The WildFly 27 release will require Java SE 11 or higher and will support Jakarta EE 10 and MicroProfile APIs based on the jakarta.* package namespace. We plan to do a WildFly 26.1.1 bug fix release in May. Something different from previous releases is we also intend to do a WildFly 26.1.2 bug fix release in the July-August time frame. The aim of that release will be to deliver any critical fixes we’ve discovered, particularly security related items. We recognize that moving on from SE 8 and EE 8 may be a substantial task for many of our users, so we want to help ease that transition by providing an extra bug fix release. Enjoy! Thank you for your continued support of WildFly. We’d love to hear your feedback at the WildFly forum. ### [Vlog: WildFly Datasource configuration on OpenShift](/news/2022/05/11/Vlog-WildFly-Datasource-configuration-on-OpenShift/) ### [WildFly Cloud Testsuite](/news/2022/05/08/WildFly-Cloud-Testsuite/) In addition to the WildFly zip download familiar to a lot of our users, a big part of the WildFly story is that it is very usable on the cloud. And of course for that we have a lot of tests, many of which are currently private. We now have a proof of concept public cloud testsuite which can be found at https://github.com/wildfly-extras/wildfly-cloud-tests. It does not aim to run the full testsuite from https://github.com/wildfly/wildfly/tree/main/testsuite. Rather, we want to focus attention on areas relevant to the cloud. So far it includes tests for: our container launch scripts actually being able to connect to a database when configured with the documented environment variables to do so configmaps and secrets can be read by the MicroProfile subsystem being able to connect to Kafka provided by the Strimzi operator that we are able to execute CLI command and REST calls on a server running on a pod It is still a proof of concept, but is something we’re actively working on, so expect to see this grow and evolve as we identify more things we want to test. Once things are more settled we will move it over to the main wildfly organisation in GitHub. On the Java side, we are currently using Dekorate as our underlying framework, but are evaluating other alternatives. There are helpers to be able to connect to the correct pods running the application from the tests. More could be done to make the experience smoother. This will be done once we decide which framework to invest in. Also, it is quite flexible when it comes to the underlying framework, so we will be able to switch tests to something else in steps - it does not all need to be done in one go. Currently, the tests work against a locally running Kubernetes instance. This makes sense for the framework in its beginning since Openshift is based on Kubernetes, and of course very important for us to support. We will look at other cloud providers in the future, and also expand it to use Openshift as needed, i.e. when Kubernetes does not offer everything we need. The hope is that the testsuite can become a nice reference point for 'power users' to be able to see how to use WildFly on Openshift/Kubernetes, and provide ideas for how you can test your applications when running on OpenShift. Please see the project README for more instructions on how to write tests. If you would like to get involved, file issues in the https://github.com/wildfly-extras/wildfly-cloud-tests repository for things you would like to see implemented (as well as for bug reports). If you would like to discuss something more abstract, the repository also has discussions enabled. Enjoy :-) ### [Extending your configuration with YAML](/news/2022/04/26/Extending-your-configuration-with-YAML/) In WildFly the configuration is managed and stored in the standalone.xml. You have several ways to customize your configuration: edit the XML manually (which is not the recommended approach) or create jboss-cli scripts that you can run on each upgrade. So why propose a 'new' solution to customize a server configuration ? Well the idea was to be able to externalize the customization from the 'standard' provided configuration to facilitate server upgrades: just unzip the new release, install/provision your applications and run the same command line. This can also be done with cli scripts that are executed on boot. But those are a bit tricky to write since you have no idempotence on each boot. That’s why we have introduced a new way to do this by using YAML configuration files. The server will be started in read-only mode, that means that you can’t update the configuration and expect your changes to be persisted. Warning Please note that this feature is considered EXPERIMENTAL and thus is DISABLED by default. Activating the feature To enable that feature you need to add a ServiceLoader configuration in the org.jboss.as.controller*_ module. You need to create the following file: META-INF/services/org.jboss.as.controller.persistence.ConfigurationExtension containing a single line org.jboss.as.controller.persistence.yaml.YamlConfigurationExtension in the dir folder of the org.jboss.as.controller module. mkdir -p $WILDFLY_HOME/modules/system/layers/base/org/jboss/as/controller/main/dir/META-INF/services/ echo 'org.jboss.as.controller.persistence.yaml.YamlConfigurationExtension' > $WILDFLY_HOME/modules/system/layers/base/org/jboss/as/controller/main/dir/META-INF/services/org.jboss.as.controller.persistence.ConfigurationExtension Writting the YAML Warning Note that the YAML structure doesn’t follow the XML model but the management model resource tree that is defined for jboss-cli. The goal of the YAML files is to be able to customize an existing configuration. It is not here to replace the existing configuration support with XML. As such we won’t support part of the management model. Only those elements would be supported: core-service interface socket-binding-group subsystem system-property That means that at least those entries would be ignored: extension: to add extension to the server as this might require modules which can be missing. deployment: to add deployments to the server as this require more that just some configuration. deployment-overlay: to add deployment-overlays to the server as this require more that just some configuration. path: since those should already have been defined when the YAML files are parsed. The YAML root node must be wildfly-configuration, then you can follow the model tree to add, remove or update resources. If a resource is already present (created by the XML or a previous YAML file) then we will update it, otherwise we will create it. Sample YAML file to define a new PostGresql datasource: wildfly-configuration: subsystem: datasources: jdbc-driver: postgresql: driver-name: postgresql driver-xa-datasource-class-name: org.postgresql.xa.PGXADataSource driver-module-name: org.postgresql.jdbc data-source: PostgreSQLDS: enabled: true exception-sorter-class-name: org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter jndi-name: java:jboss/datasources/PostgreSQLDS jta: true max-pool-size: 20 min-pool-size: 0 connection-url: "jdbc:postgresql://localhost:5432}/demo" driver-name: postgresql user-name: postgres password: postgres validate-on-match: true background-validation: false background-validation-millis: 10000 flush-strategy: FailingConnectionOnly statistics-enable: false stale-connection-checker-class-name: org.jboss.jca.adapters.jdbc.extensions.novendor.NullStaleConnectionChecker valid-connection-checker-class-name: org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker transaction-isolation: TRANSACTION_READ_COMMITTED As you can see, we are defining a jdbc-driver called postgresql and a data-source called PostgreSQLDS. Note Note that binaries is not managed by the YAML file, you need to create or provision the org.postgresql.jdbc module. Operations We also provide three operations using tags to provide more flexibility in what you can do with the YAML file. !undefine: to undefine an attribute Sample YAML file to undefine the CONSOLE logger level: wildfly-configuration: subsystem: logging: console-handler: CONSOLE: level: !undefine !remove: to remove the resource Sample YAML file to remove the embedded Artemis broker and connect to a remote broker: wildfly-configuration: socket-binding-group: standard-sockets: remote-destination-outbound-socket-binding: remote-artemis: host: localhost port: 61616 subsystem: messaging-activemq: server: default: !remove remote-connector: artemis: socket-binding: remote-artemis pooled-connection-factory: RemoteConnectionFactory: connectors: - artemis entries: - "java:jboss/RemoteConnectionFactory" - "java:jboss/exported/jms/RemoteConnectionFactory" enable-amq1-prefix: false user: admin password: admin ejb3: default-resource-adapter-name: RemoteConnectionFactory ee: service: default-bindings: jms-connection-factory: "java:jboss/RemoteConnectionFactory" !list-add: to add an element to a list (with an optionnal index). Sample YAML file to add a RemoteTransactionPermission to the permissions list at the position 0: wildfly-configuration: subsystem: elytron: permission-set: default-permissions: permissions: !list-add - class-name: org.wildfly.transaction.client.RemoteTransactionPermission module: org.wildfly.transaction.client target-name: "*" index: 0 As you may have noticed the index attribute doesn’t exist. It is used to know where to place the entry. If none is defined then the entry will be appended to the list. Starting with YAML files Using the --yaml or -y argument you can pass a list of YAML files. Each path needs to be separated by the File.pathSeparator. It is a semicolon (;) on Windows and colon (:) on Mac and Unix-based operating systems. Paths can be absolute, relative to the current execution directory or relative to the standalone configuration directory. ./standalone.sh -y=/home/ehsavoie/dev/wildfly/config2.yml:config.yml -c standalone-full.xml YouTube video player ### [New Bootable JAR example - Persistent clustered EJB timers](/news/2022/04/22/New-Bootable-JAR-example-Persistent-clustered-EJB-timers/) The new release of the WildFly Bootable JAR Maven plugin (7.0.1.Final) contains a new example to demonstrate how to build an application that employs clustered EJB timers, which currently rely on a JDBC based persistence storage. All examples in WildFly Bootable JAR Maven plugin 7.0.1.Final have been updated to use 26.1.0.Final. Use case The example use case is related to automatic timers in clustered environments. In such a scenario all the running application instances will execute the scheduled method, i.e. each timer would be executed multiple times, thus breaking the application logic. Persistent timers can be used in the above case to avoid such behavior in clustered environments, since the WildFly timer service implementation allows for the user to configure a JDBC based persistent storage for EJB timers. This is a mean for timer executors to synchronize so that a given timer execution is performed by exactly one of the running application instances. Such capabilities are provided by the related EJB Galleon layer and require specific configuration, which is included in the example. Persisting timers to a database service The example application defines an automatic timer which is executed every 10 seconds. It requires for one Postgresql instance and two replicas of the example application to be deployed on OpenShift. In order to achieve the behavior described above, a database service needs to be deployed beforehand - see the example instructions - and the following two configuration aspects must be taken into account. Connecting to a JDBC based persistence storage Similar to the Postgresql example, this is achieved by adding the postgresql-datasource Galleon layer to the Bootable JAR application configuration. <!-- ... --> <feature-packs> <feature-pack> <location>wildfly@maven(org.jboss.universe:community-universe)#${version.wildfly}</location> </feature-pack> <feature-pack> <groupId>org.wildfly</groupId> <artifactId>wildfly-datasources-galleon-pack</artifactId> <version>${version.wildfly.datasources.galleon-pack}</version> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>ejb</layer> <layer>postgresql-datasource</layer> </layers> <!-- ... --> This layer provides the application with all the bits needed to connect a Postgresql data source, including a default JNDI entry. The application must as well include a JPA persistence unit definition , in order to define the data source connection properties: <persistence-unit name="primary"> <jta-data-source>java:jboss/datasources/PostgreSQLDS</jta-data-source> <properties> <!-- Properties for Hibernate --> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> <!-- ... --> </properties> </persistence-unit> Setting the EJB timer service store The ejb3 subsystem must be configured so that timers can be persisted to Postgresql, since the default behavior would use a local, file system based, storage. This is achieved by configuring the bootable JAR through a CLI script. The script will do the following: add a new database-data-store resource, which is referencing the datasource JNDI entry installed by the posgresql-datasource Galleon layer, to the ejb3 subsystem timer-service: /subsystem=ejb3/service=timer-service/database-data-store=ejb-timers-ds:add(datasource-jndi-name=java:jboss/datasources/PostgreSQLDS, database=postgresql, partition=ejb-timers-ds-part) set the ejb3 subsystem timer-service resource default-data-store attribute to the name of the newly created datasource: /subsystem=ejb3/service=timer-service:write-attribute(name=default-data-store, value=ejb-timers-ds) Building and deploying on Openshift via Helm Chart for WildFly The new example also shows how to deploy the application on OpenShift by using Helm and the Helm Chart for WildFly. A cluster of the example Bootable JAR application instances is created on OpenShift, according to the helm.yaml definition. Here is where we define the environment variables needed to connect to a database service, so that Helm will add them to the final deployment. In conclusion EJB timers are a popular feature, and their usage in clustered architectures has some peculiar configuration and execution aspects. The new example demonstrates how to configure a WildFly Bootable JAR application in order to allow for unique timer execution in a clustered environment. Fabio Burzigotti ### [New WildFly on the cloud architecture](/news/2022/04/20/New-WildFly-on-the-cloud-architecture/) We have released the new components that make for a completely redesigned WildFly cloud experience. This redesign allows for more flexibility, simpler workflows and smaller application images. Our new cloud architecture is composed of 5 main components: New WildFly Source-to-Image (S2I) builder images (JDK11 and JDK17) New WildFly runtime images (JDK11 and JDK17) New WildFly Maven plugin 3.0.0.Final New WildFly cloud Galleon feature-pack 1.0.0.Final New Helm Chart for WildFly 2.0 The new S2I workfow can be summarized as: Configure the WildFly Maven plugin to deploy your application in the WildFly server of your choice, finely tuned according to your needs (an example)! Make your application sources available in a GIT repository (an example). Define a Helm Chart for WildFly yaml file (an example). Install your Helm file into OpenShift (an example). You are done! To get you familiar with the various components you can directly jump to these examples. They will drive you through various use-cases from source to deployment on OpenShift (for immediate access to an OpenShift cluster, you can use OpenShift sandbox). Legacy WildFly S2I and runtime centos7 images We have released the legacy images for WildFly 26.1.0.Final in quay.io/wildfly. We are not planning to release any centos7 images starting WildFly 27. Note When using the legacy S2I images for WildFly, you must stay on the 1.x version of the Helm Chart for WildFly: helm install my-legacy-app -f helm.yaml wildfly/wildfly --version ^1.x New WildFly S2I and runtime images We have released our new UBI8 minimal based images: quay.io/wildfly/wildfly-s2i-jdk11 S2I builder image. quay.io/wildfly/wildfly-s2i-jdk17 S2I builder image. quay.io/wildfly/wildfly-runtime-jdk11 runtime image. quay.io/wildfly/wildfly-runtime-jdk17 runtime image. S2I builder images and runtime images, although directly usable from docker build (an example of docker image built from a WildFly runtime image can be found here) or S2I tooling, are best used when using Helm Chart for WildFly. Helm Chart create smart chained builds in order to output lightweight application images running on the runtime of your choice (JDK11 or JDK17). Detailed documentation can be found there. Universal Base Image 8 Minimal Our new images are based on Universal Base Image. The UBI8 image has been designed and engineered to be the base layer for containerized applications. The Minimal flavor is a stripped down image. Relationship with the openjdk S2I images Our new images are sharing the Java VM configuration API with the openjdk images. This has multiple benefits: JDK alignement. Benefit from latest updates. JVM configuration alignment. Benefit from the same automatic tuning and configuration of Java VM. In the end you are getting an homogeneous user experience whatever the kind of WildFly server packaging you have chosen: WildFly Bootable JAR that runs on the openjdk images or WildFly that runs on our new images. An S2I builder image decoupled from WildFly server S2I builder images are generic and can be used to deploy application for any WildFly server version. Builder images have no dependency on a WildFly server release (as opposed to the legacy centos7 WildFly images that are bound to a given server version). You can even run Jakarta EE8 or Jakarta EE9-based application from these images. The PostgreSQL example and PostgreSQL Jakarta EE9 example are identical applications deployed on different kind of WildFly server. Just a matter of choosing the right Galleon feature-packs to assemble the right server. Release of the new images Images release cadence is now decoupled from the WildFly server release cadence. Images have their own lifecycle. New releases will be done to address fixes and new features. Released images are deployed in the quay.io/wildfly organization For the one that love to be on the bleeding edge we are constantly deploying images under development to the quay.io/wildfly-snapshots organization. Using the JDK 17 S2I builder image Applications are built and run similarly on JDK11 and JDK17. For JDK17 just make sure to have your maven projects to use 3.3.2 version for the Maven war plugin. This example shows how to configure the Maven war plugin version. Note When using JDK17 images of a version < 1.0.2, you need to set the following env variable to workaround WFCORE-5835: JAVA_OPTS_APPEND=--add-exports=jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED The latest JDK17 images have been fixed. Multiarch images preview We have released preview of Multiarch images (linux/amd64 and linux/arm64). Longer term we plan to make our official images multi arch and stop releasing the preview images, but we are not yet there. Multi arch preview images: https://quay.io/repository/wildfly-snapshots/wildfly-s2i-jdk11-multi-arch preview multi arch JDK11 S2I builder image. https://quay.io/repository/wildfly-snapshots/wildfly-s2i-jdk17-multi-arch preview multi arch JDK17 S2I builder image. https://quay.io/repository/wildfly-snapshots/wildfly-runtime-jdk11-multi-arch preview JDK11 multi arch runtime image. https://quay.io/repository/wildfly-snapshots/wildfly-runtime-jdk17-multi-arch preview JDK17 multi arch runtime image. New s2i build workflow In order to create a server to be installed into the WildFly image we are relying on the WildFly Maven plugin 3.0.0.Final that can now provision a fully configured server containing your deployment. The WildFly Maven plugin 3.0.0.Final has been evolved with some new goals to provision, configure, and package the server and the deployment in one step. When designing your application pom file, add an execution of the WildFly Maven plugin package goal, configure it with the WildFly Galleon feature-pack and Galleon layer(s), and optionally reference WildFly CLI scripts to be executed and content to be copied inside the server. At the end of the build you will get (by default in the target/server directory) a server with your app deployed, ready to be installed in the image. In order to allow for a smooth transition to the new images, we are still supporting (in a deprecated way) the legacy workflow. Your existing application would work, but you are now required to specify the Galleon feature-pack(s) and layer(s) (GALLEON_PROVISION_FEATURE_PACKS and GALLEON_PROVISION_LAYERS env variables) you want to provision during the S2I build. Execution time server configuration Application images built from the WildFly S2I builder or runtime images both expose the same API allowing you to fine tune the server execution. This API is exposed by means of environment variables to be set when configuring your deployment. JVM configuration API The JVM env variables that are used today with WildFly s2i images are still supported. They are a nice way to tune the JVM. WildFly server startup configuration API The new server startup configuration API is described in this documentation. This API comes with default values that should cover the main use-cases. 2 env variables open-up new possibilities: SERVER_ARGS allows you to pass WildFly server arguments when starting the server. CLI_LAUNCH_SCRIPT allows you to provide a path (relative to JBOSS_HOME or absolute) to a CLI script to be executed at startup time. Although CLI scripts should be executed at build time from the WildFly Maven plugin, in some cases it can be useful to adjust the configuration at execution time. You can package a set of CLI scripts inside your server at build time, then reference one of these CLI scripts to be executed at runtime. WildFly server subsystems configuration API If you are using WildFly s2i images you are perhaps asking yourself where are the env variables you have been using to configure the elytron subsystem, to add datasources, to configure logging or the microprofile-config subsystem,…​ They are provided by means of a new WildFly cloud Galleon feature-pack that you can combine with the WildFly Galleon feature-pack at build time to produce a server supporting these env variables. If you only provision org.wildfly:wildfly-galleon-pack:26.1.0.Final you will get a "vanilla" WildFly server that will get lightly adjusted by the image entrypoint to properly execute on OpenShift. If you provision org.wildfly:wildfly-galleon-pack:26.1.0.Final and org.wildfly.cloud:wildfly-cloud-galleon-pack:1.0.0.Final you will get a WildFly server pre configured for cloud execution ready to be configured thanks to the environment variables the cloud feature-pack exposes. 2 variants exist of the cloud feature-pack: org.wildfly.cloud:wildfly-cloud-galleon-pack to be used with org.wildfly:wildfly-galleon-pack to provision an EE8 server as shown in this example. org.wildfly.cloud:wildfly-preview-cloud-galleon-pack to be used with org.wildfly:wildfly-preview-feature-pack to provision a Jakarta EE9 server as shown in this example. Detailed documentation can be found there. Examples We have defined a set of examples to help you get started. They cover different use-cases that highlight the new capabilities. The examples rely on Helm Chart for WildFly to automate the build and deployment on OpenShift. In order to deploy the examples onto OpenShift, you can log in to the Developer Sandbox for Red Hat OpenShift. The use cases covered are: Cloud default configuration, an application that interacts with a postgresql database. The projects shows how to provision a server configured in a way that is similar to the default WildFly server presents in the legacy WildFly cento7 image. Docker build, highlights the steps needed to build a docker image that contains the server and your application. JSF, EJB application, simple application. Keycloak integration. Use WildFly elytron-oidc-client to interact with a Keycloak server. Also highlights the ability to provide server arguments at launch time. Logging. We all need to enable logging at some point. With a simple CLI script executed at server boot time, enable logging and redirect all traces to the CONSOLE. PostgreSQL. Create a WildFly application with support for postgreSQL database. PostgreSQL Jakarta EE9. Create a WildFly application with support for postgreSQL database. The running server and application are both compliant with Jakarta EE9. Clustering. A cluster of PODS that share web sessions. This example benefits from the WildFly cloud feature-pack and Helm Chart for WildFly capabilities to automatically enable the dns.DNS_PING JGroups protocol and generate the ping service. Enjoy! and…​keep us posted with your feedback. (You can log these as new project issues.) Thank-you! JF Denise ### [Client side default SSL context provider](/news/2022/04/19/Client-side-default-SSL-context-provider/) ### [Encrypting Pre-Existing Filesystem realms](/news/2022/04/19/Encrypting-Pre-Existing-Filesystem-realms/) ### [Encrypting Filesystem realms](/news/2022/04/19/Encrypting-Filesystem-realms/) ### [Improving readability of certificate read commands](/news/2022/04/19/Improving-readability-of-certificate-read-commands/) ### [New Security Features in WildFly 26.1](/news/2022/04/19/New-Security-Features-in-WildFly-26-1/) ### [WildFly 26.1 is released!](/news/2022/04/14/WildFly-26-1-is-released/) I’m pleased to announce that the WildFly 26.1 Final zip is now available for download. As I discussed in my January WildFly Release Plans for 2022 post, the primary work being done by the WildFly developer community since the start of this year has been aimed toward a feature-boxed WildFly 27 release, with the main targeted feature being Jakarta EE 10 support in standard WildFly. But while WildFly 27 will be feature-boxed and release when ready, we did want to deliver one more feature release to our community on our existing roughly quarterly schedule. We also intend to remove Java SE 8 and Jakarta EE 8 support from WildFly 27, so we wanted to give our community one more feature release that still supports that SE / EE combination. Hence, WildFly 26.1 New Features There are number of new features in this release: Batch A new management attribute execution-records-limit has been added to the batch job repository resources (both in-memory and JDBC based). When set, the job repository will never return more than the specified number of job execution instances. Setting this attribute is useful in situations when the job repository stores an unusually large number of job executions, which can cause delays during application deployments or out-of-memory errors when trying to display the list of executions in the Web Console. JCA The ability to configure the resource adapter validation log directory has been added. This allows administrators to see the results of the validation performed by IronJacamar. The datasources subsystem allows the configuration of custom classes for datasource validation (exception-sorter, valid-connection-checker, stale-connection-checker). For each of these the ability to specify the name of the JBoss Modules module where the classes can be found has been added, removing the need to modify the WildFly internal module configuration to make them accessible. JMS Apache Artemis now deletes queues in an asynchronous way using a scheduled thread. The frequency at which queues marked to be deleted are effectively deleted is something users need to be able to configure. So we added a new address_queue_scan attribute to allow users to set the period between each deletion. MicroProfile The MicroProfile Config with SmallRye subsystem now supports using a directory as a root for several MicroProfile ConfigSource directories, removing the need to define several ConfigSource directories if they share the same parent directory. Security The Elytron client now provides a new java security provider that can be used to load a default SSL context. When you register this provider in your JVM with high enough priority, then all client libraries that use SSLContext.getDefault() will obtain an instance of the SSL context that is configured to be the default in the Elytron client configuration. This way you can make use of the Elytron client’s SSL context configuration without interacting with the Elytron API directly. It is now possible to encrypt with a SecretKey the identities that are stored on the local filesystem when using an Elytron filesystem-realm. It is also possible to encrypt a filesystem realm that already exists to be compatible with these new changes. The management operations exposed by the Elytron key store resources have been enhanced to improve readability of the read-alias output and to make read-aliases more versatile. Java SE Support You can run WildFly 26.1 or WildFly Preview 26.1 on any of the long-term support Java SE releases, including Java SE 17. We’ve tested WildFly heavily on Java SE 8, Java SE 11 and Java SE 17. Our testing included testing WildFly Preview on SE 17 with the massive Jakarta EE 9.1 TCK. (More on that in the 'Standards Support' section below.) The most heavily tested SE options for WildFly are still SE 11 and SE 8, because both WildFly and its component library projects have so many years of testing on those versions. While we recommend using an LTS JDK release, I do believe WildFly runs well on JDK 18. By runs well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. Note that we make no attempt to ensure the projects producing the various libraries we integrate are testing their libraries on JDK 18. Please note that WildFly runs on Java 11 and later in classpath mode. Running WildFly with SE 17 Because SE 17 is probably new to a great many WildFly users, I’m continuing to copy over this next bit from the WildFly 25 release announcement. One of the key differences in SE 17 versus the previous LTS SE 11 release is that the JVM will reject reflective access calls that SE 11 would only warn about, unless the JVM launch command includes JPMS configuration options to allow that access. WildFly does quite a bit of deep reflection, so part of our efforts in recent releases has been to identify the necessary JPMS settings. We have added those to our standard launch scripts, so WildFly should just work if you’re using those. The manifest file in a WildFly bootable jar will also include these settings. But some users may not be using a bootable jar or using our launch scripts to launch WildFly. For example many users use IDEs to launch WildFly and count on the IDE to provide arguments to the JVM. And IDEs may not be using the necessary settings yet. If you are launching a WildFly instance on SE 17 and aren’t using a bootable jar or our launch scripts, here are the JPMS settings you will need: --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED Not all uses of the server will require all of those; the launch script sections that set those up include comments describing the main reason we’ve added each. It’s possible your application may do something that requires additional JPMS settings; if so you can add those to the JVM launch command by editing the bin/standalone.conf or bin/domain.conf file or their .bat or .ps1 variants. Standards Support The standard WildFly 26.1.0 distribution is a Jakarta EE 8 compatible implementation, compatible with both the Full Platform and the Web Profile. Evidence supporting our certification is available for the Full Platform and for the Web Profile. The standard WildFly 26.1 distribution is also a compliant implementation of the MicroProfile 4.1 platform specification. This has been demonstrated on SE 8, SE 11 and SE 17. The WildFly Preview distribution released today is a compatible implementation of both the Jakarta EE 9.1 Web Profile and the Full Platform. WildFly Preview has been able to demonstrate compatibility while running on both Java SE 11 and on Java SE 17. Evidence supporting our certification is available for the Full Platform on SE 11, for the Web Profile on SE 11, for the Full Platform on SE 17 and for the Web Profile on SE 17. The WildFly Preview 26.1 distribution is also a compliant implementation of the MicroProfile 5.0 platform specification. This, too, has been demonstrated on SE 8, SE 11 and SE 17. Upcoming Changes As discussed in my January WildFly Release Plans for 2022 post, WildFly 26.1 will be the last WildFly feature release that supports Java SE 8, Jakarta EE 8 and MicroProfile 4.1, while WildFly Preview 26.1 will be the last release that supports Jakarta EE 9.1. The WildFly 27 release will require Java SE 11 or higher and will support Jakarta EE 10 and MicroProfile APIs based on the jakarta.* package namespace. As with other feature releases we’ve done for the last several years, we plan to do a WildFly 26.1.1 bug fix release about a month from now. Something different from previous releases is we also intend to do a WildFly 26.1.2 bug fix release in the July-August time frame. The aim of that release will be to deliver any critical fixes we’ve discovered, particularly security related items. We recognize that moving on from SE 8 and EE 8 may be a substantial task for many of our users, so we want to help ease that transition by providing an extra bug fix release. Documentation The WildFly 26.1 documentation is available at the docs.wildfly.org site. The WildFly 26.1 management API documentation is in the wildscribe section of the WildFly 26.1 docs. Jira Release Notes The full list of issues resolved is available in the WFLY JIRA project. Issues resolved in the WildFly Core 18.1 release included with WildFly 26.1 are available in the WFCORE JIRA project. Enjoy! Thank you for your continued support of WildFly. We’d love to hear your feedback at the WildFly forum. ### [Vlog: Build and Deploy WildFly Quickstarts on OpenShift](/news/2022/04/04/Vlog-Build-and-Deploy-WildFly-Quickstarts-on-OpenShift/) ### [Vlog: Introducing the wildfly.org YouTube Channel](/news/2022/04/04/Vlog-Introducing-the-wildfly-org-YouTube-Channel/) ### [Vlog: Securing a WildFly Application with OpenID Connect on OpenShift](/news/2022/04/04/Vlog-Securing-a-WildFly-Application-with-OpenID-Connect-on-OpenShift/) ### [Vlog: HAL Standalone Mode](/news/2022/04/04/Vlog-HAL-Standalone-Mode/) ### [WildFly 26.1 Beta S2I images have been released on quay.io](/news/2022/03/29/WildFly-26-1-Beta-S2I-images-have-been-released-on-quay-io/) WildFly 26.1 Beta S2I Docker images The WildFly S2I (Source-to-Image) builder and runtime Docker images for WildFly 26.1 Beta have been released on quay.io/wildfly. For complete documentation on how to use these images using S2I, OpenShift and Docker, refer to the WildFly S2I README. Anticipating a future set of WildFly images The quay.io/wildfly/wildfly-centos7 and quay.io/wildfly/wildfly-runtime-centos7 have been deprecated since WildFly 26. When building or running the server, a deprecation notice is displayed in the console. This WildFly 26.1 Beta and the following 26.1 Final images will be the latest released in quay.io. We have started our migration to the new WildFly S2I images that will be released for WildFly 26.1. The new architecture is based on the WildFly Maven plugin 3.0 and a new pair of docker images. This post has provided the details of this new approach. Stay tuned! JF Denise ### [WildFly 26.1 Beta1 is released!](/news/2022/03/24/WildFly-26-1-Beta1-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 26.1.0.Beta1 releases are available for download at https://wildfly.org/downloads. Whilst normally at this point we would be bringing the Beta for the next major release our main branch is being used for active development for the upcoming support of Jakarta EE 10 so we are releasing a minor release in the WildFly 26 stream to bring some new features. Here are the features specifically backported to this release. Batch WFLY-15525 - JBeret: Make it possible to limit number of records retrieved via a JDBC store JCA WFLY-14266 - JCA: enable configuration of resource adapter validation log directory WFLY-14347 - Allow to configure module for custom validation classes JMS WFLY-15926 - Add an attribute to be able to define the address_queue_scan period MicroProfile WFLY-15832 - MP Config: Ability to specify root config source directory Security WFLY-14846 - Automatic registration of client side / JVM wide default SSLContext WFLY-15075 - Add encryption support to FileSystemSecurityRealm WFLY-16137 - Enchance keystore CLI commands Over the next couple of weeks we will be working on bug fixes needed for WildFly 26.1.0.Final so please try out this Beta release and let us know if you hit any bugs so we can review if we can address them. For more information about the changes included in this release please consult the release notes. I would like to thank everyone who has contributed to this release, especially whilst in parallel working hard on tasks needed to support Jakarta EE 10 in our future releases. Release Notes The release notes for the release are here, with issues fixed in the underlying WildFly Core beta listed here. Please try it out and give us your feedback, while we get to work on WildFly 26.1 Final! Best regards, Darran ### [WildFly Release Plans for 2022](/news/2022/01/21/WildFly-Release-Plans-for-2022/) In my Changes are coming to WildFly post last September, I tried to give a sense of how the transition to Jakarta EE 10 was likely to impact the next few WildFly releases. With WildFly 26 out the door and our efforts for 2022 ramping up, I want to give our community on update on how we see things playing out over the course of the year. The tl;dr; of this is WildFly will be moving away from time-boxed major feature releases for 2022, and will instead produce feature-boxed majors when key feature sets like EE 10 are ready. We do, however, want to produce updates for our community, so in the March timeframe we’ll be doing a WildFly 26.1 release. Before I get into the details, first a bit of explanation of how the WildFly project operates. Current WildFly Development and Release Practices Since the WildFly 12 release, the WildFly project has followed a roughly time-boxed development model. Roughly every three months we endeavor to produce a new WildFly major release, with a large set of features, enhancements and bug fixes. We don’t operate on a strict time schedule, but we avoid significant schedule delays just to bring in particular feature or set of features. If a feature doesn’t make a particular release it can just go in the next one a few months later. The vast majority of the work on WildFly, both for features and bug fixing, is on our main branch, aimed at producing the next WildFly major. When we release each major we also create a new branch specific to that major. That branch is used to produce one micro (primarily bug fix) release for the major, with the micro usually released about a month after the major. This too is roughly time-boxed. We just released WildFly 26.0.1 today. The number of changes in the micro is typically small compared to what’s gone into main in the same period, as we want to be particularly conservative about introducing bugs or behavior changes in the micro. We’ve been consistently producing these micros since WildFly 17.0.1, and had done a few prior to that as well. Moving to Feature-Boxed Development for 2022 Time-boxed releases work well most of the time but they can be problematic when a large interrelated set of features need to come in as a block. Say, for example, Jakarta EE 10! Trying to fit all of our EE 10 work into a single quarterly release is not looking practical, and using time boxing for EE 10 isn’t conceptually valid, as Jakarta’s work on EE 10 itself isn’t time-boxed. So, we’ve decided to make WildFly 27 feature-boxed, with EE 10 as the primary feature set. We’ll produce WildFly 27.0.0.Final when we are satisfied that we’ve met our feature goals. When that will be done is uncertain, partly because it depends on when EE 10 itself goes GA. For sure we won’t be done in March, when our next major normally would be released. Typically for a WildFly major we produce a single feature-complete Beta release a couple weeks before the Final release. It’s likely that for 27 we’ll also produce at least one interim, not-feature-complete release, probably labeled as an Alpha. I expect WildFly 28 will be feature-boxed as well. My instinct is once the EE 10 work is complete we’ll have a big enough further set of work that is best done as a unit to justify doing another feature boxed release. Late in 2022 or early in 2023 I’d like for the project to move back to quarterly time boxing. I think most of the time that is the better way to deliver software. WildFly 26.1 We don’t want to entirely move away from our quarterly feature releases though. We want to make some features available to our users without waiting for WildFly 27, and we want to have a vehicle for releasing some bug fixes. So, in the roughly March timeframe when we would have done our next feature release, we plan to release a WildFly 26.1. However, the feature and bug fix payload for this release will be significantly smaller than what would be included in a typical WildFly quarterly release. Our development efforts this quarter will largely be focused on WildFly 27. We’ll also do a 26.1.1 release roughly a month after 26.1.0. If it makes sense we may do a WildFly 27.1 as well, later this year. Major Changes Coming in WildFly 27 When WildFly 27 is released there will be large changes compared to WildFly 26: We don’t plan to support Jakarta EE 8 in standard WildFly. The WildFly 26.1 releases will be the last that support EE 8. We don’t plan to support Java SE 8 in WildFly 27. The WildFly 26.1 releases will be the last that support SE 8. WildFly 27 will require SE 11 or later. We don’t plan to support MicroProfile 4.1 in WildFly 27. The WildFly 26.1 releases will be the last that support MicroProfile 4.1. We will likely drop support for Log4j 1. With all the other major changes coming in 27, it seems like the right time to stop providing Log4j 1, and just have users who need it package it in their deployments. So, the WildFly 26.1 release will be the last feature release that support EE 8 and SE 8. With WildFly 27 we’ll have moved on to EE 10, SE 11/17 and MicroProfile 5. We plan to continue to produce WildFly Preview. The primary use case for it at its inception was as a preview of our EE 9+ support, but from the start it was meant to be a general purpose way of providing a look at things not yet appropriate for standard WildFly, and there’s still a need for that. It wouldn’t surprise me though if the difference between WildFly 27 and WildFly Preview 27 is fairly small, while we focus our energies on completing EE 10. We’re also strongly considered no longer producing the "Servlet-only distribution" of WildFly that can be found on the download page for each WildFly release. We don’t see much evidence of this distribution being used, Galleon can easily be used to provision an equivalent server, and producing that distribution requires a non-trivial amount of work that could that could be applied elsewhere. I’d like to hear from the WildFly community about this, so I started a thread on the WildFly forum. Questions? If you have questions or want to provide feedback, I encourage you to post on the WildFly forum, on the wildfly-dev mail list or in Zulip chat. I will be starting threads on the forum and wildfly-dev list about this topic. Best regards, Brian ### [WildFly 26.0.1 is released!](/news/2022/01/21/WildFly-26-0-1-is-released/) WildFly 26.0.1.Final is now available for download. It’s been about four weeks since the WildFly 26 release, so we’ve done a small bug fix update, WildFly 26.0.1. This includes an update to WildFly Preview. The full list of issues resolved in WildFly 26.0.1 is available here Enjoy! ### [Multi-tenancy Support for OpenID Connect Applications](/news/2022/01/21/Multi-tenancy-Support-for-OpenID-Connect-Applications/) ### [Upcoming client side default SSL context provider](/news/2021/12/17/Upcoming-client-side-default-SSL-context-provider/) ### [Using a JAAS realm in Elytron](/news/2021/12/17/Using-a-JAAS-realm-in-Elytron/) ### [New Security Features in WildFly](/news/2021/12/17/New-Security-Features-in-WildFly/) ### [Securing WildFly Apps with OpenID Connect](/news/2021/12/17/Securing-WildFly-Apps-with-OpenID-Connect/) ### [Upcoming filesystem realm encryption and integrity support in Elytron](/news/2021/12/17/Upcoming-filesystem-realm-encryption-and-integrity-support-in-Elytron/) ### [WildFly 26 S2I images have been released on quay.io](/news/2021/12/16/WildFly-26-S2I-images-have-been-released-on-quay-io/) WildFly 26 S2I Docker images The WildFly S2I (Source-to-Image) builder and runtime Docker images for WildFly 26 have been released on quay.io/wildfly. For complete documentation on how to use these images using S2I, OpenShift and Docker, refer to the WildFly S2I README. Anticipating a future set of WildFly images The quay.io/wildfly/wildfly-centos7 and quay.io/wildfly/wildfly-runtime-centos7 are now deprecated. When building or running the server, a deprecation notice is displayed in the console. We are planning to stop evolving these images in a future release. We are now starting our migration to the new WildFly S2I images. The new architecture is based on the WildFly Maven plugin 3.0 and a new pair of docker images. A recent post has provided the details of this new approach. We are expecting that these new artifacts will become final by the next WildFly release. New vs current S2I workflow The main difference with the current WildFly S2I image is that no more WildFly server is installed in the S2I builder image. A Galleon provisioning of the server is required during the S2I build phase. If you are evolving the pom.xml of your application to use the WildFly Maven Plugin to package the server and your application, the provisioned server and deployment are automatically installed in the generated image. Although we strongly encourage you to evolve your pom file, the builder image offers a mode that allows you to build and deploy existing application with the new builder image. In order to initiate Galleon provisioning of the server during S2I build phase you need to set the following environment variables: GALLEON_PROVISION_FEATURE_PACKS=<WildFly Galleon feature-pack GAV[,additional Galleon feature-packs GAV]>. The WildFly Galleon feature-pack to provision a WildFly server (org.wildfly:wildfly-galleon-pack:26.0.0.Final) must be the first feature-pack in the list. Then additional feature-packs can be provided. The feature-packs of interest in a cloud context (non exhaustive list) are: org.wildfly.cloud:wildfly-cloud-galleon-pack:1.0.0.Beta1: To provision the additional cloud content (mainly server configuration based on env variables). org.wildfly:wildfly-datasources-galleon-pack:2.0.6.Final: To provision drivers and datasources. GALLEON_PROVISION_LAYERS=<comma separated list of Galleon layers>. The set of WildFly Galleon layers or Galleon layers provided by listed additional Galleon feature-packs. These environment variables are not new, they are already used to initiate the provisioning of a custom WildFly server. With the new S2I builder image, if you are not using the WildFly Maven plugin, they must be set. To conclude While we are progressing to complete the transition (mainly documentation and release of final artifacts), we would really appreciate your feedback. (You can log these as new project issues). This will help us evolve the WildFly S2I experience in the right direction. Thank-you! JF Denise ### [WildFly 26 is released!](/news/2021/12/16/WildFly-26-is-released/) I’m pleased to announce that the WildFly 26 Final zip is now available for download. (Note that the release may not be available yet on Maven Central; please Maven Availability below for more details.) There are number of new things in this release: WildFly Preview and MicroProfile Platform 5 Last week the MicroProfile group announced the release of the MicroProfile 5.0 platform. Thanks and congratulations to the MicroProfile community! MicroProfile 5.0 is mainly focused on updating APIs and dependencies from the use of Jakarta EE 8 and the javax.* namespace to EE 9.1 and the jakarta.* namespace. As I announced when we released WildFly 22 Alpha1, along with our traditional Jakarta EE 8 distribution we want to give our users a preview of what will be coming in WildFly as we move on to EE 9 and later. We call this distribution "WildFly Preview". The WildFly 26.0.0.Final release includes an update to WildFly Preview. The current focus of WildFly Preview is on showcasing our efforts toward using the jakarta.* namespace and eventual Jakarta EE 10 support, so in the WildFly Preview 26 release we wanted to take advantage of the new developments in MicroProfile by demonstrating compatibility with MicroProfile 5.0. I’m very pleased to be able to say that WildFly Preview 26 is a compatible implementation of MicroProfile 5.0! Evidence supporting our certification is available on the WildFly certifications site. My thanks to the MicroProfile working group for their efforts in getting MicroProfile 5.0 released, and to WildFly contributors Kabir Khan, Martin Stefanko and James Perkins for their hard work on integration of the 5.0 spec APIs and TCKs and on testing compliance. To learn more about WildFly Preview, see the WildFly and WildFly Preview doc page. Please note that even though WildFly Preview 26 is coming from a .Final tag of the WildFly codebase, WildFly Preview should always be regarded as a tech-preview/beta distribution. Cloud Configuration WildFly now supports overriding the value of simple management attributes with environment variables. This allows you to tailor a huge range of settings to your runtime environment without needing to use multiple different configuration files for different environments or modify a common configuration file to add a lot of configuration expressions. This kind of configuration overriding can be useful anywhere, but particularly in cloud environments. To override the value of a simple attribute of a management resource, you can specify an environment variable with the following conversion mapping: Take the address of the resource. Remove the leading slash (/). Append two underscores (__) and the name of the attribute. Replace all non-alphanumeric characters with an underscore (_) Transform to upper case. For example, to set the value of the proxy-address-forwarding attribute to true on the /subsystem=undertow/server=default-server/http-listener=default resource, you can use the following environment variable: export SUBSYSTEM_UNDERTOW_SERVER_DEFAULT_SERVER_HTTP_LISTENER_DEFAULT__PROXY_ADDRESS_FORWARDING=true This feature is not activated by default. To activate this feature, you must set the WILDFLY_OVERRIDING_ENV_VARS environment variable on your target platform: export WILDFLY_OVERRIDING_ENV_VARS=1 Other New Features The Elytron subsystem has added a new JAAS security realm type. The JAAS security realm can be used to configure custom Login Modules in the Elytron subsystem to use for credential verification. This is done by initializing and using a LoginContext from a provided JAAS configuration file to verify user’s credentials. A WildFly domain mode Host Controller can now resolve standard server system properties when launching a managed server JVM. This makes it easier to configure shared server JVM settings at the domain, server-group or host level, while still having those settings incorporate server-specific path values. This is useful for things like adding GC logging to the server launch command, where the setting needs to include a server-specific location to write the log file. The MicroProfile Reactive Messaging quickstart has been enhanced to demonstrate new capabilities that came with our integration of MicroProfile Reactive Messaging 2.0. Compatibility Notes There are a couple of compatibility topics that I want to highlight: To build a Bootable JAR with WildFly 26, you will need to upgrade the Bootable JAR Maven plugin to the 6.1.1.Final or later release, preferably to 7.0.0.Final. The need to upgrade is a result of an important improvement in how the plugin can handle certain updates. Some developers may be accustomed to exposing the H2 database web console during development work by adding servlets provided by WildFly’s com.h2database.h2 module in an application deployment. In WildFly 26 this no longer works out of the box. In standard WildFly (but not WildFly Preview), the ability to do this can be restored by following the instructions in the WildFly 26 documentation. Java SE Support You can run WildFly 26 or WildFly Preview 26 on any of the long-term support Java SE releases, including Java SE 17. We’ve tested WildFly heavily on Java SE 8, Java SE 11 and Java SE 17. Our testing included testing WildFly Preview on SE 17 with the massive Jakarta EE 9.1 TCK. (More on that in the 'Standards Support' section below.) The most heavily tested SE options for WildFly are still SE 11 and SE 8, because both WildFly and its component library projects have so many years of testing on those versions. As I noted in September’s Changes are coming to WildFly post, it is likely that WildFly will drop support for SE 8 in one of the next few releases. Eventually the transition to Jakarta EE 10 support and the expected minimum requirement for SE 11 by some of its API projects will drive WildFly to only support SE 11 or later. Early next year we’re aiming to nail down plans for when that will happen. Please note that WildFly runs on Java 11 and later in classpath mode. Running WildFly with SE 17 Because SE 17 is probably new to a great many WildFly users, I decided to copy over over this next bit from the WildFly 25 release announcement. One of the key differences in SE 17 versus the previous LTS SE 11 release is that the JVM will reject reflective access calls that SE 11 would only warn about, unless the JVM launch command includes JPMS configuration options to allow that access. WildFly does quite a bit of deep reflection, so part of our efforts in recent releases has been to identify the necessary JPMS settings. We have added those to our standard launch scripts, so WildFly should just work if you’re using those. The manifest file in a WildFly bootable jar will also include these settings. But some users may not be using a bootable jar or using our launch scripts to launch WildFly. For example many users use IDEs to launch WildFly and count on the IDE to provide arguments to the JVM. And IDEs may not be using the necessary settings yet. If you are launching a WildFly instance on SE 17 and aren’t using a bootable jar or our launch scripts, here are the JPMS settings you will need: --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED Not all uses of the server will require all of those; the launch script sections that set those up include comments describing the main reason we’ve added each. It’s possible your application may do something that requires additional JPMS settings; if so you can add those to the JVM launch command by editing the bin/standalone.conf or bin/domain.conf file or their .bat or .ps1 variants. Standards Support The standard WildFly 26.0.0 distribution is a Jakarta EE 8 compatible implementation, compatible with both the Full Platform and the Web Profile. Evidence supporting our certification is available for the Full Platform and for the Web Profile. The standard WildFly 26 distribution is also a compliant implementation of the MicroProfile 4.1 platform specification. This has been demonstrated on SE 8, SE 11 and SE 17. The WildFly Preview distribution released today is a compatible implementation of both the Jakarta EE 9.1 Web Profile and the Full Platform. WildFly Preview has been able to demonstrate compatibility while running on both Java SE 11 and on Java SE 17. Evidence supporting our certification is available for the Full Platform on SE 11, for the Web Profile on SE 11, for the Full Platform on SE 17 and for the Web Profile on SE 17. As discussed above the WildFly Preview 26 distribution is a compliant implementation of the MicroProfile 5.0 platform specification. This, too, has been demonstrated on SE 8, SE 11 and SE 17. Upcoming Changes WildFly 26 was the second in a series of a few releases where we’re expecting to make some big changes in the server. I encourage you to have a look at the Changes are coming to WildFly post that I mentioned above. Maven Availability As of the time I’m writing this, we’ve been experiencing issues with syncing artifacts initially deployed to the JBoss.org Nexus installation to Maven Central. This has affected WildFly 26 and a number of its component projects, so until this is resolved you may not find the WildFly 26 artifacts on Maven Central. The Maven repository url to use to pull WildFly from JBoss.org nexus is https://repository.jboss.org/nexus/content/groups/public/. The repository is easily accessed via a browser as well; for example the wildfly-dist artifacts can be found here. Documentation The WildFly 26 documentation is available at the docs.wildfly.org site. The WildFly 26 management API documentation is in the wildscribe section of the WildFly 26 docs. Jira Release Notes The full list of issues resolved is available in the WFLY JIRA project. Issues resolved in the WildFly Core 18 release included with WildFly 26 are available in the WFCORE JIRA project. Enjoy! Thank you for your continued support of WildFly. We’d love to hear your feedback at the WildFly forum. ### [WildFly Impact of the Apache Log4j Security Vulnerabilities](/news/2021/12/13/WildFly-Impact-of-the-Apache-Log4j-Security-Vulnerabilities/) WildFly users are of course interested in the impact of the recently disclosed security vulnerabilities related to Apache Log4j. On Friday the @WildFlyAS Twitter account tweeted a tl;dr; summary of how the critical impact CVE-2021-44228 vulnerability affects WildFly. In this post I want to provide further details, information on how users who package the log4j-core artifact in their WildFly application deployments can mitigate the risk, and provide information on how the recently disclosed moderate Log4j 1 vulnerability affects WildFly. CVE-2021-44228 CVE-2021-44228 is a critical impact zero-day vulnerability in the Apache Log4j log4j-core library whereby a remote attacker who can control log messages or log message parameters can execute arbitrary code on a server via a JNDI lookup. I won’t get into the technical details of the exploit here; instead I refer you to this nice writeup on it. This vulnerability is in code in the Log4j 2 org.apache.logging.log4j:log4j-core artifact. The WildFly application server project does not ship this artifact, and it never has. So, the only way an application running on WildFly would be vulnerable to the CVE-2021-44228 vulnerability is if the log4j-core artifact has been added to the server installation, either via a user-provided JBoss Modules module, or more likely by packaging log4j-core in an application deployment artifact. Note that since WildFly 22, WildFly does ship the Log4j 2 org.apache.logging.log4j:log4j-api artifact, and up to WildFly 26.0.0.Beta1 the version of that artifact matches the CVE-2021-44228 CPE. However, the log4j-api artifact does not contain the vulnerable code.. Note that even though the artifact on WildFly 26.0.0.Beta1 does not have the vulnerability, to help avoid confusion the upcoming 26.0.0.Final release will move to the 2.15.0 version of the artifact, which does not match the CVE-2021-44228 CPE. Mitigation Strategies If your application does include the log4j-core artifact, the following are steps you can take to mitigate any vulnerability: Set formatMsgNoLookups=true Since its 2.10 release, Log4j provides a configuration option that lets you turn off the JNDI lookup behavior that results in the vulnerability. To use this, update the $WILDFLY_HOME/bin/standalone.conf or $WILDFLY_HOME/bin/domain.conf file (or, for Windows users, the .bat or .ps1 variants of those) to add -Dlog4j2.formatMsgNoLookups=true to the value of the JAVA_OPTS environment variable. (Which file you update depends on whether you are running a standalone server or a domain mode host.) Note that if you are using a version of log4j-core prior to 2.10 this will have no effect. If you’re on a recent enough log4j-core version setting this is the quickest mitigation, but whether you can use it or not as soon as you can you should also…​ Upgrade log4j-core to the 2.15.0 or later release The Apache Log4j project has released a 2.15.0 version that fixes the flaw. If you are packaging log4j-core in your application we recommend updating your deployment artifact to 2.15.0 or later as soon as possible. Note that I’ve seen user reports that upgrading to 2.15.0 in a deployment is problematic when the container is providing an earlier release of the log4j-api artifact. This should not be a problem if you are following the documentation for how to incorporate log4j-core in your application. If you are packaging log4j-core, you should exclude any module dependency on the log4-api provided by WildFly and instead package log4j-api in your deployment. CVE-2021-4104 Recently Red Hat reported another security vulnerability affecting Apache Log4j, in this case Log4j 1. They rated the impact of this vulnerability as "Moderate impact", unlike their view of CVE-2021-44228 which was rated as "Critical impact". (For more on the difference between "Critical" and "Moderate", see Red Hat’s severity ratings documentation.) CVE-2021-4104 has some surface similarity to CVE-2021-44228, in that both relate to a logging library doing a JNDI lookup, with a risk that that library could be fooled into doing a lookup and deserialization of content from an untrustworthy source. In the CVE-2021-4104 case the lookups can be performed by the org.apache.log4j.net.JMSAppender class, a class that is used if an application configures a log appender meant to write to an external JMS topic. The JMSAppender lookup is quite different from the CVE-2021-44228 one though, in that the name being looked up is meant to be of a string provided as part of the appender’s configuration, not one that is incorporated in a log message. It is significantly easier to get a server to inject a malicious string into a log message than it is to inject one into the container configuration. The latter would typically require some sort of privileged access to the server. This increased difficulty of exploit is one of the factors that Red Hat uses when deciding the severity of a vulnerability. WildFly does not ship Apache Log4j 1 itself, but the org.jboss.logmanager:log4j-jboss-logmanager artifact we ship shades the Log4j 1 classes, including JMSAppender. JMSAppender has been present in WildFly or JBoss AS at least as far back as JBoss AS 7.1, and probably much farther. However, our attempts to configure WildFly to use the JMSAppender have been unsuccessful, failing before the JMSAppender code reaches a point where it does any JNDI lookup. This is because the JBoss Modules module that packages org.jboss.logmanager:log4j-jboss-logmanager does not include a dependency on the module that provides the javax.naming package, resulting in a ClassNotFoundException if the class is used. So at this point we don’t see an exploit involving normal modular use of the org.jboss.logmanager:log4j-jboss-logmanager artifact we ship. Exploits would likely require the use of reflection. If you package Apache Log4j 1 in your application, be careful not to expose to untrusted callers any mechanism that would allow them to access the JMSAppender class or configure instances of it. Which is the right thing to do in general! Running with the JVM security manager enabled is another way to defend against attacks based on getting your application to make unexpected calls to external systems. If you have any questions about any of the above, I encourage you to ask on the WildFly forums. Best regards, Brian ### [New WildFly 26 Beta1 release](/news/2021/12/02/New-WildFly-26-Beta1-release/) I’m pleased to announce that the new WildFly and WildFly Preview 26.0.0.Beta1 releases are available for download at https://wildfly.org/downloads. For more information about the changes included in this release please consult the release notes, in the meantime the developers are working hard on tasks needed to prepare the base to add support for Jakarta EE 10 as the specifications become available. Release Notes The release notes for the release are here, with issues fixed in the underlying WildFly Core betas listed here. Please try it out and give us your feedback, while we get to work on WildFly 26 Final! Best regards, Darran ### [WildFly 25.0.1 is released!](/news/2021/11/04/WildFly-25-0-1-is-released/) WildFly 25.0.1.Final is now available for download. It’s been about four weeks since the WildFly 25 release, so we’ve done a small bug fix update, WildFly 25.0.1. This includes an update to WildFly Preview. The full list of issues resolved in WildFly 25.0.1 is available here. Issues resolved in the WildFly Core updates (there were two) included with WildFly 25.0.1 are available here and here. Enjoy! ### [WildFly S2I v2 architecture overview](/news/2021/10/29/WildFly-S2I-v2-architecture-overview/) For upcoming WildFly 26 release we are re-architecting WildFly S2I (Source to Image) images to offer more flexibility, better efficiency and a simpler user experience. Since WildFly 16, in which we introduced an evolution of the WildFly s2i images, we have identified a set of pain points that we want to see addressed in a new architecture: Strong coupling of the WildFly S2I builder image with a WildFly release. This implies that new builder images have to be released and deployed for each new server version. Configuring the server during the S2I build is complex. Executing the simplest WildFly CLI script during build is far from trivial; it requires your application project to comply with a specific directory structure then you must define bash scripts (do you know Java developers who like to write bash scripts?) in order to call CLI command lines (and don’t forget to start the embedded server). The simplest copy of some extra server content (e.g. JBoss Module modules) is also not that trivial and again requires bash scripting. Executing your own CLI scripts during server startup implies having installed some extensions (again bash scripts) inside the server during the S2I build. Server startup is always composed of a sequence of 2 steps — server starts first in admin only mode and automatically applies generated CLI scripts, then reboots in normal mode. In cases your server configuration doesn’t require some adjustments and could have booted directly in normal mode. No simple way to provide server arguments (e.g. Java system properties) when starting the server. No way to tailor a server according to the application needs from the project pom.xml file. Server provisioning during the S2I build is configured by env variables provided at S2I build time. No way to build and run an application with a WildFly Preview server. WildFly S2I images contain much more than what we actually need to build and run the server. We need a much lighter Operating System. New WildFly S2I architecture The current architecture is composed of 2 main artifacts: WildFly S2I builder image with JDK11 based on centos7. Image released for each new WildFly release (to contain the latest release of the WildFly server). WildFly S2I runtime image with JDK11 based on centos7. Image used to create docker chained builds to output smaller runtime application images. We are keeping the separation between the S2I builder image and the runtime image. The 2 new images we are offering are: WildFly S2I builder image with JDK11 based on ubi8 minimal. This image doesn’t contain a WildFly server. It expects a server containing the application deployment to be provisioned during the S2I build phase. WildFly runtime image with JDK11 based on ubi8 minimal. We are keeping the JDK (instead of a JRE) in order to make Java debugging tools available in the image. This image can be used to run any WildFly server (not only a server provisioned using the builder image in a chained build). For now we will only be providing JDK 11 versions of these images. So the WildFly S2I builder image becomes a lightweight generic image allowing to build and execute applications deployed in any WildFly server. New s2i build workflow We are removing the complex server configuration points and rely on the use of the WildFly Maven plugin that can now provision a fully configured server containing your deployment. The WildFly Maven plugin 3.0.0.Alpha1 has been evolved with some new goals to provision, configure, and package the server and the deployment in one step. When designing your application pom file, add the WildFly Maven plugin package goal, configure it with the WildFly Galleon feature-pack and Galleon layer(s), and optionally reference WildFly CLI scripts to be executed and content to be copied inside the server. At the end of the build you will get (by default in the target/server directory) a server with your app deployed, ready to be installed in the image. In order to allow for a smooth transition to the new images, we are still supporting (in a deprecated way) the legacy workflow. Your existing application would work, but you are now required to specify the Galleon feature-pack(s) and layer(s) (GALLEON_PROVISION_FEATURE_PACKS and GALLEON_PROVISION_LAYERS env variables) you want to see used during the S2I build to provision a WildFly server. New image runtime API An image built from the WildFly S2I builder or runtime images both expose the same API allowing you to fine tune the server execution. This API is exposed by means of environment variables to be set when configuring your deployment. JVM configuration API The JVM env variables that are used today with WildFly s2i images are still supported. They are a nice way to tune the JVM. WildFly server startup configuration API The new server startup configuration API is described in this documentation. This API comes with default values that should cover the main use-cases. 2 env variables open-up new possibilities: SERVER_ARGS allows you to pass WildFly server arguments when starting the server. CLI_LAUNCH_SCRIPT allows you to provide a path (relative to JBOSS_HOME or absolute) to a CLI script to be executed at startup time. Although CLI scripts should be executed at build time from the WildFly Maven plugin, in some cases it can be useful to adjust the configuration at execution time. You can package a set of CLI scripts inside your server at build time, then reference one of these CLI scripts to be executed at runtime. WildFly server subsystems configuration API If you are using WildFly s2i images you are perhaps asking yourself where are the env variables you have been using to configure the elytron subsystem, to add datasources, to configure logging or the microprofile-config subsystem,…​ They are provided by means of a new WildFly cloud Galleon feature-pack that you can combine with the WildFly Galleon feature-pack at build time to produce a server supporting these env variables. If you only provision org.wildfly:wildfly-galleon-pack:25.0.0.Final you will get a "vanilla" WildFly server that will get lightly adjusted by the image entry-point to properly execute on OpenShift. If you provision org.wildfly:wildfly-galleon-pack:25.0.0.Final and org.wildfly.cloud:wildfly-cloud-galleon-pack:1.0.0.Alpha2 you will get a similar server to the one present in the current WildFly s2i image (with JBOSS_HOME/bin/openshift-launch.sh launcher). Examples You can pull the new WildFly S2i images (Beta quality) from quay.io: docker pull quay.io/jfdenise/wildfly-s2i-jdk11 docker pull quay.io/jfdenise/wildfly-runtime-jdk11 NB: The images will be made available from the quay.io/wildfly organisation when they reach a Final quality. S2I examples We have defined a set of examples to help you get started. They cover different use-cases that highlight the new capabilities. The examples rely on WildFly Helm Charts to automate the build and deployment on OpenShift. In order to deploy the examples onto OpenShift, you can log in to the Developer Sandbox for Red Hat OpenShift. The use cases covered are: Simple application, no specific configuration. Just build and deploy on OpenShift. Keycloak integration. Use WildFly 25 elytron-oidc-client to interact with a Keycloak server. Also highlights the ability to provide server arguments at launch time. Logging. We all need to enable logging at some point. With a simple CLI script executed at server boot time, enable logging and redirect all traces to the CONSOLE. Clustering. A cluster of PODS that share web sessions. This example benefits from the WildFly cloud feature-pack and WildFly Helm Charts capabilities to automatically enable the dns.DNS_PING JGroups protocol and generate the ping service. Dockerfile example This chapter highlights the steps to build a docker image that contains the server and your application, publish it in a public docker registry in which you have an account (e.g. quay.io) and then deploy it on OpenShift. Here we are using the Simple application example. NB: Be sure to update the example steps with your own docker registry account. Build the maven project: $ mvn clean package Write a Dockerfile with the following content: FROM quay.io/jfdenise/wildfly-runtime-jdk11:latest COPY --chown=jboss:root target/server $JBOSS_HOME RUN chmod -R ug+rwX $JBOSS_HOME Build the image $ docker build -t quay.io/jfdenise/my-app:latest . You can run the image locally and interact with the application (e.g. http://docker_container_IP:8080). $ docker run --rm quay.io/jfdenise/my-app:latest Publish the image $ docker push quay.io/jfdenise/my-app:latest Write a WildFly Helm Charts my-app.yaml file with the following content: image: name: quay.io/jfdenise/my-app build: enabled: false Deploy on OpenShift helm install my-app -f my-app.yaml wildfly_v2/wildfly Once deployed, access the application route URL (e.g. https://my-app-jdenise-stage.apps.sandbox.x8i5.p1.openshiftapps.com/) To conclude We hope that, like us, you will see the benefits of this new approach (for which you can perhaps find similarities with the WildFly bootable JAR S2I experience). This is going to allow us to offer more flexibility (provision the server of your choice), better efficiency (smaller images, faster server startup), simpler user experience (WildFly Maven plugin configuration is far simpler than the existing S2I configuration points). So in the end a much better overall experience. Keep us posted with your feedback. (You can log these as new project issues.) This will help us evolve the new WildFly S2I experience in the right direction. Thank-you! JF Denise ### [Using distributed realm in WildFly Elytron](/news/2021/10/26/Using-distributed-realm-in-WildFly-Elytron/) ### [Using failover realm in WildFly Elytron](/news/2021/10/25/Using-failover-realm-in-WildFly-Elytron/) ### [Open Source Day 2021 Recap](/news/2021/10/18/Open-Source-Day-2021-Recap/) ### [MicroProfile Reactive Messaging 2.0 in WildFly 25](/news/2021/10/14/MicroProfile-Reactive-Messaging-2-0-in-WildFly-25/) For WildFly 25, we upgraded the MicroProfile Reactive Messaging support from version 1 to 2. It contains a new @Channel annotation, which in conjunction with the new Emitter interface, were introduced in order to make it possible to push data into the MicroProfile Reactive streams from code initiated by a user. The MicroProfile Reactive Messaing implementation in WildFly is based on the SmallRye Reactive Messaging project. The version included in WildFly 25, introduces a new API to have more control over how we interact with Kafka. We expose this API in WildFly 25. This post will: Take a simple web application, consisting of a few html pages, and add a Servlet filter to push information about page visits into Reactive Messaging via an Emitter. These messages will be forwarded onto Kafka Show a standalone application to read the last visited page per user from Kafka via the Kafka Streams API Deploy the above application into WildFly, bundling the Kafka Streams API (which we don’t ship in WildFly) to read the last visited page per user. The code for the application is on GitHub. Additionally, you can find more information about the MicroProfile Reactive Messaging functionality in WildFly in the WildFly documentation. Running the application See the GitHub repository README for instructions on how to build and run the different parts of the application. Here we will focus on explaining how it works. The main application The main application is contained in the app folder. The core of the application is a few html pages which link to each other. Now, we want to track which user visited which page. We do this by enhancing the application with a Servlet filter called MessagingFilter: public class MessagingFilter extends HttpFilter { @Inject @Channel("from-filter") Emitter<PageVisit> messagingEmitter; FIrst we have field injected via CDI of type Emitter, called messagingEmitter, which is annotated with @Channel. This Emitter instance makes it a breeze to push data to the MicroProfile Reactive Messaging stream indicated by the value of the @Channel annotation (i.e. from-filter). @Override public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { String user = getUsername(request); String address = request.getRemoteAddr(); String page = Paths.get(request.getRequestURI()).getFileName().toString(); PageVisit pv = new PageVisit(user, address, page); messagingEmitter.send(pv); Next we gather information about the request (user, address and page name), and bundle this information up in a PageVisit bean. We then use the injected Emitter to send the PageVisit instance. The Emitter will then send the PageVisit to the from-filter stream. // Disable caching for the html pages ((HttpServletResponse)response).addHeader("Cache-control", "no-store"); ((HttpServletResponse)response).addHeader("Pragma", "no-cache"); filterChain.doFilter(request, response); } Getting the user name is simulated in the following method which randomly chooses a user for the current request. For the purposes of this demo this is to get a few different users in the data recorded when we click on the links when running the application. private String getUsername(HttpServletRequest servletRequest) { // Pretend we're looking up the authenticated user switch ((int)Math.round(Math.random() * 3)) { case 0: return "bob"; case 1: return "emma"; case 2: return "frank"; case 3: return "linda"; } return null; } } Next, we have an ApplicationScoped CDI bean called MessagingBean @ApplicationScoped public class MessagingBean { @Inject @Channel("special") Emitter<PageVisit> special; @Incoming("from-filter") @Outgoing("kafka-visits") public Message<PageVisit> fromFilter(PageVisit pageVisit) { if (pageVisit.getPage().equals("3.html")) { special.send(pageVisit); } Message<PageVisit> msg = Message.of(pageVisit); msg = KafkaMetadataUtil.writeOutgoingKafkaMetadata( msg, OutgoingKafkaRecordMetadata .<String>builder() .withKey(pageVisit.getUserName()) .build()); return msg; } @Incoming("special") public void special(PageVisit pageVisit) { System.out.println("===> " + pageVisit.getUserName() + " visited " + pageVisit.getPage()); } } The fromFilter() method is annotated with the @Incoming("from-filter") annotation (from version 1 of the specification) and will receive all messages that were sent on our previous Emitter. Since the both the @Incoming and @Channel annotations use the value from-filter (i.e. they match), we end up with a simple in-memory stream. We could of course have routed this via Kafka, but for this example I wanted to keep the configuration needed to map to Kafka as simple as possible. The WildFly documentation goes into more details about how to configure MicroProfile Reactive Messaging streams to consume from Kafka topics. The fromFilter() method is also annotated with @Outgoing("kafka-visits"), and so it is expected that all incoming messages from the from-filter stream will be forwarded onto the kafka-visits stream. The kafka-visits stream is backed by Kafka (we will see how to map this stream onto a Kafka topic in a second). In this case we decide that we want messages sent on this topic to have a Kafka key, so we: Wrap the incoming PageVisit object in a Message object, which comes from the MicroProfile Reactive Messaging specification. We then create an OutgoingKafkaRecordMetadata instance, where we set the key of the record to be the user. We add this metadata to the message by calling KafkaMetadataUtil.writeOutgoingKafkaMetadata(). The mentioned classes come from the new SmallRye Kafka API. Finally we return the massaged Message containing our received PageVisit instance, which will forward it to the kafka-visits stream. Another thing going on in this example, is that we’re using an injected Emitter to 'fork' the sending of the received data to an additional location. In fromFilter(), if the page 3.html was visited, we will also send the received PageVisit via the injected Emitter. This in turn will send the PageVisit instance on the special stream indicated in its @Channel annotation. The special() method, annotated with @Incoming(`special) receives messages from the special stream (i.e. the ones sent via the Emitter). When running the application, and clicking on the 3 link, you should see output in the server logs. Additionally, every click on any link will show up in the Kafka consumer logs mentioned in the example README. So, in addition to being able to easily send data from user-initiated code, Emitter is useful for 'forking' streams, so you can send data to more than one location. This functionality was not present in version 1 of the specification. To map the kafka-visits stream to a Kafka topic we do the configuration in microprofile-config.properties: mp.messaging.connector.smallrye-kafka.bootstrap.servers=localhost:9092 mp.messaging.outgoing.kafka-visits.connector=smallrye-kafka mp.messaging.outgoing.kafka-visits.topic=page-visits mp.messaging.outgoing.kafka-visits.value.serializer=org.wildfly.blog.reactive.messaging.common.PageVisitsSerializer This points the mapping towards localhost:9092 to connect to Kafka, maps the kafka-visits stream to the page-visits kafka topic, and specifies PageVisitsSerializer to be used to serialize the PageVisit instances that we send to Kafka. The WildFly documentation contains more detailed information about this configuration. If you deploy the application into WildFly, as outlined in the example README, and you performed the optional step of connecting a Kafka consumer, you should see the output similar to this in the Kafka consumer terminal as you click the links in the application hosted at http://localhost:8080/app/: frank 127.0.0.1app emma 127.0.0.13.html frank 127.0.0.11.html linda 127.0.0.13.html frank 127.0.0.11.html emma 127.0.0.12.html frank 127.0.0.13.html When you visit 3.html, there will be additional output from the special() method in WildFly’s server.log ===> emma visited 3.html ===> linda visited 3.html ===> frank visited 3.html Reading data from Kafka in a standalone application While it is nice to be able to send (and receive, although not shown in this example) messages via Kafka, we may want to query the data in Kafka later. The code for the command line application to query data from Kafka is contained in the streams folder. It contains a very simple (I am a beginner at this part) application to get the most recent page visits per user. It uses the Kafka Streams API to interact with Kafka. The Main class calls through to a more interesting DataStoreWrapper class. public static void main(String[] args) throws Exception { try (DataStoreWrapper dsw = new DataStoreWrapper()) { dsw.init(); Map<String, String> lastPagesByUser = Collections.emptyMap(); try { dsw.readLastVisitedPageByUsers(); } catch (InvalidStateStoreException e) { } if (lastPagesByUser.size() == 0) { // It seems that although the stream is reported as RUNNING // in dsw.init() it still needs some time to settle. Until that // happens there is no data or we get InvalidStateStoreException Thread.sleep(4000); lastPagesByUser = dsw.readLastVisitedPageByUsers(); } System.out.println("Last pages visited:\n" + lastPagesByUser); } } } Note There is some error handling here. In case you get no entries, or if you get InvalidStateStoreException, try increasing the timeout in the sleep. Looking at the DataStoreWrapper class, the first thing to note is that it is 'CDI ready'. Although this section will run it as a standalone application where CDI is not relevant, we will reuse this class later in an application deployed in WildFly. @ApplicationScoped public class DataStoreWrapper implements Closeable { private volatile KafkaStreams streams; We will initialise this streams instance in the init() method below. @Inject private ConfigSupplier configSupplier = new ConfigSupplier() { @Override public String getBootstrapServers() { return "localhost:9092"; } @Override public String getTopicName() { return "page-visits"; } }; The configSupplier field is inititalised to an implementation of ConfigSupplier which hard codes the values of the Kafka bootstrap servers, and the topic name. When deploying this into WildFly later we will use MicroProfile Config to set these values to avoid hard coding them. DataStoreWrapper() { } Next, we will take a look at the init() method where we set up the ability to query the stream. @PostConstruct void init() { try { Properties props = new Properties(); props.put(StreamsConfig.APPLICATION_ID_CONFIG, "streams-pipe"); props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, configSupplier.getBootstrapServers()); props.putIfAbsent(StreamsConfig.CACHE_MAX_BYTES_BUFFERING_CONFIG, 0); props.putIfAbsent(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName()); props.putIfAbsent(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, PageVisitSerde.class.getName()); // For this we want to read all the data props.putIfAbsent(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); The above sets configuration properties to connect to kafka, and sets Serdes for (de)serializing the Kafka record keys and values. The class PageVisitSerde is used to (de)serialise our PageVisit class from earlier. We also specify that we want all the data stored on this topic. final StreamsBuilder builder = new StreamsBuilder(); KeyValueBytesStoreSupplier stateStore = Stores.inMemoryKeyValueStore("test-store"); KTable<String, PageVisit> source = builder.table( configSupplier.getTopicName(), Materialized.<String, PageVisit>as(stateStore) .withKeySerde(Serdes.String()) .withValueSerde(new PageVisitSerde())); final Topology topology = builder.build(); this.streams = new KafkaStreams(topology, props); Now we create a KTable associated with the Kafka topic, and create a StateStore from that. In this case since we are using the Kafka record key (above we used the user for this when sending to Kafka) as the KTable key, we will get one entry (the latest) for each user. Note this is a very simple example, and not an in-depth exploration of the Kafka Streams API, so of course more advanced views on the stored data are possible! final CountDownLatch startLatch = new CountDownLatch(1); final AtomicReference<KafkaStreams.State> state = new AtomicReference<>(); streams.setStateListener((newState, oldState) -> { state.set(newState); switch (newState) { case RUNNING: case ERROR: case PENDING_SHUTDOWN: startLatch.countDown(); } }); this.streams.start(); startLatch.await(10, TimeUnit.SECONDS); System.out.println("Stream started"); if (state.get() != KafkaStreams.State.RUNNING) { throw new IllegalStateException(); } Finally, we start the stream and wait for it to start. } catch (Exception e) { if (this.streams != null) { this.streams.close(); } throw new RuntimeException(e); } } The readLastVisitedPageByUsers() method uses the StateStore we set up earlier and returns all the found entries: public Map<String, String> readLastVisitedPageByUsers() { StoreQueryParameters<ReadOnlyKeyValueStore<String, PageVisit>> sqp = StoreQueryParameters.fromNameAndType("test-store", QueryableStoreTypes.keyValueStore()); final ReadOnlyKeyValueStore<String, PageVisit> store = this.streams.store(sqp); Map<String, String> lastPageByUser = new HashMap<>(); KeyValueIterator<String, PageVisit> it = store.all(); it.forEachRemaining(keyValue -> lastPageByUser.put(keyValue.key, keyValue.value.getPage())); return lastPageByUser; } @PreDestroy public void close() { this.streams.close(); } } If you run the application, following the instructions in the example README, you should see output like this: Stream started Last pages visited: {frank=3.html, emma=2.html, linda=3.html} As already mentioned, this will be the latest page visited for each user. Reading data from Kafka in a WildFly application WildFly does not ship with the Kafka Streams API, but we can still deploy the application above into WildFly with some adjustments in how we package it. The example README contains more details, but in a nutshell we: Include the Kafka Streams API jar in our deployment Make sure we don’t include all the Kafka Streams API jar’s transitive dependencies in our deployment since they already exist in WildFly. Modify the deployment’s META-INF/MANIFEST.MF to set up a dependency on the org.apache.kafka.client JBoss Module. This module contains the Kafka client jar, which is needed by the Kafka Streams API. In our standalone application, we hardcoded the bootstrap servers and the topic name. When deploying to WildFly we would like to avoid recompiling the application if, say, Kafka moves somewhere else, so we specify this information in microprofile-config.properties: kafka.bootstrap.servers=localhost:9092 kafka.topic=page-visits We then create an implementation of the ConfigSupplier interface in MpConfigConfigSupplier. This is an ApplicationScoped CDI bean which gets injected with the MicroProfile Config containing the properties from the microprofile-config.properties file: @ApplicationScoped public class MpConfigConfigSupplier implements ConfigSupplier { @Inject Config config; @Override public String getBootstrapServers() { return config.getValue("kafka.bootstrap.servers", String.class); } @Override public String getTopicName() { return config.getValue("kafka.topic", String.class); } } Our DataStoreWrapper class from earlier is a CDI bean, and so our MpConfigConfigSupplier will get injected into its configSupplier field, overwriting the default implementation that was used in the standalone application case: @ApplicationScoped public class DataStoreWrapper implements Closeable { private volatile KafkaStreams streams; @Inject private ConfigSupplier configSupplier = new ConfigSupplier() { // -- SNIP -- // This implementation gets replaced by the injected MpConfigConfigSupplier In order to be able to call this from a client, we add a simple REST endpoint: @Path("/") @Produces(MediaType.APPLICATION_JSON) public class StreamsEndpoint { @Inject DataStoreWrapper wrapper; @GET @Path("/last-visited") public Map<String, String> getLastVisited() { return wrapper.readLastVisitedPageByUsers(); } } This simply delegates to our DataStoreWrapper. If you deploy the application as outlined in the example README, and visit http://localhost:8080/streams/last-visited you should see output like: {"frank":"3.html","emma":"2.html","linda":"3.html"} Conclusion We have seen how to leverage the new Emitter in MicroProfile Reactive Messaging 2 to push data to MicroProfile Reactive Messaging Streams, and how to send data to Kafka. We also used the new Kafka User API to set the Kafka record key in the data sent to Kafka. Although we did not receive data from Kafka in this example, we leveraged the Kafka Streams API to read the data we stored in Kafka in a standalone application as well as in an application deployed to WildFly. References The WildFly documentation contains more information on the various configuration options for using MicroProfile Reactive Messaging with Kafka in WildFly. Also, the SmallRye Reactive Messaging Kafka Connector documentation contains a fuller reference of configuration options for Kafka, as well as more information about MicroProfile Reactive Messaging in general. Finally, the MicroProfile Reactive Messaging specification can be found in the eclipse/microprofile-reactive-messaging GitHub project. ### [WildFly 25 S2I images have been released on quay.io](/news/2021/10/12/WildFly-25-S2I-images-have-been-released-on-quay-io/) WildFly 25 S2I Docker images The WildFly S2I (Source-to-Image) builder and runtime Docker images for WildFly 25 have been released on quay.io/wildfly. For complete documentation on how to use these images using S2I, OpenShift and Docker, refer to the WildFly S2I README. Important changes to mention in this release We have been evolving the s2i builder image to reflect part of the main changes that occurred in WildFly 25. In particular the s2i image content is impacted by the removal of legacy security: Changes in the default server configuration: Now secured with elytron. Security configuration based on legacy security-realms has been removed. security subsystem and extension have been removed. Impact on SSL configuration based on environment variables: elytron is now used by default to configure SSL. The env variable CONFIGURE_ELYTRON_SSL=true is no more needed. Impact on Keycloak integration: By default when configuring Keycloak OIDC and SAML adapters elytron was already in use. Nothing changes there. If you were using the env variable SSO_FORCE_LEGACY_SECURITY=true to rely on the legacy security subsystem, the server will fail to start, you will need to remove this env variable and rely on elytron integration. Anticipating a future support for OpenID Connect In this new release we are deprecating the usage of the keycloak Galleon layer and automatic configuration based on environment variables. We are planning in a future release to rely on the new WildFly subsystem that is providing a native support for OpenID Connect allowing to interact with Keycloak server but with also other servers compatible with the OIDC protocol. Stay tuned! ### [WildFly Bootable JAR 6.0 is released!](/news/2021/10/12/WildFly-Bootable-JAR-6-0-is-released/) The 6.0.0.Final version of the WildFly Bootable JAR Maven plugin has been released. For people who are not familiar with the WildFly Bootable JAR, I strongly recommend that you read this blog post that covers it in detail. New examples to highlight new Galleon layers introduced in WildFly 25 For each new release of the WildFly Bootable JAR Maven plugin we are upgrading the dependency of the examples to the latest WildFly release and highlight new features that you can use when building WildFly Bootable JARs. For 6.0.0.Final, we have added two new examples to cover some new Galleon layers that are of particualr importance for Wildfly Bootable JAR packaging. Automatic generation of self signed certificate Up to now, in order to configure HTTPS when using elytron, we had to include a keystore in the Bootable JAR during packaging. During development phases we generally don’t really care of the content of the keystore (and generating one implies extra steps…​). WildFly 25 introduces the undertow-https Galleon layer that adds an elytron secured https-listener that generates a self signed certificate on first connection. The https example has been evolved with the self-signed profile to provision a server that makes use of the undertow-https Galleon layer. OpenID Connect (OIDC) native support Up to now, as highlighted in the keycloak example, in order to secure a deployment using Keycloak we had to provision both WildFly Galleon feature-pack and Keycloak OIDC adapter feature-pack. Starting with WildFly 25, we are now relying on the WildFly native OIDC support and are deprecating the use of the Keycloack Galleon feature-pack. WildFly 25 introduces the elytron-oidc-client Galleon layer to provision the elytron-oidc-client subsystem that allows to interact with OIDC compliant authorization servers (such as the Keycloak server). This native support is very similar to the Keycloack one. Migrating from using Keycloak Galleon adapter to using WildFly OIDC native support when building a Bootable JAR is a matter of: Removing the Keycloak OIDC adapter feature-pack (org.keycloak:keycloak-adapter-galleon-pack) from the plugin configuration. Replacing the keycloak-client-oidc Galleon layer by the elytron-oidc-client Galleon layer in the plugin configuration. Change the <auth-method>KEYCLOAK</auth-method> to <auth-method>OIDC</auth-method> in your web.xml file. If you were using WEB-INF/keycloak.json file you would need to rename it to WEB-INF/oidc.json and update its content by following the OIDC client subsystem documentation. If you were calling WildFly CLI scripts to update the subsystem configuration, you will need to adjust the management operations. More information can be found in the OIDC client subsystem documentation. The elytron-oidc-client example covers the steps required to use this new Galleon layer. To conclude Finally we would really appreciate if if you would keep us posted with your feedback and new requirements. (You can log these as new project issues.) This will help us evolve the WildFly Bootable JAR experience in the right direction. Thank-you! JF Denise ### [WildFly 25 is released!](/news/2021/10/05/WildFly-25-is-released/) I’m pleased to announce that the WildFly 25 Final zip is now available for download. The big focus during the WildFly 25 development cycle has been on support for Java SE 17 and on the related transition away from our legacy security layer and to a purely WildFly Elytron-based security layer. More about those later, but first let’s look at new features in WildFly 25. New Features A new subsystem has been added that provides support for the tracing aspects of the OpenTelemetry spec, allowing for the injection of the OpenTelemetry and Tracer objects from the specification, as well as implicit tracing of Jakarta REST endpoints. WildFly still provides MicroProfile OpenTracing as an alternative, but I encourage users to switch to the new OpenTelemetry subsystem. A new subsystem has been added that provides the ability to secure deployments using OpenID Connect, without needing to make use of the Keycloak client adapter. It is now possible to make use of other OpenID Connect providers in addition to Keycloak. MicroProfile Health support has been updated to MicroProfile Health 3.1, a new backwards compatible release of the specification. MicroProfile Health 3.1 adds support for Kubernetes startup probes in form of a new @Startup CDI qualifier, with WildFly exposing this check at the :9990/health/started endpoint. We’ve shipped an update of the MicroProfile Reactive Messaging subsystem to version 2.0 of the spec. This now integrates with MicroProfile Health for messages sent, and facilitates user-initiated code to push data to, and, to some extent, receive data from, Reactive Messaging streams. The MicroProfile Reactive Messaging subsystem now supports additional configuration of messages sent to Kafka, and provides means of getting information from Kafka on the receiving end. You can now connect to a secure Kafka instance using the MicroProfile Reactive Messaging functionality of WildFly. For cases where you are using self-signed certificates, the truststore can be specified in an SSLContext provided by the Elytron subsystem. WildFly now supports checking environment variables, in addition to system properties, when resolving expressions used in the server configuration. If a system property value can be found, that is returned as has happened until now. If no system property is found, the name is converted to environment property format and the value of the environment variable is checked. The conversion happens by replacing each character that is neither alphanumeric nor underscore with underscore, and then converting the name to upper case (i.e. com.acme-size becomes COM_ACME_SIZE). This feature makes it easier to reuse configuration in different deployment enviroments, particularly in cloud environments where environment variables are more readily used than system properties. Logging related to discovery of failed JCA connections during validation can now be disabled. Security Layer Changes A key focus in WildFly 25 has been completing our migration away from the legacy security layer that dates back to JBoss AS and onto the WildFly Elytron-based security layer introduced in WildFly 11. SE 17 does not provide packages that legacy security heavily relies upon, so the time has come to complete the transition off of legacy security. We deprecated the use of legacy security long ago and in the WildFly 25 release we have removed support for it. As part of this change you will see a number of significant changes in WildFly 25: Our standard configuration files no longer include legacy security realms. These are the 'security-realm' elements found under the 'management' element in a standalone.xml or host.xml file, administered via the CLI at '/core-service=management/security-realm=*' addresses. The xml parsers no longer support these elements and the management API no longer provides resources at these addresses. Elytron subsystem resources are now used. Use of the Picketbox-based security vault is no longer supported. Elytron credential stores should be used instead. The 'org.jboss.as.security' extension and the 'security' subsystem it provides are no longer supported on servers not running in 'admin-only' mode. The extension and subystem can still be used on a WildFly 25 Domain Controller to allow it to manage hosts running earlier versions of WildFly. The 'org.wildlfy.extension.picketlink' extension and the 'picketlink-federation' and 'picketlink-idm' subsystems it provides are no longer supported on servers not running in 'admin-only' mode. They can still be used on a WildFly 25 Domain Controller to allow it to manage hosts running earlier versions of WildFly. Note that the reason use of the legacy security and picketlink extensions is allowed on an 'admin-only' server is to allow a server with a configuration using those to boot so an administrator can then use the CLI to alter the server configuration to use Elytron. I very much encourage any of you still using legacy security in your configuration to start experimenting with WildFly 25. WildFly Preview As I announced last November when we released WildFly 22 Alpha1, along with our traditional Jakarta EE 8 distribution we want to give our users a preview of what will be coming in WildFly as we move on to EE 9 and later. We call this distribution "WildFly Preview". The WildFly 25.0.0.Final release includes an update to WildFly Preview. Even though this is coming from a .Final tag of the WildFly codebase, WildFly Preview should always be regarded as a tech-preview/beta distribution. To learn more about WildFly Preview, see the WildFly and WildFly Preview doc page. Java SE 17 Support I’m extremely pleased to be able to say that we can recommend you run WildFly 25 or WildFly Preview 25 on any of the long-term support Java SE releases, including Java SE 17. We’ve tested WildFly heavily on Java SE 8, Java SE 11 and Java SE 17. Our testing included testing WildFly Preview on SE 17 with the massive Jakarta EE 9.1 TCK. (More on that in the 'Standards Support' section below.) The most heavily tested SE options for WildFly are still SE 11 and SE 8, because both WildFly and its component library projects have so many years of testing on those versions. As I noted in my recent Changes are coming to WildFly post, it is likely that WildFly will drop support for SE 8 in one of the next few quarterly releases. Eventually the transition to Jakarta EE 10 support and the expected minimum requirement for SE 11 by some of its API projects will drive WildFly to only support SE 11 or later. As I described in that post, it’s possible this could happen as soon as WildFly 26, although I doubt that will happen and will work to avoid it. Please note that WildFly runs on Java 11 and later in classpath mode. Running WildFly 25 with SE 17 One of the key differences in SE 17 versus the previous LTS SE 11 release is that the JVM will reject reflective access calls that SE 11 would only warn about, unless the JVM launch command includes JPMS configuration options to allow that access. WildFly does quite a bit of deep reflection, so part of our efforts in recent releases has been to identify the necessary JPMS settings. We have added those to our standard launch scripts, so WildFly should just work if you’re using those. The manifest file in a WildFly bootable jar will also include these settings. But some users may not be using a bootable jar or using our launch scripts to launch WildFly. For example many users use IDEs to launch WildFly and count on the IDE to provide arguments to the JVM. And IDEs may not be using the necessary settings yet. If you are launching a WildFly instance on SE 17 and aren’t using a bootable jar or our launch scripts, here are the JPMS settings you will need: --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED Not all uses of the server will require all of those; the launch script sections that set those up include comments describing the main reason we’ve added each. It’s possible your application may do something that requires additional JPMS settings; if so you can add those to the JVM launch command by editing the 'bin/standalone.conf` or 'bin/domain.conf' file or their .bat or .ps1 variants. Standards Support The standard WildFly 25.0.0 distribution is a Jakarta EE 8 compatible implementation, compatible with both the Full Platform and the Web Profile. Evidence supporting our certification is available for the Full Platform and for the Web Profile. The standard WildFly 25 distribution is also a compliant implementation of the MicroProfile 4.1 platform specification. The WildFly Preview distribution released today is a compatible implementation of both the Jakarta EE 9.1 Web Profile and the Full Platform. WildFly Preview has been able to demonstrate compatibility while running on both Java SE 11 and on Java SE 17! Evidence supporting our certification is available for the Full Platform on SE 11, for the Web Profile on SE 11, for the Full Platform on SE 17 and for the Web Profile on SE 17. Many thanks to the folks in the Jakarta EE community who worked hard to make it possible to run the EE 9.1 TCKs on Java SE 17! Implementations being able to demonstrate compliance using an SE version that came out after the EE release did is an important step forward for Jakarta EE. Great Community I want to particularly thank a couple members of the WildFly community for their efforts during the WildFly 25 dev cycle. One is Darran Lofthouse, who coordinated the WildFly 25 Beta release, and did the biggest part of the very heavy lifting related to the removal of support for the legacy security layer. Another is Boris Unckel, who has been very active this year filing issues, mentoring new contributors and doing a lot of work helping to elevate WildFly’s code quality. Thank you Darran and Boris! I’d also like to invite participants in this month’s Hacktoberfest to come say 'Hi' in the wildfly-developers chat and find out about contributing to WildFly. Upcoming Changes WildFly 25 was the first in a series of a few releases where we’re expecting to make some big changes in the server. I encourage you to have a look at the Changes are coming to WildFly post that I mentioned above. Documentation The WildFly 25 documentation is available at the docs.wildfly.org site. The WildFly 25 management API documentation is in the wildscribe section of the WildFly 25 docs. Jira Release Notes The full list of issues resolved is available in the WFLY JIRA project. Issues resolved in the WildFly Core 17 releases included with WildFly 25 are available in the WFCORE JIRA project. Enjoy! Thank you for your continued support of WildFly. We’d love to hear your feedback at the WildFly forum. ### [Hacktoberfest Has Begun](/news/2021/10/05/Hacktoberfest-Has-Begun/) ### [Changes are coming to WildFly](/news/2021/09/27/Changes-are-coming-to-WildFly/) As significant changes percolate through the enterprise Java ecosystem, particularly progress on Jakarta EE 10 and the move to the jakarta.* namespace for the EE APIs, changes are also going to be coming to WildFly. In this post I want to describe what I see happening over the next few WildFly releases, starting with the WildFly 25 release that will be out soon. SE 17 and the WildFly security layer This month’s GA release of the Java SE 17 LTS release has highlighted the importance of WildFly being a good choice for those wanting to run applications on the latest SE. As a result, a key focus in WildFly 25 has been completing our migration away from the legacy security layer that dates back to JBoss AS and onto the WildFly Elytron-based security layer introduced in WildFly 11. Using Elytron security has been our recommended approach for several years now, but since SE 17 does not provide packages that legacy security heavily relies upon, the time has come to complete the transition off of legacy security. We deprecated the use of legacy security long ago and in the WildFly 25 release we are removing support for it. As part of this change you will see a number of significant changes in WildFly 25: Our standard configuration files no longer include legacy security realms. These are the 'security-realm' elements found under the 'management' element in a standalone.xml or host.xml file, administered via the CLI at '/core-service=management/security-realm=*' addresses. The xml parsers no longer support these elements and the management API no longer provides resources at these addresses. Elytron subsystem resources are now used. Use of the Picketbox-based security vault is no longer supported. Elytron credential stores should be used instead. The 'org.wildlfy.extension.picketlink' extension and the 'picketlink-federation' and 'picketlink-idm' subsystems it provided are no longer supported on servers not running in 'admin-only' mode. They can still be used on a WildFly 25 Domain Controller to allow it to manage hosts running earlier versions of WildFly. The 'org.jboss.as.security' extension and the 'security' subsystem it provides are no longer part of our standard configuration files. By the time WildFly 25.0.0.Final is released our intent is that these will no longer be supported on servers not running in 'admin-only' mode. The extension and subystem can still be used on a WildFly 25 Domain Controller to allow it to manage hosts running earlier versions of WildFly. Note that the reason use of the legacy security and picketlink extensions is allowed on an 'admin-only' server is to allow a server with a configuration using those to boot so an administrator can then use the CLI to alter the server configuration to use Elytron. I very much encourage any of you still using legacy security in your configuration to start experimenting with WildFly 25, including with the WildFly 25 Beta1 release we announced last week. EE 10 and the jakarta.* namespace Work on Jakarta EE 10 is ramping up, with a rough estimate GA date at the end of Q1 2022. WildFly contributors are of course involved with EE 10, including back-to-the-early-JBoss-days veteran Scott Stark driving the release overall, Scott Marlow playing a key role on the TCK and WildFly contributors active on a number of specs. WildFly intends to shift its EE support in its main distribution to EE 10 when it’s available. The precise release when that will happen is as yet unknown, but WildFly 28 seems a reasonable candidate, as following our normal quarterly release cadence that would be the release in development when EE 10 is expected to go GA. The WildFly Preview distribution of the server will shift toward EE 10 earlier than that. It currently targets EE 9.1 and has been an EE 9.1 compliant server since the 23.0.2 release. The primary purpose of WildFly Preview though is providing a tech preview look at what’s coming in future standard WildFly releases, and not so much things like strict EE compliance. So, as EE 10 components start to become available (even betas), if they work well in WildFly Preview we’ll start to integrate them in the WildFly Preview releases, even if that means we’re no longer EE 9.1 compliant. This may begin to happen with the WildFly Preview 26 release (expected in December) and almost certainly will in WildFly Preview 27. Moving on from Jakarta EE 8 support in standard WildFly By the time standard WildFly moves to EE 10 support, my expectation is the project will no longer produce feature releases that support Jakarta EE 8. As what we’ve done with WildFly Preview demonstrates, the WildFly architecture allows the project to support different variants that support different Jakarta EE versions, but I don’t believe the project will attempt to provide an EE 8 variant once the main distribution moves to EE 10. There are a number of reasons for this, all related to the effort involved: The EE 10 APIs are going to differ from the EE 8 APIs in ways that go beyond the javax.* vs jakarta.* package name differences between EE 8 and EE 9. Where those differences affect the server integration of those specs, we’d need to provide separate integration logic for EE 8 vs EE 10. That is certainly technically possible, but shifting the focus of WildFly’s contributors to developing and maintaining separate integrations would impact their ability to drive other innovation in the server. Similarly, as components we integrate absorb the jakarta namespace change and evolve in general, it is likely that their own APIs will evolve distinctly between their javax.* releases and their jakarta.* ones. This again would likely result in the need to develop and maintain separate integration logic. Different component sets between two variants of WildFly mean the need to monitor more component for CVEs and critical bugs. There is a lot of continuous integration testing that backs standard WildFly. Trying to test two different variants of standard WildFly, plus WildFly Preview, would put excessive strain on our CI infrastructure. When will this transition happen? Honest answer: I’m not sure. But it’s possible even WildFly 26 at the end of this year could move from EE 8 to EE 9.1. And the chances are pretty good WildFly 27 will. What would be required for WildFly to move from EE 8 to EE 9.1? We’d need to have native jakarta.* variants available in public maven repos of all components that use the EE APIs. WildFly Preview bytecode transforms components that use javax.* when it provisions a server, but for standard WildFly we would need to have components available from maven. We’re progressing toward achieving that, and there’s some possibility we’ll get there during the WildFly 26 development cycle. We would need to be able to continue to be EE 9.1 compliant with those components. Why would WildFly move to EE 9.1, instead of waiting for EE 10? The WildFly developers have been reluctant to move the standard distribution to EE 9.1, because it has no added functionality vs EE 8, it just brings a migration cost. So why would we move to EE 9.1 instead of just using WildFly Preview until EE 10 is ready? Basically what would drive this would be differences in our EE 8 vs EE 9+ components that force the need for overly-costly-to-maintain-and-test differences in the relevant server integration logic. It’s possible this could occur during the WildFly 26 cycle, and the chances increase as we get to WildFly 27. My hope though is that we can avoid this and can provide EE 8 until our EE 10 support is ready. I will post more about this as work continues and the picture becomes clearer. Support for SE 8 WildFly has long supported running on SE 8, but I expect that to come to an end over the next few releases. EE 10 itself does not require its constituent APIs to support the SE 8 source or binary level, and it’s very likely that a number of EE APIs will require SE 11. That means once WildFly itself is an EE 10 server, we will require SE 11 or later. It’s also possible that we will make this transition earlier than that, particularly if one or more of our major components requires SE 11. It’s possible this could happen as soon as WildFly 26, but I doubt it and would very much want to avoid it. As work on 26 proceeds, I’ll be sure to communicate if things are happening that make a move off of SE 8 in WildFly 26 or 27 look likely. Questions? If you have questions or want to provide feedback, I encourage you to post on the WildFly forum, on the wildfly-dev mail list or in Zulip chat. Best regards, Brian ### [WildFly 25 Beta1 S2I images have been released on quay.io](/news/2021/09/23/WildFly-25-Beta1-S2I-images-have-been-released-on-quay-io/) ly 25 Beta1 S2I images have been released on quay.io WildFly 25 Beta1 S2I Docker images The WildFly S2I (Source-to-Image) builder and runtime Docker images for WildFly 25 Beta1, have been released on quay.io/wildfly. For complete documentation on how to use these images using S2I, OpenShift and Docker, refer to the WildFly S2I README. Important changes to mention in this Beta release We have been evolving the s2i builder image to reflect part of the main changes that occurred in WildFly 25 Beta. In particular the s2i image content is impacted by the removal of legacy security: Changes in the default server configuration: Now secured with elytron. Security configuration based on legacy security-realms has been removed. security subsystem and extension have been removed. Impact on SSL configuration based on environment variables: elytron is now used by default to configure SSL. The env variable CONFIGURE_ELYTRON_SSL=true is no more needed. Impact on Keycloak integration: By default when configuring Keycloak OIDC and SAML adapters elytron was already in use. Nothing changes there. If you were using the env variable SSO_FORCE_LEGACY_SECURITY=true to rely on the legacy security subsystem, the server will fail to start, you will need to remove this env variable and rely on elytron integration. Anticipating a future support for OpenID Connect In this new release we are deprecating the usage of the keycloak Galleon layer and automatic configuration based on environment variables. We are planning in a future release to rely on the new WildFly subsystem that is providing a native support for OpenID Connect allowing to interact with Keycloak server but with also other servers compatible with the OIDC protocol. Stay tuned! ### [WildFly 25 Beta1 is released!](/news/2021/09/20/WildFly-25-Beta1-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 25.0.0.Beta1 releases are available for download at https://wildfly.org/downloads. Work during the WildFly 25 development cycle has been primarily oriented toward completing a long planned evolution of our security layer. Before diving into that topic, there are a few significant new feature areas where feedback from our users would be most welcome. A new subsystem providing support for OpenTelemetry Tracing. WildFly still provides MicroProfile OpenTracing as an alternative, but I encourage users to switch to the new OpenTelemetry subsystem. A new subsystem that provides native support for OpenID Connect. This allows you to do things like configure integration with a Keycloak server without needing to install the Keycloak client adapters. An update of the MicroProfile Reactive Messaging subsystem to version 2.0 of the spec, along with improvements in the ability to configure Reactive Messaging Kafka messages and security integration related improvements, particularly the ability to use an SSLContext configured in the Elytron subsystem. Ability to use the same expression as the value of a server configuration attribute and have it be resolvable from both a system property and an environment variable. This makes it easier to reuse configuraiton in different deployment enviroments, particularly in cloud environments where environment variables are more readily used than system properties. Elytron all the way; removal of legacy security support Over four years ago with the WildFly 11 release, WildFly introduced integration of the Elytron security project as its next generation security layer. From that point onward, use of Elytron has been our recommended approach to security in WildFly. However, we’ve continued to provide as well what we call "legacy security", i.e. security services that often integrate with Elytron under the covers, but which use to some degree the Picketbox security project that was the basis for security in JBoss AS and WildFly releases prior to WildFly 11. We continued to provide "legacy security" both to give our users time to shift their use to Elytron, and to give the Elytron layer time to evolve. Which it very much has, often accounting for the largest number of new features in a WildFly release! We deprecated the use of legacy security long ago, but now with the WildFly 25 release, we are removing support for it. There are a few reasons for this: The Picketbox and related Picketlink projects have not had an active community for some years now, and their project repos on Github are archived. There is no feature or enhancement work in these projects. For bug fixes WildFly has needed to rely on occasional bug fix releases produced by Red Hat for users of its Red Hat JBoss Enterprise Application Platform product. Picketbox makes extensive use of Java SE packages that were pruned in SE 14. With the advent of the SE 17 LTS release, we need to eliminate use of libraries that cannot function on SE 17. We feel the Elytron solution is better and that our users who have not yet migrated to it are better served by doing so. As part of this change you will see a number of significant changes in WildFly 25 Beta1: Our standard configuration files no longer include legacy security realms. These are the 'security-realm' elements found under the 'management' element in a standalone.xml or host.xml file, administered via the CLI at '/core-service=management/security-realm=*' addresses. The xml parsers no longer support these elements and the management API no longer provides resources at these addresses. Elytron subsystem resources are now used. Use of the Picketbox-based security vault is no longer supported. Elytron credential stores should be used instead. The 'org.wildlfy.extension.picketlink' extension and the 'picketlink-federation' and 'picketlink-idm' subsystems it provided are no longer supported on servers not running in 'admin-only' mode. They can still be used on a WildFly 25 Domain Controller to allow it to manage hosts running earlier versions of WildFly. The 'org.jboss.as.security' extension and the 'security' subsystem it provides are no longer part of our standard configuration files. By the time WildFly 25.0.0.Final is released our intent is that these will no longer be supported on servers not running in 'admin-only' mode. The extension and subystem can still be used on a WildFly 25 Domain Controller to allow it to manage hosts running earlier versions of WildFly. Note that the reason use of the legacy security and picketlink extensions is allowed on an 'admin-only' server is to allow a server with a configuration using those to boot so an administrator can then use the CLI to alter the server configuration to use Elytron. I very much encourage any of you still using legacy security in your configuration to start experimenting with WildFly 25. SE 17 While there are a few small issues related to running WildFly and WildFly Preview on SE 17 that we’ll sort out before WildFly 25 Final, overall it runs well and I encourage our community to try it and let us know if you have any problems. Domain Mode and "Mixed Domains" One aspect of WildFly’s domain mode of operation that doesn’t get a lot of attention is the ability for a Domain Controller running the latest version to manage remote Host Controllers running earlier versions. We call this a "mixed domain". Every few years we prune the number of legacy versions that a Domain Controller can support. We’re doing this with WildFly 25, restricting mixed domain support to hosts running WildFly 23 or later. WildFly Source-to-Image (s2i) Images The s2i image for WildFly 25.0.0.Beta1 is not yet available, but we expect it will be within a few days. When it is we’ll announce it separately. Release Notes The release notes for the release are here, with issues fixed in the underlying WildFly Core betas listed here. Please try it out and give us your feedback, while we get to work on WildFly 25 Final! Best regards, Brian ### [WildFly 24.0.1 S2I images have been released on quay.io](/news/2021/08/05/WildFly-24-0-1-S2I-images-have-been-released-on-quay-io/) WildFly 24.0.1 S2I Docker images The WildFly S2I (Source-to-Image) builder and runtime Docker images for WildFly 24.0.1, have been released on quay.io/wildfly. For complete documentation on how to use these images using S2I, OpenShift and Docker, refer to the WildFly S2I README. Helm Chart for WildFly The Helm Chart for WildFly has been updated to use the WildFly S2I 24.0.1 images. The microprofile example is a good place to start using the Helm Chart with the WildFly S2I images. Enjoy! ### [WildFly 24.0.1 is released!](/news/2021/07/28/WildFly-24-0-1-is-released/) WildFly 24.0.1.Final is now available for download. It’s been about six weeks since the WildFly 24 release, so we’ve done a small bug fix update, WildFly 24.0.1. This includes an update to WildFly Preview. The full list of issues resolved in WildFly 24.0.1 is available here. Issues resolved in the WildFly Core update included with WildFly 24.0.1 are available here. Enjoy! ### [Helm Chart for WildFly in OpenShift Developer Console](/news/2021/07/13/Helm-Chart-for-WildFly-in-OpenShift-Developer-Console/) We have recently released a Helm Chart for WildFly and wrote an article about it. Since that article, we have submitted this Helm Chart to the OpenShift Developer Console. It is now possible to build and deploy a WildFly application in OpenShift directly from its Developer Console. In this article, we will show the steps to do so. We will use Red Hat Developer Sandbox for Red Hat OpenShift as our OpenShift cluster. For this article, we will use the same microprofile-config quickstart for WildFly that we used in our initial article about the Helm Chart. Install a Helm Release Once you have logged in your OpenShift Developer Sandbox, the steps to install a WildFly application are: Go to the OpenShift Developer Console (in the </> Developer perspective in the left hand menu) Click on +Add, then Helm Chart, then WildFly (at the time of this writing, the exact version is WildFly v1.4.0) Click on the Install Helm Chart button At this point, we need to configure the chart to be able to build and deploy the microprofile-config quickstart. First, we will change the name of the release to my-wildfly-app in the Release Name text field instead of the default wildfly name. We can configure the Helm Chart either using a Form View or a YAML View. We will use the YAML View by checking the button in the Configure via box. Then, we will change the YAML content to configure the Helm Chart by copying the following content in the YAML view instead of the existing content: build: uri: https://github.com/wildfly/quickstart.git ref: 24.0.0.SP1 mode: bootable-jar env: - name: ARTIFACT_DIR value: microprofile-config/target - name: MAVEN_ARGS_APPEND # Use the bootable-jar-openshift profile to ensure that the application # can be deployed on OpenShift but disable JKube as the image will be # built and deployed by this chart. value: -am -pl microprofile-config -Pbootable-jar-openshift -Djkube.skip=true - name: MAVEN_OPTS value: '-XX:MetaspaceSize=251m -XX:MaxMetaspaceSize=256m' deploy: replicas: 1 env: - name: CONFIG_PROP value: Hello from OpenShift This is the same YAML content that we used in the inital article when we install the Helm Chart from the command line. Finally, we click on the Install button to finish the installation. This will open the Topology view with a graphical represenation of the Helm realease (named my-widlfly-app) and its associated resources: Figure 1. Helm Release of the application displayed in OpenShift Topology view The Helm Release (abbreviated HR) is named my-wildlfy-app and uses the WildFly icon to shows that this release is managed by the Helm Chart for WildFly. It includes a Deployment resource (abbreviated D) also named my-wildlfy-app. When build is finished (the bottom-left icon will display a green check) and the application is deployed (the circle outline is in dark blue), you can go the the URL (using the top-right icon) from the route associated to the deployment, append /config/value and you will see the message: Hello from OpenShift This message corresponds to the CONFIG_PROP environment variable defined in the Helm Chart YAML file. Congratulations, you have built and deployed your first Java application with WildFly on OpenShift! Upgrade the Helm Release It is possible to upgrade the Helm Release to change its configuration from the OpenShift Developer Console. Click on the Helm in the left hand menu Click on the my-wildfly-app link to open the page specific to our Helm release. Click on the Actions menu in the right of the page and select Upgrade. This will show the Upgrade Helm Release page. The YAML View in that page contains some additional content compared to what was initially pasted. The OpenShift developer console aggregates some of the chart’s default values with the YAML content we provided. Let’s say we want to modify the message returned by our application. We will change the value of the CONFIG_PROP environement variable to Bonjour depuis OpenShift (instead of Hello from Openshift) deploy: ... env: - name: CONFIG_PROP value: Bonjour depuis OpenShift At this point, we click on Upgrade to upgrade the Helm release. As we have only modified the deploy section of the Helm release, we will reuse the existing application image and redeploy it with the new environment variable. Once the application is redeployed, if we click on the Route button and append /config/value, we see that the application has correctly been upgraded: Bonjour depuis OpenShift Warning Prior to OpenShift 4.8, there was a bug preventing to directly upgrade the Helm Release. To workaround that error, we had to reload the initial Chart version and apply our changes. Copy the modified content of the YAML view. Change the "Chart version" in the right hand corner from 1.4.0 / App Version 24.0 to 1.4.0 / App Version 24.0 (Provided by Red Hat Helm Charts). A confirmation window will open, click on Proceed to accept the change Paste the YAML content that was just copied back in the YAML view We can now click on the Upgrade button to finally upgrade the Helm release. Conclusion Now that the Helm Chart for WildFly is included by default in OpenShift Developer console, it is straightforward to build and deploy WildFly application in an OpenShift cluster. It is also possible to upgrade the Helm release so that it remains the source of any configuration from the application, although we need to reset the Chart version every time we want to apply such an upgrade. More information Initial Article about the Helm Chart for WildFly wildfly-charts Project Page wildfly Chart documentation Developer Sandbox for Red Hat OpenShift ### [Run WildFly Preview of Jakarta EE 9.1 with Bootable Jar](/news/2021/07/01/Run-WildFly-Preview-of-Jakarta-EE-9-1-with-Bootable-Jar/) Jakarta EE 9.1 has been recently released and WildFly 24.0.0.Final provides a preview to run existing Jakarta EE 8 applications on it. In this blog, we will take a simple existing Jakarta EE 8 applications (the WildFly JAX-RS quickstart) and modify the project structure to run it on WildFly with the EE 9.1 Preview. Compiling with Jakarta EE 8, Running with Jakarta EE 9.1 We will not change the code of the application itself that is compiled against Jakarta EE 8. We will only change its execution to run on top of Jakarta EE 9.1. The application in itself is a simple JAX-RS application that has a /rest/json HTTP endpoint. The application code imports the javax.ws.rs.ApplicationPath annotation. The javax.ws.rs package means that the code is compiled against Jakarta EE 8. In Jakarta EE 9.1, the specification is now named Jakarta RESTful Web Services) and its package is jakarta.ws.rs. Configuring Bootable Jar in pom.xml To run this application with WildFly EE 9.1 Preview, we will use the Bootable Jar mode that bundles WildFly and the application in a single runnable Jar. To achieve this, we have to modify the pom.xml and add the following section: <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>5.0.0.Final</version> <configuration> <feature-pack-location>wildfly-preview@maven(org.jboss.universe:community-universe)</feature-pack-location> <layers> <layer>jaxrs-server</layer> </layers> <plugin-options> <jboss-fork-embedded>true</jboss-fork-embedded> </plugin-options> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> With that setting, the application will now be packaged by default using Bootable Jar when we run mvn package. There are 2 important lines in the code snippet: <feature-pack-location>wildfly-preview@maven(org.jboss.universe:community-universe)</feature-pack-location> This line means that we will use the wildfly-preview feature-pack to install and provision the WildFly Server so that it runs with Jakarta EE 9.1. If we had specify instead wildfly@maven(…​), we would have install a regular WildFly server to run with Jakarta EE 8. <layer>jaxrs-server</layer> As our application is a simple JAX-RS application, we only provision the jaxrs-server layer when we install WildFly in the Bootable Jar. This ensures that we have all we need to run a JAX-RS application and nothing more. We can now package the application as a Bootable Jar by running the command: $ mvn clean package Once the Maven command is finished, we can start the application by running the command: $ java -jar target/helloworld-rs-bootable.jar There are some interesting lines in the log when the application starts: 08:36:38,676 INFO [org.jboss.as] (MSC service thread 1-1) WFLYSRV0049: WildFly Preview 24.0.0.Final (WildFly Core 16.0.0.Final) starting This line above shows that we are running WildFly Preview (and not the regular WildFly). 08:36:54,301 INFO [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 62) RESTEASY002225: Deploying jakarta.ws.rs.core.Application: class org.jboss.as.quickstarts.rshelloworld.JAXActivator$Proxy$_$$_WeldClientProxy This line above confirms that we are running with Jakarta EE 9.1 as the application is deployed with jakarta.ws.rs.core.Application which is in the namespace for Jakarta EE 9.1. So we have deployed a Jakarta EE 8 application in a Jakarta EE 9.1 server, let’s check that the application works as expected: $ curl http://:8080/rest/json {"result":"Hello World!"} Run with Jakarta EE 9.1 on OpenShift We are now successfully running our JAX-RS application locally with WildFly EE 9.1 Preview. What do we need to run it on OpenShift? It turns out we don’t need much more. We can leverage the JKube integration for WildFly Bootable Jar to create an application image and deploy it on OpenShift. We need to add another snippet to the pom.xml: <profiles> <profile> <id>openshift</id> <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>5.0.0.Final</version> <configuration> <cloud/> </configuration> </plugin> <plugin> <groupId>org.eclipse.jkube</groupId> <artifactId>openshift-maven-plugin</artifactId> <version>1.0.1</version> <executions> <execution> <goals> <goal>resource</goal> <goal>build</goal> </goals> </execution> </executions> <configuration> <enricher> <config> <jkube-service> <type>NodePort</type> </jkube-service> </config> </enricher> </configuration> </plugin> </plugins> </build> </profile> </profiles> This openshift profile ensures that the Bootable Jar will be configured for the cloud and that JKube will create all the required resources to run in on OpenShift. Note To be able to deploy the application on OpenShift, you need access to an OpenShift cluster (such as the Red Hat Developer Sandbox) and have successfully logged in by running the oc login …​ command Once we have modify the pom.xml, we can deploy the application on OpenShift by running the command: $ mvn oc:deploy -Popenshift Once the Maven command is finished, we can verify that our application is running on OpenShift by looking at the pods state: $ oc get pods -w helloworld-rs-1-deploy 0/1 Completed 0 2m28s helloworld-rs-1-h9w28 1/1 Running 0 2m20s We can then access our application as JKube automatically created a Route to access it outside of the OpenShift cluster: $ curl -L $(oc get route helloworld-rs -o jsonpath="{.spec.host}")/rest/json {"result":"Hello World!"}% Conclusion In this article, we presented the steps to run an existing Jakarta EE 8 application on WildFly EE 9.1 Preview. We were able to run the application locally and on OpenShift. The first step was to use WildFly Bootable Jar to bundle the application and uses the wildfly-preview feature-pack to install the server with EE 9.1 The second step was to configure JKube to be able to deploy the application with OpenShift. Theses steps can help starting the migration process of your applications from Jakarta EE 8 to Jakarta EE 9.1 ### [WildFly 24 S2I images have been released on quay.io](/news/2021/06/22/WildFly-24-S2I-images-have-been-released-on-quay-io/) WildFly 24 S2I Docker images The WildFly S2I (Source-to-Image) builder and runtime Docker images for WildFly 24 have been released on quay.io/wildfly. The S2I builder image has been upgraded with the following content: WildFly datasources Galleon feature-pack 2.0. This feature-pack defines some Galleon layers to provision drivers and datasources for: MariaDB, Microsoft SQL Server, MySQL, Oracle DB and PostgreSQL. You can learn how to configure the drivers by reading the feature-pack documentation. Keycloak adapter has been upgraded to the version 13.0.1. For a complete documentation on how to use these images using S2I, OpenShift and Docker, refer to the WildFly S2I README. Helm Chart for WildFly Helm Chart for WildFly has been updated to use the WildFly S2I 24.0 images. The microprofile example is a good place to start using Helm Chart with the WildFly S2I images. Enjoy! ### [WildFly 24 is released!](/news/2021/06/17/WildFly-24-is-released/) I’m pleased to announce that the WildFly 24 Final zip is now available for download. Work during the WildFly 24 development cycle has been primarily oriented toward bug fixing, plus the Jakarta EE 9.1 certification work done for WildFly 23. We’ve also been doing work on getting WildFly Preview to run well on SE 16 and 17, with a goal of being able to support SE 17 in standard WildFly later this year. There are a number of new features in 24 though: New Features The MicroProfile Reactive Streams Operators subsystem has been updated to support version 2.0. It is now possible to specify the character set and hash encoding strings to verify client-supplied passwords against passwords stored in a Properties Realm, Filesystem Realm, JDBC Realm and LDAP realm in the Elytron subsystem. Older JDK versions use the protocol SSLv2Hello in the initial handshake message where the SSL version that will be used for the rest of the handshake is negotiated. Although the use of this protocol is discouraged and disabled by default in newer JDK versions, in order to ensure feature parity with legacy security configurations it is now possible to configure a client or server SSL context using the SSLv2Hello protocol in the Elytron subsystem. Elytron previously supported configuring one certificate revocation list. However, if several Certificate Authorities were used, there was no way to configure more than one certificate revocation file. It is now possible to configure multiple certificate revocation lists in Elytron. A new quickstart todo-backend showcases how WildFly can be deployed on OpenShift to provide a backend that exposes an HTTP API (using Jakarta RESTful Web Services) and stores data to a DB (using Jakarta Persistence). Codehaus Jackson Removal Please note that in WildFly 24 we’ve removed the Codehaus Jackson libraries from the server distribution, along with support for the Jakarta RESTful Web Services provider that used Codehaus Jackson. For many years now a provider based on the successor FasterXML Jackson project has been available and is the preferred option for those wanting to use Jackson. WildFly Preview As I announced in November when we released WildFly 22 Alpha1, along with our traditional Jakarta EE 8 distribution we want to give our users a preview of what will be coming in WildFly as we move on to EE 9 and later. We call this distribution "WildFly Preview". The WildFly 24.0.0.Final release includes an update to WildFly Preview. Even though this is coming from a .Final tag of the WildFly codebase, WildFly Preview should always be regarded as a tech-preview/beta distribution. EE 9 is primarily about implementing the necessary change in the Jakarta EE APIs from the javax.* package namespace to the jakarta.* namespace. This is a big change that is going to take a while to percolate through the EE ecosystem, e.g. for the many projects that compile against the EE APIs to provide versions that use jakarta.*. While this happens we want to continue to deliver new features and fixes to our community, so the primary WildFly distribution will continue to provide the EE 8 APIs. This will continue at least through WildFly 25. Standards Support The standard WildFly 24.0.0 distribution is a Jakarta EE 8 compatible implementation, compatible with both the Full Platform and the Web Profile. Evidence supporting our certification is available for the Full Platform and for the Web Profile. Beginning with WildFly 23 we are exclusively focusing on the Jakarta EE test suite for EE certification / compliance. The standard WildFly 24 distribution is also a compliant implementation of the MicroProfile 4.0 platform specification. The WildFly Preview distribution released today is a compatible implementation of both the Jakarta EE 9.1 Web Profile and the Full Platform. Evidence supporting our certification is available for the Full Platform and for the Web Profile. JDK Support Our recommendation is that you run WildFly on the most recent long-term support JDK release, i.e. on JDK 11 for WildFly 24. While we do do some testing of WildFly on JDK 13, we do considerably more testing of WildFly itself on the LTS JDKs, and we make no attempt to ensure the projects producing the various libraries we integrate are testing their libraries on anything other than JDK 8 or 11. WildFly 24 also is heavily tested and runs well on Java 8. We plan to continue to support Java 8 at least through WildFly 25, and probably beyond. While we recommend using an LTS JDK release, I do believe WildFly runs well on JDK 13. By run well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. A major focus during the WildFly 24 development cycle was on identifying and addressing issues related to running WildFly on JDK 16 and the early access releases of JDK 17. JDK 17 is due out in September and will be the next LTS JDK release, so we want to be ready to support it as soon as we can. I’m pleased to be able to say that the 24.0.0.Final release of WildFly Preview runs well on SE 16 and the SE 17 early access release for most use cases. The main use case where we still have some issues to resolve relate to Hibernate’s proxy generation, but these don’t prevent JPA from working well in general. For developers wanting to get a sense of what SE 17 will mean for their applications, I encourage you to give WildFly Preview 24 a look. Standard WildFly does not run well on SE 14 or later because the security implementation used in our standard configurations will not work on SE 14 or later. However if you want to experiment with standard WildFly 24 on the latest SE, you can try starting with the configuration files provided in WildFly Preview, which do not use the legacy security subsystem. This has not been heavily tested, so YMMV. Please note that WildFly runs on Java 11 and later in classpath mode. Upcoming Changes Beginning with WildFly 25 there will be some significant changes coming in WildFly, primarily related to moving completely to Elytron-based security and away from the legacy security implementation. Significant changes you can expect to see include: Removal of the legacy security subsystem from the standard configurations. Removal of support for the security vault, with Elytron credential stores as the replacement. Removal of the core management security realms from the standard configurations, with Elytron subsystem resources used instead. Removal of the Picketlink extension and the subsystems it provides. Potentially the Picketbox libraries will no longer be available, making the legacy security subsystem and core management security realms unavailable altogether on a server. Unrelated to security, "legacy feature-packs" (which use a provisioning technology that predates Galleon) will no longer be distributed. We’re also evaluating changes in domain mode to limit the set of older version Host Controllers a current Domain Controller must be able to support, reducing the set to some of the more recent WildFly versions. Documentation The WildFly 24 documentation is available at the docs.wildfly.org site. The WildFly 24 management API documentation is in the wildscribe section of the WildFly 24 docs. Jira Release Notes The full list of issues resolved is available in the WFLY JIRA project. Issues resolved in the WildFly Core 16 release included with WildFly 24 are available in the WFCORE JIRA project. Enjoy! Thank you for your continued support of WildFly. We’d love to hear your feedback at the WildFly forum. ### [How to Change Logging Level for WildFly on the Cloud](/news/2021/06/15/How-to-Change-Logging-Level-for-WildFly-on-the-Cloud/) When your WildFly application is running on the Cloud (on Kubernetes, OpenShift or any other container platform) and starts to behave unexpectedly, it is useful to be able to change the logging of the server to display debug logs to get a better insight. In this article, I will walkthrough a very simple script that can be used to change the logging level of a WildFly server in an application image on the (wild) fly. WildFly Management Commands By default, the WildFly server is configured to display INFO logs on the console. These logs are the output displayed by the command kubectl logs <pod>): $ kubectl logs wildfly-s2i-app-8f8b49957-b7xbk ... 08:10:40,347 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 23.0.2.Final (WildFly Core 15.0.1.Final) started in 15658ms - Started 288 of 383 services (156 services are lazy, passive or on-demand) 08:10:40,348 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://0.0.0.0:9990/management 08:10:40,348 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0054: Admin console is not enabled If we need to change the logging level to display debug logs, we can use the jboss-cli.sh script located in the WildFly server directory to execute two management commands: $ kubectl exec -it wildfly-s2i-app-8f8b49957-b7xbk -- sh sh-4.2$ $JBOSS_HOME/bin/jboss-cli.sh -c [standalone@localhost:9990 /] /subsystem=logging/console-handler=CONSOLE:write-attribute(name=level,value=DEBUG) {"outcome" => "success"} [standalone@localhost:9990 /] /subsystem=logging/root-logger=ROOT:write-attribute(name=level,value=DEBUG) {"outcome" => "success"} With that change, we can no see DEBUG logs in the console output: $ kubectl logs wildfly-s2i-app-8f8b49957-b7xbk ... 08:26:35,002 DEBUG [io.undertow.request] (default I/O-2) Matched default handler path /config/value 08:26:35,004 DEBUG [org.jboss.resteasy.resteasy_jaxrs.i18n] (default task-1) RESTEASY002315: PathInfo: /config/value 08:26:35,005 DEBUG [org.jboss.resteasy.cdi.i18n] (default task-1) RESTEASY010520: Beans found for class org.wildfly.quickstarts.microprofile.config.ConfigResour ce : [Managed Bean [class org.wildfly.quickstarts.microprofile.config.ConfigResource] with qualifiers [@Any @Default]] 08:26:35,006 DEBUG [org.jboss.resteasy.resteasy_jaxrs.i18n] (default task-1) MessageBodyWriter: org.jboss.resteasy.spi.ResteasyProviderFactory$SortedKey 08:26:35,006 DEBUG [org.jboss.resteasy.resteasy_jaxrs.i18n] (default task-1) MessageBodyWriter: org.jboss.resteasy.plugins.providers.StringTextStar JBOSS_HOME environment variable These commands work fine when the application image has been built with WildFly S2I as the JBOSS_HOME environment variable is set and we can invoke $JBOSS_HOME/bin/jboss-cli.sh without any issue. However if the application image has been built with Bootable Jar, there is no JBOSS_HOME as the server will be unzipped when the container is started. How can we then determine the actual location of the server? When the container image is started, a special file is created at /opt/jboss/container/wildfly-bootable-jar/install-dir whose content is the actual location of the unzipped WildFly server for this specific pod: $ kubectl exec -it wildfly-bootable-jar-app-7cf8bdc95c-j9mjk -- sh sh-4.4$ cat /opt/jboss/container/wildfly-bootable-jar/install-dir /tmp/wildfly-bootable-server15112249313411534387 With that knowledge, we can update our script to set the value of the JBOSS_HOME environment with the content of that file if it exists: sh-4.4$ [ -e /opt/jboss/container/wildfly-bootable-jar/install-dir ] && JBOSS_HOME=$( cat /opt/jboss/container/wildfly-bootable-jar/install-dir ) sh-4.4$ echo $JBOSS_HOME /tmp/wildfly-bootable-server15112249313411534387 change-log-level Script We can now write a very simple script that can be used to change the global logging level one any WildFly application image. The script is available at https://gist.github.com/jmesnil/78581f90c68f84ba9240ef48f627ff45 and is straigthforward to use: $ wget https://gist.githubusercontent.com/jmesnil/78581f90c68f84ba9240ef48f627ff45/raw/062b3f1a8f7cf6e85b233e69348c97d006003a92/change-log-level $ chmod u+x change-log-level $ ./change-log-level change-log-level is a script to change the logging level of the WildFly server inside an application image running on any Kubernetes cluster. Usage: change-log-level <pod> <logging-level> Where the parameters are: * <pod> - Name of the pod running the application image * <logging-level> - The logging level to set (can be one of ALL, FINEST, FINER, TRACE, DEBUG, FINE, CONFIG, INFO WARN, WARNING, ERROR, SEVERE, FATAL, OFF) $ ./change-log-level wildfly-bootable-jar-app-7cf8bdc95c-j9mjk DEBUG Change logging level to TRACE for WildFly server in wildfly-microprofile-config-app-7cf8bdc95c-j9mjk [standalone@localhost:9990 /] /subsystem=logging/console-handler=CONSOLE:write-attribute(name=level,value=DEBUG) {"outcome" => "success"} [standalone@localhost:9990 /] /subsystem=logging/root-logger=ROOT:write-attribute(name=level,value=DEBUG) {"outcome" => "success"} $ kubectl logs wildfly-bootable-jar-app-7cf8bdc95c-j9mjk 10:14:10,380 DEBUG [io.undertow.request] (default I/O-1) Matched default handler path / 10:14:10,381 DEBUG [org.jboss.resteasy.resteasy_jaxrs.i18n] (default task-1) RESTEASY002315: PathInfo: / 10:14:10,382 DEBUG [org.jboss.resteasy.cdi.i18n] (default task-1) RESTEASY010520: Beans found for class org.wildfly.quickstarts.microprofile.config.RootResource : [Managed Bean [class org.wildfly.quickstarts.microprofile.config.RootResource] with qualifiers [@Any @Default]] 10:14:10,393 DEBUG [org.jboss.resteasy.plugins.validation.i18n] (default task-1) RESTEASY008510: ResteasyCdiExtension is on the classpath. 10:14:10,394 DEBUG [org.jboss.resteasy.resteasy_jaxrs.i18n] (default task-1) MessageBodyWriter: org.jboss.resteasy.spi.ResteasyProviderFactory$SortedKey 10:14:10,394 DEBUG [org.jboss.resteasy.resteasy_jaxrs.i18n] (default task-1) MessageBodyWriter: org.jboss.resteasy.plugins.providers.StringTextStar Note This script is doing a brute-force switch of the root logger and will change the log level of all loggers in the WildFly server. In a more realistic case, you would have to adapt the management commands to change the log level on more specific loggers related to your application to reduce the noise from other loggers. This can easily be done by updating the script and changing the commands from the WILDFLY_COMMANDS property. Conclusion This simple script is useful to be able to change the logging of the server to display debug logs to get a better insight. It can be used as the basis to run any kind of management commands on WildFly in an application image. ### [WildFly 24 Beta1 is released!](/news/2021/06/04/WildFly-24-Beta1-is-released/) I’m pleased to announce that the new WildFly and WildFly Preview 24.0.0.Beta1 releases are available for download at https://wildfly.org/downloads. Work during the WildFly 24 development cycle has been primarily oriented toward bug fixing, plus the Jakarta EE 9.1 certification work done for WildFly 23. But I do want to express my special thanks to Sonia Zaldana, a great contributor to WildFly over the past year, who has added three new features in WildFly 24 Beta1: Security Realm support for specifying the charset and encoding for credentials. Additional Elytron server-ssl-context allowed protocols. Certificate revocation lists The other area of focus during this development cycle was improving how WildFly, particularly WildFly Preview, runs on JDK 16 and the early access releases of the next LTS JDK release, JDK 17. There are still some issues to resolve, but WildFly Preview 24 Beta1 runs well enough on the latest JDKs that it’s worthwhile for people interested in what JDK 17 will mean for their application to give it a look. The release notes for the release are here, with issues fixed in the underlying WildFly Core betas listed here. Please try it out and give us your feedback, while we get to work WildFly 24 Final! Best regards, Brian ### [Helm Chart for WildFly](/news/2021/05/05/Helm-Chart-for-WildFly/) Helm is a tool that helps define, install and upgrade complex applications on Kubernetes clusters. We have now released a Helm Chart for WildFly to help our users build and deploy WildFly applications on OpenShift that leverages all the innovative features provided by the WildFly ecosystem. The wildfly Chart can be used to achieve two objectives: build an application image from a Git repository containing a Java project. This step leverages WildFly features such as Galleon provisioning or Bootable Jar to provide the fittest image for your application requirements. deploy an application image with all the resources and configuration needed to integrate it on OpenShift. By default, the two steps are connected: the build step’s output is an application image that becomes the input of the deploy step. However, it is possible to enable or disable these steps: if you have another way to build your application image, you can disable the build step and still deploy it by specifying where your application image can be pulled. All the chart configuration is described in the Chart documentation. In this post, we will focus on a simple MicroProfile application to show you how the Helm chart simplifies its deployment on OpenShift. MicroProfile Application Example We will use one WildFly quickstart as an example: microprofile-config. We will not cover the code of this example but the important things to mention are: This application will be running as a WildFly Bootable Jar It uses MicroProfile API and provides a HTTP endpoint. A WildFly server will be provisioned with the jaxrs-server and microprofile-platform layers so that server contains all the bits (and only those!) to run these features. Its HTTP endpoint uses MicroProfile Config to read a config property from the CONFIG_PROP environment variable and returns its value in the HTTP response. Install Helm and have access to an OpenShift cluster. Please refer to Installing Helm page to install Helm in your environment. We will use Developer Sandbox for Red Hat OpenShift as our OpenShift cluster and make sure that we are logged in the cluster and that the oc command applies to that cluster. Install Helm Repository for WildFly Chart The wildfly Chart can be installed from the https://docs.wildfly.org/wildfly-charts/ repository $ helm repo add wildfly https://docs.wildfly.org/wildfly-charts/ "wildfly" has been added to your repositories $ helm search repo wildfly NAME CHART VERSION APP VERSION DESCRIPTION wildfly/wildfly 1.3.0 23.0 Build and Deploy WildFly applications on OpenShift The first thing to notice is that the APP VERSION points to 23.0. By default, the Chart will deploy your application using the latest WildFly 23.0 release (23.0.2.Final at the time of this writing). Install the Application on OpenShift Once the wildfly Chart is added, we can instal a Helm release by using the helm install command with the name of the release as well as a YAML configuration file that contains all the settings to build and deploy the application: $ helm install microprofile-config-app \ wildfly/wildfly \ -f https://raw.githubusercontent.com/wildfly/wildfly-charts/main/examples/microprofile-config/microprofile-config-app.yaml NAME: microprofile-config-app LAST DEPLOYED: Tue May 4 14:52:02 2021 NAMESPACE: jmesnil1-dev STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Your WildFly appplication is building! To follow the build, run: $ oc get build -w Note that your Deployment will report "ErrImagePull" and "ImagePullBackOff" until the build is complete. Once the build is complete, your image will be automatically rolled out. To follow the deployment of your application, run: $ oc get deployment microprofile-config-app -w As you can read above, the ouput of the helm install command contains instructions to follow the installation of the application. We can watch its build by running: $ oc get build -w NAME TYPE FROM STATUS STARTED DURATION microprofile-config-app-1 Source Git@7f0eed5 Running 2 minutes ago microprofile-config-app-1 Source Git@7f0eed5 Complete 4 minutes ago 4m30s After the application is built, we can watch its deployment by running: $ oc get deployment microprofile-config-app -w NAME READY UP-TO-DATE AVAILABLE AGE microprofile-config-app 0/1 1 0 4m4s microprofile-config-app 0/1 1 0 4m30s microprofile-config-app 1/1 1 1 5m17s The application is now available and we can query it. By default, the Helm Chart will create a Route to access the application: $ oc get route NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD microprofile-config-app microprofile-config-app-jmesnil1-dev.apps.sandbox-m2.ll9k.p1.openshiftapps.com microprofile-config-app <all> edge/Redirect None Note The HOST/PORT value is specific to my cluster and your route will have a different value We can then query the HTTP endpoint by using this information: $ curl -L http://$(oc get route microprofile-config-app -o jsonpath="{.spec.host}")/config/value Hello from OpenShift The application is up and running. Let’s now look at the configuration file that the Chart used to install the application. Looking at the Helm Release File Let’s deep dive in the YAML File that we use to install the application (https://raw.githubusercontent.com/wildfly/wildfly-charts/main/examples/microprofile-config/microprofile-config-app.yaml): build: uri: https://github.com/wildfly/quickstart.git ref: 23.0.2.SP1 mode: bootable-jar env: - name: ARTIFACT_DIR value: microprofile-config/target - name: MAVEN_ARGS_APPEND # Use the bootable-jar-openshift profile to ensure that the application # can be deployed on OpenShift but disable JKube as the image will be # built and deployed by this chart. value: -am -pl microprofile-config -Pbootable-jar-openshift -Djkube.skip=true - name: MAVEN_OPTS value: '-XX:MetaspaceSize=251m -XX:MaxMetaspaceSize=256m' deploy: replicas: 1 env: - name: CONFIG_PROP value: Hello from OpenShift The first thing to notice is that the configuration file contains two main sections build and deploy. The build section focuses on building the application image using an OpenShift BuildConfig resource. The BuildConfig resource pulls the application from a Git repository (based on the uri and ref fields). The mode field specifies which types of application image to build. There are two valid modes: s2i and bootable-jar. The s2i build mode uses WildFly Source-to-Image (S2I) Builder and Runtime images to create the application image. In the bootable-jar build mode, the BuildConfig will compile the application as a Bootable Jar and use the OpenJDK 11 image as the base image. Finally there is an env section that contains any environment variables needed to build the image. We have three environment variables that are needed for Maven options. As a whole they mean that we build only the specific microprofile-config Maven module from the quickstart Git repository with the bootable-jar-openshift Maven Profile (to create a Bootable Jar) and use its artifact as the target of the application image. The deploy section focuses on deploying the application image on OpenShift. It creates different resources (Deployment, one or many Services, a Route) to make the application accessible from inside and outside the cluster by default. We have only defined two fields in that section: replicas which specifies the number of pods that the application will use env wich are environment variables needed to run the image. In our example, we only have one named CONFIG_PROP and its value is used in the HTTP endpoint’s response. There are a lot of things to discuss with this chart and we will have other blog posts to showcase its features. All of them are documented in the wildfly Chart documentation. However as a last example, one of the interesting features of Helm is that the YAML configuration file can be overridden on the command line to provide additional customization to the application. To highlight this, we will upgrade the application by changing the number of replicas of the applications so that we have 3 pods instead of 1 (by setting the deploy.replicas field to 3 with the helm upgrade command) $ helm upgrade microprofile-config-app \ wildfly/wildfly \ -f https://raw.githubusercontent.com/wildfly/wildfly-charts/main/examples/microprofile-config/microprofile-config-app.yaml \ --set deploy.replicas=3 Release "microprofile-config-app" has been upgraded. Happy Helming! NAME: microprofile-config-app LAST DEPLOYED: Tue May 4 15:21:29 2021 NAMESPACE: jmesnil1-dev STATUS: deployed REVISION: 2 TEST SUITE: None NOTES: If we watch the deployment, we see that the application is now scaling up to 3: $ oc get deployment microprofile-config-app -w NAME READY UP-TO-DATE AVAILABLE AGE microprofile-config-app 1/3 3 1 29m microprofile-config-app 2/3 3 2 30m microprofile-config-app 3/3 3 3 30m Conclusion The Helm Chart for WildFly simplifies building and deploying WildFly application on OpenShift and Kubernetes. This wildfly Chart is designed to leverage WildFly features (such as Bootable Jar, Galleon provisioning, S2I) to make sure WildFly applications can be deployed and maintained on OpenShift with ease. More information Helm - The package manager for Kubernetes wildfly-charts Project Page wildfly Chart documentation Developer Sandbox for Red Hat OpenShift WildFly Bootable Jar ### [WildFly 23.0.2 is released!](/news/2021/04/29/WildFly-23-0-2-is-released/) WildFly 23.0.2.Final is now available for download. After the release of Jakarta EE 9 the Jakarta EE Platform Project has been busy with the Jakarta EE 9.1 Release. This has now progressed to the point that a candidate release of the Jakarta EE 9.1 TCK is available with WildFly 23.0.2.Final being our release candidate as a compatible implementation based on this TCK. WildFly Preview and Jakarta EE 9 The WildFly Preview variant of the server still passes the Jakarta EE 9 for the TCKs Full Platform and the Web Profile. We have previously sent a compatibility certification request for the Full Platform for WildFly Preview 23.0.1.Final and a compatibility certification request for the Web Profile for WildFly Preview 23.0.0.Final. Once released, Jakarta EE 9.1 will be the first Jakarta EE release that allows a server to certify using both Java 8 and Java 11 for both the web profile and the full platform. For the various permutations we have published the following test results using the WildFly Preview variant of the server with the candidate release of the Jakarta EE 9.1 TCKs and submitted corresponding certification requests to Eclipse. Test Results - Web Profile - Java 8 / Certification Request - Web Profile - Java 8 Test Results - Web Profile - Java 11 / Certification Request - Web Profile - Java 11 Test Results - Full Platform - Java 8 / Certification Request - Full Platform - Java 8 Test Results - Full Platform - Java 11 / Certification Request - Full Platform - Java 11 We are hopeful this will mean the WildFly Preview variant of the server can be declared compatible with Jakarta EE 9.1 at the time it is released for the Web Profile and Full Platform against both Java 8 and Java 11. This has been a busy couple of weeks working through the remaining issues to pass the candidate release of the Jakarta EE Platform 9.1 TCKs with particular thanks to Brian Stansberry, Scott Marlow, Richard Opalka, Jean-Francois Denise, Tomasz Adamski, Jim Ma, and Alessio Soldano for making it happen. As is described in the WildFly docs, WildFly Preview is a tech preview variant of the server meant to allow our community to get an early look at new things we’re looking to eventually bring into the standard WildFly variant. Currently, the main (but not only) difference from standard WildFly is support of Jakarta EE 9 and 9.1 instead of EE 8. WildFly Preview is not a compatible Jakarta EE 8 or MicroProfile Platform 4.0 implementation, although we do expect most apps using the EE 8 and MP 4 APIs to run well on it. WildFly Preview is available on the download page, next to the standard WildFly download links for the same version. Look for the 'WildFly Preview EE 9 Distribution' links. Release Notes The full list of issues resolved in WildFly 23.0.2 is available here. WildFly 23.0.2.Final is using the same version of WildFly Core as was used in the 23.0.1.Final release so no WildFly Core specific fixes have been applied. Enjoy! ### [WildFly 23.0.1 is released!](/news/2021/04/14/WildFly-23-0-1-is-released/) WildFly 23.0.1.Final is now available for download. It’s been about a month since the WildFly 23 release, so we’ve done a bug fix update, WildFly 23.0.1. WildFly Preview and Jakarta EE 9.0 The big news in this release is the fact that the WildFly Preview variant of the server passes the TCKs for the Jakarta EE 9.0 Full Platform and the Web Profile. We’ve sent a compatibility certification request for the Full Platform to Eclipse. We’d previously been able to certify compatibility with the Web Profile for WildFly Preview 23.0.0. I’m very excited about this achievement and am so proud of the great WildFly contributors who made it happen, particularly Scott Marlow, Richard Opalka, Jean-Francois Denise, Geoffrey DeSmet, Emmanuel Hugonnet, Farah Juma, Jason Lee, Jim Ma, Matej Novotny, Flavia Rainone and Parul Sharma. As is described in the WildFly docs, WildFly Preview is a tech preview variant of the server meant to allow our community to get an early look at new things we’re looking to eventually bring into the standard WildFly variant. Currently, the main (but not only) difference from standard WildFly is support of Jakarta EE 9 instead of EE 8. WildFly Preview is not a compatible Jakarta EE 8 or MicroProfile Platform 4.0 implementation, although we do expect most apps using the EE 8 and MP 4 APIs to run well on it. WildFly Preview is available on the download page, next to the standard WildFly download links for the same version. Look for the 'WildFly Preview EE 9 Distribution' links. Release Notes The full list of issues resolved in WildFly 23.0.1 is available here. Issues resolved in the WildFly Core update included with WildFly 23.0.1 are available here. Enjoy! ### [Upcoming automatic registration of client side default SSLContext](/news/2021/03/19/Upcoming-automatic-registration-of-client-side-default-SSLContext/) ### [WildFly Bootable JAR 4.0 is released!](/news/2021/03/19/WildFly-Bootable-JAR-4-0-is-released/) The 4.0.0.Final version of the WildFly Bootable JAR Maven plugin has been released. For people who are not familiar with the WildFly Bootable JAR, I strongly recommend that you read this blog post that covers it in detail. WildFly CLI script executed at startup time Starting with the recently announced WildFly 23, the bootable JAR runtime allows you to execute a WildFly CLI script when launching the bootable JAR. Although applying changes to the server configuration at build time is the preferred way (no impact on startup time), runtime execution gives you the flexibility to adjust the server configuration to the execution context. The authentication example has been evolved with a new 'runtime-config' Maven profile to disable CLI script execution at build time in favor of runtime execution. To execute a CLI script during boot: java -jar app-bootable.jar --cli-script=<path to CLI script> Note This support is Tech Preview as the mechanism may change in later releases. JBoss Modules module artifact upgrades Starting with WildFly 23, you can upgrade part of the server when building a bootable JAR. This offers you the ability to use a different version of an identified component of the server (eg: an Undertow artifact, a JDBC driver provided by a third party Galleon feature-pack, …​). Obviously the updated component must be compatible with the server in which it is provisioned…​ This is done at your own risk ;-). WildFly Galleon feature-pack server artifact packaging The way the JBoss Modules module artifacts that compose a WildFly server are packaged inside a WildFly Galleon feature-pack allows you to override their version when building a Bootable JAR. Instead of packaging the artifact binaries inside Galleon feature-packs, the artifacts' Maven coordinates are packaged. The actual artifact files are resolved when a WildFly server is built using Galleon (or when building a bootable JAR). This way of packaging artifacts is not new; WildFly follows this design pattern since the first Galleon releases. (This is what allows you to provision a slim WildFly server or a slim WildFly bootable JAR). If you design custom Galleon feature-packs for WildFly, we encourage you, when applicable (the artifacts must be released in an accessible Maven repository), to design your feature-packs by following this pattern. As an example, the WildFly datasources Galleon feature-pack (that provides drivers and datasources for some major databases) pom file contains in its dependencies the driver artifacts that it can bring to the server. The JBoss Modules modules that contain the driver artifacts (e.g. the postgresql driver module) only reference the GroupId and ArtifactId of the artifact. The artifact versions are stored inside the feature-pack but outside of the JBoss Modules module. This separation between the GroupId, ArtifactId (optionally Classifier) and the Version is what makes it possible to upgrade when building a bootable JAR. To learn more about artifact upgrades The WildFly bootable JAR documentation contains more information about this capability. MyFaces Galleon feature-pack I’m happy to take the opportunity of this blog post to mention a new community project that defines Galleon feature-packs that you can use with the WildFly 23 Galleon feature-pack (and "WildFly Preview" Galleon feature-pack) to build a Bootable JAR (or to provision a server using Galleon) containing a JSF implementation based on MyFaces. Known issues Incompatibility with Keycloak client adapter Galleon feature-pack Note This issue is now solved when using keycloak adapter 13.0.1. Due to some incompatible changes in the WildFly Galleon feature-pack (i.e. the removal of core and servlet Galleon feature-packs in the dependency chain) the Keycloak 12.0.x OIDC client adapter Galleon feature-pack can’t be used with the WildFly 23 Galleon feature-pack. As a workaround, we have setup a project that highlights the workaround you need to follow to include the Keycloak 12.0.x OIDC client adapter inside a WildFly 23 bootable JAR. In summary, we are including in the bootable JAR the content of the Keycloak zipped client adapter (that you can download from Keycloak downloads). In addition the WildFly server security is configured by the adapter-elytron-install.cli WildFly CLI script that is packaged in the zipped adapter. To conclude Finally, we would really appreciate it if you would keep us posted with your feedback and new requirements. (You can log these as new project issues.) This will help us evolve the WildFly Bootable JAR experience in the right direction. Thank-you! JF Denise ### [New Security Features in WildFly 23](/news/2021/03/19/New-Security-Features-in-WildFly-23/) ### [Upcoming SSL features: Multiple certificate revocation lists support and SSLv2Hello support](/news/2021/03/19/Upcoming-SSL-features-Multiple-certificate-revocation-lists-support-and-SSLv2Hello-support/) ### [Normalize principal propagation/injection across elytron and legacy](/news/2021/03/19/Normalize-principal-propagation-injection-across-elytron-and-legacy/) ### [Upcoming SSLContext that supports delegation to alternate instances based on peer information](/news/2021/03/19/Upcoming-SSLContext-that-supports-delegation-to-alternate-instances-based-on-peer-information/) ### [Upcoming hash character sets and hash encodings support in Elytron](/news/2021/03/19/Upcoming-hash-character-sets-and-hash-encodings-support-in-Elytron/) ### [WildFly Encrypted Expression Support](/news/2021/03/19/WildFly-Encrypted-Expression-Support/) ### [WildFly 23 S2I images have been released on quay.io](/news/2021/03/18/WildFly-23-S2I-images-have-been-released-on-quay-io/) WildFly 23 S2I Docker images The WildFly S2I (Source-to-Image) builder and runtime Docker images for WildFly 23 have been released on quay.io/wildfly. For a complete documentation on how to use these images using S2I, OpenShift and Docker, refer to the WildFly S2I README. Adding the imagestreams and template to OpenShift At some point the new images will be made available from the OpenShift catalog and image repository. But you can already use these images by adding them yourselves to your OpenShift cluster. WildFly S2I builder image stream: oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-23.0/imagestreams/wildfly-centos7.json WildFly runtime image stream: oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-23.0/imagestreams/wildfly-runtime-centos7.json Chained build template: oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-23.0/templates/wildfly-s2i-chained-build-template.yml NB: If you import the image streams into your project, be sure to set the ImageStreams Namespace (IMAGE_STREAM_NAMESPACE argument) to your project namespace in the template. openshift being the default namespace. Enjoy! ### [Configuring DNS ping on a WildFly Bootable JAR cluster application](/news/2021/03/12/Configuring-DNS-ping-on-a-WildFly-Bootable-JAR-cluster-application/) Note This post is a continuation of my WildFly Bootable JAR cluster application with JKube openshift-maven-plugin blog post. It assumes you are familiar with the demo application we used for that article. Introduction We recently described in this post details about how to deploy and configure a WildFly Bootable JAR cluster application on OpenShift. By default, a Bootable JAR cluster application uses the KUBE_PING protocol for its clustering discovery mechanism. This protocol is based on the ability to query the Kubernetes API to determine which pods match certain criteria and then create a JGroups cluster based on this information. This protocol may not be a viable or an ideal solution for your scenario; for example, if you cannot grant a specific permission on your Kubernetes cluster to use KUBE_PING, or if your requirement is to make your application agnostic to the Kubernetes API. In this guide we will explain how you can configure the same Bootable JAR cluster application but this time using the DNS_PING protocol. Getting started The following are the key points we need to accomplish to configure our Bootable JAR cluster application to use DNS_PING: Define a ping service. We need to create a headless service resource, which is used by the protocol to get the IP addresses of the pods that would be part of the cluster. When we are defining this resource, we need to pay attention to the service selector and service name. The selector defines the pods that will be backed by this service. The JGroups subsystem needs to know the service name to configure the DNS_PING protocol. Configure the JGroups subsystem to use DNS_PING. We need to change the default JGroups subsystem configuration of our Bootable JAR application. We will execute a CLI script at build time to configure the JGroups protocol stack, removing the default KUBE_PING protocol and adding the DNS_PING. One important detail about the DNS_PING configuration is the value we will use for the dns_query property. This value specifies the DNS name of the Kubernetes ping service the protocol is going to use to discover other cluster members. To sum up, we will need a Kubernetes service with a matching label selector to define which pods will be part of our cluster, and we will tell the JGroups subsystem that we want to use such a service to locate other possible cluster members. Define a ping service The ping service is just an additional Kubernetes service resource. We are using the JKube openshift-maven-plugin to deploy our application. This maven plugin allows us to specify any additional resource we want to deploy. What we need to do is create our additional resources under src/main/jkube/ and JKube will create the resource for us when deploying the application. This is our ping service definition at src/main/jkube/ping_service.yaml: apiVersion: v1 kind: Service metadata: name: wildfly-demo-ping-service annotations: description: The JGroups ping service for clustering discovery. spec: clusterIP: None publishNotReadyAddresses: true selector: app: wildfly-clustering-demo The selector specifies the name of our application. Without any additional modification, the name of our application is the maven group id of our project. We have also configured the service with publishNotReadyAddresses: true. This configuration specifies that when there is a DNS lookup by using this service, the result will contain all pods matching the service’s label selector, even those which are not yet in a ready state. We want the JGroups cluster to form before the pods are receiving end user requests. This configuration makes it possible by returning also the IP of the pods that are not ready yet. We have also added clusterIP: None in the service spec. This means this service will not assign a cluster IP through which clients can connect to all the pods backing it; instead it will return an IP to connect directly to the pod. Configure the JGroups subsystem to use DNS_PING. As a second step, we need to configure the JGroups stack to use the DNS_PING protocol. We have to instruct the wildfly-jar-maven-plugin to execute the following script: /subsystem=jgroups/stack=tcp/protocol=kubernetes.KUBE_PING:remove /subsystem=jgroups/stack=tcp/protocol=dns.DNS_PING:add(add-index=0) /subsystem=jgroups/stack=tcp/protocol=dns.DNS_PING/property=dns_query:add(value=${env.DNS_PING_SERVICE_NAME}) /subsystem=jgroups/stack=tcp/protocol=dns.DNS_PING/property=async_discovery_use_separate_thread_per_request:add(value=true) The script removes the existing kubernetes.KUBE_PING protocol and adds the dns.DNS_PING. The value of the dns_query property will be retrieved from an environment variable named DNS_PING_SERVICE_NAME. The value of this environment variable is specified under the <env> section of the JKube maven plugin configuration in our pom.xml. The maven openshift profile looks as follows: <profiles> <profile> <id>openshift</id> ... <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <configuration> <cloud/> <cli-sessions> <cli-session> <script-files> <script>${project.build.scriptSourceDirectory}/configure_dns_ping.cli</script> </script-files> </cli-session> </cli-sessions> </configuration> </plugin> <plugin> <groupId>org.eclipse.jkube</groupId> <artifactId>openshift-maven-plugin</artifactId> <version>1.0.2</version> <configuration> <resources> <env> ... <DNS_PING_SERVICE_NAME>wildfly-demo-ping-service</DNS_PING_SERVICE_NAME> </env> </resources> </configuration> <executions> <execution> <goals> <goal>resource</goal> <goal>build</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> Build, deploy and verify the demo application Now let us build and deploy our Bootable JAR application. We assume you have a cluster running and you have already logged into it. Clone the demo application and checkout the dns-ping branch. $ git clone https://github.com/yersan/wildfly-clustering-demo.git $ cd wildfly-clustering-demo wildfly-clustering-demo (master) $ git checkout dns-ping Switched to branch 'dns-ping' Build and deploy the application by issuing the following maven goal: wildfly-clustering-demo (dns-ping) $ mvn oc:deploy -Popenshift Once your application has been completely deployed, scale it up, for example, three replicas: wildfly-clustering-demo (dns-ping) $ oc scale dc/wildfly-clustering-demo --replicas=3 deploymentconfig.apps.openshift.io/wildfly-clustering-demo scaled Once your pods are in ready state, you can inspect the logs of any pod and verify there are three members in the cluster: wildfly-clustering-demo (dns-ping) $ oc get pods NAME READY STATUS RESTARTS AGE wildfly-clustering-demo-3-9dmrk 1/1 Running 0 117s wildfly-clustering-demo-3-deploy 0/1 Completed 0 3m6s wildfly-clustering-demo-3-f99qb 1/1 Running 0 3m2s wildfly-clustering-demo-3-snh74 1/1 Running 0 117s wildfly-clustering-demo-s2i-1-build 0/1 Completed 0 5m31s wildfly-clustering-demo (dns-ping) $ oc logs -f pods/wildfly-clustering-demo-3-snh74 ... 11:05:33,906 INFO [org.infinispan.CLUSTER] (ServerService Thread Pool -- 50) ISPN000078: Starting JGroups channel ee 11:05:33,908 INFO [org.infinispan.CLUSTER] (ServerService Thread Pool -- 50) ISPN000094: Received new cluster view for channel ee: [clustering-demo-3-f99qb|2] (3) [clustering-demo-3-f99qb, clustering-demo-3-9dmrk, clustering-demo-3-snh74] 11:05:33,911 INFO [org.infinispan.CLUSTER] (ServerService Thread Pool -- 50) ISPN000079: Channel ee local address is clustering-demo-3-snh74, physical addresses are [10.129.148.40:7600] ... You should have at this point the Bootable JAR application running on a cluster of three pods. Conclusion You can easily configure a Bootable JAR application and adapt it to your needs by executing a CLI script. In this article, we have seen a practical example of how to configure the JGroups protocol stack. Together with the ability to deploy additional resources given by the JKube maven plugin, we have replaced the default clustering discovery mechanism by adding minimal changes to our project. You can find out more examples of how to use and work with the Bootable JAR here. If you have any question related, feel free to contact us joining to the WildFly community forums or Zulip Chat. ### [MicroProfile Reactive Messaging in WildFly 23, and WildFly MicroProfile Reactive Specifications Feature-Pack 2.0.0.Final](/news/2021/03/11/MicroProfile-Reactive-Messaging-in-WildFly-23-and-WildFly-MicroProfile-Reactive-Specifications-Feature-Pack-2-0-0-Final/) I am pleased to announce the 2.0.0.Final release of the MicroProfile Reactive Specifications Feature-Pack for WildFly. Between the 1.0.0.Final release and the WildFly 23.0.0.Final release, we pulled the core of what the feature-pack contained into WildFly. WildFly now contains these Galleon layers which used to live in the 1.0.x stream of the feature-pack: microprofile-reactive-messaging - Provides the MicroProfile Reactive Messaging 1.0 functionality - this is a framework for building event-driven, data streaming and event sourcing applications using CDI. The streams, or channels, can be backed by a variety of messaging technologies. microprofile-reactive-messaging-kafka - The include the connector for Kafka in WildFly, in the layer microprofile-reactive-streams-operators - provides the MicroProfile Reactive Streams Operators 1.0 functionality. The WildFly 23.0.0.Final zip available from our downloads page contains these layers, however they are not enabled by default. To enable the functionality you need to add the extensions and enable the subsystems. The simplest way is to run this CLI script. This script is taken from the WildFly Reactive Messaging with Kafka QuickStart, which you can find here to get you started. Additionally there are sections about these subsystems in our Admin Guide (Reactive Streams Operators/Reactive Messaging). The Feature-Pack As before to use the feature-pack you will need to use Galleon to provision a server, as pointed out in the feature-pack README. That README contains more details of what is contained, but in summary it contains Galleon layers to provide the following functionality: MicroProfile Context Propagation 1.0 functionality. Additional Reactive Messaging connectors for: AMQP MQTT We decided to remove RxJava2 support of context propagation for the feature-pack since that caused some problems under the hood. RxJava2 is not a supported API for user applications in WildFly (although we use it for somem internal functionality). If you have the need to process streams, please use the MicroProfile Reactive Streams Operators API instead. Note that the 2.0.x series of the feature-pack will only work with WildFly 23. For earlier WildFly versions, use the 1.0.x releases. The present latest release on that stream, 1.0.2, works with WildFly 21 and WildFly 22. Spec compliance It is worth pointing out that we’re strictly staying with what version 1.0 of the MicroProfile Reactive Messaging specification provides. However, the SmallRye Reactive Messaging version we use is used to develop the next version of the specification, which is not ready yet. If you wish to get a preview of that, the steps are to instead of compiling your application against org.eclipse.microprofile.reactive.messaging:microprofile-reactive-messaging-api:1.0, compile against io.smallrye.reactive:smallrye-reactive-messaging-api:3.0.0, and make sure you start the server with -Djboss.as.reactive.messaging.experimental=true which will bypasss some checks and allow you to use more recent, although currently unreleased constructs such as @Channel and Emitter. Note: - these APIs may still change until there is a final release of the next specification version. What is coming up? Once the MicroProfile Reactive Messaging 2.0 specification is released and the other reactive specifications, MicroProfile Reactive Streams Operators and MicroProfile Context Propagation, are finalised, we will start work on integrating them into a future (as yet to be determined) WildFly version. With the current information, the feature-pack then mainly becomes a place for the connectors we don’t want in WildFly yet. Feedback We’re keen to hear your feedback! Please raise any issues found with the feature-pack at https://github.com/wildfly-extras/wildfly-mp-reactive-feature-pack/issues. And for the parts in WildFly, raise issues at https://issues.redhat.com, in the WFLY project (using 'MP Reactive Messaging' as the component). ### [WildFly 23 is released!](/news/2021/03/11/WildFly-23-is-released/) I’m pleased to announce that the WildFly 23 Final zip is now available for download. It’s been a busy time since the January WildFly 22 release, with a bit shorter development cycle than normal. But a lot has been accomplished. Let’s have a look at what’s new. New Features MicroProfile 4.0 In this release we have moved our MicroProfile platform implementations from the 3.3 platform specification versions to the 4.0 versions. WildFly 23 supports the following MicroProfile platform specifications: Specification Version in WildFly 23 MicroProfile Config 2.0 MicroProfile Fault Tolerance 3.0 MicroProfile Health 3.0 MicroProfile JWT Authentication 1.2 MicroProfile Metrics 3.0 MicroProfile OpenAPI 2.0 MicroProfile OpenTracing 2.0 MicroProfile Rest Client 2.0 We also provide all of the MicroProfile specs that are also part of Jakarta EE 8. Please note that an overarching goal of MicroProfile is to prioritize innovation over legacy compatibility. This may result in incompatible changes between specification releases, which WildFly will necessarily reflect. With MicroProfile 4.0 the following specifications include API incompatible changes: Config Fault Tolerance Health Metrics Open API MicroProfile Reactive Messaging WildFly 23 now provides Tech Preview support for MicroProfile Reactive Messaging. This includes providing a connector for interaction with Kafka streams. This capability adds support for two more MicroProfile specifications to WildFly, implemented via two new extensions and subsystems: Specification Version in WildFly 23 MicroProfile Reactive Messaging 1.0 MicroProfile Reactive Streams Operators 1.0.1 Please note that these extensions and subsystems are not included by default in the standard standalone.xml files that WildFly provides. Users who want them can add them to their configuration by using Galleon to provision a server or build a bootable jar and telling Galleon to include the new Galleon layers we’ve added for these. Or, use our zip and use the CLI to add the new extensions and subsystems. Further details can be found in the WildFly Admin Guide. Expression Resolution from a Credential Store WildFly 23 adds support for expressions in the management model to be encrypted using AES encryption and dynamically decrypted at runtime using a SecretKey from a credential store. This enhancement makes use of a new resource expression-encryption in the elytron subsystem to configure the expression resolution. This new resource also contains a management operation create-expression which allows users to create encrypted expressions using the usual management clients. In addition to the new resource for expression resolution a new secret-key-credential-store has been added for the purpose of providing an initial secret key to the application server process. In the past users needed to rely on masking a password but this was achieved using a well known public password and password based encryption. Starting from a secret key allows administrators to manage their own initial secret. Both this new credential store resource and the existing credential-store resource have been updated to support the generation of secret keys as well as the ability to export and import previously generated secret keys. Finally the wildfly-elytron-tool has also been updated to support both types of credential store and the credential-store command updated to support management of secret keys and the generation of encrypted tokens for use in expressions. Users of the deprecated Picketbox-vault-backed expression resolution mechanism are strongly encouraged to move to this new feature, as our intent is to remove support for Picketbox and the Picketbox-vault in an upcoming release. Provisioning and Managing WildFly For users who wish to deploy multiple applications on the same server instance where one application during startup needs to make an external (i.e. over the network) invocation on another, we have provided a mechanism to turn off the default 'graceful startup' behavior that prevents such requests being accepted. Not handling such requests can prevent startup of the deployment making them and prevent the server booting. A number of users have asked for this use case tp be supported, so we have done so, but this is not a recommended deployment architecture. A server that is not booting gracefully may receive incoming requests that it is not yet ready to handle, resulting in errors. There is now support for common script configurations. A common file can be used to set up the environment for all the shell scripts that WildFly provides. For example, you can set the JAVA_HOME in a common.conf script configuration file to ensure the same version of Java is used for all scripts. When launching a WildFly bootable jar, users can instruct the bootable jar to execute an external CLI script as part of boot. This provides a mechanism for performing final configuration that cannot be accomplished via the preferred approach of configuring at build time or via typical runtime customization mechanisms like setting environment variables or system properties. This support is Tech Preview as the mechanism may change in later releases. Messaging The management API can now be used to get a dump of the embedded Artemis broker’s journal for investigative purposes. The behavior of the embedded Artemis broker’s critical-analyzer feature can now be configured. The embedded Artemis broker can be configured to retain a corrupted journal file for subsequent investigation instead of immediately deleting it. A call-timeout attribute has been added to the Jakarta Messaging core bridge configuration. The attribute specifies the time out for blocking calls performed by a core bridge. Other areas The Jakarta Concurrency managed executors provided by the ee subsystem can be configured to detect and automatically terminate tasks that have been executing for an unexpectedly long time. Such tasks can also be manually terminated. The transaction subsystem now supports configuring a maximum timeout for transactions. The undertow subsystem can now be configured to obfuscate the server instance-id data included as part of the request and response JSESSION_ID cookie. Deployments can now depend on and use the APIs provided by the following Infinispan-related modules without getting a private API usage warning: org.infinispan (embedded cache) org.infinispan.client.hotrod (client for remote infinispan server) org.infinispan.commons Principal propagation of EJBs was different for legacy security and Elytron security in some cases. To provide a possibility to configure which behaviour should apply, we added a new attribute legacy-compliant-principal-propagation to application-security-domain component in the ejb3 subsystem. This attribute is optional and the principal propagation is legacy compliant by default. WildFly Preview As I announced in November when we released WildFly 22 Alpha1, along with our traditional Jakarta EE 8 distribution we want to give our users a preview of what will be coming in WildFly as we move on to EE 9 and later. We call this distribution "WildFly Preview". The WildFly 23.0.0.Final release includes an update to WildFly Preview. Even though this is coming from a .Final tag of the WildFly codebase, WildFly Preview should always be regarded as a tech-preview/beta distribution. EE 9 is primarily about implementing the necessary change in the Jakarta EE APIs from the javax.* package namespace to the jakarta.* namespace. This is a big change that is going to take a while to percolate through the EE ecosystem, e.g. for the many projects that compile against the EE APIs to provide versions that use jakarta.*. While this happens we want to continue to deliver new features and fixes to our community, so the primary WildFly distribution will continue to provide the EE 8 APIs. Feature-Pack Changes WildFly users can use Galleon feature-packs to provision a server or build a bootable jar. The WildFly project produces five different feature-packs: wildfly-core, wildfly-servlet, wildfly-ee, wildfly and wildfly-preview. The composition of these feature-packs has changed somewhat in WildFly 23, in that the wildfly-ee feature-pack no longer depends on wildfly-servlet or (transitively) wildfly-core. Instead it directly incorporates the same content that was previously made available via a dependency relationship. For most users, this subtle difference should have no impact. However, there are some cases where it might: If you are producing your own feature-pack that depends on wildfly or wildfly-ee you may need to adjust your pom.xml and wildfly-feature-pack-build.xml to remove any dependency on wildfly-servlet and wildfly-core. If your build uses another feature-pack that depends on the wildfly or wildfly-ee feature-packs, you should wait to upgrade to WildFly 23 until a release of that feature-pack that depends on the WildFly 23 packs is available. A commonly used example of this is the org.wildfly:wildfly-datasources-galleon-pack feature-pack. Users of that feature-pack should move to the 1.2.3.Final release that came out today. The WildFly project still produces the wildfly-core and wildfly-servlet feature-packs for those who wish to use them, although they may be discontinued at some point. Standards Support WildFly 23.0.0 is a Jakarta EE 8 compatible implementation, with both the Full Platform and the Web Profile. Evidence supporting our certification is available for the Full Platform and for the Web Profile. Beginning with WildFly 23 we will be exclusively focusing on the Jakarta EE test suite for EE certification / compliance. WildFly 23 is also a compliant implementation of the MicroProfile 4.0 platform specification. The WildFly Preview distribution released today is not yet a compatible implementation of Jakarta EE 9 or MicroProfile 4.0. We’re continuing to make good progress toward being able to certify compatibility, but we’re not there yet. The main area where users may hit meaningful issues related to EE compliance is in webservices if deployment descriptors using the EE 9 xml schemas are used. This can be worked around by using EE 8 schemas, which are functionally equivalent. JDK Support Our recommendation is that you run WildFly on the most recent long-term support JDK release, i.e. on JDK 11 for WildFly 23. While we do do some testing of WildFly on JDK 12 and 13, we do considerably more testing of WildFly itself on the LTS JDKs, and we make no attempt to ensure the projects producing the various libraries we integrate are testing their libraries on anything other than JDK 8 or 11. WildFly 23 also is heavily tested and runs well on Java 8. We plan to continue to support Java 8 at least through WildFly 24, and probably beyond. While we recommend using an LTS JDK release, I do believe WildFly runs well on JDK 13. By run well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. We do see a couple of test failures with JDK 13 when using the deprecated Picketlink subsystem and WS Trust. Work to allow WildFly to run on JDK 15 and later is ongoing. We’re continuing our work to digest fully some of the package removals that came in JDK 14, particularly in the security area. The biggest barrier we face is the deprecated legacy security implementation based on Picketbox cannot support JDK 14. We intend to remove support for that security implementation quite soon and to only provide Elytron-based security. Please note that WildFly runs on Java 11 and later in classpath mode. Documentation The WildFly 23 documentation is available at the docs.wildfly.org site. The WildFly 23 management API documentation is in the wildscribe section of the WildFly 23 docs. Jira Release Notes The full list of issues resolved is available in the WFLY JIRA project. Issues resolved in the WildFly Core 15 release included with WildFly 23 are available in the WFCORE JIRA project. Enjoy! Thank you for your continued support of WildFly. We’d love to hear your feedback at the WildFly forum. ### [WildFly 23 Beta1 -- More Progress with MicroProfile](/news/2021/02/24/WildFly-23-Beta1-More-Progress-with-MicroProfile/) I’m pleased to announce that the new WildFly and WildFly Preview 23.0.0.Beta1 releases are available for download at https://wildfly.org/downloads. The WildFly 23 development cycle has been a bit shorter than our typical three months, as we’ve reduced this one some to see if we can get on a rough cadence of Final releases in March/June/September/December. That works well for avoiding releases during the peak summer and year end holiday periods. And the cycle was even shorter in practice due to the normal year end slowdown. But we got a lot done! The biggest thing we’ve done is update all our of Eclipse MicroProfile implementations to the MicroProfile Platform 4.0 versions. We’ve also added tech preview support for MicroProfile Reactive Messaging 1.0. There are lots of other features and fixes in WildFly 23 Beta1. I’ll wait for the Final release in a couple weeks to get into more details, but the release notes for the release are here, with issues fixed in the underlying WildFly Core beta listed here. Please try it out and give us your feedback, while we get to work WildFly 23 Final! Best regards, Brian ### [WildFly 22.0.1 is released!](/news/2021/02/11/WildFly-22-0-1-is-released/) WildFly 22.0.1.Final is now available for download. It’s been about a month since the WildFly 22 release, so we’ve done a small bug fix update, WildFly 22.0.1. The full list of issues resolved in WildFly 22.0.1 is available here. Issues resolved in the WildFly Core update included with WildFly 22.0.1 are available here. Enjoy! ### [WildFly Bootable JAR cluster application with JKube openshift-maven-plugin](/news/2021/02/01/WildFly-Bootable-JAR-cluster-application-with-JKube-openshift-maven-plugin/) Introduction This post is a step-by-step guide describing how you can build and deploy on OpenShift an example of a WildFly Bootable JAR application that caches the HTTP session state. We will explore how Bootable JAR uses the KUBE_PING protocol for clustering discovery mechanisms and how you can use JKube openshift-maven-plugin to deploy the application on OpenShift. Getting started The demo application is a minimalistic shopping cart that stores items in the HTTP session. The key points are: We want our session data to be replicated across all cluster members. The Jakarta Servlet specification supports distributable web applications. If you want to share your session data, you need to specify your session is distributable on the web.xml file: <?xml version="1.0" encoding="UTF-8"?> <web-app 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" version="4.0"> <distributable /> </web-app> Our bootable JAR application is built by using wildfly-jar-maven-plugin. This is the default configuration in our pom.xml: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <configuration> <feature-pack-location>wildfly@maven(org.jboss.universe:community-universe)#22.0.0.Final</feature-pack-location> <layers> <layer>jaxrs-server</layer> <layer>web-clustering</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> The feature-pack-location is an expression used to resolve feature-pack artifacts from the remote repository. The feature-packs determine the WildFly version in use. Using a feature-pack location has some advantages when you are interested in an automatic version resolution. Note If you are more comfortable by using maven GAVs, the above feature-pack-location can be replaced by the equivalent feature-pack: <feature-packs> <feature-pack> <groupId>org.wildfly</groupId> <artifactId>wildfly-galleon-pack</artifactId> <version>22.0.0.Final</version> </feature-pack> </feature-packs> The layers section specify the Galleon layers we want for our application: jaxrs-server: It adds support for JAX-RS, CDI and JPA. The application stores the items in the session by using a JAX-RS resource. web-clustering: Support for distributable web applications. This layer will supply the Infinispan web container cache and the JGroups subsystem. The default maven profile the application uses is to build and deploy the application locally. When we are going to deploy on Openshift, we will activate the openshift maven profile which adds on top of the default maven configuration the required configuration for running the application in OpenShift. In the aim to get a better understanding, firstly, we will build and verify the application locally. Then we will deploy and verify on OpenShift. Building and testing the application locally Clone the application and build it: $ git clone https://github.com/yersan/wildfly-clustering-demo.git $ cd wildfly-clustering-demo wildfly-clustering-demo$ mvn package Now you can launch two server instances to verify the cluster works as expected. If you are running a Bootable JAR cluster application locally, you have to specify the node name for each server instance and deal with the port numbers to avoid port conflicts between the launched instances. Launch the first application. In a terminal window execute the following: wildfly-clustering-demo$ java -jar ./target/wildfly-clustering-demo-bootable.jar -Djboss.node.name=node1 Launch the second application in a different terminal taking care of the port conflicts: wildfly-clustering-demo$ java -jar ./target/wildfly-clustering-demo-bootable.jar -Djboss.node.name=node2 -Djboss.socket.binding.port-offset=10 You should see in the logs that a cluster has been formed, and the name of the nodes that have been joined to it: 16:15:06,908 INFO [org.infinispan.CLUSTER] (ServerService Thread Pool -- 44) ISPN000094: Received new cluster view for channel ejb: [node1|1] (2) [node1, node2] Note When you have built the Bootable JAR application locally, without any further configuration, by default the JGroups subsystem is configured to use the UDP protocol and send messages to discover other cluster members to the 230.0.0.4 multicast address. If you do not see the above log trace, verify that your Operating System is capable of sending and receiving multicast datagrams and can route them to the 230.0.0.4 IP through your ethernet interface. We are now ready to add some items to our HTTP session. We do not have a load balancer locally, so we will add items by using the first instance. Later, we will stop that instance and verify the session is replicated correctly. Add some items to the application cart: $ curl --cookie-jar /tmp/session.txt -XPOST http://localhost:8080/api/jeans/2 $ curl --cookie /tmp/session.txt -XPOST http://localhost:8080/api/shorts/4 Check the cart items accessing to the first instance: $ curl --cookie /tmp/session.txt -XGET http://localhost:8080/api/cart {"host":"localhost","sessionId":"vcVIqIU80USV7W11Qoh3QyJU1PPEFFxOPwI-HcEZ","cart":[{"item":"shorts","quantity":4},{"item":"jeans","quantity":2}]} Stop the first instance and check the cart again by accessing to the second node; notice the port is now 8090: $ curl --cookie /tmp/session.txt -XGET http://localhost:8090/api/cart {"host":"localhost","sessionId":"vcVIqIU80USV7W11Qoh3QyJU1PPEFFxOPwI-HcEZ","cart":[{"item":"shorts","quantity":4},{"item":"jeans","quantity":2}]} We see the same session id and items on the second node. The session data is correctly replicated. Our cluster and application is working locally. Moving to OpenShift The demo application uses a specific maven profile to configure the particularities to build and deploy on OpenShift. Adapting the wildfly-jar-maven-plugin for the cloud executions The wildfly-jar-maven-plugin has to know that we intend to build the WildFly Bootable JAR application for cloud execution. In the openshift maven profile, we extend the default configuration adding the cloud configuration item as follows: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <configuration> <cloud/> </configuration> </plugin> This setting adds specific server configuration to run the Bootable JAR in the cloud context, for example, the JGroups subsystem is now configured to use the KUBE_PING protocol for both tcp (default stack) and udp, the microprofile-health Galleon layer is automatically provisioned, the jboss.node.name is set automatically to the pod hostname. You can check Configuring the server for cloud execution section in the Bootable JAR documentation to get more details about this setting. With the KUBE_PING protocol enabled, cluster member discovery is done by asking Kubernetes for a list of IP addresses of running pods. In order to make it work we need the following: Our pods have to have the KUBERNETES_NAMESPACE environment variable set. This environment variable is used to define the namespace JGroups will use to discover other cluster members from this pod. The JKube OpenShift maven plugin sets this environment for us. We need to grant authorization to the service account the pod is running under so that it can access the Kubernetes REST API to get the list of addresses of all cluster nodes. We need to manually complete this step before deploying the Bootable JAR application. Using openshift-maven-plugin to deploy on OpenShift To deploy the application on OpenShift we will use openshift-maven-plugin. This maven plugin is integrated with the Bootable JAR. It allows us to use some defaults for starting up applications keeping a simple and tidy configuration. It also adds automatically the readiness and liveness probes to the Bootable JAR application. These probes are just simple HTTP gets for following endpoints: Readiness: http://localhost:9990/health/ready Liveness: http://localhost:9990/health/live If you add readiness / liveness checks on your application code, those checks will be taken into account when you are deploying with the JKube plugin, since those checks will be available on the built-in microprofile-health capabilities added by the Bootable JAR maven plugin as an additional Galleon layer. Let us take a look at the JKube plugin configuration: <profiles> <profile> <id>openshift</id> <properties> <jkube.generator.from>registry.redhat.io/ubi8/openjdk-11:latest</jkube.generator.from> </properties> <build> <plugins> <plugin> <groupId>org.eclipse.jkube</groupId> <artifactId>openshift-maven-plugin</artifactId> <version>1.0.2</version> <configuration> <resources> <env> <GC_MAX_METASPACE_SIZE>256</GC_MAX_METASPACE_SIZE> <GC_METASPACE_SIZE>96</GC_METASPACE_SIZE> </env> </resources> </configuration> <executions> <execution> <goals> <goal>resource</goal> <goal>build</goal> <goal>apply</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> The jkube.generator.from specifies the base image our application is going to use. The Zero-Config capability of the JKube maven plugin will add one base layer if you do not specify this configuration. However, for our demo, we have chosen registry.redhat.io/ubi8/openjdk-11 as base image. When we are using this ubi8/openjdk-11 base image, we have to configure the GC metaspace sizes. We can add environment variables by specifying them in the resources/env section. We have also configured the oc:resource, oc:build and oc:apply maven goals on the JKube plugin. With the above configuration, we should be able to execute mvn install -Popenshift to kick off all the process to build and deploy on OpenShift. In the following sections, we will go step by step, so we can explain what happens behind the scenes in each phase. Building and verifying the Bootable Jar application on OpenShift We will use Red Hat CodeReady Containers (CRC) as a local OpenShift cluster. It brings a minimal OpenShift 4 cluster with one node to our local computer. Start CRC and create the new project where we are going to work on: $ crc start -p crc_license.txt $ oc login -u kubeadmin -p dpDFV-xamBW-kKAk3-Fi6Lg https://api.crc.testing:6443 $ oc new-project wildfly-cluster-demo Now using project "wildfly-cluster-demo" on server "https://api.crc.testing:6443". Our application uses the KUBE_PING protocol so we need to grant authorization to the service account the pod is running under: $ oc policy add-role-to-user view system:serviceaccount:$(oc project -q):default -n $(oc project -q) clusterrole.rbac.authorization.k8s.io/view added: "system:serviceaccount:wildfly-cluster-demo:default" Build our application by using the openshift maven profile: wildfly-clustering-demo$ mvn clean package -Popenshift Let us take a look at some points at this stage: The JKube oc:resource is bound to the resource maven phase: [INFO] --- openshift-maven-plugin:1.0.2:resource (default) @ wildfly-clustering-demo --- [INFO] oc: Using docker image name of namespace: wildfly-cluster-demo [INFO] oc: Running generator wildfly-jar [INFO] oc: wildfly-jar: Using Docker image registry.redhat.io/ubi8/openjdk-11:latest as base / builder [INFO] oc: Using resource templates from /home/yborgess/dev/projects/wildfly-clustering-demo/src/main/jkube [INFO] oc: jkube-controller: Adding a default DeploymentConfig [INFO] oc: jkube-service: Adding a default service 'wildfly-clustering-demo' with ports [8080] [WARNING] oc: jkube-image: Environment variable GC_MAX_METASPACE_SIZE will not be overridden: trying to set the value 256, but its actual value is 256 [WARNING] oc: jkube-image: Environment variable GC_METASPACE_SIZE will not be overridden: trying to set the value 96, but its actual value is 96 [INFO] oc: jkube-healthcheck-wildfly-jar: Adding readiness probe on port 9990, path='/health/ready', scheme='HTTP', with initial delay 10 seconds [INFO] oc: jkube-healthcheck-wildfly-jar: Adding liveness probe on port 9990, path='/health/live', scheme='HTTP', with initial delay 60 seconds [INFO] oc: jkube-revision-history: Adding revision history limit to 2 At the resource phase, JKube prepares all the OpenShift resources needed to deploy the application. You can inspect what resources are going to be deployed by looking at target/classes/META-INF/jkube/openshift.yml file. You will find the following: A service exposing the 8080 port. A route exposing this service. A deploymentConfig which defines and starts our pods. On this file you can see the probes, and our required environment variables; GC_MAX_METASPACE_SIZE and GC_METASPACE_SIZE added manually by us on the plugin configuration, KUBERNETES_NAMESPACE added automatically. Create the OpenShift specific builds: $ mvn oc:build -Popenshift At this step, JKube has created by us: Our contanerized application. You can check the generated dockerfile at target/docker/wildfly-clustering-demo/1.0/build/Dockerfile. An OpenShift BuildConfig object that uses as the source base image our containerized application: $ oc describe buildconfig/wildfly-clustering-demo-s2i Name: wildfly-clustering-demo-s2i Namespace: wildfly-cluster-demo Created: 47 minutes ago Labels: app=wildfly-clustering-demo group=org.wildfly.s2i provider=jkube version=1.0 Annotations: <none> Latest Version: 1 Strategy: Source From Image: DockerImage registry.redhat.io/ubi8/openjdk-11:latest Pull Secret Name: pullsecret-jkube Output to: ImageStreamTag wildfly-clustering-demo:1.0 Binary: provided on build This BuildConfig is built automatically resulting in an ImageStreamTag available. You can verify the build by issuing: $ oc logs pods/wildfly-clustering-demo-s2i-1-build We have now an ImageStreamTag named wildfly-clustering-demo:1.0 built. Now we can deploy the application by using oc:apply maven goal: $ mvn oc:apply -Popenshift [INFO] Scanning for projects... [INFO] [INFO] --------------< org.wildfly.s2i:wildfly-clustering-demo >--------------- [INFO] Building maven-web 1.0 [INFO] --------------------------------[ war ]--------------------------------- [INFO] [INFO] --- openshift-maven-plugin:1.0.2:apply (default-cli) @ wildfly-clustering-demo --- [INFO] oc: Using OpenShift at https://api.crc.testing:6443/ in namespace wildfly-cluster-demo with manifest /home/yborgess/dev/projects/wildfly-clustering-demo/target/classes/META-INF/jkube/openshift.yml [INFO] oc: OpenShift platform detected [INFO] oc: Using project: wildfly-cluster-demo [INFO] oc: Creating a Service from openshift.yml namespace wildfly-cluster-demo name wildfly-clustering-demo [INFO] oc: Created Service: target/jkube/applyJson/wildfly-cluster-demo/service-wildfly-clustering-demo.json [INFO] oc: Creating a DeploymentConfig from openshift.yml namespace wildfly-cluster-demo name wildfly-clustering-demo [INFO] oc: Created DeploymentConfig: target/jkube/applyJson/wildfly-cluster-demo/deploymentconfig-wildfly-clustering-demo.json [INFO] oc: Creating Route wildfly-cluster-demo:wildfly-clustering-demo host: null [INFO] oc: HINT: Use the command `oc get pods -w` to watch your pods start up [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ We should have in our local OpenShift cluster the following DeploymentConfig object created by JKube: $ oc describe dc/wildfly-clustering-demo Name: wildfly-clustering-demo Namespace: wildfly-cluster-demo Created: 57 seconds ago Labels: app=wildfly-clustering-demo group=org.wildfly.s2i provider=jkube version=1.0 Annotations: app.openshift.io/vcs-ref=master app.openshift.io/vcs-uri=https://github.com/yersan/wildfly-clustering-demo.git jkube.io/git-branch=master jkube.io/git-commit=b5cfa009b7724065260c3a5c9d45733978626797 jkube.io/git-url=https://github.com/yersan/wildfly-clustering-demo.git Latest Version: 1 Selector: app=wildfly-clustering-demo,group=org.wildfly.s2i,provider=jkube Replicas: 1 Triggers: Config, Image(wildfly-clustering-demo@1.0, auto=true) Strategy: Rolling Template: Pod Template: Labels: app=wildfly-clustering-demo group=org.wildfly.s2i provider=jkube version=1.0 Annotations: app.openshift.io/vcs-ref: master app.openshift.io/vcs-uri: https://github.com/yersan/wildfly-clustering-demo.git jkube.io/git-branch: master jkube.io/git-commit: b5cfa009b7724065260c3a5c9d45733978626797 jkube.io/git-url: https://github.com/yersan/wildfly-clustering-demo.git Containers: wildfly-jar: Image: image-registry.openshift-image-registry.svc:5000/wildfly-cluster-demo/wildfly-clustering-demo@sha256:e8274e7de4c7b9d280ff20cb595a627754a80052b4c1e5e54738c490ac7e86e7 Ports: 8080/TCP, 9779/TCP, 8778/TCP Host Ports: 0/TCP, 0/TCP, 0/TCP Liveness: http-get http://:9990/health/live delay=60s timeout=1s period=10s #success=1 #failure=3 Readiness: http-get http://:9990/health/ready delay=10s timeout=1s period=10s #success=1 #failure=3 Environment: GC_MAX_METASPACE_SIZE: 256 GC_METASPACE_SIZE: 96 KUBERNETES_NAMESPACE: (v1:metadata.namespace) ... Notice the environment variables used in the pod template section and the probes. The deployment is also started automatically. You can monitor the progress by checking the pods running on the current OpenShift project: $ oc get pods -w Once your deployment finishes, scale up the application pod: $ oc scale dc wildfly-clustering-demo --replicas=2 deploymentconfig.apps.openshift.io/wildfly-clustering-demo scaled If you check the logs of your pods, you should notice a cluster has been created, for example: 17:15:23,842 INFO [org.infinispan.CLUSTER] (ServerService Thread Pool -- 49) ISPN000094: Received new cluster view for channel ee: [clustering-demo-1-vrt7h|1] (2) [clustering-demo-1-vrt7h, clustering-demo-1-cmmzn] Now we can verify our cluster is working as expected and verify the session data is replicated across all the cluster members. Create session data and retrieve it to see on which pod it was created: $ curl --cookie-jar /tmp/session.txt -XPOST $(oc get route wildfly-clustering-demo -o=jsonpath='{.spec.host}')/api/jeans/2 $ curl --cookie /tmp/session.txt -XPOST $(oc get route wildfly-clustering-demo -o=jsonpath='{.spec.host}')/api/shorts/4 $ curl --cookie /tmp/session.txt -XGET $(oc get route wildfly-clustering-demo -o=jsonpath='{.spec.host}')/api/cart {"host":"wildfly-clustering-demo-1-zs8fg","sessionId":"rLHbOGXWUBUmAoySM-1HpxNwFULzbyuhHTdcHUtv","cart":[{"item":"shorts","quantity":4},{"item":"jeans","quantity":2}]} Delete the pod which gave you the latest response and get the cart again through the same route. OpenShift will balance the load to the other pod available. We should get the same session data, verifying the replication works as expected: $ oc delete pod wildfly-clustering-demo-1-zs8fg pod "wildfly-clustering-demo-1-zs8fg" deleted $ curl --cookie /tmp/session.txt -XGET $(oc get route wildfly-clustering-demo -o=jsonpath='{.spec.host}')/api/cart {"host":"wildfly-clustering-demo-1-cdv27","sessionId":"rLHbOGXWUBUmAoySM-1HpxNwFULzbyuhHTdcHUtv","cart":[{"item":"shorts","quantity":4},{"item":"jeans","quantity":2}]} Conclusion Combining the Bootable JAR with the JKube maven plugin is one option to simplify the workflow developing applications on OpenShift. Firstly, we have seen how you can work with your application locally and then, with minimal effort, how to adapt it to be deployed on OpenShift. In this specific example, we have explored the default discovery mechanism available on the Bootable JAR. This mechanism requires granting permissions on your cluster to add to JGroups the ability to discover other cluster members. Note If you are interested in learning how to configure the DNS_PING protocol instead of KUBE_PING, this follow-up blog post describes how to do it. You can find out more examples of how to use and work with the Bootable JAR here. If you have any question related, feel free to contact us joining to the WildFly community forums or Zulip Chat. ### [Developing on OpenShift with WildFly bootable jar](/news/2021/01/24/Developing-on-OpenShift-with-WildFly-bootable-jar/) With the bootable jar feature of WildFly it is now easier to build applications for the cloud. You can trim the server to reduce its footprint which makes this a perfect candidate to build microservices on the cloud. Let’s discover how to combine this feature to build and deploy applications on OpenShift. Using odo odo is a fast, iterative, and straightforward CLI tool for developers who write, build, and deploy applications on Kubernetes and OpenShift. odo abstracts away complex Kubernetes and OpenShift concepts for the developer. Installing odo Download the binary from odo download site according to your target environment and follow the instructions from odo website. Please note that you need at least the version 2.0.3 to use the devfile we will be using in the rest of this article. Preparing our cloud environement During this article we will use the 'free' OpenShift developer-sandbox that you can have with your account on Red Hat Developer website. Once you have your cloud environment we need to connect to it from odo. odo login https://api.sandbox.x8i5.p1.openshiftapps.com:6443 --token=sha256~################################# Connecting to the OpenShift cluster Logged into "https://api.sandbox.x8i5.p1.openshiftapps.com:6443" as "ehugonne1" using the token provided. You have access to the following projects and can switch between them with 'odo project set <project-name>': * ehugonne1-code ehugonne1-dev ehugonne1-stage Using project "ehugonne1-code". Creating the new project First we need to create a namespace in OpenShift: odo project create microprofile-config Now we can create our project using the microprofile-config quickstart sample project. mkdir odo-demo cd odo-demo odo create java-wildfly-bootable-jar --starter=microprofile-config Validation ✓ Checking devfile existence [19047ns] ✓ Creating a devfile component from registry: DefaultDevfileRegistry [31878ns] ✓ Validating devfile component [153099ns] Starter Project ✓ Downloading starter project microprofile-config from https://github.com/wildfly/quickstart.git [1m] Please use `odo push` command to create the component with source deployed This will create the microprofile-config quickstart Apache Maven project with a devfile.yaml that describe how the project will be built and run on OpenShift. This devfile is the entry point of our whole project, you may think of it as the pom.xml for the cloud. They are fully described on Devfile User Guide 2.0.0. Let’s take a quick look at the devfile and their main entry points. I’ll pass the starterProjects which are the quickstarts you can select when creating your initial project. First we can see that it defines two components: a jaeger component that will provide an OpenTracing compatible server so that Eclipse MicroProfile OpenTracing applications can send traces to. a wildfly component which is a simple Java image with Apache Maven where the application will be built and run. It exposes only the 8080 port for HTTP. a m2-repository component which is a persistent volume that we will be using to avoid losing all the downloaded artefacts between each restart of the wildfly container. Then we have the list of commands available to build, debug and run our application: build: this will compile and build a bootable jar from the sources. run: this will start and run the bootable jar. debug: this will start and run the bootable jar in debug mode. dev-build: this will compile and build a bootable jar from the sources so that it can be used in developper mode which means the server won’t get rebuilt nor restarted when the application is modified. dev-run: this will start and run the bootable jar in developper mode which means the server won’t get rebuilt nor restarted when the application is modified. dev-debug: this will start and run the bootable jar in debug developper mode which means the server won’t get rebuilt nor restarted when the application is modified. watch-build: this will do nothing except print a nice message. watch-run: this will start the bootable jar in watch mode. watch-debug: this will start the bootable jar in watch mode with debug on. Building and running the application So let’s just build and start our application odo push Validation ✓ Validating the devfile [290197ns] Creating Kubernetes resources for component java-wildfly-bootable-jar ✓ Waiting for component to start [29s] Applying URL changes ✓ URL tracing-ui: http://tracing-ui-java-wildfly-bootable-jar-ehugonne1-code.apps.sandbox.x8i5.p1.openshiftapps.com/ created ✓ URL http: http://http-java-wildfly-bootable-jar-ehugonne1-code.apps.sandbox.x8i5.p1.openshiftapps.com/ created Syncing to component java-wildfly-bootable-jar ✓ Checking files for pushing [1ms] ✓ Syncing files to the component [4s] Executing devfile commands for component java-wildfly-bootable-jar ✓ Executing watch-build command "echo 'It's watcher mode Baby !!!''" [2s] ✓ Executing watch-run command "mvn ${MVN_ARGS_APPEND} -Dwildfly.bootable.arguments=\"-b=0.0.0.0\" org.wildfly.plugins:wildfly-jar-maven-plugin:dev-watch -e -DskipTests", if not running [2s] Pushing devfile component java-wildfly-bootable-jar ✓ Changes successfully pushed to component You can get the url to access your application with oc get route java-wildfly-bootable-jar Now we can access the application on this URL. Building and debugging the application in developper mode To develop our application we provide a set of commands in to get feedbacks more quickly than with the default commands. Important The developper mode will only provision the server on the first build. That means that if you want to change the layers or the configuration of the server you will need to delete your application and push it again. So let’s start our server in developper mode with debug enabled. odo push --debug --build-command dev-build --debug-command dev-debug Validation ✓ Validating the devfile [165733ns] Creating Kubernetes resources for component java-jboss-eap-xp-bootable-jar ✓ Waiting for component to start [15s] Applying URL changes ✓ URL tracing-ui: http://tracing-ui-java-jboss-eap-xp-bootable-jar-microprofile-config.apps-crc.testing/ created ✓ URL http: http://http-java-jboss-eap-xp-bootable-jar-microprofile-config.apps-crc.testing/ created Syncing to component java-jboss-eap-xp-bootable-jar ✓ Checking files for pushing [2ms] ✓ Syncing files to the component [825ms] Executing devfile commands for component java-jboss-eap-xp-bootable-jar ✓ Executing dev-build command "mvn -Pbootable-jar -Dinsecure.repositories=WARN -Dmaven.repo.local=/home/jboss/.m2/repository -Dmaven.test.skip=true -Ddev package" [11m] ✓ Executing dev-debug command "mvn -Pbootable-jar -Dinsecure.repositories=WARN -Dwildfly.bootable.arguments=\"-b=0.0.0.0\" -Dwildfly.bootable.jvmArguments=\"-agentlib:jdwp=transport=dt_socket,address=0.0.0.0:${DEBUG_PORT},server=y,suspend=n\" -Dmaven.repo.local=/home/jboss/.m2/repository wildfly-jar:dev", if not running [1s] Pushing devfile component java-jboss-eap-xp-bootable-jar ✓ Changes successfully pushed to component If we edit the source code and push our changes you can see that the deployment is quicker. Now let’s try to debug our application. First we need to create a tunnel to access the listening debug port on our application, so in a new terminal we need to execute: odo debug port-forward -l 8787 Started port forwarding at ports - 8787:5858 Now we can connect to debug our application on port 8787 with our IDE and debug as usual. Quite simple is’nt it ? Using the watch mode Now that we managed to build, run and debug our application on OpenShift we still need to execute commands to push our changes to the cloud. It would be nice to just have things updated automatically. odo provides a nice watch command that will push changes to OpenShift. But the bootable maven plugin offers also a watch mode that will have it recompile the application and redeploy it automatically when the code change. So let’s take advantage of those two modes. First we need to start our application in debug and watch mode: odo push --debug --build-command watch-build --debug-command watch-debug Validation ✓ Validating the devfile [34305ns] Creating Kubernetes resources for component java-wildfly-bootable-jar ✓ Waiting for component to start [21s] Applying URL changes ✓ URLs are synced with the cluster, no changes are required. Syncing to component java-wildfly-bootable-jar ✓ Checking file changes for pushing [1ms] ✓ Syncing files to the component [4s] Executing devfile commands for component java-wildfly-bootable-jar ✓ Executing watch-build command "echo 'It's watcher mode Baby !!!''" [812ms] ✓ Executing watch-debug command "mvn ${MVN_ARGS_APPEND} -Dwildfly.bootable.arguments=\"-b=0.0.0.0\" -Dwildfly.bootable.jvmArguments=\"-agentlib:jdwp=transport=dt_socket,address=0.0.0.0:${DEBUG_PORT},server=y,suspend=n\" org.wildfly.plugins:wildfly-jar-maven-plugin:dev-watch -e", if not running [2s] Pushing devfile component java-wildfly-bootable-jar ✓ Changes successfully pushed to component Now we can set odo in watch mode too: odo watch Component is running in debug mode Please start port-forwarding in a different terminal Waiting for something to change in /home/ehsavoie/tmp/test When you edit a file like src/main/resources/META-INF/microprofile-config.properties, you can see the following on the console: File /home/ehsavoie/tmp/test/src/main/resources/META-INF/microprofile-config.properties changed Pushing files... Validation ✓ Validating the devfile [145787ns] Creating Kubernetes resources for component java-wildfly-bootable-jar ✓ Waiting for component to start [132ms] Applying URL changes ✓ URLs are synced with the cluster, no changes are required. Syncing to component java-wildfly-bootable-jar ✓ Checking file changes for pushing [1ms] ✓ Syncing files to the component [994ms] Executing devfile commands for component java-wildfly-bootable-jar ✓ Executing watch-build command "echo 'It's watcher mode Baby !!!''" [808ms] ✓ Executing watch-debug command "mvn ${MVN_ARGS_APPEND} -Dwildfly.bootable.arguments=\"-b=0.0.0.0\" -Dwildfly.bootable.jvmArguments=\"-agentlib:jdwp=transport=dt_socket,address=0.0.0.0:${DEBUG_PORT},server=y,suspend=n\" org.wildfly.plugins:wildfly-jar-maven-plugin:dev-watch -e", if not running [851ms] Component is running in debug mode Please start port-forwarding in a different terminal Waiting for something to change in /home/ehsavoie/tmp/test And of course since we used a debug command, you can connect your IDE on port 8787 and debug as usual. So as we have seen, developping on OpenShift is now very easy and simple and almost as slick as local development. All the more so as you can add several containers on your pod. In the sample devfile that is provided you have a Jaeger Server that is running. Connecting to its web interface (exposed throught a route too), you can see the traces produced by our application. ### [Planned Security Features for WildFly](/news/2021/01/22/Planned-Security-Features-for-WildFly/) ### [WildFly Bootable JAR 3.0 is released!](/news/2021/01/15/WildFly-Bootable-JAR-3-0-is-released/) The version 3.0 of the WildFly Bootable JAR Maven plugin has been released. For people who are not familiar with WildFly Bootable JAR, I strongly recommend that you read this blog post that covers it in detail. The new features that come in this release (in particular the dev-watch goal) have already been covered when announcing the Beta1 release. The Bootable JAR documentation contains a new chapter that provides details on the dev-watch goal. Since Beta1, the Bootable JAR examples have been evolved to use WildFly 22.0.0.Final that has just been released. In this blog post I will focus on the integration with Keycloak. This integration is now possible thanks to the Keycloak Galleon feature-pack that is new in Keycloak 12.0.0. Keycloak Galleon feature-pack The Keycloak Galleon feature-pack provides an OIDC client adapter by the means of a Galleon layer. The keycloak-client-oidc Galleon layer brings the OIDC keycloak subsystem (and associated JBoss modules) and configures the server security. For more information on the Keycloak Galleon feature-pack usage with WildFly, you can read the dedicated chapter in the WildFly documentation. Using the Bootable JAR Maven plugin, you can combine layers coming from multiple Galleon feature-packs. In your plugin configuration it looks like: <configuration> <feature-packs> <feature-pack> <location>wildfly@maven(org.jboss.universe:community-universe)</location> </feature-pack> <feature-pack> <location>org.keycloak:keycloak-adapter-galleon-pack:12.0.1</location> </feature-pack> </feature-packs> <layers> <layer>web-server</layer> <layer>keycloak-client-oidc</layer> </layers> ... </configuration> You will notice that the <location> element is structured differently for the WildFly feature-pack and the Keycloak one. The WildFly feature-pack is accessible from the Galleon community-universe. Retrieving the WildFly feature-pack from this universe allows us to not specify any version and get the latest one. Since the Keycloak Galleon feature-pack is not registered inside an universe, you need to specify its Maven coordinates. When building a Bootable JAR, the plugin retrieves the feature-packs from Maven repositories and provisions a server based on the set of Galleon layers. You can follow the steps documented in this example to secure a servlet deployed inside a Bootable JAR using Keycloak. Developing on OpenShift with Bootable JAR We are currently working at defining ODO dev files in order to make for a smooth and efficient development experience on OpenShift. Changes done in your local Maven project fire automatic re-build and re-deploy of your application in the remote OpenShift cluster POD. To achieve this, we are leveraging the ODO source watching capabilities to push changes onto your OpenShift POD. dev-watch goal, that is running in the POD, takes over and automatically re-build/re-deploy your application. Stay tuned! Known issues We have encountered an issue when using the dev-watch goal with the WildFly microprofile-* quickstarts. You need to upgrade the plugin to 3.0.2.Final to allow for dev-watch to properly operate. The Maven command to use is: mvn wildfly-jar:dev-watch -Pbootable-jar -Dversion.wildfly-jar.maven.plugin=3.0.2.Final To conclude If you have an interesting use-case, simple enough to be reduced to a simple example, and it is not covered by the examples, then feel free to contribute one. We will be very happy to help you integrate your example in the project. Just ask! Finally, we would really appreciate that you keep us posted with your feedback and new requirements (that you can log as new project issues), this will help evolve the WildFly Bootable JAR experience in the right direction. Thank-you! JF Denise ### [Automatic Self-Signed Certificate Generation with Elytron](/news/2021/01/14/Automatic-Self-Signed-Certificate-Generation-with-Elytron/) ### [How to properly stop batch processing job and step in WildFly](/news/2021/01/14/How-to-properly-stop-batch-processing-job-and-step-in-WildFly/) Batch jobs are long-running background processing tasks, and therefore it’s common that user may need to pause or stop the execution. WildFly, which implements batch processing through its jberet component based on JSR 352 and Jakarta Batch Specification, offers a variety of ways to achieve that requirement. This post will demonstrate how to stop a running job execution, or individual step execution, and some design and implementation consideration. Properly stop a running job execution Batch spec defines a standard API for stopping a running job execution: javax.batch.operations.JobOperator#stop As stated in its javadoc, calling JobOperator.stop() sends a stop request to the batch container, which tries its best effort to stop the running job execution. So it’s important to implement batch application that properly responds to a stop request. In the following sections, I’ll explain what it entails for the two different types of steps: batchlet step and chunk step. Stop a running job execution that contains batchlet step A batchelt step represents a free-form, opaque task that is fully controlled by the batch application. The batch container has no chance to intervene once the batchlet starts its processing. So the batchlet class is responsible for providing a way to stop itself, if it wants to support graceful stop. That’s why javax.batch.api.Batchlet interface declares a stop() method that a batchlet class must implement. In the example batchlet class below, once it receives a stop request in its stop() method, it sets the toStop flag to true. Its process() method periodically checks this flag to determine if it needs to stop processing. Note that bathlet stop() method is called asynchronously while the batchlet process() method is running in a different thread. And the batchlet class should be implemented to properly handle concurrency. @Named public class Batchlet1 implements Batchlet { private final AtomicBoolean toStop = new AtomicBoolean(); @Override public String process() throws Exception { String exitStatus = "BATCHLET1_COMPLETED"; while (true) { if (toStop.get()) { exitStatus = "BATCHLET1_STOPPED"; break; } // perform batchlet task, such as downloading and copying files, sending emails, etc. } return exitStatus; } @Override public void stop() throws Exception { toStop.set(true); } } After the batch application is deployed to WildFly, you can start and stop a job execution in WildFly CLI: # To start a new job execution # /deployment=numbers-chunk.war/subsystem=batch-jberet:start-job(job-xml-name=numbers) { "outcome" => "success", "result" => 1L } # To stop the running job execution # /deployment=numbers-chunk.war/subsystem=batch-jberet:stop-job(execution-id=1) {"outcome" => "success"} The above stop-job CLI operation calls JobOperator.stop(jobExecutionId) behind the scene, and eventually the batchlet stop() method is called to receive the stop request. The following CLI commands checks the status of the stopped job execution, and a stopped job execution can be restarted from where it left off. # To check the status of the stopped job execution: # /deployment=numbers-chunk.war/subsystem=batch-jberet/job=numbers/execution=1:read-resource(include-runtime, recursive) { "outcome" => "success", "result" => { "batch-status" => "STOPPED", "create-time" => "2020-10-29T19:33:13.843-0400", "end-time" => "2020-10-29T19:33:30.258-0400", "exit-status" => "STOPPED", "instance-id" => 1L, "last-updated-time" => "2020-10-29T19:33:30.258-0400", "start-time" => "2020-10-29T19:33:13.853-0400" } } # To restart the previously stopped job execution: # /deployment=numbers-chunk.war/subsystem=batch-jberet:restart-job(execution-id=3) { "outcome" => "success", "result" => 4L } You can also perform all the above operations in WildFly Management Console. For example, the following screenshot shows the UI to stop a job execution: Stop a running job execution that contains chunk step A chunk step is basically a read-process-write loop and naturally supports stop operation. The batch container can intervene at certain junctures amid the iterations. So unlike a batchlet step, there is no required method to implement in order to support stop. However, since a graceful stop will wait for the current chunk to complete, the chunk step should choose a suitable chunk size (configured in item-count, time-limit, or custom checkpoint policy in job xml). If the chunk size is too big, and the stop request arrives shortly after the current chunk starts, it may take a long time for the current chunk to complete before the batch container can safely stop the current step execution. On the other hand, a small chunk size results in more frequent checkpointing and quicker response to stop request at the expense of processing speed. Properly stop an individual running step The previous section describes ways to stop the entire job execution. You may be wondering if there is a way to stop an individual step only while allowing the rest of the job to continue. Since this is slightly deviates from the standard, you cannot use JobOperator.stop(jobExecutionId) or Batchlet.stop() to achieve that. Instead, I would consider this a special case of normal execution, which should be implemented by the batch application itself. Stop an individual running batchlet step Batchlet class can watch for some condition to determine if it should stop its processing. It can exit its process() method with different exit status to signal different outcomes to subsequent steps. For example, Batchlet1 below polls the system property job1.batchlet1.stop; once it’s set to true, process() method returns with exit status BATCHLET1_STOPPED. Similarly, the condition can be a marker file in the file system, a column value in a database table, a shared state in a single bean, etc. Once the batchlet is stopped this way, the batch status of the step will be COMPLETED, and its exit status will be BATCHLET1_STOPPED. The job execution will continue to the next step configured in job xml. @Named public class Batchlet1 implements Batchlet { @Override public String process() throws Exception { String exitStatus = "BATCHLET1_COMPLETED"; while (true) { if (shouldStop()) { exitStatus = "BATCHLET1_STOPPED"; break; } // perform batchlet task // Thread.sleep(5000); } return exitStatus; } private boolean shouldStop() { return Boolean.getBoolean("job1.batchlet1.stop"); } @Override public void stop() throws Exception { // implement stop() method to respond to incoming request // to stop this batchlet step and entire job execution } } In WildFly CLI, you can set and unset a system property as a flag to batch application: # set system property in WildFly as a flag to stop the step execution # /system-property=job1.batchlet1.stop:add(value=true) {"outcome" => "success"} # clean up afterwards and remove the system property # /system-property=job1.batchlet1.stop:remove() {"outcome" => "success"} Stop an individual running chunk step Stopping an individual running chunk step is more complicated than a batchlet step. When implement this case as a special case of normal processing, a possible strategy is: A graceful stop should wait for the current chunk to complete, and then stop the next chunk. The batch application can poll certain condition in javax.batch.api.chunk.listener.ChunkListener#beforeChunk method, and save the condition, e.g., in javax.batch.runtime.context.StepContext#setTransientUserData. javax.batch.api.chunk.ItemReader#readItem can check the condition from javax.batch.runtime.context.StepContext#getTransientUserData, and if true, return null. This will cause the chunk step to complete normally as if there is no more data to read. Once the chunk step is stopped this way, the batch status of the step will be COMPLETED, and its exit status will be COMPLETED unless reset by the batch application. The job execution will continue to the next step configured in job xml. Summary In this post we went through ways to stop either a job execution or an individual step execution. It’s possible to combine them, so the batch application can support graceful stop of both the entire job execution and any individual step. In most cases, I’d recommend designing your batch application, adhering to the batch spec and leveraging the well-defined stop behavior. It makes your batch application and workflow easier to understand and maintain. Standard stop operation also supports restarting the previously stopped job execution from where it left off (e.g., stopped step or checkpoint). When some batch applications really need to stop an individual step, the design choice and implementation should be well documented to convey the justification and implications. As this type of stop is disguised as a normal execution, it does not support restart. Care should be taken to avoid data loss and data corruption. ### [Using case principal transformers in Elytron](/news/2021/01/14/Using-case-principal-transformers-in-Elytron/) ### [WildFly 22 is released!](/news/2021/01/13/WildFly-22-is-released/) I’m pleased to announce that the WildFly 22 Final zip is now available for download. Let’s have a look at what’s new. New Features Logging In response to a great deal of user demand, WildFly has added support for log4j2. Applications deployed in the server can use the log4j2 API which will delegate to the JBoss Log Manager. Provisioning and Managing WildFly It is now possible to use a Galleon feature-pack provided by Keycloak to install the Keycloak client adapters for WildFly into your WildFly installation, instead of having to unzip content manually into your installation and update your config using the CLI. These Keycloak adapters allow you to secure deployments using OpenID Connect. A new web-passivation Galleon layer is available. Use it to provision the Distributable Web subsystem configured with a local web container cache. New base health and base metrics subsystems are available. These provide a foundation for updated versions of the corresponding 'microprofile-health-smallrye' and 'microprofile-metrics-smallrye' subsystems. They also allow users who don’t need the custom deployment-specific health and metrics information provided by Eclipse MicroProfile Health and Metrics to still get general server health and metrics information via the management endpoint without needing to include the MicroProfile Health and Metrics libraries in their server installation. This is discussed further in the Feature-pack Changes section below. If the --read-only-server-config startup param is used, the server will now run even if the configuration directory is read-only. This allows non-writable storage to be mounted as the configuration directory. The high-level CLI command command has been enhanced to allow creation of commands for existing resources. Messaging The management API can now be used to pause or resume a topic thus stopping all the subscribers from receiving new messages from a paused topic. In order to help mitigate the possibility of split brain problems ActiveMQ Artemis has the ability to ping a configurable list of hosts to check the health of the broker’s network connection. This Artemis feature can now be configured via the messaging-activemq subystem’s management API. Security WildFly now provides the ability to lazily generate a self-signed certificate on first use when using Elytron. This self-signed certificate should only be used for testing purposes. It should never be used in a production environment. It is now possible to configure a 'case-principal-transformer' in the Elytron subsystem to convert a principal to upper or lower case. Previously, a custom transformer was required to adjust a principal’s username to upper/lower case. Elytron now provides a principal transformer for this use case. WildFly Preview As I announced in November when we released WildFly 22 Alpha1, along with our traditional Jakarta EE 8 distribution we want to give our users a preview of what will be coming in WildFly as we move on to EE 9 and later. We call this distribution "WildFly Preview". The WildFly 22.0.0.Final release includes an update to WildFly Preview. Even though this is coming from a .Final tag of the WildFly codebase, WildFly Preview should always be regarded as a tech-preview/beta distribution. EE 9 is primarily about implementing the necessary change in the Jakarta EE APIs from the javax.* package namespace to the jakarta.* namespace. This is a big change that is going to take a while to percolate through the EE ecosystem, e.g. for the many projects that compile against the EE APIs to provide versions that use jakarta.*. While this happens we want to continue to deliver new features and fixes to our community, so the primary WildFly distribution will continue to provide the EE 8 APIs. EE 9 Via Bytecode Transformation and the 'wildfly-preview' Galleon Feature-Pack The large majority of the libraries included in WildFly Preview that were compiled against EE APIs were based on the javax.* EE 8 APIs. This includes the libraries produced from WildFly’s own code base and by WildFly Core. But the EE APIs libraries available in the WildFly Preview runtime all use the jakarta.* packages. How can this work? The solution we’ve come up with for this is to provide a new 'wildfly-preview' Galleon feature-pack, in addition to the standard 'wildfly' feature-pack. (Recall that any WildFly server installation, including the ones that are zipped up and made available for download here, is produced by telling Galleon tooling to provision from a feature-pack.) The 'wildfly-preview' feature-pack differs from the standard 'wildfly' one in a number of ways, with the key ones relevant to EE 9 being: Where suitable EE 9 spec API jars were available from Eclipse, those were used instead of the EE 8 spec jars used in standard WildFly. Where suitable 'native' EE 9 implementation libraries (i.e. ones compiled against jakarta.*) were available, those were used. This includes Weld, Hibernate Validator, Mojarra, Yasson, Jakarta EL and Jakarta JSON. Any libraries that were using EE 8 APIs were detected and instructions were incorporated in the feature-pack telling Galleon to do byte code transformation of that library whenever it provisions a server using the feature-pack. The last item is the key point. When Galleon provisions a 'wildfly-preview' server by pulling jars down from maven, it knows that some artifacts were compiled against EE 8 javax.* packages. So it bytecode transforms those jars to alter references to EE 8 packages in the class file constant tables to change from javax.* to jakarta.*. The transformation goes beyond simple package renames; a number of other known differences between EE 8 and EE 9 are handled. Thanks to the Eclipse Transformer project for their work on the underlying transformation tool. You can use the Galleon CLI tool to provision a server from the wildfly-preview feature-pack yourself: galleon.sh install wildfly-preview:current --dir=my-wildfly-server Note the use of 'wildfly-preview' instead of 'wildfly'. As Galleon provisions the server it will log quite a bit of information about the transformation work it is doing. Please note that the transformation adds a fair bit to the amount of time it takes to provision the server. WildFly Preview Support for EE 8 Deployments The APIs that WildFly Preview exposes to deployments are the EE 9 APIs, so all the classes and interfaces are in the jakarta.* packages. But what if you want to run an existing EE 8 application on WildFly Preview? We expect that to be a very important use case in the long run. Eventually the jakarta.* APIs will be what’s provided by the standard WildFly distribution, but many WildFly users will have existing applications that they’ll want to continue to run unchanged. So we wanted to make sure from the very beginning that that works. What we’ve done is we’ve added to the server’s handling of managed deployments the same basic transformation that’s applied to the server artifacts when provisioning. A managed deployment is one where a management client (the CLI, HAL console or the deployment scanner) presents deployment content to the server and the server makes a copy of it in its internal deployment content repository. The content that gets installed into the runtime is that internal copy. A WildFly Preview server, when it reads in deployment content to store in the content repository, will transform any EE 8 content into EE 9. In the long run I feel it’s better for users if they either convert their application source to EE 9 APIs, or use build-time tooling that we and the rest of the Jakarta community will work to provide to do transformation at build time. But some applications just can’t be changed, so the server-side solution we’re using can handle those cases. Feature-Pack Changes The WildFly server is provisioned using five Galleon feature-packs. The composition of these feature-packs has changed somewhat in WildFly 22. The five feature-packs are: wildfly-core — provides the functionality provided by the WildFly Core project. wildfly-servlet — depends on wildfly-core and adds the functionality needed for the "Servlet-Only Distribution" you can find for each WildFly release on the download page. wildfly-ee — depends on wildfly-servlet and adds the functionality needed for a full EE appserver, plus other long-standing appserver functionality like clustering support. wildfly — depends on wildfly-ee and adds Eclipse MicroProfile functionality. This is the feature-pack used to provision the standard WildFly distribution found on the download page, and is the feature-pack that we expect most users who provision their own server or bootable jar to use. wildfly-preview — depends on wildfly-core and adds all other functionality needed for the WildFly Preview distribution. In WildFly 22 we corrected a conceptual problem in WildFly 21 and earlier where the 'wildfly-ee' feature-pack was including five MicroProfile specifications: Config, Health, Metrics, OpenTracing and Rest Client. We want the support for the faster moving, more-open-to-breaking-changes MicroProfile specs to only come from the top level 'wildfly' feature-pack. So in WildFly 22 we moved that functionality out of 'wildfly-ee' and into 'wildfly'. People only using only 'wildfly-ee' to provision will no longer have access to those specifications. We do want 'wildfly-ee' users to be able to continue to use the WildFly management interface to do server health and readiness checks and to get JVM and container metrics in Prometheus format. To support this we have added new base health and base metrics subsystems to wildfly-ee. These subsystems do not provide any sort of API to deployments; e.g. you can’t use them to provide your own health checks or metrics in your application code. If you want that you should use the 'wildfly' feature-pack and the MicroProfile Health and Metrics subsystems. The MicroProfile Health and Metrics subsystems now require the presence in the config of the base health and base metrics subsystems. Users migrating from WildFly 21 or earlier should add these new extensions/subsystems to their configuration. We anticipate further evolution in these feature-packs in WildFly 23. In particular, it is likely the 'wildfly-ee' feature-pack will no longer depend on 'wildfly-servlet' or transitively on 'wildfly-core'. Instead it will directly provide the content currently provided by those feature-packs. Standards Support WildFly 22.0.0 is a Jakarta EE 8 compatible implementation, with both the Full Platform and the Web Profile. Evidence supporting our certification is available for the Full Platform and for the Web Profile. WildFly 22 is also a compatible implementation of Java EE 8. WildFly 22 is also a compliant implementation of the Eclipse MicroProfile 3.3 platform specification. The WildFly Preview distribution released today is not yet a compatible implementation of Jakarta EE 9 or MicroProfile 3.3. We’re continuing to make good progress toward being able to certify compatibility, but we’re not there yet. The main area where users may hit meaningful issues related to EE compliance is in webservices if deployment descriptors using the EE 9 xml schemas are used. This can be worked around by using EE 8 schemas, which are functionally equivalent. JDK Support Our recommendation is that you run WildFly on the most recent long-term support JDK release, i.e. on JDK 11 for WildFly 22. While we do do some testing of WildFly on JDK 12 and 13, we do considerably more testing of WildFly itself on the LTS JDKs, and we make no attempt to ensure the projects producing the various libraries we integrate are testing their libraries on anything other than JDK 8 or 11. WildFly 22 also is heavily tested and runs well on Java 8. We plan to continue to support Java 8 at least through WildFly 23, and probably beyond. While we recommend using an LTS JDK release, I do believe WildFly runs well on JDK 13. By run well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. We do see a couple of test failures with JDK 13 when using the deprecated Picketlink subsystem and WS Trust. Work to allow WildFly to run on JDK 14 and 15 is ongoing. We’re continuing our work to digest fully some of the package removals that came in JDK 14, particularly in the security area. The biggest barrier we face is the deprecated legacy security implementation based on Picketbox cannot support JDK 14. We intend to remove support for that security implementation after WildFly 23 and to only provide Elytron-based security. A lot of behind-the-scenes work to make that possible got accomplished during the WildFly 21 cycle. Please note that WildFly runs on Java 11 and later in classpath mode. Documentation The WildFly 22 documentation is available at the docs.wildfly.org site. The WildFly 22 management API documentation is in the wildscribe section of the WildFly 22 docs. Jira Release Notes The full list of issues resolved is available here. Issues resolved in the WildFly Core 14 releases included with WildFly 22 are available here. Enjoy! We hope you enjoy WildFly 22. We’d love to hear your feedback at the WildFly forum. But most important, please stay safe and well! ### [New WildFly 22 Beta1 and 21.0.2 releases](/news/2020/12/17/New-WildFly-22-Beta1-and-21-0-2-releases/) Year End Treats I’m pleased to announce that two new WildFly releases are available for download at https://wildfly.org/downloads. First you can get WildFly 22.0.0.Beta1 and have a look at what’s coming soon in WildFly 22. This also includes an update of WildFly Preview. Release notes for that release are here, with issues fixed in the underlying WildFly Core betas listed here. For developers using our bootable jar feature, please have a look at the new dev-watch mode that Jean-Francois Denise describes in his latest blog post. We’ve also done a micro update of WildFly 21, a new WildFly 21.0.2.Final release. This includes a fix for CVE-2020-27822, a medium impact CVE. Release notes for that release are here. Thank you to Rafael Paz and Michel Erard for reporting the problems that led to these fixes! Thank you to everyone in the WildFly community for your support of WildFly in 2020. It’s been a trying year but I’m excited by and proud of the progress we’ve made. I wish all of you and your families a happy and healthy rest of the year, and I’m looking forward to a great 2021! Best regards, Brian ### [WildFly Bootable JAR 3.0.0.Beta1 is released!](/news/2020/12/15/WildFly-Bootable-JAR-3-0-0-Beta1-is-released/) The 3.0.0.Beta1 version of the WildFly bootable JAR Maven plugin has been released. This release is not yet Final, it is "just a beta", but we think that it is of enough good quality to acquire feedback on it. For people who are not familiar with WildFly bootable JAR, I strongly recommend that you read this blog post that covers it in details. In addition to bug fixes, this release brings 2 new goals: help: to display the plugin goals and configuration elements descriptions. dev-watch: an evolution of the dev goal that makes repackaging of your application no more required. Dev-watch goal The current dev goal, although offering an efficient workflow to develop WildFly applications, requires an explicit repackaging of your application. This is currently done in two steps: mvn wildfly-jar:dev that builds and starts the server in background. The deployment scanner monitors the target/deployments directory for new deployed content. mvn package -Ddev that builds your application then copy the deployment to the target/deployments directory. Update your src, re-call mvn package -Ddev When done call mvn wildfly-jar:shutdown that kills the running server (NB: requires the management layer to be provisioned). So each time a change is made to your application, mvn package -Ddev must be called for the deployment to be re-deployed. Furthermore, when the plugin configuration located in the pom.xml file is modified (e.g.: a new Galleon layer is added), when a CLI script is updated or when some extra content is added, the running server must be killed and wildfly-jar:dev must then be re-called. This knowledge of when to re-build a bootable JAR, when to stop/re-start it, when to re-build your sources and when to re-deploy is now under the control of the dev-watch goal. The new workflow introduced by the goal is: mvn wildfly-jar:dev-watch that builds your application (if needed), builds and starts the server, deploys your application and finally watches for file changes in your project. Note that this call is blocking. The dev-watch goal and the server write traces to the console. Update your files. changes are detected. The goal advertises in the console what is the action it is taking (re-build, re-deploy, …). Refresh your browser (if needed) to access the re-deployed application. When done, send Ctrl-C in the shell. Integration in IDE is straightforward. As an example I have created a Maven action named 'dev-watch' that calls wildfly-jar:dev-watch goal in NetBeans IDE. Once called, the goal traces are displayed in the IDE output windows. You can then forget about the execution and start modifying your files in the IDE and refresh your web browser to visualize changes. New Examples We have added some new examples: An example that shows how to use the webservices Galleon layer. An example that shows how to integrate the Maven plugin from Graddle. An example that shows how to deploy activemq rar file and use the ejb Galleon layer. Plugin configuration changes We have fixed the extraServerContent configuration element to be extraServerContentDirs. That was required to align its name with the extra-server-content-dirs alias. If you are already using extra-server-content-dirs (that is the advised way), then nothing change for you, if you are using extraServerContent, you will have to update your pom file. To conclude We hope that you are seeing the benefits of the new features that this release is bringing. We would really appreciate your feedback on the dev-watch goal. We aim toward a smooth and efficient first class WildFly developer experience and we need you there! Thank-you. JF Denise ### [WildFly MicroProfile GraphQL Feature-Pack 1.0.0.Final Released!](/news/2020/11/27/WildFly-MicroProfile-GraphQL-Feature-Pack-1-0-0-Final-Released/) I am happy to announce that the first Final build of the GraphQL feature-pack has been released! It is fully compatible with MicroProfile GraphQL 1.0 and has been tested with WildFly 20 and 21, JDK 8 and 11. It bundles the latest available version of SmallRye GraphQL, and that is 1.0.17. Client libraries The feature-pack now contains the typesafe GraphQL client libraries. They are now installed as WildFly static modules, so deployments using the client libraries don’t have to carry all the libraries within themselves, they just need to depend on the io.smallrye.graphql.client module. Layer rename The graphql layer included in the feature-pack was renamed to microprofile-graphql to align with other WildFly layers. Multiple deployment support While MicroProfile specifications are generally designed to be used in microservice environments as opposed to application servers with multiple deployments, the GraphQL feature-pack does support running with multiple deployments in one WildFly instance. There have been issues with it in the past, but since we now bundle graphql-java 16.1, multiple deployments should work. Note that this support is only on a best-effort basis, and there will probably still be some issues. Future goodies to look forward to SmallRye Mutiny support and better alignment with reactive programming in general Managed federation (see this article) Other transport protocols apart from HTTP And more! Feedback We’re keen to hear your feedback! Please raise any issues found at https://github.com/wildfly-extras/wildfly-graphql-feature-pack/issues. ### [WildFly 21.0.1 is released!](/news/2020/11/19/WildFly-21-0-1-is-released/) WildFly 21.0.1.Final is now available for download. It’s been about a month since the WildFly 21 release, so we’ve done a small bug fix update, WildFly 21.0.1. The full list of issues resolved in WildFly 21.0.1 is available here. Issues resolved in the WildFly Core update included with WildFly 21.0.1 are available here. Enjoy! ### [Jakarta EE 9 with WildFly Preview](/news/2020/11/12/Jakarta-EE-9-with-WildFly-Preview/) I’m pleased to announce that the WildFly 22 Alpha1 zips are now available for download. This includes the first release of a new 'WildFly Preview' distribution of WildFly, which we’re using to give our community a tech preview look at things we see coming down the road in our main WildFly distribution. Right now this is mostly about what we are doing with Jakarta EE 9, although there are some other differences that I’ll get into below. We don’t normally do alpha releases of WildFly, but we’re overdue to give our community a look at what we’re doing on EE 9. I believe what we have can be a useful milestone for people wanting an early look at where we’re going, so here it is! WildFly Preview and Jakarta EE 9 It’s exciting to see the great progress the Jakarta EE community has made on the way to the upcoming GA release of Jakarta EE 9! As I discussed in my June post on the plans for WildFly and EE 9, the EE 9 release is primarily about implementing the necessary change in the Jakarta EE APIs from the javax.* package namespace to the jakarta.* namespace. This is a big change that is going to take a while to percolate through the EE ecosystem, e.g. for the many projects that compile against the EE APIs to provide versions that use jakarta.*. While this happens we want to continue to deliver new features and fixes to our community, so the primary WildFly distribution will continue to provide the EE 8 APIs. But, we want the community to begin to look at EE 9, so we decided to produce a new distribution of WildFly, which we’re calling WildFly Preview. With WildFly 22 Alpha1 we’re providing the first download of WildFly Preview. EE 9 Via Bytecode Transformation and the 'wildfly-preview' Galleon Feature-Pack The large majority of the libraries included in WildFly Preview that were compiled against EE APIs were based on the javax.* EE 8 APIs. This includes the libraries produced from WildFly’s own code base and by WildFly Core. But the EE APIs libraries available in the WildFly Preview runtime all use the jakarta.* packages. How can this work? The solution we’ve come up with for this is to provide a new 'wildfly-preview' Galleon feature-pack, in addition to the standard 'wildfly' feature-pack. (Recall that any WildFly server installation, including the ones that are zipped up and made available for download here, is produced by telling Galleon tooling to provision from a feature-pack.) The 'wildfly-preview' feature-pack differs from the standard 'wildfly' one in a number of ways, with the key ones relevant to EE 9 being: Where suitable EE 9 spec API jars were available from Eclipse, those were used instead of the EE 8 spec jars used in standard WildFly. Where suitable 'native' EE 9 implementation libraries (i.e. ones compiled against jakarta.*) were available, those were used. This includes Weld, Hibernate Validator, Mojarra, Yasson, Jakarta EL and Jakarta JSON. Any libraries that were using EE 8 APIs were detected and instructions were incorporated in the feature-pack telling Galleon to do byte code transformation of that library whenever it provisions a server using the feature-pack. The last item is the key point. When Galleon provisions a 'wildfly-preview' server by pulling jars down from maven, it knows that some artifacts were compiled against EE 8 javax.* packages. So it bytecode transforms those jars to alter references to EE 8 packages in the class file constant tables to change from javax.* to jakarta.*. The transformation goes beyond simple package renames; a number of other known differences between EE 8 and EE 9 are handled. We owe a great deal of thanks to B.J. Hargrave and the community behind the Eclipse Transformer project for their work on the underlying transformation tool. You can use the Galleon CLI tool to provision a server from the wildfly-preview feature-pack yourself: galleon.sh install wildfly-preview:current#22.0.0.Alpha1 --dir=my-wildfly-server Note the use of 'wildfly-preview' instead of 'wildfly'. Because this release is an alpha, Galleon won’t try to install it by default if you don’t give it explicit instructions to do so. So I include the '#22.0.0.Alpha1' in the feature-pack location string. Another way to do this is to explicitly state that an alpha feature-pack frequency is acceptable: galleon.sh install wildfly-preview:current/alpha --dir=my-wildfly-server As Galleon provisions the server it will log quite a bit of information about the transformation work it is doing. Please note that the transformation adds a fair bit to the amount of time it takes to provision the server. WildFly Preview Support for EE 8 Deployments The APIs that WildFly Preview exposes to deployments are the EE 9 APIs, so all the classes and interfaces are in the jakarta.* packages. But what if you want to run an existing EE 8 application on WildFly Preview? We expect that to be a very important use case in the long run. Eventually the jakarta.* APIs will be what’s provided by the standard WildFly distribution, but many WildFly users will have existing applications that they’ll want to continue to run unchanged. So we wanted to make sure from the very beginning that that works. What we’ve done is we’ve added to the server’s handling of managed deployments the same basic transformation that’s applied to the server artifacts when provisioning. A managed deployment is one where a management client (the CLI, HAL console or the deployment scanner) presents deployment content to the server and the server makes a copy of it in its internal deployment content repository. The content that gets installed into the runtime is that internal copy. A WildFly Preview server, when it reads in deployment content to store in the content repository, will transform any EE 8 content into EE 9. In the long run I feel it’s better for users if they either convert their application source to EE 9 APIs, or use build-time tooling that we and the rest of the Jakarta community will work to provide to do transformation at build time. But some applications just can’t be changed, so the server-side solution we’re using can handle those cases. Confession: beyond wanting to make sure EE 8 deployments can run for users, we need it to work for ourselves. The WildFly testsuite is full of hundreds of EE 8 deployments. We want to be able to run those tests aganst WildFly Preview, so we needed to make this work. Other Differences in WildFly Preview Besides exposing EE 9 APIs, we want to use WildFly Preview to help get community exposure for other changes we plan to make in the server. Here are the key ones: The legacy security subsytem is not supported. The standard configurations are all based on Elytron security. Our goal is to remove the underlying Picketbox libraries altogether in the next few months. This is an important prerequisite for supporting JDK 14 or later. When we do this, security vault support will be removed as well. Elytron credential stores should be used. The security vault tool (used to manipulate vault contents) is not provided. The standard configuration files do not configure an embedded messaging broker. Instead they configure the 'messaging-activemq' subsystem to provide connections to a remote ActiveMQ Artemis broker. (It’s a task for the user to run such a broker or to update the config to integrate with a different broker.) We want WildFly out-of-the-box to be more of a cloud native appserver and having an embedded messaging broker in the default configuration is not cloud native. A WildFly container in the cloud running an embedded broker is not scalable, as multiple broker instances need separate configuration to act as a primary or backup. An embedded messaging broker also has more advanced persistent storage requirements than a server primarily dedicated to handling HTTP requests would have. Note however that running an embedded broker is still supported. We’ve added an example 'standalone-activemq-embedded.xml' configuration showing its use to the $WILDFLY_HOME/docs/examples/configs folder. The Picketlink extension is removed. The JSR-77 extension is removed. The extensions providing the legacy subsystems 'cmp', 'config-admin', 'jacorb', 'jaxr', 'messaging' (HornetQ based), and 'web' (not 'undertow') are removed. These were only used for domain mode to allow a Domain Controller to control hosts running much earlier WildFly versions where servers using these subsystems were supported. Known Issues Please understand that WildFly Preview is a true alpha, so you may find issues if you try it for your use case. If you do, please report them on the WildFly JIRA. There are a number of known issues: WildFly Preview does not pass the EE 9 platform TCK. We currently have 193 failures (out of over 40,000 tests). These are mostly in the webservices area. The bootable jar feature we’ve been rolling out over the last few WildFly releases does not support WildFly Preview yet. JBoss Modules modules installed by the user are not transformed. If such a module uses EE 8 APIs it will not work. Deployment overlays are not transformed. So any overlay artifact that uses EE 8 APIs will not work. Unmanaged deployments that use EE 8 APIs will not work. We transform managed deployments when we copy the deployment content into the internal content repo. For unmanaged deployments we use the original content file(s) the user provides, and WildFly won’t modify those files as we don’t consider them as being 'owned' by the server. Managed exploded deployments likely won’t work. Applications incorporating the EE 9 variant of the Jakarta XML Web Services WSDL customization descriptor will not work. The EE 8 variant, which should be semantically equivalent, should work. Alternate JPA and JSF providers that you can install with standard WildFly are not supported. Note that the current lack of support for parsing EE 9 WSDL customization descriptors means our test coverage of EE 9 Jakarta XML Web Services applications is less robust than it is for most other EE technologies. Looking Forward The near term priorities for WildFly Preview are to continue to progress on the EE 9 TCK and to get bootable jar support working. We’ll strive to continue to improve the speed of the transformation process. And as more 'native' EE 9 variants of the libraries we use become available we’ll update WildFly Preview to incorporate those. Later on we’ll work to handle transforming deployment overlays and perhaps to handle JBoss Modules modules added by the user. Jira Release Notes The full list of issues resolved is available here. Issues resolved in the WildFly Core 14 Beta1 release included with WildFly 22 are available here. Enjoy! We hope you enjoy WildFly 22 Alpha1. Please give it a try, particularly WildFly Preview, and give us your feedback. But most important, please stay safe and well! ### [WildFly MicroProfile Reactive Specifications Feature-Pack 1.0.0.Final Released!](/news/2020/11/05/WildFly-MicroProfile-Reactive-Specifications-Feature-Pack-1-0-0-Final-Released/) I am happy to announce the 1.0.0.Final release of the MicroProfile Reactive specifications feature-pack for WildFly. It is tested against both WildFly 20 and 21. The main changes since 1.0.0.Beta1 are essentially upgrades to the latest SmallRye implementations of all the MicroProfile Reactive specifications, and fixing problems related to memory leaks and redeployments. The MicroProfile Reactive specifications are: MicroProfile Reactive Messaging 1.0 - this is a framework for building event-driven, data streaming and event sourcing applications using CDI. The streams, or channels, can be backed by a variety of messaging technologies. We currently ship connectors for: Apache Kafka, AMQP and MQTT. MicroProfile Reactive Streams Operators 1.0 - Reactive Messaging is built on Reactive Streams. RSO gives you a way to manipulate and handle those streams. MicroProfile Context Propagation 1.0 - The traditional way of propagating state using ThreadLocals does not work well in the reactive world. Async/reactive code often creates a 'pipeline' of code blocks that get executed 'later' - in practice after the method defining them has returned. MicroProfile Context Propagation is there to help you deal with this, so that your deferred code can still for example latch onto the transaction initiated by the calling method. We have also renamed the layers (mainly by prefixing microprofile- to their names) to bring them in line with the upcoming work to eventually bring this into WildFly. As mentioned in the original 1.0.0.Beta1 announcement this feature-pack is an incubator for WildFly. The 1.0.0.Beta1 announcement also contains some background information about the specifications, as well as how to install and use the feature-pack, so be sure to read that first if you are not familiar with this feature-pack. Also, the feature-pack README contains more detailed information about how to provision servers with this feature-pack. We will not announce every single bug fix release here, so please make sure to check for the latest release on the releases page (links to the tags with an up-to-date README are just to the left of each release in the list). What is coming up? We plan to provide Reactive Messaging in WildFly for either WildFly 22 or 23. The initial focus for WildFly will be on MicroProfile Reactive Messaging 1.0 with support for Kafka. This means that MicroProfile Reactive Messaging, MicroProfile Reactive Streams Operators and the Kafka connector will be moved over to WildFly. That WIP currently lives in the https://github.com/kabir/wildfly/tree/reactive-port branch. MicroProfile Context Propagations which we don’t see as immediately useful for the use-cases provided by MicroProfile Reactive Messaging 1.0 will remain in the feature-pack. Also the AMQP and MQTT connectors will remain in the feature-pack for now. In short WildFly will eventually contain parts of what the feature-pack currently contains, while the remainder remains in a trimmed version of the feature-pack. The feature-pack master branch will still be where we cut the stable releases from if we need to fix something for the current incarnation of the feature-pack. For example if we find some bugs, or if we don’t make the cutoff for WildFly 22. The reorganisation of the feature-pack to deal with the partial migration of the MicroProfile Reactive specifications to WildFly will happen in the feature-pack development branch. Feedback We’re keen to hear your feedback! Please raise any issues found at https://github.com/wildfly-extras/wildfly-mp-reactive-feature-pack/issues. ### [WildFly 21 S2I images have been released on quay.io](/news/2020/11/03/WildFly-21-S2I-images-have-been-released-on-quay-io/) WildFly 21 S2I Docker images The WildFly S2I (Source-to-Image) builder and runtime Docker images for WildFly 21 have been released on quay.io/wildfly. For a complete documentation on how to use these images using S2I, OpenShift and Docker, refer to the WildFly S2I README. Adding the imagestreams and template to OpenShift At some point the new images will be made available from the OpenShift catalog and image repository. But you can already use these images by adding them yourselves to your OpenShift cluster. WildFly S2I builder image stream: oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-21.0/imagestreams/wildfly-centos7.json WildFly runtime image stream: oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-21.0/imagestreams/wildfly-runtime-centos7.json Chained build template: oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-21.0/templates/wildfly-s2i-chained-build-template.yml NB: If you import the image streams into your project, be sure to set the ImageStreams Namespace (IMAGE_STREAM_NAMESPACE argument) to your project namespace in the template. openshift being the default namespace. EJB, JSF new Galleon layers example WildFly 21 brings a new set of Galleon layers that you can use during s2i build phase. In this example, we are composing a server using these 2 new Galleon layers: ejb-lite: Support for Jakarta Enterprise Beans Lite. jsf: Support for Jakarta Server Faces. Build and run the application The example is a CRUD JSF application. Build the application image: oc new-app wildfly-s2i-chained-build-template -p APPLICATION_NAME=jsf-ejb-jpa \ -p GIT_REPO=https://github.com/wildfly/wildfly-s2i \ -p GIT_BRANCH=v21.0 \ -p GIT_CONTEXT_DIR=examples/jsf-ejb-jpa \ -p GALLEON_PROVISION_LAYERS=web-server,ejb-lite,jsf,jpa,h2-driver \ -p IMAGE_STREAM_NAMESPACE=myproject Create an application from the application image: oc new-app myproject/jsf-ejb-jpa Expose the service: oc expose svc/jsf-ejb-jpa Access the application route. You will see pre-populated tasks. You can add, update and delete tasks. Enjoy! ### [New Security Features in WildFly 21](/news/2020/11/02/New-Security-Features-in-WildFly-21/) ### [Release of WildFly Operator 0.4.1](/news/2020/10/27/Release-of-WildFly-Operator-0-4-1/) The WildFly Operator helps deploy and manage WildFly applications on Kubernetes and OpenShift. With the recently released 0.4.1 version, the WildFly Operator is now able to provide seamless upgrades of your application on OpenShift. Note This feature is specific to OpenShift as it relies on resources such as ImageStreams that are not provided by vanilla Kubernetes. The WildFly operator was using the applicationImage field to identify and deploy your application on the container platform. This field accepts different types: the name of the image: quay.io/jmesnil/wildfly-demo-app:step-1 a tag: quay.io/jmesnil/wildfly-demo-app:step-1 a digest: quay.io/wildfly-quickstarts/wildfly-operator-quickstart@sha256:0af38bc38be93116b6a1d86a9c78bd14cd527121970899d719baf78e5dc7bfd2 In all these cases, the container platform would pull the image when the application is deployed and uses it for the whole application lifecycle. If you wanted to deploy a new image, you had to edit the applicationImage manually and specify the checksum of the new image to deploy. Now, with the 0.4.1 release, the WildFly Operator also accepts an ImageStreamTag for its applicationImage field, for example wildfly-demo-app:latest. This imagestream tag must belong to an ImageStream in the same namespace than the application. With that simple setting, any changes to the imagestream tag will trigger a new deployment of the application without having to modify any resources. Note This article does not provide an extensive explanation on how Images are managed by OpenShift with ImageStreams and ImageStreamTags. Please refer to the OpenShift documentation for a complete description. Create a Demo application To illustrate this feature, I wrote a very simple MicroProfile application that return a JSONified version of "Hello, World!": https://github.com/jmesnil/wildfly-operator-demo-app AppEndpoint.java @Path("/") @ApplicationScoped public class AppEndpoint { @Inject @ConfigProperty(name = "greetings", defaultValue = "Hello") String greetings; @GET @Produces({ "application/json" }) public String getText() { String text = "{\"text\":\"" + greetings + ", World!\"}"; return text; } } As the application has access to the full MicroProfile APIs (including MicroProfile Config), it is possible to configure the greetings returned by the application by setting the greetings config property (which defaults to "Hello"). It can be configured using an environment variable named GREETINGS. I have built a Docker image of this application and pushed it to quay.io/jmesnil/wildfly-demo-app:step-1. You can run it directly from Docker: $ docker run -p 8080:8080 -e GREETINGS=Bonjour quay.io/jmesnil/wildfly-demo-app:step-1 ... $ curl http://localhost:8080 {"text":"Bonjour, World!"} Note I created this Docker image from the step-1 tag of the Git repository. It uses the WildFly 21 S2I image and the microprofile-platform layer so that the image contains only what is needed to run a MicroProfile application. The command I used to create the application image is: $ s2i build https://github.com/jmesnil/wildfly-operator-demo-app.git \ --ref=step-1 \ quay.io/wildfly/wildfly-centos7:21.0 \ -e GALLEON_PROVISION_LAYERS=microprofile-platform \ wildfly-demo-app:step-1 To show how we can seamlessly upgrade to a new version of this application, I created a second image of the application corresponding to the step-2 tag where the text is now returned in uppercase: public String getText() { String text = "{\"text\":\"" + (greetings + ", World!").toUpperCase() + "\"}"; return text; } This second image is pushed to quay.io/jmesnil/wildfly-demo-app:step-2 and can also be run directly from Docker: $ docker run -p 8080:8080 -e GREETINGS=Ahoj quay.io/jmesnil/wildfly-demo-app:step-2 ... $ curl http://localhost:8080 {"text":"AHOJ, WORLD!"} Install the WildFly Operator on OpenShift We will first install the WildFly Operator on OpenShift in a new project named wildfly-demo First, we create the new project (and the corresponding namespace): $ oc new-project wildfly-demo Then we install a CatalogSource to get access to the WildFly Operator that is in the operatorhub.io catalog: operatorhub-io-catalogsource.yaml apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: name: operatorhub-io spec: displayName: Operators from operatorhub.io image: quay.io/operatorhubio/catalog:latest sourceType: grpc We install it by running: $ oc apply -f operatorhub-io-catalogsource.yaml catalogsource.operators.coreos.com/operatorhub-io created Then we create a subscription for the current version (0.4.1) of the WildFly Operator: wildfly.yaml apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: name: wildfly labels: operators.coreos.com/wildfly.wildfly-demo: '' spec: channel: alpha installPlanApproval: Automatic name: wildfly source: operatorhub-io sourceNamespace: wildfly-demo startingCSV: wildfly-operator.v0.4.1 Again, we install it on OpenShift by running: $ oc apply -f wildfly.yaml subscription.operators.coreos.com/wildfly created We will then wait until the WildFly Operator is installed by monitoring its installation: $ oc get csv -w NAME DISPLAY VERSION REPLACES PHASE wildfly-operator.v0.4.1 WildFly 0.4.1 wildfly-operator.v0.4.1 WildFly 0.4.1 Pending ... wildfly-operator.v0.4.1 WildFly 0.4.1 InstallReady ... wildfly-operator.v0.4.1 WildFly 0.4.1 Installing ... wildfly-operator.v0.4.1 WildFly 0.4.1 Succeeded Note For the purpose of this example, the WildFly Operator is only be installed in the current wildfly-demo namespace. All resources that are created must also be installed in that same namespace. Create an ImageStream Before we can deploy our application on OpenShift using the WildFly Operator, we will first create an ImageStream named wildfly-demo-app that will contain a stream of all our application images $ oc import-image wildfly-demo-app:step-1 \ --from quay.io/jmesnil/wildfly-demo-app:step-1 \ --confirm We have added the wildfly-demo-app:step-1 imagestream tag to this imagestream by importing the Docker image from quay.io/jmesnil/wildfly-demo-app:step-1. Then we tag it with the latest tag that will be referenced from our deployments. $ oc tag wildfly-demo-app:step-1 wildfly-demo-app:latest At this point, we have an ImageStreamTag wildfly-demo-app:latest that we can use to deploy our application and upgrade it later seamlessly. We have finally the image inside OpenShift and are ready to deploy our application. Deploy the Application To deploy the application, we create a WildFlyServer resource with the applicationImage set to wildfly-demo-app:latest. This will let OpenShift pull the image from the latest imagestream tag in the wildfly-demo-app imagestream. wildfly-app.yaml apiVersion: wildfly.org/v1alpha1 kind: WildFlyServer metadata: name: wildfly-app spec: applicationImage: 'wildfly-demo-app:latest' env: - name: GREETINGS value: Guten Tag replicas: 2 $ oc apply -f wildfly-app.yaml wildflyserver.wildfly.org/wildfly-app created The WildFly Operator will then configure and deploy the application on OpenShift. It will also automatically create a Route to access it outside of the cluster. The application is thoroughly described by the oc describe command: Name: wildfly-app Namespace: wildfly-demo Kind: WildFlyServer Metadata: ... Spec: Application Image: wildfly-demo-app:latest Env: Name: GREETINGS Value: Guten Tag Replicas: 2 Status: Hosts: wildfly-app-route-wildfly-demo.apps.jmesnil-80cs.eapqe.psi.redhat.com Pods: Name: wildfly-app-0 Pod IP: 10.128.2.199 State: ACTIVE Name: wildfly-app-1 Pod IP: 10.128.2.200 State: ACTIVE Replicas: 2 Scalingdown Pods: 0 Events: <none> The only information we need is the hosts field that contains the public URL of our application. If we access it, we can get our text message: $ curl http://$(oc get wfly/wildlfy-app -o jsonpath="{.status.hosts[0]}") {"text":"Guten Tag, World!"} Seamless Upgrade to a New Version of the Application Image We now want to deploy the second version of our application without disrupting our services. We can take advantage of seamless upgrades to do it. First, we will import the quay.io/jmesnil/wildfly-demo-app:step-2 image in the wildfly-demo-app imagestream with the step-2 tag: $ oc import-image wildfly-demo-app:step-2 \ --from quay.io/jmesnil/wildfly-demo-app:step-2 \ --confirm At this point, nothing has changed, the image is available in OpenShift but the WildFly Operator will not use it as it only references the wildfly-demo-app:latest imagestream tag. Let’s now change this latest tag to point to the wildfly-demo-app:step-2 tag. $ oc tag wildfly-demo-app:step-2 wildfly-demo-app:latest Tag wildfly-demo-app:latest set to wildfly-demo-app@sha256:a9970ab8cebad210d7248e090ea88d6af87e8f910c7a087a3aac03c951cd764e. Once this is done, OpenShift will observe that the latest tag has changed (it corresponds to a new image) and will notify the WildFly Operator to trigger a new deployment of the application. If you continue to access the public route of the application, you will see that it will eventually return the upper case version of the text: $ curl http://$(oc get wfly/wildlfy-demo-app -o jsonpath="{.status.hosts[0]}") {"text":"GUTEN TAG, WORLD!"} It can take some time as OpenShift will terminate and redeploy all the Pods that runs the application. Image Build Pipeline This short demo illustrates that it is now possible to seamlessly upgrade an application maintained by the WildFly Operator by using an imagestream tag to refer to the application image. To illustrate this, we did a step-by-step demo to understand how and when the upgrade is triggered. However, in normal use, most of these steps are automated and the upgrade becomes really seamless (and do not require user intervention). There is a lot more that can be achieved by taking full advantage of the OpenShift ecosystem to build and deploy images. I have built the application image using S2I outside of OpenShift but it is possible to use BuildConfig resources to build the image inside OpenShift and automatically tag them with the latest imagestream tag. Using BuildConfig to build the images has two main benefits: You can specify hooks to trigger building new images when the code from a remote Git repository is updated. You can also trigger building new images when WildFly S2I images are upgraded. In that case, seamless upgrades apply not only to the application image but also to the WildFly S2I images that are used to build the application image. In a more realistic example, we could have a staging cluster with a BuildConfig that would trigger new application images when the code is updated (or when a new Git tag is pushed to a remote repository) or when new WildFly S2I images are released. This would automatically trigger a test pipeline to test and verify the new application image. Once this new application image has been validated (automatically or manually), we can then push this new application image in our production cluster and tag it with latest to trigger an upgrade of the application in production. Summary When it is running on OpenShift, the WildFly Operator can leverage its ecosystem around Images to provide seamless upgrades of applications to trigger new deployments when anything in the build pipeline (application code or WildFly images) changes. This simplifies application maintenance and reduces security risks by automating the upgrades and making sure that the application is always built on top of the latest application code and WildFly images. More information User Documentation for WildFly Operator WildFly S2I Project OpenShift Documentation - Understanding containers, images, and imagestreams ### [WildFly Bootable JAR is final!](/news/2020/10/19/WildFly-Bootable-JAR-is-final/) As we introduced few months ago, we have been working on a "Fat JAR" packaging for WildFly. We are pleased to announce that the 2.0.0 Final version of the WildFly bootable JAR Maven plugin has been released. WildFly 21, that has just been released (you can check the announcement), fully supports this new way of packaging applications. A bootable JAR allows you to package both the server and your application deployment inside a single JAR file and execute it with a simple command such as java -jar myapp-bootable.jar. Important There is no need to re-design your application to have it executed inside a bootable JAR. Developing an application packaged as a bootable JAR is not different from developing an application for a traditional WildFly server installation using Maven. WildFly installation strategies Along side the WildFly zip installation and Galleon provisioning, the bootable JAR Maven plugin introduces a new way to install a WildFly server and package your applications. In order to help you identify the more appropriate installation strategy, the WildFly documentation introduces a new Installation Guide that helps you choose the best approach according to your application needs. WildFly Bootable JAR To help you start with this new packaging, we have defined a WildFly Bootable Guide. This guide summarizes the steps required to get started. For a detailed documentation of the Maven Plugin usage, you can read the Maven plugin documentation. The example Maven projects are a good place to start practicing with the Maven plugin. The WildFly quickstarts that cover Eclipse MicroProfile features have been evolved with the 'bootable-jar' and 'bootable-jar-openshift' Maven profiles allowing you to use the bootable JAR plugin. Using Maven Packaging your application inside a bootable JAR is done when building your application using Maven. This is done by adding an extra build step to your Maven application pom.xml file. <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <configuration> ... </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> Then call mvn package to build both your deployment and the bootable JAR ( target/<app name>-bootable.jar file) that contains it. The details on how to configure the build of a bootable JAR can be found in the Maven plugin documentation. Composing a WildFly Server Galleon layers The Maven plugin depends on Galleon trimming capabilities to build a tailored server. From the plugin configuration element, you need to provide the WildFly Galleon feature-pack and the list of Galleon layers you want to include/exclude. The WildFly Galleon feature-pack is a maven artifact that contains everything needed to dynamically provision a server. A WildFly Galleon layer is a name that identifies a server capability (e.g.: jaxrs, ejb, microprofile-config, jpa) or an aggregation of such capabilities. A layer captures a server capability in the form of: A piece of server XML configuration (e.g.: extension, configured subsystem, interfaces) that describes the capability. A set of JBoss modules that implements the capability. When you are using a layer, it delivers these pieces of information in order for Galleon to assemble a server containing only the required configuration and JBoss modules. WildFly Documentation contains a description of the WildFly Galleon layers. An example of a plugin configuration needed to compose a server to run typical REST applications with support for distributed sessions: <configuration> ... <feature-pack-location>wildfly@maven(org.jboss.universe:community-universe)</feature-pack-location> (1) <layers> (2) <layer>jaxrs-server</layer> (3) <layer>web-clustering</layer> (4) </layers> </configuration> (1) In this plugin configuration extract, we are retrieving the latest WildFly Galleon feature-pack installed in the org.jboss.universe:community-universe Galleon universe. In case you would like to provision a specific version of the server, you would need to specify the server version, for example wildfly@maven(org.jboss.universe:community-universe)#21.0.0.Final (2) The included set of layers. (3) jaxrs-server is a foundational layer which provides capabilities required to build typical REST applications as well as core WildFly capabilities like the logging subsystem and a secure remote management interface. (4) web-clustering is a layer that provides Infinispan-based web session clustering. Important You are strongly advised to check the WildFly Galleon layers documentation in order to identify the Galleon layers that will fit your application needs. Third-party Galleon layers The plugin allows you to combine Galleon layers from multiple sources. A source of Galleon layers must be a Galleon feature-pack designed to be usable with WildFly. For example, the project wildfly-datasources-galleon-pack defines a Galleon feature-pack that contains layers for postgresql, mysql and oracle drivers and datasources. In order to compose a server from multiple source use the <feature-packs> configuration element. For example: <configuration> ... <feature-packs> <feature-pack> <location>wildfly@maven(org.jboss.universe:community-universe)#21.0.0.Final</location> </feature-pack> <feature-pack> <groupId>org.wildfly</groupId> <artifactId>wildfly-datasources-galleon-pack</artifactId> <version>1.1.0.Final</version> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> (1) <layer>postgresql-datasource</layer> (2) </layers> </configuration> (1) cloud-server comes from the WildFly Galleon feature-pack. (2) postgresql-datasource comes from the wildfly-datasources-galleon-pack Galleon feature-pack. The postgresql example shows how to combine Galleon layers from multiple sources. Developer Experience A strong focus has been put on "Developer Experience", in particular when it comes to development efficiency and development for cloud. Cloud support Adapting the server configuration to OpenShift To properly operate in an OpenShift context, a server such as WildFly requires configuration tuning in order to adapt to the cloud execution context (e.g.:socket binding, HA cluster protocol, logging, health checks). This tuning is automatically applied when you are using the plugin to build applications for OpenShift. When building an application to be deployed on OpenShift you need to add the <cloud> configuration element. <configuration> ... <cloud/> </configuration> The web-clustering example shows how to build a cluster of bootable JARs running on OpenShift. The details on how to configure a bootable JAR for cloud execution can be found in the Configuring the server for cloud execution chapter of the Maven plugin documentation. Zero configuration with the Eclipse JKube plugin The JKube plugin automates build and deployment of your application for OpenShift or Kubernetes. By combining the WildFly bootable JAR and JKube plugins you can achieve "zero configuration" for application deployment. No Openshift resource creation, no docker image creation, just let the plugin runs! <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <configuration> <feature-pack-location>wildfly@maven(org.jboss.universe:community-universe)#21.0.0.Final</feature-pack-location> <layers> <layer>cloud-server</layer> </layers> <cloud/> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.eclipse.jkube</groupId> <artifactId>openshift-maven-plugin</artifactId> <executions> <execution> <goals> <goal>resource</goal> <goal>build</goal> </goals> </execution> </executions> <configuration> <enricher> <config> <jkube-service> <type>NodePort</type> </jkube-service> </config> </enricher> </configuration> </plugin> </plugins> </build> Then call mvn oc:deploy to build your deployment, create a bootable JAR and deploy it onto openshift. Important Make sure you are logged in to your OpenShift Cluster prior to calling oc:deploy. The jkube example shows how to use the WildFly bootable JAR and JKube Maven plugin. The JKube plugin documentation contains information on how you can customize liveness and readiness probes. Dev mode In order to speed-up the development of your application, the Maven plugin offers the wildfly-jar:dev goal that builds and starts the bootable JAR only once. When you re-package your application, it will get automatically re-deployed in the running server. The details on how to use the dev goal can be found in the Development mode chapter of the Maven plugin documentation. Server configuration In case the default configuration that Galleon layers bring is not complete, the plugin allows you to fine tune the packaged server. WildFly CLI scripts Although Galleon layers contains commonly used server configuration elements, it can be required to fine tune the server. The WildFly CLI tooling has been integrated into the Maven plugin in order to apply management operations during build. That is done by defining one or more CLI script files containing the list of management operations you want to see executed during packaging. For example: A CLI script to add the org.foo.demo logging logger, set its level and configure the console handler to print log messages of all levels: /subsystem=logging/logger=org.foo.demo:add /subsystem=logging/logger=org.foo.demo:write-attribute(name=level,value=ALL) /subsystem=logging/console-handler=CONSOLE:write-attribute(name=level,value=ALL) The plugin configuration extract used to set the CLI script to be executed: <configuration> ... <cli-sessions> <cli-session> <script-files> <script>scripts/logging.cli</script> </script-files> </cli-session> </cli-sessions> The logging example shows how to configure the logging subsystem using WildFly CLI. Packaging extra content Sometime you need to package content along with the server (e.g.: a keystore, some properties files). The server packaged inside a bootable JAR uses the exact same file system layout as a WildFly installation. The plugin allows you to specify a directory (layout similar to a WildFly home directory) that gets copied into the packaged server. For example, to copy mykeystore.jks to the standalone/configuration directory, create the directory <project base dir>/my-custom-content that contains standalone/configuration/mykeystore.jks and reference it from the plugin configuration. For example: <configuration> ... <extra-server-content-dirs> <extra-content>my-custom-content</extra-content> </extra-server-content-dirs> </configuration> The https example shows how to package extra content. Testing with Arquillian WildFly Arquillian 3.0 contains support for a WildFly bootable JAR allowing you to test deployments with Arquillian. The org.wildfly.arquillian:wildfly-arquillian-container-bootable adapter for arquillian supports: Execution of tests that run as a client against a running bootable JAR. Execution of tests that run inside a running bootable JAR but with some limitations. The bootable JAR to test must be a Hollow JAR (a JAR that doesn’t contain any deployment). There is no support yet to repackage an existing deployment to contain the classes of the deployment created by the test. The arquillian examples show how to use WildFly arquilian to test deployments running inside a bootable JAR. To conclude We hope that you are seeing an interest in this new WildFly application packaging; keep us posted with your feedback and new requirements (that you can log as new project issues). Thank-you. JF Denise ### [WildFly 21 is released!](/news/2020/10/13/WildFly-21-is-released/) I’m excited to announce that the WildFly 21 Final zip is now available for download. Bootable JAR / Galleon Layers The biggest thing in WildFly 21 is Jean-Francois Denise and the team have added GA-level support for the Bootable JAR feature that we’ve been working on over the last two releases. The bootable jar feature allows you to add a maven plugin to your application’s pom and have your build package your application deployment and the WildFly server needed to run it inside a single executable jar file. Running your application can be as simple as java -jar my-application.jar. A bootable jar can be particularly useful for cloud deployment use cases. For example, you can use the JKube maven plugin to build and deploy your application on OpenShift. You can learn more about bootable jars in our new Bootable JAR Guide. To get the most benefit from a bootable jar, you’ll want to customize the WildFly server in it provide only the functionality you need, while leaving out configuration and binaries that are not relevant. To support this kind of customization, the bootable jar maven plugin lets you specify a list of names of the WildFly functionality you’d like. Each of those names identifies one of the Galleon layers that WildFly provides. To help ensure your experience with bootable jars is a good one, in WildFly 21 we greatly expanded the list of Galleon layers we provide. New in 21 are: batch-jberet — Support for Jakarta Batch. ejb — Support for Jakarta Enterprise Beans, excluding the IIOP protocol. ejb-dist-cache — Infinispan-based distributed caching for stateful session beans. An alternative to the default local caching. ejb-lite — Support for Jakarta Enterprise Beans Lite. ejb-local-cache — Infinispan-based local caching for stateful session beans. An alternative to distributed caching. jdr — Support for the JBoss Diagnostic Reporting (JDR) subsystem. jsf — Support for Jakarta Server Faces. jsonb — Support for Jakarta JSON Binding. jsonp — Support for Jakarta JSON Processing. mail — Support for Jakarta Mail. messaging-activemq — Support for connections to a remote Jakarta Messaging Service broker. microprofile-platform — Support for all available Eclipse MicroProfile platform specifications. pojo — Support for legacy JBoss Microcontainer applications. remote-activemq — Support for connections to a remote Apache Activemq Artemis JMS broker. sar — Support for SAR archives to deploy MBeans. webservices — Support for Jakarta XML Web Services web-console — Support for loading the HAL web console from the /console context on the HTTP management interface. More details along with the full set of layers WildFly provides is available in the bootable jar documentation. There are now a variety of ways use WildFly: by unzipping the traditional server zip, by provisioning a customized WildFly instance using the Galleon CLI tool, and by building a running a bootable jar. We’ve added a brief Installation Guide to help you decide which approach best fits your needs. Many thanks to Tomask Adamski, Tommaso Borgato, Yeray Borges, Fabio Burzigotti, Jean-Francois Denise, Vladimir Dousodil, Cheng Fang, Darragh Fitzmaurice, Emmanuel Hugonnet, Rado Husar, Bob Johnson, Jan Kasik, Darran Lofthouse, Jim Ma, Roberto Oliveira and James Perkins for all of your hard work on this this summer. But, of course, we weren’t entirely focused on bootable jar and Galleon! So, what else is new? Other Enhancements Security Once again, the folks working on security have brought us some new toys: A RESTEasy client can now make use of Elytron’s configuration on the client side of a REST deployment to use credentials, bearer tokens and SSLContexts. For this to happen, the Elytron client artifacts must be present on the classpath during the build of RESTEasy client. Users are now able to configure Elytron to use credentials established externally from the server to authenticate the client with HTTP. This will allow users to propagate authentication from mod-cluster/ajp to WildFly. Two new kinds of Elytron security realms have been added: A failover-realm is a security realm wrapper containing a delegate and a failover realm. If the delegate throws a RealmUnavailableException during identity lookup, it will be caught and failover realm will be used instead. A distributed-realm is a security realm wrapper containing a list of other security realms allowing the server to sequentially invoke them until one succeeds. It is now possible to use TLS 1.3 with WildFly when using the OpenSSL TLS provider with Elytron. EJB EJB invocations over the HTTP protocol can now be used in server-to-server configurations. The EJB client protocol allows for compression of the invocation message and the open-session message payload. Configuration of such compression can now be configured globally. Managing WildFly WildFly’s MicroProfile Health implementation now includes three vendor-specific checks as part of server readiness checking. These check the management kernel’s view of the overall server status and the status of all deployments, and that the server booted without errors. In the standalone.conf(.bat|.ps1) script configuration file you can now add a MODULE_OPTS=-javaagent:my-agent.jar environment variable. This allows you to take advantage of JBoss Modules' ability to run as a java agent invoke other agents. Taking advantage of this is useful for occasions when previously the log manager was required on the boot class path. WildFly users can use a Git repository to manage their configuration file history of their standalone server. While previously it was only possible to establish a connection with HTTP authentication, it is now possible to establish a connection with SSH authentication using an Elytron configuration file to specify the credentials to be used. Standards Support WildFly 21.0.0 is a Jakarta EE 8 compatible implementation, with both the Full Platform and the Web Profile. Evidence supporting our certification is available for the Full Platform and for the Web Profile. WildFly 21 is also a compatible implementation of Java EE 8. WildFly 21 is also a compliant implementation of the Eclipse MicroProfile 3.3 platform specification. While we made a lot of progress on an EE 9 compatible variant of WildFly during the WildFly 21 cycle, I chose not to include a variant of that as part of the WildFly 21 release. I would like to produce an alpha of that fairly early during the WildFly 22 development cycle. JDK Support Our recommendation is that you run WildFly on the most recent long-term support JDK release, i.e. on JDK 11 for WildFly 21. While we do do some testing of WildFly on JDK 12 and 13, we do considerably more testing of WildFly itself on the LTS JDKs, and we make no attempt to ensure the projects producing the various libraries we integrate are testing their libraries on anything other than JDK 8 or 11. WildFly 21 also is heavily tested and runs well on Java 8. We plan to continue to support Java 8 at least through WildFly 22, and probably beyond. While we recommend using an LTS JDK release, I do believe WildFly runs well on JDK 13. By run well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what a newer JVM means for their applications to be able to look to WildFly as a useful development platform. We do see a couple of test failures with JDK 13 when using the deprecated Picketlink subsystem and WS Trust. Work to allow WildFly to run on JDK 14 and 15 is ongoing. We haven’t had time to digest fully some of the package removals that came in JDK 14, particularly in the security area. We did make significant progress in this area during WildFly 21 development though. The biggest barrier we face is the deprecated legacy security implementation based on Picketbox cannot support JDK 14. We intend to remove support for that security implementation after WildFly 23 and to only provide Elytron-based security. A lot of behind-the-scenes work to make that possible got accomplished during the WildFly 21 cycle. Please note that WildFly runs on Java 11 and later in classpath mode. Documentation The WildFly 21 documentation is available at the docs.wildfly.org site. As a reminder, starting with WildFly 19 we shifted the location of the auto-generated documentation of the appserver management API from the wildscribe.github.io site to a make it part of the general documentation for a release. The WildFly 21 management API documentation is in the wildscribe section of the WildFly 21 docs. Jira Release Notes The full list of issues resolved is available here. Issues resolved in the WildFly Core 13 releases included with WildFly 21 are available here. Enjoy! We hope you enjoy WildFly 21. Please give it a try, particularly the bootable jar features, and give us your feedback. But most important, please stay safe and well! ### [Biased locking removed from Java - does it affect you ?](/news/2020/09/30/Biased-locking-removed-from-Java-does-it-affect-you/) Last week we became aware that the OpenJDK team in Java 15 have disabled biased locking (JEP 374)in the Java virtual machine. This is a change from previous versions and could potentially have a negative impact on a Java application’s performance. Red Hat’s own performance teams are currently running performance tests to see how it affects our Java middleware, but no amount of generic testing can reveal how this change affects real-world applications. That is where you come in. We would like to get info from you on whether your application performance is affected by biased locking or not. To do so please try the following in your application performance tests: Run your WildFly application performance tests as you normally would with the following command line flags on Java 11 (jdk11u): enabled: -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 disabled: -XX:-UseBiasedLocking We would like to know the result of this no matter if you see a regression or not on the same Java Virtual Machine. If you are accustomed to tuning WildFly’s thread utilization then running your test with the following scenarios would be of great help too: thread count ~= hardware core count thread count ~= N * hardware core count where 8 < N < 16 The intent of these are to see how the level of concurrency affects the result. The term 'thread count' can refer to a great many things in a WildFly context. For most EE apps that are primarily about handling HTTP requests the most relevant configuration area is the io subsystem, particularly the task-max-threads attribute in the IO subsystem’s worker resource. Reporting the result Please open a bug on the WildFly JIRA with [jep374] in the title + your project. e.g. [jep374] results for acme project crazy panda containing the following information per run in the description: jvm used: jdk11 hardward-core count: N (if you know) thread configuration information: io subsystem config block from your server config or other relevant threading configuration (if you can) performance test result: with biased locking performance test result: without biased locking This will help us immensely. Thank you! Background Below is some background context on biased locking - all optional reading - you don’t need to understand the details to help us by running your performance tests and let us know if anything changes. What is biased locking? Biased locking lowers the cost of uncontended synchronization. Without biased locking: a thread needs to set and clear a lock bit when it performs repeated synchronizations on the same object. It also needs to wait for those set/clear writes to be drained to local cache before proceeding to execute further memory operations. With biased locking: the first time a thread synchronizes on an object it does a bit more work to acquire synchronized ('bias' it to the thread). Subsequent syncrhonizations proceed via a simple read test with no need to drain to cache. Where’s the trade off? Well, if a biased lock is contended then there is more work to do to bias and unbias the lock. However, it is known that many synchronized operations are uncontended. Biasing can be a big win when a potentially concurrent data structure is actually used sequentially. The case where it helps most is exemplified in the problem we already found in class DataOutputStream. Normally only one thread writes a DataOutputStream and it is often not read until the stream has been filled. All the same, every putInt or putLong call invokes a syncrhonized method to increment the byte count by 4 or 8. That’s needed just in case some other thread might want to reliably locate the end of the valid buffer data but that rarely happens. So, the unbiased case suffers lock write and cache drain delays at every basic put operation. A similar case occurs with class ByteOutputStream. The method putByte is synchronized. So writing a single byte involves a lock and unlock. Note that method putInt calls putByte 4 times, requiring 4 locks and unlocks. Method putLong calls it 8 times! Why is biased locking being removed? The implementation of biased locking adds a great deal of complexity to the JVM and is understood by only a small subset of the most experienced engineers. The cost of maintaining it and designing around it is significantly slowing down progress on new features. It has been a long term goal to remove it if at all possible. Some OpenJDK contributors wanted to remove it right away in JDK 15 while others argued for a slower deprecation route in order to check that we could really dispense with it. What happens next? We are collecting our own internal performance tests across multiple teams in Red Hat and will gather data from community reported tests too and see what the data indicates. At this stage we are making no assumption that the removal of biased locking will definitely make performance worse. We know that in some cases not having biased locks will improve performance. Our concern is to find cases, like the JDK examples above, where it might cause serious performance degradation and get an idea of how bad, and also how common, the worst cases might be. Once processed we might reach out to those reporting scenarios with unexpected results and get more details. Then we’ll work with the larger OpenJDK community to aid in deciding if biased locking can be turned off completely or a longer graceful deprecation period is needed. In any case - Thank you for your help and interest in making Java better! My thanks to Max Andersen from whose post on quarkus.io most of the content here was shamelessly copied! ### [Introducing the WildFly MicroProfile GraphQL Feature-Pack](/news/2020/08/13/Introducing-the-WildFly-MicroProfile-GraphQL-Feature-Pack/) I am pleased to announce the 1.0.0.Beta1 release of the MicroProfile GraphQL feature pack for WildFly. It offers experimental support for the MicroProfile GraphQL 1.0 specification, implemented by SmallRye GraphQL. MicroProfile GraphQL - link to the specification. SmallRye GraphQL - link to the underlying implementation. The source code for the feature-pack can be found on GitHub. Installing the feature-pack For now, the GraphQL support is distributed as a feature-pack rather than integrated into WildFly itself. To install the feature-pack, download the latest version of Galleon. At the time of writing this is 4.2.5. Unzip it somewhere, and add its bin/ folder to your path. Next, save a copy of provision.xml somewhere, and go to that folder in a terminal window. Then run: $galleon.sh provision ./provision.xml --dir=my-wildfly This will take some time the first time you do it since it will download a lot of dependencies from Maven. Once that is done, subsequent attempts will be fast. What this command does is: Provision a slimmed version (compared to the full download) of WildFly containing the relevant parts for a server running in the cloud. The main README of the project repository contains more information about this part. You can adjust this file to choose other parts of the server you may be interested in. Next it provisions the full contents of the feature-pack into our new server instance. The provisioned server will be output in the my-wildfly subdirectory, and can be started via the usual my-wildfly/bin/standalone.sh command. Example A very short example of what you can do with GraphQL is as follows. This is inspired by the quickstart (included in the GitHub repository containing the feature-pack), so be sure to try it out! Here we will just show you how to create an endpoint that returns data from a database of Star Wars films, namely just the operation that retrieves information about all films in the database: @GraphQLApi public class FilmResource { @Inject GalaxyService service; @Query("allFilms") @Description("Get all Films from a galaxy far far away") public List<Film> getAllFilms() { return service.getAllFilms(); } } The Film class is just a regular JavaBean (getters and setters omitted for brevity): public class Film { private String title; private Integer episodeID; private String director; private LocalDate releaseDate; } In such case, if the GraphQL client calls the following query: query allFilms { allFilms { title releaseDate } } The client will get back the requested data about all the films in the database (in our case, we only included episodes 4, 5 and 6!): { "data": { "allFilms": [ { "title": "A New Hope", "releaseDate": "1977-05-25" }, { "title": "The Empire Strikes Back", "releaseDate": "1980-05-21" }, { "title": "Return Of The Jedi", "releaseDate": "1983-05-25" } ] } } Feedback We’re keen to hear your feedback! Please raise any issues found at https://github.com/wildfly-extras/wildfly-graphql-feature-pack/issues. ### [WildFly 20.0.1 is released!](/news/2020/07/07/WildFly-20-0-1-is-released/) WildFly 20.0.1.Final is now available for download. It’s been about a month since the WildFly 20 release, so it’s time for a small bug fix update, WildFly 20.0.1. The full list of issues resolved in WildFly 20.0.1 is available here. Issues resolved in the WildFly Core 12.0.2 and 12.0.3 releases included with WildFly 20.0.1 are available here and here. Onward to WildFly 21! Enjoy. ### [WildFly and Jakarta EE 9](/news/2020/06/23/WildFly-and-Jakarta-EE-9/) Congratulations to the Jakarta EE community for the recent great progress on Jakarta EE 9! The Jakarta EE community has been making great strides in its work on Jakarta EE 9, and given today’s Jakarta EE 9 milestone release I wanted to give the WildFly community an update on what’s been going on regarding EE 9 in WildFly and a heads up on what I expect will be happening over the summer and the rest of this year. As discussed in the Jakarta EE 9 Release Plan, EE 9 is primarily about implementing the necessary change in the Jakarta EE APIs from the javax.* package namespace to the jakarta.* namespace. It isn’t about bringing new functionality to end users; the focus is on providing a platform that all of us in the EE ecosystem can use to adapt to the namespace change, ensuring we’re all in a solid position to take advantage of new features and approaches to doing things that we’d like to see in EE 10. The WildFly project is an important part of the EE ecosystem, so of course we’re going to participate in this. Besides work from WildFly community members on the Jakarta platform (big shout out to Scott Marlow for his TCK work) and the different specs, there’s been background prototyping work going on exploring how WildFly can provide an EE 9 compatible distribution. That work is now far enough along that it’s time to make it a part of the main WildFly development work. The javax.* to jakarta.* transition is a big task and it’s going to take a while to percolate through our ecosystem. I don’t think it’s good for WildFly to stop providing new features and fixes to our community while we take this on, so I’d like WildFly’s primary distribution to continue to be based on the EE 8 APIs. I think this should continue to be the case until we begin work toward EE 10. But we also need to provide an EE 9 server so our community can see what EE 9 will mean to them and so they can use us in their own EE 9 work. So I’d like us to begin producing a tech preview/beta EE 9 variant of WildFly. Ideally there would be at least one very early alpha type milestone over the summer but I don’t expect the first version to appear on the wildfly.org/downloads page until some time after the WildFly 21 release, perhaps late September or October. Then another version shortly after the WildFly 22 release, probably in December or early January. Eventually I’d like these to start coming out at the same time as the main WildFly releases. The main goal of these is to allow people to adapt to the jakarta.* namespace change. However, I would also like them to serve as a bit of a preview for how we see WildFly evolving in the future. For example WildFly 21 will still have the legacy Picketbox-based security as the default security layer, but I’d prefer not to have that layer even be present in the EE 9 variant. Although I’d like this EE 9 variant to be an evolution from what we have now, and a good way to adapt to the namespace change, it’s important to point out that any EE 10 variant of WildFly may evolve quite significantly from what we’ll be doing with EE 9. There is some uncertainty around how EE 10 will evolve and an expectation that EE 10 and Eclipse MicroProfile alignment will be a key focus, so what we’re doing with EE 9 is likely not going to align fully with our efforts in the future. We are working on getting this notion better codified. WildFly is a huge codebase, so maintaining two completely distinct flavors of it is not feasible. Furthermore, for a long time at least some of the binaries we ship will have been compiled against EE 8 APIs, with no native EE 9 variant available. To make this work, the EE 9 server would be based on a separate Galleon feature-pack from what we use for the main distribution. The large majority of the software artifacts that feature-pack references will be the same as what’s in the EE 8 distribution. However, as part of provisioning, any EE 8 content in the server will be transformed (primarily bytecode transformation) to use the EE 9 APIs. Scott Marlow, Richard Opalka and Jean-Francois Denise, with much appreciated assistance from B.J. Hargrave and others on the Eclipse Transformer project, have been making good progress on the needed transformation technology, and Jean-Francois has done well with the needed Galleon tooling. Jean-Francois’s latest POC is able to provision a server that can pass a significant chunk of the WildFly testsuite. That’s a good sign that it’s time for this work to start surfacing in the main WildFly and WildFly Core repos. Expect to hear more discussion, JIRAs, PRs, etc about this in the coming few weeks as we begin implementing changes in the main code base to make the EE 9 variant more maintainable and as development branches get underway. I’d love to hear your voices! To be honest, when the need for the javax.* to jakarta.* transition came up last year I was dreading dealing with it, but now I think it will be a lot of fun. Part of the overall goal with what we’ve been doing with Galleon has been to make it easier for users to have the WildFly they want. That rightfully should include truly distinct flavors, not just different subsets of a single flavor. This EE 9 work is going to be a great opportunity for us to make progress on that goal. Best regards, Brian ### [Introducing the WildFly MicroProfile Reactive Specifications Feature-Pack](/news/2020/06/18/Introducing-the-WildFly-MicroProfile-Reactive-Specifications-Feature-Pack/) I am pleased to announce the 1.0.0.Beta1 release of the MicroProfile Reactive specifications feature pack for WildFly. It offers experimental support for the following MicroProfile specifications, which all focus on the reactive area: MicroProfile Reactive Messaging 1.0 - this is a framework for building event-driven, data streaming and event sourcing applications using CDI. The streams, or channels, can be backed by a variety of messaging technologies. We currently ship connectors for: Apache Kafka, AMQP and MQTT. MicroProfile Reactive Streams Operators 1.0 - Reactive Messaging is build on Reactive Streams. RSO gives you a way to manipulate and handle those streams. MicroProfile Context Propagation 1.0 - The traditional way of propagating state using ThreadLocals does not work well in the reactive world. Async/reactive code often creates a 'pipeline' of code blocks that get executed 'later' - in practice after the method defining them has returned. MicroProfile Context Propagation is there to help you deal with this, so that your deferred code can still for example latch onto the transaction initiated by the calling method. We are using the SmallRye implementations of each of these specifications. The source code for the feature-pack can be found on GitHub. The README contains links to the specifications, as well as the SmallRye implementations of these and documentation. Installing the feature-pack We decided to see what the interest is in using these MicroProfile Reactive specifications in WildFly before integrating them into the WildFly code itself, which is why we have shipped this as a Galleon feature-pack. This is something that we plan on doing a lot more of in the future for experimental features. Galleon is a tool we have been using internally to compose the server the past several major releases of WildFly. To install the feature-pack, download the latest version of Galleon. At the time of writing this is 4.2.5. Unzip it somewhere, and add its bin/ folder to your path. Next, save a copy of provision.xml somewhere, and go to that folder in a terminal window. Then run: $galleon.sh provision ./provision.xml --dir=my-wildfly This will take some time the first time you do it since it will download a lot of dependencies from Maven. Once that is done, subsequent attempts will be fast. What this command does is: Provision a slimmed version (compared to the full download) of WildFly containing the relevant parts for a server running in the cloud. The main README of the project repository contains more information about this part. You can adjust this file to choose other parts of the server you may be interested in. Next it provisions the full contents of the feature-pack into our new server instance. The provisioned server will be output in the my-wildfly subdirectory, and can be started via the usual my-wildfly/bin/standalone.sh command. Example A short example of what these specs can do follows. The code snippets are inspired by the Quickstarts, so be sure to try those out! First we have a method which generates a new price every five seconds: private Random random = new Random(); @Outgoing("generated-price") public Flowable<Integer> generate() { return Flowable.interval(5, TimeUnit.SECONDS) .map(tick -> random.nextInt(100)); } The @Outgoing annotation comes from Reactive Messaging, and specifies that the stream of generated prices will be sent to a channel called 'generated-price'. Channels may be either in-memory, or they may be backed by a messaging provider. In this case, we have another method (it can be in another class) annotated with @Incoming, using the same 'generated-price' name: @Incoming("generated-price") @Outgoing("to-kafka") public double process(int priceInUsd) { return priceInUsd * CONVERSION_RATE; } The @Incoming annotation tells it to listen for messages on the generated-price channel. There is a match with the name of the @Outgoing annotation in the previous example so this method will receive all the prices generated by the generate() method. As the name is the same in the two annotations, this becomes an in-memory stream. The method is also annotated with an @Outgoing annotation so once its conversion has been done, the result is sent to the 'to-kafka' channel. To map this channel to a Kafka stream, we need some configuration, using MicroProfile Config in a microprofile-config.properties that is part of the deployment: # Selects the Kafka connector for the 'to-kafka' outgoing stream mp.messaging.outgoing.to-kafka.connector=smallrye-kafka # Maps the outgoing stream to the 'prices' Kafka topic mp.messaging.outgoing.to-kafka.topic=prices # Adds a serializer to convert the data mp.messaging.outgoing.to-kafka.value.serializer=org.apache.kafka.common.serialization.IntegerSerializer Next we create a Publisher that reads this data from Kafka. @Inject @Channel("from-kafka") Publisher<Double> prices; This @Channel annotation on a Publisher is conceptually the same as if we had annotated a method with @Incoming("from-kafka") but allows us to do some cool tricks which we will see soon. This is not part of the current Reactive Messaging 1.0 specifaction, but will be part of 1.1. For now it is a SmallRye extension to the specification. In our microprofile-config.properties that is part of the deployment we configure this channel mapping to the same Kafka stream: # Selects the Kafka connector for the 'from-kafka' incoming stream mp.messaging.incoming.from-kafka.connector=smallrye-kafka # Maps the incoming stream to the 'prices' Kafka topic mp.messaging.incoming.from-kafka.topic=prices # Adds a deserializer to convert the data mp.messaging.incoming.from-kafka.value.deserializer=org.apache.kafka.common.serialization.IntegerDeserializer To summarise where we are at so far all the messages which got generated in our generate() methods got sent, via an in memory channel, to our process() method. The process() method did some conversion before sending it to a Kafka topic called 'prices'. Then we listen to that Kafka topic, and are able to publish them from our prices Publisher instance. Now that we have the converted stream in a Publisher instance we can access it from the non-reactive world, e.g. in a REST endpoint: @GET @Path("/prices") @Produces(MediaType.SERVER_SENT_EVENTS) // denotes that server side events (SSE) will be produced @SseElementType(MediaType.TEXT_PLAIN) // denotes that the contained data, within this SSE, is just regular text/plain data public Publisher<Double> readThreePrices() { // get the next three prices from the price stream return ReactiveStreams.fromPublisher(prices) .limit(3) .buildRs(); } To keep things simple, we will consider the above simple version of this method first. As we got the stream into a Publisher by using the @Channel annotation, we have a bridge into the 'user world' from the 'reactive world'. Otherwise we would just have a chain of @Outgoing and @Incoming annotated methods (which of course may be also useful in some cases!). First, we use the MicroProfile Reactive Streams Operators method ReactiveStreams.fromPublisher() to wrap the publisher. We then specify limit(3) - this has the effect that once someone calls this method the stream will terminate after receiving three prices. We call buildRs() to return a new Publisher for those three items. As the messages are every five seconds the readPrices() method will return while our reactive stream is still receiving and re-emitting the three messages. Next, let’s see how MicroProfile Context Propagation is useful. We will modify the above method, so that each of the three prices get stored to a database @PersistenceContext(unitName = "quickstart") EntityManager em; @Transactional // This method is transactional @GET @Path("/prices") @Produces(MediaType.SERVER_SENT_EVENTS) // denotes that server side events (SSE) will be produced @SseElementType(MediaType.TEXT_PLAIN) // denotes that the contained data, within this SSE, is just regular text/plain data public Publisher<Double> readThreePrices() { // get the next three prices from the price stream return ReactiveStreams.fromPublisher(prices) .limit(3) .map(price -> { // Context propagation makes this block inherit the transaction of the caller System.out.println("Storing price: " + price); // store each price before we send them Price priceEntity = new Price(); priceEntity.setValue(price); // here we are all in the same transaction // thanks to context propagation em.persist(priceEntity); return price; }) .buildRs(); } First of all we have made the method transactional, so a transaction will be started when entering the method. We then read three prices exactly the same as before, but this time we have an extra call to map(). Inside the map() block, we save each price to a database. Thanks to Context Propagation (which is integrated with Reactive Streams Operators) this happens within the transaction of the readThreePrices() method, although that method will have completed by the time the prices come through. Feedback We’re keen to hear your feedback! Please raise any issues found at https://github.com/wildfly-extras/wildfly-mp-reactive-feature-pack/issues. ### [A bootable JAR for WildFly 20](/news/2020/06/18/A-bootable-JAR-for-WildFly-20/) Introduction Now that WildFly supports Eclipse Microprofile this seems the appropriate time to introduce a way to package a WildFly application as a bootable JAR (also known as a "fat JAR"). Bootable JAR packaging is well suited for microservices to be run on cloud and bare metal. A bootable JAR allows us to package both the container and the application in a single JAR file and execute it with a simple command such as java -jar myapp-wildfly.jar. Packaging the server and your app in a JAR makes sense when you can control the set of server features you want to see present. Packaging a complete WildFly server (250+MB) for a simple microservice would defeat the purpose of the bootable JAR. Galleon technology server trimming capabilities have made a bootable JAR for WildFly a valid solution. WildFly defines a set of Galleon layers (with new Galleon layers added nearly for each major WildFly releases) that you can combine in order to tailor the server to your application needs. The tooling to build a bootable JAR relies on WildFly Galleon layers to provision the tailored server that is bundled in the JAR file. WildFly JAR Maven plugin The project hosted in wildfly-extras/wildfly-jar-maven-plugin defines a new Maven plugin allowing you to build a bootable JAR for WildFly (starting with version 20.0.0.Final). Although currently incubating, the project has gained enough maturity that you can start using it. Obviously, things could still evolve in the near future. It is worth noting that the project has already entered the WildFly feature process in order to become a fully qualified WildFly tooling. The new feature proposal can be found here. A WildFly bootable JAR contains both the server and your packaged application (a JAR, an EAR or a WAR). Once the application has been built and packaged as a bootable JAR, you can start the application using the following command: java -jar target/myapp-wildfly.jar A WildFly bootable JAR behaves in a way that is similar to a WildFly server unzipped on the file system: It supports the main standalone server startup arguments. It can be administered/monitored using the WildFly CLI. Getting started In order to help you start using the org.wildfly.plugins:wildfly-jar-maven-plugin Maven plugin, we have defined a set of examples that cover common use-cases. To retrieve the examples: git clone -b 2.0.0.Alpha4 http://github.com/wildfly-extras/wildfly-jar-maven-plugin cd wildfly-jar-maven-plugin/examples A good example to start with is the jaxrs example. To build and run the jaxrs example: cd jaxrs mvn package java -jar target/jaxrs-wildfly.jar The plugin documentation (currently an index.html file to download) can be found here. It contains a comprehensive list of the options you can use to fine tune the Maven build and create a bootable JAR. Be sure to read the examples/README that contains required information to run the examples in an OpenShift context. Main features The main features are covered in detail in the plugin documentation. Here is a summary of what the Maven plugin and created bootable JAR offer. Maven Plugin Supports WildFly Galleon layers to create a use-case tailored bootable JAR. Supports WildFly CLI script execution to fine tune your server during build (configure security, logging, …​). Supports the ability to package extra content inside the bootable JAR (eg: a keystore) Supports the creation of a "hollow" JAR (a JAR containing only the WildFly server, the application to deploy being provided at runtime). Offers a "dev" mode to speed-up development by skipping the bootable JAR re-build. Offers goals to start and shutdown a bootable JAR. Created bootable JAR Supports the main WildFly standalone server startup arguments. Can be built and deployed in OpenShift using the registry.access.redhat.com/openjdk/openjdk-11-rhel7 java s2i image (see mp-config and postgresql examples). Can be deployed inside a JIB container (see jib example). To conclude We hope that you will have an interest in using this new way to build and run your WildFly applications. Feel free to give us feedback, this will help improve tooling and bootable JAR execution. Thank-you. ### [WildFly 20 S2I images have been released on quay.io](/news/2020/06/12/WildFly-20-S2I-images-have-been-released-on-quay-io/) WildFly 20 S2I Docker images The WildFly S2I (Source-to-Image) builder and runtime Docker images for WildFly 20 have been released on quay.io/wildfly. Changes since the last release: Upgraded Keycloak client adapters to version 10.0.2. Reduced the size of the image generated during s2i chained build template (image named <app>-build-artifacts). For a complete documentation on how to use these images using S2I, OpenShift and Docker, refer to the WildFly S2I README. Adding the imagestreams and template to OpenShift At some point the new images will be made available from the OpenShift catalog and image repository. But you can already use these images by adding them yourselves to your OpenShift cluster. WildFly S2I builder image stream: oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-20.0/imagestreams/wildfly-centos7.json WildFly runtime image stream: oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-20.0/imagestreams/wildfly-runtime-centos7.json Chained build template: oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-20.0/templates/wildfly-s2i-chained-build-template.yml NB: If you import the image streams into your project, be sure to set the ImageStreams Namespace (IMAGE_STREAM_NAMESPACE argument) to your project namespace in the template. openshift being the default namespace. Eclipse Microprofile OpenAPI example Since version 19, WildFly implements a support for the Microprofile OpenAPI specification. We are here deploying the WildFly microprofile-openapi quickstart inside OpenShift. In order to tailor WildFly to our use-case (jaxrs service) we are using WildFly Galleon Layers during s2i build to construct a WildFly server composed of jaxrs and Microprofile OpenAPI (plus their required dependencies). Build and run the application The quickstart is a jaxrs service that exposes a set of operations to manage a store inventory. We are retrieving the service interface (HTTP operations, URL paths and data types) through the openapi endpoint that WildFly exposes in the root context (eg: http://127.0.0.1:8080/openapi). Build the application image: oc new-app wildfly-s2i-chained-build-template -p APPLICATION_NAME=openapi-app \ -p GIT_REPO=https://github.com/wildfly/quickstart \ -p GIT_CONTEXT_DIR=microprofile-openapi \ -p GIT_BRANCH=20.0.0.Final \ -p GALLEON_PROVISION_LAYERS=jaxrs,microprofile-openapi \ -p IMAGE_STREAM_NAMESPACE=myproject \ --build-env=MAVEN_ARGS_APPEND="-Dcom.redhat.xpaas.repo.jbossorg" Create an application from the application image: oc new-app myproject/openapi-app Expose the service: oc expose svc/openapi-app The OpenAPI service definition is exposed at the following well known location: <application route>/openapi From the service definition we can retrieve the HTTP operations and URL paths that the service supports. For example, the HTTP GET sent to <application route>/fruit returns a JSON array containing the fruits present in the inventory. Enjoy the Apples and Pineapples! ### [WildFly 20 is released!](/news/2020/06/08/WildFly-20-is-released/) I’m pleased to announce that the WildFly 20 Final zip is now available for download. After the big push on Eclipse MicroProfile 3.3 for WildFly 19, the focus for WildFly 20 was more on bug fixing and component updates. Between WildFly Core and full WildFly we resolved well over 100 bugs and did over 90 component upgrades, most of which also brought bug fixes. These are challenging times for all of us, with a lot of disruption in our lives, and I’m very proud of how much the many people contributing to WildFly have gotten done over these last couple of months. But, of course, it wasn’t all bug fixing! So, what else is new? Enhancements Security As always, the folks working on security have been busy: Instead of needing to first add a credential to a credential store in order to reference it from a credential-reference, WildFly 20 adds the ability to automatically add a credential to a previously defined credential store. Check out Farah Juma’s blog post for an introduction to this new feature. The Elytron subsystem configuration was enhanced to allow the definition of a regex-based security role mapping mechanism. With this functionality it is possible for users to easily translate a list of roles (eg. *-admin, *-user) to simpler roles (eg. admin, user) without having to implement their own custom components. It is now possible to make use of the IP address of a remote client when making authorization decisions. EJB The standard way to configure stateful bean session timeout for each ejb is via a @StatefulTimeout annotation, or a stateful-timeout setting in ejb-jar.xml. But if these are not provided WildFly now provides the ability to configure a default global stateful bean session timeout for all deployed stateful beans. This feature is useful for deploying and configuring multiple stateful beans consistently in a server instance or a cluster. In a clustered environment where EJB timers are persisting to a shared database, applications may not want to rely solely on a periodic refresh of their timers before performing certain tasks. With WildFly 20 it is now possible to programmatically refresh EJB timers that use a database-data-store for persistence. A large amount of information about the EJBs in a deployment is now available via the server management API. MicroProfile Integration RESTEasy (integrated in WildFly via the jaxrs subsystem) can now be configured using MicroProfile Config. In addition, the jaxrs subsystem now exposes servlet init parameters, filter init parameters and servlet context parameters to applications as MicroProfile Config config sources. An example CLI script has been added to the server’s docs/examples directory to help users migrate a standalone configuration to one more like the standalone-microprofile.xml configuration WildFly provides. Standards Support WildFly 20.0.0 is a Jakarta EE 8 compatible implementation, with both the Full Platform and the Web Profile. Evidence supporting our certification is available for the Full Platform and for the Web Profile. WildFly 20 is also a compatible implementation of Java EE 8. WildFly 20 is also a compliant implementation of the Eclipse MicroProfile 3.3 platform specification. JDK Support For the last couple of years we’ve worked to ensure our releases run well for most developer use cases on the most recent GA JDK version available on the WildFly final release date. Unfortunately, that came to an end with WildFly 19 and JDK 14. We haven’t had time to digest some of the package removals in JDK 14, particularly in the security area. However, I do believe WildFly runs well on JDK 13. By run well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what the latest JVM means for their applications to be able to look to WildFly as a useful development platform. We do see a couple of test failures with JDK 13 when using the deprecated Picketlink subsystem and WS Trust While we do want to run well on the most recent JDK, our recommendation is that you run WildFly on the most recent long-term support release, i.e. on JDK 11 for WildFly 20. We do considerably more testing of WildFly itself on the LTS JDKs, and we make no attempt to ensure the projects producing the various libraries we integrate are testing their libraries on anything other than JDK 8 or 11. WildFly 20 also is heavily tested and runs well on Java 8. We plan to continue to support Java 8 at least through WildFly 22, and probably beyond. Please note that WildFly runs on Java 11 and later in classpath mode. At this point it is uncertain when we’ll be able to say that a release of WildFly runs well on JDK 14 or later. We’ll have to see how well the work for that, both in WildFly itself and in the projects we integrate, aligns with our other goals. I don’t expect it to be a priority before WildFly 22. Documentation The WildFly 20 documentation is available at the docs.wildfly.org site. Just a reminder, starting with WildFly 19 we shifted the location of the auto-generated documentation of the appserver management API from the wildscribe.github.io site to a make it part of the general documentation for a release. The WildFly 20 management API documentation is in the wildscribe section of the WildFly 20 docs. Jira Release Notes The full list of issues resolved is available here. Issues resolved in the WildFly Core 12 releases included with WildFly 20 are available here. Enjoy! I hope this post finds you and your loved ones all safe and well. Please give WildFly 20 a spin and give us your feedback! ### [Plugging Apache Qpid into WildFly](/news/2020/05/11/Plugging-Apache-Qpid-into-WildFly/) Using JBoss Generic JMS Resource Adapter you can use a JMS compatible client to connect WildFly to any broker. This article will describe how to do this with Apache Qpid and thus use JMS over AMQP. Installing Apache Qpid You need to download and untar Apache Qpid Broker-J 8.0.0 from https://qpid.apache.org/download.html. You need to allow for anonymous access. Please use the initial-config.json configuration file. Note that we will start Apache Qpid HTTP server on 9080 to avoid port conflict with WildFly. cd $INSTALL_DIR tar xvzf qpid-broker-8.0.0-bin.tgz export QPID_WORK=$INSTALL_DIR/qpid-broker/8.0.0/work cd pid-broker/8.0.0/bin ./qpid-server -icp initial-config.json -prop "qpid.http_port=9080" Now you can connect to the Qpid web interface using guest/guest. You can see that we have created 2 queues: outQueue and testQueue. Configuring WildFly We are going to use the JBoss Generic JMS Resource Adapter. For this we need to deploy a module for the JMS provider to connect to Apache Qpid. Download the archive qpid-provider.tar.gz which provides the module to connect to Apache Qpid. Then we start WildFly with the full profile. cd $WILDFLY_HOME tar xvzf qpid-provider.tar.gz cd $WILDFLY_HOME/bin ./standalone.sh -c standalone-full.xml To configure WildFly you need to execute the following operations using the jboss-cli. You can use the following script qpid.cli. First we will enable the use of property replacement in our deployment for easier configurability: /subsystem=ee:write-attribute(name=spec-descriptor-property-replacement, value=true) /subsystem=ee:write-attribute(name=annotation-property-replacement, value=true) /subsystem=ee:write-attribute(name=jboss-descriptor-property-replacement, value=true) Then we need to configure the JNDI provider for Apache Qpid: /subsystem=naming/binding=java\:global\/qpid:add(binding-type=external-context, class=javax.naming.InitialContext, module=org.jboss.genericjms.provider, environment={java.naming.factory.initial=org.apache.qpid.jms.jndi.JmsInitialContextFactory, queue.testQueue=testQueue, queue.outQueue=outQueue, connectionfactory.QpidBroker="amqp://localhost:5672?jms.username=guest&jms.password=guest"}) /subsystem=naming/binding=java\:\/jms\/qpid\/queue\/testQueue:add(binding-type=lookup, value=java\:global\/qpid\/testQueue) /subsystem=naming/binding=java\:\/jms\/qpid\/queue\/outQueue:add(binding-type=lookup, lookup=java\:global\/qpid\/outQueue) Last we need to configure the resource adapter to connect to our Apache Qpid broker: /subsystem=resource-adapters/resource-adapter=apache-qpid:add(module=org.jboss.genericjms, transaction-support=NoTransaction) /subsystem=resource-adapters/resource-adapter=apache-qpid/connection-definitions=QPIDCF:add(jndi-name=java\:\/jms\/qpid\/cf\/QpidBroker, class-name=org.jboss.resource.adapter.jms.JmsManagedConnectionFactory) /subsystem=resource-adapters/resource-adapter=apache-qpid/connection-definitions=QPIDCF/config-properties=JndiParameters:add(value="java.naming.factory.initial=org.apache.qpid.jms.jndi.JmsInitialContextFactory;connectionfactory.QpidBroker=amqp://localhost:5672?jms.username=guest&jms.password=guest") Running the example You can download the example code from this GitHub repository. The example consists of two parts : a client that will send a message to the testQueue to be processed by the Message Driven Bean which will send a message on the outQueue to be consumed by the client. This is the client code that sends a message: try (Connection connection = factory.createConnection("guest", "guest")) { connection.start(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer messageProducer = session.createProducer(queue); TextMessage message = session.createTextMessage("Hello world!"); messageProducer.send(message, DeliveryMode.NON_PERSISTENT, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); } The MDB code is in RemoteQueueMDB.java and will send back a message to be consumed by the client. @Override public void onMessage(Message message) { try (QueueConnection queueConnection = qcf.createQueueConnection("guest", "guest"); QueueSession queueSession = queueConnection.createQueueSession(true, Session.SESSION_TRANSACTED); QueueSender queueSender = queueSession.createSender(outQueue)) { if (message instanceof TextMessage) { txtMsg = (TextMessage) message; msgCnt++; queueSender.send(message); queueSession.commit(); } else { LOG.warnf("MDB[%d] Message of wrong type: %s", mdbID, message.getClass().getName()); } } Build using Apache Maven, then deploy the MDB by copying remote-mdb-ejb-1.0.0.jar into the deployments folder and run the client: cd client mvn "-Dexec.args=-classpath %classpath org.wildfly.jms.demo.qpid.client.HelloWorld" -Dexec.executable=/usr/lib/jvm/java-11/bin/java -Dexec.classpathScope=runtime org.codehaus.mojo:exec-maven-plugin:1.5.0:exec You should see the following message in the traces showing that all went nicely and that the client has received the message : Message received 419a7c4d-afe0-4dc2-9cf0-f17f531eb1ba:1:1:1-1 with text Hello world! ### [WildFly 19.1.0 is released!](/news/2020/05/04/WildFly-19-1-0-is-released/) WildFly 19.1.0 Final is now available for download. As we usually do between WildFly majors, we’ve done an update release to provide the WildFly community with important bug fixes and component upgrades that have become available. Typically these are micro releases, but this time we had one feature that we wanted to make available, so we changed the version to 19.1.0 and released a minor. The feature is related to handling of SameSite cookie attributes. Undertow has added support for SameSite="None" cookie attributes and support for a new SameSiteCookieHandler that sets SameSite attributes on cookies that match a cookie name pattern. With this handler, web developers can remain compliant with the latest changes in some browsers. To use the SameSiteCookieHandler, add a undertow-handlers.conf file to your WAR’s WEB-INF directory that includes a line like the following: samesite-cookie(mode=<mode>) Valid values for the mode parameter are Strict, Lax or None, ignoring case. See RFC6265bis for more information on the meaning of these modes. Further details, including other parameters you can use to configure the SameSiteCookieHandler, are discussed in the WFLY-13003 feature analysis document. If you want to add the SameSite handler to your application without changing the application code, look into using a deployment overlay to add the `WEB-INF/undertow-handlers.conf' file to existing deployments. The full list of issues resolved in WildFly 19.1.0 is available here. Issues resolved in the WildFly Core 11.1.0 release included with WildFly 19.1.0 are available here. Note for Galleon Users If you provisioned a WildFly server associated with the 19.0 channel, a simple Galleon update won’t update your installation to 19.1.0, as 19.1.0 is not part of that channel’s version range. There’s a new 19.1 channel that you’ll need to specify. For example, if you’d originally provisioned your server like this: $ galleon.sh install wildfly:19.0 --dir=my-wildfly --layers=jaxrs-server Feature-packs resolved. Feature-packs resolved. Packages installed. JBoss modules installed. Configurations generated. Feature-pack installed. ======= ============ ============== Product Build Update Channel ======= ============ ============== wildfly 19.0.0.Final 19.0 Then a simple update will do nothing: $ galleon.sh update --dir=my-wildfly Feature-packs resolved. Up to date. No available updates nor patches. To get the update change the channel to 19.1: $ galleon.sh update --feature-packs=wildfly:19.1#19.1.0.Final --dir=my-wildfly Feature-packs resolved. Some updates and/or patches are available. ======= ============= ============ ============== Product Current Build Update Update Channel ======= ============= ============ ============== wildfly 19.0.0.Final 19.1.0.Final 19.1 Proceed with latest updates [y/n]? Feature-packs resolved. Packages installed. JBoss modules installed. Configurations generated. $ galleon.sh get-info --dir=my-wildfly ======= ============ ============== Product Build Update Channel ======= ============ ============== wildfly 19.1.0.Final 19.1 I hope you enjoy WildFly 19.1. If you have any questions or feedback please find us at the WildFly forums. ### [Configuring WildFly S2I image by using CLI Management Operations](/news/2020/04/13/Configuring-WildFly-S2I-image-by-using-CLI-Management-Operations/) Introduction The standard and recommended way to configure the WildFly cloud images is by using environment variables. However, you could find it useful for your use case to configure the server by using a custom CLI management operations script. The following post describes how you can apply management operations to configure the WildFly server image. We will show you how you can execute CLI scripts at the Source-to-Image (S2I) phase and how to use the extensions mechanism provided by the WildFly cloud image to execute CLI management operations at runtime. This practical guide uses Red Hat CodeReady Containers as a local OpenShift cluster. It assumes you have basic knowledge of OpenShift and you know how to configure the WildFly S2I image by using environment variables. Executing a CLI management operations script at the Source-to-Image (S2I) phase Source-to-Image is the tool used internally by OpenShift to build container images from application source code. When we are creating an OpenShift new application using the WildFly image stream, S2I takes our application source code from a Git repository, provisions the WildFly server by using Galleon layers and builds the final image that runs the assembled application. In this example we are going to assemble this JAX-RS PostgreSQL demo application with the WildFly server provisioned by Galleon with the PostgreSQL drivers. Our demo application expects a data source available under the following java:jboss/datasources/PostgreSQLDS JNDI resource. This data source will be configured executing the following config-ds.cli CLI script: data-source add --jndi-name=java:/jboss/datasources/PostgreSQLDS \ --name=PostgreSQLPool \ --connection-url=jdbc:postgresql://database-server:5432/demodb \ --driver-name=postgresql \ --user-name=postgre \ --password=admin Note You can take a look at Configuring WildFly S2I image Datasources on OpenShift post where it was explained how to configure a Datasource in WildFly S2I image using Galleon layers and environment variables. S2i build time WildFly server customization hooks to execute a CLI script The WildFly server customization hooks offer a way to execute a CLI script when your application is being assembled at S2I phase. To do so you have to configure the S2I_IMAGE_SOURCE_MOUNTS variable pointing out to the directory that will contain your configuration scripts. This directory is checked during S2I phase, and if an install.sh file is located in the root of the mount point, then this file is executed. This hook gives you the opportunity to execute any task you need to tweak the final image created by the S2I tool. In our example, the install.sh file is located under s2i-config directory on our Git repository and we have S2I_IMAGE_SOURCE_MOUNTS variable configured with this directory location relative to our Git repository root. Note Notice you can set any S2I environment variables in the application source code. These variables are passed to the build, and the assemble script consumes them. All environment variables are also present in the output application image. These variables are defined in the .s2i/environment file inside the application sources. The format of this file is a simple key-value. The content of our install.sh script is the following: #!/usr/bin/env bash source /usr/local/s2i/install-common.sh injected_dir=$1 echo "Running on injected_dir=${injected_dir}" run_cli_script "${injected_dir}/config-ds.cli" echo "End CLI configuration" The script is a regular bash file. It starts with sourcing /usr/local/s2i/install-common.sh file. This file is included in the WildFly S2I image and contains the following functions that can be used by the install.sh script to install and configure JBoss Modules modules, drivers, generic deployments and execute CLI scripts: install_deployments: Copy the file passed as an argument to the server deployment directory. install_modules: Copy all the JBoss Modules modules in the directory passed as argument to the server modules directory. configure_drivers: Configure the desired drivers using the environment file passed as an argument. run_cli_script: Execute the CLI script passed as an argument. This install.sh script is invoked by the WildFly S2I image by passing it as an argument the location of the S2I_IMAGE_SOURCE_MOUNTS directory inside of the final image filesystem. You can use this argument to point out to other files or directories included in your application sources. Behind the scenes run_cli_script will start the WildFly embedded server which will execute the CLI script file you supply as an argument to this function. In our example, we have passed the CLI script which is available at "${injected_dir}/config-ds.cli" inside of the assembled image. If you need it, you can also create your CLI script on the fly when the install.sh is being executed so you can grab values for any build environment variables and use those values to tweak your script. For example suppose we need to pass the data source username and password via environment variables. You can get them in the install.sh script and use their values when you are creating the CLI script file: #!/usr/bin/env bash source /usr/local/s2i/install-common.sh injected_dir=$1 echo "Running on injected_dir=${injected_dir}" # This creates the CLI file on the fly so you can grab env build config variables and use them in your script echo "data-source add --jndi-name=java:/jboss/datasources/PostgreSQLDS \ --name=PostgreSQLPool \ --connection-url=jdbc:postgresql://database-server:5432/demodb \ --driver-name=postgresql \ --user-name=${DS_USERNAME} \ --password=${DS_PASSWORD}" > ${injected_dir}/my-script.cli run_cli_script "${injected_dir}/my-script.cli" echo "End CLI configuration" One advantage of configuring the server at S2I phase is you could gain speed when the server is being started at runtime. Your final image will be already configured by the OpenShift build config. However, currently you cannot use the standard WildFly S2I environment variables at build time, and tweak the server configuration at this stage could break possible configurations done later by the environment variables at runtime. Test the application The following commands shows you all the required steps to import the WildFly S2I image into CodeReady Containers, start the PostgreSQL server and assemble our demo application application that will execute the CLI script at S2I Phase. First of all, start CodeReady Containers, import the WildFly image, create the wildfly-demo project and start the PostgreSQL server: $ crc start ... INFO Starting OpenShift cluster ... [waiting 3m] INFO INFO To access the cluster, first set up your environment by following 'crc oc-env' instructions INFO Then you can access it by running 'oc login -u developer -p developer https://api.crc.testing:6443' INFO To login as an admin, run 'oc login -u kubeadmin -p kKdPx-pjmWe-b3kuu-jeZm3 https://api.crc.testing:6443' INFO INFO You can now run 'crc console' and use these credentials to access the OpenShift web console Started the OpenShift cluster WARN The cluster might report a degraded or error state. This is expected since several operators have been disabled to lower the resource usage. For more information, please consult the documentation $ oc login -u kubeadmin -p kKdPx-pjmWe-b3kuu-jeZm3 https://api.crc.testing:6443 Login successful. You have access to 53 projects, the list has been suppressed. You can list all projects with 'oc projects' Using project "default". $ oc import-image wildfly --confirm \--from quay.io/wildfly/wildfly-centos7 --insecure -n openshift imagestream.image.openshift.io/wildfly imported $ oc new-project wildfly-demo Now using project "wildfly-demo" on server "https://api.crc.testing:6443". $ oc new-app --name database-server \ --env POSTGRESQL_USER=postgre \ --env POSTGRESQL_PASSWORD=admin \ --env POSTGRESQL_DATABASE=demodb \ postgresql --> Found image 40d2ad9 (2 months old) in image stream "openshift/postgresql" under tag "10" for "postgresql" PostgreSQL 10 ------------- PostgreSQL is an advanced Object-Relational database management system (DBMS). The image contains the client and server programs that you'll need to create, run, maintain and access a PostgreSQL DBMS server. Tags: database, postgresql, postgresql10, rh-postgresql10 * This image will be deployed in deployment config "database-server" * Port 5432/tcp will be load balanced by service "database-server" * Other containers can access this service through the hostname "database-server" --> Creating resources ... imagestreamtag.image.openshift.io "database-server:10" created deploymentconfig.apps.openshift.io "database-server" created service "database-server" created --> Success Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose svc/database-server' Run 'oc status' to view your app. Now let us create the OpenShift application from our JAX-RS PostgreSql demo application. We use the cli-at-s2i branch: $ oc new-app --name wildfly-app \ https://github.com/yersan/jaxrs-postgresql-demo.git#cli-at-s2i \ --image-stream=wildfly \ --build-env GALLEON_PROVISION_LAYERS=jaxrs-server,postgresql-driver --> Found image bdf6490 (13 days old) in image stream "openshift/wildfly" under tag "latest" for "wildfly" WildFly 19.0.0.Final -------------------- Platform for building and running JEE applications on WildFly 19.0.0.Final Tags: builder, wildfly, wildfly19 * The source repository appears to match: jee * A source build using source code from https://github.com/yersan/jaxrs-postgresql-demo.git#cli-at-s2i will be created * The resulting image will be pushed to image stream tag "wildfly-app:latest" * Use 'oc start-build' to trigger a new build * This image will be deployed in deployment config "wildfly-app" * Ports 8080/tcp, 8778/tcp will be load balanced by service "wildfly-app" * Other containers can access this service through the hostname "wildfly-app" --> Creating resources ... imagestream.image.openshift.io "wildfly-app" created buildconfig.build.openshift.io "wildfly-app" created deploymentconfig.apps.openshift.io "wildfly-app" created service "wildfly-app" created --> Success Build scheduled, use 'oc logs -f bc/wildfly-app' to track its progress. Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose svc/wildfly-app' Run 'oc status' to view your app. Once we have created the wildfly-app application, we can inspect the logs of the pod in charge of building the image where the S2I Phase took in place: $ oc get pods NAME READY STATUS RESTARTS AGE database-server-1-deploy 0/1 Completed 0 4m36s database-server-1-mj9z4 1/1 Running 0 4m25s wildfly-app-1-build 0/1 Completed 0 3m38s wildfly-app-1-deploy 0/1 Completed 0 58s wildfly-app-1-dvnv6 1/1 Running 0 55s $ oc logs wildfly-app-1-build Caching blobs under "/var/cache/blobs". Getting image source signatures Copying blob sha256:ab5ef0e5819490abe86106fd9f4381123e37a03e80e650be39f7938d30ecb530 ... [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 16.275 s [INFO] Finished at: 2020-04-01T14:15:13Z [INFO] Final Memory: 17M/112M [INFO] ------------------------------------------------------------------------ [WARNING] The requested profile "openshift" could not be activated because it does not exist. INFO Copying deployments from target to /deployments... '/tmp/src/target/jaxrs-postgresql-demo.war' -> '/deployments/jaxrs-postgresql-demo.war' INFO Processing ImageSource mounts: s2i-config INFO Processing ImageSource from /tmp/src/s2i-config Running on injected_dir=/tmp/src/s2i-config INFO Configuring the server using embedded server INFO Duration: 4164 milliseconds End CLI configuration INFO Copying server to /s2i-output ... Successfully pushed image-registry.openshift-image-registry.svc:5000/wildfly-demo/wildfly-app@sha256:6057c3bbc0a9071b102b4d0404f9592edebb0ef7c4dfbca9b00e50a2a117adcd Push successful We can see in the log how the image source mount named s2i-config was processed, the value of the injected directory, in this case /tmp/src/s2i-config, which is a directory on the filesystem of the image being assembled, and a trace that tells us the server was configured by the embedded server. Let us now check test the application exposing the application to the outside world and fetching some information: $ oc expose svc/wildfly-app --name wildfly-app route.route.openshift.io/wildfly-app exposed $ curl http://$(oc get routes/wildfly-app --template={{.spec.host}})/jaxrs-postgresql-demo/api/tasks [{"id":1,"title":"This is the task-1"},{"id":2,"title":"This is the task-2"},{"id":3,"title":"This is the task-3"},{"id":4,"title":"This is the task-4"},{"id":5,"title":"This is the task-5"}] We can also open a remote connection and inspect the relevant data source configuration: The datasources subsystem configuration is the following: $ oc rsh wildfly-app-1-dvnv6 sh-4.2$ cat /opt/wildfly/standalone/configuration/standalone.xml <subsystem xmlns="urn:jboss:domain:datasources:5.0"> <datasources> <datasource jndi-name="java:/jboss/datasources/PostgreSQLDS" pool-name="PostgreSQLPool"> <connection-url>jdbc:postgresql://database-server:5432/demodb</connection-url> <driver>postgresql</driver> <security> <user-name>postgre</user-name> <password>admin</password> </security> </datasource> <drivers> <driver name="postgresql" module="org.postgresql.jdbc"> <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class> </driver> </drivers> </datasources> </subsystem> Now clean up the wildfly-app keeping the PostgreSQL server running, we will use it for the next example: $ oc delete all -l app=wildfly-app pod "wildfly-app-1-dvnv6" deleted replicationcontroller "wildfly-app-1" deleted service "wildfly-app" deleted deploymentconfig.apps.openshift.io "wildfly-app" deleted buildconfig.build.openshift.io "wildfly-app" deleted build.build.openshift.io "wildfly-app-1" deleted imagestream.image.openshift.io "wildfly-app" deleted Using the extension mechanism to configure the Server The extension mechanism allows the execution of arbitrary bash scripts before and after the server is configured by using environment variables. An interesting use case could be you want to tweak the server configuration after it has been configured by the environment variables, for example, there is a specific configuration that is not exposed directly by an environment variable. When the server is launched at runtime, the $JBOSS_HOME/extensions directory on the image filesystem is examined to look for any of these two files: $JBOSS_HOME/extensions/preconfigure.sh $JBOSS_HOME/extensions/postconfigure.sh If preconfigure.sh exists, then it is executed as an initial step before configuring the server by using the environment variables. Similarly, once the server is configured, if postconfigure.sh exists, it is executed. Those specific scripts give you the opportunity to prepare the image for the server configuration and to execute any task once the server is configured. In the following example we are going to use our postconfigure.sh to perform a datasource connection pool tuning configuring the following attributes: pool-use-strict-min: This attribute specifies whether WildFly allows the number of connections in the pool to fall below the specified minimum. idle-timeout-minutes: This attribute specifies the maximum time, in minutes, a connection may be idle before being closed. As idle connections are closed, the number of connections in the pool will shrink down to the specified minimum. Since we are going to supply our postconfigure.sh file in our application Git repository, we will use install.sh script to copy this file to the place expected by the WildFly S2I image so it gets executed when the server is launched. Note As alternative, in OpenShift you can also supply this file by using a config map mounted to $JBOSS_HOME/extensions. Let us examine the content of our files. First, the install.sh file: #!/usr/bin/env bash injected_dir=$1 echo "Copy ${injected_dir}/extensions/postconfigure.sh to ${JBOSS_HOME}/extensions/" mkdir -p "${JBOSS_HOME}/extensions/" cp "${injected_dir}/extensions/postconfigure.sh" "${JBOSS_HOME}/extensions/" Its content is pretty simple; it creates the ${JBOSS_HOME}/extensions/ if it does not exist yet, and copies our postconfigure.sh script. Now let us look at the content of our postconfigure.sh script: #!/usr/bin/env bash echo "Appending CLI operations to ${CLI_SCRIPT_FILE}" echo " /subsystem=datasources/data-source=database_server-DATABASE_SERVER:write-attribute(name=pool-use-strict-min, value=true) /subsystem=datasources/data-source=database_server-DATABASE_SERVER:write-attribute(name=idle-timeout-minutes, value=5) " >> "${CLI_SCRIPT_FILE}" We can append CLI operations to the final CLI script used by the WildFly image. You can access this file through the environment variable CLI_SCRIPT_FILE which is available in this script environment. The management operations executed in this script assume there is already a datasource named database_server-DATABASE_SERVER. This datasource will be created and configured by using the standard environment variables. Test the application Assuming your database server is already configured as in our previous example, let us now create our OpenShift application using this time the cli-extensions branch and by passing in the environment variables that configure our data source: $ oc new-app --name wildfly-app \ https://github.com/yersan/jaxrs-postgresql-demo.git#cli-extensions \ --image-stream=wildfly \ --env DATASOURCES=DATABASE_SERVER \ --env DATABASE_SERVER_JNDI="java:/jboss/datasources/PostgreSQLDS" \ --env DATABASE_SERVER_DATABASE="demodb" \ --env DATABASE_SERVER_USERNAME="postgre" \ --env DATABASE_SERVER_PASSWORD="admin" \ --env DATABASE_SERVER_DRIVER="postgresql" \ --env DATABASE_SERVER_MAX_POOL_SIZE=10 \ --env DATABASE_SERVER_MIN_POOL_SIZE=5 \ --env DATABASE_SERVER_NONXA=true \ --build-env GALLEON_PROVISION_LAYERS=jaxrs-server,postgresql-driver --> Found image bdf6490 (13 days old) in image stream "openshift/wildfly" under tag "latest" for "wildfly" WildFly 19.0.0.Final -------------------- Platform for building and running JEE applications on WildFly 19.0.0.Final Tags: builder, wildfly, wildfly19 * The source repository appears to match: jee * A source build using source code from https://github.com/yersan/jaxrs-postgresql-demo.git#cli-extensions will be created * The resulting image will be pushed to image stream tag "wildfly-app:latest" * Use 'oc start-build' to trigger a new build * This image will be deployed in deployment config "wildfly-app" * Ports 8080/tcp, 8778/tcp will be load balanced by service "wildfly-app" * Other containers can access this service through the hostname "wildfly-app" --> Creating resources ... imagestream.image.openshift.io "wildfly-app" created buildconfig.build.openshift.io "wildfly-app" created deploymentconfig.apps.openshift.io "wildfly-app" created service "wildfly-app" created --> Success Build scheduled, use 'oc logs -f bc/wildfly-app' to track its progress. Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose svc/wildfly-app' Run 'oc status' to view your app. Let us explain a bit the uses of these environment variables. You could have noticed we have not defined how our application will connect to the database server since there is no environment variable defining the database server host name / IP or port The DATASOURCES declaration defines the prefix for our data source, in this case the prefix is DATABASE_SERVER. By using this definition, the WildFly S2I configuration scripts will pick up the database host name and port from the following variables: <PREFIX>_SERVICE_HOST <PREFIX>_SERVICE_PORT We have created a database server with the name database-server, which in turns created a service with the same name. Because of the existence of this service, when our application pod is started, OpenShift will initialize the following variables: DATABASE_SERVER_SERVICE_HOST DATABASE_SERVER_SERVICE_PORT The WildFly S2I scripts will take the database host IP and port from those variables and will create the datasource using their values. You can verify the presence and the values of these variables executing a remote command: $ oc get pods NAME READY STATUS RESTARTS AGE database-server-1-deploy 0/1 Completed 0 46m database-server-1-mj9z4 1/1 Running 0 46m wildfly-app-1-build 0/1 Completed 0 23m wildfly-app-1-deploy 0/1 Completed 0 20m wildfly-app-1-sww2q 1/1 Running 0 20m $ oc exec wildfly-app-1-sww2q -- env | grep "DATABASE_SERVER_SERVICE_PORT\|DATABASE_SERVER_SERVICE_HOST" DATABASE_SERVER_SERVICE_PORT=5432 DATABASE_SERVER_SERVICE_HOST=172.30.142.21 We can check the data source subsystem configuration to verify it was configured as expected: $ oc exec wildfly-app-1-sww2q -- cat /opt/wildfly/standalone/configuration/standalone.xml <subsystem xmlns="urn:jboss:domain:datasources:5.0"> <datasources> <datasource jta="true" jndi-name="java:/jboss/datasources/PostgreSQLDS" pool-name="database_server-DATABASE_SERVER" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}"> <connection-url>jdbc:postgresql://172.30.142.21:5432/demodb</connection-url> <driver>postgresql</driver> <pool> <min-pool-size>5</min-pool-size> <max-pool-size>10</max-pool-size> <use-strict-min>true</use-strict-min> </pool> <security> <user-name>postgre</user-name> <password>admin</password> </security> <validation> <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker"/> <validate-on-match>true</validate-on-match> <background-validation>false</background-validation> <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter"/> </validation> <timeout> <idle-timeout-minutes>5</idle-timeout-minutes> </timeout> </datasource> <drivers> <driver name="postgresql" module="org.postgresql.jdbc"> <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class> </driver> </drivers> </datasources> </subsystem> Finally, delete the project created to clean up all the resources: $ oc delete project wildfly-demo ### [WildFly 19 S2I images have been released on quay.io](/news/2020/03/20/WildFly-19-S2I-images-have-been-released-on-quay-io/) WildFly 19 S2I Docker images The WildFly S2I (Source-to-Image) builder and runtime Docker images for WildFly 19 have been released on quay.io/wildfly. Changes since the last release: Optimized startup. The server starts much faster, as the CLI script applied to the server configuration is now executed during server boot. Support for clustering. JGroups is now part of the default server configuration. The WildFly 19 Galleon decorator layer web-clustering (support for Infinispan-based web session clustering) is fully usable in the openshift context. This blog post highlights the new clustering features. The default standalone.xml configuration file includes the Microprofile JWT (JSON Web Token) subsystem. WildFly 19 defines three new Galleon layers for Microprofile 3.3 (microprofile-fault-tolerance, microprofile-jwt and microprofile-openapi) which can be referenced from the GALLEON_PROVISION_LAYERS env variable if you want Galleon to include those subsystems in a trimmed-down server it provisions. For a complete documentation on how to use these images using S2I, OpenShift and Docker, refer to the WildFly S2I README. Adding the imagestreams and template to OpenShift At some point the new images will be made available from the OpenShift catalog and image repository. But you can already use these images by adding them yourselves to your OpenShift cluster. WildFly S2I builder image stream: oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-19.0/imagestreams/wildfly-centos7.json WildFly runtime image stream: oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-19.0/imagestreams/wildfly-runtime-centos7.json Chained build template: oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-19.0/templates/wildfly-s2i-chained-build-template.yml NB: If you import the image streams into your project, be sure to set the ImageStreams Namespace (IMAGE_STREAM_NAMESPACE argument) to your project namespace in the template. openshift being the default namespace. Clustering examples Configure Openshift Allow to view all pods in the project: oc policy add-role-to-user view system:serviceaccount:$(oc project -q):default Be sure to kill any WildFly application running in the myproject namespace. Any running application would join the cluster. Web session sharing using the web-clustering galleon layer Build and run the application We are provisioning a web server with support for web session sharing. Build the application image: oc new-app wildfly-s2i-chained-build-template -p APPLICATION_NAME=web-clustering \ -p GIT_REPO=https://github.com/wildfly/wildfly-s2i \ -p GIT_CONTEXT_DIR=examples/web-clustering \ -p GALLEON_PROVISION_LAYERS=web-server,web-clustering \ -p IMAGE_STREAM_NAMESPACE=myproject Create an application from the application image: oc new-app myproject/web-clustering -e KUBERNETES_NAMESPACE=myproject -e JGROUPS_CLUSTER_PASSWORD=mypassword NB: The KUBERNETES_NAMESPACE is required to see other pods in the project, otherwise the server attempts to retrieve pods from the 'default' namespace which is not the one our project is using. JGROUPS_CLUSTER_PASSWORD is used to authenticate servers in the cluster. Expose the service: oc expose svc/web-clustering Access the application route, note the user created time and session ID. Scale the application to 2 pods: oc scale --replicas=2 dc web-clustering List pods: oc get pods Kill the oldest POD (which answered the first application request): oc delete pod web-clustering-1-r4cx8 -n myproject Access the application again. You will notice that the displayed values are the same, meaning the web session has been shared between the 2 pods. EJB singleton Another aspect of the WildFly clustering features is the support for high availabilty EJB singletons. We are here running the ha-singleton-deployment WildFly quickstart. In this example we are using the default server present in the wildfly S2I builder image; we are not provisioning a server trimmed-down with Galleon. We don’t have (yet) layers for EJB features. Build the application image: oc new-app wildfly-s2i-chained-build-template -p APPLICATION_NAME=singleton \ -p GIT_REPO=https://github.com/wildfly/quickstart/ \ -p GIT_BRANCH=19.0.0.Final \ -p GIT_CONTEXT_DIR=ha-singleton-deployment \ -p IMAGE_STREAM_NAMESPACE=myproject \ --build-env=MAVEN_ARGS_APPEND=-Dcom.redhat.xpaas.repo.jbossorg Create an application from the application image: oc new-app myproject/singleton -e KUBERNETES_NAMESPACE=myproject -e JGROUPS_CLUSTER_PASSWORD=mypassword Scale the application to 2 pods: oc scale --replicas=2 dc singleton Check the server logs: oc logs -f dc/singleton One pod is elected for the timer service. List pods: oc get pods Kill the oldest POD (elected one): oc delete pod singleton-1-r4cx8 -n myproject The timer service is started in the remaining pod. ### [Eclipse MicroProfile OpenTracing comes to WildFly](/news/2020/03/19/Eclipse-MicroProfile-OpenTracing-comes-to-WildFly/) Until WildFly 19 you could use Eclipse MicroProfile OpenTracing (MPOT) to trace your application using environment variables relying on the SmallRye OpenTracing implementation. With WildFly 19 you can now configure several Jaeger Tracers to be used in your applications. Installing Jaeger Let’s start a jaeger instance using docker : docker run -d --name jaeger \ -p 6831:6831/udp \ -p 5778:5778 \ -p 14268:14268 \ -p 16686:16686 \ jaegertracing/all-in-one:1.16 Now, you can navigate to http://localhost:16686 to access the Jaeger UI. Configuring the OpenTracing subsystem You can use either UDP or TCP to send your log spans to Jaeger. Note that those configurations are exclusive, so if you configure a TCP endpoint then Jaeger won’t use the UDP configuration. Using UDP First we use the WildFly CLI tool to define an outbound socket binding towards the Jaeger tracer. [standalone@localhost:9990 /] /socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=jaeger:add(host=localhost, port=6831) {"outcome" => "success"} Now we can define our MPOT tracer configuration: [standalone@localhost:9990 /] /subsystem=microprofile-opentracing-smallrye/jaeger-tracer=jaeger-demo:add(sampler-type=const, sampler-param=1, reporter-log-spans=true, sender-binding=jaeger) {"outcome" => "success"} Using TCP If you want to use TCP instead of UDP you need to configure the sender-endpoint and set its value to http://localhost:14268/api/traces. [standalone@localhost:9990 /] /subsystem=microprofile-opentracing-smallrye/jaeger-tracer=jaeger-demo:write-attribute(name="sender-endpoint", value="http://localhost:14268/api/traces") { "outcome" => "success", "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } } [standalone@localhost:9990 /] reload Setting the default tracer Let’s define this new tracer as the default tracer to be used by WildFly: [standalone@localhost:9990 /] /subsystem=microprofile-opentracing-smallrye:write-attribute(name=default-tracer, value=jaeger-demo) { "outcome" => "success", "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } } [standalone@localhost:9990 /] reload Note Instead of relying on the default tracer attribute, you can use the web.xml deployment descriptor and set the init-parameter smallrye.opentracing.tracer.configuration to the name of the tracer to use. Deploying a demo application We provide a sample application at https://github.com/ehsavoie/opentracing-demo. This application is a simple JAXRS endpoint producing XML or JSON and failing randomly. git clone git@github.com:ehsavoie/opentracing-demo.git cd opentracing-demo mvn clean install cp target/opentracing-demo.war $WILDFLY_HOME/standalone/deployments $WILDFLY_HOME/bin/standalone.sh Now, you can navigate to http://localhost:8080/opentracing-demo to access the deployed application. Generate a few traces by clicking on the links several times. Note that in order to demonstrate error traces the application deliberately throws exceptions randomly, so don’t be surprised if some requests fail. Now open the Jaeger UI and search for traces related to the service opentracing-demo.war, you should see the result of your previous actions. References WildFly Microprofile OpenTracing configuration: Admin Guide WildScribe: https://docs.wildfly.org/19/wildscribe/subsystem/microprofile-opentracing-smallrye/jaeger-tracer/index.html Eclipse MicroProfile OpenTracing: https://github.com/eclipse/microprofile-opentracing Smallrye Opentracing: https://github.com/smallrye/smallrye-opentracing Jaeger: https://www.jaegertracing.io/ ### [WildFly 19 is released!](/news/2020/03/18/WildFly-19-is-released/) I’m pleased to announce that the WildFly 19 Final zip is now available for download. Work on WildFly 19 has been a long and exciting journey, with tremendous help from contributors in the community, a lot of support from the communities behind the components we integrate (particularly the Smallrye folks) and crucial backing from many of my colleagues at Red Hat, particularly all the QE folks who helped make sure all the new goodies really taste good! So, what are the new goodies? MicroProfile 3.3 As I’ve discussed in a couple blog posts about the WildFly 19 Beta releases, WildFly 19 supports the Eclipse MicroProfile 3.3 platform specifications. Achieving this has been the main focus of the release. WildFly now provides support for the following MicroProfile specifications: Specification Version in WildFly 19 MicroProfile Config 1.4 MicroProfile Fault Tolerance 2.1 MicroProfile Health Check 2.2 MicroProfile JWT Authentication 1.1 MicroProfile Metrics 2.3 MicroProfile OpenAPI 1.1 MicroProfile OpenTracing 1.3 MicroProfile Rest Client 1.4 We also provide all of the MicroProfile specs that are also part of EE 8. WildFly 19 includes three new subsystems to provide the MicroProfile specs that weren’t in WildFly 18: microprofile-fault-tolerance-smallrye, microprofile-jwt-smallrye and microprofile-openapi-smallrye. We’ve also added two new standard configuration files to help guide users toward server configurations well suited for microservice use cases: standalone-microprofile.xml Provides our MicroProfile platform implementations combined with JAX-RS and technologies JAX-RS applications commonly use to integrate with external services. standalone-microprofile-ha.xml Similar to standalone-microprofile.xml but with support for high availability web sessions and distributed Hibernate second-level caching. Our other standard config files (e.g. standalone.xml) also include the subsystems needed to support Config, JWT, Health, Metrics, OpenTracing and Rest Client. The inclusion of JWT is new with WildFly 19. The WildFly 19 quickstarts also include a number of new quickstarts for MicroProfile. My thanks to everyone who helped with those, particularly Martin Stefanko who did a ton of work. And finally, we’ve introduced a new wildfly-microprofile maven bom to help Micrapplication developers align with the API artifacts used by WildFly. The maven GAV for this new bom is org.wildfly.bom:wildfly-microprofile:19.0.0.Final. Thanks to Eduardo Martins for this! Other Enhancements WildFly 19 brings a number of other enhancements beyond MicroProfile: Elytron configuration on the client side of a Webservices deployment is now supported, so a WS client can support the Elytron security framework available within the application server. A new constant-headers attribute has been added to the HTTP management interface resource definition. Administrators can make use of this attribute to specify additional HTTP headers to be returned in responses to requests made against the HTTP management interface. It is now possible to use TLS 1.3 with WildFly when running against JDK 11 or higher. However, if JDK 11 is in use and if there is a very large number of TLS 1.3 requests being made, it is possible that a drop in performance (throughput and response time) will occur compared to TLS 1.2. Upgrading to newer JDK versions should improve performance. For this reason, the use of TLS 1.3 is currently disabled by default. TLS 1.3 can be enabled by configuring the new cipher-suite-names attribute in the SSL Context resource definition in the Elytron subsystem. It is recommended to test for performance degradation prior to enabling TLS 1.3 in a production environment. RESTEasy context parameters and providers can now be configured via attributes in the jaxrs subsystem configuration. Expression resolution in EE security manager deployment descriptors (permissions.xml and jboss-permissions.xml) is now supported. You can now use the familiar ${foo:true} syntax in these deployment descriptors to allow customization of settings at runtime. A JBoss Modules module can be made globally available to all deployments by simply copying one or more library artifacts or other resources to a directory and then configuring the WildFly ee subsystem with the location of that directory. Executor / thread pool statistics are now available for the EE Concurrency resources. Jakarta EE and Java EE WildFly 19.0.0 is a Jakarta EE 8 compatible implementation, with both the Full Platform and the Web Profile. Evidence supporting our certification is available for the Full Platform and for the Web Profile. WildFly 19 is also a certified compatible implementation of Java EE 8. JDK Support For the last couple of years we’ve worked to ensure our releases run well for most developer use cases on the most recent GA JDK version available on the WildFly final release date. Unfortunately, that has come to an end with WildFly 19 and the just-released JDK 14. We haven’t had time to digest some of the package removals in JDK 14, particularly in the security area. While we do like to run well on more recent JDKs, our recommendation is that you run WildFly on the most recent long-term support release, i.e. on JDK 11 for WildFly 19. We do considerably more testing of WildFly itself on the LTS JDKs, and we make no attempt to ensure the projects producing the various libraries we integrate are testing their libraries on anything other than JDK 8 or 11. WildFly 19 also is heavily tested and runs well on Java 8. We plan to continue to support Java 8 at least through WildFly 21, and probably beyond. Please note that WildFly runs on Java 11 and later in classpath mode. At this point it is uncertain when we’ll be able to say that a release of WildFly runs well on JDK 14 or later. We’ll have to see how well the work for that, both in WildFly itself and in the projects we integrate, aligns with our other goals. I don’t expect it to be a priority before WildFly 22. Management API Documentation Since the JBoss AS 7.1.1 release we’ve published auto-generated documentation of the appserver management API at the wildscribe.github.io site. Starting with WildFly 19 we’ve stopped publishing there and instead we will be including the management API documentation as part of the overall documentation for the release. The content is equivalent; we’ve just changed where it is located. Jira Release Notes The full list of issues resolved is available here. Issues resolved in the WildFly Core 11 releases included with WildFly 19 are available here. User Forum Move Finally, a quick reminder that we have moved the WildFly user forum from the developer.jboss.org site to google groups. That’s a great place to provide feedback on or ask questions about WildFly 19. Enjoy, but more importantly, stay safe and stay well! ### [WildFly 19.0.0.Beta3 with Eclipse MicroProfile 3.3 Support](/news/2020/01/17/WildFly-19-0-0-Beta3-with-Eclipse-MicroProfile-3-3-Support/) I’m pleased to announce that with today’s WildFly 19.0.0.Beta3 release WildFly supports the Eclipse MicroProfile 3.3 platform specifications! The WildFly 19 Beta3 zip is now available for download. With the January release of WildFly 19 Beta1 we added support for MicroProfile 3.2. Since the MicroProfile 3.3 release was coming in February and the delta from 3.2 wasn’t too extreme we decided to go ahead and delay WildFly 19 a bit and go for MicroProfile 3.3 support. Thanks to some heroic efforts from the WildFly developers and testers and a huge assist from the Smallrye community we’ve been able to get this done. Thank you all, and congratulations on this achievement! WildFly now provides support for the following MicroProfile specifications: Specification Version in WildFly 19 MicroProfile Config 1.4 MicroProfile Fault Tolerance 2.1 MicroProfile Health Check 2.2 MicroProfile JWT Authentication 1.1 MicroProfile Metrics 2.3 MicroProfile OpenAPI 1.1 MicroProfile OpenTracing 1.3 MicroProfile Rest Client 1.4 We also provide all of the MicroProfile specs that are also part of EE 8. As I noted in my post about the 19.0.0.Beta1 release, WildFly 19 includes three new subsystems to provide the MicroProfile specs that weren’t in WildFly 18: microprofile-fault-tolerance-smallrye, microprofile-jwt-smallrye and microprofile-openapi-smallrye. We’ve also added two new standard configuration files to help guide users toward server configurations well suited for microservice use cases: standalone-microprofile.xml Provides our MicroProfile platform implementations combined with JAX-RS and technologies JAX-RS applications commonly use to integrate with external services. standalone-microprofile-ha.xml Similar to standalone-microprofile.xml but with support for high availability web sessions and distributed Hibernate second-level caching. Our other standard config files (e.g. standalone.xml) also include the subsystems needed to support Config, JWT, Health, Metrics, OpenTracing and Rest Client. The inclusion of JWT is new with the Beta 3 release. On to Final! We plan to have a pretty short bake period for this beta during which we’ll get a couple more bug fixes in and then we’re shooting for the WildFly 19 Final release in 5 to 10 days. Enjoy, please give us feedback, and as always, thank you so much for your support of WildFly! ### [MicroProfile 3.2 in WildFly 19.0.0.Beta1](/news/2020/01/17/MicroProfile-3-2-in-WildFly-19-0-0-Beta1/) I’m pleased to announce that the WildFly 19 Beta1 zip is now available for download. I typically don’t blog about the WildFly betas, but I want to this time because I’m so thrilled to be able to say we’ve gotten implementations of all of the MicroProfile 3.2 specifications in this release! This is the first WildFly release that includes all the MicroProfile platform specs. We’ve added three new subsystems to provide support for the MicroProfile platform specs we’ve never supported before: Specification Version in WildFly 19 JIRA Issue MicroProfile Fault Tolerance 2.0 WFLY-12590 MicroProfile JWT Authentication 1.1 WFLY-12609 MicroProfile OpenAPI 1.1 WFLY-12313 MicroProfile 3.2 also includes updates to two of the specs we included in WildFly 18, so those have been updated as well: Specification Version in WildFly 19 JIRA Issue MicroProfile Health Check 2.1 WFLY-12685 MicroProfile Metrics 2.2 WFLY-12686 As we did in WildFly 18, we also provide MicroProfile Config 1.3, OpenTracing 1.3, and Rest Client 1.3, the implementations of which have had some updates. In particular, the subsystem for integrating OpenTracing has been updated to provide a richer management API. Finally, we of course provide all of the MicroProfile specs that are also part of Java EE 8. WildFly’s MicroProfile implementations are primarily based on the Smallrye projects. (We use RESTEasy’s Rest Client impl.) Many thanks to Ken Finnigan and all the folks in the Smallrye community for providing great implementations of these rapidly evolving specs! It takes a great community to bring in major new features like this. A great number of other folks have helped; I thank you all and my apologies to anyone I’ve missed: Fabio Burzigotti Michael Edgar Paul Ferraro Emmanuel Hugonnet Radoslav Husar Jan Kasik Kabir Khan Darran Lofthouse Eduardo Martins Stefano Maestri Jeff Mesnil Miroslav Novak Ron Sigal Alessio Soldano Tobias Stadler Martin Stefanko Ivan Straka Rostislav Svoboda Sultan Zhantemirov I’d particularly like to thank Stefano Maestri for his leadership in getting this done, and Michael Edgar and Tobias Stadler for providing a lot of the drive behind this — and for putting up with our sometimes burdensome feature development processes! Jira Release Notes I’ll wait for the WildFly 19 Final release to get into all the details, but 19.0.0.Beta1 includes a wide variety of other features, component updates, bugs fixes and enhancements beyond the MicroProfile work. The full list of issues resolved is available here. This release incorporates WildFly Core 11.0.0.Beta7 — see the WildFly Core JIRA for details of what was in the WildFly Core 11 betas. Enjoy, and as always, thank you so much for your support of WildFly! ### [Custom Filters in WildFly](/news/2020/01/04/Custom-Filters-in-WildFly/) What is a log filter? A log filter is used to add fine grained control over a log message. In the case of WildFly this is a java.util.logging.Filter. As of WildFly 18 there is the ability to use custom log filters. Creating a Filter To create a filter you must implement the java.util.logging.Filter interface. The filter must be in a module and can be defined on a logger or a handler via the filter-spec attribute. A custom filter can also be combined on the filter-spec attribute with a filter expression. For example any(match(".*WELD.*"), myCustomFilter). The below example will filter log messages based on the current thread’s context class loader. It takes advantage of WildFly’s use of JBoss Modules to get the module name from the class loader. The name is then checked to see if it matches the pattern configured on the filter. Example Filter public class ClassLoaderFilter implements Filter { @Override public boolean isLoggable(final LogRecord record) { final ClassLoader cl = getClassLoader(); String value; if (cl instanceof ModuleClassLoader) { value = ((ModuleClassLoader) cl).getName(); } else { value = cl.toString(); } if (pattern == null || pattern.matcher(value).matches()) { MDC.put("moduleName", value); return true; } MDC.remove("moduleName"); return false; } } Adding a Filter A filter can be added to WildFly by first creating a module based on the library the filter is in. We then need to create a filter resource on the logging subsystem based on this new module and filter. Finally the filter can be added to a logger or handler resource. Example CLI Commands module add --name=org.jboss.example.filter --resources=/path/to/log-filter.jar --dependencies=org.jboss.modules,java.logging,org.jboss.logging /subsystem=logging/json-formatter=json:add(exception-output-type=formatted, date-format="yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ") /subsystem=logging/filter=clFilter:add(module=org.jboss.example.filter, class=org.jboss.example.filter.ClassLoaderFilter, properties={pattern=".*deployment\.app.*"}) /subsystem=logging/file-handler=DEPLOYMENT:add(file={relative-to=jboss.server.log.dir, path=deployment.log}, level=TRACE, append=false, autoflush=true,named-formatter=json, filter-spec=clFilter) /subsystem=logging/root-logger=ROOT:add-handler(name=DEPLOYMENT) In the example above we create a filter which uses the pattern .*deployment\.app.*. This will match the module name from the current thread’s context class loader and only accept messages where the module name matches the pattern. In our case this will only log messages that are associated with our deployment. We then add the filter created to the file handler created with a JSON formatter. Finally we add the file handler to the root logger. Example Project An example project can be found at https://github.com/jamezp/wildfly-examples/tree/master/custom-log-filter. To use the example project simply download the source and run mvn clean wildfly:run. Once started and the application is deployed you can access the example at http://localhost:8080/app. You should initially see some log messages that were logged during the deployment process. You can then log a custom message or start a job which logs a message at the defined number of seconds. ### [Ship Your WildFly Additions via Galleon Feature-Packs](/news/2019/12/17/Ship-Your-WildFly-Additions-via-Galleon-Feature-Packs/) Galleon is a tool for provisioning Java runtimes. It comes with plugins for provisioning WildFly server instances. We have been using it internally in WildFly to build and configure the server the past few releases, and we recently introduced it into our OpenShift cloud image to be able to create a server with a smaller footprint than the default. This post will give an overview of how to use Galleon to provide your additions to WildFly so that users can easily install them. The intended audience is someone who is familiar with writing WildFly subsystems, and how our JBoss Modules classloading system works. We will see how this is a great way for: Third-party vendors to ship their products which are intended to run on top of WildFly. Shipping experimental features that we don’t want in the main WildFly code base yet. Up until recently there was not really any standard way to do this. You would need one of the following options: Have your code included in the main WildFly code base. This is not really a realistic option for a lot of people since what we put into there is mainly driven by where we, the WildFly community, want WildFly to go next. Provide your subsystem via other means, for example a script to copy your additions into an existing WildFly installation and add them to the configuration. Template Galleon feature-pack repository This blog post references a repository which extends WildFly with a generic subsystem whose only job is to make a CDI @Produces method available to deployments. The repository also contains the needed bits to have an Arquillian test suite running outside of the WildFly code base, and of course to create the Galleon feature-pack. The subsystem code is basic, as the intent is for you to be able to use this repository as a template for creating your own Galleon feature-packs. This is not meant to be an in-depth guide, more a high level overview to get you started. The template repository README goes into more depth in some areas. Also, as people provide feedback, its explanation of how things work can evolve independently of the static snapshot of information contained in this blog post. The blog-post-snapshot tag is from when this blog post was written. Initial run If you are impatient, you can simply run: $mvn install $./build/target/wildfly-<WildFly Version>-template-<Template Version>/bin/standalone.sh The server in the build/target directory is a trimmed down version of ‘official’ WildFly with our subsystem added. Then in another terminal window: $mvn package wildfly:deploy -pl example Then go to http://localhost:8080/example/greeting and you will see a greeting message. This message comes from the CDI @Produces method made available by the template’s subsystem, and the language used for the message changes as you refresh the page. We will look at various ways of customising your WildFly server with our feature-pack later in this post. Core Galleon concepts The Galleon documentation discusses the concepts in depth but we will summarise some of the core concepts which we have used for this template, mainly to make sense of what we have done. Package - A package is file system content that should be included in the built server. In our example this means JBoss Modules for our subsystem and its dependency, and also licenses. A package may have a task to run when it is installed. Features and Feature groups - we use a feature to add configuration for our subsystem to the WildFly configuration. Features can be added to groups. Features and feature groups may (among other things) have dependencies on other features and feature groups, and may include dependencies on packages. Layers - Layers split up the server into fine-grained bits, so that we can pick and choose exactly the parts we want. For example you could ask for a WildFly server just implementing JAX-RS (and its dependencies) and not implementing the management interfaces. The resulting server will be a lot smaller than the one you download from https://www.wildfly.org/downloads/. Layers can have dependencies on other layers, e.g. when asking for JAX-RS it will also install the web server. There is a list of all our layers defined by WildFly and WildFly Core in our documentation. If you want to understand better what their dependencies are, you can look at the layer-spec.xml for the various layers that make up WildFly in the following locations WildFly Core’s Core Feature-Pack WildFly’s Servlet Feature-Pack WildFly’s Full Feature-Pack The above links take you to the versions used for WildFly 18.0.1.Final; adjust them to see what is available in other server versions. Once you have read this article and browsed the template repository you should be able to work out what all those files contain. The template subsystem Galleon feature-pack This section will explain our feature-pack. Let’s take a quick look at its packages, feature groups, layers, feature-pack configuration, and the build. Packages We have some packages which contain the JBoss Modules for our subsystem and its dependency. These can be found under the galleon-pack/src/main/resources/modules/system/layers/base/ directory. The subsystem code is in the subsystem/ folder of the project, while the example subsystem dependency (which contains the CDI @Produces method mentioned) code is in the dependency/ folder of the project. In addition we have some packages to deal with installing licenses for your added libraries. We won’t go into details of that here. See the the template README for more information. Feature Groups We define a single feature group in galleon-pack/src/main/resources/feature_groups/template-subsystem.xml. The group contains the <feature spec="subsystem.template-subsystem"/> for our subsystem. The value of 'spec' used for these feature specifications is of the form subsystem.<subsystem name in the model> and it essentially configures the subsystem. In this case <subsystem name in the model> is 'template-subsystem', and this configuration results in a /subsystem=template-subsystem:add() when provisioning the server. Our subsystem is empty, if it had some attributes that need setting they would also be defined in the feature spec. Layers galleon-pack/src/main/resources/layers/standalone/template-layer/layer-spec.xml contains our single layer called ‘template-layer’. It adds dependencies on the following other constructs: A dependency on the cdi layer. This is needed so that when we install our layer, which uses CDI, Galleon will automatically pull in the CDI dependencies as well if they are not already there. The feature group we already discussed. When this layer is installed, our subsystem gets configured. Any additional packages (i.e. content) needed. In this case there are none, since we add the dependency on the subsystem’s extension module in wildfly-feature-pack-build.xml as we see in the next section. The layer-spec.xml and template README contain some more information about this. Feature-pack configuration galleon-pack/wildfly-feature-pack-build.xml is used to provision new features (the template README explains how to install additions which have no configuration). It adds our extension module org.wildfly.extension.template-subsystem to the configuration. Galleon is smart enough to inspect this module’s dependencies and automatically add our org.wildfly.template-dependency module. The file also sets up the feature-packs we depend upon in order to provide the underlying server. Build Finally we have the feature-pack build in galleon-pack/pom.xml. It contains the wildfly-galleon-maven-plugin which creates the Galleon feature-pack. Note that it uses the build-feature-pack goal which is needed to add a new subsystem along with the mentioned entry in wildfly-feature-pack-build.xml. When building the galleon-pack/ module you can see what the feature-pack contains in the galleon-pack/target/layout/org.wildfly.extras.galleon-feature-pack-template/template-galleon-pack/<version>/ directory to help you figure out what is missing if your feature-pack does not work the way you expected. Provisioning a server There are a few ways we can provision a server to include our feature-pack. They are via a Maven plugin, or via Galleon CLI. Galleon CLI has a few different ways to provision a server. Maven plugin Using the wildfly-galleon-maven-plugin Maven plugin isn’t really for end users, but it is very handy to be able to use it from within our project. For example, build/pom.xml provisions a server that we can use to verify that our feature-pack works. Earlier in this post, we already played with the server in the build/target directory and deployed our example into that. Also, in our testsuite, testsuite/integration/subsystem/pom.xml provisions a server to run the Arquillian tests against. In both cases we use the provision goal of the galleon-maven-plugin to provision a server. It lists the feature-packs that our feature-pack depends on (note that they are 'transitive') as well as the layers to install into our server. However, the layers used are slightly different in the two cases since we are doing two different things. They both need our template-layer of course. The build/ version is used to run our example from the example/ directory. As this uses a REST endpoint, we need the jaxrs layer to provide this functionality. Also, the wildfly:deploy goal we used to deploy the application uses the management interfaces, so it also needs the management layer. The testsuite version, on the other hand, does not use REST for the test, so we just use the plain web-server layer (the jaxrs layer used in build/ depends on this web-server layer). Also, since Arquillian uses JMX to do the interactions with the server, we also need the jmx-remoting layer. Galleon CLI Galleon CLI is explained in more detail in the Galleon documentation. We will look at a few ideas for how to provision a WildFly server containing our plugin. There are probably other ways too, Galleon is very powerful! The two main ways to do this are to install the various parts manually, or to provision it from an xml file. Doing it manually is powerful, but there can be a lot of commands to remember. If you use an xml file to provision it, everything is contained in that file and you can run it again and again to provision servers using a simpler to remember command. To use the Galleon CLI you need to download it. The following examples assume that you have added the bin/ folder of the distribution to your PATH (This is where the galleon.sh command comes from in the following examples). We will look at how to provision the server via the two main mechanisms, then the Trying the provisioned server section below tells you how to run your application to check that our example subsystem got installed into the server and works as expected. Manual Galleon CLI installation To install additional feature-packs via Galleon you generally follow the following two steps: Install the main server - here we can for example choose the version of the main server, and also trim it down if we don’t want the full server. Install the feature-pack. Note that this part is only possible if the main server was provisioned via Galleon. It is currently not possible to install feature-packs into e.g. the unzipped zip from the wildfly.org/downloads page. Install main server To install the main server we can do: $galleon.sh install wildfly:current --dir=wildfly This installs all of (i.e. the same as the downloaded zip) the latest WildFly version (at the time of writing 18.0.1.Final) into the directory specified by the --dir argument. In this case I am using a relative child directory called wildfly/. If you want to install a particular version of WildFly you can append the version to wildfly:current. E.g.: wildfly:current#18.0.0.Final - installs WildFly 18.0.0.Final. wildfly:current#19.0.0.Beta1-SNAPSHOT - installs WildFly from locally built SNAPSHOT maven artifacts. If you want to trim the base server that we install (similar to what we did in the testsuite and the example server build), you can specify which layers to install by passing in the --layers option. To install the same server as we had in the build/target/ directory that we used to run the example above, you can run: $galleon.sh install wildfly:current --dir=wildfly --layers=jaxrs,management Note that we did not install our template-layer because this is unknown in the main WildFly feature-pack. We will add it in the next step. Install feature-pack Now to install our layer, we run the following command: $galleon.sh install org.wildfly.extras.galleon-feature-pack-template:template-galleon-pack:1.0.0.Alpha-SNAPSHOT --layers=template-layer --dir=wildfly We specify the same directory that we installed the server into in the last step by specifying the same value for --dir. org.wildfly.extras.galleon-feature-pack-template:template-galleon-pack:1.0.0.Alpha-SNAPSHOT is the Maven GAV of the Galleon feature-pack (i.e. what we have in wildfly-galleon-pack-template/blob/master/galleon-pack/pom.xml. If you went with the trimmed server in the previous step, and you look at wildfly/standalone/configuration/standalone.xml, you should see that both the template-subsystem and the weld subsystems were added in this second step. Weld is our CDI implementation. As we have seen the 'cdi' layer is a dependency of our layer, so Galleon pulls it in too! See the Trying the provisioned server section below for how to start your server and give it a quick sanity check by deploying and running the example. Galleon CLI provision from xml file An alternative to having to type all the CLI commands we saw every time you want to provision a server is to use an XML file as input to the Galleon CLI. There is an example in provision.xml. This file contains all the information needed to provision our server, and as you can see, it lists the feature-pack(s) we depend on, and the feature-pack implemented in the template repository. For each of those we specify the Maven GAV, as in the previous section. We can set what to include from each feature-pack (Refer to the Galleon documentation for more in-depth explanation of what each setting does). Finally, we say that we want the cloud-profile and template-layer layers. cloud-profile is just to give you another example base server, we could have used the same layers as in the previous section. To provision the server, you now simply run the following command: $galleon.sh provision /path/to/provision.xml --dir=wildfly Now you can start the server and run the example as outlined in the Trying the provisioned server section. Trying the provisioned server The example/ folder contains the sample application that you can deploy into the server. The steps to do this are the same whether you are using the example server from the build/ directory that we saw in the start of this post, or any of the Galleon CLI mechanisms. The example itself is very simple, consisting of a single REST endpoint which is injected with a bean made available by the CDI @Produces method from the template subsystem dependency. To run it, first start the server by running (the value of JBOSS_HOME is the root of the built server, which depends on which flavour of the provisioned server you are trying): $"${JBOSS_HOME}"/bin/standalone.sh Then to deploy the application, in another terminal window in the checkout folder of the template project, run: $mvn package wildfly:deploy -pl example/ Then go to http://localhost:8080/example/greeting, which will output the message created by the CDI producer. As you refresh, the message will change. Adapting the template for your use To provision your own subsystem you can copy this template, but of course you should try to give your subsystem, modules, Galleon constructs, and Java package and class names sensible names for your WildFly addition. There are quite a few things that need changing, and I have tried to add some hints in the template source code in the form of TODO comments. This template has not been officially released to Maven. Since it doesn’t do anything useful apart from provide a framework for you to copy, it is still using a SNAPSHOT version. For your purposes you should create real tags and releases, and deploy to e.g. Maven Central. Then you can advertise your feature-pack to the world, and it will be easy for people to provision WildFly servers containing your super-cool feature! Finally, if something is not clear in the template repository, please either open a pull request or an issue. ### [WildFly 18.0.1 is released!](/news/2019/11/14/WildFly-18-0-1-is-released/) WildFly 18.0.1 Final is now available for download. It’s been over a month since the WildFly 18 release and we had a number of important bug fixes and component upgrades ready to go so we decided to do a WildFly 18.0.1 release. The full list of issues resolved in WildFly 18.0.1 is available here. Issues resolved in the WildFly Core 10.0.2 and 10.0.3 releases included with WildFly 18.0.1 are available here and here. Now it’s time to get back to the exciting work on MicroProfile 3.2 support for WildFly 19! Enjoy! ### [Configuring WildFly S2I image Datasources on OpenShift](/news/2019/11/11/Configuring-WildFly-S2I-image-Datasources-on-OpenShift/) Introduction In this guide, we will show you how we can containerize a JAX-RS PostgreSQL demo application to run on WildFly in a local OpenShift cluster. We will explore the different options we have to configure the data source subsystem in a cloud-based infrastructure. First of all, we will use the WildFly Datasources Galleon Pack to bring in the PostgreSQL data source and driver configuration to our WildFly server. Later, we will show you how you can configure more aspects of the data source subsystem beyond the capabilities given by this Galleon pack. This practical guide requires Red Hat CodeReady Containers to install an OpenShift cluster for development purposes on your system. On this local cluster, we will deploy a PostgreSQL database server and this simple Jaxrs PostgreSQL demo application running on WildFly. It assumes you have basic knowledge of OpenShift. Preparing the OpenShift cluster and PostgreSQL Database Server The CodeReady Containers Getting Started Guide describes pretty well how to install, configure, and start a local OpenShift cluster for development purposes; you only have to follow the installation instructions. At the time this post was written, CodeReady Containers does not ship the Wildfly image stream by default. The easiest way to create an image stream is by using the oc import-image to import the WildFly image from quay.io/wildfly. We import the image under the openshift namespace to make the image available to all projects and to avoid repeating the same step for each project we create. Finally, we verify the image is imported by using oc get is: $ crc start ... INFO Starting OpenShift cluster ... [waiting 3m] INFO INFO To access the cluster, first set up your environment by following 'crc oc-env' instructions INFO Then you can access it by running 'oc login -u developer -p developer https://api.crc.testing:6443' INFO To login as an admin, username is 'kubeadmin' and password is wyozw-5ywAy-5yoap-7rj8q INFO INFO You can now run 'crc console' and use these credentials to access the OpenShift web console The OpenShift cluster is running $ oc login -u kubeadmin -p wyozw-5ywAy-5yoap-7rj8q https://api.crc.testing:6443 Login successful. You have access to 51 projects, the list has been suppressed. You can list all projects with 'oc projects' Using project "default". $ oc import-image wildfly --confirm \--from quay.io/wildfly/wildfly-centos7 --insecure -n openshift imagestream.image.openshift.io/wildfly imported $ oc get is -n openshift | grep wildfly NAME IMAGE REPOSITORY TAGS UPDATED wildfly default-route-openshift-image-registry.apps-crc.testing/default/wildfly latest 8 seconds ago This is all that we need to configure the local OpenShift cluster to work with WildFly. Let us begin creating a new project for our demo: $ oc new-project wildfly-demo Now using project "wildfly-demo" on server "https://api.crc.testing:6443". Now, let us deploy our database server image. CodeReady Containers comes with a PostgreSQL image by default, so we do not need to import it. For our testing purposes, we need a basic server configured with a database name, user, and password. The oc new-app command creates the resources required to deploy the postgresql image: $ oc new-app --name database-server \ --env POSTGRESQL_USER=postgre \ --env POSTGRESQL_PASSWORD=admin \ --env POSTGRESQL_DATABASE=demodb \ postgresql --> Found image f427c5c (2 months old) in image stream "openshift/postgresql" under tag "10" for "postgresql" PostgreSQL 10 ------------- PostgreSQL is an advanced Object-Relational database management system (DBMS). The image contains the client and server programs that you'll need to create, run, maintain and access a PostgreSQL DBMS server. Tags: database, postgresql, postgresql10, rh-postgresql10 * This image will be deployed in deployment config "database-server" * Port 5432/tcp will be load balanced by service "database-server" * Other containers can access this service through the hostname "database-server" --> Creating resources ... imagestreamtag.image.openshift.io "database-server:10" created deploymentconfig.apps.openshift.io "database-server" created service "database-server" created --> Success Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose svc/database-server' Run 'oc status' to view your app. Note Instead of using directly postgresql image stream with the new-app command, you can use one of the available templates. We have used the image stream directly here as an example to clear up better what a template does behind scenes. Notice here the output of new-app describes for us which resources have been created. One important resource is the database-server service which is the internal load balancer service that connects to the data base server. Our URL connection will use this service name to connect to the database. We can get the status of the pod created with the command oc get pods: $ oc get pods NAME READY STATUS RESTARTS AGE database-server-1-5l6fd 1/1 Running 0 44s database-server-1-deploy 0/1 Completed 0 57s The new-app command has created two pods, the one with -deploy suffix is the pod created by a deployment config resource to create application pods. The other one is the application pod running our database server. We can verify the database was created opening a remote shell connection on this pod: $ oc rsh database-server-1-5l6fd sh-4.2$ psql demodb psql (10.6) Type "help" for help. demodb=# \q sh-4.2$ exit Configuring the WildFly Data Source Now is time to create our application container image that includes the WildFly server and our demo application. The oc new-app is also used for such purposes. Unlike the previous configuration of the database server where we were building a new container from an existing image stream, now we are going to create a new image combining the WildFly image stream with an external GitHub application source code. OpenShift takes care of the details and creates a final image containing the server and the application. Internally, it uses the Source-To-Image (S2I) tool. During this process, the WildFly server is provisioned by Galleon, and our demo JAX-RS application is built and copied into the $WILDFLY_HOME/deployments folder. We do not need the full server to run our example, for example, we do not need the ejb3, remoting or messaging subsystems. We can specify a set of Galleon layers by using the GALLEON_PROVISION_LAYERS environment variable to reduce the server footprint. This environment variable contains a comma-separated list of layer names you want to use to provision your server during the S2I phase. It is important to understand that the server provisioning is done in OpenShift by a Build Config resource, so we need to make this variable available as a build environment variable. Notice that these details usually are hidden to you when you are using a template or an Operator. Note Check this post to learn more about OpenShift and Galleon layers. For our demo example on OpenShift, we instruct Galleon to provision our server with these two Galleon Layers: jaxrs-server and postgresql-datasource. The jaxrs-server layer provisions the server with some features needed to run our example e.g. cdi, jaxrs, jpa, undertow, transactions, datasources. It belongs to the default Galleon pack which is used to provision the default WildFly server. The postgresql-datasource layer comes from WildFly Datasources Galleon Pack. This layer adds to the server the PostgreSQL drivers and specific PostgreSQL data source configuration. It allows us to configure the PostgreSQL data source by using the following variables: POSTGRESQL_DATABASE POSTGRESQL_SERVICE_PORT POSTGRESQL_SERVICE_HOST POSTGRESQL_PASSWORD POSTGRESQL_USER Let us create our WildFly container then configuring the data source to connect to our PostgreSQL server running in a different pod: $ oc new-app --name wildfly-app \ https://github.com/yersan/jaxrs-postgresql-demo.git \ --image-stream=wildfly \ --env POSTGRESQL_SERVICE_HOST=database-server \ --env POSTGRESQL_SERVICE_PORT=5432 \ --env POSTGRESQL_USER=postgre \ --env POSTGRESQL_PASSWORD=admin \ --env POSTGRESQL_DATABASE=demodb \ --env POSTGRESQL_DATASOURCE=PostgreSQLDS \ --build-env GALLEON_PROVISION_LAYERS=jaxrs-server,postgresql-datasource --> Found image 38b29f9 (3 weeks old) in image stream "openshift/wildfly" under tag "latest" for "wildfly" WildFly 18.0.0.Final -------------------- Platform for building and running JEE applications on WildFly 18.0.0.Final Tags: builder, wildfly, wildfly18 * The source repository appears to match: jee * A source build using source code from https://github.com/yersan/jaxrs-postgresql-demo.git will be created * The resulting image will be pushed to image stream tag "wildfly-app:latest" * Use 'oc start-build' to trigger a new build * This image will be deployed in deployment config "wildfly-app" * Ports 8080/tcp, 8778/tcp will be load balanced by service "wildfly-app" * Other containers can access this service through the hostname "wildfly-app" --> Creating resources ... imagestream.image.openshift.io "wildfly-app" created buildconfig.build.openshift.io "wildfly-app" created deploymentconfig.apps.openshift.io "wildfly-app" created service "wildfly-app" created --> Success Build scheduled, use 'oc logs -f bc/wildfly-app' to track its progress. Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose svc/wildfly-app' Run 'oc status' to view your app. $ oc get pods NAME READY STATUS RESTARTS AGE database-server-1-5l6fd 1/1 Running 0 10m database-server-1-deploy 0/1 Completed 0 10m wildfly-app-1-build 0/1 Completed 0 3m50s wildfly-app-1-deploy 0/1 Completed 0 55s wildfly-app-1-sdk2m 1/1 Running 0 46s $ oc expose svc/wildfly-app --name wildfly-app route.route.openshift.io/wildfly-app exposed The new-app command creates three additional pods in the OpenShift cluster; one build config (-build suffix, completed), one deploy config (-deploy suffix, completed) and our running application pod. Remember, the build config is the resource that creates the container image using the S2I tool, builds your application and provisions the server using Galleon. The deployment config is the resource that starts the new container image created by the build config. Note You can review the pod logs issuing the following command oc log pod/{pod_name} Now we can verify our application is working. We exposed the application to the outside world using oc expose. If we want to access to our container via the web, we need to know its host name. We can get this value by inspecting the routes/wildfly-app resource. Once we know the host name, we can use curl to fetch some information from our application: $ oc get routes/wildfly-app --template={{.spec.host}} wildfly-app-wildfly-demo.apps-crc.testing $ curl http://wildfly-app-wildfly-demo.apps-crc.testing/jaxrs-postgresql-demo/api/tasks [{"id":1,"title":"This is the task-1"},{"id":2,"title":"This is the task-2"},{"id":3,"title":"This is the task-3"},{"id":4,"title":"This is the task-4"},{"id":5,"title":"This is the task-5"}] Now, let us take a look at our current datasources subsystem configuration to see how it was configured. We can open a remote session on our WildFly running pod and examine the standalone.xml file: $ oc rsh wildfly-app-1-sdk2m sh-4.2$ cat /opt/wildfly/standalone/configuration/standalone.xml The datasources subsystem configuration is the following: <subsystem xmlns="urn:jboss:domain:datasources:5.0"> <datasources> <datasource jndi-name="java:jboss/datasources/${env.POSTGRESQL_DATASOURCE,env.OPENSHIFT_POSTGRESQL_DATASOURCE:PostgreSQLDS}" pool-name="PostgreSQLDS" enabled="true" use-java-context="true" use-ccm="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}"> <connection-url>jdbc:postgresql://${env.POSTGRESQL_SERVICE_HOST, env.OPENSHIFT_POSTGRESQL_DB_HOST}:${env.POSTGRESQL_SERVICE_PORT, env.OPENSHIFT_POSTGRESQL_DB_PORT}/${env.POSTGRESQL_DATABASE, env.OPENSHIFT_POSTGRESQL_DB_NAME}</connection-url> <driver>postgresql</driver> <pool> <flush-strategy>IdleConnections</flush-strategy> </pool> <security> <user-name>${env.POSTGRESQL_USER, env.OPENSHIFT_POSTGRESQL_DB_USERNAME}</user-name> <password>${env.POSTGRESQL_PASSWORD, env.OPENSHIFT_POSTGRESQL_DB_PASSWORD}</password> </security> <validation> <check-valid-connection-sql>SELECT 1</check-valid-connection-sql> <background-validation>true</background-validation> <background-validation-millis>60000</background-validation-millis> </validation> </datasource> <drivers> <driver name="postgresql" module="org.postgresql.jdbc"> <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class> </driver> </drivers> </datasources> </subsystem> As you can see in the configuration file, Galleon has prepared the data source subsystem to be configured by the WildFly Datasources Galleon Pack environment variables. You can also verify that a PostgreSQL driver is added as a JBoss module in the server: sh-4.2$ ls /opt/wildfly/modules/org/postgresql/jdbc/main/ module.xml postgresql-9.4.1211.jar This sort of configuration done by using the WildFly Datasource Galleon Pack is simple and easy to use. However, it has some limitations; there are some attributes related to the datasource that cannot be configured, e.g. connection min/max pool size, flush-strategy, background-validation-millis. We cannot configure more than one datasource of the same type. In the following section, we explain how you can achieve this. Before moving to the next part, let us remove all unused configurations: $ oc delete all -l app=wildfly-app pod "wildfly-app-1-84lh6" deleted replicationcontroller "wildfly-app-1" deleted service "wildfly-app" deleted deploymentconfig.apps.openshift.io "wildfly-app" deleted buildconfig.build.openshift.io "wildfly-app" deleted build.build.openshift.io "wildfly-app-1" deleted imagestream.image.openshift.io "wildfly-app" deleted route.route.openshift.io "wildfly-app" deleted Configuring additional aspects of the datasource subsystem If you need to configure more than one data source or you need to configure some attributes that are not available by the WildFly Datasources Galleon Pack, there is a generic datasources subsystem configuration by using environment variables. You can check the Datasources configuration where these variables are explained. In the next example, we make use of some environments to configure two different datasources specifying different max/min pool sizes. One detail we need to take into account is we no longer need the PostgreSQL datasource configuration added by the WildFly Datasources Galleon Pack, since we are going to configure the data source using a different set of variables. But we still need the PostgreSQL driver added by the Galleon Pack. The solution is easy, just instead of specifying the postgresql-datasource layer, we will specify this the postgresql-driver layer which is the layer that brings in only the driver. Again, using new-app, we configure the two data sources s specifying the different max/min pool sizes: $ oc new-app --name wildfly-app \ https://github.com/yersan/jaxrs-postgresql-demo.git \ --image-stream= wildfly \ --env DB_SERVICE_PREFIX_MAPPING="dbone-postgresql=DSONE,dbtwo-postgresql=DSTWO" \ --env DSONE_JNDI="java:/jboss/datasources/PostgreSQLDS" \ --env DSONE_USERNAME="postgre" \ --env DSONE_PASSWORD="admin" \ --env DSONE_DATABASE="demodb" \ --env DSONE_DRIVER="postgresql" \ --env DBONE_POSTGRESQL_SERVICE_HOST="database-server" \ --env DBONE_POSTGRESQL_SERVICE_PORT=5432 \ --env DSONE_MAX_POOL_SIZE=10 \ --env DSONE_MIN_POOL_SIZE=5 \ --env DSONE_NONXA=true \ --env DSTWO_JNDI="java:/jboss/datasources/UnusedDS" \ --env DSTWO_USERNAME="postgre" \ --env DSTWO_PASSWORD="admin" \ --env DSTWO_DATABASE="demodb" \ --env DSTWO_DRIVER="postgresql" \ --env DBTWO_POSTGRESQL_SERVICE_HOST="database-server" \ --env DBTWO_POSTGRESQL_SERVICE_PORT=5432 \ --env DSTWO_MAX_POOL_SIZE=5 \ --env DSTWO_MIN_POOL_SIZE=2 \ --build-env GALLEON_PROVISION_LAYERS=jaxrs-server,postgresql-driver warning: --env no longer accepts comma-separated lists of values. "DB_SERVICE_PREFIX_MAPPING=dbone-postgresql=DSONE,dbtwo-postgresql=DSTWO" will be treated as a single key-value pair. --> Found image 38b29f9 (3 weeks old) in image stream "openshift/wildfly" under tag "latest" for "wildfly" WildFly 18.0.0.Final -------------------- Platform for building and running JEE applications on WildFly 18.0.0.Final Tags: builder, wildfly, wildfly18 * The source repository appears to match: jee * A source build using source code from https://github.com/yersan/jaxrs-postgresql-demo.git will be created * The resulting image will be pushed to image stream tag "wildfly-app:latest" * Use 'oc start-build' to trigger a new build * This image will be deployed in deployment config "wildfly-app" * Ports 8080/tcp, 8778/tcp will be load balanced by service "wildfly-app" * Other containers can access this service through the hostname "wildfly-app" --> Creating resources ... imagestream.image.openshift.io "wildfly-app" created buildconfig.build.openshift.io "wildfly-app" created deploymentconfig.apps.openshift.io "wildfly-app" created service "wildfly-app" created --> Success Build scheduled, use 'oc logs -f bc/wildfly-app' to track its progress. Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose svc/wildfly-app' Run 'oc status' to view your app. The DB_SERVICE_PREFIX_MAPPING specifies the list of data sources we are going to configure (dbone-postgresql and dbtwo-postgresql) and links them with a variable prefix (DSONE and DSTWO). This mechanism allows us to create multiple datasources by using a variable prefix name identifying the variables that configure each data source. Explore the Datasource configuration documentation to learn more on this. Once our application pod is created, if we inspect the final server configuration file, we will see that we have added two different data sources, one xa-datasource and one non-xa-datasource, each of them with a specific max/min pool sizes: $ oc get pods NAME READY STATUS RESTARTS AGE database-server-1-5l6fd 1/1 Running 0 19m database-server-1-deploy 0/1 Completed 0 19m wildfly-app-1-build 0/1 Completed 0 3m18s wildfly-app-1-deploy 0/1 Completed 0 33s wildfly-app-1-lwnf8 1/1 Running 0 25s $ oc rsh wildfly-app-1-lwnf8 sh-4.2$ cat /opt/wildfly/standalone/configuration/standalone.xml <subsystem xmlns="urn:jboss:domain:datasources:5.0"> <datasources> <datasource jta="true" jndi-name="java:/jboss/datasources/PostgreSQLDS" pool-name="dbone_postgresql-DSONE" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}"> <connection-url>jdbc:postgresql://database-server:5432/demodb</connection-url> <driver>postgresql</driver> <pool> <min-pool-size>5</min-pool-size> <max-pool-size>10</max-pool-size> </pool> <security> <user-name>postgre</user-name> <password>admin</password> </security> <validation> <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker"/> <validate-on-match>true</validate-on-match> <background-validation>false</background-validation> <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter"/> </validation> </datasource> <xa-datasource jndi-name="java:/jboss/datasources/UnusedDS" pool-name="dbtwo_postgresql-DSTWO" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}"> <xa-datasource-property name="ServerName"> database-server </xa-datasource-property> <xa-datasource-property name="DatabaseName"> demodb </xa-datasource-property> <xa-datasource-property name="PortNumber"> 5432 </xa-datasource-property> <driver>postgresql</driver> <xa-pool> <min-pool-size>2</min-pool-size> <max-pool-size>5</max-pool-size> </xa-pool> <security> <user-name>postgre</user-name> <password>admin</password> </security> <validation> <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker"/> <validate-on-match>true</validate-on-match> <background-validation>false</background-validation> <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter"/> </validation> </xa-datasource> <drivers> <driver name="postgresql" module="org.postgresql.jdbc"> <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class> </driver> </drivers> </datasources> </subsystem> Notice this time the datasources subsystem configuration is done when the server is launched by the deployment config resource. Behind the scenes the WildFly embedded server is launched and the server is configured from the values found in the environment variables. Since we have used the postgresql-driver layer, we still have the PostgreSQL driver installed in our server, we can see it under the modules folder: sh-4.2$ ls /opt/wildfly/modules/org/postgresql/jdbc/main/ module.xml postgresql-9.4.1211.jar Now you can delete the project to remove all the resources created in this demo: $ oc delete project wildfly-demo project.project.openshift.io "wildfly-demo" deleted In the next post, we will show you how you can configure the server using pure CLI management operations instead of using environment variables. That will give you all the flexibility you could need to configure any aspect of the WildFly S2I cloud image. ### [WildFly 18 S2I image has been released on quay.io](/news/2019/10/07/WildFly-18-S2I-image-has-been-released-on-quay-io/) WildFly 18 S2I docker images WildFly s2i builder and runtime Docker images for WildFly 18 have been released on quay.io/wildfly Changes since last release: New env variable GALLEON_PROVISION_LAYERS=<layers list> that you can use during s2i to provision a custom WildFly server. It does replace the GALLEON_PROVISION_SERVER that was only offering a subset of Galleon layers. You can now provision WildFly server by directly providing Galleon layers. This offers a lot of flexibility when composing a server. The list of Galleon layers can be found in the image repository README file. S2I chained build template updated with Galleon layers argument. New cloud-server, jaxrs-server, datasources-web-server base Galleon layers to help you provision use-case adjusted servers. Out of the box Keycloak support. This blog post highlight usage of this new feature. keycloak Galleon layer that you can combine with base Galleon layers to enable secure deployments for custom provisioned server. Smaller s2i builder image size. The default server is a "slim" server with JBoss modules artifacts resolved from maven local cache. New environment variables to fine tune the server at execution time, more information in README. For a complete documentation on how to use these images using s2i, OpenShift and Docker, refer to README. Adding imagestreams and template to OpenShift At some point the new images will be made available from OpenShift catalog and image repository. You can already use these images by adding them yourselves to your OpenShift cluster. WildFly S2I builder image stream: oc create -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-18.0/imagestreams/wildfly-centos7.json WildFly runtime image stream: oc create -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-18.0/imagestreams/wildfly-runtime-centos7.json Chained build template: oc create -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-18.0/templates/wildfly-s2i-chained-build-template.yml NB: If you import the image streams in your project, be sure to set ImageStreams Namespace to your project namespace in the template. openshift being the default namespace. Configuring WildFly server to secure deployments with Keycloak We have added support to automatically configure the WildFly server to secure your deployments using Keycloak. The Keycloak configuration aspects are handled by the WildFly server at startup. The following example illustrate the steps required to secure your deployments using Keycloak. Deploy Keycloak server image In Openshift, deploy the jboss/keycloak image. You must set the following env variables to create an initial user KEYCLOAK_USER=admin, KEYCLOAK_PASSWORD=admin. Access to the Keycloak admin console, add user role and add user role to the admin user roles mapping. Access to the Realm Settings Keys and copy the public key (you will need it to configure the WildFly server). Build the application Once you have imported the WildFly image streams, use the WildFly s2i builder template. Select image version 18.0 and switch to 'Advanced options'. Use the git URL: https://github.com/redhat-developer/redhat-sso-quickstarts, context directory: app-profile-jee-jsp, branch: 7.0.x-ose Build env variables: MAVEN_ARGS_APPEND=-Dmaven.compiler.source=1.6 -Dmaven.compiler.target=1.6 GALLEON_PROVISION_LAYERS=cloud-server,keycloak (Optional, default server supports Keycloak, only use Galleon to create trimmed down server). NB: If using galleon layers, be sure to update the quickstart to use the keycloak security domain (for example jboss-web.xml). other security domain is pre-configured by the cloud-profile layer and can’t be used for Keycloak. Deployment env variables: SSO_PUBLIC_KEY=<Keycloak server public key> (copied from Keycloak admin console) SSO_USERNAME=admin SSO_PASSWORD=admin SSO_URL=<Keycloak server route URL> (for example: http://keycloak-myproject.192.168.42.233.nip.io/auth) SSO_SECRET=my-secret HOSTNAME_HTTP=<application hostname> (for example: my-app-myproject.192.168.42.233.nip.io) SSO_SECURITY_DOMAIN=other (by default security domain is named keycloak, the quickstart relies on the other default security domain. NB: If using Galleon with an updated quickstart, do not set this env variable). Build your application. Once deployed you can access to <your external route>/app-profile-jsp, click on Login and use admin user credentials. ### [WildFly 18 is released!](/news/2019/10/03/WildFly-18-is-released/) I’m pleased to announce that the WildFly 18 Final zip is now available for download. This has been a very busy summer for the many folks who contribute to WildFly; a lot of long hours and a lot of progress. I’m forever grateful for the chance to work on a project with such a great group of people. So, what have we been up to? Jakarta EE and Java EE As I announced last month, WildFly 17.0.1 was certified as a Jakarta EE 8 compatible implementation. As you would expect, WildFly 18 is compatible as well, with both the Full Platform and the Web Profile. Evidence supporting our certification is available here for Full Platform and here for the Web Profile. WildFly 18 is also a certified compatible implementation of Java EE 8. Besides ensuring WildFly is a compatible Jakarta EE 8 implementation, we put a lot of effort into better alignment with the Jakarta EE API projects, which I explain further below. MicroProfile 3 In addition to the parts of MicroProfile that are also in EE 8, WildFly provides support for five other MicroProfile standards. For WildFly 18 we have upgraded those to the spec versions included in the MicroProfile 3.0 release: Specification Version in WildFly 18 MP Config 1.3 MP Health Check 2.0 MP Metrics 2.0 MP OpenTracing 1.3 MP Rest Client 1.3 MicroProfile will be a significant focus for the next couple of WildFly releases. For WildFly 19 we are aiming to introduce support for the three remaining required MP 3 specs that we don’t currently support: MP JWT Authentication, MP Fault Tolerance and MP Open API. Security Enhancements WildFly 18 brings a number of enhancements in the security area: SSL certificate revocation using OCSP is now supported. Elytron audit logging now supports RFC5424/RFC3164 and also allows the administrator to configure the number of reconnect attempts. Mapping of an X509 Certificate to the underlying identity has been enhanced. The Elytron subsystem now supports loading the attributes of an identity using multiple security realms and aggregating the results together into a single identity. The high level CLI security commands (ssl enable-ssl-management and ssl enable-ssl-http-server) have been enhanced to support obtaining certificates from the Let’s Encrypt certificate authority. The Elytron subsystem’s aggregrate security realms now support transforming the principal in between loading the authentication identity and loading the authorization identity. This would be needed in the case where the principal stored in the authentication realm is different from the principal stored in the authorization realm(s). Support for masking passwords in an Elytron client’s XML configuration was added. The certificate authority used by a certificate-authority-account resource is now configurable. This may help in some testing scenarios, or in the future if other authorities besides Let’s Encrypt support the ACME protocol. Enhancements to the EE Subsystems There are a number of new features provided by various WildFly subsystems that I’ll lump into the 'EE' category: In the EJB3 subsystem support has been added for configuring system-wide (i.e. applicable to all EJB deployments) client-side interceptors and server-side interceptors. The behavior and configurability of thread pools used in the EJB3 subsystem has been improved. RESTEasy now supports enabling an HTTP proxy on the client builder using the JAX-RS API. RESTEasy now supports injecting Optional<T> parameter types. The messaging subsystem now: Exposes an attribute which indicates whether any backup server is synchronized with the live server. Exposes an attribute that indicates the Artemis journal type that’s in use. Displays statistics about messages that have been processed by any JMS bridge. Exposes metrics from Artemis resource adapter thread pools. The return value of HttpServletRequest.getServletPath/getRequestURI/getRequestURL is now configurable. This feature is to support a backwards compatible behavior of HttpServletRequest.getServletPath. For example, in a Struts2 application deployed to JBoss AS 7, this method returns the action name, but in WildFly it returns the forwarded jsp name. If the JBoss AS 7 behavior is preferred this can now be configured. Clustering Enhancements As always, the folks working on clustering have been busy as well: For a clustered web app the JSESSIONID can now be encoded with multiple routes, ranked in order of preference. Thus, if the primary owner of a given session is inactive (from the load balancer’s perspective), the load balancer can attempt to route the request to the next route in the list. This ensures that requests will be directed to the next best worker in the event that the primary owner is inactive, and prevents requests from "spraying" across the cluster. The Infinispan subsystem now exposes management metrics for remote HotRod caches. Management The logging subsystem now supports configuration of custom logging filters, allowing for a higher degree of control over logging. As an example a filter could be created to filter messages based on the cause of the log message. The HAL web console includes numerous new features and enhancements. WildFly in the Cloud We’ve continued to make a lot of progress on the source-to-image (s2i) image for WildFly and on the WildFly Operator for Kubernetes/OpenShift. We’ll provide further details on what’s new there in the next couple of weeks when we announce new versions of those images based on the WildFly 18 server release. Alignment with Jakarta EE API Projects Besides ensuring we could certify as Jakarta EE 8 compatible, a lot of effort this summer went into further aligning with the Jakarta community. Specifically, WildFly incorporates a large number of component jars that provide the various EE APIs. For some EE specs WildFly directly provided jars produced by the various Java EE spec projects; for others the JBoss.org community has provided its own jars, derived from source from the Java EE spec projects. For both cases, for WildFly 18 we moved to align the source for our API jars with the source coming from the active Jakarta community. For projects where we were directly shipping a jar from a Java EE 8 project, we switched to a jar from the equivalent Jakarta project. As a result the Maven groupId and artifactId of these artifacts has changed. For projects where we were consuming an API jar produced by a JBoss.org community project, for all of those projects a new github repo was created, with the initial code derived from the Jakarta projects, and new releases were produced. For these APIs the Maven groupId and artifactId did not change (except for JTA, where we moved from the 1.2 version of the spec to 1.3, which affected the artifactId). The new releases have a maven version number one higher than the previous release, but this version bump solely reflects the new origin of the source code. It does not indicate major changes in the source itself. It’s important to emphasize that the Jakarta EE 8 APIs are API identical to the Java EE 8 APIs and generally the method implementations are identical as well. So this change of the source from which we get the API jars is not expected to introduce any runtime incompatibility. This change is all about aligning the code we provide with projects that are actively maintained. If you were compiling a deployment project against the Java EE 8 API artifacts we shipped in WildFly 17, that deployment should run fine on WildFly 18. WildFly provides a number of maven boms for each release. These boms have been updated to use the Jakarta-based dependencies. In addition, the previous boms with maven ids org.wildfly.bom:wildfly-javaee8 and org.wildfly.bom:wildfly-javaee8-with-tools have been discontinued and new boms org.wildfly.bom:wildfly-jakartaee8 and org.wildfly.bom:wildfly-jakartaee8-with-tools have been introduced. Note that this name change does not indicate the WildFly 18 is not a Java EE 8 compatible server. We’re just aligning our names with Jakarta EE. Within the WildFly runtime, deployments don’t concern themselves with the Maven GAV of the API jars we provide. To the extent a deployment is concerned at all about the details of how EE API classes are made visible (which would not be common), it would be interested in the names of the JBoss Modules modules that provide the spec classes. All of the existing EE API modules from WildFly 17 still exist in 18 — with the same names — and provide the equivalent APIs so there is no need for deployment authors to make any changes. JDK 13 Our goal with WildFly is to have our releases run well for most use cases on the most recent GA JDK version available on the WildFly final release date. I’m pleased to report that this is the case with WildFly 18 and JDK 13. By run well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what the latest JVM means for their applications to be able to look to WildFly as a useful development platform. While we do want to run well on the most recent JDK, our recommendation is that you run WildFly on the most recent long-term support release, i.e. on JDK 11 for WildFly 18. We do considerably more testing of WildFly itself on the LTS JDKs, and we make no attempt to ensure the projects producing the various libraries we integrate are testing their libraries on anything other than JDK 8 or 11. WildFly 18 also is heavily tested and runs well on Java 8. We plan to continue to support Java 8 at least through WildFly 21, and probably beyond. Please note that WildFly runs on Java 11 and later in classpath mode. At this point it is uncertain whether we’ll be able to say that the release of WildFly that follows JDK 14 going GA will run well on 14. We’ll have to see how well the work for that, both in WildFly itself and in the projects we integrate, aligns with our other goals for that release. Jira Release Notes The full list of issues resolved is available here. Issues resolved in the WildFly Core 10 releases included with WildFly 18 are available here. Enjoy, and as always, thank you so much for your support of WildFly! ### [WildFly is Jakarta EE 8 Certified!](/news/2019/09/12/WildFly-is-Jakarta-EE-8-Certified/) Tuesday was a great day in the world of enterprise Java. It’s been a long road since Jakarta EE was born following Oracle’s announcement that stewardship of Java EE would be moving to the Eclipse Foundation. But after a lot of hard work by folks in the Jakarta community, Jakarta EE 8 has been released. Congratulations to everyone involved with the Jakarta EE Platform project and all the various spec projects. The ability to enhance enterprise Java standards under an open-source model should bring great benefits to our communities. I’m pleased to say that WildFly 17.0.1 has passed the Jakarta EE 8 TCK and our compatibility certification request has been approved by the Jakarta EE Spec Committee. So, WildFly is a Jakarta EE Full platform compatible implementation. We also remain a certified Java EE 8 compatible implementation. My thanks to the many people whose work on WildFly and Jakarta EE made this certification possible, particularly to Scott Stark and Scott Marlow, who put in a lot of long days and nights on this. TCKs are not simple things, something you can now find out for yourself, as the move to Jakarta means the TCKs are all open source! If you’re interested in the details of our certification request, they can be found at our certification repository. Onward to WildFly 18! ### [WildFly 17.0.1 is released!](/news/2019/07/07/WildFly-17-0-1-is-released/) WildFly 17.0.1 Final is now available for download. We had a number of important bug fixes ready to go so we decided to do a micro release for WildFly 17. I also wanted to blog a bit about using Galleon to update an existing Galleon-provisioned WildFly installation after a new release comes out. Jira Release Notes The full list of issues resolved in WildFly 17.0.1 is available here. Issues resolved in the WildFly Core 9.0.2 release included with WildFly 17.0.1 are available here. Using Galleon to Update a WildFly Installation As discussed in the WildFly 16 release announcement, you can use the Galleon tool to create a customized WildFly installation. Once you’ve done that, if a new WildFly release comes out you can use Galleon to update your installation. In this post I’ll walk through the basics of doing that. If you want to follow along with the examples, download the latest Galleon command line tool, unzip it and add the bin dir to your PATH. Feature-Packs and Channels The simplest command to install the latest version of WildFly into the directory my-wildfly is to call: $ galleon.sh install wildfly:current --dir=my-wildfly Most of that command is self-explanatory, but what about the wildfly:current part? That’s a feature-pack location or FPL. An FPL has a rich possible syntax, but most commonly you’ll see something simple like wildfly:current. This consists of two parts: wildfly — the name of the feature-pack current — the name of a channel from which the feature-pack should be consumed. A channel represents a source of backward compatible releases. A feature-pack may be available over numerous channels, with different channels restricting which versions of the channel are available. The current channel for WildFly feature-packs includes all versions. Use the list-feature-packs command to see what packs and channels are available: $ galleon.sh list-feature-packs =============== ============== ============ Product Update Channel Latest Build =============== ============== ============ wildfly current/final 17.0.1.Final wildfly 17.0/final 17.0.1.Final wildfly-core current/final 9.0.2.Final wildfly-core 9.0/final 9.0.2.Final wildfly-servlet current/final 17.0.1.Final wildfly-servlet 17.0/final 17.0.1.Final Feature-packs for wildfly, wildfly-core and wildfly-servlet are available, with wildfly-core and wildfly-servlet providing subsets of the traditional functionality of the WildFly application server. There are two channels for each, the current channel, which will have the latest release available, regardless of major/minor version, and then the 17.0 and 9.0 channels for wildfly/wildfly-servlet and wildfly-core respectively. The final in the Update Channel column for each channel indicates that the default frequency for the channel is final releases. This means that unless instructed otherwise by the user the Galleon tool when looking for releases from the channel will limit itself to final releases. When provisioning a new server to which you anticipate applying updates when new versions come out, it’s good to consider which channel you want, as that will become the default place the Galleon tool looks for future updates. When doing an update you can specify the channel to use, but if you don’t do that, the channel associated with the installation will be used. So, if you don’t want your WildFly 17 installation accidentally updated to WildFly 18, use the 17.0 channel. Installing and updating from the 17.0 Channel This blog is about updating an installation to 17.0.1.Final, so first we want to install 17.0.0. I’m going to install a customized build that uses the cloud-profile plus standard management functionality. $ galleon.sh install wildfly:17.0#17.0.0.Final --dir=my-wildfly --layers=cloud-profile,core-server,core-tools Note the #17.0.0.Final in the FPL. I included this because by default Galleon would install the latest final version in the channel, i.e. 17.0.1.Final. Since this post is about updating to 17.0.1 I didn’t want to start there, so I added a specific feature-pack version to the FPL. Normally you wouldn’t need to include that when provisioning a server. The get-info command tells us the status of the installation: $ galleon.sh get-info --dir=my-wildfly ======= ============ ============== Product Build Update Channel ======= ============ ============== wildfly 17.0.0.Final 17.0 If I’m working inside a Galleon-provisioned installation, then I don’t need the --dir=my-wildfly in all the commands: $ cd my-wildfly $ galleon.sh get-info ======= ============ ============== Product Build Update Channel ======= ============ ============== wildfly 17.0.0.Final 17.0 Use check-updates to find out if updates are available for an installation: $ galleon.sh check-updates Feature-packs resolved. Some updates and/or patches are available. ======= ============= ============ ============== Product Current Build Update Update Channel ======= ============= ============ ============== wildfly 17.0.0.Final 17.0.1.Final 17.0 And then, update to do the upgrade: $ galleon.sh update Galleon will prompt you with a y/n prompt to confirm. You can pass a --yes param to the update command to suppress this confirmation prompt. Note I’ve observed that if I’m inside an installation directory and update it, for subsequent commands Galleon throws exceptions, until I maneuver out of the directory and back in. $ galleon.sh get-info shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory Error occurred during initialization of VM java.lang.Error: Properties init: Could not determine current working directory. at java.lang.System.initProperties(Native Method) at java.lang.System.initializeSystemClass(System.java:1166) $ cd ../my-wildfly/ $ galleon.sh get-info ======= ============ ============== Product Build Update Channel ======= ============ ============== wildfly 17.0.1.Final 17.0 If for some reason you don’t like the result of a provisioning step, use the undo command to revert the most recent provisioning change (i.e. the update): $ galleon.sh undo $ cd ../my-wildfly/ $ galleon.sh get-info ======= ============ ============== Product Build Update Channel ======= ============ ============== wildfly 17.0.0.Final 17.0 Finally, same as with the install command, you can provide the FPL of the feature-pack to update. (Its dependencies will also be updated.) This can be useful, for example, if an installation was associated with the current channel but you want to be sure to only update to a WildFly 17 release. $ galleon.sh update wildlfy:17.0 --yes In that example I included the --yes param to tell Galleon to skip the y/n confirmation prompt. Dealing with a modified installation Of course in the real world you probably don’t provision a server, do nothing with it, and then update it. Instead, you probably modify the installation in some way after the initial install; e.g. add a deployment or use the CLI to change a configuration value. If you’ve done this, when you do an update, Galleon tracks the changes you have made and reapplies them. This asciinema recording shows this kind of workflow in action. It also demonstrates the Galleon CLI’s interactive shell, where you can provide a series of commands without having to type galleon.sh all the time. I start the recording after the initial provisioning. Enjoy, and as always, thank you so much for your support of WildFly! And many thanks to Jean-Francois Denise for his help with this post! ### [WildFly 17 S2I image has been released on quay.io!](/news/2019/06/20/WildFly-17-S2I-image-has-been-released-on-quay-io/) WildFly 17 S2I image on quay.io Starting with WildFly 17, the WildFly S2I Docker image is now accessible from quay.io at this URL: https://quay.io/repository/wildfly/wildfly-centos7 A companion image, a WildFly runtime Docker image that allows you to chain builds in OpenShift or use Docker multi stage builds, is available from: https://quay.io/repository/wildfly/wildfly-runtime-centos7 For a complete documentation on how to use these images using s2i, OpenShift and Docker, refer to this documentation. WildFly 17 S2I image and the WildFly Operator Images built with WildFly 17 or 16 S2I image can be managed by the WildFly Operator. Documentation on how to install the Operator and use it can be found in WildFly Operator. WildFly S2I implementation notes The WildFly S2I image that used to be developed in the repository openshift-s2i/s2i-wildfly is now developed in wildfly/wildfly-s2i repository. This image offers the same features that were provided by the WildFly 16 image. In addition, during S2I build you have now the ability to provision a WildFly server using Galleon. Documentation on how to configure S2I build and WildFly server execution can be found there. Chaining builds with runtime image In order to benefit from OpenShit chained builds or docker multi stage builds to build an application image that only contains what is required to execute WildFly (S2I tooling being removed), we have introduced a docker wildfly-runtime-centos7 image into which you can copy the WildFly server and deployed application from the WildFly S2I generated application image. This OpenShift template automates the chained builds to output a smaller application image. Adding imagestreams and template to OpenShift At some point the new images will be made available from OpenShift catalog and image repository. You can already use these images by adding them yourselves to your OpenShift cluster. WildFly S2I builder image stream: oc create -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-17.0/imagestreams/wildfly-centos7.json WildFly runtime image stream: oc create -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-17.0/imagestreams/wildfly-runtime-centos7.json Chained build template: oc create -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-17.0/templates/wildfly-s2i-chained-build-template.yml NB: If you import the image streams in your project, be sure to set ImageStreams Namespace to your project namespace in the template. openshift being the default namespace. ### [WildFly 17 is released!](/news/2019/06/10/WildFly-17-is-released/) I’m pleased to announce that WildFly 17 Final is now available for download. A lot of effort in this last quarter has gone into using WildFly in cloud environments, which I’ll expand on more below, but first I wanted to touch on improvements we’ve made in the main WildFly server. Clustering Improvements You can now use a separate subsystem for configuring distributed web session managers. This will help users avoid common configuration mistakes, and is also a prerequisite for the next two improvements. We have improved support for offloading session caching to an external Infinispan caching service by using adding a new HotRod-based distributed session manager. Applications that use HA singleton services can now register listeners to receive notifications when the service starts and stops, which will include information on which cluster member was elected as the new primary provider. If you configure session sharing between wars in an ear, you can now configure whether those sessions are handled with 'distributable' semantics. Being able to turn off 'distributable' semantics is necessary for applications that need to store non-serializable objects in the session. Messaging Improvements We’ve added support for messaging clusters behind http load balancers by disabling automatic topology updates on clients. (This allows the client to continue to address the load balancer rather than trying to communicate with the servers behind the load balancer.) The timeout the embedded messaging broker uses for opening journal files is now configurable. Configurability of connections to remote AMQ brokers has been enhanced. Other Notable Items Web access logs in JSON format can now be configured to use a formatted structure for main log message, instead of a simple opaque string. Elytron JDBC security realms now support hex encoding of hashes, passwords and salts. Support has also been added for mod_crypt encoding of passwords. The title of the HAL management console can now be customized by the user. Client-side resolution of properties can now be enabled without editing the CLI’s xml configuration file. WildFly in the Cloud As we continue with our quarterly delivery model, a major focus continues to be on making WildFly as easy and productive as possible to use on the cloud, particularly on Kubernetes and OpenShift. Quite a lot has happened this past quarter: First, there’s now a launcher allowing you to use WildFly as a backend runtime at https://launch.openshift.io ! Second, I’m very pleased to announce the first release of our WildFly Operator for Kubernetes/OpenShift. It’s available at operatorhub.io — try it out! Or even better lend a hand at https://github.com/wildfly/wildfly-operator . This is a key step in making it easier to manage WildFly-based applications in the cloud, with more to come. Finally, the Galleon-driven cloud image prototype work that Jean-Francois Denise described in March is making very good progress. It’s leading to the next generation of source-to-image (s2i) for WildFly. Later this week Jean-Francois will be uploading WildFly 17-based images to quay.io. In the meantime, I encourage you to learn more about these efforts or even have a go at building the images yourself. For those of you who have previously used the OpenShift s2i image for WildFly, please note that going forward development will be happening at the new source repo under the wildfly GitHub organization. JDK 12 and 13 Our goal with WildFly is to have our releases run well for most use cases on the most recent GA JDK version available on the WildFly final release date. I’m pleased to report that this is the case with WildFly 17 and JDK 12. By run well, I mean our main testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what the latest JVM means for their applications to be able to look to WildFly as their development platform. It may not always be possible to attain this goal, but it’s one we take seriously. Although JDK 13 is still in the EA stages, Richard Opalka continues to informally test WildFly against the EA releases as they come out and he reports that it is working well. While we do want to run well on the most recent JDK, our recommendation is that you run WildFly on the most recent long-term support release, i.e. on JDK 11 for WildFly 17. We do considerably more testing on the LTS JDKs. WildFly 17 also is heavily tested and runs well on Java 8. We plan to continue to support Java 8 at least through WildFly 18, and probably beyond. Please note that WildFly runs on Java 11, 12 and 13 in classpath mode. Jira Release Notes The full list of issues resolved is available here. Issues resolved in the WildFly Core 9 releases included with WildFly 17 are available here and here. Enjoy, and as always, thank you so much for your support of WildFly! ### [Zulip Chat](/news/2019/04/23/Zulip-Chat/) After HipChat got closed down earlier this year we evaluated a few alternative chat solutions. During this period we temporarily moved community discussions back to IRC (#wildfly on Freenode). We found that Zulip worked well for us and have now settled on this as our main chat tool. Thanks to the people at Zulip for their open source license! To join in, go to https://wildfly.zulipchat.com and sign up. The most obvious stream to join is #wildfly-users for user questions. If you want to get involved in development, or keep tabs on what we are up to, #wildfly-developers. We also have more specific streams for development of larger app server areas (e.g. #wildfly-elytron and #undertow). ### [Onward to WildFly 17 and Beyond!](/news/2019/03/09/Onward-to-WildFly-17-and-Beyond/) Following the release of WildFly 16, I thought it would be a good time to give the WildFly community a sense of what I see coming in the project over the next few releases. WildFly will continue with the quarterly delivery model we began last year with WildFly 12. These releases are essentially time-boxed; i.e. we typically won’t significantly delay a release in order to get a feature in. So when I discuss general feature roadmaps I’ll be talking in terms of the next two or three releases rather than just WildFly 17. WildFly on the Cloud A major focus will be on making WildFly as easy and productive as possible to use on the cloud, particularly on Kubernetes and OpenShift. In particular we’ll be working on the following: Creation of an Operator to help automate best practices for deploying and managing a WildFly-based application on Kubernetes and OpenShift. Work on this has just kicked off; we’d love to have your participation! Continuation of our efforts to use Galleon to make WildFly a truly "cloud native" application server. This will involve a number of areas, including: Further development and greater testing of the Galleon layers provided by WildFly. Enhancements to the Galleon tooling for creating feature-packs. Fleshing out the image build processes. Adding an openshift.io launcher for WildFly and enhancing it as best practices for cloud-native application development evolve. Improved support for offloading session caching to an external Infinispan caching service by using a HotRod-based distributed session manager. Jakarta EE Of course, the EE standards are very important to WildFly. We’re very focused on Jakarta EE, with a number of members of the WildFly community involved in the various specs. We’re keeping a close eye on the finalization of Jakarta EE 8 with certification a high priority. As work on Jakarta EE 9 ramps up we’ll be active participants, although I don’t expect significant change in WildFly related to EE 9 until the fall at earliest. Security Darran Lofthouse and Farah Juma do an excellent job of maintaining a roadmap for security-related work in WildFly. I encourage you to read Darran’s recent blog post to learn more about what’s coming in WildFly 17. Other Items Besides the broader topics I’ve touched on above, there are always individual items that are in progress. Here are a few noteworthy ones: Support for messaging clusters behind http load balancers by disabling automatic topology updates on clients. (This allows the client to continue to address the load balancer rather than trying to communicate with the servers behind the load balancer.) WFLY-6143 — Ability to configure server-side EJB interceptors that should apply to all deployments. Client-side interceptors are also being considered. WFCORE-1295 — Support for expression resolution for deployment descriptors parsed by WildFly Core, e.g. jboss-deployment-structure.xml and permissions.xml. WFCORE-4227 — Ability for the CLI SSL security commands to be able to obtain a server certificate from Let’s Encrypt. In the clustering area: WFLY-5550 — A separate subsystem for configuring distributed web session managers. This will help users avoid common configuration mistakes, and is also a prerequisite for the aforementioned HotRod-based distributed session manager and for…​ WFLY-6944 — Support for encoding web session affinity using multiple routes, if supported by the load balancer. WFLY-11098 — Support for Singleton Service election listeners. Future Work I regularly hear from community members asking about MicroProfile. Last year we added subsystems to bring support of MicroProfile Config, Health, Metrics and OpenTracing. The overall focus there was on "observability" of WildFly, particular in the cloud. These subsystems were oriented toward allowing monitoring and management tooling to observe the behavior of WildFly servers. The MicroProfile specs were a good choice because observers want to work in a standardized way. As this year continues we’ll think about adding support for some other MicroProfile specifications, perhaps as new subsystems within the main WildFly codebase, or perhaps via new projects in the WildFly Extras organization along with a Galleon feature-pack and a Galleon layer to allow easy integration into a WildFly installation. I suspect anything on this would be in WildFly 18 or later. WildFly Feature Delivery Process / Following Development I’d love to have input both into our roadmap and into the requirements for the implementations of features. If you’re interested in following WildFly feature development one thing to do is to monitor the WFLY and WFCORE projects in JIRA. Beyond that I encourage you to subscribe to the wildfly-dev mailing list. It’s relatively low traffic, and I’ve been encouraging folks to post a brief note to the list when work on a new feature kicks off. So that’s a good way to hear early on about work to which you may have something to add. When we went to the quarterly time-boxed release model, we formalized our feature development process quite a bit. In order to reliably release on time, we needed to be sure that features were truly ready for release before they ever got merged. No more merging things that were 90% done with the expectation of further improvements before the final release. To help facilitate this we started requiring the creation of an asciidoc analysis document at the start of feature work. This document is meant to cover: Who is going to work on the feature, both in terms of development and of testing. What the requirements for the feature are. (This IMHO is the most important part.) How the feature will be tested. How the feature will be documented. (Some form of documentation is required, either in the WildFly docs or, for simple things, in the software itself, e.g. in help messages.) The analysis documents are all submitted as github pull requests to a github repo we created for them. Discussion of the document is done via comments on and updates to the PR. The document remains unmerged until the feature code itself is merged. The analysis is meant to be a living document, revised as necessary as new things are learned as the feature is developed. One of the goals we had with all this is encourage community input to the feature requirements. So I very much encourage you to have a look at and comment on the PRs for any features in which you’re interested. The announcement posts to wildfly-dev that I mentioned are meant to inform you when new PRs are submitted. Key WildFly 17 Schedule Dates Following are the expected key dates associated with the WildFly 17 release: Fri, May 10 — Completion date for features coming in via WildFly Core Tue, May 14 — All features ready Wed, May 15 — WildFly 17 Beta. No new features after this date. Fri, May 24 — All changes for WildFly Core ready Tue, May 28 — All changes for WildFly ready Thu, May 30 — WildFly 17 Final released Finally, thanks, as always, for your interest in and support of WildFly! ### [WildFly 16 and Galleon, towards a cloud native EE application server](/news/2019/03/01/WildFly-16-and-Galleon-towards-a-cloud-native-EE-application-server/) This post has been co-authored with Jorge Morales and Josh Wood from the OpenShift Developer Advocacy Team. Jorge is passionate about Developer experience, Java programming, and, most importantly, improving the integration of Red Hat’s Middleware into the OpenShift platform. Josh is committed to constructing the future of utility computing with open source technologies like Kubernetes. Problem space Containers are becoming the default deployment strategy for applications in the enterprise. We’ve seen the software packaged in those containers adapt to this new deployment paradigm. The WildFly team was an early adopter of container technology, driven by running our software on Red Hat’s OpenShift Container Platform. However, only recently have we started adapting WildFly to take advantage of the “cloud-native” features of containers and platforms like Kubernetes and OpenShift, such as elasticity, scalability, and lifecycle automation. We maintain a pair of WildFly container images. One is a classic container for Docker and other Open Container Image (OCI) compatible runtimes. The second is a variant incorporating OpenShift’s Source-to-Image (s2i) mechanism to work with the platform’s build support. Both have been updated with each WildFly version since WildFly 8. In that time, we’ve learned a lot about what’s needed to make WildFly and the WildFly container images for OpenShift and Kubernetes more cloud-native — more able to take advantage of the facilities of the environments where they run today. We’ve gathered feedback from many sources, including upstream developers as well as enterprise end-users and customers, and we’ve tried to apply their insight to our own experience. One recurring theme we’ve heard about is image sizes. The size of a WildFly container image is driven by these three factors: The size of the base layer, or FROM image, that typically provides the essential Operating System user space including the runtimes needed for a Java application. The size of the WildFly runtime added to the image. The size of the application itself. We can only control the second factor, the size of the WildFly runtime added to the image. In this post, we introduce some experiments we’ve been working on, with the aim of producing more “cloud-native” WildFly image for OpenShift or any other Kubernetes-based container platform Intro to Galleon Galleon is a provisioning tool for working with Maven repositories. Galleon automatically retrieves released WildFly Maven artifacts to compose a software distribution of a WildFly-based application server according to a user’s configuration. With no configuration, Galleon installs a complete WildFly server. Users can express which configuration, such as standalone only, or which set of features, such as web-server, jpa, jaxrs, cdi, etc., they want to install. WildFly Galleon Layers Starting with WildFly 16, we can use Galleon layers to control the set of features present in a WildFly server. A Galleon layer identifies one or more server features that can be installed on its own or in combination with other layers. For example, if your application, some-microservice, makes use of only the jaxrs and cdi server features, you can choose to install just the jaxrs and cdi layers. The configuration in standalone.xml would then contain only the required subsystems and their dependencies. If you want to follow along with the examples, download the latest Galleon command line tool. Using the Galleon cli tool, creating such a jaxrs and cdi-only server distribution would look like: galleon.sh install wildfly:current --layers=jaxrs,cdi --dir=my-wildfly-server This command installs the jaxrs and cdi layers of the latest released version of WildFly (wildfly:current argument) into the my-wildfly-server directory specified in the --dir argument. The my-wildfly-server directory will contain only the artifacts needed to run your application. Here’s a list of commonly used layers. You can find a complete list of wildfly layers in the WildFly Admin Guide web-server: Servlet container cloud-profile: Aggregates layers often required for cloud applications. jaxrs, cdi, jpa (hibernate), and jms (external broker connections) core-server: Aggregates management features (management, elytron, jmx, logging, and others) core-tools: Contains management tools (jboss-cli, add-user, and others) To provision a lightweight microservice with the management features, run a command like: galleon.sh install wildfly:current --layers=cloud-profile,core-server,core-tools --dir=my-wildfly-server Galleon also defines an XML file to describe an installation in a fine-grained way. The following provisioning.xml file provisions a WildFly server with support for jaxrs: <installation xmlns="urn:jboss:galleon:provisioning:3.0"> <feature-pack location="wildfly@maven(org.jboss.universe:community-universe):current"> <default-configs inherit="false"/> <packages inherit="false"/> </feature-pack> <config model="standalone" name="standalone.xml"> <layers> <include name="jaxrs"/> </layers> </config> <options> <option name="optional-packages" value="passive+"/> </options> </installation> In a nutshell, this file captures the following installation customizations: Do not include default configurations. Do not include all packages (JBoss Module modules and other content). Generate a standalone.xml configuration that includes only the jaxrs layer. Include only packages related to the jaxrs layer (option passive+). Using the Galleon CLI tool’s provision subcommand, we can install from an XML provisioning file like the example above: galleon.sh provision <path to XML file> --dir=my-wildfly-server This asciinema recording shows these CLI commands in action, as well as the generated server content and image sizes. Creating a WildFly server with OpenShift builds By coupling OpenShift build features with Galleon, we can create customized images according to application requirements. S2I image for Galleon For this demonstration, we built an S2I image that adds Galleon tools to the WildFly S2I image. When building your source code into this image, both the application and server are built. The S2I build process looks for the presence of a provisioning.xml file at the root of the application project. If it finds one, it is used as input to Galleon to provision the server it defines. The S2I image has been deployed on quay.io. Note You must add this image stream in OpenShift to continue following the example: oc create -f https://raw.githubusercontent.com/jorgemoralespou/s2i-wildfly-galleon/master/ose3/galleon-s2i-imagestream.yml Two Build Stages Optimize Production Image Size In this OpenShift template that automates the build and deployment, we’ve split the build to create 2 separate images: A “development” image built from the Galleon S2I image. This is a “fat” image containing all of the tooling to build the application (JDK, Maven, Galleon, …). This image is runnable, but it consumes a larger amount of resources. We build it first to produce the artifacts we need for an optimized image intended for production. A “production” image, built from JRE-8, into which the WildFly server and .war files are copied. This image has a smaller footprint. It contains only the dependencies needed to run the WildFly server and the application. The template creates a deployment for each image. The “development image” is the primary deployment and scaled to 1 instance, the “production image” is a replica and scaled to 0 instances. When one wants to use the “production image”, this would need to be scaled to 1, and the route will need to be balanced to this “production” deployment. To be conservative on resources, the “development” deployment can be downscaled to 0. You can add the template to your OpenShift project by running: oc create -f https://raw.githubusercontent.com/jorgemoralespou/s2i-wildfly-galleon/master/ose3/galleon-s2i-template.yml Building the development image We use OpenShift’s s2i support to build the application. Note the s2i-wildfly-galleon:16.0.0.Final image stream specified in this BuildConfig excerpt: source: git: ref: master uri: https://github.com/jorgemoralespou/s2i-wildfly-galleon contextDir: test/test-app-jaxrs type: Git strategy: sourceStrategy: from: kind: ImageStreamTag name: s2i-wildfly-galleon:16.0.0.Final type: Source Once this build is complete, the server is installed in /output/wildfly and the compiled application is written to /output/deployments/ROOT.war. Building the production image This build stage only needs to copy the /output/wildfly directory and /output/deployments/ROOT.war file into a new image. The copy operations comprise most of our production image Dockerfile. It also sets the CMD to start the server when the container image runs: FROM openjdk:8-jre COPY /wildfly /wildfly COPY /deployments /wildfly/standalone/deployments EXPOSE 8080 CMD ["/wildfly/wildfly/bin/standalone.sh", "-b", "0.0.0.0"] OpenShift BuildConfig excerpt: images: - from: kind: ImageStreamTag name: dev-image:latest paths: - sourcePath: /output/wildfly destinationDir: "." - from: kind: ImageStreamTag name: dev-image:latest paths: - sourcePath: /output/deployments destinationDir: "." Sample Applications We have developed 3 sample applications to exercise our experimental Galleon S2I image: A simple web server app that serves an HTML and JSP page (derived from the OpenShift sample app). Its provisioning.xml file tells Galleon to provision a WildFly server configured with the web-server layer. A toy JSON endpoint app that depends on jaxrs to expose a simple service that returns some JSON. Its provisioning.xml file tells Galleon to provision a WildFly server configured with the jaxrs layer. Some JBoss Module modules, such as the datatype providers, are useless in this image and can be excluded by Galleon. This makes the server’s footprint even smaller. A persistent state demonstration app that depends on jaxrs, cdi, and jpa to persist user-created tasks (derived from the tasks-rs WildFly quickstart). Postgresql is used as the storage backend. This sample app’s provisioning.xml file tells Galleon to provision a WildFly server configured with cdi,jaxrs,and jpa layers. Running the jaxrs JSON endpoint sample application Note You must have added both the image stream and template to your OpenShift project. Click on “Add to Project/Select From Project” then select the template “App built with Galleon S2I image and optionally connect to DB”. Choose an Image name. The GIT repository is https://github.com/jorgemoralespou/s2i-wildfly-galleon, sub directory is test/test-app-jaxrs. By default we are using the S2I Image Version 16.0.0.Final. This image has all WildFly artifacts present in the local Maven repository, making provisioning of the WildFly server faster. When using the latest image tag, the artifacts of the latest released WildFly server are retrieved from remote repositories. You can ignore the Postgresql JDBC URL and credentials, they are not used by this sample. Click on Create The development image starts to build. When it is complete, the build of the production image starts. Once both are built, the 2 deployments are created on the OpenShift cluster and a route is created through which external clients can access the JSON service. Note Only the development image will have an active instance. The production image is scaled to 0 to save on resources, and the route is balanced to send all traffic to the development image. If you want to use/test the production image, you’ll need to change the scaling of both deployments and the weights used in the route. Adding Features to WildFly Developers frequently need to customize server configurations to match their applications. For example, we often need to add a JDBC driver and datasource. In the following example, we extend the server configuration with a PostgreSQL driver and datasource. Problems we need to solve: Add a JBoss Module module for the PostgreSQL driver to the WildFly installation. Add the driver to the standalone.xml configuration file. Add a datasource to the standalone.xml configuration file. Datasources must be configured with contextual information. The JDBC url, user, and password are specific to a deployment and can’t be statically set in the server configuration. We need to adapt the configuration to the container execution context. Galleon can help us solve these problems. Using the Galleon API to package a JDBC driver as a Galleon feature-pack Note The creation of custom Galleon feature-packs is an advanced topic. The API and overall technique may change in the future. Galleon has a concept called the feature-pack. The WildFly feature-pack is retrieved when installation occurs. A feature-pack (a zip file) contains features, configurations, layers, and content such as modules and scripts. Features are used to assemble a WildFly configuration. We have been using the Galleon FeaturePack Creator API to build a PostgreSQL feature-pack that extends the standalone.xml configuration with a driver and contains the postgresql driver jar file packaged as a JBoss Module module. This feature-pack can then be installed on top of an existing WildFly installation to provision the PostgreSQL driver configuration and module. Once the feature-pack is installed, the WildFly server has the plumbing it needs to connect to a PostgreSQL server. We’ve solved problems 1) and 2), above. Evolving provisioning.xml with the PostgreSQL feature-pack and datasource As we saw earlier, Galleon allows you to describe the content of an installation in an XML file, called provisioning.xml by convention. We are going to evolve this file to describe both the server and the driver to install. In addition, we extend the standalone configuration with a datasource. The resulting provisioning.xml file contains a complete description of the server installation. We use environment variables to represent the JDBC URL, user, and password so they can be resolved for each running instance of the container. Postgresql feature-pack installation inside S2I image The Postgresql feature-pack was built for the purposes of this demonstration. It is not present in public Maven repositories. You can fetch it from this location, then install it in a local Maven repository. In order to inform S2I assembly that some feature-packs must be downloaded and installed locally, the file local-galleon-feature-packs.txt must be present at the root of your project. Each desired feature-pack is specified with two lines in this file, a line for the feature-pack URL followed by a line naming the path inside the local Maven repository: https://github.com/jfdenise/galleon-openshift/releases/download/1.0/postgresql-1.0.zip org/jboss/galleon/demo/postgresql/1.0/ Running the postgresql sample application Before these steps, you must deploy a PostgreSQL server in your project and create a database on it. Click on “Add to Project/Select From Project” then select the template “App built with Galleon S2I image and optionally connect to DB”. Choose an Image name. The GIT repository is https://github.com/jorgemoralespou/s2i-wildfly-galleon, sub directory is test/test-app-postgres. By default we are using the S2I Image Version 16.0.0.Final. If needed, replace the host, port and database of the JDBC URL. Set the Postgres user name and password. Click on Create The build of the development image starts. When completed, the build of the production image starts. Once the two images are built, the deployments are created and a route added through which you can access the service. To add a new task, open a terminal and run curl -i -H "Content-Length: 0" -X POST http://<your route hostname>/tasks/title/task1 Reduced server footprint When using Galleon layers to provision a WildFly server, the image size as well as runtime memory consumption varies according to the set of installed features. Here are the total file sizes and for the servers we have provisioned in this post. As a reference, a complete WildFly server is around 216MB. Table 1. WildFly server Feature Size cdi, jaxrs, jpa 122 MB jaxrs 57 MB jaxrs with JSON data binding provider only 49 MB web-server 43 MB Full server 216 MB Table 2. Sample memory sizes used by the WildFly server process App Features installed (layers) Actual mem used Full server mem used PostgreSQL sample app cdi, jaxrs, jpa 30 MB 35 MB jaxrs sample app jaxrs 19 MB 28 MB jsp sample app web-server 16 MB 27 MB Conclusions One of the beauties of cloud platforms is that (ideally) you don’t need to care that much about the infrastructure that runs your application. As a developer, you focus on creating your application logic, and then rely on the platform, OpenShift, to keep it available at all times, providing scalability and failover. Your application may run on any worker node in the cluster. These worker nodes must download the container images before running the application. The time it takes to download these images is reduced by reducing the image sizes, although it’s not the only factor. Intelligent use of the filesystem layering inside the container image is also key. Nevertheless, a simple rule still holds: Take only what you need. Removing inessential components not only speeds things up by making images smaller, it also helps reduce the vulnerability surface of the image. A bug can’t be exploited if it is not installed. Producing smaller, more focused container images is a step toward a more cloud-ready WildFly application server, but it’s not the only thing we’re working on. Integrating with more of the cloud platform’s capabilities will be a topic for a later post. One last remark: everything here described is not part of the project and hence not supported. ### [WildFly 16 is released!](/news/2019/02/27/WildFly-16-is-released/) WildFly 16 Final is now available for download! Provisioning WildFly with Galleon As we continue with our quarterly delivery model, a major focus over the next few quarters will be on making WildFly as easy and productive as possible to use on the cloud, particularly on Kubernetes and OpenShift. An important requirement for the cloud is to be able to reduce the footprint of your server to what you need to run your application, eliminating unneeded runtime memory overhead, cutting down image size and reducing the possibility for security vulnerabilities. So, I’m very excited to announce Tech Preview support for use of the Galleon provisioning tool to allow you to easily provision a slimmed down server tailored toward REST applications. By easily, I mean a simple command that provisions a server that provides the technologies you want, with a correct configuration, and with unneeded libraries not present on disk. Being able to do this is an important piece of foundational technology that we’ll be building upon over the course of 2019, particularly with tooling and best practices aimed at taking advantage of Galleon when creating cloud images. Galleon provisioning isn’t just useful in cloud; users running on bare metal or virtualized environments can get the same benefits. Easy server slimming has been a goal for as long as I’ve been involved with JBoss AS! To use Galleon, download and unzip the Galleon tool. To install the latest final version of WildFly into the directory my-wildfly-server call: galleon.sh install wildfly:current --dir=my-wildfly-server That’s not so interesting as the result is equivalent to unzipping the standard download zip. Note WildFly still provides the usual zip / tar.gz. Using Galleon is not required to use WildFly. The real power comes when using the Galleon layers that WildFly provides to limit your installation to just the technologies you need. For example, if all you want is jaxrs and cdi: galleon.sh install wildfly:current --dir=my-wildfly-server --layers=cdi,jaxrs The result is an installation that doesn’t include unnecessary modules, has a correct configuration and has less than a third of the disk footprint of the standard WildFly distribution. And you don’t have to worry about knowing and specifying technologies required by the ones you know you want (e.g. the servlet support that jaxrs needs). Galleon handles that for you. If you’re ok with a slightly bigger footprint in order to have common WildFly Core management functionality, add the core-server and core-tools layers: galleon.sh install wildfly:current --dir=my-wildfly-server --layers=cdi,jaxrs,core-server,core-tools WildFly 16 provides a rich set of layers oriented toward letting optimize your server for running HTTP applications. For further details, see the WildFly Admin Guide and the Galleon documentation. Please give Galleon provisioning a try and give us feedback! We’d love to hear about your use cases and how Galleon can be improved to meet them. We’ll be doing more articles and blog posts explaining how to take advantage of this technology. JDK 12 While the GA version of JDK 12 has not been released yet (it is in the Release Candidate phase), we are pleased to report that WildFly 16 should run well on JDK 12 once it is GA. I’d like to especially thank Richard Opalka and Matej Novotny for their efforts in making this happen. Our goal with WildFly is to have our releases run well for most use cases on the most recent GA JDK version available on the WildFly final release date. If practical we’ll try and run well on release candidates for upcoming JDK versions as well, which we’ve achieved with WildFly 16. By run well, I mean our main testsuite runs with no more than a few failures in areas not expected to be commonly used. (In the JDK 12 case we have no failures.) We want developers who are trying to evaluate what the latest JVM means for their applications to be able to look to WildFly as their development platform. It may not always be possible to attain this goal, but it’s one we take seriously. While we do want to run well on the most recent JDK, our recommendation is that you run WildFly on the most recent long-term support release, i.e. on JDK 11 for WildFly 16. We do considerably more testing on the LTS JDKs. WildFly 16 also is heavily tested and runs well on Java 8. We plan to continue to support Java 8 at least through WildFly 18. Please note that WildFly runs on Java 11 and 12 in classpath mode. Messaging Improvements MDBs can be configured to belong to multiple delivery groups, with delivery only enabled only when all the delivery groups are active. Users can use standard Java EE 8 resource definitions (annotations or xml) to define JMS resources that connect to a remote Artemis-based broker (including AMQ-7 instances). Users can configure the maximum amount of memory that the embedded messaging broker can use to store messages for its addresses before they are considered "full" and their address-full-policy starts to apply (e.g. to drop messages, block producers, etc.) Clustering Improvements When WildFly servers behind a mod_cluster load balancer start they will instruct the load balancer to gracefully ramp up their load over the first minute or so of operation, instead of having the balancer send the maximum possible amount of traffic, possibly overwhelming the server. Users running a cluster with HA Singleton deployments or services can connect with the CLI to any cluster member and determine which node is the primary provider of a given deployment or service. Other Notable Items You can use the CLI to list which modules are visible to a deployment. This is helpful in analyzing classloading issues. In a WildFly managed domain, you can suspend and resume all of the servers managed by a particular Host Controller. Previously suspending or resuming multiple servers was limited to all servers in the domain or those in a particular server group. When using Elytron, HTTP Basic authentication mechanism can be configured to only operate in 'silent mode', only sending a challenge if the request contained an authorization header. Jira Release Notes The full list of issues resolved is available here. Issues resolved in the WildFly Core 8 release included with WildFly 16 are available here. ### [New WildFly Project Lead](/news/2019/01/07/New-WildFly-Project-Lead/) I am very excited to announce that Brian Stansberry (@bestansberry) will be taking on the role of WildFly project lead. Brian has been a major contributor to the project for almost 15 years now. During this time, he led a number of critical and complex subsystems including Clustering, Management, and most recently the cross-cutting cloud integration work. He is also one of our most active reviewers, and has helped many contributors navigate deep WildFly internals. Congratulations Brian! It’s been a great journey, so I want to think each and every one of you for your contributions and support over the years. Our work as a community has frequently pushed the envelope, and led to WildFly being one of the most innovative and popular application servers available. While I will be moving on from this role, I won’t be too far way, still participating but tackling a new challenge (I’ll have more to say about that in the future). With Brian at the helm, and all the great folks contributing to the project, I know WildFly has a bright future. I look forward to seeing the next chapter. Turn the page. -Jason ### [WildFly 15 is released!](/news/2018/12/13/WildFly-15-is-released/) WildFly 15 Final is now available for download! This is our fourth release following our quarterly delivery model. The major objective of this year’s release plan was to deliver EE8 functionality in incremental chunks over the first three quarters, and then to ensure WildFly ran well on the latest long term support version of Java. Accordingly, in this fourth release our focus was less on new features and more on polishing our support for JDK 11. JDK 11 Support The modularization of the JVM that began with Java 9 has a significant impact on a complex server like WildFly, particularly in the areas of classloading and reflection, both of which are extensively used in any application server. Since the early days of Java 9 development we’ve been working to ensure that not only the WildFly code itself, but also the scores of libraries we integrate, would all run well on the later generation JVMs. Specifically we wanted to be sure we ran well on the first long term supported Java version under the new Java SE release cadence, Java 11. We’re proud to say we’ve achieved that goal in our first quarterly release since Java 11 itself went GA. WildFly 15 also is heavily tested and runs well on Java 8. We also do testing with non-LTS releases like Java 9 and 10, and aim to run reasonably well for most use cases on those, but the primary aim of that kind of testing is to identify problems early enough to resolve them for the upcoming LTS release. Please note that WildFly runs on Java 11 in classpath mode. Server Observability Continuing the effort from WildFly 14 to improve the ability of tools to observe the behavior of WildFly in a container environment, in WildFly 15 we added a new subsystem that brings tech-preview support for MicroProfile Metrics. Application authors can declare their own application-scoped metrics, and those as well as base metrics will be available in Prometheus or JSON format over a new /metrics context on the HTTP management interface. SNI Support for HTTPS Listeners WildFly 15 supports server side SNI on its HTTPS listeners. This allows a WildFly instance listening on a single socket but with multiple virtual hosts associated with that listener to provide a different server certificate depending on what SNI name the client requests. Default SSL Context Setting a simple attribute on the Elytron subsystem ensures that as the server is started a JVM-wide default SSLContext is registered for use by any libraries within the application server that support use of the default context. JASPIC Integration with Elytron The Elytron subsystem now provides support for the Servlet Container Profile of the JSR-196 Java Authentication SPI for Containers spec. Jira Release Notes The full list of issues resolved is available here. Issues resolved in the WildFly Core 7 release included with WildFly 15 are available here. ### [Using Git for configuration history](/news/2018/09/28/Using-Git-for-configuration-history/) Until now the history of configuration in WildFly was using the folder + filename pattern. Now we have moved to a proper SCM integrating Git to manage history. You can now take advantage of a full Git support for your configuration history: every change in your configuration is now a commit. you can use branches to develop in parallel. you can create tags for stable points in your configuration. pull configuration from a remote repository. push your configuration history to a remote repository. use the git-bisect tool at your disposal when things go wrong. Now if we execute a management operation that modifies the model, for example adding a new system property using the CLI: [standalone@localhost:9990 /] /system-property=test:add(value="test123") {"outcome" => "success"} What happens is: The change is applied to the configuration file. The configuration file is added to a new commit. Important The notion of configuration has been updated with the Git support. It covers more than 'just' the standalone.xml history but also the content files (aka managed deployments). Thus even your deployments are in history, which makes sense in a way since those deployments appear in the configuration file. Starting with a local Git repository To start using Git you don’t have to create the repository, WildFly can do that for you. Just start your server with the following command line: $ __WILDFLY_HOME__/bin/standalone.sh --git-repo=local --git-branch=my_branch If a --git-branch parameter is added then the repository will be checked out from the supplied branch. Please note that the branch will not be automatically created and must already exist in the repository. By default, if no parameter is specified, the branch master will be used. If a --git-branch parameter is added then the repository will be checked out from the supplied branch. Please note that the branch will not be automatically created and must already exist in the repository. By default, if no parameter is specified, the branch master will be used. Starting with a remote Git Repository To start WildFly with a configuration from a remote Git repository is simple too, just use the following command line: $ __WILDFLY_HOME__/bin/standalone.sh --git-repo=https://github.com/USER_NAME/wildfly-config.git --git-branch=master Important Be careful with this as the first step is to delete the configuration files to avoid conflicts when pulling for the first time. Note Note that you can use remote aliases if you have added them to your .gitconfig. Snapshots In addition to the commits taken by the server as described above, you can manually take snapshots which will be stored as tags in the Git repository. The ability to take a snapshot has been enhanced to allow you to add a comment to it. This comment will be used when creating the Git tag. This is how you can take a snapshot from the JBoss CLI tool: [standalone@localhost:9990 /] :take-snapshot(name="snapshot", comment="1st snapshot") { "outcome" => "success", "result" => "1st snapshot" } You can also use the CLI to list all the snapshots: [standalone@localhost:9990 /] :list-snapshots { "outcome" => "success", "result" => { "directory" => "", "names" => [ "snapshot : 1st snapshot", "refs/tags/snapshot", "snapshot2 : 2nd snapshot", "refs/tags/snapshot2" ] } } To delete a particular snapshot: [standalone@localhost:9990 /] :delete-snapshot(name="snapshot2") {"outcome" => "success"} Note Note that this is a real Git repository, thus using the git client of your choice you can list those tags, or browse the history. Publishing You may 'publish' your changes on a remote repository (provided you have write access to it) so you can share them. For example, if you want to publish on GitHub, you need to create a token and allow for full control of the repository. Then use that token in an Elytron configuration file like this: <?xml version="1.0" encoding="UTF-8"?> <configuration> <authentication-client xmlns="urn:elytron:1.1"> <authentication-rules> <rule use-configuration="test-login"> </rule> </authentication-rules> <authentication-configurations> <configuration name="test-login"> <sasl-mechanism-selector selector="BASIC" /> <set-user-name name="$GITHUB_USERNAME" /> <credentials> <clear-password password="$GITHUB_TOKEN" /> </credentials> <set-mechanism-realm name="testRealm" /> </configuration> </authentication-configurations> </authentication-client> </configuration> Then, to publish your changes: [standalone@localhost:9990 /] :publish-configuration(location="origin") {"outcome" => "success"} References For the official documentation regarding Git history : Official Documentation. ### [WildFly 14 is released!](/news/2018/08/30/WildFly-14-is-released/) WildFly 14 Final is now available for download! EE8 Certified!! I am happy to announce that the WildFly 14 release is Java EE8 Certified! Since WildFly is now certified, the default EE7 mode and EE8 preview option have been dropped. The server now only provides EE8 APIs in all run modes. Since Java EE8 is backwards compatible with EE7, applications developed against EE7 (and earlier) will still run on WildFly 14. This is our third release following our new quarterly delivery model. A major theme of this plan, was to deliver EE8 functionality in fully completed incremental chunks, as opposed to waiting for everything to finish in a big bang release. This goal has now been completed, and we greatly appreciate the feedback and support from the community during this process. We plan to continue this model going forward. An overview of the new and updated standards in Java EE8 are as follows: Name From Version From JSR To Version To JSR Java Servlet 3.1 JSR-340 4.0 JSR-369 Contexts and Dependency Injection for Java 1.2 JSR-346 2.0 JSR-365 Bean Validation 1.1 JSR-349 2.0 JSR-380 JavaServer Faces 2.2 JSR-344 2.3 JSR-372 JavaMail 1.5 JSR-919 1.6 JSR-919 Java API for RESTFul Web Services 2.0 JSR-339 2.1 JSR-370 Java API for JSON Processing 1.0 JSR-353 1.1 JSR-374 Java API for JSON Binding - - 1.0 JSR-367 Common Annotations for the Java Platform 1.2 JSR-250 1.3 JSR-250 Java EE Security - - 1.0 JSR-375 Java Persistence 2.1 JSR-338 2.2 JSR-338 MicroProfile Capabilities Another major improvement in WildFly 14 is the inclusion of a number of important MicroProfile standards that are useful for running in container environments. These include: MP Config MP OpenTracing MP Health High Performance Connection Pool Also new in WildFly 14, is a new high performance direct connection pool backed by the Agroal project. Since this is a new pooling implementation, it must be explicitly enabled to take advantage of it. By default, the existing JCA based implementation (IronJacamar) is still used; however, in a future release, Agroal may become the new default. For more information, please see the WildFly 14 documentation. Mod-Cluster Multiplicity Mod cluster support within WildFly previously only supported a single web server listener and server configuration on a WildFly instance. Mod-cluster has now been enhanced to support multiple web server configurations by adding the ability to declare and reference multiple mod-cluster configurations within its subsystem. Jira Release Notes The full list of issues resolved is available here. ### [What's New in WildFly Management Console](/news/2018/06/01/What-s-New-in-WildFly-Management-Console/) WildFly 13 comes with a management console (HAL) which has been rewritten from scratch. HAL still uses a similar technical stack (GWT) and user experience, but now fully adopts PatternFly. More important we enhanced the existing features and added support for many new subsystems and attributes. The following sections show some highlights of the latest version. For more details about the new features see the release notes for HAL 3.0.0.Final. Finder The column based navigation (finder) has been greatly improved. You can now use the cursor keys for navigation inside and across columns. To open an application view press ↵ (enter), to go back press ⌫ (backspace). Items in one column are now ordered alphabetically by default. You can pin frequently used items to stay at the top. Most columns offer a filter which can be used to quickly find the items you’re looking for. Finally the previews have been enriched and provide detailed documentation or the main attributes of the selected item. If appropriate the previews contain action links for the most common tasks. Figure 1. Finder Applications Applications provide a new breadcrumb at the top to quickly switch between items of the same kind. More complex applications can include a vertical navigation. Finally most applications can be easily opened in an external window and provide an expert mode which uses the generic model browser. Figure 2. Applications Deployments Many new features have been added to the deployment section: Use drag and drop to deploy artifacts Content browser with preview for text and images Create exploded deployments CRUD support for exploded deployments: Add empty files Upload content Modify content Remove content Download complete deployments or deployment content Figure 3. Deployments Figure 4. Deployment Model Figure 5. Content Browser Topology The topology view has been reintroduced to the management console. It was removed in the last versions due to performance issues with large domains. But thanks to new management operations, we were able to add this useful tool again. Figure 6. Topology Runtime The lifecycle operations for hosts, server groups and servers have been improved. New operations are available for hosts and disconnected hosts are now shown in the finder columns. For servers you can specify custom URLs which is extremely useful when running WildFly inside a docker container. Figure 7. Runtime Monitor The existing screens have been improved and many new subsystems have been added to the monitoring section. Some of the new and enhanced subsystems are: Batch EJB IO JAX-RS Messaging Web (Undertow) Figure 8. Monitor Server Figure 9. EJB Subsystem Figure 10. JAX-RS Resources Figure 11. Undertow Listener Statistics Get Involved If you want to learn more about HAL, head over to https://hal.github.io/. The new website contains both end user and technical documentation. Read about HAL’s architecture, building blocks and how you can build, run and debug the console. HAL is an open source project and we love to receive contributions from our community — you! ### [WildFly 13 "Baker's Dozen" is released!](/news/2018/05/31/WildFly-13-Baker-s-Dozen-is-released/) WildFly 13 Final is now available for download! EE8 Capabilities & New Release Model This is our second release following our new quarterly delivery model. A central theme of this plan, is to deliver EE8 functionality in fully completed incremental chunks, as opposed to waiting for everything to finish in a big bang relase. WildFly 13 largely accomplishes this goal, by achieving EE8 feature completeness. WildFly 14 will focus on achieving formal certification, and converting over to a sole EE8 execution model. Since Java EE8 is fully backwards compatible, EE7 deployments will still function ast they do today. An overview of all changes for the EE8 execution mode are as follows: Name From Version From JSR To Version To JSR Java Servlet 3.1 JSR-340 4.0 JSR-369 Contexts and Dependency Injection for Java 1.2 JSR-346 2.0 JSR-365 Bean Validation 1.1 JSR-349 2.0 JSR-380 JavaServer Faces 2.2 JSR-344 2.3 JSR-372 JavaMail 1.5 JSR-919 1.6 JSR-919 Java API for RESTFul Web Services 2.0 JSR-339 2.1 JSR-370 Java API for JSON Processing 1.0 JSR-353 1.1 JSR-374 Java API for JSON Binding - - 1.0 JSR-367 Common Annotations for the Java Platform 1.2 JSR-250 1.3 JSR-250 Java EE Security - - 1.0 JSR-375 Java Persistence 2.1 JSR-338 2.2 JSR-338 By default WildFly 13 launches in EE7 mode. In order to use these new capabilities you have to enable EE8 preview mode. This can be accomplished by passing the ee8.preview.mode property during startup: ./standalone.sh -Dee8.preview.mode=true Alternatively, this can be achieved by launching the server using the new standalone-ee8.xml configuration, which simply includes the property in the config. ./standalone.sh -c standalone-ee8.xml The CLI can also be used to modify the existing configuration to add this property. For example: embed-server --admin-only=true /system-property=ee8.preview.mode:add(value=true) stop-embedded-server Other Notable Items WildFly 13 is now internally built using project Galleon, a new provisioning model for WildFly we plan to roll out in coming releases Java 10 compatibilty has been improved A major upgrade to the WildFly administration console (HAL version 3) Infinispan has been updated to 9.2 Hibernate ORM has been updated to 5.3 when running in EE8 mode Jira Release Notes The full list of issues resolved is available here. ### [WildFly 12 Final is now available!](/news/2018/03/01/WildFly-12-Final-is-now-available/) WildFly 12 Final is now available for download! EE8 Capabilities & New Release Model This is our first release following our new quarterly delivery model. As part of this plan, we are delivering EE8 functionality in fully completed incremental chunks, as opposed to waiting for everything to finish in a big bang reelase. WildFly 12 makes significant progress on this front, adding support for the majority of the new standards: Name From Version From JSR To Version To JSR Java Servlet 3.1 JSR-340 4.0 JSR-369 Contexts and Dependency Injection for Java 1.2 JSR-346 2.0 JSR-365 Bean Validation 1.1 JSR-349 2.0 JSR-380 JavaServer Faces 2.2 JSR-344 2.3 JSR-372 JavaMail 1.5 JSR-919 1.6 JSR-919 Java API for RESTFul Web Services 2.0 JSR-339 2.1 JSR-370 Java API for JSON Processing 1.0 JSR-353 1.1 JSR-374 Java API for JSON Binding - - 1.0 JSR-367 Common Annotations for the Java Platform 1.2 JSR-250 1.3 JSR-250 By default WildFly 12 launches in EE7 mode. In order to use these new capabilities you have to enable EE8 preview mode. This can be accomplished by passing the ee8.preview.mode property during startup: ./standalone.sh -Dee8.preview.mode=true Alternatively, this can be achieved by launching the server using the new standalone-ee8.xml configuration, which simply includes the property in the config. ./standalone.sh -c standalone-ee8.xml The CLI can also be used to modify the existing configuration to add this property. For example: embed-server --admin-only=true /system-property=ee8.preview.mode:add(value=true) stop-embedded-server Other Notable Items WildFly 12 includes a new thread pooling strategy that reduces the number of threads active at any given time, which helps conserve system resources. MicroProfile REST Client 1.0 is now supported Java 9 compatibilty has been improved CLI scripts can now take advantage of loops with variables WildFly Documentation is now in asciidoc, and part of the source tree Jira Release Notes The full list of issues resolved is available here. ### [WildFly 11 Final is now available!](/news/2017/10/24/WildFly-11-Final-is-now-available/) WildFly 11 Final is now available for download! The highlights of WildFly 11 are as follows: Elytron - New Security Infrastructure The biggest change in WildFly 11 is unification on a new common security framework across the full application server. Previously we had two separate security infrastructures (picketbox and security-realms), each covering separate use cases, and largely operating independent of the other. In addition to unification, Elytron brings a number of advanced capabilities such as privilege propagation across multiple service invocations, identity switching, pre-request TLS verification, and rich security policies. Finally, it improves the overall extensibility of the system allowing for tight integration with SSO / IDP systems such as KeyCloak. While WildFly 11 introduces a new security infrastructure, the existing security-domain and security-realm configurations and APIs are all present and internally mapped to Elytron. To further ease the impact of this change, WildFly 11’s default configurations still use the legacy security-domains and security-realms. A subsequent release will convert the default configurations over to the new configuration model. For more information see the Elytron documentation: https://docs.jboss.org/author/display/WFLY/WildFly+Elytron+Security As well as the section on migration: https://docs.jboss.org/author/display/WFLY/Migrate+Legacy+Security+to+Elytron+Security Simplified EJB / Naming Proxies JNDI and EJB invocation have both been simplified and enhanced in WildFly 11. There is a new naming client library, WildFly Naming Client that allows you to easily configure access to WildFly with minimal properties and configuration. EJBs (and other resources) can be accessed in a dynamic discovery mode, or alternatively, in a new point to point mode that locks all EJB proxies to a specified address. This replaces the previous scoped context feature with more intuitive semantics that are ideal for ad-hoc behavior. Additionally, with the new Elytron authentication infrastructure, the user identity can now be changed in-between requests. Finally, older clients from past WildFly releases can still be used with WildFly 11. See the following for more information on the new WildFly Naming client: https://github.com/wildfly/wildfly-naming-client Request oriented EJB/JNDI over HTTP Since WildFly 8, all protocols (with the exception of IIOP) can utilize HTTP Upgrade to communicate over a reduced set of ports on the server (one for management, and one for applications). However, since HTTP Upgrade converts the connection to the native protocol used, any HTTP load-balancers acting as an intermediary can only balance on initial connection establishment. To allow for balancing at the individual invocation level, a new “pure” HTTP protocol was added. Clients which utilize http:// URLs as opposed to remoting+http:// will obtain this new behavior. Since this protocol utilizes standard HTTP behavior, it can be efficiently balanced by any load-balancer, not just the one built into WildFly. WildFly OpenSSL & HTTP/2 WildFly 11 now provides a JSSE provider that can offload TLS handling from the JVM’s internal implementation to an OpenSSL library on your system, typically improving TLS performance. If the version discovered and/or specified is 1.0.2 or greater, then WildFly will utilize OpenSSL’s ALPN support to provide HTTP/2 support. HTTP/2 support will be disabled on versions less than 1.0.2. Note that HTTP/2 is also supported without OpenSSL, out of the box, on Java 8 (on VMs derived from OpenJDK) and Java 9 (using the new standard ALPN API). You can enable OpenSSL in the default configurations with the following CLI command: /core-service=management/security-realm=ApplicationRealm/server-identity=ssl:write-attribute(name=protocol,value=openssl.TLS) If your openssl library is not installed in a standard location, you will need to additionally set the org.wildfly.openssl.path system property to point to the location of the library: -Dorg.wildfly.openssl.path=/path/to/dir/with/openssl/lib New Load-Balancer Configs In order to simplify the setup of WildFly as an HTTP load-balancer, there is an additional standalone-load-balancer.xml configuration in the distribution, which is an instance slimmed to just running the load balancing services. Additionally the stock domain.xml also includes this as a profile configuration that can be referenced by server groups. Graceful Shutdown/Startup Improvements Distributed transactions are now handled by the graceful shutdown mechanism. Existing transactions will allow local operations to continue, but any new in-flowed transaction will be rejected. Additionally there is a new EJB parameter that allows for additional remote calls to occur against an established/active remote transaction. Finally you can now start the server directly in suspended mode, for staging changes. This is now part of the default start sequence where the server enters suspend first, and then resumes after all services have launched, so new requests aren’t accepted during the brief window of the server starting. Web Console Improvements A number of Web Console improvements are included in WildFly 11, including the ability to see recent configuration changes, to manage active JMS transactions, manage active batch jobs, manage Undertow filters, and test data-sources during creation. Management and Configuration Improvements WildFly 11 now supports remote managed exploded deployments, which allows remote management clients the ability to update content within the deployment, such as html and jsp files without requiring a full redeployment. Additionally there is a new management operation that can be used to read individual files in any deployment. In addition to these new capabilities, errors in the XML now lead to pretty printed easier to understand error messages, Also notable is that CLI tab completion can now tab complete attribute reference values that have capabilities present, such as references to socket bindings. Finally, there is a new SPI for server extensions, that can be used to register a process state listener, and react to server life-cycle changes (such as the server stopping). Further Reading In the run-up to the release, we have been blogging about WildFly 11’s features. These articles contain detailed information and useful tips on how take advantage of these capabilities, so be sure to take a look! Table 1. Recent Articles Author Title Emmanuel Hugonnet Using exploded deployments and CLI attachments Farah Juma How to secure EJBs with Elytron and invoke them from remote clients Farah Juma EJB invocations from remote servers Farah Juma How to use an Elytron SASL mechanism that supports channel binding Claudio Miranda Admin/Web Console Features & Enhancements Darran Lofthouse WildFly Elytron - Add Kerberos Authentication to Existing Web Application Darran Lofthouse Using WildFly Elytron with Undertow Standalone Brian Stansberry Management Model Referential Integrity and Suggestions Jeff Mesnil Messaging features in WildFly 11 Stuart Douglas OpenSSL & HTTP/2 Ken Wills Embedded Hostcontroller Jira Release Notes The full list of issues resolved is available here. What’s Next Now that WildFly 11 is out the door, we plan to move to a faster, more incremental release model, starting with WildFly 12. Expect to see more details here in the future, and as always, your contributions are welcome! ### [Running an Embedded WildFly Host Controller in the CLI](/news/2017/10/10/Running-an-Embedded-WildFly-Host-Controller-in-the-CLI/) WildFly supports running a standalone server in Offline mode as an embedded server. An analogous capability has been added for domain mode in the form of running an offline host controller. This article discusses some of the details and possible applications of this feature. Introduction For those not familiar with the existing embedded standalone server, see: Offline mode Running an Embedded WildFly 9 Server in the CLI · WildFly. One of the major use cases of this feature was to allow local administration of a WIldFly / JBoss EAP instance without requiring a socket based connection, or opening any local ports but still enabling configuration and administration operations. The embedded approach also allows for a fast boot that will allow multiple concurrent running instances to co-exist without configuring any additional socket offsets or interfaces to avoid port conflicts etc. Using jboss-cli.sh and the embed-host-controller command enables a fast and flexible means of configuring host controller instances and servers. Embedded Host Controller In a similar way to the standalone embed-server command, the embed-host-controller command is provided, to start an embedded host controller running in the CLI. This host controller is started in admin-only mode, and no servers are started. [See below for more details on admin-only restrictions]. Starting an embedded Host Controller: $ ./bin/jboss-cli.sh You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands. [disconnected /] embed-host-controller --std-out=echo 11:07:46,723 INFO [org.jboss.modules] (AeshProcess: 1) JBoss Modules version 1.6.0.Final 11:07:46,825 INFO [org.jboss.msc] (AeshProcess: 1) JBoss MSC version 1.2.7.SP1 11:07:46,870 INFO [org.jboss.as] (MSC service thread 1-7) WFLYSRV0049: WildFly Full 11.0.0 (WildFly Core 3.0.1.Final) starting [ Note: some startup output omitted for brevity. ] 11:07:48,845 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 11.0.0 (WildFly Core 3.0.1.Final) (Host Controller) started in 2105ms - Started 56 of 61 services (18 services are lazy, passive or on-demand) [domain@embedded /] ls -l ATTRIBUTE VALUE TYPE domain-organization undefined STRING launch-type EMBEDDED STRING local-host-name master STRING management-major-version 5 INT management-micro-version 0 INT management-minor-version 0 INT name Unnamed Domain STRING namespaces [] OBJECT process-type Host Controller STRING product-name WildFly Full STRING product-version 11.0.0 STRING release-codename Kenny STRING release-version 3.0.1.Final STRING schema-locations [] OBJECT CHILD MIN-OCCURS MAX-OCCURS core-service n/a n/a deployment n/a n/a deployment-overlay n/a n/a extension n/a n/a host n/a n/a host-exclude n/a n/a interface n/a n/a management-client-content n/a n/a path n/a n/a profile n/a n/a server-group n/a n/a socket-binding-group n/a n/a system-property n/a n/a The non-modular client may also be used from the bin/client WildFly distribution: $ java -jar bin/client/jboss-cli-client.jar You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands. [disconnected /] embed-host-controller --jboss-home=/wildfly-11.0.0 Warning! The CLI is running in a non-modular environment and cannot load commands from management extensions. [domain@embedded /] cd /host=master/server-config=server-one [domain@embedded server-config=server-one] ls -l ATTRIBUTE VALUE TYPE auto-start true BOOLEAN cpu-affinity undefined STRING group main-server-group STRING name server-one STRING priority undefined INT socket-binding-default-interface undefined STRING socket-binding-group undefined STRING socket-binding-port-offset 0 INT status STOPPED STRING update-auto-start-with-server-status false BOOLEAN CHILD MIN-OCCURS MAX-OCCURS interface n/a n/a jvm n/a n/a path n/a n/a ssl n/a n/a system-property n/a n/a [domain@embedded server-config=server-one] See Modular vs Non-Modular Classloading and JBOSS_HOME in the original embedded server news article for details. Executing commands: [domain@embedded /] /host=master/interface=public:write-attribute(name=inet-address, value=127.0.0.1) { "outcome" => "success", "result" => undefined, "server-groups" => undefined, "response-headers" => {"process-state" => "reload-required"} } Reloading: [domain@embedded /] reload --host=master --admin-only=true 11:17:20,092 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 11.0.0 (WildFly Core 3.0.1.Final) (Host Controller) started in 279ms - Started 56 of 61 services (18 services are lazy, passive or on-demand) [domain@embedded /] Note that currently, the embedded host controller may only be started / reloaded in admin-only mode. In domain mode, servers are started and stopped via use of the process controller which is not currently supported as part of embedded mode. Stopping: [domain@embedded /] stop-embedded-host-controller 11:08:29,925 INFO [org.jboss.as] (MSC service thread 1-7) WFLYSRV0050: WildFly Full 11.0.0 (WildFly Core 3.0.1.Final) stopped in 13ms Command usage: The embed-host-controller command has several options that behave in the same way as the previously mentioned standalone embedded server, which will not be discussed again here. The relevant embed-host-controller parameters are: -c - Name of the domain configuration file to use (default is "domain.xml") (Same as --domain-config) --domain-config - Name of the domain configuration file to use (default is "domain.xml") (Same as -c) --host-config - Name of the host configuration file to use (default is "host.xml") As mentioned above, --jboss-home, --std-out and --timeout may also be provided and function in the same manner as the embed-server command. The configuration files mentioned above (domain.xml, host.xml) above should be located in the $JBOSS_HOME/domain/configuration directory (or under the location pointed to by the system property jboss.domain.config.dir.) [See Command Line Properties for additional details on those properties.] For example, to start an embedded host controller with configuration files contained in the otherdomain/configuration directory: [wildfly-11]$ ./bin/jboss-cli.sh -Djboss.domain.config.dir=/wildfly-11/otherdomain/configuration You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands. [disconnected /] embed-host-controller --std-out=echo 11:26:44,122 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 11.0.0 (WildFly Core 3.0.1.Final) (Host Controller) started in 1894ms - Started 56 of 61 services (18 services are lazy, passive or on-demand) [domain@embedded /] Configuration may then proceed and will be persisted to the otherdomain/configuration directory. This directory must already exist and contain base copies of the required configuration files (host.xml, domain.xml etc.). Scripted configuration The embedded host controller may be useful for configuration from a prepared file of scripted CLI commands. For example: $ cat commands.cli embed-host-controller /server-group=main-server-group:write-attribute(name=socket-binding-port-offset, value=100) /host=master/server-config=server-one:write-attribute(name=auto-start, value=false) deploy --all-server-groups test.war stop-embedded-host-controller $ ./bin/jboss-cli.sh --file=commands.cli { "outcome" => "success", "result" => undefined, "server-groups" => undefined } This approach may be used for a variety of setup and configuration tasks, for example setting up unit or integration tests quickly using the embedded host controller, then restarting in domain mode using domain.sh may require less time than starting the host controller normally using domain.sh, performing configuration and deployment etc, then restarting. Other examples Set server socket-binding-port-offset In order to allow more than one running instance on the same host, a common configuration for testing (or any scenario needing to run a domain controller and a slave host controller (with servers) on the same host), a socket-binding-port-offset is commonly used. The slave host is configured to have a port offset so that the ports already in use by the domain controller’s servers do not conflict with those of the slave. [domain@embedded /] /server-group=main-server-group:write-attribute(name=socket-binding-port-offset, value=100) { "outcome" => "success", "result" => undefined, "server-groups" => undefined } Configure connection to remote domain controller When configuring a slave host controller, configure the connection to the domain controller. [domain@embedded /] /host=master:write-remote-domain-controller(host=remotedc.somedomain.tld, security-realm=ManagementRealm) { "outcome" => "success", "result" => undefined, "server-groups" => undefined, "response-headers" => {"process-state" => "reload-required"} } System property This can be useful as an initial configuration step before the host controller is started with domain.sh: [domain@embedded /] /server-group=main-server-group/system-property=foo:add(value=bar) { "outcome" => "success", "result" => undefined, "server-groups" => undefined } Future Direction In the future we’d like to allow for starting the embedded host controller with some additional features, such as empty configurations in host and domain configuration files (similar to standalone embedded), and also re-examine the meaning and usage of --admin-only in the context of the embedded host controller. ### [OpenSSL support with WildFly](/news/2017/10/06/OpenSSL-support-with-WildFly/) The upcoming WildFly 11 release includes support for OpenSSL. This provides two main advantages over JSSE: Support for ALPN on all JDK’s Significantly improved performance compared to JSSE Setting up OpenSSL In general for Linux based systems all that is required is to install a recent version of OpenSSL using your systems package manager. The OpenSSL support will search the library path, and use whatever version of OpenSSL it finds. The same applies to MacOS when OpenSSL has been installed using brew (the system default OpenSSL installation is too old). For windows and for custom OpenSSL locations you need to specify the location via a system property, org.wildfly.openssl.path. If this is set then Wildfly will search for OpenSSL in the directory specified. If you have multiple versions of OpenSSL in the same directory and need to specify the precise file to use you can instead use org.wildfly.openssl.path.ssl and org.wildfly.openssl.path.crypto to specify the path to libssl and libcrypto respectively. As Wildfly uses dynamic linking this should work with any OpenSSL version from 1.0.1 onwards (however for security reasons it is recommended to always use the most up to date 1.1.x or 1.0.x version that is available, as older versions may have unpatched vulnerabilities). Setting up Wildfly with Security Realms As Wildfly supports SSL out of the box with dynamically generated self signed certificates all that is required is to change the protocol in use. Doing this is as simple as running a single command in the CLI: /core-service=management/security-realm=ApplicationRealm/server-identity=ssl:write-attribute(name=protocol, value=openssl.TLS) Other valid values are openssl.TLSv1.1 and openssl.TLSv1.2, which limit the minimum TLS version to 1.1 and 1.2 respectively. Once this is done you can use OpenSSL by simply pointing your browser to https://localhost:8443. You should see the following message in the log that tells you that OpenSSL is in use: 09:01:04,150 INFO [org.wildfly.openssl.SSL] (MSC service thread 1-6) WFOPENSSL0002 OpenSSL Version OpenSSL 1.0.2l 25 May 2017 Setting up Wildfly with Elytron As Elytron is not used by default there is a little bit more work involved in setting it up. Elytron does not support auto generation of SSL certificates, so for the sake of this example I am going to assume that the keystore is located at standalone/configuration/application.keystore (the same location that the auto generated keystore is placed, if you just want a self signed certificate for testing purposes you can simply connect to https://localhost:8443 with the default configuration and one will be generated for you). In order to set up SSL using Elytron run the following commands (note that this is just to use JSSE, the OpenSSL config will come later). /subsystem=elytron/key-store=server:add(path=application.keystore, relative-to=jboss.server.config.dir, credential-reference={clear-text=password}, type=jks) /subsystem=elytron/key-manager=server:add(key-store=server, credential-reference={clear-text=password}, algorithm=SunX509) /subsystem=elytron/server-ssl-context=server:add(key-manager=server, protocols=[TLSv1.2]) batch /subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm) /subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context, value=server) run-batch :reload If you point your browser at https://localhost:8443 you should now have a working Elytron based SSL config. Once you have verified that this has worked we now need to change it to use OpenSSL. To do this we change the ordering of the providers in the elytron combined-providers, which means that OpenSSL will now take precedence: /subsystem=elytron/aggregate-providers=combined-providers:list-add(index=0, name=providers, value=openssl) /subsystem=elytron/aggregate-providers=combined-providers:list-remove(index=2, name=providers) You should now have OpenSSL working with Elytron. ### [Messaging features in WildFly 11](/news/2017/10/03/Messaging-features-in-WildFly-11/) WildFly 11 is integrating Apache ActiveMQ Artemis 1.5 to provides its messaging features. New features With the integration of Artemis 1.5, WildFly has udpated its messaging-activemq subsystem to provides new Artemis features through WildFly management model. The two new main features are the JDBC Store and the configuration for ActiveMQ client thread pools. JDBC Store The JDBC store is an alternative to Artemis File journal that uses a SQL database to store broker state (messages, addresses and other application state) instead of files. It relies on a data-source resource configured in the datasources subsystem to connect to the database. To use a JDBC store in WildFly, you need to configure the journal-datasource attribute on its server resource that corresponds to a JDBC DataSource configured in the datasources subsystem: [standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default:write-attribute(name=journal-datasource, value=ExampleDS) Configuration of ActiveMQ client thread pools Artemis uses thread pools for its clients that are running inside the application server. They can now be configured in the messaging-activemq subsystem to ensure that their sizes fit the application deployed in WildFly: <subsystem xmlns="urn:jboss:domain:messaging-activemq:1.1"> <global-client thread-pool-max-size="${activemq.artemis.client.global.thread.pool.max.size}" scheduled-thread-pool-max-size="${activemq.artemis.client.global.scheduled.thread.pool.core.size}" /> <server ...> </server> ... </subsystem> Note By default, the maximum size for client thread pool is not defined. In that case, Artemis will configure them to be 8 x the number of available processors. Message-Driven Beans Features We have also added new features for Message-Driven Beans (MDBs) related to their use in a cluster of Artemis brokers. Full support for Clustered Singleton MDB When an MDB is identified as a clustered singleton and deployed in a cluster, it will always be active only on one node at a time. When the server node fails or is shut down, the clustered singleton MDB is activated on a different node and starts consuming messages on that node. Note The messaging-clustering-singleton quickstart demonstrates how to setup and configure MDB to support clustered singleton. Rebalancing of all inbound MDB connections WildFly 11 provides the rebalanceConnections activation configuration property for MDBs. This parameter allows for rebalancing of all inbound MDB connections when the underlying Artemis cluster topology changes so that when nodes are added/removed from the cluster, the MDB can connect to them instead of being stuck to the topology when the MDB initially connected to the cluster. This property can also be configured on the messaging-activemq’s `pooled-connection-factory resources using the rebalance-connections attribute: [standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default/pooled-connection-factory=activemq-ra:write-attribute(name=rebalance-connections, value=true) Generic JMS Resource Adapter 2.0 WildFly supports messaging with Artemis out of the box. It also provides the Generic JMS Resource Adapter that allows to use out of the box JMS brokers that does not provides a resource adapter (such as TIBCO EMS for example). MDBs can the connect to these external JMS brokers through the use of the Generic JMS RA. This component has been updated to support the JMS 2.0 API (provided that the external JMS broker behind it supports it). Improvements There were also many improvements to the messaging features that were in WildFly 10. Monitoring of JMS pooled connections The messaging-activemq pooled-connection-factory resources now offers statistics on their pools. They must first be enabled by setting the statistics-enabled attribute to true: [standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default/pooled-connection-factory=activemq-ra:write-attribute(name=statistics-enabled, value=true) Once statistics are enabled, the pooled-connection-factory resource will have a statistics=pool child resource that will returns metrics on the pool used by the pooled-connection-factory: [standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default/pooled-connection-factory=activemq-ra/statistics=pool:read-resource(include-runtime) { "outcome" => "success", "result" => { "ActiveCount" => 15, "AvailableCount" => 20, ... } } Web console improvements The management Web console that is bundled with WildFly 11 has been substantially improved to be able to manage messaging resources more efficiently. JMS Bridges can now be added and managed using the Web console. The Web console now displays prepared transactions for integrated Artemis brokers. You can then commit or rollback these prepared transactions from the Web console too. Elytron integration with the messaging-activemq subsystem The WildFly Elytron project is a security framework used to unify security across the entire application server. The elytron subsystem enables a single point of configuration for securing both applications and the management interfaces and replaces the legacy security subsystem. The messaging-activemq subsystem has been integrated with Elytron to provide its security features (authentication and authorization). Bug fixes There were also many many messaging bug fixes since last WildFly release. However if you find any new issues or want to request enhancements, do not hesitate to use WildFly issue tracker. ### [Management Model Referential Integrity and Suggestions](/news/2017/09/29/Management-Model-Referential-Integrity-and-Suggestions/) A significant improvement in WildFly 11 is much better support for referential integrity when one resource in your configuration refers to another resource. Going beyond just checking that your references are correct, the server provides reference information that our CLI and the HAL web console are able to use to suggest valid values to you as you set up your configuration. Configuration references When you are configuring a WildFly server, a common thing you need to do is configure attributes whose value refers to the name of some other resource. A common example of this is a resource that includes a socket-binding attribute: [standalone@localhost:9999 /] /subsystem=undertow/server=default-server/ajp-listener=ajp:add(socket-binding=ajp) When you do this, it’s because the services managed by the resource you are configuring need some capabilities provided by another resource. What you’re doing is configuring which one to use. But what kind of resource that socket-binding attribute refers to may not be obvious, and what the valid values are is also not obvious. And before the rollout of improved reference support, if you got it wrong the failure you’d see could be difficult to understand. Here, using WildFly 9 with a config where the previously unused 'ajp' socket binding config had been removed, we try and add an AJP listener to the web container: [standalone@localhost:9990 /] /subsystem=undertow/server=default-server/ajp-listener=ajp:add(socket-binding=ajp) { "outcome" => "failed", "failure-description" => {"WFLYCTL0180: Services with missing/unavailable dependencies" => ["jboss.undertow.listener.ajp is missing [jboss.binding.ajp]"]}, "rolled-back" => true } That error message says nothing about where to go to correct the mistake. Worse, if you made that mistake when working with a server started in admin-only mode, that bad reference would not be detected when you entered it. [standalone@localhost:9990 /] reload --admin-only=true [standalone@localhost:9990 /] /subsystem=undertow/server=default-server/ajp-listener=ajp:add(socket-binding=ajp) {"outcome" => "success"} The configuration would be updated and the problem would only be detected when the server was reloaded or restarted not in admin-only mode. The server would boot but would not function correctly. Referential Integrity Checks and Reference Suggestions Starting in WildFly 10 and greatly expanded in WildFly 11, we’ve added reference description metadata to our resources and attributes, and we use that to proactively ensure that management operations that violate referential integrity fail immediately. The same incorrect operation shown above will now fail immediately, with a message that gives a hint as to where you can configure the missing resource: [standalone@embedded /] /subsystem=undertow/server=default-server/ajp-listener=ajp:add(socket-binding=ajp) { "outcome" => "failed", "failure-description" => "WFLYCTL0369: Required capabilities are not available: org.wildfly.network.socket-binding.ajp; Possible registration points for this capability: /socket-binding-group=*/socket-binding=*", "rolled-back" => true } The same failure will happen if the server is running in admin-only mode (with some exceptions; see "Referential Integrity Checks in an admin-only Process" below.) If you think the resource you need already exists, but you’re not sure of its name, you can use CLI tab completion to get a list of suggestions: [standalone@embedded /] /subsystem=undertow/server=default-server/ajp-listener=ajp:add(socket-binding= http https management-http management-https txn-recovery-environment txn-status-manager [standalone@embedded /] /subsystem=undertow/server=default-server/ajp-listener=ajp:add(socket-binding= Once the needed socket binding resource is added, it is available in the tab completion results. [standalone@embedded /] /socket-binding-group=standard-sockets/socket-binding=ajp:add(port=8009) {"outcome" => "success"} [standalone@embedded /] /subsystem=undertow/server=default-server/ajp-listener=ajp:add(socket-binding= ajp https management-https txn-status-manager http management-http txn-recovery-environment [standalone@embedded /] /subsystem=undertow/server=default-server/ajp-listener=ajp:add(socket-binding=ajp) {"outcome" => "success"} The HAL console will also suggest valid values by means of a pull-down: If you try and remove a resource whose capabilities are depended upon by other resources, that will also result in a failed operation: [standalone@embedded /] /socket-binding-group=standard-sockets/socket-binding=ajp:remove { "outcome" => "failed", "failure-description" => "WFLYCTL0367: Cannot remove capability 'org.wildfly.network.socket-binding.ajp' as it is required by other capabilities: capability 'org.wildfly.undertow.listener.ajp' requires it for attribute 'socket-binding' at address '/subsystem=undertow/server=default-server/ajp-listener=ajp'", "rolled-back" => true } Referential Integrity Checks in an admin-only Process If your xml configuration file contains invalid references and you start the server normally, the server will fail to boot and the log will have an error message describing the problem. However, if you start the server with the --admin-only flag, the server boot will not fail. This is because starting in admin-only and manipulating the configuration via the CLI is the recommended way of correcting your configuration. If we didn’t allow the server to boot, the user would have no alternative to manually editing the xml. When the server is started in this state, no operation will be rejected due to an invalid reference until all referential integrity problems have been corrected. Once the configuration reaches a state where there are no integrity issues, thereafter any changes that break integrity will be rejected. If a server is started in admin-only and has no integrity problems at boot, any changes that break integrity will be rejected. So, leniency in integrity checks is only enabled when the server’s configuration at boot has problems. Further Work The referential integrity functionality discussed here first began to appear in WildFly 10, but it’s use was greatly expanded in WildFly 11, and the use of it to drive CLI tab completion and HAL pulldowns is new in 11. But still, we don’t yet have complete coverage of all capabilities subsystems provide, although the bulk of cases are covered, particularly those involve configuration attributes. Rollout of the use of capabilities will continue in future WildFly releases. More Information If you are interested in learning more about how the capabilities and requirements system works from the point of view of someone working on developing WildFly, please see the Working with WildFly Capabilities document in the WildFly documentation. ### [Using exploded deployments and CLI attachments](/news/2017/09/08/Using-exploded-deployments-and-CLI-attachments/) In WildFly there used to be two worlds : one for developers with exploded deployments using a scanner and one for production where artifacts (wars/ears/jars) were deployed. Now those two worlds have collided and you can have exploded deployments without a scanner. And since this is using the management API you get remote access to the content for "free" and of course it works in domain mode. While this new feature is really useful for tools developers (JBoss Developer Studio will use this in a tech preview, and NetBeans should use it also), YOU can also take advantage of it. Creating exploded deployments There are two ways to create an exploded deployment: Create an empty deployment and add content to it. Deploy an artifact and explode it. Creating an exploded deployment from scratch Let’s create a from_scratch.war deployment: [standalone@localhost:9990 /] /deployment=from_scratch.war:add(content=[{empty=true}]) [standalone@localhost:9990 /] /deployment=from_scratch.war:add-content(content=[ {input-stream-index=/home/ehsavoie/NetBeansProjects/SimpleWebapp/target/SimpleWebapp/index.html,target-path=index.html}, {input-stream-index=/home/ehsavoie/NetBeansProjects/SimpleWebapp/target/SimpleWebapp/WEB-INF/web.xml, target-path=WEB-INF/web.xml}, {input-stream-index=/home/ehsavoie/NetBeansProjects/SimpleWebapp/target/SimpleWebapp/WEB-INF/classes/org/wildfly/sample/simplewebapp/SimpleServlet.class, target-path=WEB-INF/classes/org/wildfly/sample/simplewebapp/SimpleServlet.class}]) [standalone@localhost:9990 /] /deployment=from_scratch.war:deploy Here we have created an empty deployment called from_scratch.war to which we have added 3 files: - a simple HTML page index.html. - A class file for a servlet. - A web.xml descriptor. Then we have enabled the deployment and thus could access the index.html and the servlet. If you take a look at the $JBOSS_HOME/standalone/content/dc/9567f71b186466b21fff825d60f5fbc84ae6b1/content/ you will see the exploded war content. Important Since this content is managed, don’t touch it directly by copying file to it manually, always use the Management API (through the jboss-cli or the web console). Note Note that the add-content can be used to replace files in a deployment but if the deployment is running this might not show until you redeploy it. You can also delete files in a deployment using remove-content but if the deployment is running this might not show until you redeploy it. Exploding a deployment Let’s install and explode a to_be_exploded.war deployment: [standalone@localhost:9990 /] /deployment=to_be_exploded.war:add(content=[{input-stream-index=/home/ehsavoie/NetBeansProjects/SimpleWebapp/target/SimpleWebapp.war}],enabled=false) [standalone@localhost:9990 /] /deployment=to_be_exploded.war:explode [standalone@localhost:9990 /] /deployment=to_be_exploded.war:deploy This can be achieved via the web console using the explode operation in the menu: If you take a look at the $JBOSS_HOME/standalone/content//cf/9918bad9d875ffb20da8747b5dcd15bdab16e0/content/ you will see the exploded war content (it differs from the first example hash has the war file contains META-INF files). Important Since this content is managed, don’t touch it directly by copying file to it manually, always use the Management API (through the jboss-cli or the web console). Note Note also that you can only explode an unexploded deployment or an archive file if the deployment is not running (aka is disabled). Reading content from a deployment Now you can read content from a deployment, so you can directly see what’s in your deployment. This operation can be use to browse the content of a deployment and read or download its files (even from inside an archive file). Using the JBoss CLI Using the browse-content operation you can have the list of files in the deployment : [standalone@localhost:9990 /] /deployment=to_be_exploded.war:browse-content { "outcome" => "success", "result" => [ { "path" => "META-INF/", "directory" => true }, { "path" => "META-INF/MANIFEST.MF", "directory" => false, "file-size" => 134L }, { "path" => "WEB-INF/", "directory" => true }, { "path" => "WEB-INF/classes/", "directory" => true }, { "path" => "WEB-INF/classes/org/", "directory" => true }, { "path" => "WEB-INF/classes/org/wildfly/", "directory" => true }, { "path" => "WEB-INF/classes/org/wildfly/sample/", "directory" => true }, { "path" => "WEB-INF/classes/org/wildfly/sample/simplewebapp/", "directory" => true }, { "path" => "WEB-INF/web.xml", "directory" => false, "file-size" => 916L }, { "path" => "WEB-INF/classes/org/wildfly/sample/simplewebapp/SimpleServlet.class", "directory" => false, "file-size" => 2302L }, { "path" => "index.html", "directory" => false, "file-size" => 234L }, { "path" => "META-INF/maven/", "directory" => true }, { "path" => "META-INF/maven/org.wildfly.sample/", "directory" => true }, { "path" => "META-INF/maven/org.wildfly.sample/SimpleWebapp/", "directory" => true }, { "path" => "META-INF/maven/org.wildfly.sample/SimpleWebapp/pom.xml", "directory" => false, "file-size" => 2992L }, { "path" => "META-INF/maven/org.wildfly.sample/SimpleWebapp/pom.properties", "directory" => false, "file-size" => 125L } ] } You can reduce the output by filtering using the path, depth and archive parameters. For exemple [standalone@localhost:9990 /] /deployment=to_be_exploded.war:browse-content(path=WEB-INF/, depth=1) { "outcome" => "success", "result" => [ { "path" => "web.xml", "directory" => false, "file-size" => 916L }, { "path" => "classes/", "directory" => true } ] } So now we can display the content of the web.xml. Using the read-content operation is not sufficient enough as it will return an attachment: [standalone@localhost:9990 /] /deployment=to_be_exploded.war:read-content(path=WEB-INF/web.xml) { "outcome" => "success", "result" => {"uuid" => "c778c51e-a507-4a71-a21f-d6af8b230db4"}, "response-headers" => {"attached-streams" => [{ "uuid" => "c778c51e-a507-4a71-a21f-d6af8b230db4", "mime-type" => "application/xml" }]} } So we need to combine this operation with the attachment operation like this : [standalone@localhost:9990 /] attachment display --operation=/deployment=to_be_exploded.war:read-content(path=WEB-INF/web.xml) ATTACHMENT 582a10e0-5159-4d2b-8d07-8d39af0df8c3: <?xml version="1.0" encoding="UTF-8"?> <web-app 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_3_1.xsd" version="3.1"> <session-config> <session-timeout> 30 </session-timeout> </session-config> <servlet id="SimpleServlet"> <servlet-name>SimpleServlet</servlet-name> <display-name>SimpleServlet</display-name> <servlet-class>org.wildfly.sample.simplewebapp.SimpleServlet</servlet-class> <init-param> <param-name>message</param-name> <param-value>Hello World</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>SimpleServlet</servlet-name> <url-pattern>/SimpleServlet</url-pattern> </servlet-mapping> </web-app> And to save this content locally we can use: [standalone@localhost:9990 /] attachment save --operation=/deployment=to_be_exploded.war:read-content(path=WEB-INF/web.xml) --file=/home/ehsavoie/tmp/web.xml File saved to /home/ehsavoie/tmp/web.xml Using the web console Navigate to 'Deployments' and select the deployment you want to browse. Then open the context menu and choose Browse Content: This opens a new page with the contents of the deployment. For each file, there’s a link with the full path and size of the file. Click on the link to download the file: Using HAL.NEXT The next major version of the web console (HAL.next) is currently under active development and is available as technical preview https://github.com/hal/hal.next. Follow the instruction in https://github.com/hal/hal.next#running to get started. Besides general improvements like better navigation and a revisited look and feel, HAL.next comes with many improvements for dealing with deployments: Add Deployments using drag & drop. New content browser using a tree view and an editor with syntax highlighting. Download complete deployments or single files of a deployment. Select deployments and just click on View to display its content: This opens a new page which allows for a really nice way to browse and read content from a deployment: References For the official documentation regarding deployments: Official Documentation The example basic webapp used in this article is available here ### [WildFly 11 CR1 is now available!](/news/2017/08/26/WildFly-11-CR1-is-now-available/) WildFly 11 CR1 is now available for download! Since the Beta, 66 issues have been resolved. You can find the full list below. Provided that no major issues are found, we hope to release the final very soon. The highlights of WildFly 11 are as follows: Elytron - New Security Infrastructure The biggest change in WildFly 11 is unification on a new common security framework across the full application server. Previously we had two separate security infrastructures (picketbox and security-realms), each covering separate use cases, and largely operating independent of the other. In addition to unification, Elytron brings a number of advanced capabilities such as privilege propagation across multiple service invocations, identity switching, pre-request TLS verification, and rich security policies. Finally it improves the overall extensibility of the system allowing for tight integration with SSO / IDP systems such as KeyCloak. While WildFly 11 introduces a new security infrastructure, the existing security-domain and security-realm configurations and APIs are all present and internally mapped to Elytron. To further ease the impact of this change, WildFly 11’s default configurations still use the legacy security-domains and security-realms. A subsequent release will convert the default configurations over to the new configuration model. For more information see the Elytron documentation: https://docs.jboss.org/author/display/WFLY/WildFly+Elytron+Security As well as the section on migration: https://docs.jboss.org/author/display/WFLY/Migrate+Legacy+Security+to+Elytron+Security Simplified EJB / Naming Proxies JNDI and EJB invocation have both been simplified and enhanced in WildFly 11. There is a new naming client library, WildFly Naming Client that allows you to easily configure access to WildFly with minimal properties and configuration. EJBs (and other resources) can be accessed in a dynamic discovery mode, or alternatively, in a new point to point mode that locks all EJB proxies to a specified address. This replaces the previous scoped context feature with more intuitive semantics that are ideal for ad-hoc behavior. Additionally, with the new Elytron authentication infrastructure, the user identity can now be changed in between requests. Finally, older clients from past WildFly releases can still be used with WildFly 11. See the following for more information on the new WildFly Naming client: https://github.com/wildfly/wildfly-naming-client Request oriented EJB/JNDI over HTTP Since WildFly 8, all protocols (with the exception of IIOP) can utilize HTTP Upgrade to communicate over a reduced set of ports on the server (one for management, and one for applications). However, since HTTP Upgrade converts the connection to the native protocol used, any HTTP load-balancers acting as an intermediary can only balance on initial connection establishment. To allow for balancing at the individual invocation level, a new “pure” HTTP protocol was added. Clients which utilize http:// URLs as opposed to remoting+http:// will obtain this new behavior. Since this protocol utilizes standard HTTP behavior, it can be efficiently balanced by any load-balancer, not just the one built into EAP. WildFly OpenSSL & HTTP/2 WildFly 11 now provides a JSSE provider that can offload TLS handling from the JVM’s internal implementation to an OpenSSL library on your system, typically improving TLS performance. If the version discovered and/or specified is 1.0.2 or greater, then WildFly will utilize OpenSSL’s ALPN support to provide HTTP/2 support. HTTP/2 support will be disabled on versions less than 1.0.2. Note that HTTP/2 is also supported without OpenSSL, out of the box, on Java 8 (on VMs derived from OpenJDK) and Java 9 (using the new standard ALPN API). You can enable OpenSSL in the default configurations with the following CLI command: /core-service=management/security-realm=ApplicationRealm/server-identity=ssl:write-attribute(name=protocol,value=openssl.TLS) If your openssl library is not installed in a standard location, you will need to additionally set the org.wildfly.openssl.path system property to point to the location of the library: -Dorg.wildfly.openssl.path=/path/to/dir/with/openssl/lib New Load-Balancer Configs In order to simplify the setup of EAP as an HTTP load-balancer, there is an additional standalone-load-balancer.xml configuration in the distribution, which is an instance slimmed to just running the load balancing services. Additionally the stock domain.xml also includes this as a profile configuration that can be referenced by server groups. Graceful Shutdown/Startup Improvements Distributed transactions are now handled by the graceful shutdown mechanism. Existing transactions will allow local operations to continue, but any new in-flowed transaction will be rejected. Additionally there is a new EJB parameter that allows for additional remote calls to occur against an established/active remote transaction. Finally you can now start the server directly in suspended mode, for staging changes. This is now part of the default start sequence where the server enters suspend first, and then resumes after all services have launched, so new requests aren’t accepted during the brief window of the server starting. Web Console Improvements A number of Web Console improvements are included in WildFly 11, including the ability to see recent configuration changes, to manage active JMS transactions, manage active batch jobs, manage Undertow filters, and test data-sources during creation. Management and Configuration Improvements WildFly 11 now supports remote managed exploded deployments, which allows remote management clients the ability to update content within the deployment, such as html and jsp files without requiring a full redeployment. Additionally there is a new management operation that can be used to read individual files in any deployment. In addition to these new capabilities, errors in the XML now lead to pretty printed easier to understand error messages, Also notable is that CLI tab completion can now tab complete attribute reference values that have capabilities present, such as references to socket bindings. Finally, there is a new SPI for server extensions, that can be used to register a process state listener, and react to server life-cycle changes (such as the server stopping). Jira Release Notes The full list of issues resolved is available here. ### [WildFly 11 Beta1 is now available!](/news/2017/08/04/WildFly-11-Beta1-is-now-available/) WildFly 11 is now feature complete and the beta is now available for download! This release includes a significant amount of change, with 459 issues completed since the Alpha, and includes a number of major changes, including architectural changes around a new richer security layer. Since WildFly 11 is feature complete, and appears stable in our local testing, we aim to move to CR quickly. The highlights of this release are as follows: Elytron - New Security Infrastructure The biggest change in WildFly 11 is unification on a new common security framework across the full application server. Previously we had two separate security infrastructures (picketbox and security-realms), each covering separate use cases, and largely operating independent of the other. In addition to unification, Elytron brings a number of advanced capabilities such as privilege propagation across multiple service invocations, identity switching, pre-request TLS verification, and rich security policies. Finally it improves the overall extensibility of the system allowing for tight integration with SSO / IDP systems such as KeyCloak. While WildFly 11 introduces a new security infrastructure, the existing security-domain and security-realm configurations and APIs are all present and internally mapped to Elytron. To further ease the impact of this change, WildFly 11’s default configurations still use the legacy security-domains and security-realms. A subsequent release will convert the default configurations over to the new configuration model. For more information see the Elytron documentation: https://docs.jboss.org/author/display/WFLY/WildFly+Elytron+Security As well as the section on migration: https://docs.jboss.org/author/display/WFLY/Migrate+Legacy+Security+to+Elytron+Security Simplified EJB / Naming Proxies JNDI and EJB invocation have both been simplified and enhanced in WildFly 11. There is a new naming client library, WildFly Naming Client that allows you to easily configure access to WildFly with minimal properties and configuration. EJBs (and other resources) can be accessed in a dynamic discovery mode, or alternatively, in a new point to point mode that locks all EJB proxies to a specified address. This replaces the previous scoped context feature with more intuitive semantics that are ideal for ad-hoc behavior. Additionally, with the new Elytron authentication infrastructure, the user identity can now be changed in between requests. Finally, older clients from past WildFly releases can still be used with WildFly 11. See the following for more information on the new WildFly Naming client: https://github.com/wildfly/wildfly-naming-client Request oriented EJB/JNDI over HTTP Since WildFly 8, all protocols (with the exception of IIOP) can utilize HTTP Upgrade to communicate over a reduced set of ports on the server (one for management, and one for applications). However, since HTTP Upgrade converts the connection to the native protocol used, any HTTP load-balancers acting as an intermediary can only balance on initial connection establishment. To allow for balancing at the individual invocation level, a new “pure” HTTP protocol was added. Clients which utilize http:// URLs as opposed to remoting+http:// will obtain this new behavior. Since this protocol utilizes standard HTTP behavior, it can be efficiently balanced by any load-balancer, not just the one built into EAP. WildFly OpenSSL & HTTP/2 WildFly 11 now provides a JSSE provider that can offload TLS handling from the JVM’s internal implementation to an OpenSSL library on your system, typically improving TLS performance. If the version discovered and/or specified is 1.0.2 or greater, then WildFly will utilize OpenSSL’s ALPN support to provide HTTP/2 support. HTTP/2 support will be disabled on versions less than 1.0.2. Note that HTTP/2 is also supported without OpenSSL, out of the box, on Java 8 (on VMs derived from OpenJDK) and Java 9 (using the new standard ALPN API). You can enable OpenSSL in the default configurations with the following CLI command: /core-service=management/security-realm=ApplicationRealm/server-identity=ssl:write-attribute(name=protocol,value=openssl.TLS) If your openssl library is not installed in a standard location, you will need to additionally set the org.wildfly.openssl.path system property to point to the location of the library: -Dorg.wildfly.openssl.path=/path/to/dir/with/openssl/lib New Load-Balancer Configs In order to simplify the setup of EAP as an HTTP load-balancer, there is an additional standalone-load-balancer.xml configuration in the distribution, which is an instance slimmed to just running the load balancing services. Additionally the stock domain.xml also includes this as a profile configuration that can be referenced by server groups. Graceful Shutdown/Startup Improvements Distributed transactions are now handled by the graceful shutdown mechanism. Existing transactions will allow local operations to continue, but any new in-flowed transaction will be rejected. Additionally there is a new EJB parameter that allows for additional remote calls to occur against an established/active remote transaction. Finally you can now start the server directly in suspended mode, for staging changes. This is now part of the default start sequence where the server enters suspend first, and then resumes after all services have launched, so new requests aren’t accepted during the brief window of the server starting. Web Console Improvements A number of Web Console improvements are included in WildFly 11, including the ability to see recent configuration changes, to manage active JMS transactions, manage active batch jobs, manage Undertow filters, and test data-sources during creation. Management and Configuration Improvements WildFly 11 now supports remote managed exploded deployments, which allows remote management clients the ability to update content within the deployment, such as html and jsp files without requiring a full redeployment. Additionally there is a new management operation that can be used to read individual files in any deployment. In addition to these new capabilities, errors in the XML now lead to pretty printed easier to understand error messages, Also notable is that CLI tab completion can now tab complete attribute reference values that have capabilities present, such as references to socket bindings. Finally, there is a new SPI for server extensions, that can be used to register a process state listener, and react to server life-cycle changes (such as the server stopping). Jira Release Notes The full list of issues resolved is available here. ### [Announcing public CI](/news/2017/05/05/Announcing-public-CI/) We are proud to announce our public CI system, which is running integration tests for WildFly, WildFly Core, Undertow, and many other related projects. This system ensures that we do not merge anything that is broken and that our master is always stable. CI also helps us with testing pull requests by: Making sure the code works on most common target platforms, currently Linux and Windows. Integration testing components as part of the full WildFly test suite. This is most often used when testing WildFly Core, where we test core itself as well as changes to core integrated on top of WildFly. This ensures that the latest core always works with the latest WildFly master. Running additional test suites such as mixed-domain tests, which are a bit harder to set up and run locally. Running complex integration tests that span across multiple projects, such as Elytron integration work that is landing in WildFly 11. It is also utilized to test WildFly against various platforms and JDK combinations, such as testing the IBM JDK on Linux and Windows, testing Solaris SPARC, as well as regularly testing early builds of JDK 9. CI also produces nightly builds of WildFly and WildFly core, which you can follow on our forums. We are using TeamCity as our CI with a few of our own customizations, including the following: A bit-modified, unofficial TeamCity.GitHub plugin that allows us to post failed tests and other details of the failure to the pull request. A pull-player, which we use as our trigger for pull requests. It provides us with a whitelisting of pull request authors for which CI tests are auto-triggered to prevent denial-of-service attacks. It also provides an option to retrigger CI testing by adding the comment “retest this please” to the pull request. The system is powered by three servers running an ESXi hypervisor with everything else virtualized. The front entry point is running Nginx with configured HTTP that is using an SSL certificate provided by Let’s Encrypt. The infrastructure is managed by Ansible with a set of our playbooks. We would like to thank JetBrains, which kindly donated the open source license for TeamCity. ### [Jigsaw's Missing Pieces](/news/2016/12/12/Jigsaw-s-Missing-Pieces/) Red Hat, with its years of experience supporting large scale software systems, has always been a strong proponent of modular Java. Over time, we have delivered many products and solutions that provide and support popular modular environments like Java EE, and OSGi. Since 2011, we introduced a flexible modular implementation called JBoss Modules, which is capable of supporting the core modularity needs of both Java EE and OSGi, but is usable in a standalone manner, without the need to bring in the full platform those specifications require. JBoss EAP and WildFly are built on this technology, which is a major contributor to the flexible runtime they provide. While the above technology allows us to meet the needs of our customers as well as our own, we are hopeful that JSR-376 (Java Platform Modular System), also known as Project Jigsaw, will provide a standardized solution that could be embraced by the full Java community and lead to better software and better interoperability. Additionally, the Java EE expert group has long wanted to improve the overall modularity of the platform, but has deferred these goals hoping to leverage the common SE technology to be introduced by the above JSR. These goals were widely shared as noted in the agreed upon JSR submission. Relevant sections include: “This JSR will define an approachable yet scalable module system for the Java Platform. It will be approachable, i.e., easy to learn and easy to use, so that developers can use it to construct and maintain libraries and large applications for both the Java SE and Java EE Platforms.” ”This JSR targets Java SE 9. We expect the module system to be leveraged by Java EE 9, so we will make sure to take Java EE requirements into account.” ”Some members of the Java community have already invested significantly in applications and frameworks built on top of the OSGi Service Platform. The module system will provide a means for an OSGi kernel to locate Java modules and resolve them using its own resolver, except possibly for core system modules. This will enable OSGi bundles running in such a kernel to depend upon Java modules.” Unfortunately, Jigsaw (JSR-376’s implementation), suffers from a number of significant gaps which may prevent these goals from being fully achieved. As currently defined, Jigsaw is not capable of fully supporting Java EE, OSGi, or any other system with similar dynamic capabilities. However in recent weeks, there have been a number of proposals and discussions to address these problems. We believe it’s critical that these gaps are addressed, as the existence of multiple incompatible standards would likely fragment the Java ecosystem. Application developers would be forced to artificially choose between a totally new static oriented universe of software based on Jigsaw, and the already existing universe, which handles more use-cases and encompases traditional Java SE, Java EE, and OSGi. Framework developers may attempt to support both, but they will likely incur additional cost and potential defects to do so. Finally, divergence will likely increase as standards such as Java EE 9 are forced to consider other options. While there are a number of issues under discussion, they can be categorized into the following areas: Reflection is disallowed from operating on non-exported types, even with the use of setAccessible [1]. This breaks anything using dependency injection or custom serialization (Java EE, Hibernate, Spring, CDI, JAXB, etc). The current proposal put forth by Oracle addresses this by allowing the user to declare packages “open” for reflection. Jigsaw has only limited support for the dynamic introduction and alteration of modules [2]. This prevents modeling Java EE deployments or OSGi bundles as sets of modules as both require support for dynamic installation and hot redeployment. While layers could potentially act as a solution, layers do not support peer-to-peer inter-layer dependency graphs [3]. Additionally everything is eagerly loaded, with a complete graph required to be known up front [4]. This problem is still under active discussion, with some partial proposals. If certain hooks are added, it may be possible to bypass Jigsaw’s native dependency resolution to work around the issue. On the other hand, this has some drawbacks. It requires replicating Jigsaw’s resolution in a dynamic fashion, and it will likely hide information from reflection that a developer might wish to see, but it opens the door for advanced/specialized behavior. Restrictions that make interoperability with alternative modular systems difficult. [5] [6] [7]. Bypassing or mangling Jigsaw’s dependency resolution would allow for a custom implementation to provide support for cyclic dependencies [5]. There is a proposal to allow more flexibility in terms of allowed characters and escaping with module names [6]. In summary, we believe fragmentation of the Java ecosystem must be avoided, as it will overly burden Java developers and stifle innovation. We remain hopeful that continued progress on these issues will not only prevent such an outcome, but allow the full Java community to embrace and benefit from standardized modularity. [1] http://openjdk.java.net/projects/jigsaw/spec/issues/#ReflectiveAccessToNonExportedTypes [2] http://openjdk.java.net/projects/jigsaw/spec/issues/#MutableConfigurations [3] http://openjdk.java.net/projects/jigsaw/spec/issues/#NonHierarchicalLayers [4] http://openjdk.java.net/projects/jigsaw/spec/issues/#LazyConfigurationAndInstantiation [5] http://openjdk.java.net/projects/jigsaw/spec/issues/#CyclicDependences [6] http://openjdk.java.net/projects/jigsaw/spec/issues/#ModuleNameCharacters [7] http://openjdk.java.net/projects/jigsaw/spec/issues/#ResourceExistenceAndSize ### [WildFly 10.1 is now available!](/news/2016/08/19/WildFly-10-1-is-now-available/) WildFly 10.1 is officially complete and available for download! Major new features include: Out of the box HTTP/2 support with no JVM flags required ! TLS cert auto-generation Load-balancing profile is now in our default domain.xml config Support for clustering node discovery on Azure (jgroups AZURE_PING) Additionally there was a massive 324 issues resolved in this release! Out of the Box HTTP/2 and TLS Unique to WildFly, is that HTTP/2 now works without any special JVM flags (even on Java 8!), configuration changes, or keystore changes. You simply point your browser at port 8443 and WildFly will automatically generate a self-signed TLS cert for you, and negotiate HTTP/2 if your browser supports it (most do). When you are ready to deploy in production, you simply update the keystore with whatever cert you would like to present to your users. Load-balancing Profile In order to make it even easier to get started with load-balancing, we added a profile to the default domain.xml file, called "load-balancer". You can now build a fully clustered topology using just our default profiles in domain mode, creating a server with the "load-balancer" profile, and a set of backend servers using the "full-ha" profile. Jira Release Notes The full list of issues resolved is available here. ### [WildFly 10 Final is now available!](/news/2016/01/30/WildFly-10-Final-is-now-available/) WildFly 10 Final is officially complete and available for download! WildFly 10 adds a number of capabilities and improvements to the powerful, yet lightweight, open-source application server. Java EE 7 As with WildFly 8 and WildFly 9, WildFly 10 implements the Java EE 7 Full and Web Profile standards. Builds on WildFly 9 In addition to the key features mentioned below, this release includes all the major features from 9, such as HTTP/2 support and a built in load-balancer. Java 8+ Java 7 support has been discontinued allowing for deeper integration with the Java 8 runtime. While Java 9 is still in development, this release runs on the current development snapshots. ActiveMQ Artemis A little over a year ago, the HornetQ codebase was donated to the Apache ActiveMQ project, and the HornetQ community joined to build a next-generation messaging broker. This materialized in the first major release of the ActiveMQ Artemis project. ActiveMQ Artemis includes many new features, and also retains protocol compatibility with the HornetQ broker. WildFly 10 includes this new exciting project as its JMS broker, and due to the protocol compatibility, it fully replaces the HornetQ project. Offline CLI Support for Domain Mode In addition to the offline CLI support for standalone mode, you can now launch a host-controller locally within the CLI. Using the embed-host-controller command you can edit the content of domain.xml and host.xml without launching additional processes or opening network sockets. JavaScript Support with Hot Reloading WildFly 10 includes the Undertow JS project, which allows you to write server side scripts that can pull in CDI beans and JPA Entity Beans. This can be quite useful for throwing together a quick view layer (perhaps using a templating language like Mustache, or a framework like Angular), or quickly developing a REST endpoint. You can edit the JS files live on the system, and they are dynamically reloaded, without having to redeploy your application. For more details see the following blog post: Using Server Side Javascript with Wildfly HA Singleton Deployments WildFly 10 adds the ability to deploy a given application as a "singleton deployment". This is a new implementation of a feature that existed in AS 6.0 and earlier. When deployed to a group of clustered servers, a singleton deployment will only deploy on a single node at any given time. If the node on which the deployment is active stops or fails, the deployment will automatically start on another node. The policies for controlling HA singleton behavior are managed by a new "singleton" subsystem. A deployment may either specify a specific singleton policy or use the default subsystem policy. A deployment identifies itself as singleton deployment via a /META-INF/singleton-deployment.xml deployment descriptor (the schema for which can be found on GitHub), which is most easily applied to an existing deployment as a deployment overlay. Alternatively, the requisite singleton configuration can be embedded within an existing jboss-all.xml. HA Singleton MDBs and MDB Delivery Groups Another advanced clustering capability in WildFly 10, singleton MDBs supports infrastructures which require message delivery on only single host at a time. In the event of a failure, another host in the cluster with the same application deployed will take over message processing. MDB delivery groups allow an administrator to selectively enable and disable a "delivery group" via a management operation, which is composed of one or more MDBs. This capability supports environments with an external custom failover mechanism. As with all management operations, these calls are accessible from the many management interfaces of WildFly, including the CLI, a Java API, and an HTTP/JSON API. SLSB and MDB Automatic Pool Sizing WildFly now pools stateless session beans by default, using a pool size that is computed relative to the size of the IO worker pool, which is itself auto-tuned to match system resources. Additionally MDBs now use a pool which is similarly tuned to a value derived from the number of CPUs on the system. Previously stateless sessions beans did not pool by default, and MDBs used a pool with a small hard-coded size. The values chosen are logged to an INFO message as part of startup. Manual tuning is still supported using the same max-pool-size attribute. Note that the default configurations shipped with WildFly 10 enable automatic pool sizing by using the derive-size attribute. Configurations used with previous versions of WildFly will need to be updated to take advantage of this capability. The intention is to preserve existing behavior as past configurations may have been explicitly tuned to best match deployed applications. While this capability improves the default pool size, achieving maximum performance would likely require specifically setting the size to match the patterns and needs of the application. Migration Operations for Discontinued Subsystems To help users migrating from old subsystems such as jbossweb (AS 7.1), jacorb (WildFly 8), and hornetq (WildFly 9), we have introduced a set of management operations that can convert old configuration over to the new respective subsystem equivalent. Since these operations migrate the underlying management resource model, old CLI scripts or custom provisioning systems can also take advantage of these. Capabilities and Requirements Subsystem developers now have the ability to negotiate interaction with other subsystems in a more pluggable way. This allows for subsystems to have dependencies that can be satisfied by more than one subsystem, which is particularly useful in providing multiple implementations of the same underlying capability. Additionally it leads to improved error reporting. Instead of a failure being reported at the service layer, which is how the WildFly runtime is mapped, it is instead reported at a higher level that is easier to connect to the server’s configuration. As an example, a missing socket binding is now reported as a missing socket binding, as opposed to a list of services with an unsatisfied dependency. Expect to see overall error reporting in WildFly improve as subsystems begin to adopt this ability. For more information, see the development guide. Hibernate 5 Hibernate 5 includes several additional improvements, such as greatly improved bytecode enhancement, which is a useful performance optimization. Additionally a number of API improvements are provided, including use of generics in Hibernate Native, and an improved SPI for second level cache providers. Also included are new and improved schema update and validation tooling. Powershell scripts Powershell scripts ware added to bin directory of WildFly distribution and are meant to fully replace .bat scripts in future releases. They provide same functionality as .bat scripts and additionally address handful of issues found in batch scripts. WildFly Jira Release Notes The following table has the complete list of issues resolved against the "full" branch during the development of WildFly 10. Table 1. WildFly 10 Releases Release Notes Issues Resolved 10.0.0.Final Full JIRA Release Notes 71 10.0.0.CR5 Full JIRA Release Notes 156 10.0.0.CR4 Full JIRA Release Notes 71 10.0.0.CR3 Full JIRA Release Notes 29 10.0.0.CR2 Full JIRA Release Notes 40 10.0.0.CR1 Full JIRA Release Notes 107 10.0.0.Beta2 Full JIRA Release Notes 42 10.0.0.Beta1 Full JIRA Release Notes 63 10.0.0.Alpha6 Full JIRA Release Notes 39 10.0.0.Alpha5 Full JIRA Release Notes 41 10.0.0.Alpha4 Full JIRA Release Notes 37 10.0.0.Alpha3 Full JIRA Release Notes 33 10.0.0.Alpha2 Full JIRA Release Notes 10 10.0.0.Alpha1 Full JIRA Release Notes 30 WildFly Core Jira Release Notes The following table has the complete list of issues resolved against the "core" container of WildFly 10. Table 2. WildFly Core 2 Releases Release Notes Issues Resolve 2.0.8.Final Full JIRA Release Notes 26 2.0.7.Final Full JIRA Release Notes 2 2.0.6.Final Full JIRA Release Notes 9 2.0.5.Final Full JIRA Release Notes 9 2.0.5.CR1 Full JIRA Release Notes 19 2.0.4.Final Full JIRA Release Notes 12 2.0.3.Final Full JIRA Release Notes 11 2.0.2.Final Full JIRA Release Notes 16 2.0.1.Final Full JIRA Release Notes 2 2.0.0.Final Full JIRA Release Notes 7 2.0.0.CR9 Full JIRA Release Notes 12 2.0.0.CR7 Full JIRA Release Notes 34 2.0.0.CR6 Full JIRA Release Notes 16 2.0.0.CR5 Full JIRA Release Notes 4 2.0.0.CR4 Full JIRA Release Notes 6 2.0.0.CR2 Full JIRA Release Notes 16 2.0.0.CR1 Full JIRA Release Notes 6 2.0.0.Beta7 Full JIRA Release Notes 20 2.0.0.Beta6 Full JIRA Release Notes 16 2.0.0.Beta5 Full JIRA Release Notes 21 2.0.0.Beta4 Full JIRA Release Notes 1 2.0.0.Beta3 Full JIRA Release Notes 13 2.0.0.Beta2 Full JIRA Release Notes 5 2.0.0.Beta1 Full JIRA Release Notes 2 2.0.0.Alpha13 Full JIRA Release Notes 10 2.0.0.Alpha12 Full JIRA Release Notes 4 2.0.0.Alpha11 Full JIRA Release Notes 14 2.0.0.Alpha10 Full JIRA Release Notes 9 2.0.0.Alpha9 Full JIRA Release Notes 31 2.0.0.Alpha8 Full JIRA Release Notes 9 2.0.0.Alpha6 Full JIRA Release Notes 14 2.0.0.Alpha5 Full JIRA Release Notes 26 2.0.0.Alpha4 Full JIRA Release Notes 10 2.0.0.Alpha3 Full JIRA Release Notes 18 2.0.0.Alpha2 Full JIRA Release Notes 4 2.0.0.Alpha1 Full JIRA Release Notes 12 ### [WildFly 10 CR5 is released!](/news/2015/12/23/WildFly-10-CR5-is-released/) The fifth release candidate for WildFly 10 (10.0.0.CR5) is now available for download! For details, see the official 10.0.0.CR5 Release Notes wiki page. Give it a try over the holidays, and let us know what you think! Provided there are no showstoppers, this will become the final 10 release. Enjoy! ### [Undertow.js 1.0.1.Final has been released](/news/2015/11/02/Undertow-js-1-0-1-Final-has-been-released/) Undertow.js 1.0.1.Final has been released. This allows you to integrate JavaScript and Java EE in your applications. There have been some notable changes since I first wrote about this at http://wildfly.org/news/2015/08/10/Javascript-Support-In-Wildfly/. Websocket Support It is now possible to use WebSockets with Undertow.js. You can declare a websocket handler with the websocket method, which takes a path and a connection handler. The connection handler gets passed the connection object, which can be used to send messages, and can respond to messages by setting the onText, onBinary and onClose functions. Binary messages are send and received using the JavaScript ArrayBuffer object. $undertow .websocket("/websocket1", ['cdi:myBean', function (myBean, connection) { connection.send(myBean.getConnectedMessage()); connection.onText = function(message) { return "echo-" + message; } connection.onBinary = function(message) { return message; } connection.onClose = function (message) { print(message.reason + " " + message.code); } }]); Declarative Security Declarative security allows you to specify the roles that are allowed to use a certain handler. This uses standard Servlet authentication, so if a user is not authenticated then the container will attempt to authenticate them using whatever authentication mechanism is defined in web.xml. The special role '**' means any authenticated user. To use this we simply need to add a roles_allowed list to a handlers options map: $undertow .onGet("/rest/endpoint", {roles_allowed: ['admin', 'user'], headers: {"content-type": "application/json"}}, [function ($exchange) { return {message: 'Hello World'}; }]) Transaction Support It is now possible to mark a handler as transactional, which means that a new transaction will be started when the method is invoked. If the method completes without an exception the transaction will be commited, otherwise it will be rolled back. To use this add transactional: true to the methods options map: $undertow .onGet("/rest/endpoint", {transactional: true, headers: {"content-type": "application/json"}}, [function ($exchange) { return {message: 'Hello World'}; }]) Option map defaults It is now possible to set defaults that will be applied to every that is declared after the option is set (i.e. setting a default will not affect any previously declared handlers, only new handlers). This can be used to set transaction or security defaults for all methods, or set a default set of response headers. It is possible to override the defaults by explicitly specifying the option in the options map. The handler below will behave the same as the transactional one above, however the defaults will be applied to any other handlers declared after the setDefault call: $undertow .setDefault('transactional', true) .setDefault('headers' {"content-type": "application/json"}) .onGet("/rest/endpoint", [function ($exchange) { return {message: 'Hello World'}; }]) Freemarker support As well as Mustache.js we now support Freemarker as a template engine. To use Freemarker as the template engine set template_type: 'freemarker' in the methods options map. If all your templates are Freemarker templates you can use setDefault('template_type', 'freemarker'). Going forward We would welcome any feedback or suggestions. If you want to contribute, or have any comments head to undertow-dev@lists.jboss.org. ### [WildFly 9.0.2 is released!](/news/2015/10/27/WildFly-9-0-2-is-released/) WildFly 9.0.2 is now available for download. This release includes a security update, bug fixes, and a few component updates. For more information, see the JIRA release notes. ### [WildFly 10 CR4 is released!](/news/2015/10/23/WildFly-10-CR4-is-released/) The fourth release candidate for WildFly 10 (10.0.0.CR4) is now available for download! For details, see the official 10.0.0.CR4 Release Notes wiki page. Give it a try and let us know what you think. If all goes well, this will be the last CR before the final release. Enjoy! ### [WildFly 10 CR2 is released!](/news/2015/09/25/WildFly-10-CR2-is-released/) The second release candidate for WildFly 10 (10.0.0.CR2) is now available for download! For details, see the official 10.0.0.CR2 Release Notes wiki page. Give it a try and let us know what you think. ### [WildFly 10 CR1 is released!](/news/2015/09/17/WildFly-10-CR1-is-released/) The first candidate for release of WildFly 10 (10.0.0.CR1) is now available for download! For details, see the official 10.0.0.CR1 Release Notes wiki page. Give it a try and let us know what you think. ### [WildFly 10 Beta2 is released!](/news/2015/08/23/WildFly-10-Beta2-is-released/) The WildFly 10.0.0.Beta2 release is now available for download! For details, see the official 10.0.0.Beta2 Release Notes wiki page. ### [WildFly Swarm 1.0.0.Alpha4 Released!](/news/2015/08/19/WildFly-Swarm-1-0-0-Alpha4-Released/) Once again, we’re delighted and enthralled to announce a release of WildFly Swarm. This time, it’s 1.0.0.Alpha4! That’s like one more than last time! This release has taken a few months, but it is chock-a-block full of awesome changes. But first, you might be wondering What is WildFly Swarm? Well, it’s WildFly, but dis-assembled and repackaged so that you can consume just the bits’n’bobs you need in order to build slimmer application services and run them from self-contained jars. What’s Changed? Now based upon WildFly 10.0.0.Beta1 Lots of new subsystems/fractions: Clustering EJB JAX-RS Multipart Support JMX JSF Keycloak Logstash Mail Netflix OSS Better source repository layout More tests Arquillian support NetflixOSS? In the world of microservices, the NetflixOSS suite of Ribbon and Hystrix make it pretty easy to hide a service behind an interface, find instances of services, and load-balance between them. In the default case, Ribbon uses the Netflix Eureka server to register and discover individual services. With WildFly Swarm, the standard clustering subsystem can be used to locate these services and maintain the lists of end-points. No additional servers are required to be running. Additionally, Ribbon has been extended to propagate Keycloak authentication tokens across the service calls if you’re also using Keycloak. Testing with Arquillian This release also brings integration with Arquillian, the fantastic tool that can not only manage your runtimes, but can inject test code directly into the running system. Normally Arquillian launches your server, deploys your app, runs your tests (either from outside the running app or within it), undeploys the app, and then stops the server. Since WildFly Swarm alters the concepts of "server" and "app", we’ve provided tight integration with Arquillian so that the same BuildTool used by the Maven and Gradle plugins is invoked to actually build your uberjar with your application (described by typical Arquillian @Deployment methods) and Arquillian launches it during the 'deploy' phase. You can still test from outside your app or inside the running process, as we provide support for all the relevant test-enhancers provided by Arquillian. The Arquillian support is definitely still a work-in-progress, so let us know if you have any suggestions for improving it. Documentation We’ve started writing some documentation, which you can contribute to: http://wildfly.org/swarm/ Examples? Yes indeedy! We have a bunch of buildable and runnable examples at GitHub in one handy repository: https://github.com/wildfly-swarm/wildfly-swarm-examples What do I download? There is no special download or installation instructions. Simply start using org.wildfly.swarm artifacts in your pom.xml, throw in the plugin and continue doing your builds. Stay in Touch You can keep up with the project through the WildFly HipChat room, @wildflyswarm on Twitter, or through GitHub Issues. ### [Using Server-Side JavaScript with WildFly](/news/2015/08/10/Using-Server-Side-JavaScript-with-WildFly/) The WildFly 10.0.0.Beta1 release includes support for an experimental new feature that allows you to use JavaScript on the server side, using the Nashorn JavaScript engine that is built into the JDK. Combined with another new feature that allows you to serve web resources from outside the deployment it is possible to write server-side code with no redeploy of copy step involved. This feature also allows Java EE resources such as CDI beans to be injected into your JavaScript handlers, allowing you to write your back end using Java, and the front end in JavaScript. This is a new feature, and as such may change before release based on user feedback. If you want to skip the tutorial and just want to see the code there are some examples at https://github.com/stuartwdouglas/undertow.js-examples Getting Started The first step is to tell WildFly where to find your JavaScript. To do this, we create a file WEB-INF/undertow-scripts.conf. In this file you list your server side JavaScript files, one per line. For the sake of this post, I will assume we have a single file, example.js. Note that even though the server JavaScript files are located in the web context, the JavaScript integration will not allow them to be served. If a user requests a server side JS file, a 404 will be returned instead. Setting up hot deployment To enable hot deployment create a file called WEB-INF/undertow-external-mounts.conf, and in this file add a single line that points to your local workspaces web content root (for example, /Users/stuart/workspace/jsexample/src/main/webapp). With this file in place resources will be served from your local workspace, instead of the deployment. This means that any changes you make to web resources or server-side JavaScript will be immediately visible as soon as you refresh your browser. This hot deployment mechanism is independent of the server side JS integration, and should work for any web resources. A simple HTTP endpoint $undertow .onGet("/hello", {headers: {"content-type": "text/plain"}}, [function ($exchange) { return "Hello World"; }]) Add this to your example.js file and point your browser at /hello. You should see your Hello World message appear. To test out hot deployment try modifying the message and refreshing your browser, the changes should be reflected immediately. Lets walk through the things that are happening here. $undertow is the entry point for all JavaScript functionality, it contains methods to register HTTP handlers, as well as some other utility methods. The onGet method registers a handler for GET requests. This method takes three parameters, the handler path, an (optional) options map, and a handler injection list (or just a plain handler function, if no injection is required). This function returns a string, which will be sent to the user as an HTTP response. Now lets try a simple JSON REST endpoint: $undertow .onGet("/rest/endpoint", {headers: {"content-type": "application/json"}}, [function ($exchange) { return {message: 'Hello World'}; }]) This is basically the same, the only difference is that a map is returned instead of a string. Any object other than simple strings that are returned from a handler function will be converted into JSON and sent to the client. Now let’s try out an injection, so our handler can interact with the app server. We will start by injecting the default datasource: $undertow .onGet("/rest/members", {headers: {"content-type": "application/json"}}, ['jndi:java:jboss/datasources/ExampleDS', function ($exchange, db) { return db.select("select * from members"); }]) JavaScript injection has the format 'type:name'. It uses angular.js style injection, where you pass in a list of injection specifiers, with the function to inject as the last item in the list. These injections will be resolved at runtime, and passed into the handler function in the order they are specified. The following injection types are supported out of the box: jndi This injection is looked up from JNDI, any item that can be looked up in JNDI can be injected into your JavaScript function. cdi This allows you to inject CDI beans into a handler. The beans are resolved by name, and as such must have the @Named annotation for them to be resolvable. $entity This allows the request entity to be injected directly into your function (for request types that have an entity, such as POST and PUT). By default this is injected as a string, however the following types are also supported. $entity:json injects parsed JSON. $entity:form injects parsed form or multipart encoded data. Undertow.js will also automatically wrap some objects (such as datasources) in a JavaScript friendly API. The raw JDBC API is not particularly script friendly, so in the example above the DataSource that is injected is actually a wrapper that supports the select, selectOne and query methods. With any wrapped object you can access the underlying Java object using the objects $underlying property. Going back to our example above, there are two issues with it: We have not set up any tables or added any data to the database. Writing the full JNDI name every time is cumbersome and error prone. Lets address those issues: $undertow .alias('db', 'jndi:java:jboss/datasources/ExampleDS') .onGet("/rest/members", {headers: {"content-type": "application/json"}}, ['db', function ($exchange, db) { return db.select("select * from member"); }]); var db = $undertow.resolve("db"); try { db.query("create table member (id serial primary key not null, name varchar(100), email varchar(100) unique, phone_number varchar(100))"); db.query("insert into member (id, name, email, phone_number) values (0, 'John Smith', 'john.smith@mailinator.jsp.com', '2125551212')"); db.query("insert into member (id, name, email, phone_number) values (1, 'Stuart Douglas', 'stuart@notmyrealaddress.com', '0487694837')"); } catch(e) { print("DB create failed") } We have added two things to this handler, the first is a call to alias, that allows us to alias commonly used names to shorter versions, and the second is some code to create the database. This DB setup code is mostly for example purposes, and is not a recommended approach, as every time this file is modified it will attempt to re-setup the database (and fail, as the table already exists). Templates There is also support for templates, at the moment Undertow.js supports Mustache, with plans to support more in the future. To use a template simply specify the template name in the parameter map, the template will be rendered using the return value of your function as the data. An example is shown below: $undertow .onGet("/hello", {template: 'hello.txt', headers: {"content-type": "text/plain"}}, [function ($exchange) { return {name: 'Stuart'}; }]); And in hello.txt: Hello {{name}} Handling POST requests POST (and other requests that contain a body) can be handled using entity injection. The body can be injected as a string, or one of the built in parsers can be used to parse JSON or form encoded data (including multipart data). An example of all three approaches is shown below: $undertow .onPost("/string", {headers: {"content-type": "text/plain"}}, ['$entity', function ($exchange, entity) { return "You posted: " + entity; }]) .onPost("/json", {headers: {"content-type": "text/plain"}}, ['$entity:json', function ($exchange, entity) { return "You posted: " + entity['name']; }]) .onPost("/form", {headers: {"content-type": "text/plain"}}, ['$entity:form', function ($exchange, entity) { return "You posted: " + entity.get('name'); }]) Going forward At the moment the following additional features are planned: Support for more template engines Support for declarative security This feature is very new, and will evolve over the coming months based on user feedback. If you want to contribute, or have any suggestions/comments head to undertow-dev@lists.jboss.org. ### [WildFly 10 Beta is released!](/news/2015/08/09/WildFly-10-Beta-is-released/) The WildFly 10.0.0.Beta1 release is now available for download! Notable highlights include: Continued Java EE7 Support Java 8+ Required ActiveMQ Artemis JavaScript Support with Hot Reloading Offline CLI Support For Domain Mode HA Singleton Deployments Migration Operations for Legacy Subsystems Capabilities and Requirements Hibernate 5 Infinispan 8 These are covered in more detail on the official 10.0.0.Beta1 Release Notes wiki page ### [Centralized Logging for WildFly with the ELK Stack](/news/2015/07/26/Centralized-Logging-for-WildFly-with-the-ELK-Stack/) The ELK stack; elasticsearch, logstash and kibana can be used for centralize logging. It’s not the intention of this post to be a tutorial on how to configure logstash. We will go through a basic logstash configuration then configure WildFly to send log messages to logstash. Download and Configure logstash First we need to download logstash. Once the download is complete simply extract logstash from the archive. Next we will need to create a configuraton file. In the logstash directory create a file called logstash-wildfly.conf and add the following content to the configuration file. input { tcp { port => 8000 } } filter { json { source => "message" } } output { elasticsearch { # Use the embedded elsasticsearch for convienence embedded => true protocol => "http" } } Start logstash with the configuration file we just created ./bin/logstash agent -f logstash-wildfly.conf. In the example configuration above logstash should be listening on port 8000. Make note of the port you use as we’ll need it later when configuring WildFly. Configure WildFly If you don’t have a local install of WildFly you’ll want to download a recent version. In my example I’ll be use WildFly 9.0.1.Final. However any other version should work the same. We also need to download the jboss-logmanager-ext library so that we can install it as a module. This library includes the formatter and handler we’ll use for logging. Start up WildFly in admin-only mode so we can configure logging, $JBOSS_HOME/bin/standalone.sh --admin-only. Once the server is running start a CLI console, $JBOSS_HOME/bin/jboss-cli.sh -c, to install the module and configure logging. The following commands can be entered manually or placed in a CLI script. batch # Add the module, replace the directory on the resources attribute to the path where you downloaded the jboss-logmanager-ext library module add --name=org.jboss.logmanager.ext --dependencies=org.jboss.logmanager,javax.json.api,javax.xml.stream.api --resources=~/tmp/jboss-logmanager-ext-1.0.0.Alpha3.jar # Add the logstash formatter /subsystem=logging/custom-formatter=logstash:add(class=org.jboss.logmanager.ext.formatters.LogstashFormatter,module=org.jboss.logmanager.ext) # Add a socket-handler using the logstash formatter. Replace the hostname and port to the values needed for your logstash install /subsystem=logging/custom-handler=logstash-handler:add(class=org.jboss.logmanager.ext.handlers.SocketHandler,module=org.jboss.logmanager.ext,named-formatter=logstash,properties={hostname=localhost, port=8000}) # Add the new handler to the root-logger /subsystem=logging/root-logger=ROOT:add-handler(name=logstash-handler) # Reload the server which will boot the server into normal mode as well as write messages to logstash :reload run-batch With these changes WildFly should be writing to logstash. You can view the log messages from logstash with kibana. With the defaults we used you should just be able to start kibana with bin/kibana and the default configuration. My dashboard looks like the following. Conclusion If you’re already using the ELK stack for centralized logging adding WildFly to the aggregation is rather simple. If you’re just looking for a way to view and filter log messages using the ELK stack with WildFly could be a good fit as well. One thing to note is if you’re seeing performance issues or you’re writing to a remote logstash server you may want to use an async-handler. ### [WildFly 9.0.1.Final and 8.2.1.Final are released.](/news/2015/07/23/WildFly-9-0-1-Final-and-8-2-1-Final-are-released/) WildFly 9.0.1.Final and 8.2.1.Final are now available for download. These releases include security updates and bug fixes. For more details see the release notes for 8.2.1 here and 9.0.1 here. ### [WildFly 9 Final is released!](/news/2015/07/02/WildFly-9-Final-is-released/) The WildFly 9 Final release is now available for download! Java EE7 As with WildFly 8, WildFly 9 is a certified implemenation of both the Java EE7 full and web profile specifications. HTTP/2 Support Undertow, the web server in WildFly, has added support for the new HTTP/2 standard. HTTP/2 reduces latency by compressing headers and multiplexing many streams over the same TCP connection. It also supports the ability for a server to push resources to the client before it has requested them, leading to faster page loads. We also included support for SPDY, the predecessor to HTTP/2, in order to support clients that have not yet updated to the new specification. Although, currently, recent versions of Chrome and Firefox provide support for the standard out of the box. Note that using HTTP/2 requires using Java 8 with a specialized setup procedure. This is because the HTTP/2 standard requires a TLS stack that supports ALPN, and a stock Java install does not include support for it. The extra setup steps will go away once Java 9 is released, which is expected to include ALPN support. Since HTTP/2 is also a goal for Java EE8, it is also expected to be made available in a future Java SE 8 update, likely after Java 9 is released. Front End Load Balancer Support WildFly can now be configured to function as an intelligent load balancer, proxying requests to backend WildFly nodes using HTTP, HTTP/2, SPDY, and mod_cluster protocols. This removes the need to use a native web server, such as Apache for this use case. To see this feature in action, check out this interview with Stuart Douglas, the lead of the Undertow project. He demonstrates how domain management, clustering, and the new load balancing capability can be used to deploy and manage a full HA setup from a single point, the WildFly CLI. Server Suspend Mode / Graceful Shutdown Previously, in order to achieve graceful draining of sessions/requests, a load balancer was required. The new server suspend mode in WildFly, once activated rejects new requests but allows old ones to complete. Once the suspension process has completed the server can either be stopped without aborting in-flight transactions, left in suspended state while maintenance is performed, or returned back to running state where new requests are once again allowed. Offline CLI Support You can now manage the server using CLI commands, without having a running server. This works similar to the admin-only mode, but does not require launching the server, and using a TCP port. Instead the CLI embeds the server and launches it directly in admin-only mode. For more information, check out the detailed article on this feature, written by Brian Stansberry, the lead of WildFly’s domain management capabilities. New Servlet-Only Distribution The new "WildFly Servlet" distribution, provides a stripped down, yet fully manageable Servlet-only distribution. This is useful for applications that prefer to roll-their-own frameworks, and wish to conserve disk space. Core / Full Split The base architecture of WildFly has been fully separated, and is now versioned separately from the full platform. We now have two different source repositories as a result. Table 1. Split Repositories Ditribution Location JIRA Location Core wildfly/wildfly-core · GitHub WildFly Core - JBoss Issue Tracker Full & Servlet wildfly/wildfly · GitHub WildFly - JBoss Issue Tracker Logging The logging subsystem now supports direct downloads of log files. The log-file mangagement resource lists all log files defined in the jboss.server.log.dir that are defined in the subsystem. Curl Example: curl --digest -L -D - http://127.0.0.1:9990/management?useStreamAsResponse --header "Content-Type: application/json" -u user:password.1234 -d '{"operation":"read-attribute","address":[{"subsystem":"logging"},{"log-file":"server.log"}],"name":"stream"}' HTTP Get Example: http://localhost:9990/management/subsystem/logging/log-file/server.log?operation=attribute&name=stream&useStreamAsResponse Web Services The Web Services subsystem is now based on JBossWS 5.0.0.Final. This is a major leap forward, bringing new features and performance improvements in WildFly. Notable new featues include: Upgrade to Apache CXF 3 series WSDL soap:address rewrite improvements Convention for automatic assignment of pre-defined endpoint and client configurations Apache CXF interceptors' declaration through properties Apache CXF HTTP Conduit configuration through system properties JBossWS 5 migration notes are also available for those migrating existing applications from WildFly 8 / JBossWS 4. Switched to the OpenJDK Orb We have switched our IIOP implementation from JacORB to a downstream branch of the OpenJDK Orb. This change should lead to better interoperability with the JVM ORB and the Java EE RI. Clustering All clustering services, including all Infinispan caches, will now share a single JGroups channel by default. The channels supplied by the JGroups subsystem are now fully managed resources and can multiplex messages to any number of "forks" via the FORK protocol. This requires fewer resources than the multi-channel, shared transport configuration of previous releases. JCA & JDBC The IronJacamar container has been upgraded to version 1.2.4.Final, fixing bugs and adding some new features. Highlights include: max-pool-size is now applied across all credentials used for the resource Pool type is determined by the decrementer policy Allow an existing connection to be obtained during MARKED_FOR_ROLLBACK Support validate-on-match for resource adapter deployments Support for the IronJacamar tracer module datasource:enable / datasource:disable is now deprecated ds.xml deployments are now deprecated in favor of the Java EE standard mechanism Management Console The managment console includes a new improved UI layout, as well as many additional capabilities including: New subsystem configuration: Remoting Support for datasource templates. Quickly configure the most commonly used datasources (PostgreSQL, MySQL, Oracle, SQLServer, DB2 and Sybase) Support for flush-* operations for connection pools Improved log viewer: The full log file is now displayed. You can search inside a log file or download and open it in an external editor. Enhanced model browser with support for singleton resources Get more details about applied patches Ability to launch the management console independently from WildFly. See the HAL development docs for more details. ### [WildFly Swarm 1.0.0.Alpha3 Released!](/news/2015/06/18/WildFly-Swarm-1-0-0-Alpha3-Released/) Once again, we’re delighted and enthralled to announce a release of WildFly Swarm. This time, it’s 1.0.0.Alpha3! Since this follows quickly on the heels of the last release, there’s not a whole lot of major changes. Rather, we’ve fixed some things, enhanced others, written some tests, and generally knocked it together a little sturdier. Changes Based on WildFly 9.0.0.CR2. You can now stop() the container. Better classloading for javax.* stuff. JPA improvements: Default datasources are now available. JPA is usable from within a normal WAR. WebSocket API included in the Undertow fraction. More configuration through the wildfly-swarm-maven-plugin. Serve static content (with or without a WAR/JAX-RS deployment). Magical favicon.ico support for JAX-RS deployments, mostly to avoid ugly stack-traces in the console. Documentation We’ve started writing some documentation, which you can contribute to: http://wildfly.org/swarm/ Examples? Yes indeed! We have a bunch of buildable and runnable examples at GitHub in one handy repository: https://github.com/wildfly-swarm/wildfly-swarm-examples What do I download? There is no special download or installation instructions. Simply start using org.wildfly.swarm artifacts in your pom.xml, throw in the plugin and continue doing your builds. Everything should be available through Maven Central shortly, and is in JBoss Nexus now for the impatient. Stay in Touch You can keep up with the project through the WildFly HipChat room, @wildflyswarm on Twitter, or through GitHub Issues. ### [WildFly 9 CR2 is released!](/news/2015/06/11/WildFly-9-CR2-is-released/) I’m happy to announce the WildFly 9.0.0.CR2 release! This release addresses a number issues discovered during the CR1 cycle, and also includes a major UX update to the console. For those new to WildFly 9, it builds off of WildFly 8’s Java EE7 support, and adds many new capabilities, including intelligent load balancing, HTTP/2 support, a new offline CLI mode, graceful single node shutdown, and a new Servlet-only distribution. Provided no major issues are discovered, we hope to release Final within the next couple of weeks. Enjoy! ### [WildFly Swarm Alpha2](/news/2015/06/05/WildFly-Swarm-Alpha2/) We’ve been churning through the improvements and fixes for Alpha2! Windows All the Windows issues are now resolved. You can enjoy the benefits of WildFly Swarm on your operating system of choice. Modify your Application from Alpha1 We’ve made a few changes to how the plugin works which means that you will need to update any applications that are already utilizing Alpha1: Remove the execution phase from the wildfly-swarm-plugin Change the goal of the wildfly-swarm-plugin from create to package Remove the provided scope from all WildFly Swarm dependencies in your pom.xml Weld and JAX-RS There were some WildFly modules missing when you wanted to use Weld with JAX-RS, so we’ve created a new fraction to cater for this combination. Simply add the following dependency: <dependency> <groupId>org.wildfly.swarm</groupId> <artifactId>wildfly-swarm-weld-jaxrs</artifactId> <version>${version.wildfly-swarm}</version> </dependency> JPA This release brings initial support for JPA projects. There are improvements planned for Alpha3 to make it even easier, but right now your project needs to have jar packaging, not war, and you will need your own Main: public class Main { public static void main(String[] args) throws Exception { Container container = new Container(); container.start(); // Create a JDBC driver deployment using maven groupId:artifactId // The version is resolved from your pom.xml's <dependency> DriverDeployment driverDeployment = new DriverDeployment(container, "com.h2database:h2", "h2"); container.deploy(driverDeployment); // Create a DS deployment DatasourceDeployment dsDeployment = new DatasourceDeployment(container, new Datasource("ExampleDS") .connectionURL("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE") .driver("h2") .authentication("sa", "sa") ); container.deploy(dsDeployment); // Create the WAR and bundle all the JPA Entities and persistence.xml WarDeployment deployment = new DefaultWarDeployment(container); deployment.getArchive().addClasses(Employee.class); deployment.getArchive().addClass(EmployeeServlet.class); deployment.getArchive().addAsWebInfResource(new ClassLoaderAsset("META-INF/persistence.xml", Main.class.getClassLoader()), "classes/META-INF/persistence.xml"); deployment.getArchive().addAsWebInfResource(new ClassLoaderAsset("META-INF/load.sql", Main.class.getClassLoader()), "classes/META-INF/load.sql"); container.deploy(deployment); } } More ways to run your WildFly Swarm Application! As with Alpha1 you can run your generated self-contained executable with: java -jar ./target/myproject-1.0-swarm.jar With Alpha2 you can also run it from the command line, without building the project: mvn wildfly-swarm:run or run the Main class of your application, or org.wildfly.swarm.Swarm if you don’t have one, directly within your favorite IDE! Examples? Yes indeed! We have a bunch of buildable and runnable examples at GitHub: Servlet WAR JAX-RS WAR JAX-RS with ShrinkWrap JAX-RS with CDI Datasource via Subsystem Config Datasource via Deployment JBoss MSC Services Messaging, JAX-RS and MSC Transactions and JAX-RS CDI and Servlet JPA and Servlet JPA, JAX-RS and CDI What do I download? There is no special download or installation instructions. Simply start using org.wildfly.swarm artifacts in your pom.xml, throw in the plugin and continue doing your builds. Everything is available through Maven Central. Stay in Touch You can keep up with the project through the WildFly HipChat room, @wildflyswarm on Twitter, or through GitHub Issues. ### [WildFly Swarm Initial Release](/news/2015/05/05/WildFly-Swarm-Initial-Release/) Happy Cinco De Mayo! Crack open a cold adult beverage and start retooling your JavaEE skills towards microservices. What is WildFly Swarm? WildFly Swarm [1] is a new sidecar project supporting WildFly 9.x to enable deconstructing the WildFly AS and pasting just enough of it back together with your application to create a self-contained executable jar. JAX-RS is a microservice? In the simplest case, you make small adjustments to your existing Maven pom.xml that generates a WAR file and you’ll get another artifact with a name akin to myproject-1.0-swarm.jar. Simply add the wildfly-swarm-plugin to your pom.xml: <plugin> <groupId>org.wildfly.swarm</groupId> <artifactId>wildfly-swarm-plugin</artifactId> <version>${version.wildfly-swarm}</version> <executions> <execution> <phase>package</phase> <goals> <goal>create</goal> </goals> </execution> </executions> </plugin> Add a <dependency> block or two: <dependency> <groupId>org.wildfly.swarm</groupId> <artifactId>wildfly-swarm-jaxrs</artifactId> <version>${version.wildfly-swarm}</version> <scope>provided</scope> </dependency> Build your project: mvn package And run that sucker: java -jar ./target/myproject-1.0-swarm.jar Can I get fancier? You betcha! Since WildFly Swarm is based upon WildFly 9.x, you have most of the power of WildFly available to you. This includes subsystems such as: Undertow (Servlets) JAX-RS Naming/JNDI Transactions Messaging Datasources Logging Weld (CDI) JBoss MSC Security Additionally, if you want to provide your own main(…​) method to instantiate the Container, configure some of the subsystems, and perform whatever deployments you need, that’s possible also! public class Main { public static void main(String[] args) throws Exception { Container container = new Container(); container.subsystem(new MessagingFraction() .server( new MessagingServer() .enableInVmConnector() .topic("my-topic") .queue("my-queue") ) ); // Start the container container.start(); JaxRsDeployment appDeployment = new JaxRsDeployment(); appDeployment.addResource(MyResource.class); // Deploy your JAX-RS app container.deploy(appDeployment); // Create an MSC deployment ServiceDeployment deployment = new ServiceDeployment(); deployment.addService(new MyService("/jms/topic/my-topic" ) ); // Deploy the services container.deploy( deployment ); } } Can I use it in production? We wouldn’t recommend it. We just released 1.0.0.Alpha1. It’s pretty new and we’re sure there’s some dark corners that we have not addressed. If you come across any issues or desire any improvements, file an issue over at GitHub, and we’ll do our best to make you happy. Do you have more examples? Yes indeed! We have a bunch of buildable and runnable examples at GitHub: Servlet WAR JAX-RS WAR JAX-RS with ShrinkWrap JAX-RS with ShrinkWrap Datasource via Subsystem Config Datasource via Deployment JBoss MSC Services Messaging, JAX-RS and MSC What do I download? There is no special download or installation instructions. Simply start using org.wildfly.swarm artifacts in your pom.xml, throw in the plugin and continue doing your builds. Everything is available through Maven Central. Stay in Touch You can keep up with the project through the WildFly HipChat room, @wildflyswarm on Twitter, or through GitHub Issues. 1. never to be called just "Swarm", because Legal ### [WildFly 9 CR1 is released!](/news/2015/05/01/WildFly-9-CR1-is-released/) I’m happy to announce WildFly 9.0.0.CR1! WildFly 9 builds off of WildFly 8’s Java EE7 support, and adds many new capabilities, including intelligent load balancing, HTTP/2 support, a new offline CLI mode, graceful single node shutdown, and a new Servlet-only distribution. For more details, check out the full release notes. Provided no major issues are discovered, we plan to move to Final fairly quickly, sometime in May. Enjoy! ### [WildFly 9 Beta is released!](/news/2015/03/27/WildFly-9-Beta-is-released/) I’m happy to announce the beta release of WildFly 9! WildFly 9 builds off of WildFly 8’s Java EE7 support, and adds many new capabilities, including intelligent load balancing, HTTP/2 support, a new offline CLI mode, graceful single node shutdown, and a new Servlet-only distribution. For more details, check out the full release notes. Provided no major issues are discovered, we plan to move to CR fairly quickly, sometime in April. Enjoy! ### [Running an Embedded WildFly 9 Server in the CLI](/news/2015/03/14/Running-an-Embedded-WildFly-9-Server-in-the-CLI/) In WildFly 9 Beta1 we are introducing a new capability to our Command Line Interface (CLI) tool: the ability to embed a WildFly standalone server process inside the CLI process, with the CLI interacting with the embedded server in a manner consistent with how it interacts with a remote WildFly server. All of the standard CLI commands that you can use to administer a remote server are available. The immediate goal is to support direct local administration of a WildFly installation via the CLI without requiring a socket-based connection. The general use case is initial setup type activities where the user doesn’t want to have to launch a WildFly server and have it be visible on the network. RBAC configuration and other management security configuration is one use case; another is a desire users have expressed to be able to do configuration without first having to edit any xml to avoid port conflicts on 9990 or 9999. Longer term, since the CLI is itself embeddable, this opens up the possibility of embedding the CLI inside some other process (say a test class, a provisioning tool or a jar with a main) and then launching the embedded server and using the embedded CLI as a convenient management tool. For example, an installer or other provisioning tool could include in its own configuration a small amount of CLI script, which the tool would use to customize a stock WildFly configuration, say by adding a datasource configuration. The user of the tool would only need to understand the CLI script. Simple Example Here I start the CLI in a modular environment, launch an embedded server, do a couple simple CLI things, and stop the embedded server: $ bin/jboss-cli.sh You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands. [disconnected /] embed-server --std-out=echo 12:10:15,300 INFO [org.jboss.modules] (main) JBoss Modules version 1.4.1.Final 12:10:15,983 INFO [org.jboss.msc] (main) JBoss MSC version 1.2.4.Final 12:10:16,049 INFO [org.jboss.as] (MSC service thread 1-6) WFLYSRV0049: WildFly Full 9.0.0.Alpha2-SNAPSHOT (WildFly Core 1.0.0.Alpha18-SNAPSHOT) starting 12:10:16,891 INFO [org.jboss.as.controller.management-deprecated] (Controller Boot Thread) WFLYCTL0028: Attribute enabled is deprecated, and it might be removed in future version! 12:10:17,055 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 9.0.0.Alpha2-SNAPSHOT (WildFly Core 1.0.0.Alpha18-SNAPSHOT) started in 7113ms - Started 35 of 48 services (19 services are lazy, passive or on-demand) [standalone@embedded /] ls -l ATTRIBUTE VALUE TYPE launch-type EMBEDDED STRING management-major-version 3 INT management-micro-version 0 INT management-minor-version 0 INT name taozi STRING namespaces [] OBJECT process-type Server STRING product-name WildFly Full STRING product-version 9.0.0.Alpha2-SNAPSHOT STRING profile-name undefined STRING release-codename Kenny STRING release-version 1.0.0.Alpha18-SNAPSHOT STRING running-mode ADMIN_ONLY STRING schema-locations [] OBJECT server-state running STRING suspend-state RUNNING STRING CHILD MIN-OCCURS MAX-OCCURS core-service n/a n/a deployment n/a n/a brew unlink gcc-4.2 deployment-overlay n/a n/a extension n/a n/a interface n/a n/a path n/a n/a socket-binding-group n/a n/a subsystem n/a n/a system-property n/a n/a [standalone@embedded /] cd socket-binding-group=standard-sockets/socket-binding=management-http [standalone@embedded socket-binding=management-http] :write-attribute(name=port,value=19990) {"outcome" => "success"} [standalone@embedded socket-binding=management-http] reload --admin-only=false 12:12:34,615 INFO [org.jboss.as] (MSC service thread 1-16) WFLYSRV0050: WildFly Full 9.0.0.Alpha2-SNAPSHOT (WildFly Core 1.0.0.Beta1) stopped in 16ms 12:12:34,621 INFO [org.jboss.as] (MSC service thread 1-16) WFLYSRV0049: WildFly Full 9.0.0.Alpha2-SNAPSHOT (WildFly Core 1.0.0.Beta1) starting . . . . 12:12:36,176 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 9.0.0.Beta1 (WildFly Core 1.0.0.Beta1) started in 1505ms - Started 202 of 379 services (210 services are lazy, passive or on-demand) [standalone@embedded socket-binding=management-http] stop-embedded-server 12:12:43,352 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-5) WFLYJCA0010: Unbound data source [java:jboss/datasources/ExampleDS] 12:12:43,352 INFO [org.wildfly.extension.undertow] (MSC service thread 1-8) WFLYUT0019: Host default-host stopping 12:12:43,364 INFO [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-13) WFLYJCA0019: Stopped Driver service with driver-name = h2 12:12:43,368 INFO [org.wildfly.extension.undertow] (MSC service thread 1-4) WFLYUT0008: Undertow HTTP listener default suspending 12:12:43,380 INFO [org.wildfly.extension.undertow] (MSC service thread 1-4) WFLYUT0007: Undertow HTTP listener default stopped, was bound to /127.0.0.1:8080 12:12:43,384 INFO [org.wildfly.extension.undertow] (MSC service thread 1-13) WFLYUT0004: Undertow 1.2.0.Beta8 stopping 12:12:43,393 INFO [org.jboss.as] (MSC service thread 1-7) WFLYSRV0050: WildFly Full 9.0.0.Beta1 (WildFly Core 1.0.0.Beta1) stopped in 13ms [disconnected socket-binding=management-http] quit Here I do a similar thing, but using the non-modular jboss-cli-client.jar included in the bin/client directory of the WildFly distribution. I also don’t include the --std-out=echo param, so I don’t see the server logging in the console: $ java -jar bin/client/jboss-cli-client.jar You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands. [disconnected /] embed-server --jboss-home=/home/brian/dev/wildfly/dist/target/wildfly-9.0.0.Alpha2-SNAPSHOT [standalone@embedded /] cd socket-binding-group=standard-sockets/socket-binding=management-http [standalone@embedded socket-binding=management-http] :read-attribute(name=port) { "outcome" => "success", "result" => 19990 } [standalone@embedded socket-binding=management-http] quit I’ll explain the --jboss-home parameter below. See Modular vs Non-Modular Classloading and JBOSS_HOME. Finer points Specifying the Server Configuration The embed-server command supports -c and --server-config parameters that can be used to specify the name of the configuration file to use. If not specified, the default is standalone.xml. [disconnected /] embed-server --server-config=standalone-full.xml Starting with an Empty Configuration Embedding the server opens up the possibility of starting from a completely empty, even non-existent, configuration. Such a configuration makes no sense without embedding, as no configuration means no remote management interface, and thus no means to change the configuration to something useful. But a server embedded in the CLI tool doesn’t have that problem. So, the embed-server command allows you to specify that an initially empty configuration should be used: [disconnected /] embed-server --server-config=my-config.xml --empty-config That command will fail if file $JBOSS_HOME/standalone/configuration/my-config.xml already exists. This is to avoid accidental deletion of a configuration file. However, you can specify that you want any existing configuration removed: [disconnected /] embed-server --server-config=my-config.xml --empty-config --remove-existing Here I launch the CLI telling it to run a CLI script (available here) that starts an embedded server with an empty configuration and then uses CLI commands to build the entire server configuration. The resulting configuration is equivalent to the standard standalone-full-ha.xml config that ships with WildFly: $ bin/jboss-cli.sh --file=/home/bstansberry/tmp/embedded-server.txt The batch executed successfully The batch executed successfully process-state: reload-required $ The script is long but conceptually straightforward. First it launches the embedded server: embed-server --server-config=standalone-empty.xml --empty-config --remove-existing Then it runs a CLI batch to add all the desired extensions: # Extensions first batch /extension=org.jboss.as.clustering.infinispan:add /extension=org.jboss.as.clustering.jgroups:add /extension=org.jboss.as.connector:add . . . . /extension=org.wildfly.extension.undertow:add /extension=org.wildfly.iiop-openjdk:add run-batch Once this batch runs, the server will understand the management APIs exposed by those extensions, so the rest of the configuration can be applied. This is done in a second batch: # Other batch /core-service=management/security-realm=ManagementRealm:add(map-groups-to-roles=false) . . . . /subsystem=webservices/client-config=Standard-Client-Config:add /subsystem=weld:add run-batch It works! $ bin/standalone.sh -c standalone-empty.xml ========================================================================= JBoss Bootstrap Environment JBOSS_HOME: /Users/bstansberry/dev/wildfly/wildfly/dist/target/wildfly-9.0.0.Alpha2-SNAPSHOT JAVA: /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/bin/java JAVA_OPTS: -server -XX:+UseCompressedOops -server -XX:+UseCompressedOops -Xms64m -Xmx512m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true ========================================================================= 12:24:45,565 INFO [org.jboss.modules] (main) JBoss Modules version 1.4.1.Final 12:24:45,775 INFO [org.jboss.msc] (main) JBoss MSC version 1.2.4.Final 12:24:45,843 INFO [org.jboss.as] (MSC service thread 1-6) WFLYSRV0049: WildFly Full 9.0.0.Beta1 (WildFly Core 1.0.0.Beta1) starting . . . . 12:24:48,649 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management 12:24:48,649 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990 12:24:48,649 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 9.0.0.Beta1 (WildFly Core 1.0.0.Beta1) started in 3365ms - Started 246 of 478 services (281 services are lazy, passive or on-demand) Admin-only Mode By default the embedded server will be started in admin-only mode. This is because the main expected use cases are for initial configuration. A server running in admin-only mode will only start services related to server administration but will not start other services or accept end user requests. This can be changed with a parameter to the embed-server command: [disconnected /] embed-server --admin-only=false Same as with a non-embedded server, a server can be moved in and out of admin-only using the CLI reload command: [standalone@embedded /] reload --admin-only=false Admin-only Mode and the Server’s Management Interfaces One of the goals of this work is to support use cases where the server being configured is completely invisible on the network. Normally, the management interfaces themselves open sockets (e.g. port 9990, 9999), even when the server is in admin-only mode. But, what if there is a port conflict on those ports, with the purpose of using the offline CLI being to change settings to avoid the conflict? To account for this, we have changed the behavior of the management interface resources. Now, if those resources detect they are running in an embedded server and the running mode is admin-only, the services for the remote management interfaces will not be started. The server will not be visible to remote management clients. Controlling stdout The CLI uses stdout heavily. The embedded server may also want to write to stdout, particularly for console logging. These two uses of stdout have the potential to interfere with each other, particularly in an interactive session where the CLI may output a command prompt and then the server logs something, resulting in the prompt being in the middle of server log messages, possibly in the middle of a line. The interactive CLI will still work if this happens, but it can be disorienting. The embed-server command includes a parameter to allow the user to control what happens to output the embedded server writes to stdout: --std-out=echo — the output from the server is allowed to go to the CLI’s stdout, allowing the user to see logging, but at the risk of mixing the CLI prompt with server logging --std-out=discard — the output the server attempts to send to stdout is discarded. Users should look at the server.log file to see server logging. The default behavior is --std-out=discard Boot Timeout By default, the embed-server command will block indefinitely waiting for the embedded server to reach server-state running; i.e. to complete boot. The amount of time to wait can be controlled by using the --timeout parameter [disconnected /] embed-server --timeout=30 The value is in seconds. A value of less than 1 means the embed-server command will not block waiting for boot to complete. Rather, it will return as soon as boot proceeds to the point where the internal ModelController service is available, allowing the CLI to obtain an internal client to use to execute management operations. A server in admin-only mode would typically boot very quickly, so configuring this timeout would be more useful when --admin-only=false is used. Stopping the Embedded Server To stop an embedded server but continue with your CLI session, use the stop-embedded-server command: [standalone@embedded /] stop-embedded-server [disconnected /] If you also want to exit the CLI session, you can simply use the standard quit command: [standalone@embedded /] quit $ The embedded server will be stopped cleanly. When an embedded server is running, the CLI shutdown command usually used to stop a remote server is not available. The shutdown command has some behavior somewhat inconsistent with embedded server operation, so we chose to use a separate command for the embedded case. Modular vs Non-Modular Classloading and JBOSS_HOME As shown in the Simple Example section above, the CLI can either be running in a modular classloading environment (bin/jboss-cli.sh example) or in a flat classpath (java --jar bin/client/jboss-cli-client.jar example.) Either way, the embedded server runs in a modular classloading environment. There are some behavior differences between the two cases though: If the CLI is running in a modular classloading environment: the embedded server will use the same boot module loader as the CLI. The implication here is the CLI and server are running from the same WildFly installation, with the same module path and therefore the same set of modules available. the embedded server will need to know where the root of the WildFly installation is. This must be provided to the CLI via the JBOSS_HOME environment variable. The jboss-cli.sh script sets this. If some other mechanism is used for starting the CLI, the JBOSS_HOME environment variable must be set. If the CLI is not running in a modular classloading environment: the embedding logic will set up an appropriate modular classloading environment for the server. The module path for the modular classloader will have a single element: <root_of_wildfly_installation>/modules the embedded server will need to know where the root of the WildFly installation is. This must be provided to the CLI via one of the following mechanisms: the JBOSS_HOME environment variable the --jboss-home parameter to the embed-server command. If this is set, it takes precedence over any JBOSS_HOME environment variable The --jboss-home parameter to the embed-server command is not supported in a modular CLI environment, as it would imply that the root of the embedded server could be something other than the root of the install from which the CLI is running. Future Work In WildFly 10 we’d like to also be able to embed a Host Controller process in the CLI, allowing similar offline configuration of WildFly managed domain hosts. Enjoy! ### [WildFly 8.2 Final is released!](/news/2014/11/21/WildFly-8-2-Final-is-released/) I’m happy to announce the release of WildFly 8.2.0.Final! This release includes a number of improvements and bug fixes over the last release, 8.1.0.Final. CDI 1.2 & Weld 2.2 WildFly 8.2 builds upon the existing Java EE7 support, by adding the latest iteration of CDI, which includes improved discovery semantics and better compatibility with AtInject (JSR 330) implementations. Additionally, Weld, our CDI implementation has been updated with improved performance. Large deployments were observed to be as much as 20% faster to deploy. For more details, see the Weld 2.2 release announcement. Web Sockets 1.1 (JSR-356) Undertow now supports the new Web Sockets 1.1 APIs, which allows Java 8 lambdas to be used as message handlers. Additionally the TCK for 1.1 is much more extensive, with nearly three times the tests. This ultimately leads to better portability and quality of conformant implementations, such as WildFly. Other Improvements New mechanism to load tag libraries from module EJBs in WARs now inherit the WAR security domain SSO session id cookie name is now configurable Notification support added to the domain management API Improved JASPI Support for Web Services HTTPSession sharing can be configured between WARs in the same EAR Reverse proxy configuration now uses outbound-socket-binding Custom http handlers now configurable in standalone.xml/domain.xml More Web Service management attributes are hot changeable A number of usability improvements to the Web Console TLS Cipher suites are now configurable in security realms Issue Resolution 107 issues were resolved since 8.1 Component Updates Jackson 2.4.1 Mojarra 2.2.8-jbossorg-1 Undertow 1.1.0.Final JSoup 1.7.1 Apache CXF 2.7.13 Apache Santuario 1.5.7 Apache WS Security 1.6.17 EL 3.0.1-b05 Hibernate 4.3.7.Final Hibernate Validator 5.1.3.Final HornetQ 2.4.5.Final HAL 2.4.9.Final IronJacamar 1.1.9.Final Jandex 1.2.1.Final JBoss Marshalling 1.4.9.Final JBoss Remoting 4.0.6.Final RestEASY 3.0.10.Final JSTL 1.1.2.Final Weld 2.2.6.Final JBoss WS CXF 4.3.2.Final XNIO 3.3.0.Final JGroups 3.4.5.Final PicketBox 4.0.21.Final PicketLink 2.6.0.Final JAXB 2.2.5.jboss-2 ### [Getting Started with WildFly in OpenShift and JBoss Developer Studio](/news/2014/04/25/Getting-Started-with-WildFly-in-OpenShift-and-JBoss-Developer-Studio/) OpenShift provides an open source hybrid cloud application platform by Red Hat. It enables polyglot applications to be deployed on a public, private, and a hybrid cloud very easily. It provides an extensible cartridge-based architecture that allows a wide range of functionality such as frameworks, databases, monitoring services, or connectors to external backends to be easily added. WildFly cartridge allows you to start a WildFly instance in OpenShift Online. JBoss Developer Studio provide comprehensive tooling around Java EE, HTML5, Mobile, and many other technologies needed for modern web application development. The latest 7.1.1 release provide support for Eclipse Kepler SR2, the latest Eclipse release. This blog contains a video tutorial that explains how to get started with WildFly in OpenShift and JBoss Developer Studio. Specifically, it shows: Create an OpenShift application using WildFly cartridge Access the WildFly administration console using port forwarding Import the created application in JBoss Developer Studio Make changes to the application and view them in the deployed application Add a simple Java EE 7 component to the application Getting Started with WildFly 8 in OpenShift from JBoss Developer on Vimeo. Enjoy! ### [HTTP Session Failover in WildFly 8](/news/2014/03/15/HTTP-Session-Failover-in-WildFly-8/) WIldFly enables high availability of a Java EE application using session failover and load balancing. Session failover allows uninterrupted access to an application, even in the presence of a node failure. Load balancing allows for a timely response from the application, even in the presence of high volume requests. WildFly can operate in standalone mode which is an independent process, much like JBoss Application Serer 3, 4, 5, and 6. It can also operate in managed domain mode where mulitple WildFly 8 instances across different physical or virtual hosts can be managed from a single control point. Centralized administration and high availability together provides a very powerful combination for Java EE application deployments. This blog contains a video tutorial explaining that. Specifically, it shows: Introduction to WildFly and Managed Domain concepts Setup up a 2-instance cluster Deploy a WAR file to the cluster using centralized administration from admin console Access the application on one node and add HTTP session attributes on it Shutdown that instance and show HTTP session failover by accessing the application on other instance HTTP Session Failover in WildFly 8 from JBoss Developer on Vimeo. Enjoy! ### [WildFly 8 Final is released!](/news/2014/02/12/WildFly-8-Final-is-released/) I’m happy to announce the release of WildFly 8.0.0.Final. This means we feel the project is now stable and ready for general use. We received excellent feedback from the community regarding the CR1 release, and are looking forward to hearing more about your experiences with 8 Final. We will be highlighting notable WildFly 8 articles, videos and resources on our new WildFly 8 Resources page. Please keep an eye on it for future developments. Java EE7 Certified The biggest development in this release is that WildFly 8 is now officially Java EE7 certified, meeting both the Web and the Full profiles. For those unfamiliar with Java EE7, it is an industry leading specification that offers applications productivity improving capabilities, including support for the modern web, batch processing, and improvements in dependency injection. High Performance Web Server (Undertow.io) Undertow, the new cutting-edge web server in WildFly 8, is designed for maximum throughput and scalability, including environments with over a million connections. It supports non-blocking and blocking handlers, traditional and asynchronous servlets, and JSR-356 web socket handlers. It is highly customizable, with the ability for applications to implement nearly anything from dynamic request routing to custom protocols. It can also function as a very efficient, pure non-blocking reverse proxy, allowing WildFly to delegate to other web servers with minimal impact to running applications. This release adds numerous improvements including greater extensibility and enhanced security capabilities. Port Reduction By utilizing HTTP upgrade, WildFly 8 has moved nearly all of its protocols to be multiplexed over two HTTP ports: a management port, and an application port. This is a big benefit to cloud providers (such as OpenShift) who run hundreds to thousands of instances on a single server. In total, our default configuration now only has two ports: Table 1. Ports Port Protocols                                                                                             Bound Interface 9990 HTTP/JSON Management, HTTP Upgraded Remoting - (Native Management & JMX), Web Administration Console management 8080 HTTP (Servlet, JAX-RS, JAX-WS), Web Sockets, HTTP Upgraded Remoting (EJB Invocation, Remote JNDI)     application Note that since CR1 we have finally dropped the native management port 9999, which instead uses the HTTP management port (9990). Our full profile configuration also dropped the native JMS ports 5445 and 5455, which instead are multiplexed over port 8080. However, all of these original ports can still be enabled if desired. Management Role Based Access Control (RBAC) & Auditing WildFly can now support organizations with separated management responsibilities and restrictions. Roles represent different sets of permissions such as runtime operation execution, configuration areas that can read or written, and the ability to audit changes and manage users. As part of this work, LDAP integration was improved to support group mapping to roles, as well as configurable caching strategies. Finally, a new restricted audit log can be enabled including the ability to offload to a secure syslog server. Security Manager WildFly now provides a specialized Java security manager that allows you to define per-deployment security permissions, and also greatly improves upon the performance of using the standard Java security manager. In addition to the standard Java EE permissions.xml, a more flexible jboss-permissions.xml descriptor is also supported. Logging The management API now supports the ability to list and view the available log files on a server. There is also a new ablity to define a custom formatters other than the default pattern formmatter. For deployments that wish to bypass container logging, there is now an attribute, add-logging-api-dependencies, to disable the adding of the implicit server logging dependencies. Another option is to use a jboss-deployment-structure.xml to exclude the logging subsystem which will stop the logging subsystem from processing a deployment. Finally, use-deployment-logging-config, has been added to enable or disable processing pf logging configuration files found in a deployment. Note that the system property org.jboss.as.logging.per-deployment to disable per-deployment logging has been deprecated. JCA & Datasources WildFly 8 now supports a DistributedWorkManager implementation based on the JGroups project, and the JCA connection manager has been enhanced with the lazy connection manager extensions. The data sources and resource adapters subsystems allow setting capacity policies and additional flush strategies as well. Resource adapters now allows a security inflow policy per deployment. More information is available here. Clustering Clustering support was heavily refactored in WildFly 8 and includes the following: New/optimized distributed web session implementation for use with Undertow mod_cluster support for Undertow New/optimized distributed single sign-on support for Undertow New/optimized distributed @Stateful EJB caching implementation SFSB state is now replicated by default, if supported by the server profile. Replication can be disabled per bean by via @Stateful(passivationCapable=false). New public clustering API Allows applications to view cluster topology and listen for topology changes Allows applications to broadcast/submit commands to nodes in the cluster for remote execution Requisite modules are automatically made available to deployments, if supported by the server profile New public API for creating singleton services A singleton service is a decorated MSC service that only runs on one node in the cluster at any given time. Exposes a builder API that simplifies the process of installing an MSC service as a singleton service. Requisite modules are automatically made available to deployments, if supported by the server profile Maintain hot backups of cache data across distinct clusters (i.e. remote locations) CLI Improvements Within the CLI configuration it is now possible to define aliases to servers that you regularly connect to allowing you to specify the name of an alias when using the 'connect' command instead of requiring the full URL. The CLI GUI now lets you "Explore" any node in the tree. This makes it much easier to work on a single section of the tree and is particularly useful in domain mode when the tree gets huge. https://community.jboss.org/wiki/AGUIForTheCommandLineInterface#explore Patching The infrastructure to support the application of patches to an existing install has been implemented. This capability allows for a remote client to install and rollback new static modules and binary files using the WildFly management protocol. New Minimalistic "Core" Distribution A new download option is now available in WildFly 8, called the "core" distribution. This distribution is ideal for framework authors that want to build their own application runtime using the powerful WildFly 8 architecture. This architecture includes: Rich management later supporting configuration persistence, hot runtime updates, and unified set of tools and protocols. Fully concurrent service container with advanced capabilities Modular class loading which enables multi-tenancy of applications Pluggable hot deployment layer Built-in lightweight web server (supports the HTTP/JSON management protocol) Improved JDK8 Compatibility This release has improved compatibility with JDK8, and we now encourage everyone interested in Java 8 to run WildFly 8 on it as well. Expect future releases of WildFly to include APIs that take advantage of the new language features. Web Services A number of major web services improvements also occured in this release: WebServiceFeature to control when to create new Apache CXF Bus instances and when / how to share them in the container. You can read more about the new feature here. WS-Policy code-first improvements (@PolicySets) allow users to choose desired policy assertions among a list of pre-defined groups and scenarios. More information is available here. WS-Discovery support allows selected deployments to be automatically registered with the discovery service so that outside consumers can discover available endpoints. See the documentation for more information. REST WildFly 8 includes RESTEasy 3 which supports the standard Java EE REST APIs (JAX-RS 2.0) and also provides a number of useful extensions including JSON Web Encryption, Jackson, Yaml, JSON-P, and Jettison. Hibernate Search Hibernate Search is now offered out of the box in WildFly. Hibernate Search indexes objects for fast full-text searching. Multiple data sources are supported including Infinispan and standard database entities. Pruning Java EE7 no longer requires the following technologies: CMP - JPA offers much more performant and flexible API. JAX-RPC - JAX-WS offers a much more accurate and complete solution. JSR-88 - Very little adoptionr. Most preferred the more complete deployment APIs provided by venders. We decided to completely remove support for these technologies due to the high maintenance cost, low community interest, and much better alternative solutions. If you are not able to port at this time, we recommend looking at JBoss EAP6, which provides long term maintenance and support of these technologies, Other Notable Updates Non-clustered session persistence (disabled by default, might be enabled in a future release) CDI integration and performance improvements EJB SLSB pooling is disabled by default, which is a better performing configuration for most applications A number of significant JPA improvements including better support for OpenJPA and EclipseLink Batch now supports JDBC based backends, including a number of DB providers Generic JMS RAR for simplifying integration with third party messaging providers JASPIC compliance has greatly improved after a number of community contributions and testing (Thanks!) Issue Resolution 211 issues were resolved since CR1 Component Updates Arquillian 1.1.2.Final-wildfly-1 Byteman 2.1.4 EJB Client 2.0.0.Final Eclipse JDT Core Compiler 4.3.1 Groovy 2.2.1 Hal 2.1.1.Final Hibernate 4.3.1.Final Hibernate Search 4.5.0.Final Hibernate Validator 5.0.3.Final Hornetq 2.4.1.Final Invocation 1.2.1.Final Ironjacamar 1.1.3.Final JBeret 1.0.0.Final JBoss Logging 3.1.4.GA JBoss Logmanager 1.5.2.Final JBoss Marshalling 1.4.3.Final JGroups 3.4.2.Final Jackson 1.9.13 Jastow 1.0.0.Final Jipijapa 1.0.1.Final Log4j JBoss LogManager 1.1.0.Final Metadata 8.0.0.Final Mod_cluster 1.3.0.Final Mojarras 2.2.5-jbossorg-3 Msc 1.2.0.Final Narayana 5.0.0.Final Netty 4.0.15.Final Netty-xnio-transport 0.1.1.Final PicketBox 4.0.20.Final PicketLink 2.5.2.Final Remote naming 2.0.0.Final Remoting 4.0.0.Final Remoting JMX 2.0.0.Final SASL 1.0.4.Final Santuario 1.5.6 Undertow 1.0.0.Final Weld 2.1.2.Final Wildfly Security Manager 1.0.0.Final XNIO 3.2.0.Final ### [Migrating a Java EE App from GlassFish to WildFly](/news/2014/02/06/Migrating-a-Java-EE-App-from-GlassFish-to-WildFly/) by Hildeberto Mendonça and Efraim Gentil from CEJUG Serious open source projects should be backed up by at least one company who has genuine interest to be profitable with that project in the long run. It’s a matter of fitting the project in the current economic model, where people can be employed full time to address the continuous flow of issues and features coming from users all over the world. That’s what happens all the time at RedHat and that’s what stopped happening at Oracle in the case of GlassFish. GlassFish users, who take open source seriously and care about the transparency of what is running on their servers, are currently looking for alternatives and WildFly is the strongest candidate because it: follows the evolution of Java EE specifications faster than any other vendor; is a continuation of JBoss, which is a rock solid application server with years of expertise on critical business applications; is supported by Red Hat, a consistently growing IT company. This article helps you to migrate from GlassFish to WildFly. We initially take into account the most common configurations, such as database connection, JavaMail session, Security Realm and Java EE libraries. More advanced topics will come in future articles. You will notice in the coming sections that server configuration is definitely not part of the Java EE specification. Each application server is configured in a different way and we hope you will get a good deal of WildFly configuration tips through this article. Installing WildFly 8 The installation is very straightforward. Download the latest installation package from [http://www.wildfly.org/downloads/](http://www.wildfly.org/downloads/) and unzip it in a place you can easily remember. We will leave it to your decision about the best location to install it because it depends on the operating system, the server configuration and personal preferences. We refer to the location you chose to unzip WildFly as WILDFLY_HOME. WildFly requires JDK 7 or higher. Before starting WildFly, make sure either the variable JAVA_HOME is pointing to a certified JDK 7 installation or bin directory of JDK is in the system path. Go to the folder WILDFLY_HOME/bin and execute the command to start WildFly in standalone mode: #> ./standalone.sh (Linux) #> standalone.bat (Windows) Make sure you have stopped GlassFish or any other application server before doing this to avoid TCP/IP ports conflicts. You know when the startup finishes when you see the following message: WildFly 8.0.0.CR1 "WildFly" started in 1846ms Open a web browser and access the url [http://localhost:8080](http://localhost:8080) to see the WildFly welcome page. Configuring WildFly 8 From this point on, we are going to configure WildFly to support Java EE applications. Changes in the configuration reflect in one of these files: WILDFLY_HOME/domain/configuration/domain.xml: when you have a clustered environment, which usually happens in production, where there is a domain controller and at least two synchronised server instances. This configuration is taken into account when the command WILDFLY_HOME/bin/domain.sh(.bat) is executed to start WildFly. In addition, the file host.xml, located in the same folder, is used to configure each host that joins the domain. WILDFLY_HOME/standalone/configuration/standalone.xml: when you have a single WildFly instance for less demanding applications or for the development environment. This configuration is taken into account when the command WILDFLY_HOME/bin/standalone.sh(.bat) is executed to start WildFly. We refer to those files simply as ``configuration file'' throughout the text. Be careful when changing those files. Things can stop working just because of a simple distraction. It’s recommended to use the command line or the admin console to make sure the XML content is correctly defined. Syntax changes from a version to another may happen sometimes, so it’s better to delegate changes to a specialised tool. The Admin Console You can change the configuration through the administration console or the command line. The console is a web application available at [http://localhost:9990](http://localhost:9990). Unlike GlassFish, it is not accessible by default. We have to create a user in the administration realm to be able to operate the admin console. Therefore, there is no risk of forgetting to protect the admin console. To create one, execute the file WILDFLY_HOME/bin/add-user.sh(.bat) and follow the instructions, remembering to note the username and password as they will be needed later. The Command Line All admin operations can be also done through the command line. To activate WildFly command line prompt start WildFly, go to the WILDFLY_HOME/bin folder and execute the command: #> jboss-cli.sh(.bat) --connect It connects to localhost and port 9990 by default. The prompt looks like [standalone@localhost:9990 /], indicating it is ready to accept admin commands. Type quit when you are done. Command line examples are spreaded througout the text. Before using them, please remove all line breaks and identation spaces, making them a continous text string. For example: Instead of doing exactly this: [standalone@localhost:9990 /] /subsystem=datasources/jdbc-driver=mysql:add( driver-name=mysql, driver-module-name=com.mysql, driver-class-name=com.mysql.jdbc.Driver ) You should do this: [standalone@localhost:9990 /] /subsystem=datasources/jdbc-driver=mysql:add(driver-name=mysql,driver-module-name=com.mysql,driver-class-name=com.mysql.jdbc.Driver) We decided to change the presentation to improve readability. Migrating The Database Connection Let’s start discussing about the database connection, which is by far the most frequent need of a Java EE application. JDBC Driver On GlassFish the JDBC driver becomes available when it is visible in the classpath. The practical way of doing it is dropping the driver in the lib folder, then a connection pool can be created and tested using that driver. On WildFly, you have two ways of installing the JDBC driver: whether you deploy it as any other application package or you install it as a module. You can always choose to deploy the driver, but it’s specially recommend when you have a cluster environment, since the deployments are automatically propagated in the server groups. You may have issues with the deployment if the driver is not JDBC4-compliant. In this case, installing the driver as a module solves those issues. The advantage of the JDBC driver as a module is the possibility of creating a custom WildFly bundle for your organization. This way, you can repeat exactly the same installation throughout several machines, preserving the same configuration. This is perfect for the development environment. We use MySQL to illustrate the deployment and the creation of a module for the JDBC Driver. If you use another database, you will probably go through the same steps, but using different parameters. Deploying the JDBC Driver In the admin console, go to Runtime > Server > Manage Deployments and click on Add to deploy the MySQL driver. Upload the driver and give a new name to it. Any JDBC4-compliant driver is automatically recognised by WildFly and made available for new datasources. If not using a JDBC4 driver, then click on En/Disable right after the deployment`. Creating a Module To create a module: Go to WILDFLY_HOME/modules/system/layers/base/com and create the folder mysql/main; Visit the page [http://dev.mysql.com/downloads/connector/j/](http://dev.mysql.com/downloads/connector/j/) and download MySQL’s JDBC Driver; Unzip the downloaded file and copy the file mysql-connector-java-5.1.23-bin.jar to the new folder WILDFLY_HOME/modules/system/layers/base/com/mysql/main create the file module.xml in the same folder with the following content: <?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.1" name="com.mysql"> <resources> <resource-root path="mysql-connector-java-5.1.23-bin.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module> The name of the driver file may vary, so make sure you declare exactly the same name in the resource-root tag. At this point, the module is not available yet. We still need to reference the module as a driver in WildFly configuration. Do it using the following command: [standalone@localhost:9990 /] /subsystem=datasources/jdbc-driver=mysql:add( driver-name=mysql, driver-module-name=com.mysql, driver-class-name=com.mysql.jdbc.Driver ) The command returns {"outcome" ⇒ "success"} in case of success. This command resulted in the following part in the configuration file: <datasources> {...} <drivers> {...} <driver name="mysql" module="com.mysql"> <driver-class>com.mysql.jdbc.Driver</driver-class> </driver> </drivers> </datasources> It makes the JDBC driver module available for the datasource creation. Datasource On GlassFish the datasource is nothing but a JNDI name to a connection pool. On WildFly, a datasource really means a datasource. It contains a connection pool and the JNDI name is just another property. The JNDI name is used by the application to reference the datasource. That’s a fundamental difference between GlassFish and WildFly. Your current JNDI name may look like jdbc/appds in GlassFish, but in WildFly you need to append the prefix java:/ or java:jboss/, resulting in java:/jdbc/appds or java:jboss/jdbc/appds respectively. On the admin console: Go to Profile > subsytems > Connector > Datasources and click on Add to create a datasource. Give a name to the datasource to easily identify it in the console. We use AppDS in our example. Define the JNDI name appending the prefix java:/ to your current datasource name like java:/jdbc/AppDS and click Next. Select the driver you deployed or added as a module and click Next. Fill in the connection parameters to your database and click Done when finished. For example: Connection URL: jdbc:mysql://localhost:3306/AppDS Username: db_user Password: secret These are the very basic steps to have the datasource working. Next, we are going to configure the connection pool: Select the datasource you just created and click on Disable (if it is not already disabled) to be able to edit it. Select the tab Pool and then click on Edit. Update values for Min Pool Size and Max Pool Size for 5 and 15 respectively, or values ​​you may find optimal. Click on Save and restart the server to all changes take effect. Go back to Profile > subsytems > Connector > Datasources, select the recently created datasource, select the tab Connection and click on Test connection. A success message may appear if everything is correctly configured. If not, then recheck the connection parameters and the precise execution of the steps above. The same datasource can be created using the following command: [standalone@localhost:9990 /] /subsystem=datasources/data-source=AppDS:add( driver-name=mysql, user-name=db_user, password=secret, connection-url=jdbc:mysql://localhost:3306/appdb, min-pool-size=5, max-pool-size=15, jndi-name=java:/jdbc/AppDS, enabled=true, validate-on-match=true, valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker, exception-sorter-class-name=org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter ) The resulting part made by the console/command in the configuration file are: <datasources> {...} <datasource jndi-name="java:/jdbc/AppDS" pool-name="AppDS" enabled="true" use-java-context="true"> <connection-url>jdbc:mysql://localhost:3306/app</connection-url> <driver>mysql</driver> <pool> <min-pool-size>5</min-pool-size> <max-pool-size>15</max-pool-size> <prefill>true</prefill> </pool> <security> <user-name>db_user</user-name> <password>secret</password> </security> <validation> <validate-on-match>true</validate-on-match> <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker”/> <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter”/> </validation> </datasource> {...} </datasources> For more datasource examples, please consult the JBoss EAP 6 documentation that also applies to WildFly. Application Configuration for the Datasource Because of differences in the JNDI naming rules, it’s necessary to change all occurrences of the previous JNDI name to the new one. So, search for jdbc/AppDS and change it to java:/jdbc/AppDS. If you are using JPA, you find the reference to the datasource in the file persistence.xml, as illustrated below: <persistence-unit name="app-pu" transaction-type="JTA"> <jta-data-source>java:/jdbc/AppDS</jta-data-source> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties/> </persistence-unit> You may also find such references in @Resource annotations. Change them to @Resource(name = "java:/jdbc/AppDS"). Migrating the JavaMail Session Configuring WildFly to send emails with JavaMail is also slightly different from GlassFish. Every inbound and outbound communication through TCP/IP should be declared in the socket binding group. Since SMTP uses TCP/IP to communicate, then we have to create an Outbound Socket Binding for that. To proceed: In the admin console, go to Profile > General Configuration > Socket Binding. In standard-sockets, click on View >, select the tab Outbound Remote, and click on Add. Fill the form with the data to connect to your SMTP server. For instance: name: mail-smtp-gmail host: smtp.gmail.com port: 465 The second step is to create the JavaMail session that uses the socket binding. To proceed: Go to Profile > Subsytems > Connector > Mail and click on Add. Define a JNDI name like java:/mail/app and save. Click on View > in the session you just created and click on Add. Fill the form with the data to connect to the SMTP server. For instance: Socket Binding: mail-smtp-gmail Type: smtp Use SSL?: true Username: johnsmith@gmail.com Password: supersecret You can also perform the same configuration using the following command lines: [standalone@localhost:9990 /] /socket-binding-group=standard-sockets/ remote-destination-outbound-socket-binding=mail-smtp-gmail:add(host=smtp.gmail.com, port=465) [standalone@localhost:9990 /] /subsystem=mail/mail-session=App:add(jndi-name=java:/mail/app) [standalone@localhost:9990 /] /subsystem=mail/mail-session=App/server=smtp:add( outbound-socket-binding-ref=mail-smtp-gmail, username=your_email@gmail.com, password=secret, ssl=true) It’s necessary to change all occurrences of the previous JNDI name to the new one. So, search for mail/App and change it to java:/mail/App. You may find such references in @Resource annotations. Change them to @Resource(name = "java:/mail/App"). Migrating the Security Realm There are several ways of configuring a security realm on GlassFish. It would require a full article on that to cover all possibilities. For now, we simply cover a realm for authentication and authorization, using the database as the source of users and groups. In GlassFish it is called JDBCRealm, which is pretty restrictive. It requires you do provide a database model such as the one in the figure below. You won’t have too much freedom out of that model. Fortunately, WildFly is far more flexible than that. You are going to configure a security domain, which is the equivalent to a security realm for an application. Instead of specifying fixed tables and columns for users and groups, you can actually specify a SQL query that finds in the database what the security domain needs to authenticate and to authorize users. Note At the time of this writing, WildFly Beta’s admin console was not mature enough to allow the configuration of the application’s security. So, we had to do it using the command line only. Considering the data model in the figure above, go to the command line and type the following command to create the security domain: ./subsystem=security/security-domain=app:add(cache-type="default") cd ./subsystem=security/security-domain=app ./authentication=classic:add( login-modules=[ { code="Database", flag="required", module-options={ dsJndiName="java:/jdbc/AppDS", principalsQuery="select password from authentication where username=?", rolesQuery="select group_name, 'Roles' from user_group ug inner join authentication a on ug.user_id = a.user_account where a.username = ?", hashAlgorithm="SHA-256", hashEncoding="BASE64", unauthenticatedIdentity="guest" } }, { code="RoleMapping", flag="required", module-options={ rolesProperties="file:${jboss.server.config.dir}/app.properties", replaceRole="false" } } ]) The resulting part made by the command in the configuration file are: <security-domain name="app" cache-type="default"> <authentication> <login-module code="Database" flag="required"> <module-option name="dsJndiName" value="java:jboss/datasources/AppDS"/> <module-option name="principalsQuery" value="select password from authentication where username=?"/> <module-option name="rolesQuery" value="select group_name, 'Roles' from user_group ug inner join authentication a on ug.user_id = a.user_account where a.username = ?"/> <module-option name="hashAlgorithm" value="SHA-256"/> <module-option name="hashEncoding" value="BASE64"/> <module-option name="unauthenticatedIdentity" value="guest"/> </login-module> <login-module code="RoleMapping" flag="required"> <module-option name="rolesProperties" value="file:${jboss.server.config.dir}/app.properties"/> <module-option name="replaceRole" value="false"/> </login-module> </authentication> </security-domain> The role-group mapping you have in the file WEB-INF/glassfish-web.xml should be migrated to the file app.properties, where app is the name of the security domain, as defined above. Save this file in the folder WILDFLY_HOME/standalone/configuration or WILDFLY_HOME/domain/configuration to be taken into account. The following glassfish-web.xml content: <security-role-mapping> <role-name>admin</role-name> <group-name>admins</group-name> </security-role-mapping> <security-role-mapping> <role-name>leader</role-name> <group-name>leaders</group-name> <group-name>admins</group-name> </security-role-mapping> <security-role-mapping> <role-name>helper</role-name> <group-name>helpers</group-name> <group-name>leaders</group-name> <group-name>admins</group-name> </security-role-mapping> <security-role-mapping> <role-name>member</role-name> <group-name>members</group-name> <group-name>helpers</group-name> <group-name>leaders</group-name> <group-name>admins</group-name> </security-role-mapping> <security-role-mapping> <role-name>partner</role-name> <group-name>partners</group-name> <group-name>leaders</group-name> <group-name>admins</group-name> </security-role-mapping> <security-role-mapping> <role-name>speaker</role-name> <group-name>speakers</group-name> </security-role-mapping> is drastically simplified in the app.properties file: admins=admin,leader,helper,member,partner leaders=leader,helper,member,partner members=member helpers=helper,member partners=partner where groups are listed on the left of the equal operator and roles are listed on the right. In the example above, users in the group admins fulfill the role of admin, leader, helper, member and partner. To finish the configuration, add the file jboss-web.xml in the folder WEB-INF of your web module with the following content: <?xml version="1.0" encoding="UTF-8"?> <jboss-web> <security-domain>app</security-domain> </jboss-web> If you don’t use a database as a security repository, you can find more details about available login modules for WildFly in its online documentation. At this point, your application probably has what it takes to be deployed and run on WildFly. Java EE Implementation Migrating to another application server also means migrating to other implementations of Java EE specifications (i.e. EJB, CDI, JSF, JPA, etc.). In general, you don’t have to do anything in your application to make it work with other implementations, unless you are using extra features, out of the specification, or you want to stick to a specific implementation. It’s very common in the case of the JPA specification. GlassFish provides EclipseLink as JPA implementation while WildFly provides Hibernate. To be completely implementation independent, your code should reference classes from the package javax.persistence. only. If it happens to reference classes from org.eclipse.persistence., then your application depends on EclipseLink to work properly. Whether you refactor it to use javax.persistence classes or you change WildFly to also include EclipseLink jars. In the last case, you can follow the instructions in the WildFly JPA Reference Guide. You can explicitly declare in the persistence.xml the use of EclipseLink instead of Hibernate by adding the tag provider as illustrated below: <persistence-unit name="app-pu" transaction-type="JTA"> <jta-data-source>java:/jdbc/AppDS</jta-data-source> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties/> </persistence-unit> Then add the following dependence to your pom.xml file: <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.5.1</version> <scope>provided</scope> </dependency> You can find a complete list of Java EE implementations provided by WildFly on this Arun Gupta’s blog post. Note Despite rigorous tests to make sure that the implementation respects all specification requirements, there is always the risk of finding some differences. Therefore, do not forget to create new unit and integration tests for every refactoring you dealt with due to implementation differences. Conclusion To keep this text on the limits of readability, we could not cover all sorts of possibilities. We’ve focused on those configurations most people need. But you can consider this text as an invitation to give feedback about your particular environment. It will help us to plan future articles about migrating to WildFly. Note Make sure to report every strange behavior in WildFly’s forum, mailing list or even submit a bug. ### [WildFly 8 CR1 is released!](/news/2013/12/22/WildFly-8-CR1-is-released/) I’m happy to announce the release of WildFly 8.0.0.CR1. This is the first candidate for release of WildFly 8. Provided no significant issues are discovered, we will follow up with an 8.0.0.Final release soon after. We are calling on all members in the community to help us evaluate WildFly 8, and that it is indeed ready for primetime. Java EE7 TCK 100% Passing The biggest development in this release is that WildFly 8 is now passing both the full and web profiles of the Java EE7 TCK. We are now submitting the paperwork for official certification, and will be able to announce WildFly 8 Final as Java EE certified. For those unfamiliar with Java EE7, it is an industry leading specification that offers applications productivity improving capabilities, including support for the modern web, batch processing, and improvements in dependency injection. High Performance Web Server (Undertow.io) Undertow, the new cutting-edge web server in WildFly 8 is designed for maximum throughput and scalability, including environments with over a million connections. It supports non-blocking and blocking handlers, traditional and asynchronous servlets, and JSR-356 web socket handlers. It is highly customizable, with the ability for applications to implement nearly anything from dynamic request routing to custom protocols. It can also function as a very efficient, pure non-blocking reverse proxy, allowing WildFly to delegate to other web servers with minimal impact to running applications. This release adds numerous improvements including greater extensibility and enhanced security capabilities. Port Reduction By utilizing HTTP upgrade, WildFly 8 has moved nearly all of its protocols to be multiplexed over two HTTP ports: a management port, and an application port. This is a big benefit to cloud providers (such as OpenShift) who run hundreds to thousands of instances on a single server. As of this release, HornetQ, our JMS implementation, is now multiplexed over HTTP, which fully completes our port reduction goals for WildFly 8. In total, our default configuration now only has three ports, and will become two ports by final. We decided to preserve the original, now duplicative, native management port once again in this release in order to remove any potential obstacle in evaluating the release. Table 1. Ports Port Protocols                                                                                             Bound Interface 9990 HTTP/JSON Management, HTTP Upgraded Remoting - (Native Management & JMX), Web Administration Console management 8080 HTTP (Servlet, JAX-RS, JAX-WS), Web Sockets, HTTP Upgraded Remoting (EJB Invocation, Remote JNDI)     application 9999 Remoting - Native Management (deprecated)                                                         management Management Role Based Access Control (RBAC) & Auditing WildFly can now support organizations with separated management responsibilities and restrictions. Roles represent different sets of permissions such as runtime operation execution, configuration areas that can read or written, and the ability to audit changes and manage users. In addition a new restricted audit log can be enabled including the ability to offload to a secure syslog server. Patching The infrastructure to support the application of patches to an existing install has been implemented. This capability allows for a remote client to install and rollback new static modules and binary files using the WildFly management protocol. New Minimalistic "Core" Distribution A new download option is now available in WildFly 8, called the "core" distribution. This distribution is ideal for framework authors that want to build their own application runtime using the powerful WildFly 8 architecture. This architecture includes: Rich management later supporting configuration persistence, hot runtime updates, and unified set of tools and protocols. Fully concurrent service container with advanced capabilities Modular class loading which enables multi-tenancy of applications Pluggable hot deployment layer Built-in lightweight web server (supports the HTTP/JSON management protocol) Improved JDK8 Compatibility This release has improved compatibility with JDK8, and we now encourage everyone interested in Java 8 to run WildFly 8 on it as well. Expect future releases of WildFly to include APIs that take advantage of the new language features. Other Notable Updates Since Beta1 CDI integration and performance improvements Batch now supports JDBC based backends Generic JMS RAR for simplifying integration with third party messaging providers Logging now supports custom formatters sl4j forked to fix concurrency issues Hibernate Search is included, although undecided if it will remain (opinions welcome!) Issue Resolution 387 issues were resolved since Beta1 Component Updates PicketBox 4.0.18.Final JBoss SASL 1.0.4.CR1 JGroups to 3.4.0.Final JBoss Negotiation 2.2.6.Final Remoting JMX 2.0.0.CR4 MSC 1.2.0.CR1 JBossWS 4.2.2.Final Mojarra 2.2.4-jbossorg-1 Infinispan 6.0.1.Final PicketBox 4.0.19.Final JGroups to 3.4.1.Final IronJacamar 1.1.2.Final JBossWS 4.2.3.Final Narayana 5.0.0.CR2 Generic JMS RA 1.0.1.Final HornetQ 2.4.0.Final Javamail 1.5.0 Hibernate 4.3.0.Final Hibernate Validator 5.0.2.Final Hibernate Search 4.5.0.Alpha2 JacORB 2.3.2-jbossorg-5 JBeret 1.0.0.CR1 Jandex 1.1.0.Final JBoss Marshalling 1.4.2.Final Netty 4.0.13.Final Netty XNIO Transport 0.1.1.CR1 Undertow 1.0.0.Beta30 Weld 2.1.1.Final XNIO 3.2.0.Beta4 Apache CXF 2.7.7 RestEASY 3.0.6.Final Syslog4j 0.9.30 ### [WildFly 8 Webinar Recording](/news/2013/11/21/WildFly-8-Webinar-Recording/) A few days ago, Brian Stansberry, Stuart Douglas and I presented a webinar on all of the major WildFly 8 features. Dive Into WildFly 8 from JBoss Developer on Vimeo. This video covers a number of topics including: Java EE7 JSONP Batch Processing EE Concurrency Productivity & Portability Improvements Undertow Performance Servlet 3.1 Web Sockets Non-blocking Handlers HTTP Upgrade Reverse Proxy Management Role Based Access Control Roles Auditing Privileges Constraints We also had some great questions at the end. ### [Welcome to the new WildFly.ORG!](/news/2013/11/15/Welcome-to-the-new-WildFly-ORG/) Hello everyone. I recently revamped the WildFly.ORG website, and I hope you will find it to be a much more useful source of information about the WildFly project. Walkthrough I’d like to take you through a short tour of what’s on the website. The website is based on the JBoss community bootstrap theme. So it should operate in a familiar manner to other JBoss community websites. Main Landing Page ~~~~~~~ The first page aims to keep you up to date with the latest WildFly news and events. The rotating banners in the center are clickable and will take you into an area that provides more information about the banner subject. Below the banners we have the latest WildFly news, which is a specialized blog that will contain articles that we think Wildfly users, such as yourself, will find interesting. If you click on the RSS looking icon in the "Latest News" title you will get an atom feed for the news. Clicking on the title links will take you into the article and display some information about the author. Aside from regular bloggers on the development team, we will post guest articles from community members with interesting WildFly experiences they would like to share. Let us know if you are interested! On the right bottom section, our WildFlyAS twitter account will post interesting tweets, and frequently retweet WildFly commenters. If you like to talk about WildFly on twitter, you will probably see your tweets pop up here from time to time. About Page ~~~~ If you click About in the navigation bar, you’ll find a list of compelling reasons to use WildFly for your next project. We are certainly proud of what it has become. News Page ~~~ The News page displays a number of entries at once, so you can catch up quickly. Downloads ~~~ The Downloads page displays a list of all WildFly releases since 8. For older releases you will need to visit the older JBoss AS Community page. If you are interested in our commercial offering, JBoss EAP, those releases are also referenced on that page. All of the 8 binaries have multiple download options, so be sure to look carefully for the option and format you prefer. Finally, we highly recommend reviewing the release notes icon at the bottom of each download entry. We always announce important information about the release regarding compatibility and known issues. Documentation ~~~~~ The Documentation link will take you into our official WildFly documentation, which is maintained in separate Confluence system. We allow comments, so if you have suggestions on how we can improve a particular page in the documentation, let us know! Source Code ~~~~~ This takes you to our GitHub repository. From here you can search, browse, and fork our code. Get Help ~~~~ The Get Help section covers the various options available to get in touch with the WildFly community. These include our web based forums, mailing lists, and IRC. Join Us ~~~ Since WildFly is a community project, we only exist because various developers around the world have decided to pitch in and help build a great application server. We are always looking for new volunteers, and the Join Us page will expand on the many benefits of doing so. It also provides helpful information to new contributors. Governance ~~~~ On the bottom footer there is a link to a page describing how we govern the WildFly project. If you are evaluating the project, you might find it useful to understand how we plan and develop it. Special Thanks To the various tools and people that helped. Awestruct - a handy templating engine for generating nice static sites. Asciidoctor - supports the best blog formatting language ever. JBoss Bootstrap - a great starting template based on the awesome Twitter Bootstrap project. Infinispan Website - a great bootstrap derived site I was able to reuse a few layouts and ideas from. Arquillian Website - an awestruct derived site that had a nice little snippet of summary code I was able to reuse. Blender - a really amazing OSS 3d ray tracing tool. Gimp - a really amazing OSS 2d drawing program. Brian, Marko, David & Tomaz - for testing the site on various mobile devices and providing general feedback. James & Design Team - for the really nice logo. Ruby - for reminding me why I love Java. ### [Role Based Access Control in WildFly 8](/news/2013/11/07/Role-Based-Access-Control-in-WildFly-8/) One of the big new features in WildFly 8 is the ability to enforce role-based access control on management operations. I recorded some videos that describe how you can use this powerful feature and also demonstrate it in action. Check them out!   Role Based Access Control in WildFly 8 (Part 1 of 3) from Brian Stansberry on Vimeo. In the first part of the series, I walk through the basics of Role Based Access Control, and show how you can use standard roles within the WildFly Administration Console.   Role Based Access Control in WildFly 8 (Part 2 of 3) from Brian Stansberry on Vimeo. In the second video, I show how you can configure roles and setup users which map to roles.   Role Based Access Control in WildFly 8 (Part 3 of 3) from Brian Stansberry on Vimeo. In the final video, I show how you can configure constraints which allow you to tweak the behavior of roles. ### [WildFly 8 Beta is released!](/news/2013/10/04/WildFly-8-Beta-is-released/) I’m happy to announce the release of WildFly 8.0.0.Beta1. This is a significant milestone because all planned major features have been implemented. Let’s run through the big ones. Java EE7 Java EE7 offers applications several productivity improving capabilities including support for the modern web, batch processing, simplified concurrent task processing, and improvements in dependency injection. At this point all user facing EE7 APIs have been implemented! Aside from achieving compliance certification, the only remaining work is to implement a few updates in the security integration SPIs, JASPIC and JACC. High Performance Web Server (Undertow.io) Undertow, the new cutting-edge web server in WildFly 8 is designed for maximum throughput and scalability, including environments with over a million connections. It supports non-blocking and blocking handlers, traditional and asynchronous servlets, and JSR-356 web socket handlers. It is highly customizable, with the ability for applications to implement nearly anything from dynamic request routing to custom protocols. It can also function as a very efficient, pure non-blocking reverse proxy, allowing WildFly to delegate to other web servers with minimal impact to running applications. Undertow has been fully integrated for several releases now. This release finalizes the key features of this integration with reverse proxy support. Port Reduction An important goal of WildFly 8 was to greatly reduce the number of ports used by multiplexing protocols over HTTP using HTTP Upgrade. This is a big benefit to cloud providers (such as OpenShift) who run hundreds to thousands of instances on a single server. Our default configuration now only has three ports, and will become two ports by final. We decided to preserve the original native management port for this Beta release to give those using legacy clients time to update before the final release. The native management port, 9999, is deprecated and will be removed by final. Table 1. Ports Port Protocols Bound Interface 9990 HTTP/JSON Management, HTTP Upgraded Remoting - (Native Management & JMX), Web Administration Console management 8080 HTTP (Servlet, JAX-RS, JAX-WS), Web Sockets, HTTP Upgraded Remoting (EJB Invocation, Remote JNDI) application 9999 Remoting - Native Management (deprecated) management Management Role Based Access Control (RBAC) & Auditing WildFly can now support organizations with separated management responsibilities and restrictions. Roles represent different sets of permissions such as runtime operation execution, configuration areas that can read or written, and the ability to audit changes and manage users. In addition a new restricted audit log can be enabled including the ability to offload to a secure syslog server. Patching The infrastructure to support the application of patches to an existing install has been implemented. This capability allows for a remote client to install and rollback new static modules and binary files using the WildFly management protocol. Notable Updates Since Alpha4 Initial EE Batch support Initial EE concurrency support Java EE Connector Architecture 1.7 support New :jca: subsystem with support for DistributedWorkManager New :resource-adapters: subsystem with f.ex. pool capacity policies New :datasources: subsystem with f.ex. pool capacity policies Greatly improved RBAC & Audit logging Fixed few memory leaks Upgrade clustering to Infinispan 6 Full AJP backend support Reverse proxy support Multi-JSF is fully functional and we upload an installer for MyFaces Made sure server starts on JDK8 Issue Resolution 219 issues were resolved since Alpha4 Component Updates Weld 2.1.0 CR1 Undertow Beta 17 Hibernate 4.3.0.Beta4 Console 2.0.0.Final JBoss Modules 1.3.0.Final HornetQ 2.4.0.Beta2 aesh 0.33.8 Jipijapa 1.0.0.Beta1 Javassist 3.18.1-GA Remoting JMX 2.0.0.CR3 JBoss WS 4.2.1.Final Jgroups 3.4.0.Beta1 Infinispan 6.0.0.Beta1 JBoss Log Manager 1.5.0.Final PicketLink 2.5.1.Final jboss-threads 2.1.1.Final mod_cluster 1.2.4.Final Narayana 5.0.0.M4 Mojarra 2.2.3 IronJacamar 1.1.0.Final ## Pages ### [Events](/events/) ### [Guides](/guides/) ### [404.html](/404.html) body { background-image: url('/assets/img/wildfly_hero_r3v1.jpg'); background-repeat: no-repeat; background-size: 100%; } Error '404' ERROR FOUR O’ FOUR LOST IN THE WildFly MOUNTAINS YOU SHOULD TRY THE NAV ~ a haiku ### [About WildFly](/about/) ### [Get Involved with WildFly](/contribute/) ### [Contributor PGP Information](/contributors/pgp/) ### [WildFly Downloads](/downloads/) ### [Getting Started with WildFly](/get-started/) Build and run an EE application with WildFly in a few minutes. Step 0. Install Java & Maven You need Java (at least version 17, and preferably 21) and Maven installed on your machine to create a Maven project that contains the source code of the EE application. You can verify they are installed by executing the commands: java -version mvn -version Step 1. Create the Application You can create the EE application as a Maven project by executing the commands: mvn archetype:generate \ -DarchetypeGroupId=org.wildfly.archetype \ -DarchetypeArtifactId=wildfly-getting-started-archetype The getting-started project that is generated contains a simple "Hello World" application that exposes a HTTP endpoint with the Jakarta-RS API. The Maven project is configured to "provision" (install and configure) the WildFly that hosts your application. Step 2. Build the Application You can build the application by executing the commands: cd getting-started mvn package verify This Maven command compiles the EE application, provisions WildFly, deploys the application into WildFly and runs integration tests against it. When this command is finished, you have a fully functional, tested application running on WildFly. Step 3. Run the Application The target/server contains a fully functional WildFly server with your application. You start it by executing the command: ./target/server/bin/standalone.sh The application is accessible at http://localhost:8080/. To stop the application, type Ctrl + C in the terminal where you started WildFly. Step 4. Continuous Development You can develop your application and see the updates in the running application immediately by using the wildfly:dev goal from the root of your project: mvn clean wildfly:dev The application is accessible at http://localhost:8080 and will be continuously updated when its code changes. Open your favorite code editor and change the hello method in the GettingStartedService.java file: public String hello(String name) { return String.format("Hello '%s'.", name.toUpperCase()); } Save the file, and the application will be recompiled and updated in WildFly. If you access the application at http://localhost:8080, it will now return the name in uppercase. What’s next? To learn more about WildFly, you can read its documentation. If you want to learn how to use WildFly on OpenShift, read the Getting Started with WildFly on OpenShift Guide. In addition, you can also watch the talk from our first mini conference about getting started with WildFly. Finally, you can browse more guides on a wide range of topics relating to WildFly. ### [Configuring Logging for your Application](/guides/application-logging/) Configuring Logging for your Application Table of Contents Prerequisites Add a Dependency on JBoss Logging Add Logging to the Application Configure Logging in the WildFly Subsystem What’s next? References In this guide, you will learn how to use logging in your application and configure WildFly to display the logs at the level you want. Prerequisites To complete this guide, you need: Roughly 10 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ WildFly supports all major logging facades. These include: JBoss Logging SLF4J Apache Log4j (2.x+) Apache Commons Logging Java Util Logging Choose the logging facade you’d like to use and ensure it’s added in your Maven pom.xml file with a scope of provided. Then, we will add a few logs in our code at different levels. Finally, we will configure WildFly to change the log level of our application logs independently of WildFly own logs. In our example we will be using JBoss Logging. Add a Dependency on JBoss Logging In order to use JBoss Logging in our application, we need to add a dependency on it in the pom.xml. The dependency is defined as: <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <!-- Provided by WildFly --> <scope>provided</scope> </dependency> You need to add it to the <dependencies> section of the pom.xml: <dependencies> ... <!-- copy the dependency here --> </dependencies> Add Logging to the Application As an example, you can update the GettingStartedService.java file to add logging to the application at different levels: package org.wildfly.examples; import jakarta.enterprise.context.ApplicationScoped; import org.jboss.logging.Logger; @ApplicationScoped public class GettingStartedService { private static Logger log = Logger.getLogger(GettingStartedService.class); public String hello(String name) { log.tracef("called method with: %s", name); String out = String.format("Hello '%s'.", name); log.infof("returning: %s", out); return out; } } You added a log Logger that can log messages with a name corresponding to the class org.wildfly.examples.GettingStartedService. You also added two logging calls, one at the TRACE level and the other one at the INFO level. If you run the integration tests with mvn clean verify, you will only see the logs at the INFO level in the standard output: $ mvn clean verify ... 15:18:08,482 INFO [org.wildfly.examples.GettingStartedService] (default task-1) returning: Hello 'World'. ... By default, WildFly only displays INFO logs on the console. Let’s now configure WildFly to display our application logs at the TRACE level. Configure Logging in the WildFly Subsystem The configuration of logging is done by WildFly in its logging subsystem. There are different ways to modify the WildFly configuration but as we used the wildfly-maven-plugin to provision WildFly, we can pass a CLI script so the WildFly configuration will be modified whenever we invoke mvn package. First, we add a configuration.cli in the src/main/scripts directory: # Start the embedded server embed-server # let the console display TRACE logs /subsystem=logging/console-handler=CONSOLE:write-attribute(name=level, value=TRACE) # create the logger for our code (with the name org.wildfly.examples corresponding to our package) /subsystem=logging/logger=org.wildfly.examples:add(level=TRACE) stop-embedded-server Note We use the logger name org.wildfly.examples instead of the full logger name. This will allow trace logs from all loggers which have this same base name. This script contains the management operations to change the WildFly configuration. We could invoke any management operations but, in this case, we only modify the /subsystem=logging resources that control the logging aspects. You then need to modify the wildfly-maven-plugin configuration in pom.xml to execute this: Copy the XML snippet: <!-- Execute the script in offline mode --> <offline>true</offline> <scripts> <script>${project.build.scriptSourceDirectory}/configuration.cli</script> </scripts> And add it to the <configuration> section of the wildfly-maven-plugin: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <!-- copy the XML snippet here --> </configuration> <executions> <execution> <id>provision-server</id> <phase>package</phase> <goals> <goal>provision</goal> <goal>execution-commands</goal> </goals> </execution> </executions> </plugin> With that change in place, if you provision WildFly and run the integration tests again, both log calls are now displayed: $ mvn clean verify ... 16:04:22,260 TRACE [org.wildfly.examples.GettingStartedService] (default task-2) called method with: World 16:04:22,260 INFO [org.wildfly.examples.GettingStartedService] (default task-2) returning: Hello 'World'. ... What’s next? WildFly provides extensive logging configuration. You can learn more by reading WildFly’s Logging Subsystem Configuration Guide and its model reference. References Logging Subsystem Configuration Guide Logging Subsystem Model Reference ### [Deploying WildFly using Ansible](/guides/automate-with-ansible/) Deploying WildFly using Ansible Table of Contents Prerequisites Install Ansible and its collection for WildFly Set up the WildFly cluster Ansible playbook to install WildFly Run the playbook! Check that everything worked as expected Deploy an application to the WildFly cluster Verify that the WildFly cluster is running and the app is deployed Using the Ansible collection as an installer for WildFly Conclusion In this brief guide, we’ll set up and run three instances of WildFly on the same machine (localhost). Together they will form a cluster. It’s a rather classic setup, where the appservers need to synchronize the content of their application’s sessions to ensure fail over if one of the instances fails. This configuration guarantees that, if one instance fails while processing a request, another one can pick up the work without any data loss. Note that we’ll use a multicast to discover the members of the cluster and ensure that the cluster’s formation is fully automated and dynamic. Prerequisites To complete this guide, you need: Roughly 20 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Install Ansible and its collection for WildFly On a Linux system using a package manager, installing Ansible is pretty straightforward: $ sudo dnf install ansible-core Please refer to the documentation available online for installation on other operating systems. Note that this guide assumes you are running both the Ansible controller and the target (same machine in our case) on a Linux system. However, it should work on any other operating system with a few adjustments. Before going further, double check that you are running a recent enough version of Ansible (2.12 or above will do, but 2.9 is the bare minimum): $ ansible --version ansible [core 2.14.1] config file = /etc/ansible/ansible.cfg configured module search path = ['/home/rpelisse/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3.11/site-packages/ansible ansible collection location = /home/rpelisse/.ansible/collections:/usr/share/ansible/collections executable location = /usr/bin/ansible python version = 3.11.0 (main, Oct 24 2022, 00:00:00) [GCC 12.2.1 20220819 (Red Hat 12.2.1-2)] (/usr/bin/python3) jinja version = 3.0.3 libyaml = True The next, and last, step to ready your Ansible environment is to install the Ansible collection for WildFly on the controller (the machine that will run Ansible): $ ansible-galaxy collection install middleware_automation.wildfly Starting galaxy collection install process Process install dependency map Starting collection install process Downloading https://galaxy.ansible.com/download/middleware_automation-wildfly-1.2.2.tar.gz to /root/.ansible/tmp/ansible-local-25jj_dxqei/tmpvb6d55ho/middleware_automation-wildfly-1.2.2-33znbzkb Downloading https://galaxy.ansible.com/download/middleware_automation-redhat_csp_download-1.2.2.tar.gz to /root/.ansible/tmp/ansible-local-25jj_dxqei/tmpvb6d55ho/middleware_automation-redhat_csp_download-1.2.2-3apb_j2g Installing 'middleware_automation.wildfly:1.2.2' to '/root/.ansible/collections/ansible_collections/middleware_automation/wildfly' middleware_automation.wildfly:1.2.2 was installed successfully Downloading https://galaxy.ansible.com/download/community-general-6.1.0.tar.gz to /root/.ansible/tmp/ansible-local-25jj_dxqei/tmpvb6d55ho/community-general-6.1.0-rr64e3dg Installing 'middleware_automation.redhat_csp_download:1.2.2' to '/root/.ansible/collections/ansible_collections/middleware_automation/redhat_csp_download' middleware_automation.redhat_csp_download:1.2.2 was installed successfully Installing 'community.general:6.1.0' to '/root/.ansible/collections/ansible_collections/community/general' community.general:6.1.0 was installed successfully Set up the WildFly cluster For simplicity’s sake and to allow you to reproduce this demonstration on a single machine (physical or virtual) or even a container, we opted to deploy our three instances on one target. We chose localhost as a target, so the demonstration can even be performed without a remote host. There are essentially two steps to set up the WildFly cluster: Install WildFly on the targeted hosts (here just localhost). This means downloading the archive from this website and decompressing the archive in the appropriate directory (JBOSS_HOME). These tasks are handled by the wildfly_install role supplied by Ansible collection for WildFly. Create the configuration files to run several instances of WildFly. Because we’re running multiple instances on a single host, you also need to ensure that each instance has its own subdirectories and set of ports, so the instances can coexist and communicate. Fortunately, this functionality is provided by a role within the Ansible collection called wildfly_systemd. Ansible playbook to install WildFly Here is the playbook we’ll use to deploy our clusters. Its content is relatively self-explanitory, at least if you are somewhat familiar with the Ansible syntax. - name: "WildFly installation and configuration" hosts: "{{ hosts_group_name | default('localhost') }}" become: yes vars: wildfly_install_workdir: '/opt/' wildfly_config_base: standalone-ha.xml wildfly_version: 27.0.1.Final wildfly_java_package_name: java-11-openjdk-headless.x86_64 wildfly_home: "/opt/wildfly-{{ wildfly_version }}" instance_http_ports: - 8080 - 8180 - 8280 app: name: 'info-1.2.war' url: 'https://drive.google.com/uc?export=download&id=13K7RCqccgH4zAU1RfOjYMehNaHB0A3Iq' collections: - middleware_automation.wildfly roles: - role: wildfly_install tasks: - name: "Set up for WildFly instance {{ item }}." ansible.builtin.include_role: name: wildfly_systemd vars: wildfly_config_base: 'standalone-ha.xml' wildfly_instance_id: "{{ item }}" instance_name: "wildfly-{{ wildfly_instance_id }}" wildfly_config_name: "{{ instance_name }}.xml" wildfly_basedir_prefix: "/opt/{{ instance_name }}" service_systemd_env_file: "/etc/wildfly-{{ item }}.conf" service_systemd_conf_file: "/usr/lib/systemd/system/wildfly-{{ item }}.service" loop: "{{ range(0,3) | list }}" - name: "Wait for each instance HTTP ports to become available." ansible.builtin.wait_for: port: "{{ item }}" loop: "{{ instance_http_ports }}" - name: "Checks that WildFly server is running and accessible." ansible.builtin.get_url: url: "http://localhost:{{ port }}/" dest: "/opt/{{ port }}" loop: "{{ instance_http_ports }}" loop_control: loop_var: port In short, this playbook uses the Ansible collection for WildFly to, first, install the appserver by using the wildfly_install role. This will download all the artifacts, create the required system groups and users, install dependency (unzip) and so on. At the end of its execution, all the tidbits required to run WildFly on the target host are installed, but the server is not yet running. That is what’s happening in the next step. In the tasks section of the playbook, we then call on another role provided by the collection: wildfly_systemd. This role will take care of integrating WildFly, as a regular system service, into the service manager. Here, we use a loop to ensure that we create not one, but three different services. Each one will have the same configuration (standalone-ha.xml) but runs on different ports, using a different set of directories to store its data. Run the playbook! Now, let’s run our Ansible playbook and observe its output: $ ansible-playbook -i inventory playbook.yml PLAY [Converge] **************************************************************** TASK [Gathering Facts] ********************************************************* ok: [localhost] TASK [wildfly_install : Validating arguments against arg spec 'main'] ********** ok: [localhost] TASK [wildfly_install : Ensures prerequirements are fullfilled.] *************** included: /work/roles/wildfly_install/tasks/prereqs.yml for localhost TASK [wildfly_install : Check that required packages list has been provided.] *** ok: [localhost] TASK [wildfly_install : Prepare packages list] ********************************* skipping: [localhost] TASK [wildfly_install : Add JDK package java-11-openjdk-headless to packages list] *** ok: [localhost] TASK [wildfly_install : Install required packages (4)] ************************* changed: [localhost] TASK [wildfly_install : Ensures required local user exists.] ******************* included: /work/roles/wildfly_install/tasks/user.yml for localhost TASK [wildfly_install : Check arguments] *************************************** ok: [localhost] TASK [wildfly_install : Set wildfly group] ************************************* ok: [localhost] TASK [wildfly_install : Ensure group wildfly exists.] ************************** changed: [localhost] TASK [wildfly_install : Ensure user wildfly exists.] *************************** changed: [localhost] TASK [wildfly_install : Ensure workdir /opt/wildfly/ exists.] ****************** changed: [localhost] TASK [wildfly_install : Ensure archive_dir /opt/wildfly/ exists.] ************** ok: [localhost] TASK [wildfly_install : Ensure server is installed] **************************** included: /work/roles/wildfly_install/tasks/install.yml for localhost TASK [wildfly_install : Check arguments] *************************************** ok: [localhost] TASK [wildfly_install : Check local download archive path] ********************* ok: [localhost] TASK [wildfly_install : Set download paths] ************************************ ok: [localhost] TASK [wildfly_install : Check target archive: /opt/wildfly//wildfly-27.0.0.Final.zip] *** ok: [localhost] TASK [wildfly_install : Retrieve archive from website: https://github.com/wildfly/wildfly/releases/download] *** included: /work/roles/wildfly_install/tasks/install/web.yml for localhost TASK [wildfly_install : Check arguments] *************************************** ok: [localhost] TASK [wildfly_install : Download zipfile from https://github.com/wildfly/wildfly/releases/download/27.0.0.Final/wildfly-27.0.0.Final.zip into /work/wildfly-27.0.0.Final.zip] *** ok: [localhost] TASK [wildfly_install : Retrieve archive from RHN] ***************************** skipping: [localhost] TASK [wildfly_install : Install server using RPM] ****************************** skipping: [localhost] TASK [wildfly_install : Check downloaded archive] ****************************** ok: [localhost] TASK [wildfly_install : Copy archive to target nodes] ************************** changed: [localhost] TASK [wildfly_install : Check target archive: /opt/wildfly//wildfly-27.0.0.Final.zip] *** ok: [localhost] TASK [wildfly_install : Read target directory information: /opt/wildfly/wildfly-27.0.0.Final/] *** ok: [localhost] TASK [wildfly_install : Check target directory state: /opt/wildfly/wildfly-27.0.0.Final/] *** ok: [localhost] TASK [wildfly_install : Extract files from /opt/wildfly//wildfly-27.0.0.Final.zip into /opt/wildfly/.] *** changed: [localhost] TASK [wildfly_install : Note: decompression was not executed] ****************** skipping: [localhost] TASK [wildfly_install : Read information on server home directory: /opt/wildfly/wildfly-27.0.0.Final/] *** ok: [localhost] TASK [wildfly_install : Check state of server home directory: /opt/wildfly/wildfly-27.0.0.Final/] *** ok: [localhost] TASK [wildfly_install : Set instance name] ************************************* ok: [localhost] TASK [wildfly_install : Deploy configuration] ********************************** changed: [localhost] TASK [wildfly_install : Ensure required parameters for cumulative patch application are provided.] *** skipping: [localhost] TASK [Apply latest cumulative patch] ******************************************* skipping: [localhost] TASK [wildfly_install : Ensure required parameters for elytron adapter are provided.] *** skipping: [localhost] TASK [Install elytron adapter] ************************************************* skipping: [localhost] TASK [wildfly_install : Check wildfly install directory state] ***************** ok: [localhost] TASK [wildfly_install : Validate conditions] *********************************** ok: [localhost] TASK [wildfly_systemd : Validating arguments against arg spec 'main'] ********** ok: [localhost] TASK [wildfly_systemd : Check arguments] *************************************** ok: [localhost] TASK [wildfly_systemd : Check current EAP patch installed] ********************* skipping: [localhost] TASK [wildfly_systemd : Check arguments for yaml configuration] **************** skipping: [localhost] TASK [Ensure required local user and group exists.] **************************** TASK [wildfly_install : Check arguments] *************************************** ok: [localhost] TASK [wildfly_install : Set wildfly group] ************************************* ok: [localhost] TASK [wildfly_install : Ensure group wildfly exists.] ************************** ok: [localhost] TASK [wildfly_install : Ensure user wildfly exists.] *************************** ok: [localhost] TASK [wildfly_systemd : Set destination directory for configuration] *********** ok: [localhost] TASK [wildfly_systemd : Set instance destination directory for configuration] *** ok: [localhost] TASK [wildfly_systemd : Check arguments] *************************************** skipping: [localhost] TASK [wildfly_systemd : Set base directory for instance] *********************** skipping: [localhost] TASK [wildfly_systemd : Check arguments] *************************************** skipping: [localhost] TASK [wildfly_systemd : Set instance name] ************************************* skipping: [localhost] TASK [wildfly_systemd : Set instance name] ************************************* skipping: [localhost] TASK [wildfly_systemd : Set bind address] ************************************** ok: [localhost] TASK [wildfly_systemd : Create basedir /opt/wildfly/wildfly-27.0.0.Final//standalone for instance: wildfly] *** ok: [localhost] TASK [wildfly_systemd : Create deployment directories for instance: wildfly] *** ok: [localhost] TASK [wildfly_systemd : Deploy configuration] ********************************** ok: [localhost] TASK [wildfly_systemd : Include YAML configuration extension] ****************** skipping: [localhost] TASK [wildfly_systemd : Check YAML configuration is disabled] ****************** ok: [localhost] TASK [wildfly_systemd : Set systemd envfile destination] *********************** ok: [localhost] TASK [wildfly_systemd : Determine JAVA_HOME for selected JVM RPM] ************** ok: [localhost] TASK [wildfly_systemd : Set systemd unit file destination] ********************* ok: [localhost] TASK [wildfly_systemd : Deploy service instance configuration: /etc//wildfly.conf] *** changed: [localhost] TASK [wildfly_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/wildfly.service] *** changed: [localhost] TASK [wildfly_systemd : Perform daemon-reload to ensure the changes are picked up] *** ok: [localhost] TASK [wildfly_systemd : Ensure service is started] ***************************** included: /work/roles/wildfly_systemd/tasks/service.yml for localhost TASK [wildfly_systemd : Check arguments] *************************************** ok: [localhost] TASK [wildfly_systemd : Set instance wildfly state to started] ***************** changed: [localhost] TASK [wildfly_driver : Validating arguments against arg spec 'main'] *********** ok: [localhost] TASK [wildfly_driver : Check arguments] **************************************** ok: [localhost] TASK [wildfly_driver : Check module directory: /opt/wildfly/wildfly-27.0.0.Final//modules/org/postgresql/main] *** ok: [localhost] TASK [wildfly_driver : Set up module dir for JDBC Driver: /opt/wildfly/wildfly-27.0.0.Final//modules/org/postgresql/main] *** changed: [localhost] TASK [wildfly_driver : Retrieve JDBC Driver from https://repo.maven.apache.org/maven2/org/postgresql/postgresql/9.4.1212/postgresql-9.4.1212.jar] *** changed: [localhost] TASK [wildfly_driver : Set source template path] ******************************* ok: [localhost] TASK [wildfly_driver : Deploy module.xml for JDBC Driver] ********************** changed: [localhost] TASK [wildfly_utils : Validating arguments against arg spec 'main'] ************ ok: [localhost] TASK [Install second driver with wildfly_driver role] ************************** TASK [wildfly_driver : Validating arguments against arg spec 'main'] *********** ok: [localhost] TASK [wildfly_driver : Check arguments] **************************************** ok: [localhost] TASK [wildfly_driver : Check module directory: /opt/wildfly/wildfly-27.0.0.Final//modules/org/mariadb/main] *** ok: [localhost] TASK [wildfly_driver : Set up module dir for JDBC Driver: /opt/wildfly/wildfly-27.0.0.Final//modules/org/mariadb/main] *** changed: [localhost] TASK [wildfly_driver : Retrieve JDBC Driver from https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/2.7.4/mariadb-java-client-2.7.4.jar] *** changed: [localhost] TASK [wildfly_driver : Set source template path] ******************************* ok: [localhost] TASK [wildfly_driver : Deploy module.xml for JDBC Driver] ********************** changed: [localhost] PLAY RECAP ********************************************************************* localhost : ok=70 changed=16 unreachable=0 failed=0 skipped=16 rescued=0 ignored=0 Note that the playbook is not that long, but it does a lot for us. It performs almost 100 different tasks! Starting by automatically installing the dependencies, including the JVM required by WildFly, along with downloading its binaries. And the wildfly_systemd role does even more, effortlessly setting up three distinct services, each with its own set of ports and directory layout to store instance-specific data. Even better, the WildFly installation is NOT duplicated. All the binaries live under the /opt/wildfly-27.0.1 directory, but all the data files of each instance are stored in separate folders. This means that we just need to update the binaries, once, and then restart the instances, to deploy a patch or upgrade to a new version of WildFly. On top of everything, we configured the instances to use the standalone-ha.xml configuration as the baseline, so they are already set up for clustering. Check that everything worked as expected The easiest way to confirm that the playbook did indeed install WildFly and started three instances of the appserver is to use the systemctl command to check the associate services state: ● wildfly.service - JBoss EAP (standalone mode) Loaded: loaded (/usr/lib/systemd/system/wildfly.service; enabled; vendor preset: disabled) Active: active (running) since Tue 2023-01-10 09:24:21 UTC; 6h ago Main PID: 857 (standalone.sh) CGroup: /system.slice/wildfly.service ├─ 857 /bin/sh /opt/wildfly/wildfly-27.0.0.Final/bin/standalone.sh -c wildfly.xml -b 0.0.0.0 -bmanagement 127.0.0.1 -Djboss.bind.address.private=127.0.0.1 -Djboss.default.multicast.address=230.0.0.4 -Djboss.server.config.dir=/opt/wildfly/wildfly-27.0.0.Final//standalone/configuration/ -Djboss.server.base.dir=/opt/wildfly/wildfly-27.0.0.Final//standalone -Djboss.tx.node.id=wildfly -Djboss.node.name=wildfly -Dwildfly.statistics-enabled=false └─1001 /usr/lib/jvm/java-11-openjdk-11.0.17.0.8-2.el8_6.x86_64/bin/java -D[Standalone] -server -Xmx1024M -Xms512M --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldaps=ALL-UNNAMED --add-exports=jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED -Dorg.jboss.boot.log.file=/opt/wildfly/wildfly-27.0.0.Final/standalone/log/server.log -Dlogging.configuration=file:/opt/wildfly/wildfly-27.0.0.Final/standalone/configuration/logging.properties -jar /opt/wildfly/wildfly-27.0.0.Final/jboss-modules.jar -mp /opt/wildfly/wildfly-27.0.0.Final/modules org.jboss.as.standalone -Djboss.home.dir=/opt/wildfly/wildfly-27.0.0.Final -Djboss.server.base.dir=/opt/wildfly/wildfly-27.0.0.Final/standalone -c wildfly.xml -b 0.0.0.0 -bmanagement 127.0.0.1 -Djboss.bind.address.private=127.0.0.1 -Djboss.default.multicast.address=230.0.0.4 -Djboss.server.config.dir=/opt/wildfly/wildfly-27.0.0.Final//standalone/configuration/ -Djboss.server.base.dir=/opt/wildfly/wildfly-27.0.0.Final//standalone -Djboss.tx.node.id=wildfly -Djboss.node.name=wildfly -Dwildfly.statistics-enabled=false Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,504 INFO [org.wildfly.extension.undertow] (MSC service thread 1-6) WFLYUT0006: Undertow HTTPS listener https listening on [0:0:0:0:0:0:0:0]:8443 Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,549 INFO [org.jboss.as.ejb3] (MSC service thread 1-7) WFLYEJB0493: Jakarta Enterprise Beans subsystem suspension complete Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,623 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-8) WFLYJCA0001: Bound data source [java:jboss/datasources/ExampleDS] Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,691 INFO [org.jboss.as.patching] (MSC service thread 1-8) WFLYPAT0050: WildFly Full cumulative patch ID is: base, one-off patches include: none Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,696 INFO [org.jboss.as.server.deployment.scanner] (MSC service thread 1-5) WFLYDS0013: Started FileSystemDeploymentService for directory /opt/wildfly/wildfly-27.0.0.Final/standalone/deployments Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,755 INFO [org.jboss.ws.common.management] (MSC service thread 1-7) JBWS022052: Starting JBossWS 6.1.0.Final (Apache CXF 3.5.2.jbossorg-3) Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,905 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,910 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 27.0.0.Final (WildFly Core 19.0.0.Final) started in 3859ms - Started 290 of 563 services (357 services are lazy, passive or on-demand) - Server configuration file in use: wildfly.xml Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,913 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management Jan 10 09:24:25 94aa1904876e standalone.sh[1001]: 09:24:25,914 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990 Deploy an application to the WildFly cluster Now, our three WildFly servers are running, but the cluster has yet to form. Indeed, with no apps there is no reason for the cluster to exist. Let’s modify our Ansible playbook to deploy a simple application to all instances; this will allow us to check that the cluster is working as expected. To achieve this, we’ll leverage another role provided by the WildFly collection: wildfly_utils. In our case, we will use the jboss_cli.yml task file, which encapsulates the running of JBoss command-line interface (CLI) commands: … post_tasks: - name: "Ensures webapp {{ app.name }} has been retrieved from {{ app.url }}." ansible.builtin.get_url: url: "{{ app.url }}" dest: "{{ wildfly_install_workdir }}/{{ app.name }}" - name: "Deploy webapp" ansible.builtin.include_role: name: wildfly_utils tasks_from: jboss_cli.yml vars: jboss_home: "{{ wildfly_home }}" query: "'deploy --force {{ wildfly_install_workdir }}/{{ app.name }}'" jboss_cli_controller_port: "{{ item }}" loop: - 9990 - 10090 - 10190 Now, we will once again execute our playbook so the web application is deployed on all instances. Once the automation completes successfully, the deployment will trigger the formation of the cluster. Verify that the WildFly cluster is running and the app is deployed You can verify the cluster formation by looking at the log files of any of the three instances: … 2022-12-23 15:02:08,252 INFO [org.infinispan.CLUSTER] (thread-7,ejb,jboss-eap-0) ISPN000094: Received new cluster view for channel ejb: [jboss-eap-0] (3) [jboss-eap-0, jboss-eap-1, jboss-eap-2] … Using the Ansible collection as an installer for WildFly Last remark: while the collection is designed to be used inside a playbook, you can also use the provided playbook to directly install WildFly: $ ansible-playbook -i inventory middleware_automation.wildfly.playbook Conclusion Here you go, with a short and simple playbook, we have fully automated the deployment of a WildFly cluster! This playbook can now be used against one, two, three remote machine or even hundreds of them! I hope this will post will have been informative and that it’ll have convinced you to use Ansible to set up your own WildFly servers! ### [Integrating with a PostgreSQL database](/guides/database-integrating-with-postgresql/) Integrating with a PostgreSQL database Table of Contents Prerequisites Database PostgreSQL Application Create a new Maven project pom.xml persistence.xml Configure the Jakarta RESTful Web Services application Book Entity BookResource Start the application Check the application Create a book Read all the books Update a book Delete a book Test Cases pom.xml Book Resource test case Run the tests Stop the database What’s next? References In this guide, you will learn how to configure WildFly to connect to a PostgreSQL database. You will create a simple Book Store API application to manage books stored in the database using Jakarta RESTful Web Services (Jakarta REST). Prerequisites To complete this guide, you need: Roughly 20 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Docker or any Open Container Initiative engine installed. This guide uses Podman. Database PostgreSQL We will use PostgreSQL as the database server in its containerized version: see PostgreSQL Official Image. Start PostgreSQL database in a container with: podman run --rm --name bookstore \ -p 5432:5432 \ -e POSTGRES_PASSWORD=admin \ -e POSTGRES_USER=postgres \ -e POSTGRES_DB=bookstore_db \ docker.io/library/postgres Note we started the container with the --rm flag so it can be disposed of automatically when we stop it. Application Create a new Maven project We are going to use the WildFly Getting Started Archetype to create the base structure of our Book Store API application. Open a new terminal window and create a new project using the WildFly Getting Started Archetype: mvn archetype:generate \ -DarchetypeGroupId=org.wildfly.archetype \ -DarchetypeArtifactId=wildfly-getting-started-archetype \ -DdefaultClassPrefix=BookStore \ -DartifactId=bookstore \ -Dversion=1.0.0 \ -DinteractiveMode=false Remove the following files from the base project since we are not going to use them: cd bookstore rm src/main/java/org/wildfly/examples/BookStoreService.java rm src/main/java/org/wildfly/examples/BookStoreEndpoint.java rm src/test/java/org/wildfly/examples/BookStoreApplicationIT.java rm src/test/java/org/wildfly/examples/BookStoreServiceIT.java pom.xml Jakarta dependencies: Add the following dependencies to the pom.xml file: <dependency> <groupId>jakarta.persistence</groupId> <artifactId>jakarta.persistence-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.transaction</groupId> <artifactId>jakarta.transaction-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> <scope>provided</scope> </dependency> Configure WildFly Datasource and trimming server capabilities: To connect to the database we need to configure the WildFly Datasource Subsystem and install the PostgreSQL driver into the WildFly server. The WildFly Datasources Galleon Pack contains a set of Galleon Layers that provide JDBC drivers and WildFly Datasource Subsystem configurations for various databases. For this guide, we will use the postgresql-default-datasource Galleon layer that will configure a PostgreSQL datasource as the default datasource for the server. In addition to the Galleon Layers to configure the datasource and install the drivers, we also want to trim the WildFly server to remove any unnecessary subsystems and features we don’t need. That will reduce the server footprint and the security attack surface. This task can be done by selecting the appropriate Galleon Layers shipped with any WildFly distribution. However, instead of adding a static list of Galleon Layers, we are going to configure the wildfly-maven-plugin plugin to discover the required layers automatically for us. Replace the current wildfly-maven-plugin configuration in the pom.xml file provided by the getting started guide with the following one: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <discover-provisioning-info> <addOns> <addOn>postgresql:default</addOn> </addOns> </discover-provisioning-info> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> In the above configuration, behind the scenes the wildfly-maven-plugin is using WildFly Glow to discover automatically the required Galleon Layers for our application. The discover-provisioning-info configuration tells the plugin to discover the required layers by inspecting our application code. By using the postgresql:default addon, we are specifying we want to use a PostgreSQL database, and we want to configure it as the default datasource for the server. persistence.xml This file is used to configure the Jakarta Persistence persistence unit and its database schema generation strategy. In this guide, we are using the drop-and-create strategy to drop the existing schema and create a new one every time the application starts. For a production environment, you should use a more appropriate strategy to avoid data loss. Create the following persistence.xml file in the src/main/resources/META-INF directory: <?xml version="1.0" encoding="UTF-8" ?> <persistence xmlns="https://jakarta.ee/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd" version="3.0"> <persistence-unit name="bookstore-PU"> <properties> <property name="jakarta.persistence.schema-generation.database.action" value="drop-and-create"/> </properties> </persistence-unit> </persistence> Note We don’t need to specify the name of the Datasource by using <jta-data-source>. In absence of this property, Jakarta Persistence will use the default datasource configured in the server. Configure the Jakarta RESTful Web Services application The BookStoreApplication class acts as a configuration class for the Jakarta REST application. It essentially tells the WildFly runtime that this is a Jakarta REST application and provides the base path for the application’s RESTful web services. Modify it as follows to specify /api as the base URL for our Jakarta REST Web Service: package org.wildfly.examples; import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; @ApplicationPath("/api") public class BookStoreApplication extends Application { } Book Entity The Book entity represents a book record in the database. Create a new class Book in the src/main/java/org/wildfly/examples/books directory with the following content: package org.wildfly.examples.books; import java.util.Objects; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.PositiveOrZero; @Entity @Table(name = "books") public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotBlank @Column(nullable = false) private String title; @NotBlank @Column(nullable = false) private String author; @NotBlank @Column(nullable = false) private String isbn; @PositiveOrZero @Column private double price; public Book() { } public Book(String title, String author, String isbn, double price) { this.title = title; this.author = author; this.isbn = isbn; this.price = price; } public Long getId() { return id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getIsbn() { return isbn; } public void setIsbn(String isbn) { this.isbn = isbn; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Book book = (Book) o; return Double.compare(price, book.price) == 0 && Objects.equals(id, book.id) && Objects.equals(title, book.title) && Objects.equals(author, book.author) && Objects.equals(isbn, book.isbn); } @Override public int hashCode() { return Objects.hash(id, title, author, isbn, price); } @Override public String toString() { return "Book{" + "id=" + id + ", title='" + title + '\'' + ", author='" + author + '\'' + ", isbn='" + isbn + '\'' + ", price=" + price + '}'; } } BookResource The BookResource is the web service that exposes the book records as JSON objects. Create a new class BookResource in the src/main/java/org/wildfly/examples/books directory with the following content: package org.wildfly.examples.books; import java.net.URI; import java.util.List; import jakarta.enterprise.context.RequestScoped; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.POST; import jakarta.ws.rs.PUT; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.UriInfo; @Path("/books") @RequestScoped @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class BookResource { @PersistenceContext EntityManager em; @Context UriInfo uriInfo; @GET public Response getAll() { List<Book> all = em.createQuery("SELECT b FROM Book b", Book.class) .getResultList(); return Response.ok() .entity(all) .build(); } @GET @Path("/{id}") public Response getById(@PathParam("id") Long id) { Book book = em.find(Book.class, id); if (book == null) { throw new NotFoundException("Book with id " + id + " not found"); } return Response.ok() .entity(book) .build(); } @POST @Transactional public Response create(@Valid Book book) { em.persist(book); final URI location = uriInfo.getBaseUriBuilder() .path(BookResource.class) .path(book.getId().toString()) .build(); return Response.created(location) .entity(book) .build(); } @PUT @Path("/{id}") @Transactional public Response update(@PathParam("id") Long id, @Valid Book book) { Book existing = em.find(Book.class, id); if (existing == null) { throw new NotFoundException("Book with id " + id + " not found"); } existing.setAuthor(book.getAuthor()); existing.setTitle(book.getTitle()); existing.setIsbn(book.getIsbn()); existing.setPrice(book.getPrice()); return Response.ok() .entity(existing) .build(); } @DELETE @Path("/{id}") @Transactional public Response delete(@PathParam("id") Long id) { Book book = em.find(Book.class, id); if (book == null) { throw new NotFoundException("Book with id " + id + " not found"); } em.remove(book); return Response.noContent() .build(); } } Start the application Now we should be ready to start our application and interact with the database. First, build the application using Maven: mvn clean package Notice how WildFly Glow gives us information about the feature-packs and Galleon layers discovered. It also provides some hints about required environment variables: [INFO] --- wildfly:5.0.0.Final:package (default) @ bookstore --- [INFO] Glow is scanning... [INFO] Glow scanning DONE. [INFO] context: bare-metal [INFO] enabled profile: none [INFO] galleon discovery [INFO] - feature-packs org.wildfly:wildfly-galleon-pack:32.0.1.Final org.wildfly:wildfly-datasources-galleon-pack:8.0.0.Final - layers ee-core-profile-server jaxrs jpa postgresql-default-datasource [INFO] enabled add-ons [INFO] - postgresql : Documentation in https://github.com/wildfly-extras/wildfly-datasources-galleon-pack - postgresql:default : Documentation in https://github.com/wildfly-extras/wildfly-datasources-galleon-pack [INFO] identified fixes [INFO] * no default datasource found error is fixed - add-on postgresql:default fixes the problem but you need to set the strongly suggested configuration. [WARNING] strongly suggested configuration at runtime [WARNING] postgresql-datasource environment variables: - POSTGRESQL_DATABASE=Defines the database name to be used in the datasource’s `connection-url` property. - POSTGRESQL_PASSWORD=Defines the password for the datasource. - POSTGRESQL_USER=Defines the username for the datasource. [WARNING] postgresql-default-datasource environment variables: - POSTGRESQL_DATABASE=Defines the database name to be used in the datasource’s `connection-url` property. - POSTGRESQL_PASSWORD=Defines the password for the datasource. - POSTGRESQL_USER=Defines the username for the datasource. Now create the required environment variables used by WildFly to connect to the PostgreSQL database and start the server: export POSTGRESQL_USER=postgres export POSTGRESQL_PASSWORD=admin export POSTGRESQL_DATABASE=bookstore_db ./target/server/bin/standalone.sh …​ 11:34:49,242 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 32.0.1.Final (WildFly Core 24.0.1.Final) started in 2118ms - Started 295 of 366 services (139 services are lazy, passive or on-demand) - Server configuration file in use: standalone.xml Check the application We have our application running at http://localhost:8080/. Let’s now interact with it using the following endpoints to Create, Read, Update and Delete books. We will use the curl utility to interact with the application. Create a book To create a new book, execute a POST request to the /api/books endpoint with the book information: $ curl -v -X POST http://localhost:8080/api/books -H "Content-Type: application/json" -d ' { "author": "Jules Verne", "isbn": "10-0760765197", "price": 9.99, "title": "From the Earth to the Moon" }' If you inspect the response, you will see the URL of the newly created book gets returned under the location header: Location: http://localhost:8080/api/books/1 You can use the location to check the book you have just created: $ curl http://localhost:8080/api/books/1 { "author": "Jules Verne", "id": 1, "isbn": "10-0760765197", "price": 9.99, "title": "From the Earth to the Moon" } Read all the books To list all the books, execute a GET request to the /api/books endpoint: $ curl http://localhost:8080/api/books It will return the list of books of our database: [ { "author": "Jules Verne", "id": 1, "isbn": "10-0760765197", "price": 9.99, "title": "From the Earth to the Moon" } ] Update a book To update a book, execute a PUT request to the /api/books/{id} endpoint with the book information you want. For example to change the price of the recent book we have recently created, execute the following: $ curl -X PUT http://localhost:8080/api/books/1 -H "Content-Type: application/json" -d ' { "author": "Jules Verne", "isbn": "10-0760765197", "price": 10.99, "title": "From the Earth to the Moon" }' Delete a book To delete a book, execute a DELETE request to the /api/books/{id} endpoint with the book id you want to delete. For example, to delete the book we have recently created: $ curl -X DELETE http://localhost:8080/api/books/1 Stop the application To stop the application, press Ctrl+C in the terminal where the server is running. Test Cases Until now, we have verified the application manually. The following steps will guide you with the required changes to test our application using the Arquillian framework. pom.xml We need to have a JSON provider available on the test classpath to convert Book objects to JSON and vice versa. Add the following dependency to the pom.xml file: <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jackson2-provider</artifactId> <scope>test</scope> </dependency> Book Resource test case Create a new class BookResourceIT in the src/test/java/org/wildfly/examples/books directory with the following content: package org.wildfly.examples.books; import static org.junit.jupiter.api.Assertions.assertEquals; import java.net.URI; import java.util.List; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.Entity; import jakarta.ws.rs.core.GenericType; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.jboss.arquillian.container.test.api.RunAsClient; import org.jboss.arquillian.junit5.ArquillianExtension; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; @RunAsClient @ExtendWith(ArquillianExtension.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class BookResourceIT { @Test @Order(1) public void testHelloEndpoint() { try (Client client = ClientBuilder.newClient()) { Response response = client .target(URI.create("http://localhost:8080/")) .path("/") .request() .get(); assertEquals(200, response.getStatus()); } } @Test @Order(2) public void create() { try (Client client = ClientBuilder.newClient()) { Book book = new Book("Test Book title", "Test Book author", "Test Book isbn", 10.0); Response response = client .target(URI.create("http://localhost:8080/")) .path("/api/books") .request(MediaType.APPLICATION_JSON) .post(Entity.entity(book, MediaType.APPLICATION_JSON)); assertEquals(201, response.getStatus()); assertEquals("http://localhost:8080/api/books/1", response.getLocation().toString()); } } @Test @Order(3) public void list() { try (Client client = ClientBuilder.newClient()) { Response response = client .target(URI.create("http://localhost:8080/")) .path("/api/books") .request(MediaType.APPLICATION_JSON) .get(); assertEquals(200, response.getStatus()); List<Book> books = response.readEntity(new GenericType<>() { }); assertEquals(1, books.size()); Book book = books.get(0); assertEquals("Test Book title", book.getTitle()); assertEquals("Test Book author", book.getAuthor()); assertEquals("Test Book isbn", book.getIsbn()); assertEquals(10.0, book.getPrice()); } } @Test @Order(4) public void update() { try (Client client = ClientBuilder.newClient()) { Book book = new Book("Test Book title updated", "Test Book author updated", "Test Book isbn updated", 99.9); Response response = client .target(URI.create("http://localhost:8080/")) .path("/api/books/1") .request(MediaType.APPLICATION_JSON) .put(Entity.entity(book, MediaType.APPLICATION_JSON)); assertEquals(200, response.getStatus()); response = client .target(URI.create("http://localhost:8080/")) .path("/api/books/1") .request(MediaType.APPLICATION_JSON) .get(); Book updated = response.readEntity(new GenericType<>() { }); assertEquals("Test Book title updated", updated.getTitle()); assertEquals("Test Book author updated", updated.getAuthor()); assertEquals("Test Book isbn updated", updated.getIsbn()); assertEquals(99.9, updated.getPrice()); } } @Test @Order(5) public void delete() { try (Client client = ClientBuilder.newClient()) { Response response = client .target(URI.create("http://localhost:8080/")) .path("/api/books/1") .request(MediaType.APPLICATION_JSON) .delete(); assertEquals(204, response.getStatus()); response = client .target(URI.create("http://localhost:8080/")) .path("/api/books/1") .request(MediaType.APPLICATION_JSON) .get(); assertEquals(404, response.getStatus()); } } } Run the tests You can run the tests using the following command: export POSTGRESQL_USER=postgres export POSTGRESQL_PASSWORD=admin export POSTGRESQL_DATABASE=bookstore_db mvn clean verify In this guide we have reused the same database instance for running the application and for the test cases. If you want to use a different instance for test cases, you have to adapt the values of the environment variables accordingly. Stop the database Finally, to stop the PostgreSQL database, press Ctrl+C in the terminal where the container is running. What’s next? In this guide we have learned how to configure a WildFly server to access to a PostgreSQL database and how to easily trim the server capabilities using WildFly Glow. Seamlessly, you can adapt the same application to use other databases by changing the Galleon Layers used by the WildFly server. You can learn more about how to configure WildFly for other databases by looking at the WildFly Datasources Galleon Pack documentation and WildFly Glow Guide. References WildFly Datasource Subsystem WildFly Datasources Galleon Pack WildFly Glow Guide ### [Java Microservices on Kubernetes with WildFly](/guides/get-started-microservices-on-kubernetes/) Build Java Microservices with WildFly and run them on Kubernetes. Intro In this series, you’ll learn HOW-TO to build applications using some of the most common Jakarta specifications (e.g. Jakarta REST services, Jakarta Persistence, Jakarta Messaging, etc.) and run them on Kubernetes. At some point, we’ll go even further and use some MicroProfile specifications (e.g. Rest Client invoking a Jakarta REST service in another application). We will start building a Docker Image containing a WildFly Java Microservice (WildFly Java Microservice - PART 1: Container Image), and then we will run that Docker Image on Kubernetes (WildFly Java Microservice - PART 2: Kubernetes): this will set the basis to extend this example in subsequent guides. Guides in this series WildFly Java Microservice WildFly Java Microservice - PART 1: Container Image WildFly Java Microservice - PART 2: Kubernetes Connecting to a DB Connecting to a DB - PART 1: Container Image Connecting to a DB - PART 2: Kubernetes Using Infinispan remote cache Using Infinispan remote cache - PART 1: Container Image Using Infinispan remote cache - PART 2: Kubernetes Using a Message Broker Using a Message Broker - PART 1: Container Image Using a Message Broker - PART 2: Kubernetes Invoke one Microservices from another Invoke one Microservices from another - PART 1: Container Images Invoke one Microservices from another - PART 2: Kubernetes Invoke one Microservices from another - PART 3: Propagate Authentication References Eclipse MicroProfile Config ### [{get-enterprise-ready}](/guides/get-started-microservices-on-kubernetes/get-enterprise-ready/) Get “Enterprise” ready Back to Guides < Back to Getting Started with WildFly micro-services on Kubernetes ### [{simple-microservice-client-part1}](/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part1/) Invoke one Microservices from another - PART 1: Container Images Table of Contents Prerequisites Introduction This Guide Microservice B - the server Maven Project Docker Image Microservice A - the client Maven Project Docker Image Test What’s next? References In this guide, you will learn HOW-TO invoke one microservice from another; Prerequisites To complete this guide, you need: Complete WildFly Java Microservice - PART 1: Container Image Introduction This guide is the first in a series of three: In Invoke one Microservices from another - PART 1: Container Images (this guide), we explain HOW-TO invoke one microservice from another; In Invoke one Microservices from another - PART 2: Kubernetes, as usual, we explain HOW-TO run the whole thing on Kubernetes In Invoke one Microservices from another - PART 3: Propagate Authentication we explain HOW-TO propagate user authentication and authorization data from the calling microservice to the invoked microservice; this is most useful in a scenario where you have a "chain" of microservices ("A → B → C → etc.") and you want the user’s authentication and authorization data to be propagated from one microservice to the next; This Guide In these guides, we work with a simple invocation chain composed by two microservices: Microservice A: acting as client Microservice B: acting as server Our invocation chain is then: "Microservice A → Microservice B": when working with Microprofile, this is achieved by using the microprofile-rest-client; Specifically, Microservice A will use the microprofile-rest-client to invoke the Jakarta REST service exposed by Microservice B; For both services, we will start from the microservice we built in WildFly Java Microservice - PART 1: Container Image (complete code in https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice); Microservice B - the server We start from the server because we need the server’s API for the client later on; Maven Project Copy https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice into a new folder named simple-microservice-server and: remove folder src/test remove all test scope dependencies Note we remove tests because, since we are going to introduce service to service invocation, they wouldn’t be much useful anymore pom.xml Update the artifactId to <artifactId>simple-microservice-server</artifactId>; Note Microservice B is basically unchanged, we will modify it in Invoke one Microservices from another - PART 3: Propagate Authentication Build the application mvn clean package Docker Image Dockerfile Since you copied simple-microservice, the Dockerfile from examples/docker-build/Dockerfile should already be at the root of your project; Build the Docker Image podman build -t simple-microservice-server:latest . Note You can use wildfly-maven-plugin to automate the image build Run the Docker Image First we create a network for our containers: podman network create demo-network Then we run our container using this network: podman run --rm -p 8180:8080 -p 10090:9990 \ --network=demo-network \ --name=simple-microservice-server \ simple-microservice-server Microservice A - the client Maven Project Copy https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice into a new folder named simple-microservice-client and: remove folder src/test remove all test scope dependencies Note we remove tests because, since we are going to introduce service to service invocation, they wouldn’t be much useful anymore pom.xml Update the artifactId to <artifactId>simple-microservice-client</artifactId>; Add the following to dependencyManagement: <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>wildfly-expansion</artifactId> <version>${version.wildfly.bom}</version> <type>pom</type> <scope>import</scope> </dependency> Add the following to dependencies: <dependency> <groupId>org.eclipse.microprofile.rest.client</groupId> <artifactId>microprofile-rest-client-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.microprofile.config</groupId> <artifactId>microprofile-config-api</artifactId> <scope>provided</scope> </dependency> Add the following layers in the wildfly-maven-plugin: <layer>microprofile-config</layer> <layer>microprofile-rest-client</layer> Later on, we will use: microprofile-config to make the URL to Microservice B configurable microprofile-rest-client to actually invoke Microservice B microprofile-config.properties As anticipated, we use microprofile-config to make the URL to Microservice B configurable; Add file src/main/resources/META-INF/microprofile-config.properties with the following content: microprofile-config.properties: simple-microservice-server/mp-rest/uri=${simple-microservice-server-uri:http://127.0.0.1:8080} simple-microservice-server/mp-rest/connectTimeout=3000 Note simple-microservice-server-uri would pick up its value, whenever set, from the environment variable named SIMPLE_MICROSERVICE_SERVER_URI (see env.mapping) Java code Add the following interface: GettingStartedEndpointClient.java: package org.wildfly.examples; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; @RegisterRestClient(configKey="simple-microservice-server") @Path("/hello") public interface GettingStartedEndpointClient { @GET @Path("/{name}") @Produces(MediaType.TEXT_PLAIN) Response sayHello(@PathParam("name") String name); } Note this class is used to define the API to be invoked by the Rest Client; the actual URL where the remote service is located, comes from the microprofile-config.properties file we just added; Remove the src/main/java/org/wildfly/examples/GettingStartedService.java file and replace the content of src/main/java/org/wildfly/examples/GettingStartedEndpoint.java with the following: GettingStartedEndpoint.java: package org.wildfly.examples; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.eclipse.microprofile.rest.client.inject.RestClient; @Path("/") public class GettingStartedEndpoint { @Inject @RestClient private GettingStartedEndpointClient client; @GET @Path("/{name}") @Produces(MediaType.TEXT_PLAIN) public Response sayHello(final @PathParam("name") String name) { return client.sayHello(name); } } Note as anticipated, we use microprofile-rest-client to actually invoke Microservice B Build the application mvn clean package Docker Image Dockerfile Since you copied simple-microservice, the Dockerfile from examples/docker-build/Dockerfile should already be at the root of your project; Build the Docker Image Build the Docker Image simple-microservice-client:latest with the following command: podman build -t simple-microservice-client:latest . Note You can use wildfly-maven-plugin to automate the image build Run the Docker Image podman run --rm -p 8080:8080 -p 9990:9990 \ --network=demo-network \ --env "SIMPLE_MICROSERVICE_SERVER_URI=http://simple-microservice-server:8080" \ --name=simple-microservice-client \ simple-microservice-client Note The simple-microservice-server container can be reached, inside the demo-network network, using the DNS name simple-microservice-server Test Open http://localhost:8080 in your browser: this web page is served by the simple-microservice-client container; Write something in the "Name" input box and then press "Say Hello": the response you’ll see will come from simple-microservice-server container! The complete invocation chain is "web browser → simple-microservice-client → simple-microservice-server" What’s next? Invoke one Microservices from another - PART 2: Kubernetes References microprofile-rest-client microprofile-config Source code for this guide: https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-rest-client/simple-microservice-client https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-rest-client/simple-microservice-server ### [{simple-microservice-client-part2}](/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part2/) Invoke one Microservices from another - PART 2: Kubernetes Table of Contents Prerequisites Introduction Minikube Microservice B - the server Image Registry Deploy on Kubernetes Create Kubernetes ClusterIP Service Check Kubernetes Service Microservice A - the client Image Registry Deploy on Kubernetes Create Kubernetes NodePort Service Check your application What’s next? References In this guide, you will learn HOW-TO run the Docker Images you built in Invoke one Microservices from another - PART 1: Container Images on Kubernetes. Prerequisites To complete this guide, you need: Complete Invoke one Microservices from another - PART 1: Container Images Introduction In this guide, we will deploy on Kubernetes the two container images we created in Invoke one Microservices from another - PART 1: Container Images; Minikube You can use whatever Kubernetes cluster you have available; in this guide, and in the following, we will use minikube. Microservice B - the server Image Registry To make the simple-microservice-server:latest Docker Image available to Kubernetes, you need to push it to some Image Registry that is accessible by the Kubernetes cluster you want to use. Quay.io There are many Image Registries you can use: in this guide, we will push the simple-microservice-server:latest Docker Image, to the quay.io Image Registry. Create a public repository named simple-microservice-server on quay.io (e.g. https://quay.io/repository/tborgato/simple-microservice-server). Note replace tborgato with the name of your account in all the commands that will follow Tag the Docker image: podman tag simple-microservice-server quay.io/tborgato/simple-microservice-server Push the simple-microservice-server Docker Image to it: podman push quay.io/tborgato/simple-microservice-server At this point, the simple-microservice-server:latest Docker Image should be publicly available and free to be consumed by any Kubernetes Cluster; Deploy on Kubernetes Create a folder named kubernetes in the root of your project and create a file named simple-microservice-server-deployment.yaml inside it: simple-microservice-server-deployment.yaml: apiVersion: apps/v1 kind: Deployment metadata: name: simple-microservice-server-deployment labels: app: simple-microservice-server spec: replicas: 1 selector: matchLabels: app: simple-microservice-server template: metadata: labels: app: simple-microservice-server spec: containers: - name: simple-microservice-server image: quay.io/tborgato/simple-microservice-server ports: - containerPort: 8080 - containerPort: 9990 livenessProbe: httpGet: path: /health/live port: 9990 readinessProbe: httpGet: path: /health/ready port: 9990 startupProbe: httpGet: path: /health/started port: 9990 Deploy to your Kubernetes Cluster: kubectl apply -f kubernetes/simple-microservice-server-deployment.yaml Note before running any kubectl remember to start you Kubernetes cluster (use minikube start if using minikube) Create Kubernetes ClusterIP Service We create a kubernetes service to consume the services exposed by simple-microservice-server from inside Kubernetes; Create a file named simple-microservice-server-service.yaml in the kubernetes folder: simple-microservice-server-service.yaml: apiVersion: v1 kind: Service metadata: name: simple-microservice-server-service labels: app: simple-microservice-server spec: ports: - name: http protocol: TCP port: 8080 targetPort: 8080 selector: app: simple-microservice-server type: ClusterIP Deploy to your Kubernetes Cluster: kubectl apply -f kubernetes/simple-microservice-server-service.yaml Check Kubernetes Service kubectl run --rm -it --tty curl-simple-microservice-server --image=curlimages/curl --restart=Never -- http://simple-microservice-server-service:8080/hello/pippo Microservice A - the client Image Registry To make the simple-microservice-client:latest Docker Image available to Kubernetes, you need to push it to some Image Registry that is accessible by the Kubernetes cluster you want to use. Quay.io There are many Image Registries you can use: in this guide, we will push the simple-microservice-client:latest Docker Image, to the quay.io Image Registry. Create a public repository named simple-microservice-client on quay.io (e.g. https://quay.io/repository/tborgato/simple-microservice-client). Note replace tborgato with the name of your account in all the commands that will follow Tag the Docker image: podman tag simple-microservice-client quay.io/tborgato/simple-microservice-client Push the simple-microservice-client Docker Image to it: podman push quay.io/tborgato/simple-microservice-client At this point, the simple-microservice-client:latest Docker Image should be publicly available and free to be consumed by any Kubernetes Cluster; Note You can use wildfly-maven-plugin to automate the image push to an image registry Deploy on Kubernetes Create a file named simple-microservice-client-deployment.yaml in the kubernetes folder: simple-microservice-client-deployment.yaml: apiVersion: apps/v1 kind: Deployment metadata: name: simple-microservice-client-deployment labels: app: simple-microservice-client spec: replicas: 1 selector: matchLabels: app: simple-microservice-client template: metadata: labels: app: simple-microservice-client spec: containers: - name: simple-microservice-client image: quay.io/tborgato/simple-microservice-client ports: - containerPort: 8080 - containerPort: 9990 livenessProbe: httpGet: path: /health/live port: 9990 readinessProbe: httpGet: path: /health/ready port: 9990 startupProbe: httpGet: path: /health/started port: 9990 env: - name: SIMPLE_MICROSERVICE_SERVER_URI value: "http://simple-microservice-server-service:8080" Note The environment variable SIMPLE_MICROSERVICE_SERVER_URI allows simple-microservice-client to invoke simple-microservice-server through the service simple-microservice-server-service Deploy to your Kubernetes Cluster: kubectl apply -f kubernetes/simple-microservice-client-deployment.yaml Create Kubernetes NodePort Service We create a service to consume the services exposed by simple-microservice-client from outside Kubernetes; Create a file named simple-microservice-client-service.yaml in the kubernetes folder: simple-microservice-client-service.yaml: apiVersion: v1 kind: Service metadata: name: simple-microservice-client-service labels: app: simple-microservice-client spec: ports: - name: http protocol: TCP port: 8080 targetPort: 8080 selector: app: simple-microservice-client type: NodePort Deploy to your Kubernetes Cluster: kubectl apply -f kubernetes/simple-microservice-client-service.yaml Check your application Find out on what IP address/port, minikube is exposing your service: $ minikube service simple-microservice-client-service --url http://192.168.39.143:30347 Verify it’s working as expected: $ curl http://192.168.39.143:30347/hello/pippo Hello 'pippo'. What’s next? Invoke one Microservices from another - PART 3: Propagate Authentication References Source code for this guide: https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-rest-client/simple-microservice-client https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-rest-client/simple-microservice-server ### [{simple-microservice-client-part3}](/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part3/) Invoke one Microservices from another - PART 3: Propagate Authentication Table of Contents Prerequisites Introduction How it works Keycloak Run Keycloak on Kubernetes Web Application (Microservice A) Maven Project Java code Build and push the image to Quay.io Deploy to Kubernetes Service (Microservice B) Maven Project microprofile-config.properties Java code Build and push the image to Quay.io Deploy to Kubernetes Test References In this guide, you will learn HOW-TO propagate user authentication and authorization data between two microservices; Prerequisites To complete this guide, you need: Complete Invoke one Microservices from another - PART 2: Kubernetes Introduction The scenario consists of: a Service deployed on a Kubernetes cluster which is not exposed outside the cluster a Web Application deployed on a Kubernetes cluster which is exposed outside the cluster and consumes the Service The user is required to authenticate before using the Web Application and, after authentication happens, we want authentication data to be available, not only to the Web Application, but also tho the Service; authentication is delegated to Keycloak using OpenID Connect protocol; The overall architecture is: We will start from the two microservices we built in Invoke one Microservices from another - PART 2: Kubernetes and: Microservice A will be the basis for Web Application Microservice B will be the basis for Service How it works This is how it works: The user tries to access Web Application (Microservice A) from a web browser The browser is redirected to Keycloak where, by providing username and password, the user authenticates itself The browser is redirected back to Web Application: this time the request contains a JWT Access Token (and a few more tokens actually) provided by Keycloak, containing authentication and authorization data Web Application validates the JWT Access Token and grants access to the user Web Application invokes Service (Microservice B) forwarding to it the JWT Access Token it just received Service validates the JWT Access Token and grants access to Web Application Keycloak First, we install and configure Keycloak with users, groups etc.. Run Keycloak on Kubernetes Create a folder named keycloak wherever you want; Download file keycloak-realm-realm.json inside the keycloak folder you just created; Then, create a configmap using it as its content (run the command from the keycloak folder): kubectl create configmap keycloak-data-import --from-file=keycloak-realm-realm.json=keycloak-realm-realm.json Create a file named keycloak.yaml in the keycloak folder: keycloak.yaml: apiVersion: v1 kind: Service metadata: name: keycloak-external labels: app: keycloak spec: ports: - name: http port: 8080 targetPort: 8080 selector: app: keycloak type: NodePort --- apiVersion: v1 kind: Service metadata: name: keycloak-internal labels: app: keycloak spec: ports: - name: http port: 8080 targetPort: 8080 selector: app: keycloak type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: keycloak labels: app: keycloak spec: replicas: 1 selector: matchLabels: app: keycloak template: metadata: labels: app: keycloak spec: volumes: - name: keycloak-data-import-volume configMap: name: keycloak-data-import containers: - name: keycloak image: quay.io/keycloak/keycloak:26.0 args: [ "start-dev", "--import-realm" ] env: - name: KEYCLOAK_ADMIN value: "admin" - name: KEYCLOAK_ADMIN_PASSWORD value: "admin" ports: - name: http containerPort: 8080 readinessProbe: httpGet: path: /realms/master port: 8080 volumeMounts: - name: keycloak-data-import-volume mountPath: /opt/keycloak/data/import Deploy to your Kubernetes Cluster (run the command from the keycloak folder): kubectl apply -f keycloak.yaml To access the Keycloak console, find out on what IP address/port, minikube is exposing your keycloak-external service: $ minikube service keycloak-external --url http://192.168.39.190:31950 Open the link in your web browser and login to Keycloak with username/password "admin/admin"; Note since we are using minikube, we expose Keycloak outside the cluster with a NodePort service (keycloak-external) and inside the cluster with a ClusterIP service (keycloak-internal) optional alternative: configure Keycloak manually As an alternative to using Keycloak auto import feature (see the "--import-realm" command argument above), you can configure Keycloak manually: remove volumes and volumeMounts and follow these steps: Create a realm called keycloak-realm Create a client called simple-microservice-client-secured; in the Capability config, turn on Client authentication. For the simple-microservice-client-secured client, we also need to set the valid redirect URIs to * and set the Web origins to + to permit all origins of Valid Redirect URIs. For the simple-microservice-client-secured client, note down the Client Secret in the Credentials tab (e.g. KqIQIzNHD9LnCRjsCxblDnfEl4rcNoKB); Now, click on Realm roles and create two roles, user and admin. Create a user called alice and assign her the user and admin roles; set password 123 for alice Create a user called bob and assign him only the user role; set password 123 for bob Note in case you want to go deeper, find more information and examples in Setting up your Keycloak OpenID provider Web Application (Microservice A) Maven Project Copy simple-microservice-client into a new folder named simple-microservice-client-secured; pom.xml Update the artifactId to <artifactId>simple-microservice-client-secured</artifactId>; Add the following to dependencies: <dependency> <groupId>org.wildfly.security</groupId> <artifactId>wildfly-elytron-http-oidc</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <scope>provided</scope> </dependency> Add the following layers in the wildfly-maven-plugin: <layer>elytron-oidc-client</layer> web.xml Create file src/main/webapp/WEB-INF/web.xml with the following content: src/main/webapp/WEB-INF/web.xml: <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" metadata-complete="false"> <security-constraint> <web-resource-collection> <web-resource-name>secured</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>user</role-name> <role-name>admin</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>OIDC</auth-method> </login-config> <security-role> <role-name>user</role-name> </security-role> <security-role> <role-name>admin</role-name> </security-role> </web-app> oidc.json Create file src/main/webapp/WEB-INF/oidc.json with the following content: src/main/webapp/WEB-INF/oidc.json: { "client-id" : "simple-microservice-client-secured", "provider-url" : "${env.OIDC_PROVIDER_URL:http://localhost:8080}/realms/keycloak-realm", "ssl-required" : "EXTERNAL", "credentials" : { "secret" : "${env.OIDC_CLIENT_SECRET:KqIQIzNHD9LnCRjsCxblDnfEl4rcNoKB}" } } In case you followed the steps in optional alternative: configure Keycloak manually, replace KqIQIzNHD9LnCRjsCxblDnfEl4rcNoKB with the Client Secret you previously noted down; Java code GettingStartedEndpointClient Add the following interface: org.wildfly.examples.GettingStartedEndpointClient.java: package org.wildfly.examples; import jakarta.ws.rs.GET; import jakarta.ws.rs.HeaderParam; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; @RegisterClientHeaders @RegisterRestClient(configKey="simple-microservice-server") @Path("/hello") public interface GettingStartedEndpointClient { @GET @Path("/{name}") @Produces(MediaType.TEXT_PLAIN) public Response sayHello(@HeaderParam("Authorization") String authorization, final @PathParam("name") String name); } GettingStartedEndpoint Modify the class GettingStartedEndpoint as in the following: org.wildfly.examples.GettingStartedEndpoint.java: package org.wildfly.examples; import jakarta.inject.Inject; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.wildfly.security.http.oidc.OidcSecurityContext; import java.io.IOException; @Path("/") public class GettingStartedEndpoint { @Context private HttpServletRequest httpServletRequest; @Inject @RestClient private GettingStartedEndpointClient client; @GET @Path("/{name}") @Produces(MediaType.TEXT_PLAIN) public Response sayHello(final @PathParam("name") String name) throws IOException { Response response; OidcSecurityContext oidcSecurityContext = getOidcSecurityContext(httpServletRequest); if (oidcSecurityContext != null) { String authzHeaderValue = "Bearer " + oidcSecurityContext.getTokenString(); System.out.println("\n\n[JWT] service Token: " + authzHeaderValue + "\n\n"); return client.sayHello(authzHeaderValue, name); } else { System.out.println("\n\n[JWT] No token :(\n\n"); return client.sayHello(null, name); } } private OidcSecurityContext getOidcSecurityContext(HttpServletRequest req) { return (OidcSecurityContext) req.getAttribute(OidcSecurityContext.class.getName()); } } Build and push the image to Quay.io Build the application: mvn clean package Build the Docker image: podman build -t simple-microservice-client-secured:latest . Note You can use wildfly-maven-plugin to automate the image build Create a public repository named simple-microservice-client-secured on quay.io (e.g. https://quay.io/repository/tborgato/simple-microservice-client-secured). Note replace tborgato with the name of your account in all the commands that will follow Tag the Docker image: podman tag simple-microservice-client-secured quay.io/tborgato/simple-microservice-client-secured Push the simple-microservice-client-secured Docker Image: podman push quay.io/tborgato/simple-microservice-client-secured Deploy to Kubernetes Create file simple-microservice-client-secured-deployment.yaml in the kubernetes folder in the root of your project: simple-microservice-client-secured-deployment.yaml: apiVersion: apps/v1 kind: Deployment metadata: name: simple-microservice-client-secured-deployment labels: app: simple-microservice-client-secured spec: replicas: 1 selector: matchLabels: app: simple-microservice-client-secured template: metadata: labels: app: simple-microservice-client-secured spec: containers: - name: simple-microservice-client-secured image: quay.io/tborgato/simple-microservice-client-secured ports: - containerPort: 8080 - containerPort: 9990 livenessProbe: httpGet: path: /health/live port: 9990 readinessProbe: httpGet: path: /health/ready port: 9990 startupProbe: httpGet: path: /health/started port: 9990 env: - name: SIMPLE-MICROSERVICE-SERVER_MP_REST_URI value: "http://simple-microservice-server-secured-service:8080" - name: OIDC_PROVIDER_URL # replace with the outcome of "minikube service keycloak-external --url" value: "http://192.168.39.190:31950" - name: OIDC_CLIENT_SECRET value: "KqIQIzNHD9LnCRjsCxblDnfEl4rcNoKB" Then: replace "http://192.168.39.190:31950" with the outcome of command minikube service keycloak-external --url (this is where your web browser will be redirected for authentication) replace "tborgato" with your account name on quay.io In case you followed the steps in optional alternative: configure Keycloak manually, replace KqIQIzNHD9LnCRjsCxblDnfEl4rcNoKB with the Client Secret you previously noted down; Deploy to your Kubernetes Cluster: kubectl apply -f kubernetes/simple-microservice-client-secured-deployment.yaml Create file simple-microservice-client-secured-service.yaml in the kubernetes folder: simple-microservice-client-secured-service.yaml: apiVersion: v1 kind: Service metadata: name: simple-microservice-client-secured-service labels: app: simple-microservice-client-secured spec: ports: - name: http protocol: TCP port: 8080 targetPort: 8080 selector: app: simple-microservice-client-secured type: NodePort Deploy to your Kubernetes Cluster: kubectl apply -f kubernetes/simple-microservice-client-secured-service.yaml Service (Microservice B) Maven Project Copy simple-microservice-server into a new folder named simple-microservice-server-secured; pom.xml Update the artifactId to <artifactId>simple-microservice-server-secured</artifactId>; Add the following to dependencyManagement: <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>wildfly-expansion</artifactId> <version>${version.wildfly.bom}</version> <type>pom</type> <scope>import</scope> </dependency> Add the following to dependencies: <dependency> <groupId>org.eclipse.microprofile.config</groupId> <artifactId>microprofile-config-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.microprofile.jwt</groupId> <artifactId>microprofile-jwt-auth-api</artifactId> <scope>provided</scope> </dependency> Add the following layers in the wildfly-maven-plugin: <layer>microprofile-config</layer> <layer>microprofile-jwt</layer> microprofile-config.properties Add file src/main/resources/META-INF/microprofile-config.properties with the following content: microprofile-config.properties: mp.jwt.verify.publickey.location=http://localhost:8080/realms/keycloak-realm/protocol/openid-connect/certs Java code GettingStartedApplication Modify the class GettingStartedApplication as in the following: org.wildfly.examples.GettingStartedApplication.java: package org.wildfly.examples; import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; import org.eclipse.microprofile.auth.LoginConfig; @LoginConfig(authMethod="MP-JWT") @ApplicationPath("/hello") public class GettingStartedApplication extends Application { } GettingStartedEndpoint Modify the class GettingStartedEndpoint as in the following: org.wildfly.examples.GettingStartedEndpoint.java: package org.wildfly.examples; import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.jwt.JsonWebToken; @Path("/") public class GettingStartedEndpoint { @Inject @ConfigProperty(name = "mp.jwt.verify.publickey.location") private String publicKeyLocation; @Inject JsonWebToken jwt; @GET @Path("/{name}") @Produces(MediaType.TEXT_PLAIN) @RolesAllowed({"admin"}) public Response sayHello(final @PathParam("name") String name) { System.out.println("mp.jwt.verify.publickey.location=" + publicKeyLocation); String response = "Hello " + name + (jwt != null ? (" Subject:" + jwt.getSubject()) : null) + (jwt != null ? (" Issuer: " + jwt.getIssuer()) : null); return Response.ok(response).build(); } } Build and push the image to Quay.io Build the application: mvn clean package Build the Docker image: podman build -t simple-microservice-server-secured:latest . Create a public repository named simple-microservice-server-secured on quay.io (e.g. https://quay.io/repository/tborgato/simple-microservice-server-secured). Note replace tborgato with the name of your account in all the commands that will follow Tag the Docker image: podman tag simple-microservice-server-secured quay.io/tborgato/simple-microservice-server-secured Push the simple-microservice-server-secured Docker Image: podman push quay.io/tborgato/simple-microservice-server-secured Deploy to Kubernetes Create file simple-microservice-server-secured-deployment.yaml in the kubernetes folder: simple-microservice-server-secured-deployment.yaml: apiVersion: apps/v1 kind: Deployment metadata: name: simple-microservice-server-secured-deployment labels: app: simple-microservice-server-secured spec: replicas: 1 selector: matchLabels: app: simple-microservice-server-secured template: metadata: labels: app: simple-microservice-server-secured spec: containers: - name: simple-microservice-server-secured image: quay.io/tborgato/simple-microservice-server-secured ports: - containerPort: 8080 - containerPort: 9990 livenessProbe: httpGet: path: /health/live port: 9990 readinessProbe: httpGet: path: /health/ready port: 9990 startupProbe: httpGet: path: /health/started port: 9990 env: - name: MP_JWT_VERIFY_PUBLICKEY_LOCATION value: "http://keycloak-internal:8080/realms/keycloak-realm/protocol/openid-connect/certs" Then: replace "tborgato" with your account name on quay.io Deploy to your Kubernetes Cluster: kubectl apply -f kubernetes/simple-microservice-server-secured-deployment.yaml Create file simple-microservice-server-secured-service.yaml in the kubernetes folder: simple-microservice-server-secured-service.yaml: apiVersion: v1 kind: Service metadata: name: simple-microservice-server-secured-service labels: app: simple-microservice-server-secured spec: ports: - name: http protocol: TCP port: 8080 targetPort: 8080 selector: app: simple-microservice-server-secured type: ClusterIP Deploy to your Kubernetes Cluster: kubectl apply -f kubernetes/simple-microservice-server-secured-service.yaml Test $ minikube service simple-microservice-client-secured-service --url http://192.168.39.190:32225 Open that URL in your browser, log in as alice/123 and try it out! After pressing the "Say Hello" button, you should see something like: Hello ddd Subject:aaef43ee-4005-4d2d-a5f0-0e0d11a1f831 Issuer: http://192.168.39.190:31950/realms/keycloak-realm References https://wildfly-security.github.io/wildfly-elytron/blog/bearer-only-support-openid-connect/ https://github.com/wildfly-security-incubator/elytron-examples/tree/main/oidc-with-bearer https://www.keycloak.org/getting-started/getting-started-kube Source code for this guide: https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-rest-client/simple-microservice-client-secured https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-rest-client/simple-microservice-server-secured ### [{simple-microservice-database-part1}](/guides/get-started-microservices-on-kubernetes/simple-microservice-database-part1/) Connecting to a DB - PART 1: Container Image Table of Contents Prerequisites Database PostgreSQL Maven Project pom.xml Java Classes persistence.xml Build the application Docker Image Build the Docker Image Run the Docker Image Check the application Stop the Docker containers What’s next? References In this guide, we will extend the example created in WildFly Java Microservice - PART 1: Container Image and add Database connectivity. Prerequisites To complete this guide, you need: Complete WildFly Java Microservice - PART 1: Container Image Database PostgreSQL We will use PostgreSQL in this guide in its containerized version: see PostgreSQL Official Image. Start PostgreSQL: podman network create demo-network podman run --rm --network=demo-network --name my-postgres \ -p 5432:5432 \ -e POSTGRES_PASSWORD=admin \ -e POSTGRES_USER=postgres \ -e POSTGRES_DB=postgres \ docker.io/library/postgres Note we started the container with the --rm flag: this way it is disposed of automatically when we stop it Note We created the demo-network network and started the my-postgres container with the --network=demo-network option: later in this guide, this will allow us to connect to the my-postgres container from the my-jaxrs-app-db container Maven Project You will extend the sample application you created in WildFly Java Microservice - PART 1: Container Image by adding the wildfly-datasources-galleon-pack. The wildfly-datasources-galleon-pack will: install the JDBC Driver for the PostgreSQL Database into WildFly add a database connection to PostgreSQL in WildFly pom.xml dependencies Add the following dependencies to the pom-xml file dependencies section: <dependency> <groupId>jakarta.persistence</groupId> <artifactId>jakarta.persistence-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.transaction</groupId> <artifactId>jakarta.transaction-api</artifactId> <scope>provided</scope> </dependency> wildfly-maven-plugin Add the wildfly-datasources-galleon-pack feature-pack and the postgresql-datasource layer to the wildfly-maven-plugin configuration. You should end up with the wildfly-maven-plugin configured like in the following: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>5.1.3.Final</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:36.0.1.Final</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:8.0.0.Final</location> </feature-pack> <feature-pack> <location>org.wildfly:wildfly-datasources-galleon-pack:10.0.0.Final</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>postgresql-datasource</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> Java Classes Add the following classes to the project: org.wildfly.examples.test_table.TestTable : package org.wildfly.examples.test_table; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import java.util.Objects; import static jakarta.persistence.GenerationType.IDENTITY; @Entity public class TestTable { @Id @GeneratedValue(strategy = IDENTITY) private Long id; private String field1; private String field2; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } public String getField2() { return field2; } public void setField2(String field2) { this.field2 = field2; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TestTable testTable = (TestTable) o; return Objects.equals(id, testTable.id) && Objects.equals(field1, testTable.field1) && Objects.equals(field2, testTable.field2); } @Override public int hashCode() { return Objects.hash(id, field1, field2); } } org.wildfly.examples.test_table.TestTableResource : package org.wildfly.examples.test_table; import jakarta.enterprise.context.RequestScoped; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import jakarta.transaction.Transactional; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.Response; import java.util.List; @RequestScoped @Path("/test-table") public class TestTableResource { @PersistenceContext(unitName = "primary") private EntityManager em; public void createOrUpdateRow(TestTable row) { if (!em.contains(row)) { row = em.merge(row); } em.persist(row); } public List<TestTable> getAllRows() { return em.createQuery("SELECT t FROM TestTable t", TestTable.class).getResultList(); } @Transactional @POST @Produces({"application/json"}) @Path("{field1}/{field2}") public Response insertIntoTestTable( @PathParam("field1") @DefaultValue("some data 1") String field1, @PathParam("field2") @DefaultValue("some data 2") String field2) throws Exception { TestTable testTable = null; try { testTable = new TestTable(); testTable.setField1(field1); testTable.setField2(field2); createOrUpdateRow(testTable); } catch (Exception ex) { throw new RuntimeException(ex); } return Response.ok(testTable).build(); } @GET @Produces({"application/json"}) public List<TestTable> getAllRowsFromTestTable() { try { List<TestTable> allRows = getAllRows(); return allRows; } catch (Exception ex) { throw new RuntimeException(ex); } } } persistence.xml Add the src/main/resources/META-INF/persistence.xml file to the project with the following content: src/main/resources/META-INF/persistence.xml <?xml version="1.0" encoding="UTF-8"?> <persistence version="3.0" xmlns="https://jakarta.ee/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd" > <persistence-unit name="primary"> <jta-data-source>java:jboss/datasources/PostgreSQLDS</jta-data-source> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> <property name="hibernate.hbm2ddl.auto" value="update"/> <property name="hibernate.show_sql" value="true"/> </properties> </persistence-unit> </persistence> Build the application $ mvn clean package ... [INFO] Copy deployment /home/tborgato/Documents/WildFly-Mini-Serie/getting-started/target/ROOT.war to /home/tborgato/Documents/WildFly-Mini-Serie/getting-started/target/server/standalone/deployments/ROOT.war [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 5.830 s [INFO] Finished at: 2024-05-07T16:18:22+02:00 [INFO] ------------------------------------------------------------------------ Docker Image Build the Docker Image Build the Docker Image with the following command: $ podman build -t my-jaxrs-app-db:latest . STEP 1/3: FROM quay.io/wildfly/wildfly-runtime:latest STEP 2/3: COPY --chown=jboss:root target/server $JBOSS_HOME -→ 4609f8ed0c7f STEP 3/3: RUN chmod -R ug+rwX $JBOSS_HOME COMMIT my-jaxrs-app:latest -→ db4677f5bf4f Successfully tagged localhost/my-jaxrs-app:latest db4677f5bf4f471f5624bd63a21fce3d91b7b3b93e985d3e86a8a4b0682d85cd Note You can use wildfly-maven-plugin to automate the image build Run the Docker Image Note that, when running the my-jaxrs-app-db:latest Docker Image, we specify some environment variables used by WildFly to connect to the PostgreSQL database: podman run --rm --network=demo-network -p 8080:8080 -p 9990:9990 \ -e POSTGRESQL_USER=postgres \ -e POSTGRESQL_PASSWORD=admin \ -e POSTGRESQL_HOST=my-postgres \ -e POSTGRESQL_PORT=5432 \ -e POSTGRESQL_DATABASE=postgres \ -e POSTGRESQL_JNDI=java:jboss/datasources/PostgreSQLDS \ --name=my-jaxrs-app-db \ my-jaxrs-app-db:latest Note We started the my-jaxrs-app-db container with the --network=demo-network option just like we did when we started the my-postgres container: the two containers now run in the same demo-network network and we can connect to the my-postgres container from the my-jaxrs-app-db container using the my-postgres DNS name; Check the application Hit the following URLs, using a utility like curl: Insert some Data into the Database: $ curl -X POST http://localhost:8080/hello/test-table/somedata1/somedata2 {"field1":"somedata1","field2":"somedata2","id":1} Query the database to show the inserted data: $ curl http://localhost:8080/hello/test-table [{"field1":"somedata1","field2":"somedata2","id":1}] Stop the Docker containers Stop the running container: podman stop my-jaxrs-app-db podman stop my-postgres What’s next? Connecting to a DB - PART 2: Kubernetes References Source code for this guide: https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-database wildfly-datasources-galleon-pack PostgreSQL datasource example Back to Guides < Back to Getting Started with WildFly micro-services on Kubernetes ### [{simple-microservice-database-part2}](/guides/get-started-microservices-on-kubernetes/simple-microservice-database-part2/) Connecting to a DB - PART 2: Kubernetes Table of Contents Prerequisites Database PostgreSQL Image Registry Quay.io Deploy to Kubernetes Check the application What’s next? References In this guide, you will learn HOW-TO run the Docker Image we built in Connecting to a DB - PART 1: Container Image on Kubernetes. Prerequisites To complete this guide, you need: Complete Connecting to a DB - PART 1: Container Image Database PostgreSQL We basically will repeat everything we did in WildFly Java Microservice - PART 2: Kubernetes but, before, we will deploy PostgreSQL on Kubernetes. PostgreSQL configmap Create the file named postgres-configmap.yaml with the following content: postgres-configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: postgres-secret labels: app: postgres data: POSTGRESQL_USER: postgres POSTGRESQL_PASSWORD: admin POSTGRESQL_HOST: postgres-service POSTGRESQL_PORT: "5432" POSTGRESQL_DATABASE: postgres POSTGRESQL_JNDI: java:jboss/datasources/PostgreSQLDS apply the ConfigMap configuration to Kubernetes: kubectl apply -f postgres-configmap.yaml PostgreSQL deployment Create the file named postgres-deployment.yaml with the following content: postgres-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: postgres spec: replicas: 1 selector: matchLabels: app: postgres template: metadata: labels: app: postgres spec: containers: - name: postgres image: 'docker.io/library/postgres' imagePullPolicy: IfNotPresent ports: - containerPort: 5432 env: - name: POSTGRES_USER valueFrom: configMapKeyRef: name: postgres-secret key: POSTGRESQL_USER - name: POSTGRES_PASSWORD valueFrom: configMapKeyRef: name: postgres-secret key: POSTGRESQL_PASSWORD - name: POSTGRES_DB valueFrom: configMapKeyRef: name: postgres-secret key: POSTGRESQL_DATABASE apply the Deployment configuration to Kubernetes: kubectl apply -f postgres-deployment.yaml PostgreSQL service Create a file named postgres-service.yaml with the following content: postgres-service.yaml apiVersion: v1 kind: Service metadata: name: postgres-service labels: app: postgres spec: ports: - protocol: TCP port: 5432 targetPort: 5432 selector: app: postgres apply the Service configuration to Kubernetes: kubectl apply -f postgres-service.yaml Note if you are using minikube, and you want to test if PostgreSQL is working, run kubectl port-forward svc/postgres-service 5432:5432 and then connect via JDBC using URL jdbc:postgresql://localhost:5432/postgres Image Registry To make the my-jaxrs-app-db:latest Docker Image available to Kubernetes, you need to push it to some Image Registry that is accessible by the Kubernetes cluster you want to use. Quay.io There are many Image Registries you can use: in this guide, we will push the my-jaxrs-app-db:latest Docker Image, to the quay.io Image Registry. Create a public repository named my-jaxrs-app-db on quay.io (e.g. https://quay.io/repository/tborgato/my-jaxrs-app-db). Note replace tborgato with the name of your account in all the commands that will follow Tag the Docker image: podman tag my-jaxrs-app-db quay.io/tborgato/my-jaxrs-app-db Push the my-jaxrs-app-db Docker Image to it: podman push quay.io/tborgato/my-jaxrs-app-db At this point, the my-jaxrs-app-db:latest Docker Image should be publicly available and free to be consumed by any Kubernetes Cluster; you can verify this by running: podman pull quay.io/tborgato/my-jaxrs-app-db Deploy to Kubernetes To deploy our my-jaxrs-app-db Docker Image on minikube, create a file named deployment-my-jaxrs-app-db.yaml (see kubernetes deployment) in the same directory as the Dockerfile and the pom.xml file, with the following content: deployment-my-jaxrs-app-db.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-jaxrs-app-db-deployment labels: app: my-jaxrs-app-db spec: replicas: 1 selector: matchLabels: app: my-jaxrs-app-db template: metadata: labels: app: my-jaxrs-app-db spec: containers: - name: my-jaxrs-app-db image: quay.io/tborgato/my-jaxrs-app-db ports: - containerPort: 8080 - containerPort: 9990 livenessProbe: httpGet: path: /health/live port: 9990 readinessProbe: httpGet: path: /health/ready port: 9990 startupProbe: httpGet: path: /health/started port: 9990 env: - name: POSTGRESQL_USER valueFrom: configMapKeyRef: name: postgres-secret key: POSTGRESQL_USER - name: POSTGRESQL_PASSWORD valueFrom: configMapKeyRef: name: postgres-secret key: POSTGRESQL_PASSWORD - name: POSTGRESQL_HOST valueFrom: configMapKeyRef: name: postgres-secret key: POSTGRESQL_HOST - name: POSTGRESQL_PORT valueFrom: configMapKeyRef: name: postgres-secret key: POSTGRESQL_PORT - name: POSTGRESQL_DATABASE valueFrom: configMapKeyRef: name: postgres-secret key: POSTGRESQL_DATABASE - name: POSTGRESQL_JNDI valueFrom: configMapKeyRef: name: postgres-secret key: POSTGRESQL_JNDI apply the Deployment configuration to Kubernetes: kubectl apply -f deployment-my-jaxrs-app-db.yaml We used minikube as Kubernetes Cluster, hence we expose the deployment as NodePort: kubectl expose deployment.apps/my-jaxrs-app-db-deployment --type=NodePort --port=8080 Check the application Find out on what IP address/port, minikube is exposing your service: $ minikube service my-jaxrs-app-db-deployment --url http://192.168.39.143:30433 Just like we did before, hit the following URLs, using a utility like curl: Insert some Data into the Database: $ curl -X POST http://192.168.39.143:30433/hello/test-table/somedata1/somedata2 {"field1":"somedata1","field2":"somedata2","id":1} Query the database to show the inserted data: $ curl http://192.168.39.143:30433/hello/test-table [{"field1":"somedata1","field2":"somedata2","id":1}] What’s next? Using Infinispan remote cache - PART 1: Container Image References Source code for this guide: https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-database Back to Guides < Back to Getting Started with WildFly micro-services on Kubernetes ### [{simple-microservice-infinispan-part1}](/guides/get-started-microservices-on-kubernetes/simple-microservice-infinispan-part1/) Using Infinispan remote cache - PART 1: Container Image Table of Contents Prerequisites Infinispan Server Start Infinispan Maven Project web.xml Infinispan Connection pom.xml Java Classes Build the application Docker Image Build the Docker Image Run the Docker Image Check the application Stop the Docker containers What’s next? References In this guide, we will extend the example created in WildFly Java Microservice - PART 1: Container Image and use a remote Infinispan Server to cache HTTP Session data. Prerequisites To complete this guide, you need: Complete WildFly Java Microservice - PART 1: Container Image Infinispan Server Infinispan is the most common solution used with WildFly when you want to cache some data outside WildFly. Using Infinispan, for example, you can avoid users losing their session in case WildFly is shut down and re-started. In this guide, we will use the containerized version of Infinispan: see Infinispan Server. Start Infinispan podman network create demo-network podman run --rm --network=demo-network --name=my-infinispan \ -p 11222:11222 \ -e USER="admin" \ -e PASS="123pippobaudo" \ quay.io/infinispan/server:latest Note NOTE: We created the demo-network network and started the my-infinispan container with the --network=demo-network option: later in this guide, this will allow us to connect to the my-infinispan container from the my-jaxrs-app-infinispan container. Note you can check the container is running by opening http://localhost:11222/console/ in your browser and logging in as admin / 123pippobaudo Maven Project web.xml Add the <distributable/> tag to the src/main/webapp/WEB-INF/web.xml file (if the src/main/webapp/WEB-INF/web.xml doesn’t exist then create it): web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" version="6.0"> <distributable/> </web-app> Infinispan Connection Add a file named infinispan.cli to the root of the maven project: infinispan.cli /subsystem=jgroups/channel=ee:write-attribute(name=stack,value=tcp) /subsystem=transactions:write-attribute(name=node-identifier,value=${transactions.node-identifier:wildfly1}) # add DNS_PING protocol to TCP stack /subsystem=jgroups/stack=tcp/protocol=dns.DNS_PING:add(add-index=1, properties={dns_query="_ping._tcp.jgroups-dns-ping.myproject.svc.cluster.local"}) # connection to the remote infinispan server /socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=remote-infinispan-server:add(host=${infinispan.server.host}, port=${infinispan.server.port:11222}) batch # remote-cache-container /subsystem=infinispan/remote-cache-container=web-sessions:add(default-remote-cluster=infinispan-server-cluster, statistics-enabled=true, properties={infinispan.client.hotrod.auth_username=${infinispan.server.user:admin}, infinispan.client.hotrod.auth_password=${infinispan.server.password:123pippobaudo}, infinispan.client.hotrod.sasl_mechanism=DIGEST-MD5}) /subsystem=infinispan/remote-cache-container=web-sessions/remote-cluster=infinispan-server-cluster:add(socket-bindings=[remote-infinispan-server]) # hotrod /subsystem=infinispan/remote-cache-container=web-sessions:write-attribute(name=modules,value=[org.wildfly.clustering.web.hotrod]) # PROTOSTREAM /subsystem=infinispan/remote-cache-container=web-sessions:write-attribute(name=marshaller,value=PROTOSTREAM) # set as default for session management /subsystem=distributable-web/hotrod-session-management=remote-infinispan-session-management:add(remote-cache-container=web-sessions,granularity=SESSION) /subsystem=distributable-web/hotrod-session-management=remote-infinispan-session-management/affinity=local:add /subsystem=distributable-web:write-attribute(name=default-session-management,value=remote-infinispan-session-management) run-batch pom.xml dependencies Add the following dependency to dependencies section: <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <scope>provided</scope> </dependency> wildfly-maven-plugin Add the following to the wildfly-maven-plugin configuration: packaging-scripts pointing to the infinispan.cli file web-clustering layer You should end up with the wildfly-maven-plugin configured like in the following: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>5.1.3.Final</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:36.0.1.Final</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:8.0.0.Final</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>web-clustering</layer> </layers> <packaging-scripts> <packaging-script> <scripts> <script>infinispan.cli</script> </scripts> </packaging-script> </packaging-scripts> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> Java Classes Modify the GettingStartedService class: GettingStartedService.java package org.wildfly.examples; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.servlet.http.HttpServletRequest; @ApplicationScoped public class GettingStartedService { @Inject private HttpServletRequest httpRequest; public String hello(String name) { String previousName = (String) httpRequest.getSession().getAttribute("NAME_PARAMETER"); httpRequest.getSession().setAttribute("NAME_PARAMETER", name); return String.format("Hello '%s'." + (previousName == null ? "" : "(last time you were " + previousName + ")"), name); } } Build the application $ mvn clean package ... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 7.417 s [INFO] Finished at: 2024-05-30T16:32:46+02:00 [INFO] ------------------------------------------------------------------------ Docker Image Build the Docker Image Build the Docker Image with the following command: $ podman build -t my-jaxrs-app-infinispan:latest . STEP 1/3: FROM quay.io/wildfly/wildfly-runtime:latest STEP 2/3: COPY --chown=jboss:root target/server $JBOSS_HOME -→ 5afd485c6552 STEP 3/3: RUN chmod -R ug+rwX $JBOSS_HOME COMMIT my-jaxrs-app-infinispan:latest -→ 625a63506dab Successfully tagged localhost/my-jaxrs-app-infinispan:latest 625a63506dab171c4750f6be89e45c236591d40524b239307e32c716add01457 Note You can use wildfly-maven-plugin to automate the image build Run the Docker Image Note that, when running the my-jaxrs-app-infinispan:latest Docker Image, we specify some environment variables used by WildFly to connect to the PostgreSQL database: podman run --rm --network=demo-network -p 8080:8080 -p 9990:9990 \ -e INFINISPAN_SERVER_HOST=my-infinispan \ -e INFINISPAN_SERVER_PORT=11222 \ -e INFINISPAN_SERVER_USER=admin \ -e INFINISPAN_SERVER_PASSWORD=123pippobaudo \ --name=my-jaxrs-app-infinispan \ my-jaxrs-app-infinispan:latest Note NOTE: We started the my-jaxrs-app-infinispan container with the --network=demo-network option just like we did when we started the my-infinispan container: the two containers now run in the same demo-network network and we can connect to the my-infinispan container from the my-jaxrs-app-infinispan container using the my-infinispan DNS name Check the application Open http://localhost:8080/ in your Browser, enter some name in the Name field (e.g. "pippo") and press `Say Hello`". Stop the application (press CTRL+C from the terminal where you started it). Start the application once again. Type a different name in the Name field and press Say Hello again: the page should display something like "last time you were pippo" and that means that the previous name was stored in the Infinispan Server. Stop the Docker containers Stop the running container: podman stop my-jaxrs-app-infinispan podman stop my-infinispan What’s next? Using Infinispan remote cache - PART 2: Kubernetes References Source code for this guide: https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-infinispan Infinispan Distributable Web Applications Check Environment Variables When Resolving Expressions Back to Guides < Back to Getting Started with WildFly micro-services on Kubernetes ### [{simple-microservice-infinispan-part2}](/guides/get-started-microservices-on-kubernetes/simple-microservice-infinispan-part2/) Using Infinispan remote cache - PART 2: Kubernetes Table of Contents Prerequisites Infinispan Infinispan configmap Infinispan deployment Infinispan service Image Registry Quay.io Deploy to Kubernetes Check the application What’s next? References In this guide, you will learn HOW-TO run the Docker Image we built in Using Infinispan remote cache - PART 1: Container Image on Kubernetes. Prerequisites To complete this guide, you need: Complete Using Infinispan remote cache - PART 1: Container Image Infinispan We basically will repeat everything we did in WildFly Java Microservice - PART 2: Kubernetes but, before, we will deploy Infinispan on Kubernetes. Infinispan configmap Create a file named infinispan-configmap.yaml with the following content: infinispan-configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: infinispan-secret labels: app: infinispan data: USER: admin PASS: 123pippobaudo apply the ConfigMap configuration to Kubernetes: kubectl apply -f infinispan-configmap.yaml Infinispan deployment Create a file named infinispan-deployment.yaml with the following content: infinispan-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: infinispan spec: replicas: 1 selector: matchLabels: app: infinispan template: metadata: labels: app: infinispan spec: containers: - name: infinispan image: 'quay.io/infinispan/server:latest' imagePullPolicy: IfNotPresent ports: - containerPort: 5432 env: - name: USER valueFrom: configMapKeyRef: name: infinispan-secret key: USER - name: PASS valueFrom: configMapKeyRef: name: infinispan-secret key: PASS - name: JAVA_OPTIONS value: '-Dinfinispan.cluster.stack=kubernetes -Djgroups.dns.query="infinispan-dns-ping.myproject.svc.cluster.local"' apply the Deployment configuration to Kubernetes: kubectl apply -f infinispan-deployment.yaml Infinispan service Create a file named infinispan-service.yaml with the following content: infinispan-service.yaml apiVersion: v1 kind: Service metadata: name: infinispan-service labels: app: infinispan spec: ports: - protocol: TCP port: 11222 targetPort: 11222 selector: app: infinispan apply the Service configuration to Kubernetes: kubectl apply -f infinispan-service.yaml Note if you are using minikube, and you want to test if Infinispan Server on Kubernetes is working, run kubectl port-forward svc/infinispan-service 11222:11222, then open http://0.0.0.0:11222/console/ in your browser and log in as admin / 123pippobaudo Image Registry To make the my-jaxrs-app-infinispan:latest Docker Image available to Kubernetes, you need to push it to some Image Registry that is accessible by the Kubernetes cluster you want to use. Quay.io There are many options to achieve this; in this guide, we will push the my-jaxrs-app-infinispan:latest Docker Image, to the quay.io Image Registry. Create a public repository named my-jaxrs-app-infinispan on quay.io (e.g. https://quay.io/repository/tborgato/my-jaxrs-app-infinispan). Note replace tborgato with the name of your account in all the commands that will follow Tag the Docker image: podman tag my-jaxrs-app-infinispan quay.io/tborgato/my-jaxrs-app-infinispan Push the my-jaxrs-app-infinispan Docker Image to it: podman push quay.io/tborgato/my-jaxrs-app-infinispan At this point, the my-jaxrs-app-infinispan:latest Docker Image should be publicly available and free to be consumed by any Kubernetes Cluster; you can verify this by running: podman pull quay.io/tborgato/my-jaxrs-app-infinispan Deploy to Kubernetes To deploy our my-jaxrs-app-infinispan Docker Image on minikube, create a file named deployment-my-jaxrs-app-infinispan.yaml (see kubernetes deployment) in the same directory as the Dockerfile and the pom.xml file, with the following content: deployment-my-jaxrs-app-infinispan.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-jaxrs-app-infinispan-deployment labels: app: my-jaxrs-app-infinispan spec: replicas: 1 selector: matchLabels: app: my-jaxrs-app-infinispan template: metadata: labels: app: my-jaxrs-app-infinispan spec: containers: - name: my-jaxrs-app-infinispan image: quay.io/tborgato/my-jaxrs-app-infinispan ports: - containerPort: 8080 - containerPort: 9990 livenessProbe: httpGet: path: /health/live port: 9990 readinessProbe: httpGet: path: /health/ready port: 9990 startupProbe: httpGet: path: /health/started port: 9990 env: - name: INFINISPAN_SERVER_HOST value: infinispan-service - name: INFINISPAN_SERVER_PORT value: '11222' - name: INFINISPAN_SERVER_USER valueFrom: configMapKeyRef: name: infinispan-secret key: USER - name: INFINISPAN_SERVER_PASSWORD valueFrom: configMapKeyRef: name: infinispan-secret key: PASS apply the Deployment configuration to Kubernetes: kubectl apply -f deployment-my-jaxrs-app-infinispan.yaml We used minikube as Kubernetes Cluster, hence we expose the deployment as NodePort: kubectl expose deployment.apps/my-jaxrs-app-infinispan-deployment --type=NodePort --port=8080 Check the application Find out on what IP address/port, minikube is exposing your service: $ minikube service my-jaxrs-app-infinispan-deployment --url http://192.168.39.143:31076 Open http://192.168.39.143:31076/ in your Browser, enter some name in the Name field (e.g. "pippo") and press `Say Hello`". Stop the application: kubectl scale deploy my-jaxrs-app-infinispan-deployment --replicas=0 Start the application once again: kubectl scale deploy my-jaxrs-app-infinispan-deployment --replicas=1 Type a different name in the Name field and press Say Hello again: the page should display something like "last time you were pippo" and that means that the previous name was stored in the Infinispan Server. What’s next? Using a Message Broker - PART 1: Container Image References Source code for this guide: https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-infinispan Back to Guides < Back to Getting Started with WildFly micro-services on Kubernetes ### [{simple-microservice-jms-part1}](/guides/get-started-microservices-on-kubernetes/simple-microservice-jms-part1/) Using a Message Broker - PART 1: Container Image Table of Contents Prerequisites External Message Broker Apache Artemis Maven Project pom.xml Java Classes Build the application Docker Image Build the Docker Image Run the Docker Image Check the application What’s next? References In this guide, we will extend the example created in WildFly Java Microservice - PART 1: Container Image and add an external Message Broker connectivity. Prerequisites To complete this guide, you need: Complete WildFly Java Microservice - PART 1: Container Image External Message Broker Apache Artemis We will use Apache Artemis in this guide in its containerized version: see Artemis Official Image. Start Apache Artemis: podman network create demo-network podman run --rm --name my-artemis \ --network=demo-network \ -p 8161:8161 \ -p 61616:61616\ -e AMQ_USER=admin \ -e AMQ_PASSWORD=admin \ -e AMQ_DATA_DIR=//home/jboss/data \ quay.io/artemiscloud/activemq-artemis-broker-kubernetes:latest Note we started the container with the --rm flag: this way it is disposed of automatically when we stop it Note We started the my-artemis container with the --network=bridge option: later in this guide, this will allow us to connect to the my-artemis container from the my-jms-app container; Maven Project pom.xml dependencies Add the following dependencies to the pom-xml file dependencies section: <dependency> <groupId>jakarta.ejb</groupId> <artifactId>jakarta.ejb-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.enterprise</groupId> <artifactId>jakarta.enterprise.cdi-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.jms</groupId> <artifactId>jakarta.jms-api</artifactId> <scope>provided</scope> </dependency> wildfly-maven-plugin We need to add some features that are necessary when to connect to the broker and to support a Message Driven Bean. We can add these features by adding the remote-activemq layer to our application; add the following to the the wildfly-maven-plugin configuration in the pom.xml file: <layers> …​ <layer>ejb</layer> <layer>remote-activemq</layer> …​ </layers> You should end up with the wildfly-maven-plugin configured like in the following: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>5.1.3.Final</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:36.0.1.Final</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:8.0.0.Final</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>ejb</layer> <layer>remote-activemq</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> Java Classes Add the following classes to the project: org.wildfly.examples.mdb.GettingStartedQueueMDB : package org.wildfly.examples.mdb; import jakarta.ejb.ActivationConfigProperty; import jakarta.ejb.MessageDriven; import jakarta.jms.JMSException; import jakarta.jms.Message; import jakarta.jms.MessageListener; import jakarta.jms.TextMessage; import java.util.logging.Logger; @MessageDriven( name = "GettingStartedQueueMDB", activationConfig = { @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "queue/gettingStartedQueue"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "jakarta.jms.Queue"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")} ) public class GettingStartedQueueMDB implements MessageListener { private static final Logger LOGGER = Logger.getLogger(GettingStartedQueueMDB.class.toString()); public void onMessage(Message rcvMessage) { TextMessage msg = null; try { if (rcvMessage instanceof TextMessage) { msg = (TextMessage) rcvMessage; LOGGER.info("Received Message from queue: " + msg.getText()); } else { LOGGER.warning("Message of wrong type: " + rcvMessage.getClass().getName()); } } catch (JMSException e) { throw new RuntimeException(e); } } } org.wildfly.examples.GettingStartedQueueEndpoint : package org.wildfly.examples; import jakarta.annotation.Resource; import jakarta.inject.Inject; import jakarta.jms.JMSContext; import jakarta.jms.JMSDestinationDefinition; import jakarta.jms.JMSDestinationDefinitions; import jakarta.jms.JMSException; import jakarta.jms.Queue; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; @JMSDestinationDefinitions( value = { @JMSDestinationDefinition( name = "java:/queue/gettingStartedQueue", interfaceName = "jakarta.jms.Queue", destinationName = "getting-started-queue", properties = {"enable-amq1-prefix=false"} ) } ) @Path("/message") public class GettingStartedQueueEndpoint { @Resource(lookup="java:/queue/gettingStartedQueue") private Queue queue; @Inject private JMSContext context; @GET @Path("/send") @Produces(MediaType.TEXT_PLAIN) public Response sendMessage(final @QueryParam("content") String content) throws JMSException { String response = "Sent " + content + " to " + queue.getQueueName(); context.createProducer().send(queue, content); return Response.ok(response).build(); } } Build the application $ mvn clean package ... [INFO] Copy deployment /home/ehugonne/dev/wildfly/guides/get-started-microservices-on-kubernetes/simple-microservice-jms/target/ROOT.war to /home/ehugonne/dev/wildfly/guides/get-started-microservices-on-kubernetes/simple-microservice-jms/target/server/standalone/deployments/ROOT.war [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 6.848 s [INFO] Finished at: 2024-07-18T10:06:17+02:00 [INFO] ------------------------------------------------------------------------ Docker Image Build the Docker Image Build the Docker Image with the following command: $ podman build -t my-jms-app:latest . STEP 1/3: FROM quay.io/wildfly/wildfly-runtime:latest STEP 2/3: COPY --chown=jboss:root target/server $JBOSS_HOME -→ 4609f8ed0c7f STEP 3/3: RUN chmod -R ug+rwX $JBOSS_HOME COMMIT my-jms-app:latest -→ db4677f5bf4f Successfully tagged localhost/my-jms-app:latest db4677f5bf4f471f5624bd63a21fce3d91b7b3b93e985d3e86a8a4b0682d85cd Note You can use wildfly-maven-plugin to automate the image build Run the Docker Image Note that, when running the my-jms-app:latest Docker Image: podman run --rm --network=demo-network -p 8080:8080 -p 9990:9990 \ --name=my-jms-app \ -e JBOSS_MESSAGING_CONNECTOR_HOST=my-artemis \ my-jms-app:latest Note We started the my-jms-app container with the --network=demo-network option just like we did when we started the my-artemis container: the two containers now run in the same demo-network network and we can connect to my-artemis container from the my-jms-app container using the my-artemis name. Check the application Hit the following URLs, using a utility like curl: Send and consume messages using a queue: $ curl -X GET http://localhost:8080/hello/message/send?content=Hello%20World Sent Hello World to getting-started-queue What’s next? Using a Message Broker - PART 2: Kubernetes References Source code for this guide: https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-jms ActiveMQ Artemis - Docker Back to Guides < Back to Getting Started with WildFly micro-services on Kubernetes ### [{simple-microservice-jms-part2}](/guides/get-started-microservices-on-kubernetes/simple-microservice-jms-part2/) Using a Message Broker - PART 2: Kubernetes Table of Contents Prerequisites Apache Artemis Apache Artemis deployment Apache Artemis service Image Registry Quay.io Deploy to Kubernetes Check the application References In this guide, you will learn HOW-TO run the Docker Image we built in Using a Message Broker - PART 1: Container Image on Kubernetes. Prerequisites To complete this guide, you need: Complete Using a Message Broker - PART 1: Container Image Apache Artemis Apache Artemis deployment Create a file named artemis-deployment.yaml with the following content: artemis-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: artemis spec: replicas: 1 selector: matchLabels: app: artemis template: metadata: labels: app: artemis spec: containers: - name: artemis image: 'quay.io/artemiscloud/activemq-artemis-broker-kubernetes:latest' imagePullPolicy: IfNotPresent ports: - containerPort: 61616 - containerPort: 8161 env: - name: AMQ_USER value: admin - name: AMQ_PASSWORD value: admin - name: AMQ_DATA_DIR value: //home/jboss/data apply the Deployment configuration to Kubernetes: kubectl apply -f artemis-deployment.yaml Apache Artemis service Create a file named artemis-service.yaml with the following content: artemis-service.yaml apiVersion: v1 kind: Service metadata: name: artemis-service labels: app: artemis spec: ports: - protocol: TCP port: 61616 targetPort: 61616 name: artemis-port - protocol: TCP port: 8161 targetPort: 8161 name: artemis-console-port selector: app: artemis apply the Service configuration to Kubernetes: kubectl apply -f artemis-service.yaml Image Registry To make the my-jms-app:latest Docker Image available to Kubernetes, you need to push it to some Image Registry that is accessible by the Kubernetes cluster you want to use. Quay.io There are many options to achieve this; in this guide, we will push the my-jms-app:latest Docker Image, to the quay.io Image Registry. Create a public repository named my-jms-app on quay.io (e.g. https://quay.io/repository/tborgato/my-jms-app). Note replace tborgato with the name of your account in all the commands that will follow Tag the Docker image: podman tag my-jms-app quay.io/tborgato/my-jms-app Push the my-jms-app Docker Image to it: podman push quay.io/tborgato/my-jms-app At this point, the my-jms-app:latest Docker Image should be publicly available and free to be consumed by any Kubernetes Cluster; you can verify this by running: podman pull quay.io/tborgato/my-jms-app Deploy to Kubernetes To deploy our my-jms-app Docker Image on minikube, create a file named deployment-my-jms-app.yaml (see kubernetes deployment) in the same directory as the Dockerfile and the pom.xml file, with the following content: deployment-my-jms-app.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-jms-app-deployment labels: app: my-jms-app spec: replicas: 1 selector: matchLabels: app: my-jms-app template: metadata: labels: app: my-jms-app spec: containers: - name: my-jms-app image: quay.io/tborgato/my-jms-app ports: - containerPort: 8080 - containerPort: 9990 livenessProbe: httpGet: path: /health/live port: 9990 readinessProbe: httpGet: path: /health/ready port: 9990 startupProbe: httpGet: path: /health/started port: 9990 env: - name: JBOSS_MESSAGING_CONNECTOR_HOST value: artemis-service - name: JBOSS_MESSAGING_CONNECTOR_PORT value: '61616' apply the Deployment configuration to Kubernetes: kubectl apply -f deployment-my-jms-app.yaml We used minikube as Kubernetes Cluster, hence we expose the deployment as NodePort: kubectl expose deployment.apps/my-jms-app-deployment --type=NodePort --port=8080 Check the application Find out on what IP address/port, minikube is exposing your service: $ minikube service my-jms-app-deployment --url http://192.168.39.143:31858 Send and consume messages using a queue (replace "http://192.168.39.143:31858" with the output of the command above!): $ curl -X GET http://192.168.39.143:31858/hello/message/send?content=Hello%20World Sent Hello World to getting-started-queue References Source code for this guide: https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-jms Back to Guides < Back to Getting Started with WildFly micro-services on Kubernetes ### [{simple-microservice-llm-part1}](/guides/get-started-microservices-on-kubernetes/simple-microservice-llm-part1/) Invoke an LLM using LangChain4J - PART 1: Container Image Table of Contents Prerequisites LLM Ollama + smollm2 Maven Project pom.xml Java Classes Build the application Docker Image Build the Docker Image Run the Docker Image Check the application Stop the Docker containers What’s next? References In this guide, we will extend the example created in WildFly Java Microservice - PART 1: Container Image and consume an external LLM APIs through LangChain4J. Prerequisites To complete this guide, you need: Complete WildFly Java Microservice - PART 1: Container Image LLM You can use any LLM supported by LangChain4J; in this guide we will use model smollm2 and run it using the Ollama Docker Image; Ollama + smollm2 Start Ollama: podman network create demo-network podman volume create ollama podman run --rm --network=demo-network -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama Note we started the container with the --rm flag: this way it is disposed of automatically when we stop it Note We created the demo-network network and started the ollama container with the --network=demo-network option: later in this guide, this will allow us to connect to the ollama container from the my-jaxrs-app-llm container Install the smollm2 LLM inside the ollama container: podman exec -it ollama ollama pull smollm2 Test that your LLM is working by invoking its APIs like in the following: $ curl http://localhost:11434/api/generate -d '{ "model": "smollm2", "prompt":"Hi! My name is Tommaso"}' {"model":"llama3.1:8b","created_at":"2025-03-19T16:26:19.388567244Z","response":"C","done":false} {"model":"llama3.1:8b","created_at":"2025-03-19T16:26:19.518556766Z","response":"iao","done":false} {"model":"llama3.1:8b","created_at":"2025-03-19T16:26:19.646976123Z","response":" Tom","done":false} {"model":"llama3.1:8b","created_at":"2025-03-19T16:26:19.77417658Z","response":"mas","done":false} {"model":"llama3.1:8b","created_at":"2025-03-19T16:26:19.901190847Z","response":"o","done":false} {"model":"llama3.1:8b","created_at":"2025-03-19T16:26:20.033013914Z","response":"!","done":false} …​ Maven Project You will extend the sample application you created in WildFly Java Microservice - PART 1: Container Image by adding the wildfly-ai-feature-pack. The wildfly-ai-feature-pack will: add the necessary LangChain4J modules to the server (= the necessary dependencies to work with the model of choice) add the configuration related to the model of choice; e.g. when using the <layer>ollama-chat-model</layer>, the feature-pack would configure the server to connect to an external Ollama service pom.xml dependencies Add the following dependencies to the pom-xml file dependencies section: <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j</artifactId> <version>1.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-core</artifactId> <version>1.0.1</version> <scope>provided</scope> </dependency> Note we are not adding LLM specific LangChain4J dependencies because they will be added automatically to the server by the wildfly-ai-feature-pack based on the specific AI layer we are using (e.g. the ollama-chat-model layer, will add the dev.langchain4j:langchain4j-ollama module to the server) wildfly-maven-plugin Add the wildfly-ai-feature-pack feature-pack and the ollama-chat-model layer to the wildfly-maven-plugin configuration. You should end up with the wildfly-maven-plugin configured like in the following: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>5.1.3.Final</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:36.0.1.Final</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:8.0.0.Final</location> </feature-pack> <feature-pack> <location>org.wildfly:wildfly-ai-feature-pack:0.6.0</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>ollama-chat-model</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> Note The wildfly-maven-plugin configuration can be simplified by using wildfly-glow; wildfly-glow inspects your deployment and figures out what feature-pack and layers to use automatically! just replace the whole configuration section with the following: <configuration> <discoverProvisioningInfo> <context>cloud</context> <spaces> <space>incubating</space> </spaces> </discoverProvisioningInfo> </configuration> Java Classes Replace the content of the org.wildfly.examples.GettingStartedEndpoint class with the following: org.wildfly.examples.GettingStartedEndpoint : package org.wildfly.examples; import dev.langchain4j.data.message.AiMessage; import dev.langchain4j.data.message.UserMessage; import dev.langchain4j.memory.ChatMemory; import dev.langchain4j.memory.chat.MessageWindowChatMemory; import dev.langchain4j.model.chat.ChatLanguageModel; import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; import jakarta.inject.Named; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; @Path("/") @RequestScoped public class GettingStartedEndpoint { @Inject @Named(value = "ollama") ChatLanguageModel model; @GET @Path("/{name}") @Produces(MediaType.TEXT_PLAIN) public Response sayHello(final @PathParam("name") String name) { ChatMemory memory = MessageWindowChatMemory.withMaxMessages(5); UserMessage message1 = UserMessage.from("Hi! my name is " + name); memory.add(message1); AiMessage response1 = model.chat(memory.messages()).aiMessage(); memory.add(response1); return Response.ok(response1).build(); } } Delete class org.wildfly.examples.GettingStartedService which isn’t used anymore at this point, since the LLM is now responsible for greeting us! Build the application $ mvn clean package ... [INFO] Copy deployment /home/tborgato/projects/guides/get-started-microservices-on-kubernetes/simple-microservice-llm/target/ROOT.war to /home/tborgato/projects/guides/get-started-microservices-on-kubernetes/simple-microservice-llm/target/server/standalone/deployments/ROOT.war [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 6.694 s [INFO] Finished at: 2025-03-19T14:39:09+01:00 [INFO] ------------------------------------------------------------------------ Docker Image Build the Docker Image Build the Docker Image with the following command: $ podman build -t my-jaxrs-app-llm:latest . STEP 1/3: FROM quay.io/wildfly/wildfly-runtime:latest STEP 2/3: COPY --chown=jboss:root target/server $JBOSS_HOME -→ 026526b27879 STEP 3/3: RUN chmod -R ug+rwX $JBOSS_HOME COMMIT my-jaxrs-app-llm:latest -→ 1cae487d4086 Successfully tagged localhost/my-jaxrs-app-llm:latest 1cae487d408603eedebdc5f7d116ce70a4bfa5c1d44d8eeca890645973039899 Note You can use wildfly-maven-plugin to automate the image build Run the Docker Image Note that, when running the my-jaxrs-app-llm:latest Docker Image, we specify some environment variables used by WildFly to connect to the Ollama service: podman run --rm --network=demo-network -p 8080:8080 -p 9990:9990 \ -e OLLAMA_CHAT_URL=http://ollama:11434 \ -e OLLAMA_CHAT_LOG_REQUEST=true \ -e OLLAMA_CHAT_LOG_RESPONSE=true \ -e OLLAMA_CHAT_TEMPERATURE=0.9 \ -e OLLAMA_CHAT_MODEL_NAME=smollm2 \ --name=my-jaxrs-app-llm \ my-jaxrs-app-llm:latest Note We started the my-jaxrs-app-llm container with the --network=demo-network option just like we did when we started the ollama container: the two containers now run in the same demo-network network and we can connect to the ollama container from the my-jaxrs-app-llm container using the ollama DNS name; Check the application Put the http://localhost:8080/api/tom URL in your browser and you should receive a response like: AiMessage { text = "Nice to meet you, Tom! I'm happy to chat with you. What's on your mind today?" toolExecutionRequests = [] } now point your browser to http://localhost:8080/api/get-previous-name and you should receive a response like: AiMessage { text = "I already knew that, Tom! You told me earlier, remember? Your name is... (drumroll) ...Tom!" toolExecutionRequests = [] } which proves that the chat memory actually works and the LLM is able to tell your name from the previous conversation; Stop the Docker containers Stop the running container: podman stop my-jaxrs-app-llm podman stop ollama What’s next? Invoke an LLM using LangChain4J - PART 2: Kubernetes References Source code for this guide: simple-microservice-llm wildfly-ai-feature-pack LangChain4J Playing with Generative AI with WildFly Back to Guides < Back to Getting Started with WildFly micro-services on Kubernetes ### [{simple-microservice-llm-part2}](/guides/get-started-microservices-on-kubernetes/simple-microservice-llm-part2/) Invoke an LLM using LangChain4J - PART 2: Kubernetes Table of Contents Prerequisites LLM Ollama + smollm2 Image Registry Quay.io Deploy to Kubernetes Check the application What’s next? References In this guide, you will learn HOW-TO run the Docker Image we built in Invoke an LLM using LangChain4J - PART 1: Container Image on Kubernetes. Prerequisites To complete this guide, you need: Complete Invoke an LLM using LangChain4J - PART 1: Container Image LLM We basically will repeat everything we did in WildFly Java Microservice - PART 2: Kubernetes with a few changes but, before that, we will deploy smollm2 on Kubernetes using the Ollama container. You can choose any LLM you like: we chose smollm2 because it’s small and there are fewer chances minikube complains about its size (more on this later on); Ollama + smollm2 Ollama deployment Create a file named ollama-deployment.yaml with the following content: ollama-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: ollama spec: selector: matchLabels: app: ollama template: metadata: labels: app: ollama spec: containers: - name: ollama image: ollama/ollama:latest ports: - name: http containerPort: 11434 protocol: TCP apply the Deployment configuration to Kubernetes: kubectl apply -f ollama-deployment.yaml Ollama service Create a file named ollama-service.yaml with the following content: ollama-service.yaml apiVersion: v1 kind: Service metadata: name: ollama-service labels: app: ollama spec: ports: - protocol: TCP port: 11434 targetPort: 11434 selector: app: ollama apply the Service configuration to Kubernetes: kubectl apply -f ollama-service.yaml smollm2 Now find the name of your running Ollama POD: $ kubectl get pods NAME READY STATUS RESTARTS AGE ollama-777d6c546-hmsps 1/1 Running 0 39s and use it to get a shell to the running container and, once connected, pull smollm2: $ kubectl exec --stdin --tty ollama-777d6c546-hmsps — /bin/bash root@ollama-777d6c546-hmsps:/# ollama pull smollm2 pulling manifest pulling 4d2396b16114…​ 100% ▕██████████████████████████████████████████████████████████████████████████████████████████████████████▏ 1.8 GB pulling fbacade46b4d…​ 100% ▕██████████████████████████████████████████████████████████████████████████████████████████████████████▏ 68 B pulling dfebd0343bdd…​ 100% ▕██████████████████████████████████████████████████████████████████████████████████████████████████████▏ 1.8 KB pulling 58d1e17ffe51…​ 100% ▕██████████████████████████████████████████████████████████████████████████████████████████████████████▏ 11 KB pulling f02dd72bb242…​ 100% ▕██████████████████████████████████████████████████████████████████████████████████████████████████████▏ 59 B pulling 6c6b9193c417…​ 100% ▕██████████████████████████████████████████████████████████████████████████████████████████████████████▏ 559 B verifying sha256 digest writing manifest success after smollm2 has been pulled you can exit the shell; Note if you are using minikube, and you want to test if Ollama + smollm2 on Kubernetes is working, run kubectl port-forward svc/ollama-service 11434:11434, then open http://0.0.0.0:11434/ in your browser and you should see "Ollama is running" Image Registry To make the my-jaxrs-app-llm:latest Docker Image available to Kubernetes, you need to push it to some Image Registry that is accessible by the Kubernetes cluster you want to use. Quay.io There are many options to achieve this; in this guide, we will push the my-jaxrs-app-llm:latest Docker Image, to the quay.io Image Registry. Create a public repository named my-jaxrs-app-llm on quay.io (e.g. https://quay.io/repository/tborgato/my-jaxrs-app-llm). Note replace tborgato with the name of your account in all the commands that will follow Tag the Docker image: podman tag my-jaxrs-app-llm quay.io/tborgato/my-jaxrs-app-llm Push the my-jaxrs-app-llm Docker Image to it: podman push quay.io/tborgato/my-jaxrs-app-llm At this point, the my-jaxrs-app-llm:latest Docker Image should be publicly available and free to be consumed by any Kubernetes Cluster; you can verify this by running: podman pull quay.io/tborgato/my-jaxrs-app-llm Deploy to Kubernetes To deploy our my-jaxrs-app-llm Docker Image on minikube, create a file named deployment-my-jaxrs-app-llm.yaml (see kubernetes deployment) in the same directory as the Dockerfile and the pom.xml file, with the following content: deployment-my-jaxrs-app-llm.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-jaxrs-app-llm-deployment labels: app: my-jaxrs-app-llm spec: replicas: 1 selector: matchLabels: app: my-jaxrs-app-llm template: metadata: labels: app: my-jaxrs-app-llm spec: containers: - name: my-jaxrs-app-llm image: quay.io/tborgato/my-jaxrs-app-llm ports: - containerPort: 8080 - containerPort: 9990 livenessProbe: httpGet: path: /health/live port: 9990 readinessProbe: httpGet: path: /health/ready port: 9990 startupProbe: httpGet: path: /health/started port: 9990 env: - name: OLLAMA_CHAT_URL value: 'http://ollama-service:11434' - name: OLLAMA_CHAT_MODEL_NAME value: 'smollm2' apply the Deployment configuration to Kubernetes: kubectl apply -f deployment-my-jaxrs-app-llm.yaml We used minikube as Kubernetes Cluster, hence we expose the deployment as NodePort: kubectl expose deployment.apps/my-jaxrs-app-llm-deployment --type=NodePort --port=8080 Check the application Find out on what IP address/port, minikube is exposing your service: $ minikube service my-jaxrs-app-llm-deployment --url http://192.168.39.178:30781 And set the following variable: export DEPLOYMENT_URL=http://192.168.39.178:30781 Now, invoke the application endpoint using curl: curl $DEPLOYMENT_URL/api/tommaso AiMessage { text = "Ciao Tommaso! Nice to meet you! How are you doing today?" toolExecutionRequests = null } Alternatively, open the $DEPLOYMENT_URL/api/tommaso URL in your browser; Note if you get "dev.langchain4j.exception.HttpException: {"error":"model requires more system memory (3.9 GiB) than is available (3.6 GiB)"}" try to stop minikube and re-start it with "minikube start --memory 7000": this should give minikube enough memory to run smollm2 What’s next? Playing with Generative AI with WildFly: contains a Retrieval-Augmented Generation (RAG) example application WildFly Mini Conference March 2025: check the last track which is about MCP Making WildFly Glow with Intelligence: see how to use Glow to find what feature-packs and layers your deployment needs to be available on WildFly WildFly AI - monitor and troubleshoot a WildFly server with the WildFly chatbot References Source code for this guide: https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice-llm Back to Guides < Back to Getting Started with WildFly micro-services on Kubernetes ### [{simple-microservice-part1}](/guides/get-started-microservices-on-kubernetes/simple-microservice-part1/) WildFly Java Microservice - PART 1: Container Image Table of Contents Prerequisites Maven Project pom.xml Build the application Start the application Check the application Check Liveness, Readiness and Startup Probes Docker Image Dockerfile Build the Docker Image Run the Docker Image Check the application Check Liveness, Readiness and Startup Probes Stop the Docker container What’s next? References In this guide, you will learn how to create and run a Docker Image containing a Jakarta REST service implemented using WildFly. In the following guide WildFly Java Microservice - PART 2: Kubernetes, you will see how to run the same Docker Image on Kubernetes; Prerequisites To complete this guide, you need: Roughly 10 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Install Docker or Podman Maven Project Create a simple Jakarta EE application Maven Project containing a Jakarta REST service using the org.wildfly.archetype:wildfly-getting-started-archetype archetype: mvn archetype:generate \ -DarchetypeGroupId=org.wildfly.archetype \ -DarchetypeArtifactId=wildfly-getting-started-archetype Note See Getting Started with WildFly for the details pom.xml We need to add some features that will be required when, in the next guide, we will run our application on Kubernetes; specifically, we need to expose Liveness, Readiness and Startup Probes; we can add these features thanks to the wildfly-cloud-galleon-pack. Thanks to the integration of WildFly Glow in the wildfly-maven-plugin, the wildfly-cloud-galleon-pack will be automatically added to the Galleon provisioning configuration. Update the pom.xml file to add the <context>cloud</context> XML element to the wildfly-maven-plugin configuration like in the following: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>5.1.3.Final</version> <configuration> <discover-provisioning-info> <version>${version.wildfly.bom}</version> <context>cloud</context> </discover-provisioning-info> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> Build the application $ mvn clean package ... [INFO] Copy deployment /home/tborgato/Documents/WildFly-Mini-Serie/getting-started/target/ROOT.war to /home/tborgato/Documents/WildFly-Mini-Serie/getting-started/target/server/standalone/deployments/ROOT.war [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 5.478 s [INFO] Finished at: 2024-04-12T17:35:46+02:00 [INFO] ------------------------------------------------------------------------ Start the application $ ./target/server/bin/standalone.sh ... 17:36:25,755 INFO [org.wildfly.extension.undertow] (MSC service thread 1-3) WFLYUT0006: Undertow HTTP listener default listening on 0.0.0.0:8080 ... 17:36:25,967 INFO [org.jboss.weld.deployer] (MSC service thread 1-2) WFLYWELD0003: Processing weld deployment ROOT.war ... 17:36:26,835 INFO [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 62) RESTEASY002225: Deploying jakarta.ws.rs.core.Application: class org.wildfly.examples.GettingStartedApplication 17:36:26,859 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool -- 62) WFLYUT0021: Registered web context: '/' for server 'default-server' 17:36:26,883 INFO [org.jboss.as.server] (ServerService Thread Pool -- 35) WFLYSRV0010: Deployed "ROOT.war" (runtime-name : "ROOT.war") 17:36:26,901 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server 17:36:26,904 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management 17:36:26,904 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0054: Admin console is not enabled 17:36:26,904 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 31.0.0.Final (WildFly Core 23.0.1.Final) started in 2175ms - Started 280 of 378 services (149 services are lazy, passive or on-demand) - Server configuration file in use: standalone.xml As you can see, the application started, and it’s ready to serve requests on port 8080. Check the application Go to this URL: http://127.0.0.1:8080/hello/pippo either in your browser or using a utility like curl: $ curl http://127.0.0.1:8080/hello/pippo Hello 'pippo'. Check Liveness, Readiness and Startup Probes Go to these URLs: http://127.0.0.1:9990/health/live http://127.0.0.1:9990/health/ready http://127.0.0.1:9990/health/started either in your browser, or using a utility like curl: $ curl http://127.0.0.1:9990/health/live {"status":"UP","checks":[{"name":"empty-liveness-checks","status":"UP"}]} $ curl http://127.0.0.1:9990/health/ready {"status":"UP","checks":[{"name":"suspend-state","status":"UP","data":{"value":"RUNNING"}},{"name":"server-state","status":"UP","data":{"value":"running"}},{"name":"deployments-status","status":"UP","data":{"ROOT.war":"OK"}},{"name":"boot-errors","status":"UP"},{"name":"ready-deployment.ROOT.war","status":"UP"}]} $ curl http://127.0.0.1:9990/health/started {"status":"UP","checks":[{"name":"started-deployment.ROOT.war","status":"UP"}]} Everything works fine! Let’s move on and package our application in a Docker Image …​ Docker Image Dockerfile We will use the Dockerfile from examples/docker-build/Dockerfile because it is crafted specifically for WildFly. Create a file named Dockerfile in the same directory as the pom.xml file, with the following content: ARG runtime_image=quay.io/wildfly/wildfly-runtime:latest FROM ${runtime_image} COPY --chown=jboss:root target/server $JBOSS_HOME RUN chmod -R ug+rwX $JBOSS_HOME Build the Docker Image Build the Docker Image my-jaxrs-app:latest with the following command: $ podman build -t my-jaxrs-app:latest . STEP 1/3: FROM quay.io/wildfly/wildfly-runtime:latest STEP 2/3: COPY --chown=jboss:root target/server $JBOSS_HOME -→ cf1b99511a9b STEP 3/3: RUN chmod -R ug+rwX $JBOSS_HOME COMMIT my-jaxrs-app:latest -→ e1ab6e80ed20 Successfully tagged localhost/my-jaxrs-app:latest e1ab6e80ed20c3619a7e859f03c71f33b79a4d292f971ed83e7484f4779121d8 Note As you can see, we used Podman, but you can also use Docker, depending on your preference and on which one you have installed on your PC; to switch to Docker, replace podman with docker in the previous command (and in the ones that will follow). Note You can use wildfly-maven-plugin to automate the image build (have a look at the image profile in simple-microservice/pom.xml for a complete example). Note Have a look at Testing WildFly applications on Docker with Arquillian Cube to see how to automate the image build and execution. Run the Docker Image To check that our brand-new my-jaxrs-app:latest Docker Image works as expected, run the following command: $ podman run --rm -p 8080:8080 -p 9990:9990 \ --name=my-jaxrs-app \ my-jaxrs-app …​ 16:14:49,477 INFO [org.wildfly.extension.undertow] (MSC service thread 1-5) WFLYUT0006: Undertow HTTP listener default listening on 0.0.0.0:8080 …​ 16:14:49,677 INFO [org.jboss.weld.deployer] (MSC service thread 1-4) WFLYWELD0003: Processing weld deployment ROOT.war …​ 16:14:50,403 INFO [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool — 61) RESTEASY002225: Deploying jakarta.ws.rs.core.Application: class org.wildfly.examples.GettingStartedApplication 16:14:50,426 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool — 61) WFLYUT0021: Registered web context: '/' for server 'default-server' 16:14:50,451 INFO [org.jboss.as.server] (ServerService Thread Pool — 35) WFLYSRV0010: Deployed "ROOT.war" (runtime-name : "ROOT.war") 16:14:50,459 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server 16:14:50,460 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://0.0.0.0:9990/management 16:14:50,460 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0054: Admin console is not enabled 16:14:50,461 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 31.0.0.Final (WildFly Core 23.0.1.Final) started in 1101ms - Started 280 of 378 services (149 services are lazy, passive or on-demand) - Server configuration file in use: standalone.xml As you can see, the application started, and it’s ready to serve requests on port 8080. Note we explicitly mapped port 8080 in the container to port 8080 on the HOST (your PC); we also mapped port 9990 in the container to port 9990 on the HOST to expose the Liveness, Readiness and Startup Probes. Check the application Repeat the checks in Check the application. Note the only difference here, is that the response is served by the application running inside our my-jaxrs-app:latest Docker Image Check Liveness, Readiness and Startup Probes Repeat the checks in Check Liveness, Readiness and Startup Probes; Note here too, the only difference, is that the responses are served by the application running inside our my-jaxrs-app:latest Docker Image Stop the Docker container Stop the running container: $ podman stop my-jaxrs-app What’s next? WildFly Java Microservice - PART 2: Kubernetes References wildfly-maven-plugin Source code for this guide: simple-microservice Testing WildFly applications on Docker with Arquillian Cube < Back to Getting Started with WildFly micro-services on Kubernetes ### [{simple-microservice-part2}](/guides/get-started-microservices-on-kubernetes/simple-microservice-part2/) WildFly Java Microservice - PART 2: Kubernetes Table of Contents Prerequisites Image Registry Quay.io Kubernetes Minikube Deploy to Kubernetes Check your application What’s next? References In this guide, you will learn HOW-TO run the Docker Image you built in WildFly Java Microservice - PART 1: Container Image on Kubernetes. Prerequisites To complete this guide, you need: Complete WildFly Java Microservice - PART 1: Container Image A Kubernetes cluster: throughout this mini-series, we will use Minikube Image Registry To make the my-jaxrs-app:latest Docker Image available to Kubernetes, you need to push it to some Image Registry that is accessible by the Kubernetes cluster you want to use. Quay.io There are many Image Registries you can use: in this guide, we will push the my-jaxrs-app:latest Docker Image, to the quay.io Image Registry. Create a public repository named my-jaxrs-app on quay.io (e.g. https://quay.io/repository/tborgato/my-jaxrs-app). Note replace tborgato with the name of your account in all the commands that will follow Tag the Docker image: podman tag my-jaxrs-app quay.io/tborgato/my-jaxrs-app Push the my-jaxrs-app Docker Image to it: podman push quay.io/tborgato/my-jaxrs-app At this point, the my-jaxrs-app:latest Docker Image should be publicly available and free to be consumed by any Kubernetes Cluster; you can verify this by running: podman pull quay.io/tborgato/my-jaxrs-app Note You can use wildfly-maven-plugin to automate the image push to an image registry Kubernetes Minikube You can use whatever Kubernetes cluster you have available; in this guide, and in the following, we will use minikube. In case you are using minikube, start the cluster: minikube start Deploy to Kubernetes To deploy our quay.io/tborgato/my-jaxrs-app Docker image to Kubernetes, create a file named deployment-my-jaxrs-app.yaml (see kubernetes deployment) in the same directory as the Dockerfile and the pom.xml file, with the following content: deployment-my-jaxrs-app.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-jaxrs-app-deployment labels: app: my-jaxrs-app spec: replicas: 1 selector: matchLabels: app: my-jaxrs-app template: metadata: labels: app: my-jaxrs-app spec: containers: - name: my-jaxrs-app image: quay.io/tborgato/my-jaxrs-app ports: - containerPort: 8080 - containerPort: 9990 livenessProbe: httpGet: path: /health/live port: 9990 readinessProbe: httpGet: path: /health/ready port: 9990 startupProbe: httpGet: path: /health/started port: 9990 Deploy to your Kubernetes Cluster: $ kubectl apply -f deployment-my-jaxrs-app.yaml deployment.apps/my-jaxrs-app-deployment created We used minikube as Kubernetes Cluster, hence we expose the deployment as NodePort: $ kubectl expose deployment.apps/my-jaxrs-app-deployment --type=NodePort --port=8080 service/my-jaxrs-app-deployment exposed Note you can also use Helm Chart for WildFly to deploy your application Check your application Find out on what IP address/port, minikube is exposing your service: $ minikube service my-jaxrs-app-deployment --url http://192.168.39.139:30782 Verify it’s working as expected: $ curl http://192.168.39.139:30782/hello/pippo Hello 'pippo'. What’s next? Connecting to a DB - PART 1: Container Image Testing WildFly applications on Kubernetes with Arquillian Cube References Source code for this guide: https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice < Back to Getting Started with WildFly micro-services on Kubernetes ### [LangChain4j AI Services in WildFly](/guides/langchain-ai-chat-bot/) LangChain4j AI Services in WildFly In this guide, we will learn how to create a simple AI assistant using LangChain4j-cdi in WildFly. This example is inspired by the official LangChain4j-cdi examples available at LangChain4j-cdi examples. The guide is divided into two main sections: Create simple Chatbot assistant: We will create a simple chatbot application that exposes tools to an LLM to retrieve information and cancel bookings. We will use Ollama as the LLM provider running on our local machine, configure the application using MicroProfile Config, and add resilience with MicroProfile Fault Tolerance. Retrieval-Augmented Generation (RAG) system: We will provide the LLM with information from our rent-a-car company documents. The source code of the application developed in this guide is available at wildfly-car-booking-chat-bot. Prerequisites To complete this guide, you need: Roughly 30 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Ollama available for your local computer and running with the ollama serve command. You can follow the instructions at Ollama installation guide to install Ollama on your machine or alternatively, run it as a docker image. A Simple Chatbot example Project Setup Scaffold a new project using the WildFly Getting Started Archetype: mvn archetype:generate \ -DarchetypeGroupId=org.wildfly.archetype \ -DarchetypeArtifactId=wildfly-getting-started-archetype \ -DarchetypeVersion=41.0.0.Final \ -DdefaultClassPrefix=CarBooking \ -DartifactId=wildfly-car-booking-chat-bot \ -Dversion=1.0.0 \ -DinteractiveMode=false Remove the classes created by the archetype that we are not going to use in this demo: $ cd wildfly-car-booking-chat-bot wildfly-car-booking-chat-bot $ rm src/main/java/org/wildfly/examples/CarBookingEndpoint.java wildfly-car-booking-chat-bot $ rm src/main/java/org/wildfly/examples/CarBookingService.java wildfly-car-booking-chat-bot $ rm -rf src/test Let’s start with the basic POM configuration and dependencies. We are going to use LangChain4j as the core library to talk to the LLM, LangChain4j-cdi to easily integrate LangChain4j into our CDI application, and the WildFly Maven plugin to provision a WildFly server with the required layers to run our application. Add the following properties to control the LangChain4j and LangChain4j-cdi versions: <version.langchain4j>1.16.1</version.langchain4j> <version.langchain4j-cdi>1.3.2</version.langchain4j-cdi> Replace the dependencyManagement section with the following content: <dependencyManagement> <dependencies> <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>wildfly-expansion</artifactId> <version>${version.wildfly.bom}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-bom</artifactId> <version>${version.langchain4j}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> This configures the expected WildFly and LangChain4j BOMs. At the time of writing, there is no BOM for LangChain4j-cdi, so we add the dependencies directly with their versions. Replace the dependencies section with the following: <dependencies> <!-- LangChain4j dependencies --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-core</artifactId> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-ollama</artifactId> </dependency> <!-- LangChain4j-cdi dependencies --> <dependency> <groupId>dev.langchain4j.cdi</groupId> <artifactId>langchain4j-cdi-core</artifactId> <version>${version.langchain4j-cdi}</version> </dependency> <dependency> <groupId>dev.langchain4j.cdi</groupId> <artifactId>langchain4j-cdi-portable-ext</artifactId> <version>${version.langchain4j-cdi}</version> </dependency> <dependency> <groupId>dev.langchain4j.cdi.mp</groupId> <artifactId>langchain4j-cdi-config</artifactId> <version>${version.langchain4j-cdi}</version> </dependency> <dependency> <groupId>dev.langchain4j.cdi.mp</groupId> <artifactId>langchain4j-cdi-fault-tolerance</artifactId> <version>${version.langchain4j-cdi}</version> </dependency> <!-- WildFly provided dependencies --> <dependency> <groupId>jakarta.enterprise</groupId> <artifactId>jakarta.enterprise.cdi-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.microprofile.config</groupId> <artifactId>microprofile-config-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.microprofile.fault-tolerance</groupId> <artifactId>microprofile-fault-tolerance-api</artifactId> <scope>provided</scope> </dependency> </dependencies> We are not going to use Glow for this example. Update the WildFly Maven plugin configuration as follows to provision our WildFly server. The cloud-server layer already includes MicroProfile Config, so we only add the fault tolerance layer: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.wildfly.bom}</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>microprofile-fault-tolerance</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> Creating the Chatbot Application classes and Jakarta RESTful Web Service application Our application simulates a rent-a-car company named "Miles of Smiles" that wants to provide a Chatbot to its customers. Our domain entities are Booking and Customer. Create them in the src/main/java/org/wildfly/examples/ directory with the following content: package org.wildfly.examples; import java.time.LocalDate; /** Represents a car rental booking. */ public record Booking( String bookingNumber, LocalDate start, LocalDate end, Customer customer, boolean canceled, String carModel) {} package org.wildfly.examples; /** Represents a car rental customer. */ public record Customer(String name, String surname) {} The CarBookingRepository class is our database access layer keeping an in-memory hash map with the data of our company: package org.wildfly.examples; import java.time.LocalDate; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import jakarta.enterprise.context.ApplicationScoped; @ApplicationScoped public class CarBookingRepository { private static final Map<String, Booking> BOOKINGS = new HashMap<>(); static { BOOKINGS.put( "123-456", new Booking( "123-456", LocalDate.now().plusDays(1), LocalDate.now().plusDays(7), new Customer("James", "Bond"), false, "Aston Martin")); // Not cancelable: too late BOOKINGS.put( "234-567", new Booking( "234-567", LocalDate.now().plusDays(10), LocalDate.now().plusDays(12), new Customer("James", "Bond"), false, "Renault")); // Not cancelable: too short BOOKINGS.put( "345-678", new Booking( "345-678", LocalDate.now().plusDays(14), LocalDate.now().plusDays(20), new Customer("James", "Bond"), false, "Porsche")); // Cancelable } public Booking findBookingByNumberAndCustomer(String bookingNumber, Customer customer) { Booking booking = findBookingByNumber(bookingNumber); if (booking == null || !booking.customer().equals(customer)) { throw new BookingException("Booking not found for booking number: " + bookingNumber + " and customer: " + customer.name() + " " + customer.surname()); } return booking; } public List<Booking> findBookingByCustomer(Customer customer) { return BOOKINGS.values().stream() .filter(booking -> booking.customer().equals(customer)) .collect(Collectors.toList()); } public Booking findBookingByNumber(String bookingNumber) { return BOOKINGS.get(bookingNumber); } public void saveBooking(Booking booking) { BOOKINGS.put(booking.bookingNumber(), booking); } } This class uses an application Exception named BookingException that we need to create as follows: package org.wildfly.examples; public class BookingException extends RuntimeException { public BookingException(String message) { super(message); } } The Chatbot will be exposed to client applications as a JAX-RS (Jakarta RESTful Web Services) web service under localhost:8080/car-booking. Update the JAX-RS CarBookingApplication application to reflect the base path as follows: package org.wildfly.examples; import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; @ApplicationPath("/car-booking") public class CarBookingApplication extends Application {} LangChain4j AI service and tools to interact with the LLM LangChain4j-cdi provides a portable extension to easily integrate LangChain4j into our CDI applications using annotations. The Chatbot uses a LangChain4j AI service to manage the conversation with the LLM. Behind the scenes, LangChain4j will manage the ReAct loop and provide the LLM with the tools we expose. To do so, we need to create an interface annotated with @RegisterAIService: package org.wildfly.examples; import java.time.temporal.ChronoUnit; import dev.langchain4j.cdi.spi.RegisterAIService; import dev.langchain4j.service.SystemMessage; import org.eclipse.microprofile.faulttolerance.Fallback; import org.eclipse.microprofile.faulttolerance.Retry; import org.eclipse.microprofile.faulttolerance.Timeout; @RegisterAIService( chatModelName = "chat-model", chatMemoryName = "chat-memory", tools = CarBookingService.class ) public interface CarBookingAIService { @SystemMessage(""" You are a customer support agent of a car rental company named 'Miles of Smiles'. Before providing information about booking or canceling a booking, you MUST always check: booking number, customer name and surname. You should not answer to any request not related to car booking or Miles of Smiles company general information. When a customer wants to cancel a booking, you must check their name and the Miles of Smiles cancellation policy first. Any cancellation request must comply with cancellation policy both for the delay and the duration. Today is {{current_date}}. """) @Timeout(unit = ChronoUnit.MINUTES, value = 5) @Retry(maxRetries = 2) @Fallback(fallbackMethod = "fallback") String chat(String question); default String fallback(String question) { return "Sorry, I'm having trouble processing your request at the moment. Please try again later."; } } With the @RegisterAIService annotation, we specify the name of the chat model and the chat memory. Our Chatbot needs to remember who the current user is, so we need to provide a memory mechanism to track the current conversation. Both pieces are configured later using MicroProfile Config. We have also added some MicroProfile Fault Tolerance annotations to make our Chatbot more resilient. The LLM needs access to some tools to interact with our application. These tools are defined in the CarBookingService class as follows: package org.wildfly.examples; import java.time.LocalDate; import java.util.List; import java.util.logging.Logger; import java.util.stream.Collectors; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import dev.langchain4j.agent.tool.Tool; @ApplicationScoped public class CarBookingService { private static final Logger LOGGER = Logger.getLogger(CarBookingService.class.getName()); @Inject CarBookingRepository repository; @Tool("Get booking details given a booking number and customer name and surname") public Booking getBookingDetails(String bookingNumber, String name, String surname) { LOGGER.info("DEMO: Calling Tool-getBookingDetails: " + bookingNumber + " and customer: " + name + " " + surname); return repository.findBookingByNumberAndCustomer(bookingNumber, new Customer(name, surname)); } @Tool("Get all booking ids for a customer given his name and surname") public List<String> getBookingsForCustomer(String name, String surname) { LOGGER.info("DEMO: Calling Tool-getBookingsForCustomer: " + name + " " + surname); return repository.findBookingByCustomer(new Customer(name, surname)) .stream() .map(Booking::bookingNumber) .collect(Collectors.toList()); } @Tool("Cancel a booking given its booking number and customer name and surname") public Booking cancelBooking(String bookingNumber, String name, String surname) { LOGGER.info("DEMO: Calling Tool-cancelBooking " + bookingNumber + " for customer: " + name + " " + surname); Booking booking = repository.findBookingByNumberAndCustomer(bookingNumber, new Customer(name, surname)); if (booking.canceled()) throw new BookingException("Booking with number " + bookingNumber + " is already canceled."); checkCancelPolicy(booking); Booking canceledBooking = new Booking(booking.bookingNumber(), booking.start(), booking.end(), booking.customer(), true, booking.carModel()); repository.saveBooking(canceledBooking); return canceledBooking; } public void checkCancelPolicy(Booking booking) { // Reservations can be canceled up to 7 days prior to the start of the booking period if (LocalDate.now().plusDays(7).isAfter(booking.start())) { throw new BookingException("Booking with number " + booking.bookingNumber() + " cannot be canceled less than 7 days before the start of the booking period."); } // If the booking period is less than 3 days, cancellations are not permitted. if (booking.end().isBefore(booking.start().plusDays(3))) { throw new BookingException("Booking with number " + booking.bookingNumber() + " cannot be canceled because the booking period is less than 3 days."); } } } The three methods annotated with @Tool will be bound to the LLM toolbox. The LLM will invoke them whenever it considers it necessary to answer a question. For example, if the user asks "What is the status of my booking with number 123-456?", the LLM will call the getBookingDetails method with the corresponding parameters to retrieve that booking’s information. The descriptions in the @Tool annotation together with the arguments the decorated method accepts are passed behind the scenes by LangChain4j to the LLM to make it understand when and how to use each tool. Now that we have the AI service and the tools defined, we need to expose the AI service as a REST endpoint so that clients can interact with it. Create the ChatBotResource with the following content: package org.wildfly.examples; import java.util.logging.Level; import java.util.logging.Logger; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; @ApplicationScoped @Path("/chat") public class ChatBotResource { private static final Logger LOGGER = Logger.getLogger(ChatBotResource.class.getName()); @Inject CarBookingAIService aiService; @GET @Produces(MediaType.TEXT_PLAIN) public Response chatWithAssistant(@QueryParam("question") String question) { try { return Response.ok(aiService.chat(question)) .build(); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error while chatting with assistant for question: " + question, e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("My failure reason is:\n\n" + e.getMessage()) .build(); } } } In order to invoke the Chatbot, we only need to use the aiService.chat() method. For simplicity, we are not using streaming responses in this example, but LangChain4j and Jakarta EE can be combined to provide streaming responses for a better client experience. Configure and Run the Application This demo uses MicroProfile Config to configure the AI services. An alternative method is to use the WildFly AI feature pack. In that case, the configuration can be done directly in the server management model and stored in the standalone.xml configuration file. Using MicroProfile Config, you will get per-application configuration on the server, whereas by using WildFly AI feature pack you will get a global configuration integrated in the server management model. Create the src/main/resources/META-INF/microprofile-config.properties file with the following content: # OllamaChatModel - connects to Ollama server dev.langchain4j.cdi.plugin.chat-model.class=dev.langchain4j.model.ollama.OllamaChatModel dev.langchain4j.cdi.plugin.chat-model.config.base-url=http://localhost:11434 dev.langchain4j.cdi.plugin.chat-model.config.model-name=qwen3.5:4b dev.langchain4j.cdi.plugin.chat-model.config.temperature=0.2 dev.langchain4j.cdi.plugin.chat-model.config.topP=0.9 dev.langchain4j.cdi.plugin.chat-model.config.log-requests=false dev.langchain4j.cdi.plugin.chat-model.config.log-responses=false # MessageWindowChatMemory - keeps last N messages dev.langchain4j.cdi.plugin.chat-memory.class=dev.langchain4j.memory.chat.MessageWindowChatMemory dev.langchain4j.cdi.plugin.chat-memory.scope=jakarta.enterprise.context.ApplicationScoped dev.langchain4j.cdi.plugin.chat-memory.config.maxMessages=10 We configure the Chat Model (OllamaChatModel in this case) and the Chat Memory (MessageWindowChatMemory in this case) LangChain4j objects that our AI service needs. We have chosen qwen3.5:4b as the LLM model for this demo. You can choose any other model available in your local Ollama server, but take into account that smaller models with fewer parameters will provide less accurate responses. The only requirement is that the model you are using must support function calling in order to invoke the tools the application exposes to the LLM. You can also change the chat-model configuration to point to any other LLM provider supported by LangChain4j, for example, an OpenAI model. In that case, you will need to provide the corresponding configuration properties plus the required dependencies in the pom.xml file. The temperature and topP (nucleus sampling) are set to 0.2 and 0.9 respectively to favor more consistent and accurate responses; this is a Chatbot, and we don’t want it to be too creative. The log-requests and log-responses properties are set to false to avoid polluting the console with too many logs. Enabling them will allow you to debug and see what messages are sent and received between the application and the LLM. With this configuration, we are all set to do our first test. Let’s now start the Ollama server, build the application, and start the server. Note Before starting the server, make sure the model you are using in the above configuration is already pulled and available in your local Ollama server. After starting your Ollama server, you can check the available models with the ollama list command and pull a model with the ollama pull <model-name> command. Start the Ollama server with the following command: $ ollama serve In another terminal, build the application and start WildFly with the following commands: wildfly-car-booking-chat-bot $ mvn clean package wildfly-car-booking-chat-bot $ ./target/server/bin/standalone.sh The Chatbot is available at http://localhost:8080/car-booking/chat and accepts questions related to car rental bookings, company policies and more. Try asking for example: "Hello, how can you help me?" "My name is James and my surname is Bond, please list my bookings" "What is the cancellation policy?" "Cancel my booking number 123-456" "What are the available car brands I can book?" $ curl "http://localhost:8080/car-booking/chat?question=Hello,+how+can+you+help+me?" Hello! I'm here to help you with your Miles of Smiles car rental booking. I can assist you with: - **Getting booking details** - If you have a booking number and your name, I can look up your reservation information - **Finding all your bookings** - I can retrieve all booking IDs associated with your name - **Canceling bookings** - I can help you cancel a reservation, but I'll need to check your name and the cancellation policy first To get started, could you please provide me with your **first name** and **last name**? This will help me assist you with any booking-related requests you might have. $ curl "http://localhost:8080/car-booking/chat?question=My+name+is+James+and+my+surname+is+Bond,+please+list+my+bookings" I have successfully retrieved the booking IDs for James Bond. Here are your current bookings: 1. **Booking ID:** 345-678 2. **Booking ID:** 234-567 3. **Booking ID:** 123-456 Would you like to get the details for any of these bookings or proceed with a cancellation? If so, please let me know which booking number you are interested in. $ curl "http://localhost:8080/car-booking/chat?question=What+is+the+cancellation+policy?" I don't have access to the specific Miles of Smiles cancellation policy details in my current system. However, I can help you with the cancellation process if you provide me with your booking number and name. To proceed with a cancellation, I'll need: - Your **booking number** (from the three bookings listed above: 345-678, 234-567, or 123-456) - Your **name** (James Bond) Once you provide the booking number, I can check the booking details and assist you with the cancellation. Would you like to proceed with canceling any of your bookings? That sounds good. Although we configured in our system prompt that the Chatbot should check the cancellation policy before canceling any booking, this policy information is not something the LLM knows from its training data. We will provide the LLM with this information in our next section using RAG. $ curl "http://localhost:8080/car-booking/chat?question=Cancel+my+booking+number+123-456" I understand you'd like to cancel booking **123-456**, but I need to inform you that **this booking cannot be canceled**. Here's why: **Booking Details:** - **Start Date:** 2026-06-09 (tomorrow) - **End Date:** 2026-06-15 - **Car Model:** Aston Martin - **Customer:** James Bond **Cancellation Policy:** According to the Miles of Smiles cancellation policy, bookings can only be canceled if they are at least **7 days before the start of the booking period**. Since your booking starts tomorrow (2026-06-09), it falls outside the 7-day cancellation window. The cancellation request is being made on 2026-06-08, which is only 1 day before the booking starts. **Your Options:** 1. **Check your other bookings** (345-678 or 234-567) to see if they might be eligible for cancellation 2. **Contact Miles of Smiles directly** for any special circumstances that might apply 3. **Proceed with any other assistance** you need Would you like me to check the details of your other bookings to see if they might be eligible for cancellation? Notice now that the LLM has learnt something about the cancellation policy and is able to apply it to the specific booking details. This is because our tooling threw an exception with a short explanation about why this booking cannot be canceled. In this case, the LLM was able to interpret that exception and use that information to answer the user question. This is not deterministic, so you might see different responses in different runs, but it is a good example of how the LLM can learn from the tools and use that information in the conversation. Finally, notice also the logs on the server console; they show how the tools are being invoked by the LLM: 13:54:09,851 INFO [org.wildfly.examples.CarBookingService] (default task-2) DEMO: Calling Tool-getBookingsForCustomer: James Bond 13:58:49,639 INFO [org.wildfly.examples.CarBookingService] (default task-2) DEMO: Calling Tool-getBookingDetails: 123-456 and customer: James Bond 13:58:55,482 INFO [org.wildfly.examples.CarBookingService] (default task-2) DEMO: Calling Tool-cancelBooking 123-456 for customer: James Bond Adding custom company documentation using RAG (Retrieval-Augmented Generation) We want our Chatbot to also answer questions based on company-specific, up-to-date, and private data rather than its LLM training data alone or chat conversation. We are now going to implement a simple RAG (Retrieval-Augmented Generation) system to provide the LLM with specific information. Create the following text files in the company-docs directory with the following content: ./company-docs/company-overview.txt: Miles of Smiles - Company Overview Miles of Smiles is an international car rental company operating across 40 countries in Europe, the Americas, and Asia. Workforce: The company employs 500 people worldwide. Fleet: Miles of Smiles manages a fleet of 1,000 vehicles. 10% of the fleet is fully electric, reflecting the company's commitment to sustainable mobility. Customer Satisfaction: Miles of Smiles holds a 99% customer satisfaction rating. ./company-docs/available-car-brands.txt: Miles of Smiles - Available Car Brands Miles of Smiles offers a selection of 9 car brands ranging from mainstream to luxury, including fully electric options. Luxury: Aston Martin, Porsche Premium: BMW, DS, Mercedes Mainstream: Renault, Peugeot, Toyota Electric: Tesla ./company-docs/terms-of-use.txt: Miles of Smiles Car Rental Services Terms of Use 1. Introduction These Terms of Service (“Terms”) govern the access or use by you, an individual, from within any country in the world, of applications, websites, content, products, and services (“Services”) made available by Miles of Smiles Car Rental Services, a company registered in the United States of America. 2. The Services Miles of Smiles rents out vehicles to the end user. We reserve the right to temporarily or permanently discontinue the Services at any time and are not liable for any modification, suspension or discontinuation of the Services. 3. Bookings 3.1 Users may make a booking through our website or mobile application. 3.2 You must provide accurate, current and complete information during the reservation process. You are responsible for all charges incurred under your account. 3.3 All bookings are subject to vehicle availability. 4. Cancellation Policy 4.1 Reservations lasting less than three days cannot be canceled 4.2 Reservations can be canceled up to 7 days prior to the start of the booking period. 5. Use of Vehicle 5.1 All cars rented from Miles of Smiles must not be used: for any illegal purpose or in connection with any criminal offense. for teaching someone to drive. in any race, rally or contest. while under the influence of alcohol or drugs. 6. Liability 6.1 Users will be held liable for any damage, loss, or theft that occurs during the rental period. 6.2 We do not accept liability for any indirect or consequential loss, damage, or expense including but not limited to loss of profits. 7. Governing Law These terms will be governed by and construed in accordance with the laws of the United States of America, and any disputes relating to these terms will be subject to the exclusive jurisdiction of the courts of United States. 8. Changes to These Terms We may revise these terms of use at any time by amending this page. You are expected to check this page from time to time to take notice of any changes we made. 9. Acceptance of These Terms By using the Services, you acknowledge that you have read and understand these Terms and agree to be bound by them. If you do not agree to these Terms, please do not use or access our Services. RAG in LangChain4j works by converting documents into numerical vectors (embeddings) and storing them in an embedding store. When the user asks a question, the system finds the most relevant document chunks and includes them in the prompt sent to the LLM. To set this up, we need two things: the embedding infrastructure (an embedding model to transform text into vectors and an embedding store to store them), and an ingestor that loads and indexes our documents at application startup, or more probably, in an external system that periodically ingests this information. Add the following dependency to the pom.xml file to bring in the embedding model and the in-memory embedding store: <!-- RAG dependencies --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-embeddings-all-minilm-l6-v2</artifactId> </dependency> The AllMiniLmL6V2EmbeddingModel is a lightweight ONNX-based embedding model that runs locally inside the application. Create the EmbeddingsProducers class at src/main/java/org/wildfly/examples/EmbeddingsProducers.java to produce the embedding model and the embedding store as CDI beans: package org.wildfly.examples; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.model.embedding.EmbeddingModel; import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel; import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; @ApplicationScoped public class EmbeddingsProducers { @Produces @ApplicationScoped public EmbeddingModel embeddingModel() { return new AllMiniLmL6V2EmbeddingModel(); } @Produces @ApplicationScoped public InMemoryEmbeddingStore<TextSegment> embeddingStore() { return new InMemoryEmbeddingStore<>(); } } Now create the DocRagIngestor class at src/main/java/org/wildfly/examples/DocRagIngestor.java to load the documents: package org.wildfly.examples; import static dev.langchain4j.data.document.loader.FileSystemDocumentLoader.loadDocuments; import dev.langchain4j.data.document.Document; import dev.langchain4j.data.document.parser.TextDocumentParser; import dev.langchain4j.data.document.splitter.DocumentSplitters; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.model.embedding.EmbeddingModel; import dev.langchain4j.store.embedding.EmbeddingStore; import dev.langchain4j.store.embedding.EmbeddingStoreIngestor; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.Initialized; import jakarta.enterprise.event.Observes; import jakarta.inject.Inject; import java.io.File; import java.util.List; import java.util.logging.Logger; import org.eclipse.microprofile.config.inject.ConfigProperty; @ApplicationScoped public class DocRagIngestor { private static final Logger LOGGER = Logger.getLogger(DocRagIngestor.class.getName()); @Inject EmbeddingModel embeddingModel; @Inject EmbeddingStore<TextSegment> embeddingStore; @Inject @ConfigProperty(name = "app.docs-for-rag.dir") private File docs; private List<Document> loadDocs() { return loadDocuments(docs.getPath(), new TextDocumentParser()); } public void ingest(@Observes @Initialized(ApplicationScoped.class) Object pointless) { long start = System.currentTimeMillis(); EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder() .documentSplitter(DocumentSplitters.recursive(300, 30)) .embeddingModel(embeddingModel) .embeddingStore(embeddingStore) .build(); List<Document> docs = loadDocs(); ingestor.ingest(docs); LOGGER.info(String.format( "DEMO %d documents ingested in %d msec", docs.size(), System.currentTimeMillis() - start)); } } This class loads the company documents from a configurable directory and creates the EmbeddingStoreIngestor for ingesting the documents. It uses our EmbeddingModel to compute the vectors and the EmbeddingStore to store them. The ingestor is configured with a document splitter that splits the documents into chunks of 300 characters with a 30-character overlap. Once we have our EmbeddingStore with the documents indexed, we need to configure a content retriever that will retrieve the most relevant document chunks for each user question and provide them to the LLM as context. Add the following properties to the microprofile-config.properties file to configure the EmbeddingStoreContentRetriever retriever and tell the DocRagIngestor where to find the company documents: # RAG - path to company documents app.docs-for-rag.dir=company-docs # EmbeddingStoreContentRetriever - retrieves relevant documents from an embedding store dev.langchain4j.cdi.plugin.doc-retriever.class=dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever dev.langchain4j.cdi.plugin.doc-retriever.config.embeddingStore=lookup:@default dev.langchain4j.cdi.plugin.doc-retriever.config.embeddingModel=lookup:@default dev.langchain4j.cdi.plugin.doc-retriever.config.maxResults=5 dev.langchain4j.cdi.plugin.doc-retriever.config.minScore=0.6 The lookup:@default syntax tells LangChain4j-cdi to resolve these from the CDI default beans. The maxResults and minScore parameters control how many document chunks are retrieved (at most 5) and the minimum similarity threshold (0.6) to filter out irrelevant results. Finally, we need to wire the content retriever into our AI service. Update the @RegisterAIService annotation in the CarBookingAIService interface to add the contentRetrieverName parameter: @RegisterAIService( chatModelName = "chat-model", chatMemoryName = "chat-memory", tools = CarBookingService.class, contentRetrieverName = "doc-retriever" ) Rebuild and restart the application, and you can now ask the Chatbot questions about the company. For example: "What is the cancellation policy?" "What are the available car brands I can book?" $ curl "http://localhost:8080/car-booking/chat?question=What+is+the+cancellation+policy?" Based on the Miles of Smiles cancellation policy, here are the key points: **Cancellation Policy:** 1. **Reservations lasting less than three days cannot be canceled** - This means short-term rentals under 3 days are not eligible for cancellation. 2. **Reservations can be canceled up to 7 days prior to the start of the booking period** - To cancel a reservation, you must do so at least 7 days before your rental period begins. **Additional Terms:** - By using the Miles of Smiles Services, you acknowledge that you have read and understand these Terms and agree to be bound by them. - Users will be held liable for any damage, loss, or theft that occurs during the rental period. - We do not accept liability for any indirect or consequential loss, damage, or expense. If you have a specific booking you'd like to cancel, I'll need your booking number and customer name/surname to check the details and assist you further. $ curl "http://localhost:8080/car-booking/chat?question=What+are+the+available+car+brands+I+can+book?" Based on the Miles of Smiles car rental services, here are the available car brands you can book: **Luxury:** - Aston Martin - Porsche **Premium:** - BMW - DS - Mercedes **Mainstream:** - Renault - Peugeot - Toyota **Electric:** - Tesla **Fleet Overview:** - Miles of Smiles manages a fleet of 1,000 vehicles - 10% of the fleet is fully electric (100 vehicles) - The company operates across 40 countries in Europe, the Americas, and Asia **Important Usage Terms:** - All cars rented must not be used for illegal purposes or criminal offenses - Cars cannot be used for teaching someone to drive - No racing, rallies, or contests are permitted - Vehicles cannot be used while under the influence of alcohol or drugs If you'd like to book a vehicle, I'll need your booking number and customer name/surname to assist you further. What’s next? This is just a simple demo of what can be achieved by combining LangChain4j and Jakarta EE. Check the LangChain4j documentation for more advanced use cases and features, such as: Using streaming responses to provide a better experience to the users Use a different embedding store to be able to manage larger document collections and have a more scalable RAG system Use a separate chat memory for each user and a persistent chat memory store to offload the chat memory to an external cache or database References LangChain4j documentation LangChain4j CDI Integration ### [Configuring Clustered Messaging in WildFly](/guides/messaging-clustering/) Configuring Clustered Messaging in WildFly Table of Contents Prerequisites Prepare WildFly Servers Testing and Verifying the Messaging Cluster What’s Next? References In this guide, you will learn how to configure WildFly servers with an embedded ActiveMQ Artemis broker in a messaging cluster, enabling server-side message and client load balancing. It will demonstrate how to configure deployments, such as MDBs, EJBs, or Servlets, as well as external JMS clients, to load balance connections across all servers in the cluster. Note An ActiveMQ Artemis cluster is distinct from a standard WildFly cluster formed by the Infinispan subsystem. While a WildFly cluster using Infinispan focuses on data caching and session replication across nodes, an Artemis cluster is specifically designed for messaging, allowing message redistribution across brokers and load balancing of message producers and consumers. These two clusters operate independently, each with its own purpose and configuration, although they can coexist within the same WildFly environment. For a detailed explanation of ActiveMQ Artemis clusters, refer to the Apache ActiveMQ Artemis Clustering Documentation and the EAP 7.4 Messaging Clusters Overview. Prerequisites To complete this guide, you need: Roughly 15 minutes JDK 17+ installed with JAVA_HOME configured appropriately Prepare WildFly Servers Now, let’s configure two WildFly servers with embedded ActiveMQ Artemis brokers in a cluster. We’ll use the full-ha profile, as it already contains most of the necessary settings and requires only minor modifications. By default, the messaging cluster in WildFly uses JGroups, which relies on a multicast-based discovery mechanism to locate servers in the cluster. This allows the cluster to automatically discover and add new servers within the network. However, if multicast is not available or suitable for your environment, you can configure the messaging cluster to use alternative discovery mechanisms based on your specific requirements. This flexibility ensures that the cluster can be adapted to various network topologies and infrastructure setups. Note While the full-ha profile may seem to provide High Availability (HA) for messaging, it only configures a messaging cluster without inherent HA capabilities. To enable HA for messaging, refer to the Configure WildFly with a Messaging (ActiveMQ Artemis) Cluster and High Availability guide. Copy WildFly into two directories wildfly-1 and wildfly-2 Start wildfly-1 in a full-ha profile in admin-only mode: ./wildfly-1/bin/standalone.sh -c standalone-full-ha.xml --admin-only In a different terminal, connect to the server using the JBoss CLI: ./wildfly-1/bin/jboss-cli.sh -c Run the following CLI commands on wildfly-1: Note In the following CLI script, replace <password> with the actual password for the cluster connection. # Change ActiveMQ Artemis cluster <password> /subsystem=messaging-activemq/server=default:write-attribute(name=cluster-password, value=<password>) # Rebalance inbound connections for MDBs when cluster topology changes /subsystem=messaging-activemq/server=default/pooled-connection-factory=activemq-ra:write-attribute(name=rebalance-connections,value=true) # Shutdown the server shutdown Start wildfly-2 in a full-ha profile in admin-only mode (set port offset to 1000 to avoid port conflicts): ./wildfly-2/bin/standalone.sh -c standalone-full-ha.xml -Djboss.socket.binding.port-offset=1000 --admin-only In a different terminal, connect to the server using the JBoss CLI: ./wildfly-2/bin/jboss-cli.sh -c --controller=127.0.0.1:10990 Run the following CLI commands on wildfly-2: Note In the following CLI script, replace <password> with the actual password for the cluster connection. # Change ActiveMQ Artemis cluster <password> /subsystem=messaging-activemq/server=default:write-attribute(name=cluster-password, value=<password>) # Rebalance inbound connections for MDBs when cluster topology changes /subsystem=messaging-activemq/server=default/pooled-connection-factory=activemq-ra:write-attribute(name=rebalance-connections,value=true) # Shutdown the server shutdown Testing and Verifying the Messaging Cluster We’ll use the helloworld-mdb quickstart from WildFly to test and verify the messaging cluster. This quickstart features a HelloWorldMDBServletClient servlet that sends messages to the HELLOWORLDMDBQueue queue, and a HelloWorldQueueMDB MDB that consumes messages from this queue. Start both WildFly servers, each in a separate terminal: ./wildfly-1/bin/standalone.sh -c standalone-full-ha.xml ./wildfly-2/bin/standalone.sh -c standalone-full-ha.xml -Djboss.socket.binding.port-offset=1000 Check the server logs to verify it contains the following entry: 14:20:30,673 INFO [org.apache.activemq.artemis.core.server] (Thread-2 (ActiveMQ-server-org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl$6@33607b42)) AMQ221027: Bridge ClusterConnectionBridge ... is connected This log entry indicates that the cluster has been successfully formed. You can build and deploy the helloworld-mdb quickstart by running: git clone git@github.com:wildfly/quickstart.git cd quickstart/helloworld-mdb mvn clean package wildfly:deploy mvn clean package wildfly:deploy -Dwildfly.port=10990 At this point, open your web browser and navigate to http://localhost:8080/helloworld-mdb/. This will invoke the servlet to send messages to the HelloWorldMDBServletClient queue on wildfly-1 server. Check the server logs of both servers to ensure they contain entries similar to the following: ... 14:54:32,439 INFO [class org.jboss.as.quickstarts.mdb.HelloWorldQueueMDB] (Thread-19 (ActiveMQ-client-global-threads)) Received Message from queue: This is message 2 14:54:32,447 INFO [class org.jboss.as.quickstarts.mdb.HelloWorldQueueMDB] (Thread-19 (ActiveMQ-client-global-threads)) Received Message from queue: This is message 4 ... ---- The presence of these log entries in the wildfly-2 server log confirms that messages were successfully load balanced from wildfly-1. What’s Next? With the ActiveMQ Artemis cluster in place, you can explore various strategies for server-side message and client load balancing. This flexibility allows you to optimize performance and reliability according to your specific needs. Additionally, the setup of an ActiveMQ Artemis cluster is a prerequisite for implementing High Availability. For a comprehensive guide on configuring WildFly with a Messaging (ActiveMQ Artemis) Cluster and High Availability, refer to Configure WildFly with a Messaging (ActiveMQ Artemis) Cluster and High Availability. References Apache ActiveMQ Artemis Documentation - Clusters EAP 7.4 Messaging Clusters Overview. ### [Deploying High-Availability Messaging with WildFly and AMQ 7 on OpenShift](/guides/messaging-high-availability-openshift/) Deploying High-Availability Messaging with WildFly and AMQ 7 on OpenShift Table of Contents Prerequisites Log Into the OpenShift Cluster Install and deploy AMQ 7 using an operator Build WildFly with a messaging application image using the WildFly Maven Plugin Push WildFly image to the OpenShift registry Install the WildFly Operator Deploy the application image using the WildFly Operator Test the Application What’s Next? References In this guide, you will learn how to configure a WildFly server connected to a remote AMQ 7 cluster on OpenShift using operators. Prerequisites To complete this guide, you need: Roughly 20 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Access to an OpenShift cluster (consider using the 'Self-managed' variant for a local development environment, available for free at Red Hat OpenShift) OpenShift CLI tool Podman (Docker is also compatible with minor adjustments) Log Into the OpenShift Cluster Before we can deploy our application, we need to log in to an OpenShift cluster. You can log in via the OpenShift CLI: oc login -u myUserName Alternatively, you can log in using an API token: oc login --token=myToken --server=myServerUrl You can request the token via the Copy Login Command link in the OpenShift web console. If you don’t already have a project created, you can create one using: oc new-project myProjectName Install and deploy AMQ 7 using an operator To install the AMQ 7 Operator, follow the instructions in the Red Hat documentation: Installing the Operator using OperatorHub Next, create a file named broker.yaml with the following content to deploy the AMQ 7 cluster: apiVersion: broker.amq.io/v1beta1 kind: ActiveMQArtemis metadata: name: amq-broker application: amq-broker-app spec: acceptors: - name: acceptor protocols: core,amqp port: 61616 sslEnabled: false enabledProtocols: TLSv1,TLSv1.1,TLSv1.2 needClientAuth: true wantClientAuth: true verifyHost: true sslProvider: JDK sniHost: localhost expose: true anycastPrefix: jms.queue. multicastPrefix: /topic/ console: expose: true deploymentPlan: journalType: nio messageMigration: true persistenceEnabled: true requireLogin: false size: 2 storage: size: "1Gi" upgrades: enabled: false minor: false This Custom Resource (CR) file configures an AMQ 7 cluster with two brokers deployed as a StatefulSet. This setup ensures high availability because, in the event of a pod failure, the StatefulSet will automatically restart the failed pod. However, to maintain data integrity, Persistent Volumes must be configured to store the messaging journal. Without them, messages will be lost during restarts. Additionally, the messageMigration: true setting enables the graceful scaling down of AMQ 7 pods. This ensures that messages from the scaled-down node are migrated to another node in the cluster, preventing data loss. Run following command to deploy AMQ 7 on OpenShift: oc create -f broker.yaml Check that AMQ 7 brokers are in Running state by checking running pods: $ oc get pods NAME READY STATUS RESTARTS AGE amq-broker-ss-0 1/1 Running 0 35m amq-broker-ss-1 1/1 Running 0 36m ... Build WildFly with a messaging application image using the WildFly Maven Plugin We’re going to use the WildFly Quickstart: remote-helloworld-mdb to demonstrate how to build a trimmed WildFly server with a deployed messaging application. This quickstart leverages the WildFly Maven plugin to create a trimmed WildFly server and deploy the remote-helloworld-mdb.war application. It then produces a new container image based on the WildFly Runtime Image, incorporating the application. This quickstart includes a HelloWorldMDBServletClient servlet, which sends messages to the HELLOWORLDMDBQueue queue, and a HelloWorldQueueMDB message-driven bean (MDB) that consumes messages from this queue. To build the remote-helloworld-mdb quickstart, execute the following commands: git clone git@github.com:wildfly/quickstart.git cd quickstart/remote-helloworld-mdb mvn clean package wildfly:image -Popenshift The openshift profile is used to provide additional configuration for the WildFly server to work correctly on the Openshift environment. The Maven goal wildfly:image instructs the WildFly Maven Plugin to build a container image. You can verify the newly built image by running: $ podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/remote-helloworld-mdb latest cf9a174a5311 14 minutes ago 621 MB ... Push WildFly image to the OpenShift registry We need to expose the created image in the registry, so it can later be referenced from the Custom Resource for the WildFly Operator. We can utilize the integrated OpenShift registry and push the image into it through the ImageStream. First create a new ImageStream in your namespace: oc create imagestream remote-helloworld-mdb Now push your image into the ImageStream: export REGISTRY="$(oc get routes -n openshift-image-registry default-route -o=jsonpath='{.spec.host}')" podman login --tls-verify=false -u admin -p $(oc whoami -t) $REGISTRY podman tag localhost/remote-helloworld-mdb $REGISTRY/$(oc config view --minify -o jsonpath='{..namespace}')/remote-helloworld-mdb podman push --tls-verify=false $REGISTRY/$(oc config view --minify -o jsonpath='{..namespace}')/remote-helloworld-mdb You can verify that the image was successfully pushed to the ImageStream by running: $ oc get imagestream remote-helloworld-mdb NAME IMAGE REPOSITORY TAGS UPDATED remote-helloworld-mdb default-route-openshift-image-registry.apps-crc.testing/mnovak/remote-helloworld-mdb latest 17 minutes ago Install the WildFly Operator First we need to install the WildFly Operator to OpenShift cluster. Since the WildFly Operator is not included in the OpenShift OperatorHub by default, it must be added manually. Create the file community-catalog-source.yaml with content: apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: name: operatorhubio-catalog namespace: openshift-marketplace spec: displayName: Community Operators grpcPodConfig: securityContextConfig: restricted image: quay.io/operatorhubio/catalog:latest publisher: OperatorHub.io sourceType: grpc updateStrategy: registryPoll: interval: 60m Execute the following command to add the community catalog to the OperatorHub: oc apply -f community-catalog-source.yaml You can now install the WildFly Operator using the wildfly-operator.yml file: apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: name: wildfly spec: channel: alpha installPlanApproval: Automatic name: wildfly source: operatorhubio-catalog sourceNamespace: openshift-marketplace and install it by: oc apply -f wildfly-operator.yml You can now verify the installed operator in your namespace by inspecting the pods: $ oc get pods NAME READY STATUS RESTARTS AGE wildfly-operator-d975cb47c-q9vgp 1/1 Running 0 4m17s ... Deploy the application image using the WildFly Operator Now, we will configure the WildFly Operator to deploy the WildFly image with the messaging application. To achieve this, we will create a new file, wildfly-remote-messaging.yaml. In this file, the location of the AMQ 7 broker must be specified by setting the environment variables JBOSS_MESSAGING_CONNECTOR_HOST and JBOSS_MESSAGING_CONNECTOR_PORT: apiVersion: wildfly.org/v1alpha1 kind: WildFlyServer metadata: name: wildfly-remote-activemq spec: applicationImage: "remote-helloworld-mdb:latest" replicas: 1 env: - name: JBOSS_MESSAGING_CONNECTOR_HOST value: amq-broker-acceptor-0-svc - name: JBOSS_MESSAGING_CONNECTOR_PORT value: '61616' and deploy it by: oc apply -f wildfly-remote-messaging.yaml You can now verify the deployed wildfly in your namespace by inspecting the pods: $ oc get pods NAME READY STATUS RESTARTS AGE wildfly-remote-activemq-0 1/1 Running 0 63s ... Test the Application We’re going to test the application by sending 5 messages to the HELLOWORLDMDBQueue to the AMQ 7 broker. Then we will check that the MDB consumed those messages from the queue: curl http://$(oc get route wildfly-remote-activemq-route --template='{{ .spec.host }}')/remote-helloworld-mdb/HelloWorldMDBServletClient This command invokes the HelloWorldMDBServletClient servlet deployed to WildFly to send messages. Check the server log to ensure they contain entries similar to the following: $ oc logs wildfly-remote-activemq-0 ... 13:39:27,846 INFO [class org.jboss.as.quickstarts.mdb.HelloWorldQueueMDB] (Thread-10 (ActiveMQ-client-global-threads)) Received Message from queue: This is message 1 13:39:27,860 INFO [class org.jboss.as.quickstarts.mdb.HelloWorldQueueMDB] (Thread-12 (ActiveMQ-client-global-threads)) Received Message from queue: This is message 3 13:39:27,863 INFO [class org.jboss.as.quickstarts.mdb.HelloWorldQueueMDB] (Thread-11 (ActiveMQ-client-global-threads)) Received Message from queue: This is message 2 13:39:27,874 INFO [class org.jboss.as.quickstarts.mdb.HelloWorldQueueMDB] (Thread-10 (ActiveMQ-client-global-threads)) Received Message from queue: This is message 4 13:39:27,878 INFO [class org.jboss.as.quickstarts.mdb.HelloWorldQueueMDB] (Thread-12 (ActiveMQ-client-global-threads)) Received Message from queue: This is message 5 The presence of these log entries in the server log confirms that the MDB successfully consumed messages from the HELLOWORLDMDBQueue from one of the clustered remote AMQ 7 broker. What’s Next? Now that you have deployed WildFly with a messaging application connected to AMQ 7, explore the following resources to enhance your understanding and further extend your deployment: Deploying AMQ Broker on OpenShift: Dive deeper into deploying and managing AMQ Broker on OpenShift with detailed guides and best practices. Deploying AMQ Broker on OpenShift WildFly Operator Repository: Learn more about the WildFly Operator, its features, and advanced configuration options directly from the official GitHub repository. WildFly Operator GitHub WildFly Maven Plugin Documentation: Explore the WildFly Maven Plugin for automating deployment, configuration, and management of WildFly applications during your build process. WildFly Maven Plugin Documentation These resources provide valuable insights and tools to optimize your WildFly and AMQ deployments, automate workflows, and build robust applications on OpenShift. References WildFly Operator GitHub Deploying AMQ Broker on OpenShift WildFly Maven Plugin Documentation Apache ActiveMQ Artemis Documentation - Clusters EAP 7.4 Messaging Clusters Overview ### [Configure WildFly with a Messaging (ActiveMQ Artemis) Cluster and High Availability](/guides/messaging-high-availability/) Configure WildFly with a Messaging (ActiveMQ Artemis) Cluster and High Availability Table of Contents Prerequisites Prepare shared journal directories Prepare WildFly Servers Test High Availability What’s next? References In this guide you will learn how to configure two WildFly servers with messaging (integrated ActiveMQ Artemis broker) in a high availability topology with shared journal. The Apache ActiveMQ Artemis broker, embedded within WildFly, supports linking brokers together in primary-secondary pairs. This creates an active-passive HA design: under normal conditions, the primary broker handles all the workload, while the secondary node remains on standby, ready to take over if the primary broker fails. However, we will not start another WildFly server solely to support an inactive Artemis broker, instead we will configure an additional ActiveMQ Artemis broker on each WildFly instance to act as the secondary broker for the primary in the other WildFly. This setup results in two primary-secondary pairs, with each pair maintaining its own journal directory. If one WildFly server fails, the secondary ActiveMQ Artemis broker on the other WildFly server will activate and take over all duties. All HA enabled connections from the original primary broker will fail over to the secondary broker. The secondary broker will access all messages stored on the primary broker by loading them from the shared journal directory. Once the original WildFly server is restarted, the secondary broker will automatically switch back to standby mode, and all clients will fail back to the primary broker. Note For simplicity, we will use just one machine to run WildFly instances and use local directories for shared journals. In a real world scenario those should be two separate machines with a shared journal mount from a shared file system (like NFS4). Prerequisites To complete this guide, you need: Roughly 20 minutes JDK 17+ installed with JAVA_HOME configured appropriately Prepare shared journal directories Create two directories for each primary-secondary pair: mkdir messaging-journal-a mkdir messaging-journal-b Prepare WildFly Servers Now let’s configure two WildFly servers with two primary-secondary pairs of embedded ActiveMQ Artemis brokers. The ActiveMQ Artemis broker configured as the primary on the first WildFly server and as the secondary on the second WildFly server will use the messaging-journal-a directory for their shared journal. Similarly, the primary broker on the second WildFly server and the secondary broker on the first WildFly server will use the messaging-journal-b directory for their shared journal. Note All ActiveMQ Artemis brokers must be in a cluster so that they are aware of each other and can provide cluster topology to connected clients. If any WildFly instance crashes, clients will know the location of the secondary broker and can fail over seamlessly. The procedures in this guide ensure that the brokers are properly clustered. Copy WildFly into two directories wildfly-1 and wildfly-2 Start wildfly-1 in a full-ha profile in admin-only mode: ./wildfly-1/bin/standalone.sh -c standalone-full-ha.xml --admin-only In a different terminal, connect to the server using the JBoss CLI: ./wildfly-1/bin/jboss-cli.sh -c Run the following CLI commands on wildfly-1: Note In the following CLI script, replace the <password> and <path> values according to your environment. # Change ActiveMQ Artemis cluster <password> /subsystem=messaging-activemq/server=default:write-attribute(name=cluster-password, value=<password>) # Set location of journal for pair A - change path to messaging-journal-a directory based on your environment /subsystem=messaging-activemq/server=default/path=bindings-directory:write-attribute(name=path,value=<path>/messaging-journal-a/bindings) /subsystem=messaging-activemq/server=default/path=journal-directory:write-attribute(name=path,value=<path>/messaging-journal-a/journal) /subsystem=messaging-activemq/server=default/path=large-messages-directory:write-attribute(name=path,value=<path>/messaging-journal-a/largemessages) /subsystem=messaging-activemq/server=default/path=paging-directory:write-attribute(name=path,value=<path>/messaging-journal-a/paging) # Set "default" Artemis broker as primary /subsystem=messaging-activemq/server=default/ha-policy=shared-store-primary:add(failover-on-server-shutdown=true) reload # Add secondary broker /subsystem=messaging-activemq/server=secondary:add(security-enabled=true, elytron-domain=ApplicationDomain) # Change ActiveMQ Artemis cluster <password> /subsystem=messaging-activemq/server=secondary:write-attribute(name=cluster-password, value=password) # Create http-connector/http-acceptor pointing to this broker /subsystem=messaging-activemq/server=secondary/http-acceptor=acceptor:add(http-listener=default) /subsystem=messaging-activemq/server=secondary/http-connector=connector:add(endpoint=acceptor,socket-binding=http) # Create a broadcast group to advertise the broker in the cluster and a corresponding discovery group to be used by the cluster connection to discover other brokers, enabling the formation of the cluster. /subsystem=messaging-activemq/server=secondary/jgroups-broadcast-group=bg-group1:add(jgroups-cluster=activemq-cluster, connectors=[connector]) /subsystem=messaging-activemq/server=secondary/jgroups-discovery-group=dg-group1:add(jgroups-cluster=activemq-cluster) /subsystem=messaging-activemq/server=secondary/cluster-connection=my-cluster:add(cluster-connection-address=jms,connector-name=connector,discovery-group=dg-group1) # Set "secondary" Artemis broker as secondary /subsystem=messaging-activemq/server=secondary/ha-policy=shared-store-secondary:add(failover-on-server-shutdown=true) # Set location of journal for pair B - change path to messaging-journal-a directory based on your environment /subsystem=messaging-activemq/server=secondary/path=bindings-directory:write-attribute(name=path,value=<path>/messaging-journal-b/bindings) /subsystem=messaging-activemq/server=secondary/path=journal-directory:write-attribute(name=path,value=<path>/messaging-journal-b/journal) /subsystem=messaging-activemq/server=secondary/path=large-messages-directory:write-attribute(name=path,value=<path>/messaging-journal-b/largemessages) /subsystem=messaging-activemq/server=secondary/path=paging-directory:write-attribute(name=path,value=<path>/messaging-journal-b/paging) # Shutdown the server shutdown Start wildfly-2 in a full-ha profile in admin-only mode (set port offset to 1000 to avoid port conflicts): ./wildfly-2/bin/standalone.sh -c standalone-full-ha.xml -Djboss.socket.binding.port-offset=1000 --admin-only In a different terminal, connect to the server using the JBoss CLI: ./wildfly-2/bin/jboss-cli.sh -c --controller=127.0.0.1:10990 Run the following CLI commands on wildfly-2: Note In the following CLI script, replace the <password> and <path> values according to your environment. # Change ActiveMQ Artemis cluster <password> /subsystem=messaging-activemq/server=default:write-attribute(name=cluster-password, value=<password>) # Set location of journal for pair B - change path to messaging-journal-b directory based on your environment /subsystem=messaging-activemq/server=default/path=bindings-directory:write-attribute(name=path,value=<path>/messaging-journal-b/bindings) /subsystem=messaging-activemq/server=default/path=journal-directory:write-attribute(name=path,value=<path>/messaging-journal-b/journal) /subsystem=messaging-activemq/server=default/path=large-messages-directory:write-attribute(name=path,value=<path>/messaging-journal-b/largemessages) /subsystem=messaging-activemq/server=default/path=paging-directory:write-attribute(name=path,value=<path>/messaging-journal-b/paging) # Set "default" Artemis broker as primary /subsystem=messaging-activemq/server=default/ha-policy=shared-store-primary:add(failover-on-server-shutdown=true) reload # Add secondary broker /subsystem=messaging-activemq/server=secondary:add(security-enabled=true, elytron-domain=ApplicationDomain) # Change ActiveMQ Artemis cluster <password> /subsystem=messaging-activemq/server=secondary:write-attribute(name=cluster-password, value=password) # Create http-connector/http-acceptor pointing to this broker /subsystem=messaging-activemq/server=secondary/http-acceptor=acceptor:add(http-listener=default) /subsystem=messaging-activemq/server=secondary/http-connector=connector:add(endpoint=acceptor,socket-binding=http) # Create a broadcast group to advertise the broker in the cluster and a corresponding discovery group to be used by the cluster connection to discover other brokers, enabling the formation of the cluster. /subsystem=messaging-activemq/server=secondary/jgroups-broadcast-group=bg-group1:add(jgroups-cluster=activemq-cluster, connectors=[connector]) /subsystem=messaging-activemq/server=secondary/jgroups-discovery-group=dg-group1:add(jgroups-cluster=activemq-cluster) /subsystem=messaging-activemq/server=secondary/cluster-connection=my-cluster:add(cluster-connection-address=jms,connector-name=connector,discovery-group=dg-group1) # Set "secondary" Artemis broker as secondary /subsystem=messaging-activemq/server=secondary/ha-policy=shared-store-secondary:add(failover-on-server-shutdown=true) # Set location of journal for pair A - change path to messaging-journal-a directory based on your environment /subsystem=messaging-activemq/server=secondary/path=bindings-directory:write-attribute(name=path,value=<path>/messaging-journal-a/bindings) /subsystem=messaging-activemq/server=secondary/path=journal-directory:write-attribute(name=path,value=<path>/messaging-journal-a/journal) /subsystem=messaging-activemq/server=secondary/path=large-messages-directory:write-attribute(name=path,value=<path>/messaging-journal-a/largemessages) /subsystem=messaging-activemq/server=secondary/path=paging-directory:write-attribute(name=path,value=<path>/messaging-journal-a/paging) # Shutdown the server shutdown Test High Availability We’ll test HA by crashing the first WildFly server and checking that the secondary ActiveMQ Artemis broker on the second WildFly server is active. Start both WildFly servers, each in a separate terminal: ./wildfly-1/bin/standalone.sh -c standalone-full-ha.xml ./wildfly-2/bin/standalone.sh -c standalone-full-ha.xml -Djboss.socket.binding.port-offset=1000 Shut down or crash wildfly-1 and verify in the server log that the secondary broker has started in wildfly-2: 16:25:44,921 INFO [org.apache.activemq.artemis.core.server] (AMQ229000: Activation for server ActiveMQServerImpl::name=secondary) AMQ221010: Backup Server is now active Start wildfly-1 server and verify that fail-back happened and the secondary broker on wildfly-2 went to standby mode: 16:26:53,043 INFO [org.apache.activemq.artemis.core.server] (Thread-4 (ActiveMQ-scheduled-threads)) AMQ221008: primary server wants to restart, restarting server in backup ... 16:26:55,488 INFO [org.apache.activemq.artemis.core.server] (Thread-0 (ActiveMQ-server-org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl$6@2845f281)) AMQ221031: backup announced What’s next? ActiveMQ Artemis in WildFly also allows you to use a replicated journal, where each primary-secondary pair replicates data over the network. This approach has its pros and cons: it eliminates the need to mount shared journal directories on each machine but typically results in lower performance due to the network round trip times required between paired brokers. More information can be found in the ActiveMQ Artemis documentation. References Configuring Messaging guide for EAP 7.4 ActiveMQ Artemis documentation ### [Prototype WildFly applications with JBang](/guides/prototyping-with-jbang/) Prototype WildFly applications with JBang Table of Contents Prerequisites Install JBang Prototype a Jakarta RESTful Application Use MicroProfile Config Export the application What’s next? References In this guide, you will learn how to use JBang to prototype enterprise Java applications running with WildFly. Prerequisites To complete this guide, you need: Roughly 15 minutes Install JBang JBang is a tool to create, edit and run self-contained source-only Java programs with unprecedented ease. There are numerous ways to install JBang (as described in its Download page) but the simplest one is to execute the command: curl -Ls https://sh.jbang.dev | bash -s - app setup The jbang executable is then added to your path and you can start using it. Note You do not even need to have Java installed in your machine. If Java is not present, JBang will install it for you. JBang is a powerful tool with many features. For the purpose of this guide, we will cover the ones you need to understand to prototype WildFly applications. JBang allows you to create, edit and run self-contained source-only Java programs. You can make your .java file an executable script by adding at the top of the file the comment: ///usr/bin/env jbang "$0" "$@" ; exit $? JBang provides dependency declarations using //DEPS <gav> comments for automatic dependency resolution. If your Java source depends on a library, you can import its package and add a //DEPS comment to declare which library in Maven is providing these packages. A simple example of a Java program with JBang is: myapp.java ///usr/bin/env jbang "$0" "$@" ; exit $? //DEPS com.github.lalyos:jfiglet:0.0.8 import com.github.lalyos.jfiglet.FigletFont; class myapp { public static void main(String[] args) throws Exception { String name = args.length==0 ? "World" : args[0]; String hello = String.format("Hello, %s!", name); System.out.println(FigletFont.convertOneLine(hello)); } } You can save this program in a myapp.java file and run it with JBang: $ jbang run myapp.java Bob [jbang] Building jar for myapp.java... _ _ _ _ ____ _ _ | | | | ___ | | | | ___ | __ ) ___ | |__ | | | |_| | / _ \ | | | | / _ \ | _ \ / _ \ | '_ \ | | | _ | | __/ | | | | | (_) | _ | |_) | | (_) | | |_) | |_| |_| |_| \___| |_| |_| \___/ ( ) |____/ \___/ |_.__/ (_) Prototype a Jakarta RESTful Application To create a source-only Java file that runs on WildFly, you need to follow a few rules: Create a Jakarta RESTful application that defines your HTTP API Always add the dependency: //DEPS org.wildfly.glow:wildfly-glow:1.4.0.Final WildFly Glow is the magic "sauce" that binds JBang with WildFly to deploy and run the Web application.` Use the WildFly BOM dependency to add dependencies provided by WildFly: //DEPS org.wildfly.bom:wildfly-expansion:35.0.1.Final@pom(note the @pom after the version that identifies this dependency as a POM dependency instead of a Jar dependency). You can then add non-versioned dependencies on the APIs you are using to pull the versions provided by WildFly. For example //DEPS jakarta.ws.rs:jakarta.ws.rs-api Note Make sure to always use the latest version of WildFly BOM and Glow. You do not need to download WildFly: a WildFly server will automatically be provisioned with the capabilities required to run your application when jbang run is executed. If you change the Java program listed above to make it a Web application running on WildFly, it will now look like: myapp.java ///usr/bin/env jbang "$0" "$@" ; exit $? //DEPS com.github.lalyos:jfiglet:0.0.8 //DEPS org.wildfly.bom:wildfly-expansion:35.0.1.Final@pom //DEPS jakarta.ws.rs:jakarta.ws.rs-api //DEPS jakarta.enterprise:jakarta.enterprise.cdi-api //DEPS org.wildfly.glow:wildfly-glow:1.4.1.Final import jakarta.enterprise.context.ApplicationScoped; import jakarta.ws.rs.*; import jakarta.ws.rs.core.*; import com.github.lalyos.jfiglet.FigletFont; @ApplicationPath("/") public class myapp extends Application { @Path("/hello") @ApplicationScoped public static class Hello { @GET public String sayHello(@QueryParam("name") @DefaultValue("World") String name) throws Exception { String hello = String.format("Hello, %s!", name); return FigletFont.convertOneLine(hello); } } } You can run this Web application with: $ jbang run myapp.java [jbang] Resolving dependencies... [jbang] org.wildfly.glow:wildfly-glow:1.4.0.Final [jbang] com.github.lalyos:jfiglet:0.0.8 [jbang] org.wildfly.bom:wildfly-expansion:35.0.1.Final@pom [jbang] jakarta.ws.rs:jakarta.ws.rs-api:3.1.0 [jbang] jakarta.enterprise:jakarta.enterprise.cdi-api:4.0.1 [jbang] Dependencies resolved [jbang] Building jar for myapp.java... [jbang] Post build with org.wildfly.glow.jbang.JBangIntegration ... 17:02:39,613 INFO [org.jboss.as.server] (ServerService Thread Pool -- 20) WFLYSRV0010: Deployed "myapp.war" (runtime-name : "myapp.war") ... 17:02:39,632 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly 35.0.1.Final (WildFly Core 27.0.1.Final) started in 2225ms - Started 192 of 196 services (35 services are lazy, passive or on-demand) - Server configuration file in use: standalone.xml - Minimum feature stability level: community Your web application can now be accessed with: $ curl "http://localhost:8080/myapp/hello?name=Alice" _ _ _ _ _ _ _ _ | | | | ___ | | | | ___ / \ | | (_) ___ ___ | | | |_| | / _ \ | | | | / _ \ / _ \ | | | | / __| / _ \ | | | _ | | __/ | | | | | (_) | _ / ___ \ | | | | | (__ | __/ |_| |_| |_| \___| |_| |_| \___/ ( ) /_/ \_\ |_| |_| \___| \___| (_) Use MicroProfile Config Let’s update the code to use MicroProfile Config to inject the "Hello" word so that the application can be localized. To do so, we will add a String with the @Inject @ConfigProperty annotations and use it in our HTTP API: @Inject @ConfigProperty(name = "hello", defaultValue = "Hello") String helloWord; @GET public String sayHello(@QueryParam("name") @DefaultValue("World") String name) throws Exception { String hello = String.format("%s, %s!", helloWord, name); return FigletFont.convertOneLine(hello); } We need to add the import statements for the new types used in our code: import jakarta.inject.Inject; import org.eclipse.microprofile.config.inject.ConfigProperty; And, finally, we need to declare the dependencies that provides these new types. CDI was already declared (by the comment //DEPS jakarta.enterprise:jakarta.enterprise.cdi-api), so we only need to declare the dependency for the MicroProfile Config API: //DEPS org.eclipse.microprofile.config:microprofile-config-api With all these changes, the Java file now looks like: myapp.java ///usr/bin/env jbang "$0" "$@" ; exit $? //DEPS com.github.lalyos:jfiglet:0.0.8 //DEPS org.wildfly.bom:wildfly-expansion:35.0.1.Final@pom //DEPS jakarta.ws.rs:jakarta.ws.rs-api //DEPS jakarta.enterprise:jakarta.enterprise.cdi-api //DEPS org.eclipse.microprofile.config:microprofile-config-api //DEPS org.wildfly.glow:wildfly-glow:1.3.2.Final import jakarta.enterprise.context.ApplicationScoped; import jakarta.ws.rs.*; import jakarta.ws.rs.core.*; import com.github.lalyos.jfiglet.FigletFont; import jakarta.inject.Inject; import org.eclipse.microprofile.config.inject.ConfigProperty; @ApplicationPath("/") public class myapp extends Application { @Path("/hello") @ApplicationScoped public static class Hello { @Inject @ConfigProperty(name = "hello", defaultValue = "Hello") String helloWord; @GET public String sayHello(@QueryParam("name") @DefaultValue("World") String name) throws Exception { String hello = String.format("%s, %s!", helloWord, name); return FigletFont.convertOneLine(hello); } } } We can now use the HELLO environment variable to change the value of the helloWord to something other than Hello (which is its default). For example, you can run a French version of this application with: $ HELLO="Bonjour" jbang run myapp.java [jbang] Resolving dependencies... ...] [jbang] org.eclipse.microprofile.config:microprofile-config-api:3.1 [jbang] Dependencies resolved [jbang] Building jar for myapp.java... [jbang] Post build with org.wildfly.glow.jbang.JBangIntegration ... 17:02:39,613 INFO [org.jboss.as.server] (ServerService Thread Pool -- 20) WFLYSRV0010: Deployed "myapp.war" (runtime-name : "myapp.war") ... 17:11:19,525 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly 35.0.1.Final (WildFly Core 27.0.1.Final) started in 2326ms - Started 192 of 196 services (35 services are lazy, passive or on-demand) - Server configuration file in use: standalone.xml - Minimum feature stability level: community When you access the Web application, it will now greet the user in French: $ curl "http://localhost:8080/myapp/hello?name=Alice" ____ _ _ _ _ _ | __ ) ___ _ __ (_) ___ _ _ _ __ / \ | | (_) ___ ___ | | | _ \ / _ \ | '_ \ | | / _ \ | | | | | '__| / _ \ | | | | / __| / _ \ | | | |_) | | (_) | | | | | | | | (_) | | |_| | | | _ / ___ \ | | | | | (__ | __/ |_| |____/ \___/ |_| |_| _/ | \___/ \__,_| |_| ( ) /_/ \_\ |_| |_| \___| \___| (_) |__/ |/ Export the application If you want to publish or share your Web application, you can export it with JBang with the command: jbang export portable myapp.java It will create a myapp.jar file that is actually a WildFly Bootable Jar. You can then directly execute this Jar file to run your Web application: $ java -jar myapp.jar ... 09:00:48,890 INFO [org.jboss.as.server] (ServerService Thread Pool -- 20) WFLYSRV0010: Deployed "myapp.war" (runtime-name : "myapp.war") ... 09:00:48,909 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly 35.0.1.Final (WildFly Core 27.0.1.Final) started in 2243ms - Started 192 of 196 services (35 services are lazy, passive or on-demand) - Server configuration file in use: standalone.xml - Minimum feature stability level: community What’s next? This guide has shown how you can use JBang to quickly prototype WildFly applications from a single Java source file without having to create a full-fledged Maven project. The example was a simple Web application that showed how to use dependencies provided by WildFly as well as 3rd-party libraries. It is possible to further customize the WildFly server by using //GLOW comments as described in the WildFly Glow documentation. JBang documentation also provides information to organize your files, specify which version of Java to run the program, etc. For a deeper dive into prototyping WildFly applications with JBang (including writing a Simple AI Chat bot model), you can watch the presentation done during the March 2024 WildFly Mini Conference: References JBang Home Page WildFly Glow documentation to run WildFly with JBang ### [Using Credential Stores for WildFly Client](/guides/security-credential-store-client-config/) Using Credential Stores for WildFly Client Table of Contents Prerequisites Access the Example Application About WildFly Client Configuration Configure the Server Configure the FileSystem Realm Configure the Security Domain Create an Authentication Factory Configure the WildFly Client Create the Credential Store Configure wildfly-config.xml Build and Deploy the application Summary References WildFly allows the use of credential stores to keep aliases for sensitive information, such as, passwords for external services. Credential stores can be used to store different credentials under aliases and use credential-reference to specify them in server configuration. As a result, the credential is no longer visible in clear text. However, there are additional uses for credential store as well. This guides explains how to create credential stores using the elytron-tool and use it for an application deployed to WildFly. Prerequisites To complete this guide, you need: Roughly 10 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Elytron-tool (provided with WildFly) Access the Example Application For this guide we will be using the ejb-security example application. Let us first clone the project and navigate to it: git clone https://github.com/wildfly-security-incubator/elytron-examples cd ejb-security About WildFly Client Configuration EJBs, also known as Enterprise JavaBeans are a collection of specifications that are used for building java applications and offer a set of APIs for developing and running secured applications. When invoking EJBs using the WildFly server, we need to configure the WildFly client to specify relevant information about authentication to the secured the application. This can be done using a file named wildfly-config.xml located inside the src/main/resources folder of the application. Configure the Server For this guide, we will be securing an EJB using a filesystem realm and invoking them from a remote client using a credential store. This guide will dive deeper into the credential-store configuration of it. This blog post contains more details about the steps we are taking for configuring the server and what they do. Configure the FileSystem Realm First run the server and in another terminal, connect to the management cli: $ WILDFLY_HOME/bin/jboss-cli.sh --connect Now we can create the filesystem realm and create an identity called quickStartUser, which we will be using to access the application: # Create a filesystem realm called fs-realm-users in the server configuration directory /subsystem=elytron/filesystem-realm=fsRealm:add(path=fs-realm-users, relative-to=jboss.server.config.dir) # Add an identity called quickStartUser, which we will be using to access the application /subsystem=elytron/filesystem-realm=fsRealm:add-identity(identity=quickstartUser) # Set a password for the identity /subsystem=elytron/filesystem-realm=fsRealm:set-password(clear={password=quickstartPwd1!}, identity=quickstartUser) # Assign the appropriate roles needed to access the application /subsystem=elytron/filesystem-realm=fsRealm:add-identity-attribute(identity=quickstartUser, name=Roles, value=[guest]) # Add a role decoder which can convert atteibutes from the identity into roles /subsystem=elytron/simple-role-decoder=from-roles-attribute:add(attribute=Roles) Note that the password can also be specified using an encrypted expression instead of clear text. You can refer to this guide for more details about using credential stores and encrypted expressions. Configure the Security Domain Let’s create a security domain and an application security domain to be able to invoke our EJB: /subsystem=elytron/security-domain=fsSD:add(realms=[{realm=fsRealm, role-decoder=from-roles-attribute}], default-realm=fsRealm,permission-mapper=default-permission-mapper) /subsystem=ejb3/application-security-domain=other:add(security-domain=fsSD) Note that creating an additional security domain (fsSD in this case) is not necessary. We could alternatively take the default ApplicationDomain and add the FileSystem realm, role-decoder and permission-mapper to it. Create an Authentication Factory We now need to create a sasl-authentication-factory and connect our security domain to it and specify a mechanism for the authentication: /subsystem=elytron/sasl-authentication-factory=application-sasl-authentication:write-attribute(name=security-domain, value=fsSD) /subsystem=elytron/sasl-authentication-factory=application-sasl-authentication:list-add(name=mechanism-configurations, value={mechanism-name=SCRAM-SHA-512}) /subsystem=remoting/http-connector=http-remoting-connector:write-attribute(name=sasl-authentication-factory,value=application-sasl-authentication). Configure the WildFly Client Now that the server is configured, we can move onto configuring our WildFly client. The first step is to create a credential-store so we can add the quickStartUser identity and its password to it. Using a credential-store helps us avoid specifying the credentials for our identity using plaintext. Previous guides demonstrated how to create a credential store using the elytron subsystem. However, we can also do it using the elytron-tool, which the WildFly server comes with. The elytron tool can be accessed using the elytron-tool.sh(.bat for windows) script and offers many functionalities that the elytron subsystem has. Create the Credential Store We can use the elytron-tool to securely create a credential-store as follows: $ WILDFLY_HOME/bin/elytron-tool.sh credential-store --create --location "/PATH/TO/mycredstore.cs" --password StorePassword Now let’s store the login information for our quickStartUser identity into the credential-store: $ WILDFLY_HOME/bin/elytron-tool.sh credential-store --location "/PATH/TO/mycredstore.cs" --password StorePassword --add quickstartUser --secret quickstartPwd1! Our WildFly client will be able to access this credential-store to access the login information for the identity. Here the quickstartUser is an alias that the password is being stored under and it does not have to match the identity name we specified earlier. Configure wildfly-config.xml Now that we have our credential-store set up, we need to let our WildFly Client know where to find it and how to access it. We will be making use of a file called wildfly-config.xml to communicate that. This file can be found inside the src/main/resources folder. We can specify the location and the type and password for the credential-store as follows: <credential-stores> <credential-store name="mycredstore"> <attributes> <attribute name="keyStoreType" value="JCEKS"/> <attribute name="location" value="PATH/TO/mycredstore.cs"></attribute> </attributes> <protection-parameter-credentials> <clear-password password="StorePassword"/> </protection-parameter-credentials> </credential-store> </credential-stores> This should be added into the xml file already, but you may need to update the paths with the actual paths for the credential store. Note you would need to replace "PATH/TO/mycredstore.cs" with the actual path to your credential store. Now we need to specify which identity to extract from our credential-store. A credential-store can hold multiple credentials that are used for various purposes. We can specify which one to use by identifying it with the unique alias we declared earlier. We will also be specifying the authentication mechanism here to match what we specified for the server: <authentication-configurations> <configuration name="default-config"> <set-user-name name="quickstartUser"/> <credentials> <credential-store-reference store="mycredstore" alias="quickstartUser"/> </credentials> <sasl-mechanism-selector selector="SCRAM-SHA-512"/> <providers> <use-service-loader /> </providers> </configuration> </authentication-configurations> Build and Deploy the application Now we can use maven to build and deploy the application using the commands below: $ mvn clean install wildfly:deploy Unlike other applications, this will not be a web application, rather something we can run on the terminal. If you examine the server logs, you will notice that instead of a .war deployment, we will be producing a .jar deployment file. This will not be a web application, so we won’t use a browser to access it, but instead we will use the terminal as follows: $ mvn exec:exec You can see the following output on your terminal: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Successfully called secured bean, caller principal quickstartUser Principal has admin permission: false * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * As you can see, it mentions that the secured bean has been accessed by our identity, quickstartUser and it does not have admin permissions, since we only assigned the guest role to it. Summary This guide demonstrates how a credential-store can be used to specify identity credentials when configuring a WildFly client. This guide also demonstrates how the elytron-tool can be used to generate the credential store and add aliases to it. References Filesystem Credential-Stores Creating credential-stores using the Elytron-tool To learn more about the functions of elytron-tool, you can use the ./bin/elytron-tool.sh -h command from WILDFLY_HOME. ### [Using Credential Stores With Encrypted Expressions With WildFly](/guides/security-credential-store-enc-exp/) Using Credential Stores With Encrypted Expressions With WildFly Table of Contents Prerequisites Prerequisite About Encrypted Expressions Configuring Encrypted Expressions Encrypted Expression for Credential Reference Encrypted Expression for System Property Encrypted Expressions to Replace Other Passwords Disabling Cli History Summary References WildFly allows the use of credential stores to keep alias for sensitive information, such as, passwords for external services. Credential stores can be used to store different credentials under aliases and use credential-reference to specify them in server configuration. As a result, the sensitive information is no longer visible in clear text. Prerequisites To complete this guide, you need: Roughly 10 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Prerequisite To follow along with this guide you will need: about 10 minutes WildFly with credential-store support About Encrypted Expressions A previous guide demonstrates how to use credential stores to avoid using clear-text passwords. However, as you may have noticed, the password for the credential store was specified in clear-text. And while having access to the credential-store password does not allow a human to read the contents of a credential-store, it is still not secure. Additionally, there are other types of sensitive information we may use when configuring a server which we would not want to appear in the standalone.xml file. This is where encrypted expressions are useful. Support for encrypted expressions allow us to specify sensitive information, like the password for a credential-store without using plain-text values. Encrypted expressions can also be used for system properties, where a value expression is specified. And lastly, credential-store can only be used for credential-reference attributes. But there are other attributes where we can enter sensitive information, but it does not include a credential reference. This guide will explain the these three use cases for encrypted expressions and how to configure them. Configuring Encrypted Expressions Let’s first create a secret-key-credential-store that we can use to store secret keys that will be used to encrypt expressions. Just like a regular credential-store file, this will also create a .cs file inside the directory you specify. However, this will be human readable. /subsystem=elytron/secret-key-credential-store=newCredStore:add(path=newSecretKeyCred.cs, relative-to=jboss.server.config.dir) If you already had a .cs file that you would like to use, then you can specify the path here and set the create and populate attributes to false. These attributes are true by default as seen here: { "outcome" => "success", "result" => { "path" => "newSecretKeyCred.cs", "relative-to" => "jboss.server.config.dir", "create" => true, "default-alias" => "key", "key-size" => 256, "populate" => true } } Here is an example of the contents of the newSecretKeyCred.cs file: # Properties Credential Store (Do Not Modify) key=RUxZAUsOhzQhCv7KbD9f2SGBgWkmTC9l0lgu28FWM4UfRBY7QQ== As you can see there has been a key created for you already using the default alias key. You can create a new key with a new alias of your own using the following command: /subsystem=elytron/secret-key-credential-store=newCredStore:generate-secret-key(alias=newSecretKey, key-size=128) Now let’s use these keys for the use cases mentioned above. Encrypted Expression for Credential Reference Now that we have a generated secret key in a credential store we can activate the resource responsible for handling encrypted expressions. And we can use that to convert a clear-text password phrase into an encrypted expression. /subsystem=elytron/expression=encryption:add(resolvers=[{name=initial-resolver, credential-store=newCredStore, secret-key=key}]) /subsystem=elytron/expression=encryption:create-expression(resolver=initial-resolver, clear-text=MyPassword) the second command will give you an output like this which we will use to specify the password instead of the clear-text phrase: { "outcome" => "success", "result" => {"expression" => \ "${ENC::initial-resolver:RUxZAUMQEH6CP3xXyAqYzqsC3oNayyeGH32wsdAZ8VLkkxaEmWc=}"} } Now if we wanted to create another credential-store, then we can use this encrypted expression to create it as follows: /subsystem=elytron/credential-store=main:add(path=mySecondCredStore.cs, relative-to=jboss.server.config.dir, credential-reference= {clear-text="${ENC::initial-resolver:RUxZAUMQEH6CP3xXyAqYzqsC3oNayyeGH32wsdAZ8VLkkxaEmWc=}"}, create=true) This does not just apply to credential stores, we can also do this with any other resource that uses credential-reference, such as a key-store or a key-manager. Encrypted Expression for System Property System properties can be used to customize the behaviour of the server. These are key-value pairs that can be specified using the cli commands. System properties can be specified as follows: /system-property=foo:add(value=bar) However, sometimes the value may be something you do not want to specify in plaintext. If we configure it as shown above, the value can easily be discovered using the read-resource function. So, we need a way to specify it without using clear-text. However, since this does not use credential-reference we cannot use a credential-store directly. Instead, we can use encrypted expressions. We can encrypt the value for a system property using encrypted expressions as follows: /subsystem=elytron/expression=encryption:create-expression(resolver=initial-resolver, clear-text=bar) { "outcome" => "success", "result" => {"expression" => "${ENC::initial-resolver:RUxZAUMQXSp3dFy+4aUcAzpayRZVeHHNTU/4bE3iUW8LGPplXkA=}"} } We can now update our value to this encrypted expression: /system-property=foo:write-attribute(name=value, value=${ENC::initial-resolver:RUxZAUMQXSp3dFy+4aUcAzpayRZVeHHNTU/4bE3iUW8LGPplXkA=}) If we use the read-resource function on our system property, we can no longer see the value in plaintext. Encrypted Expressions to Replace Other Passwords The WildFly has some resources which contain sensitive information, such as passwords, without using credential-reference. One such example is the truststore-password attribute under the secure-deployment resource under tne elytron-oidc-client subsystem. These values can also be specified using encrypted expressions. We can encrypt the value as follows: /subsystem=elytron/expression=encryption:create-expression(resolver=initial-resolver, clear-text=secret) { "outcome" => "success", "result" => {"expression" => "${ENC::initial-resolver:RUxZAUMQdZ5/RHt5Oj+Whv K3l+rtR2AnjrtOhBkKW6X58vUtrUw=}"} } Once the encrypted expression has been added, it can easily be used to specify sensitive information, like as seen below: /subsystem=elytron-oidc-client/secure-deployment=simple-webapp.war:write-attribute(name=truststore-password,value="${ENC::initial-resolver:RUxZAUMQA6O7VXU/6cdzA4qlQNU1SM34N5kk53l8DjsljXoEYTc=}") and for the naming subsystem example, we can use the following commands: /subsystem=naming/binding=java\:global\/federation\/ldap\/example:write-attribute(name=environment, value={java.naming.security.credentials="${ENC::initial-resolver:RUxZAUMQA6O7VXU6cdzA4qlQNU1SM34N5kk53l8DjsljXoEYTc=}"}) Disabling Cli History As you may notice some of the commands still include sensitive information. And since the jboss cli caches all executed commands, we need to disable history to hide all inputs using the command below: history --disable Caching can be enabled again using the command below: history --enable Summary This guide demonstrates three use cases where we can use encrypted expressions to specify sensitive information. References Encrypted Expressions Credential Stores System Properties ### [Using Credential Stores to Replace Clear Text Passwords With WildFly](/guides/security-credential-store-for-passwords/) Using Credential Stores to Replace Clear Text Passwords With WildFly Table of Contents Prerequisites About Credential Reference Creating a Resource with Plaintext Password Create a Credential Store Add an Entry to the Credential-Store Disable History for the Management Console Update the Keystore Credentials Automatic Credential Store Update Remove Unused Credentials Summary Resources WildFly allows the use of credential stores to keep aliases for sensitive information, such as, passwords for external services. Credential stores can be used to store different credentials under aliases and use credential-reference to specify them in server configuration. As a result, the credential is no longer visible in clear text. Prerequisites To complete this guide, you need: Roughly 10 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ About Credential Reference There are multiple uses for credential stores, but this blog post will dive deeper into using credential-stores to avoid specifying passwords in clear text. Passwords are used for various resources when configuring the WildFly server, such as a key-store or a key-manager. While it is quick and easy to specify the passwords in clear text, it is not very secure. Creating a Resource with Plaintext Password Let us first create a resource with the password specified as plaintext. To do that, let’s first start the server: $ WILDFLY_HOME/bin/standalone.sh Once the server is running, open another terminal and connect to the cli to configure the server: $ WILDFLY_HOME/bin/jboss-cli.sh --connect Now we can create a keystore using a plaintext password: /subsystem=elytron/key-store=serverKS:add(path=server.keystore, relative-to=jboss.server.config.dir, type=PKCS12, credential-reference={clear-text=secret}) When configuring a resource using plaintext password, it is stores in the standalone.xml file as seen below: <key-store name="serverKS"> <credential-reference clear-text="secret"/> <implementation type="PKCS12"/> <file path="server.keystore" relative-to="jboss.server.config.dir"/> </key-store> As you can see, the password can easily be obtained from the standalone.xml file or using the read-resource() function on the elytron subsystem: { "outcome" => "success", "result" => { "alias-filter" => undefined, "credential-reference" => {"clear-text" => "secret"}, "path" => "server.keystore", "relative-to" => "jboss.server.config.dir", "required" => false, "provider-name" => undefined, "providers" => undefined, "type" => "PKCS12" } } However, this can be changed using a credential-store and alias to point to the password instead. Create a Credential Store A credential store can hold multiple passwords at once, with each password uniquely identified by an alias. When we want to use a password for a resource, we can specify which credential-store it is in and which alias it is under. Let’s first create a credential store: /subsystem=elytron/credential-store=myCredStore:add(location=mycredstore.cs, relative-to=jboss.server.config.dir, credential-reference={clear-text=StorePassword}, create=true) If you navigate to WILDFLY_HOME/standalone/configuration, you will see a new file has been created there named mycredstore.cs. This file is used to store all the credentials in a credential-store. If you try to view the contents of this file using a text editor, you will see that the file is not human readable. It is possible to programmatically read the passwords, which is what WildFly does when dereferencing the credential reference to access a resource. Add an Entry to the Credential-Store In order to use the credential-store for our keystore, we need to add the keystore password to it: /subsystem=elytron/credential-store=myCredStore:add-alias(alias=kspass, secret-value=secret) Here, alias is the unique identifier that is used to refer to this password entry inside the credential store. The secret-value refers to the actual value of the password. Disable History for the Management Console As you may have noticed, above that we specified the password to be added to the credential store in clear-text. So while it would no longer appear on the standalone.xml file, if someone went through the management CLI history, they can easily find the password. In order to avoid this, we can disable the history using the command below: [standalone@localhost:9999 /] history --disable Once you have added your passwords to the credential store, you can enable history again using the command below: [standalone@localhost:9999 /] history --enable Update the Keystore Credentials Now, we can edit our keystore to use the credential store instead of the clear-text password: /subsystem=elytron/key-store=serverKS:write-attribute(name=credential-reference, value={store=myCredStore, alias=kspass}) Now if we use the read-resource function, we can no longer see the password: { "outcome" => "success", "result" => { "alias-filter" => undefined, "credential-reference" => { "store" => "myCredStore", "alias" => "kspass" }, "path" => "server.keystore", "relative-to" => "jboss.server.config.dir", "required" => false, "provider-name" => undefined, "providers" => undefined, "type" => "PKCS12" }, "response-headers" => {"process-state" => "reload-required"} } Automatic Credential Store Update WildFly also allows us to automatically add a new password to a previously created credential-store when specifying the password for a reference. We can automatically add a new password by using the credential-reference attribute for a resource and by specifying the clear-text password there using the following commands: /subsystem=elytron/key-store=serverKS:write-attribute(name=credential-reference, value={store=myCredStore, alias=example, clear-text=secret}) This will produce the an output like this: { "outcome" => "success", "result" => {"credential-store-update" => { "status" => "new-entry-added", "new-alias" => "example" }}, "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } } As you can see from the output, the credential-store has been updated to add a new credential and that is being used for the keystore now. If you reload the server and call the read-resource function on the keystore, this will be the output: { "outcome" => "success", "result" => { "alias-filter" => undefined, "credential-reference" => { "store" => "myCredStore", "alias" => "example" }, "path" => "server.keystore", "relative-to" => "jboss.server.config.dir", "required" => false, "provider-name" => undefined, "providers" => undefined, "type" => "PKCS12" } } Notice how even though we specified the clear-text password when updating the credentials, it does not show up here. Instead, we can see the name of the credential-store and the alias listed under credential-reference. Remove Unused Credentials If you are no longer using an alias and would like to remove it from the credential store, then you can do that using the following command: /subsystem=elytron/credential-store=myCredStore:remove-alias(alias=myalias) However, when deleting an alias, you must be careful. If the alias you are trying to delete is currently in use, it may still be removed successfully, leaving the resource’s credential-reference pointing to a non-existent alias. Summary This blog post introduces us to credential stores and introduces us to one of the use cases for them. There are other use cases for credential-stores when securing resources in the WildFly server. Future guides will cover other use cases. Resources To learn more about credential stores, please refer to the documentation To learn more about automatic credential-store updates, visit this blog post You can also use the read-resource-description function in command line to learn more about the credential-reference resource. ### [HashiCorp Vault credential store integration in WildFly](/guides/security-hashicorp-vault-credential-store/) HashiCorp Vault credential store integration in WildFly Table of Contents Prerequisites About HashiCorp Vault Integration Quick Start Start HashiCorp Vault (Development Mode) Step 1: Provision WildFly with the Feature-Pack Step 2: Start WildFly with Community Stability Step 3: Configure a Credential Store and Store a Secret Alias Format Configure the HashiCorp Vault Credential Store Add a Credential Store (CLI) Current Configuration Attributes Reference Securing the Connection with TLS Using Credential Store References Example: Using with LDAP Vault Expressions What’s next? References In this guide, you will provision WildFly with the HashiCorp Vault subsystem, configure a Vault-backed credential store, store and read secrets, and reference them from other subsystems. WildFly includes support for using HashiCorp Vault as a credential store through a dedicated subsystem and feature-pack. The HashiCorp Vault feature-pack is published to Maven Central and is also available as the hashicorp-vault Galleon layer since WildFly 40 Beta release. Prerequisites To complete this guide, you need: Roughly 15 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ HashiCorp Vault server running Galleon provisioning tools WildFly server About HashiCorp Vault Integration The HashiCorp Vault feature-pack provides a dedicated WildFly subsystem for managing HashiCorp Vault credential stores. This integration currently allows you to: Store/retrieve credentials in HashiCorp Vault Reference Vault secrets from other subsystems using standard credential-reference attributes Usage of Vault secrets using ${HC_VAULT::credential-store-name:alias} expressions Manage credentials through WildFly management operations (add-alias, remove-alias, read-aliases) Note: The HashiCorp Vault layer is planned to be moved under the wildfly-ee feature-pack in the upcoming WildFly release. So usage of dedicated feature-pack will be deprecated. Quick Start Start HashiCorp Vault (Development Mode) To try it out, you need a running HashiCorp Vault server. For testing purposes, you can start Vault with Docker: docker run -p 8200:8200 -e 'VAULT_DEV_ROOT_TOKEN_ID=myroot' hashicorp/vault This starts Vault in development mode with an HTTP endpoint at http://localhost:8200 and root token myroot. For production, use a properly configured Vault server with TLS and secure token management. Step 1: Provision WildFly with the Feature-Pack Download the Galleon provisioning tools and use them to provision a WildFly server with the HashiCorp Vault subsystem. Run the following command, substituting the version with the latest version in Maven Central: galleon.sh install org.wildfly.security.vault:wildfly-vault-feature-pack:${version} \ --layers=hashicorp-vault \ --dir=wildfly This command creates a wildfly directory with a minimal WildFly server that contains the HashiCorp Vault subsystem for experimentation. Alternatively, when provisioning a recent WildFly Beta distribution, you can include the hashicorp-vault layer from the wildfly-galleon-pack feature-pack. Step 2: Start WildFly with Community Stability Start WildFly with the community stability flag: ./wildfly/bin/standalone.sh --stability=community Step 3: Configure a Credential Store and Store a Secret In another terminal, connect to the CLI and add a credential store that points at your Vault instance: $WILDFLY_HOME/bin/jboss-cli.sh --connect /subsystem=hashicorp-vault/credential-store=my-vault:add( host-address="http://localhost:8200", credential-reference={clear-text="myroot"} ) Store a secret in Vault through the subsystem (this creates the password key at path secret/demo): /subsystem=hashicorp-vault/credential-store=my-vault:add-alias( alias="secret/demo.password", secret-value="demo" ) List aliases under the secret path: /subsystem=hashicorp-vault/credential-store=my-vault:read-aliases( path="secret", recursive=true ) You should see secret/demo.password in the result. Returned aliases use the same path.key format described above. Alias Format Aliases map WildFly credential references to Vault secrets. The alias uses a dot: the segment before the dot is the Vault path, and the segment after is the secret key. Format: <vault-path>.<key> (exactly one dot) Example: secret/myapp.database_password maps to the database_password key at Vault path secret/myapp Vault paths may contain slashes; do not use additional dots in the path portion. Configure the HashiCorp Vault Credential Store The credential-store resource in the hashicorp-vault subsystem connects WildFly to your Vault server. Add a Credential Store (CLI) In production, use authentication-context attribute to specify authentication information. $WILDFLY_HOME/bin/jboss-cli.sh --connect /subsystem=hashicorp-vault/credential-store=my-vault:add( host-address="http://localhost:8200", credential-reference={clear-text="myroot"} ) Current Configuration Attributes Reference Attribute Required Description Example name Yes Unique name for the credential store my-vault host-address Yes Vault server URL including protocol and port https://vault.example.com:8200 namespace No Vault namespace (Enterprise feature) production authentication-context No Name of an Elytron authentication-context used for outbound TLS to Vault (trust store, client certificate, or mutual TLS) vault-tls-context credential-reference No Vault authentication token as clear text, or a reference to another credential store clear-text="myroot" The credential-reference and authentication-context child elements support the standard Elytron subsystem attributes. Securing the Connection with TLS Below example covers trust-only HTTPS (server TLS only). For mutual TLS, also add a client key-store, key-manager, and reference both managers on client-ssl-context. /subsystem=elytron/key-store=vault-trust:add( type=JKS, path=vault-trust.jks, relative-to=jboss.server.config.dir, credential-reference={clear-text=changeit} ) /subsystem=elytron/trust-manager=vault-trust-manager:add(key-store=vault-trust) /subsystem=elytron/client-ssl-context=vault-ssl:add( trust-manager=vault-trust-manager, cipher-suite-filter=DEFAULT ) /subsystem=elytron/authentication-context=vault-tls-context:add( match-rules=[{match-host=vault.example.com, ssl-context=vault-ssl}] ) Use the hostname from your Vault URL in match-host (for example vault.example.com when host-address is https://vault.example.com:8200). Add the credential store over HTTPS /subsystem=hashicorp-vault/credential-store=my-vault:add( host-address="https://vault.example.com:8200", authentication-context=vault-tls-context, credential-reference={clear-text="VAULT_TOKEN"} ) Using Credential Store References Once configured, reference the credential store from other subsystems using the standard credential-reference attributes. Example: Using with LDAP <subsystem xmlns="urn:wildfly:elytron:18.0"> <dir-contexts> <dir-context name="ldap-connection" url="ldap://ldap.example.com:389"> <credential-reference store="my-vault" alias="secret/ldap.bind_password"/> </dir-context> </dir-contexts> </subsystem> The store attribute references the credential store name (my-vault), and the alias attribute uses the path.key format described above. Vault Expressions Reference secrets using expressions of the form: ${HC_VAULT::credential-store-name:alias} For example, ${HC_VAULT::my-vault:secret/myapp.database_password} resolves the database_password key at path secret/myapp using the my-vault credential store. What’s next? Read more about Elytron credential stores in the WildFly Elytron Security documentation. Read about Vault configuration (TLS, namespaces, policies, and token lifecycle) using the HashiCorp Vault documentation. References HashiCorp Vault Documentation Galleon Documentation WildFly Elytron Credential Store Using Credential Stores to Replace Clear Text Passwords wildfly-elytron-hashicorp-vault wildfly-vault-feature-pack Note The HashiCorp Vault feature-pack is planned to be moved under the wildfly-ee feature-pack. You can Report issues on GitHub or reach the team on Zulip (#wildfly-elytron). ### [Securing WildFly Apps with Auth0 on OpenShift](/guides/security-oidc-auth0-openshift/) Securing WildFly Apps with Auth0 on OpenShift Table of Contents Prerequisites Example Application Log Into the OpenShift Cluster Configure Auth0 Add Helm Configuration Deploy the Example Application to WildFly on OpenShift Behind the Scenes Get the Application URL Finish Configuring Auth0 Access the Application What’s next? References You can secure your WildFly applications deployed on OpenShift with OpenID Connect (OIDC). By using OIDC to secure applications, you delegate authentication to OIDC providers. This guide shows how to secure an example application deployed to WildFly on OpenShift with OIDC using Auth0 as the OpenID provider. If you prefer to watch a video, check out this 5-minute video which also covers the steps from this guide. Prerequisites To complete this guide, you need: Roughly 15 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Access to an OpenShift cluster (try the Red Hat Developer Sandbox for free) OpenShift CLI Helm Chart Access to Auth0 Example Application We will use a simple web application in this guide that consists of a single servlet. We will secure this servlet using OIDC. We will use the example in the simple-webapp-auth0 directory in the elytron-examples repo. To obtain this example, clone the elytron-examples repository to your local machine: git clone git@github.com:wildfly-security-incubator/elytron-examples.git Log Into the OpenShift Cluster Before we can deploy our application, we need to log in to an OpenShift cluster. You can log in via the OpenShift CLI: oc login -u myUserName Alternatively, you can log in using an API token: oc login --token=myToken --server=myServerUrl You can request the token via the Copy Login Command link in the OpenShift web console. If you don’t already have a project created, you can create one using: oc new-project myProjectName Configure Auth0 We will be using Auth0 as our OpenID provider. Log into the Auth0 Dashboard. Create an application called OIDC App. For the application type, select Regular Web Applications and then click on Create. For more information, see the Auth0 documentation on how to create applications. Once the application has been created, we’ll see the Domain, Client ID, and Client Secret in the Basic Information section. We’ll make use of these values when we Add Helm Configuration later on. Using the sidebar menu on the left side of the Dashboard, navigate to the APIs page and copy the API Audience value. Using the sidebar menu on the left side of the Dashboard, navigate to the Settings page and scroll down to the API Authorization Settings. Paste the API Audience value you just copied into the Default Audience field and then click on Save. This will allow us to receive access tokens that are JWTs from Auth0. In the future, we’re hoping to add the ability to handle opaque access tokens as well to WildFly’s Elytron OIDC Client subsystem. Using the sidebar menu on the left side of the Dashboard, click on User Management and then Users. You can then create a new user by clicking on Create User. You’ll need to specify the new user’s email, we’ll use user@example.com. You’ll also need to set a password for the user. Once the user has been created, you’ll see the user’s user_id at the top of the page. For more information, see Auth0’s documentation on how to create users. Add Helm Configuration Switch to the charts directory in the simple-webapp-auth0 example. cd /PATH/TO/ELYTRON/EXAMPLES/simple-webapp-auth0/charts Notice there’s a helm.yaml file in this directory with the following content: build: uri: https://github.com/wildfly-security-incubator/elytron-examples.git contextDir: simple-webapp-auth0 deploy: env: - name: DOMAIN value: <AUTH0_DOMAIN> (1) - name: CLIENT_ID value: <AUTH0_CLIENT_ID> (2) - name: CLIENT_SECRET value: <AUTH0_CLIENT_SECRET> (3) You need to update the environment variable values here using the information we saw earlier in the Auth0 Dashboard, as described below. Replace <AUTH0_DOMAIN> with the Domain value from your OIDC App’s Basic Information section in the Auth0 Dashboard. Replace <AUTH0_CLIENT_ID> with the Client ID value from your OIDC App’s Basic Information section in the Auth0 Dashboard. Replace <AUTH0_CLIENT_SECRET> with the Client Secret value from your OIDC App’s Basic Information section in the Auth0 Dashboard. Deploy the Example Application to WildFly on OpenShift If you haven’t already installed the WildFly Helm chart, install it: helm repo add wildfly https://docs.wildfly.org/wildfly-charts/ If you’ve already installed the WildFly Helm Chart, be sure to update it to ensure you have the latest one: helm repo update We can deploy our example application to WildFly on OpenShift using the WildFly Helm Chart: helm install oidc-app -f /PATH/TO/ELYTRON/EXAMPLES/simple-webapp-auth0/charts/helm.yaml wildfly/wildfly Notice that this command specifies the file we updated, helm.yaml, that contains the values needed to build and deploy our application. The application will now begin to build. This will take a couple of minutes. The build can be observed using: oc get build -w Once complete, you can follow the deployment of the application using: oc get deployment oidc-app -w Alternatively, you can check status directly from the OpenShift web console. Behind the Scenes While our application is building, let’s take a closer look at our application. Examine the pom.xml file. Notice that it contains an openshift profile. A profile in Maven lets you create a set of configuration values to customize your application build for different environments. The openshift profile in this example defines a configuration that will be used by the WildFly Helm Chart when provisioning the WildFly server on OpenShift. <profiles> <profile> <id>openshift</id> <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <!--(1)--> <version>${version.wildfly.maven.plugin}</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.wildfly}</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:${version.wildfly.cloud.galleon.pack}</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>elytron-oidc-client</layer> <!--(2)--> </layers> <filename>simple-webapp-auth0.war</filename> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> wildfly-maven-plugin provisions a WildFly server with the specified layers with our application deployed. elytron-oidc-client automatically adds the native OIDC client subsystem to our WildFly installation. Examine the web.xml. ... <login-config> <auth-method>OIDC</auth-method> (1) </login-config> ... When the elytron-oidc-client subsystem sees the auth-method is set to OIDC, it enables the OIDC authentication mechanism for the application. Examine the oidc.json file. The oidc.json is used to configure the native OIDC client subsystem. { "client-id" : "${env.CLIENT_ID}", (1) "provider-url" : "https://${env.DOMAIN}", (2) "ssl-required" : "EXTERNAL", (3) "credentials" : { "secret" : "${env.CLIENT_SECRET}" (4) } } The client ID, which is specified using the CLIENT_ID environment variable we defined in the Helm configuration. The provider URL, which is specified using the DOMAIN environment variable. We defined its value in the Helm configuration. When ssl-required is set to EXTERNAL, HTTPS is required by default for external requests. The client secret is needed to communicate with Auth0. This refers to the CLIENT_SECRET environment variable that we defined in the Helm configuration. Get the Application URL Once the WildFly server has been provisioned, use the following command to find the URL for your example application: SIMPLE_WEBAPP_AUTH0_URL=https://$(oc get route oidc-app --template='{{ .spec.host }}') && echo "" && echo "Application URL: $SIMPLE_WEBAPP_AUTH0_URL/simple-webapp-auth0" && echo "Allowed Callback URL: $SIMPLE_WEBAPP_AUTH0_URL/simple-webapp-auth0/secured/*" && echo "" We’ll make use of these URLs in the next two sections. Finish Configuring Auth0 From your OIDC App in the Auth0 Dashboard, scroll down to the Application URIs section and set Allowed Callback URLs to the Allowed Callback URL that was output in the previous section. Then click on Save Changes. Access the Application From your browser, navigate to the Application URL that was output in the previous section. Click on Access Secured Servlet. You will be redirected to Auth0 to log in. Log in using the user@example.com user we created earlier. Upon successful authentication, you will be redirected back to the example application. The example application simply outputs the user_id of the logged in user. You should see output similar to the following: Secured Servlet Current Principal 'auth0|6544f9aa427fb9f276240d55' Notice the user_id for our user@example.com user is displayed. This indicates that we have successfully logged into our application! What’s next? This guide has shown how to secure an application deployed to WildFly on OpenShift using the Auth0 OpenID provider. For additional information, feel free to check out the resources linked below. To learn more about OIDC configuration, check out the Elytron OIDC Client documentation. References Vlog: Securing WildFly Apps with Auth0 on OpenShift Getting started with Auth0 Elytron OpenID Connect Client Subsystem Configuration Getting Started with WildFly on OpenShift OpenShift CLI WildFly Helm Chart Securing WildFly Apps with OIDC on OpenShift ### [guides/security-oidc-elytron-manual.adoc](/guides/security-oidc-elytron-manual/) Configuring More Advanced OIDC Use Cases with the Elytron Subsystem Table of Contents Prerequisites Note Server configuration changes Configure an OIDC realm Configure a security domain that references the OIDC realm Configure an HTTP server mechanism factory Configure an HTTP authentication factory Configure application-security-domain mapping Application changes Reference the security domain in jboss-web.xml Add the OIDC configuration listener in web.xml Add the Elytron HTTP OIDC dependency and module Example of combining OIDC with LDAP security realm and BASIC mechanism References WildFly can secure applications with OpenID Connect (OIDC) using the elytron-oidc-client subsystem and deployment descriptors, which is the typical approach. For more advanced control where you need to configure elytron subsystem resources as well—such as combining OIDC with other authentication mechanisms and security realms, you have to configure OIDC in the Elytron subsystem. This guide shows how to do that. Prerequisites To complete this guide, you need: Roughly 20 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ A WildFly installation that includes the Elytron HTTP OIDC module (e.g. provisioned with the elytron-oidc-client Galleon layer or equivalent) An OpenID Connect provider (e.g. Keycloak) configured with a client for your application Note Use this manual configuration approach if you need to combine with other elytron subsystem resources. This approach is not recommended if a deployment-level or elytron-oidc-client subsystem configuration is sufficient and no elytron subsystem configuration is needed. Server configuration changes The following steps enable the OIDC mechanism using the Elytron subsystem. Configure an OIDC realm /subsystem=elytron/custom-realm=myOidcRealm:add(module=org.wildfly.security.elytron-http-oidc, class-name=org.wildfly.security.http.oidc.OidcSecurityRealm) Configure a security domain that references the OIDC realm /subsystem=elytron/security-domain=myDomain:add(default-realm=myOidcRealm, permission-mapper=default-permission-mapper, realms=[{realm=myOidcRealm}]) Configure an HTTP server mechanism factory /subsystem=elytron/service-loader-http-server-mechanism-factory=myFactory:add(module=org.wildfly.security.elytron-http-oidc) Configure an HTTP authentication factory /subsystem=elytron/http-authentication-factory=myMechanism:add(http-server-mechanism-factory=myFactory, security-domain=myDomain, mechanism-configurations=[{mechanism-name=OIDC}]) Configure application-security-domain mapping /subsystem=undertow/application-security-domain=myDomain:add(http-authentication-factory=myMechanism, override-deployment-config=true) Application changes This approach requires use of oidc.json file (to configure OIDC provider settings) that will be included in your WAR deployment’s WEB-INF folder. Inability to use the elytron oidc client subsystem configuration is a limitation of this approach. Reference the security domain in jboss-web.xml In WEB-INF/jboss-web.xml, reference the security domain you created: <security-domain>myDomain</security-domain> Add the OIDC configuration listener in web.xml Register the OIDC configuration servlet listener in WEB-INF/web.xml: <listener> <listener-class>org.wildfly.security.http.oidc.OidcConfigurationServletListener</listener-class> </listener> Add the Elytron HTTP OIDC dependency and module Add the dependency to your application (e.g. in pom.xml for Maven): <dependency> <groupId>org.wildfly.security</groupId> <artifactId>wildfly-elytron-http-oidc</artifactId> <scope>provided</scope> </dependency> Declare the module dependency in WEB-INF/jboss-deployment-structure.xml (or META-INF/jboss-deployment-structure.xml): <jboss-deployment-structure> <deployment> <dependencies> <module name="org.wildfly.security.elytron-http-oidc"/> </dependencies> </deployment> </jboss-deployment-structure> Example of combining OIDC with LDAP security realm and BASIC mechanism For this example, you will combine OIDC with another authentication mechanism such as BASIC against an LDAP realm. Below is required to achieve this: Add an LDAP dir-context and ldap-realm in the Elytron subsystem. Add both custom OIDC and LDAP realms to the security domain and create constant realm mappers for each (e.g. oidc-mapper and ldap-mapper). Use an aggregate HTTP server mechanism factory that includes both a BASIC-capable factory (e.g. a configurable factory with silent=true for BASIC) and the OIDC service-loader factory. In the HTTP authentication factory, set mechanism-configurations so that OIDC uses the OIDC realm mapper and BASIC uses the LDAP realm mapper (and the appropriate mechanism-realm-configurations). Full example CLI commands to combine OIDC with silent BASIC mechanism and an LDAP security realm (adjust LDAP URL and credentials for your environment): /subsystem=elytron/custom-realm=myOidcRealm:add(module=org.wildfly.security.elytron-http-oidc, class-name=org.wildfly.security.http.oidc.OidcSecurityRealm) /subsystem=elytron/dir-context=myLdapContext:add(url="ldap://LDAP_CONTAINER_IP:389", principal="cn=admin,dc=example,dc=com", credential-reference={clear-text="admin"} ) /subsystem=elytron/ldap-realm=myLdapRealm:add(dir-context=myLdapContext, direct-verification=true, identity-mapping= { search-base-dn="ou=Users,dc=example,dc=com", rdn-identifier="cn", user-password-mapper= {from="userPassword"}}) /subsystem=elytron/security-domain=myDomain:add(default-realm=myOidcRealm, permission-mapper=default-permission-mapper, realms=[{realm=myLdapRealm},{realm=myOidcRealm}]) /subsystem=elytron/constant-realm-mapper=ldap-mapper:add(realm-name="myLdapRealm") /subsystem=elytron/constant-realm-mapper=oidc-mapper:add(realm-name="myOidcRealm") /subsystem=elytron/provider-http-server-mechanism-factory=authMechanisms:add(providers=elytron) /subsystem=elytron/configurable-http-server-mechanism-factory=silentBasic:add(http-server-mechanism-factory=authMechanisms,properties={silent=true},filters=[{pattern-filter=BASIC}]) /subsystem=elytron/service-loader-http-server-mechanism-factory=myOidcFactory:add(module=org.wildfly.security.elytron-http-oidc) /subsystem=elytron/aggregate-http-server-mechanism-factory=myAggregateHttpFactory:add(http-server-mechanism-factories=[silentBasic,myOidcFactory]) /subsystem=elytron/http-authentication-factory=myMechanism:add(http-server-mechanism-factory=myAggregateHttpFactory,security-domain=myDomain,mechanism-configurations=[ {mechanism-name=OIDC, realm-mapper=oidc-mapper}, {mechanism-name=BASIC, realm-mapper=ldap-mapper,mechanism-realm-configurations=[{realm-name=myDomain,realm-mapper=ldap-mapper}]}]) /subsystem=undertow/application-security-domain=myDomain:add(http-authentication-factory=myMechanism,override-deployment-config=true) Now you can deploy your application containing oidc.json to the server. References WildFly Elytron Security Securing WildFly Apps with OIDC on OpenShift ### [Identity Propagation with OpenID Connect](/guides/security-oidc-identity-propagation/) Identity Propagation with OpenID Connect Table of Contents Prerequisites Overview of Identity Propagation with OIDC Securing an EJB using the Same OIDC Virtual Security Domain Securing an EJB using a Different Security Domain Example Applications Start Keycloak Secure an EJB Invoked by an OIDC App using a Different Security Domain Inspect the Example Applications Start WildFly Configure the Security Domain that will be used to Secure the EJB (BusinessDomain) Configure Identity Propagation Deploy the Example Application to WildFly Finish Configuring Keycloak Access the Application Secure an EJB Invoked by an OIDC App using the Same Virtual Security Domain Inspect the Example Applications Start WildFly Configure the Virtual Security Domain that will be used to Secure the EJB Configure Identity Propagation Deploy the Example Application to WildFly Finish Configuring Keycloak Access the Application What’s next? References When securing an application with OpenID Connect (OIDC), WildFly automatically creates and makes use of a virtual security domain across the deployment. If the application invokes an EJB, additional configuration might be required in order to propagate the security identity from the virtual security domain. The configuration that’s needed depends on how the EJB that’s being invoked is secured. This guide covers the different use cases for propagating an identity from a virtual security domain. Prerequisites To complete this guide, you need: Roughly 15 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Keycloak Overview of Identity Propagation with OIDC Additional configuration might be needed in order to propagate a security identity from a virtual security domain depending on how the EJB that’s being invoked is secured. Securing an EJB using the Same OIDC Virtual Security Domain Within the Same Deployment If a web application secured with OIDC invokes an EJB within the same deployment (e.g., within the same WAR or EAR) and you’d like to secure the EJB using the same virtual security domain as the web application, no additional configuration is required. Both of examples that we’ll be going through cover this use case. Across Deployments If a web application secured with OIDC invokes an EJB in a separate deployment (e.g., across EARs) and you’d like to secure the EJB using the same virtual security domain as the web application, the following configuration is needed: A virtual-security-domain resource needs to be added in the Elytron subsystem. The EJB being invoked needs to be updated with a @SecurityDomain annotation that references the virtual-security-domain. For a guided step by step example of how to configure this use case, see Secure an EJB Invoked by an OIDC App using the Same Virtual Security Domain. Securing an EJB using a Different Security Domain If a web application secured with OIDC invokes an EJB (either in the same deployment or in a separate deployment) and you’d like to secure the EJB using a different security domain from the web application, the following configuration is needed: A virtual-security-domain resource needs to be added in the Elytron subsystem. This indicates the list of security domains that a virtual security domain should automatically outflow its security identities to. A trusted-virtual-security-domains attribute needs to be configured for the security-domain that is being used to secure the EJB being invoked. This indicates that the security-domain should trust any security identities that have been established by the specified virtual security domains. For a guided step by step example of how to configure this use case, see Securing an EJB using a Different Security Domain. Example Applications We will use some simple web applications in this guide that consist of a servlet secured using OIDC. The servlet will invoke an EJB within the same deployment (i.e., invocation within the same EAR). This EJB will then invoke another EJB located in a different deployment (i.e., invocation across EARs). We will use the oidc-with-identity-propagation and oidc-with-identity-propagation-same-domain examples from the elytron-examples repository: oidc-with-identity-propagation oidc-with-identity-propagation-same-domain To obtain the examples, clone the elytron-examples repository to your local machine: git clone git@github.com:wildfly-security-incubator/elytron-examples.git Start Keycloak This guide will be making use of Keycloak as our OpenID provider. To start a Keycloak server in your environment, follow the appropriate guide for your environment from Keycloak’s Getting Started page. :add-role: == Configure Keycloak Log into the Keycloak Admin Console. Create a new realm called myrealm. For more information, see the Keycloak documentation on how to create a realm. Add a new user named alice. For more information, see the Keycloak documentation on how to create a user. Once the new user has been created, set a password for this new user from the Credentials tab. Create a new client as follows: General Settings: Client type (or Client Protocol, depending on your Keycloak version): OpenID Connect Client ID: myclient Capability config: Authentication flow: Standard flow, Direct access grants Login settings: Leave the fields blank for now. For more information, see the Keycloak documentation on how to Manage OpenID Connect clients. Click Save to save the client. Secure an EJB Invoked by an OIDC App using a Different Security Domain For this use case, we’ll be using the oidc-with-identity-propagation example. Inspect the Example Applications Let’s take a closer look at our example. This example consists of two EARs when built: virtual-security-domain-to-domain.ear and ejb-basic.ear. Notice that virtual-security-domain-to-domain.ear contains a servlet that invokes an EJB, EntryBean, that’s also contained in the same EAR. This EJB doesn’t have any explicit security domain configuration. Thus, this EJB will automatically be secured using the same virtual security domain as the servlet. The EntryBean invokes another EJB, ManagementBean, that’s part of ejb-basic.ear. Notice that ManagementBean has a @SecurityDomain("BusinessDomain") annotation. Because the ManagementBean is being secured using a security domain that’s different from the virtual security domain that’s being used to secure the web application, we’ll need to add configuration to propagate security identities from the virtual security domain to the BusinessDomain. Start WildFly First, we need to start our WildFly instance. We’ll specify a port offset since our Keycloak instance is exposed on port 8080: ./bin/standalone.sh -Djboss.socket.binding.port-offset=10 Configure the Security Domain that will be used to Secure the EJB (BusinessDomain) We’re going to secure the EJB being invoked with a security domain called BusinessDomain. To create this security domain, we’ll connect to the WildFly CLI and execute the CLI commands shown below. ./bin/jboss-cli.sh --connect --controller=localhost:10000 # Add a filesystem realm called BusinessRealm in the jboss.server.config directory /subsystem=elytron/filesystem-realm=BusinessRealm:add(path=business-realm-users,relative-to=jboss.server.config.dir) # Add user alice with Admin role /subsystem=elytron/filesystem-realm=BusinessRealm:add-identity(identity=alice) /subsystem=elytron/filesystem-realm=BusinessRealm:add-identity-attribute(identity=alice, name=Roles, value=["Admin"]) # Add a security domain that references our newly created realm /subsystem=elytron/security-domain=BusinessDomain:add(realms=[{realm=BusinessRealm}],default-realm=BusinessRealm,permission-mapper=default-permission-mapper) # Update the application security domain mapping in the EJB3 subsystem /subsystem=ejb3/application-security-domain=BusinessDomain:add(security-domain=BusinessDomain) reload Configure Identity Propagation First, let’s configure a virtual-security-domain in the Elytron subsystem to specify that we want to automatically outflow any security identities established by the virtual security domain to the BusinessDomain: /subsystem=elytron/virtual-security-domain=virtual-security-domain-to-domain.ear:add(outflow-security-domains=[BusinessDomain]) Next, let’s update the BusinessDomain to specify that we want to trust any security identities established by the virtual security domain associated with virtual-security-domain-to-domain.ear: /subsystem=elytron/security-domain=BusinessDomain:write-attribute(name=trusted-virtual-security-domains, value=[virtual-security-domain-to-domain.ear]) Finally, let’s execute a reload: reload Deploy the Example Application to WildFly We’re now going to build and deploy our example. From the elytron-examples directory, run the following commands to build and deploy the ejb-basic.ear and virtual-security-domain-to-domain.ear: cd YOUR_PATH_TO_ELYTRON_EXAMPLES/oidc-with-identity-propagation/ejb-basic mvn clean install wildfly:deploy -Dwildfly.port=10000 cd YOUR_PATH_TO_ELYTRON_EXAMPLES/oidc-with-identity-propagation/virtual-security-domain-to-domain mvn clean install wildfly:deploy -Dwildfly.port=10000 Finish Configuring Keycloak From your myclient client in the Keycloak Administration Console, in the client settings, set Valid redirect URIs to http://localhost:8090/virtual-security-domain-to-domain/secured and then click Save. Access the Application From your browser, navigate to http://localhost:8090/virtual-security-domain-to-domain. Click on Access Secured Servlet. You will be redirected to Keycloak to log in. Log in using the alice user we created earlier. Upon successful authentication, you will be redirected back to the example application. The example application outputs information about the user. You should see the following output: Successfully logged into Secured Servlet with OIDC Identity as visible to servlet. Principal : alice Authentication Type : OIDC Caller Has Role 'User'=true Caller Has Role 'Admin'=false Identity as visible to EntryBean. Principal : alice Caller Has Role 'User'=true Caller Has Role 'Admin'=false Identity as visible to ManagementBean. Principal : alice Caller Has Role 'User'=false Caller Has Role 'Admin'=true Notice the following things: The identity as visible to the servlet and the EJB within virtual-security-domain-to-domain.ear is alice with User role. This shows that the identity from the virtual security domain was successfully propagated to the EJB within the same EAR. The identity as visible to the EJB within ejb-basic.ear is alice with Admin role. This shows that the identity from the virtual security domain was successfully propagated to the BusinessDomain that’s used to secure the EJB in a separate deployment. Secure an EJB Invoked by an OIDC App using the Same Virtual Security Domain For this use case, we’ll be using the oidc-with-identity-propagation-same-domain example. Inspect the Example Applications Let’s take a closer look at our example. This example consists of two EARs when built: same-virtual-domain.ear and ejb-same-domain.ear. Notice that same-virtual-domain.ear contains a servlet that invokes an EJB, EntryBean, that’s also contained in the same EAR. This EJB doesn’t have any explicit security domain configuration. Thus, this EJB will automatically be secured using the same virtual security domain as the servlet. The EntryBean invokes another EJB, WhoAmIBean, that’s part of ejb-same-domain.ear. Because we want to secure the WhoAmIBean with the same virtual security domain that’s being used to secure the web application, we’ll need to add configuration to accomplish this. Start WildFly First, we need to start our WildFly instance. We’ll specify a port offset since our Keycloak instance is exposed on port 8080: ./bin/standalone.sh -Djboss.socket.binding.port-offset=10 Configure the Virtual Security Domain that will be used to Secure the EJB We’re going to secure the EJB being invoked with the same virtual security domain that’s being used to secure the web application with OIDC. We first need to connect to the WildFly CLI and add a virtual-security-domain resource in the Elytron subsystem as follows: ./bin/jboss-cli.sh --connect --controller=localhost:10000 # Add a virtual security domain resource for the same-virtual-domain.ear application /subsystem=elytron/virtual-security-domain=same-virtual-domain.ear:add() Configure Identity Propagation Next, let’s update the WhoAmIBean to indicate that we want to secure it using the same virtual domain that’s being used to secure same-virtual-domain.ear: @SecurityDomain("same-virtual-domain.ear") public class WhoAmIBean implements WhoAmI { ... } Deploy the Example Application to WildFly We’re going to build and deploy our example. From the elytron-examples directory, run the following commands to build and deploy the ejb-same-domain.ear and same-virtual-domain.ear: cd YOUR_PATH_TO_ELYTRON_EXAMPLES/oidc-with-identity-propagation-same-domain/ejb-same-domain mvn clean install wildfly:deploy -Dwildfly.port=10000 cd YOUR_PATH_TO_ELYTRON_EXAMPLES/oidc-with-identity-propagation-same-domain/same-virtual-domain mvn clean install wildfly:deploy -Dwildfly.port=10000 Finish Configuring Keycloak From your myclient client in the Keycloak Administration Console, in the client settings, set Valid redirect URIs to http://localhost:8090/same-virtual-domain/secured and then click Save. Access the Application From your browser, navigate to http://localhost:8090/same-virtual-domain. Click on Access Secured Servlet. You will be redirected to Keycloak to log in. Log in using the alice user we created earlier. Upon successful authentication, you will be redirected back to the example application. The example application outputs information about the user. You should see the following output: Successfully logged into Secured Servlet with OIDC Identity as visible to servlet. Principal : alice Authentication Type : OIDC Caller Has Role 'User'=true Caller Has Role 'Admin'=false Identity as visible to EntryBean. Principal : alice Caller Has Role 'User'=true Caller Has Role 'Admin'=false Identity as visible to ManagementBean. Principal : alice Caller Has Role 'User'=true Caller Has Role 'Admin'=false Notice the following things: The identity as visible to the servlet and the EJB within same-virutal-domain.ear is alice with User role. This shows that the identity from the virtual security domain was successfully propagated to the EJB within the same EAR. The identity as visible to the EJB within ejb-same-domain.ear is alice with User role. This shows that the identity from the virtual security domain was successfully propagated to the EJB in a separate deployment. What’s next? This guide shown how to propagate security identities established by a virtual security domain within a deployment and across deployments when securing a web application with OIDC. To learn more about OIDC configuration, check out the Elytron OIDC Client documentation. References OIDC Identity Propagation Elytron OpenID Connect Client Subsystem Configuration Keycloak Server Administration Guide Securing WildFly Apps with OIDC on OpenShift ### [Securing the WildFly Management Console with OpenID Connect](/guides/security-oidc-management-console/) Securing the WildFly Management Console with OpenID Connect Table of Contents Prerequisites Start Keycloak Configure Keycloak Configure Elytron OIDC Client Accessing the WildFly Management Console What’s next? References You can secure the WildFly Management Console with OpenID Connect (OIDC) using the Keycloak OpenID provider. When the WildFly Management Console is secured using OIDC, this means that when a user attempts to access the console, they will be redirected to the Keycloak OpenID provider’s login page. Upon successful authentication, the user will then be redirected back to the WildFly Management Console. This guide explains how to configure this. Prerequisites To complete this guide, you need: Roughly 15 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Keycloak Start Keycloak This guide will be making use of Keycloak as our OpenID provider. To start a Keycloak server in your environment, follow the appropriate guide for your environment from Keycloak’s Getting Started page. Configure Keycloak Log into the Keycloak Admin Console. Create a new realm called wildfly-infra. For more information, see the Keycloak documentation on how to create a realm. Create a new client as follows: General Settings: Client type (or Client Protocol, depending on your Keycloak version): OpenID Connect Client ID: wildfly-console Capability config: Authentication flow: Standard flow, Direct access grants Login settings: Set the Valid redirect URIs using the URI that will be used to access the WildFly Management Console. Since we will use a port offset of 10 when starting WildFly in this guide, we will set the Valid redirect URIs to http://localhost:10000/console/*. Set the Web Origins using the management port for our WildFly instance, e.g., http://localhost:10000. For more information, see the Keycloak documentation on how to Manage OpenID Connect clients. Click Save to save the client. Create a second new client as follows: General Settings: Client type (or Client Protocol, depending on your Keycloak version): OpenID Connect Client ID: wildfly-management Capability config: Authentication flow: This client will be a bearer-only client, be sure to uncheck Standard flow and uncheck Direct access grants. Login settings: Leave the fields blank. For more information, see the Keycloak documentation on how to Manage OpenID Connect clients. Click Save to save the client. [Optional] If you want to configure WildFly to use Role Based Access Control, add a role called Administrator. For more information, see the Keycloak documentation on how to create a role. Add a new user named alice. For more information, see the Keycloak documentation on how to create a user. Once the new user has been created, set a password for this new user from the Credentials tab. [Optional] If you want to configure WildFly to use Role Based Access Control, from the Role Mapping tab, assign alice the Administrator role. For more information, see the Keycloak documentation on how to assign a role to a user. Configure Elytron OIDC Client Now that we’ve configured our OpenID provider, there are a couple things that need to be configured in the elytron-oidc-client subsystem to secure the WildFly Management Console with OIDC. First, we need to add a secure-deployment resource that references the wildfly-management client that was created in the previous section. A secure-server that references the wildfly-console client is also needed. We can use the following commands to add the required configuration: First, we need to start our WildFly server instance. Notice that we’re specifying a port offset here since our Keycloak instance is already exposed on port 8080: ./bin/standalone.sh -Djboss.socket.binding.port-offset=10 Next, we can connect to the WildFly CLI and then execute the commands below: ./bin/jboss-cli.sh --connect --controller=localhost:10000 # Configure the Keycloak provider /subsystem=elytron-oidc-client/provider=keycloak:add(provider-url=http://localhost:8080/realms/wildfly-infra) # Create a secure-deployment in order to secure the management interface with bearer token authentication /subsystem=elytron-oidc-client/secure-deployment=wildfly-management:add(provider=keycloak,client-id=wildfly-management,principal-attribute=preferred_username,bearer-only=true,ssl-required=EXTERNAL) # (Optional) Enable RBAC where roles are obtained from the identity /core-service=management/access=authorization:write-attribute(name=provider,value=rbac) /core-service=management/access=authorization:write-attribute(name=use-identity-roles,value=true) # Create a secure-server to ensure that the WildFly Management Console will redirect to the Keycloak OpenID provider for log in /subsystem=elytron-oidc-client/secure-server=wildfly-console:add(provider=keycloak,client-id=wildfly-console,public-client=true) reload Accessing the WildFly Management Console With the above configuration now in place, let’s access http://localhost:10000/console. We will be redirected to the Keycloak login page. We can log in using the alice user that we created earlier. Upon successful authentication, we will be redirected back to the WildFly Management Console. What’s next? This guide has shown how to secure the WildFly Management Console with OIDC. To learn more about OIDC configuration, check out the Elytron OIDC Client documentation. References Elytron OpenID Connect Client Subsystem Configuration Getting Started with Keycloak Keycloak Server Administration Guide Securing WildFly Apps with OIDC on OpenShift ### [Securing WildFly Applications Using Okta on OpenShift](/guides/security-oidc-okta-openshift/) Securing WildFly Applications Using Okta on OpenShift Table of Contents Prerequisites Example Application Log Into the OpenShift Cluster Configure Okta Advanced OpenID Configuration Add Helm Configuration Configure the Deployment Settings Deploy the Example Application to WildFly on OpenShift Behind the Scenes Get the Application URL Finish Configuring Okta Access the App What’s next? References WildFly applications can be secured using OpenID Connect (OIDC) and deployed to OpenShift. By using OIDC to secure applications, you delegate authentication to OIDC providers. The elytron-oidc-client subsystem can be used to secure an application deployed to WildFly using any OpenID Provider. This guide demonstrates how to secure an example application deployed to WildFly on OpenShift using Okta as the OpenID Provider. Prerequisites To complete this guide, you need: Roughly 15 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Roughly 15 minutes Access to an OpenShift cluster (try the Red Hat Developer Sandbox for free) OpenShift CLI Helm Chart Okta OpenID Provider Example Application We will use a simple web application in this guide that consists of a single servlet. We will use the simple-webapp-okta application in this repository. We will need to first fork, and then clone the elytron-examples repository. We will be using the simple-webapp-okta directory in this repo: git clone git@github.com:wildfly-security-incubator/elytron-examples.git cd simple-webapp-okta Log Into the OpenShift Cluster Before we can deploy our application, we need to log in to an OpenShift cluster. You can log in via the OpenShift CLI: oc login -u myUserName Alternatively, you can log in using an API token: oc login --token=myToken --server=myServerUrl You can request the token via the Copy Login Command link in the OpenShift web console. If you don’t already have a project created, you can create one using: oc new-project myProjectName Configure Okta For this guide, we will be using Okta as our OpenID provider. In order to secure the application, we will need to access the Okta web console and register our application as a client. The following set of steps outlines how to register an OpenID web-application with Okta: Log in to the Okta dashboard to get started. At the top right corner, click on Admin to be redirected to the admin dashboard. On the left hand panel, from the Applications drop down, click on Applications and then Create App Integration. Choose OIDC - OpenID Connect under Sign-in method and Web Application for Application type and click Next. Under General Settings add the following configurations: App integration name: simple-webapp-okta Grant type: Leave it as is, with Authorization Code checked. Sign-in redirect URIs: Leave it as is for now. We will edit it later. Under the Assignments tab, for Controlled access, select Skip group assignment for now. Click Save. You can find more information about configuring settings for app integration on Okta here. Next, we will be adding a user to our directory, and add them to the previously created application using the following steps: Navigate to the Directory drop down on the left panel and click People. Click Add person and add a person with: First name: Alice Last name: Smith Email: alice@example.org User Name: alice@example.org From the dropdown list for Password, choose Set by admin and set a password that fits the password requirements. Uncheck User must change password on first login and hit Save. For more information about how to add a user manually click here. Click on the Applications tab on the left hand side. Navigate to Applications and click on simple-webapp-okta. Under the Assignments tab, click on Assign, then click on Assign to People and select Alice. For more information about how to assign a user to an application, please see here. For more information about managing users on Okta, please see here. Advanced OpenID Configuration In order to extract the user information through the id token, we will need to configure a custom authorization server. Follow the steps below for this: Under the Security dropdown, select API and click on the edit button next to the Default server. Under the Claims tab, click on the Add Claim button and to add a claim with the following configurations: Name: IDTClaim Include in token type: ID Token and keep it at always. Value type: Expression Value: appuser.userName and hit Save. We will be using this claim later to extract the username of the user who is currently logged in. You can learn more about Okta Expression Language here. . Now go back to the API menu and copy the Issuer URI for the Default server. . This will be used as the provider url when configuring our WildFly application. For more information about Customizing tokens returned from Okta, please refer to this guide. Add Helm Configuration Keep the URL obtained from the last step. Switch to the charts directory in the simple-webapp-okta example. cd /PATH/TO/ELYTRON/EXAMPLES/simple-webapp-okta/charts Notice there’s a helm.yaml file in this directory with the following content: build: uri: https://github.com/wildfly-security-incubator/elytron-examples.git contextDir: simple-webapp-okta deploy: replicas: 1 env: - name: OIDC_PROVIDER_URL value: <OKTA_URL> (1) - name: OIDC_CLIENT_ID value: <CLIENT_ID> (2) - name: OIDC_CLIENT_SECRET value: <CLIENT_SECRET> (3) We will need to make the following changes locally to the helm chart: Replace OKTA_URL with the provider url you copied in the last step. Replace CLIENT_ID with the Client ID listed on the Okta console. Navigate to the General tab for our application on the Okta admin console and copy the Client Id and add it beside the client-id attribute. Replace CLIENT_SECRET with your Client Secret for this application listed on Okta. Save this file and close it. Configure the Deployment Settings Applications deployed to WildFly can be secured with OIDC in a couple different ways: Using deployment configuration by specifying the attribute values inside oidc.json or using the elytron-oidc-client subsystem. This guide uses the deployment configuration, but you can use the same attributes to configure the elytron-oidc-client subsystem. You can learn more about the elytron-oidc-client subsystem here. You can view the deployment configuration used in this example by navigating to the oidc.json file. Note that we are making use of the environment variables we defined in the helm chart. Now that we have added the required changes, we can deploy our application, the helm chart will specify the location for this example application and pull information needed for our deployment specified in the oidc.json file. Deploy the Example Application to WildFly on OpenShift If you haven’t already installed the WildFly Helm chart, install it: helm repo add wildfly https://docs.wildfly.org/wildfly-charts/ If you’ve already installed the WildFly Helm Chart, be sure to update it to ensure you have the latest one: helm repo update We can deploy our example application to WildFly on OpenShift using the WildFly Helm Chart: helm install oidc-app -f /PATH/TO/ELYTRON/EXAMPLES/simple-webapp-saml/charts/helm.yaml wildfly/wildfly Notice that this command specifies the file we updated, helm.yaml, that contains the values needed to build and deploy our application. The application will now begin to build. This will take a couple of minutes. The build can be observed using: oc get build -w Once complete, you can follow the deployment of the application using: oc get deployment oidc-app -w Alternatively, you can check status directly from the OpenShift web console. Behind the Scenes While our application is building, let’s take a closer look at our application. Examine the pom.xml file. Notice that it contains an openshift profile. A profile in Maven lets you create a set of configuration values to customize your application build for different environments. The openshift profile in this example defines a configuration that will be used by the WildFly Helm Chart when provisioning the WildFly server on OpenShift. <profiles> <profile> <id>openshift</id> <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> (1) <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.wildfly}</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:${version.wildfly.cloud.galleon.pack}</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>elytron-oidc-client</layer> (2) </layers> <filename>simple-webapp-okta.war</filename> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> wildfly-maven-plugin provisions a WildFly server with the specified layers with our application deployed. elytron-oidc-client automatically adds the native OIDC client subsystem to our WildFly installation. Now examine the web.xml file. <login-config> <auth-method>OIDC</auth-method> (1) </login-config> When the elytron-oidc-client subsystem sees auth-method is set to OIDC, it enables OIDC authentication mechanism for the application. Finally, review the oidc.json file. The oidc.json is used to configure the native OIDC client subsystem. { "client-id" : "${env.CLIENT_ID}", (1) "provider-url" : "${env.OIDC_PROVIDER_URL}", (2) "public-client" : "false", (3) "principal-attribute" : "IDTClaim", (4) "ssl-required" : "EXTERNAL", (5) "credentials" : { "secret" : "${env.CLIENT_SECRET}" (6) } } Client_ID is the unique identifier for our client used by the Okta OpenID provider. Usually for Keycloak, you can create your own client, but for Okta, you are assigned an id. As a result, we are using environment variables to specify this. The provider URL, which is the URL for the authorization server that we created, is specified as an environment variable. We set its value previously in the helm configuration. When public-client set to false, client credentials are sent when communicating with the OpenID provider. We specify that the user name of the identity, which in our case is alice, is to be used as the principal for the identity. We are extracting this information here using a custom claim in the ID token. When ssl-required is set to EXTERNAL, only the communication with external clients happens over HTTPs. Client credentials helps the OIDC server authenticate the client when accepting a request. It is required when public-client is set to false. Get the Application URL Once the pod running your WildFly server has been provisioned, use the following command to find the URL for your example application: SIMPLE_WEBAPP_OKTA_URL=https://$(oc get route oidc-app --template='{{ .spec.host }}') && echo "" && echo "Application URL: $SIMPLE_WEBAPP_OKTA_URL/simple-webapp-okta" && echo "Valid redirect URI: $SIMPLE_WEBAPP_OKTA_URL/simple-webapp-okta/secured/" && echo "" We’ll make use of these URLs in the next two sections. Finish Configuring Okta Go back to the General Settings for your application and click on Edit. add the Valid redirect URI under the Sign-in redirect URIs and check the Allow wildcard * in login URI redirect field and hit Save. Access the App Now we can access our application using the Application Url from the previous section. Click on "Access Secured Servlet". Now you will be redirected to the login page for Okta. Login using Alice. You will be prompted for the username. Although we set the username to be alice@example.org, we can just input alice here. You will be presented with three options for loggin in. Choose Password and enter the password you selected for Alice. What’s next? This guide demonstrates how to use an OpenID provider other than Keycloak to secure an application deployed to WildFly. Other OpenID providers can be used to secure WildFly applications as well. And while the specific terms may be slightly different, the overall process should be similar. Please refer to documentations by your OpenID provider for more information. References Okta Documentation Okta Quickstarts Elytron-oidc-client subsystem elytron-oidc-client docs OpenID Specifications Guides Related on Configuring Okta Getting Started with WildFly on OpenShift OpenShift CLI WildFly Helm Charts Securing WildFly Apps with OIDC on OpenShift ### [guides/security-oidc-openshift.adoc](/guides/security-oidc-openshift/) Securing WildFly Apps with OIDC on OpenShift Table of Contents Prerequisites Example Application Log Into the OpenShift Cluster Start Keycloak OpenShift CLI OpenShift Web Console Configure Keycloak Add Helm Configuration Deploy the Example Application to WildFly on OpenShift Behind the Scenes Get the Application URL Finish Configuring Keycloak Access the Application What’s next? References You can secure your WildFly applications deployed on OpenShift with OpenID Connect (OIDC). By using OIDC to secure applications, you delegate authentication to OIDC providers. This guide shows how to secure an example application deployed to WildFly on OpenShift with OIDC using Keycloak as the OpenID provider. Prerequisites To complete this guide, you need: Roughly 15 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Access to an OpenShift cluster (try the Red Hat Developer Sandbox for free) OpenShift CLI Helm Chart Example Application We will use a simple web application in this guide that consists of a single servlet. We will secure this servlet using OIDC. We will use the example in the simple-webapp-oidc directory in the elytron-examples repo. To obtain this example, clone the elytron-examples repository to your local machine: git clone git@github.com:wildfly-security-incubator/elytron-examples.git Log Into the OpenShift Cluster Before we can deploy our application, we need to log in to an OpenShift cluster. You can log in via the OpenShift CLI: oc login -u myUserName Alternatively, you can log in using an API token: oc login --token=myToken --server=myServerUrl You can request the token via the Copy Login Command link in the OpenShift web console. If you don’t already have a project created, you can create one using: oc new-project myProjectName Start Keycloak We will be using Keycloak as our OpenID provider. To start a Keycloak server in your project on OpenShift, use the following command: oc process -f https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/latest/openshift/keycloak.yaml \ -p KEYCLOAK_ADMIN=admin \// (1) -p KEYCLOAK_ADMIN_PASSWORD=admin \// (2) -p NAMESPACE=<PROJECT_NAME> \// (3) | oc create -f - Replace admin with the user name you would like to use when accessing the Keycloak Administration Console. Replace admin with the password you would like to use when accessing the Keycloak Administration Console. Replace <PROJECT_NAME> with your project name. After running the above command, you should see the following output: service/keycloak created route.route.openshift.io/keycloak created Warning: apps.openshift.io/v1 DeploymentConfig is deprecated in v4.14+, unavailable in v4.10000+ deploymentconfig.apps.openshift.io/keycloak created. It will take a few minutes for OpenShift to provision the Keycloak pod and its related resources. You can use the OpenShift CLI or the OpenShift web console, depending on your preference, to check if your Keycloak server has been provisioned. OpenShift CLI To make sure your Keycloak server has been provisioned using the OpenShift CLI, run: oc get pods After a little while, check for a message similar to the following message that indicates the pod is ready: NAME READY STATUS RESTARTS AGE keycloak-1-deploy 0/1 Completed 0 1h keycloak-1-l9kdx 1/1 Running 0 1h Once the Keycloak server has been provisioned, use the following command to find the URL for your Keycloak instance’s Admin Console: KEYCLOAK_URL=https://$(oc get route keycloak --template='{{ .spec.host }}') && echo "" && echo "Keycloak Admin Console: $KEYCLOAK_URL/admin" && echo "" OpenShift Web Console To make sure your Keycloak server has been provisioned using the OpenShift web console, navigate to the Topology view in the Developer perspective. You can click on your keycloak app to check its status. Once it is running, you can click on Open URL and then access Keycloak’s Administration Console. Configure Keycloak Log into the Keycloak Admin Console. Create a new realm called myrealm. For more information, see the Keycloak documentation on how to create a realm. Add a new user named alice. For more information, see the Keycloak documentation on how to create a user. Once the new user has been created, set a password for this new user from the Credentials tab. Create a new client as follows: General Settings: Client type (or Client Protocol, depending on your Keycloak version): OpenID Connect Client ID: myclient Capability config: Authentication flow: Standard flow, Direct access grants Login settings: Leave the fields blank for now. For more information, see the Keycloak documentation on how to Manage OpenID Connect clients. Click Save to save the client. Add Helm Configuration Obtain the URL for Keycloak. KEYCLOAK_URL=https://$(oc get route keycloak --template='{{ .spec.host }}') && echo "" && echo "Keycloak URL: $KEYCLOAK_URL" && echo "" Switch to the charts directory in the simple-webapp-oidc example. cd /PATH/TO/ELYTRON/EXAMPLES/simple-webapp-oidc/charts Notice there’s a helm.yaml file in this directory with the following content: build: uri: https://github.com/wildfly-security-incubator/elytron-examples.git contextDir: simple-webapp-oidc deploy: replicas: 1 env: - name: OIDC_PROVIDER_URL value: <KEYCLOAK_URL> (1) Replace <KEYCLOAK_URL> with the Keycloak URL obtained in the previous command. Deploy the Example Application to WildFly on OpenShift If you haven’t already installed the WildFly Helm chart, install it: helm repo add wildfly https://docs.wildfly.org/wildfly-charts/ If you’ve already installed the WildFly Helm Chart, be sure to update it to ensure you have the latest one: helm repo update We can deploy our example application to WildFly on OpenShift using the WildFly Helm Chart: helm install oidc-app -f /PATH/TO/ELYTRON/EXAMPLES/simple-webapp-oidc/charts/helm.yaml wildfly/wildfly Notice that this command specifies the file we updated, helm.yaml, that contains the values needed to build and deploy our application. The application will now begin to build. This will take a couple of minutes. The build can be observed using: oc get build -w Once complete, you can follow the deployment of the application using: oc get deployment oidc-app -w Alternatively, you can check status directly from the OpenShift web console. Behind the Scenes While our application is building, let’s take a closer look at our application. Examine the pom.xml file. Notice that it contains an openshift profile. A profile in Maven lets you create a set of configuration values to customize your application build for different environments. The openshift profile in this example defines a configuration that will be used by the WildFly Helm Chart when provisioning the WildFly server on OpenShift. <profiles> <profile> <id>openshift</id> <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <!--(1)--> <version>${version.wildfly.maven.plugin}</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.wildfly}</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:${version.wildfly.cloud.galleon.pack}</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>elytron-oidc-client</layer> <!--(2)--> </layers> <filename>simple-webapp-oidc.war</filename> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> wildfly-maven-plugin provisions a WildFly server with the specified layers with our application deployed. elytron-oidc-client automatically adds the native OIDC client subsystem to our WildFly installation. Examine the web.xml. ... <login-config> <auth-method>OIDC</auth-method> (1) </login-config> ... When elytron-oidc-client subsystem sees auth-method is set to OIDC, it enables OIDC authentication mechanism for the application. Examine the oidc.json file. The oidc.json is used to configure the native OIDC client subsystem. { "client-id" : "myclient", (1) "provider-url" : "${env.OIDC_PROVIDER_URL:http://localhost:8080}/realms/myrealm", (2) "public-client" : "true", (3) "principal-attribute" : "preferred_username", (4) "ssl-required" : "EXTERNAL" (5) } This is the client we created in Keycloak. The provider URL, which is the URL for the realm myrealm that we created, is specified as an environment variable. We will set its value in the Helm configuration. When public-client is set to true, client credentials are not sent when communicating with the OpenID provider. We specify that the user name of the identity, which in our case is alice, is to be used as the principal for the identity. When ssl-required is set to EXTERNAL, HTTPS is required by default for external requests. Get the Application URL Once the WildFly server has been provisioned, use the following command to find the URL for your example application: SIMPLE_WEBAPP_OIDC_URL=https://$(oc get route oidc-app --template='{{ .spec.host }}') && echo "" && echo "Application URL: $SIMPLE_WEBAPP_OIDC_URL/simple-webapp-oidc" && echo "Valid redirect URI: $SIMPLE_WEBAPP_OIDC_URL/simple-webapp-oidc/secured/*" && echo "" We’ll make use of these URLs in the next two sections. Finish Configuring Keycloak From your myclient client in the Keycloak Administration Console, in the client settings, set Valid redirect URIs to the Valid redirect URI that was output in the previous section and then click Save. Access the Application From your browser, navigate to the Application URL that was output in the previous section. Click on Access Secured Servlet. You will be redirected to Keycloak to log in. Log in using the alice user we created earlier. Upon successful authentication, you will be redirected back to the example application. The example application simply outputs the name of the logged in user. You should see the following output: Secured Servlet Current Principal 'alice' This indicates that we have successfully logged into our application! What’s next? This guide has shown how to secure an application deployed to WildFly on OpenShift with OIDC. To learn more about OIDC configuration, check out the Elytron OIDC Client documentation. References Elytron OpenID Connect Client Subsystem Configuration Getting Started with WildFly on OpenShift OpenShift CLI WildFly Helm Chart Getting started with Keycloak on OpenShift Keycloak Server Administration Guide ### [Sending Request Objects as A JWT Using Request Parameters for OpenID Connect](/guides/security-oidc-request-openshift/) Sending Request Objects as A JWT Using Request Parameters for OpenID Connect Table of Contents Prerequisites Example Application Setting up the Key Pairs About Key Pairs Generating Key Pairs Log Into the OpenShift Cluster Start Keycloak OpenShift CLI OpenShift Web Console OpenShift Web Console Setting up Keycloak OpenID Provider Create an OpenShift Secret Add Helm Configuration Stability Levels for OpenShift Deployment Deploy the Example Application to WildFly on OpenShift Behind the Scenes Get the Application URL Finish Configuring Keycloak Accessing the Application Sending the JWT by Reference Note about Keystores What’s Next References WildFly 33 includes the ability to send the request object as a Json Web Token (JWT) when securing an application using OIDC. The feature also includes the ability to sign and/or encrypt the JWT for added security. OpenID Connect is an identity layer on top of the OAuth 2.0 protocol that makes it possible for a client to verify a user’s identity based on authentication that’s performed by an OpenID provider. The OAuth 2.0 request syntax sends the Request Object in the request by adding them directly to the URL. However, OpenID Connect allows the Request Object to be sent as a JWT using request parameters, which can be signed and optionally encrypted. This adds an added layer of protection, as the parameters are no longer human-readable. Prerequisites To complete this guide, you need: Roughly 20 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Access to an OpenShift cluster (try the Red Hat Developer Sandbox for free) OpenShift CLI Helm Chart Keytool Example Application We will use a simple web application in this guide that consists of a single servlet. We will secure this servlet using OIDC. We will use the example in the elytron-oidc-request directory in the elytron-examples repo. To obtain this example, clone the elytron-examples repository to your local machine: git clone git@github.com:wildfly-security-incubator/elytron-examples.git Setting up the Key Pairs We need to generate a key pair to sign the JWTs. These key pairs are tokens that are communicated between the client and the server and are used to sign and encrypt JWT’s. About Key Pairs Typically key pairs have 2 components: Private Key: This is the part of the key that must be kept secret and will be used to sign the JWT. Your OpenID provider communicates the public key of some key pair(s) to you. The public key is used by you to encrypt the JWT. Public Key: This is the part of the key pair that is shared with trusted parties. Typically, the OpenID provider shared a set of public keys with us which we use to encrypt our JWT’s among other things. Public keys can be extracted from certificates and are used to verify the signatures among other things. We share the certificates of key pairs we generate with the OpenID provider, and it contains the public key. Key pairs with public and private keys are known as asymmetric keys. Some keys are symmetric, meaning they only have 1 secret key that is used by both the client and the server. Each key has an algorithm that is used to generate it, such as, RSA, Elliptic Curve, etc. An example of a symmetric algorithm is HS256, where the same key is used to sign a JWT and verify the signature. Generating Key Pairs We can use the keytool tool in the cli to generate our keys and store them in a keystore file. We can generate keystore files of type JKS and PKCS12 for our application. The general format for doing this is as follows: $ keytool -genkey pair -alias <keystore_alias> -keyalg <algorithm> -keysize <key_size> -validity <validity_in_days> -keystore <keystore_name> -dname "<distinguished_name>" -keypass <private_key_password> -storepass <keystore_password> For this example, we will be using PKCS12 keystores. Generating PKCS12 Keystore Let us first create a PKCS12 keystore file with 2 different keys. Let’s first generate an RSA key pair: $ keytool -genkey pair -alias rsaKey -keyalg RSA -keysize 2048 -validity 365 -keystore Keycloak.keystore.pkcs12 -dname "CN=client" -keypass password -storepass password And for Elliptical Curve keys, use the following commands: $ keytool -genkey pair -alias ecKey -keyalg EC -groupname secp256r1 -validity 365 -keystore Keycloak.keystore.pkcs12 -dname "CN=client" -keypass password -storepass password Note that in this case, we have specified the key size for the RSA keys, and the groupname for Elliptical Curve keys. For the RSA keys, the same keysize can be used for RSA algorithms with different SHA values (i.e. RSA256, RSA512). However, this is not the case for Elliptical Curve keys. For ES256 algorithms, you need to use the groupname associated with the SHA value (i.e. for ES256, use -groupname secp256r1 and for ES384, use -groupname secp384r1 and so on). You can use the following commands to see the contents of the keystore: $ keytool -list -v -keystore Keycloak.keystore.pkcs12 -storepass password Take a note of the absolute path of the keystore file along with the key alias and the keystore password. We will be using them to set up Keycloak later. For this guide we will only be using the key pair with the alias rsaKey. However, if you would like to use an Elliptical Curve key to sign your JWT, you can use the ecKey alias when asked for a key alias. If you would like to use JKS keystore files instead, see here for more information. Log Into the OpenShift Cluster Before we can deploy our application, we need to log in to an OpenShift cluster. You can log in via the OpenShift CLI: oc login -u myUserName Alternatively, you can log in using an API token: oc login --token=myToken --server=myServerUrl You can request the token via the Copy Login Command link in the OpenShift web console. If you don’t already have a project created, you can create one using: oc new-project myProjectName Start Keycloak We will be using Keycloak as our OpenID provider. To start a Keycloak server in your project on OpenShift, use the following command: oc process -f https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/latest/openshift/keycloak.yaml \ -p KEYCLOAK_ADMIN=admin \// (1) -p KEYCLOAK_ADMIN_PASSWORD=admin \// (2) -p NAMESPACE=<PROJECT_NAME> \// (3) | oc create -f - Replace admin with the user name you would like to use when accessing the Keycloak Administration Console. Replace admin with the password you would like to use when accessing the Keycloak Administration Console. Replace <PROJECT_NAME> with your project name. After running the above command, you should see the following output: service/keycloak created route.route.openshift.io/keycloak created Warning: apps.openshift.io/v1 DeploymentConfig is deprecated in v4.14+, unavailable in v4.10000+ deploymentconfig.apps.openshift.io/keycloak created. It will take a few minutes for OpenShift to provision the Keycloak pod and its related resources. You can use the OpenShift CLI or the OpenShift web console, depending on your preference, to check if your Keycloak server has been provisioned. OpenShift CLI To make sure your Keycloak server has been provisioned using the OpenShift CLI, run: oc get pods After a little while, check for a message similar to the following message that indicates the pod is ready: NAME READY STATUS RESTARTS AGE keycloak-1-deploy 0/1 Completed 0 1h keycloak-1-l9kdx 1/1 Running 0 1h Once the Keycloak server has been provisioned, use the following command to find the URL for your Keycloak instance’s Admin Console: KEYCLOAK_URL=https://$(oc get route keycloak --template='{{ .spec.host }}') && echo "" && echo "Keycloak Admin Console: $KEYCLOAK_URL/admin" && echo "" OpenShift Web Console To make sure your Keycloak server has been provisioned using the OpenShift web console, navigate to the Topology view in the Developer perspective. You can click on your keycloak app to check its status. Once it is running, you can click on Open URL and then access Keycloak’s Administration Console. OpenShift Web Console To make sure your Keycloak server has been provisioned using the OpenShift web console, navigate to the Topology view in the Developer perspective. You can click on your keycloak app to check its status. Once it is running, you can click on Open URL and you will be taken to Keycloak’s Administration Console login page. Setting up Keycloak OpenID Provider Log into the Keycloak Admin Console using the admin username and password you specified earlier. Select the drop down menu in the upper left corner, and click on the "Create realm" button. Enter myrealm for Realm name and click on the Create button to create a realm called myrealm. Next, go to the Clients menu and click on the Create client button to register a client called myclient as follows: General settings: Client type (or Client Protocol, depending on your keycloak version): OpenID Connect Client ID: myclient Capability config: Client authentication : On Authentication flow: Standard flow, Direct access grants Login settings: For the Valid Redirect URIs, leave it empty for now. We will come back to edit it later. Once you hit Save, you should see a new tab called Keys appear. Navigate to the Keys tab for my client from the Client details page, click on the Import button located at the bottom of the screen. Under Archive format, choose PKCS12 from the dropdown. Under Key alias, enter the alias of the RSA key you just created. Under Store password enter the password of the keystore you created. under Import file, click on the Browse button to import the keystore file. Note that when we created the keystore, we specified a key password and a keystore password. Here, we are only using the keystore password. While we set them both to be the same, they do not have to be. Once you select the file named Keycloak.keystore.pkcs12 from your filesystem, click Import and you should see a message at the top of the screen indicating that the certificate has been uploaded successfully and you will see the certificate listed in the text field in the middle of the screen. Finally, create a user called alice as follows: Click Users in the left hand menu. Click Add user. Fill in the form with the following values: Username: alice. First name: Alice. Last name: Smith. Click Create. You can find more details about creating and managing KeyCloak users here. This user needs a password to log in. To set the initial password: Click Credentials at the top of the page. Fill in the Set password form with a password. Toggle Temporary to Off so that the user does not need to update this password at the first login. Hit Save. Create an OpenShift Secret Since WildFly will use the keystore we created earlier, we need to add it to OpenShift. We can do this by generating an OpenShift secret using the keystore file as follows: $ oc create secret generic simple-webapp-secret --from-file=/PATH/TO/Keycloak.keystore.pkcs12 Once you have your environment set up with the required tools, we can move on to the next step to build and deploy our application on OpenShift. Add Helm Configuration Obtain the URL for Keycloak. KEYCLOAK_URL=https://$(oc get route keycloak --template='{{ .spec.host }}') && echo "" && echo "Keycloak URL: $KEYCLOAK_URL" && echo "" Switch to the charts directory in the elytron-oidc-client-scope example. $ cd /PATH/TO/ELYTRON/EXAMPLES/elytron-oidc-request/charts Notice there’s a helm.yaml file in this directory with the following content: build: uri: https://github.com/wildfly-security-incubator/elytron-examples.git contextDir: elytron-oidc-request deploy: replicas: 1 env: - name: OIDC_PROVIDER_URL value: <KEYCLOAK_URL> (1) - name: OIDC_CLIENT_SECRET value: <CLIENT_SECRET> (2) - name: AUTH_REQUEST_FORMAT value: request - name: SIGNING_KEYSTORE_PATH value: /etc/request-object-secret-volume/Keycloak.keystore.pkcs12 - name: SERVER_ARGS value: "--stability=preview" volumes: - name: request-object-signing-keystore-volume secret: secretName: simple-webapp-secret volumeMounts: - name: request-object-signing-keystore-volume mountPath: /etc/request-object-secret-volume readOnly: true Replace <KEYCLOAK_URL> with the Keycloak URL obtained in the previous command. Replace <CLIENT_SECRET> with the client secret for myclient. To obtain the client secret, go to the Client menu on the left hand side and select myclient from the Clients list. Click on the Credentials tab under Client details page, ensure that Client Authenticator is set to Client Id and Secret and copy the value listed beside Client Secret. Stability Levels for OpenShift Deployment The WildFly server now includes different stability levels, that can be associated with functionality. Users can use the --stability argument when staring the WildFly server. Depending on the value of the stability levels, different features are available. You can learn more about stability levels here. The attributes related to request objects under the elytron-oidc-client subsystem are preview level attributes, which means in order to access their functionalities, the server’s stability level must be set to preview. When applications are deployed to OpenShift, the WildFly Cloud Galleon Feature-Pack is used to provision a server. Therefore, in order to use this feature, we need to provision the server at the preview stability level. This is why we have added the environment variable named SERVER_ARGS with a value of --stability=preview, which specifies that the provisioned server should be started at the preview stability level. For more information about the server’s stability levels, please refer to WildFly Docs. Additionally, we have used the stability galleon option to specify the stability level used by the feature-pack when deploying the application using the tags below: <galleon-options> <stability-level>preview</stability-level> </galleon-options> Deploy the Example Application to WildFly on OpenShift If you haven’t already installed the WildFly Helm chart, install it: helm repo add wildfly https://docs.wildfly.org/wildfly-charts/ If you have already installed the WildFly Helm Chart, be sure to update it to ensure you have the latest one: helm repo update We can deploy our example application to WildFly on OpenShift using the WildFly Helm Chart: helm install oidc-app -f /PATH/TO/ELYTRON/EXAMPLES/elytron-oidc-request/charts/helm.yaml wildfly/wildfly Notice that this command uses the file we updated, helm.yaml, that contains the values needed to build and deploy our application. The application will now begin to build. This will take a couple of minutes. The build can be observed using: oc get build -w Once complete, you can follow the deployment of the application using: oc get deployment oidc-app -w Alternatively, you can check status directly from the OpenShift web console. Behind the Scenes While our application is building, let’s take a closer look at our application. Examine the pom.xml file. Notice that it contains an openshift profile. A profile in Maven lets you create a set of configuration values to customize your application build for different environments. The openshift profile in this example defines a configuration that will be used by the WildFly Helm Chart when provisioning the WildFly server on OpenShift. <profiles> <profile> <id>openshift</id> <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> (1) <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.wildfly}</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:${version.wildfly.cloud.galleon.pack}</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>elytron-oidc-client</layer> (2) </layers> <galleon-options> <stability-level>preview</stability-level> (3) </galleon-options> <filename>simple-webapp-oidc.war</filename> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> wildfly-maven-plugin provisions a WildFly server with the specified layers with our application deployed.Version 7.0.0.Beta2 or later must be used to allow for stability levels. elytron-oidc-client automatically adds the native OIDC client subsystem to our WildFly installation. stability-level for the feature-pack is set to preview since we are making use of a preview level feature. Examine the oidc.json file, which is used to configure the OIDC client. { "client-id" : "myclient", "provider-url" : "${env.OIDC_PROVIDER_URL:http://localhost:8080}/realms/myrealm", "public-client" : "false", "authentication-request-format" : "${env.AUTH_REQUEST_FORMAT}", "request-object-signing-algorithm" : "RS256", "request-object-encryption-alg-value" : "RSA-OAEP", "request-object-encryption-enc-value" : "A256GCM", "request-object-signing-keystore-file" : "${env.SIGNING_KEYSTORE_PATH}", "request-object-signing-keystore-password" : "password", "request-object-signing-key-password" : "password", "request-object-signing-key-alias" : "rsaKey", "request-object-signing-keystore-type" : "PKCS12", "principal-attribute" : "preferred_username", "ssl-required" : "EXTERNAL", "scope" : "profile email roles web-origins microprofile-jwt offline_access", "credentials" : { "secret" : "${env.OIDC_CLIENT_SECRET}" } } Note that we have specified the authentication-request-format to be request, meaning, we are sending it by value. We have specified the signing algorithm to be RS256, and we are using the RSA key to sign the request object. We have also specified the alg and enc values to encrypt the request object. The request object JWT will be signed first and then encrypted using the public key that Keycloak shared with us. To see what this key looks like, you can either go to <provider-url>/protocol/openid-connect/certs or you can go to the Keycloak console and under the Realm settings tab, click on the keys tab. You will see that there console includes 2 other keys in addition to the ones on the link. These are the symmetric keys provided by Keycloak which are used by both the client and the server to sign/verify and encrypt/decrypt. Next, navigate to the OIDC application’s web.xml file and look for the following command: <login-config> <auth-method>OIDC</auth-method> </login-config> Get the Application URL Once the WildFly server has been provisioned, use the following command to find the URL for your example application: SIMPLE_WEBAPP_OIDC_URL=https://$(oc get route oidc-app --template='{{ .spec.host }}') && echo "" && echo "Application URL: $SIMPLE_WEBAPP_OIDC_URL/simple-webapp-oidc" && echo "Valid redirect URI: $SIMPLE_WEBAPP_OIDC_URL/simple-webapp-oidc/secured/*" && echo "" Finish Configuring Keycloak From your myclient client in the Keycloak Administration Console, in the client settings, set Valid Redirect URI to the Valid redirect URI that was output in the previous section and then click Save. Accessing the Application Now, let’s try accessing our application using the application URL. Click on Access Secured Servlet. Now, you’ll be redirected to Keycloak’s login page. If you click on the url on the search bar, you will see the request value specified in the URL along with client-id, response_type, redirect_uri and the openid scope. These parameters are required to be included in the auth request according to the OAuth2 specifications. You will also notice that the additional scopes are not added to the URL. Log in with Alice and the password that you set when configuring Keycloak. Next, you’ll be redirected back to our application, and you should see the "Secured Servlet" page. That means that we were able to successfully log in to our application using the Keycloak OpenID provider! You will also see the claims that were retrieved using the additional scopes. They were sent through the request object. Sending the JWT by Reference Now try changing the value for AUTH_REQUEST_FORMAT to request_uri inside the helm chart and keep everything else the same. You can update the openshift deployment using the following commands: helm upgrade oidc-app -f /PATH/TO/ELYTRON/EXAMPLES/elytron-oidc-request/charts/helm.yaml wildfly/wildfly If the builds don’t start automatically, you might have to start them manually on the openshift console. Wait for the build to finish and access the application URL again in a new window. You will see the request_uri field appear in the url. The request_uri parameter is used to send the JWT by reference. The Elytron client sends a PAR request to the Pushed Authorization Request Endpoint ({provider-url}/protocol/openid-connect/ext/par/request), which creates the request_uri given the JWT Request Object. Once the reference has been made it is only valid for a certain amount of time specified in the structure returned by the PAR request. After which the request_uri needs to be regenerated. To learn more about the specifications of the Request Object, read the OpenID documentation on passing a Request Object by reference. Note about Keystores You can follow the same instructions to configure your server to use a PKCS12 type keystore. For Keycloak, the signing algorithms available are "PS384", "ES384", "RS384", "HS256", "HS512", "ES256", "RS256", "HS384", "ES512","PS256", "PS512", "RS512" and "none". If you use algorithms that start with "RS" and "PS" to sign the JWT, you will need to use an RSA key pair. For "ES" type keys, use Elliptical curve keys and as mentioned above, adjust the group name for the PKCS12 keystore keys to match the SHA value of the algorithms. "none" does not require a keystore and lastly, "HS" keys require a symmetric key, where the same secret hash is used by the client and the server to sign and verify respectively. Not all algorithms are supported by all OpenID Providers. Review the documentation and/or the metadata for your OpenID provider to learn more about the supported algorithms. What’s Next This example has demonstrated how to secure a web application deployed to WildFly by sending the request parameters as a JWT. For more details on the elytron-oidc-client subsystem, please check out the documentation and for more details on OpenID Connect, checkout the OpenID documentation and the documentation of your OpenID provider. References Passing Request Parameters as JWTs Using OIDC Getting Started with WildFly on OpenShift OpenShift CLI WildFly Helm Chart Getting started with Keycloak on OpenShift Keycloak Server Administration Guide Using OpenID Connect to secure applications and services Feature stability levels WildFly Galleon feature-packs Keytool documentation. ### [Securing WildFly Apps on OpenShift with OpenID Connect Using Additional Scope Values](/guides/security-oidc-scope-openshift/) Securing WildFly Apps on OpenShift with OpenID Connect Using Additional Scope Values Table of Contents Prerequisites Example Application Log Into the OpenShift Cluster Start Keycloak OpenShift CLI OpenShift Web Console OpenShift Web Console Configure Keycloak Add Helm Configuration Stability Levels for OpenShift Deployment Deploy the Example Application to WildFly on OpenShift Behind the Scenes Get the Application URL Finish Configuring Keycloak Accessing the Application Invalid Scope Values What’s next? References WildFly 32 includes the ability to add additional scope values when securing applications using OpenID Connect (OIDC). This new feature is available at the Preview stability level. OpenID Connect is an identity layer on top of the OAuth 2.0 protocol that makes it possible for a client to verify a user’s identity based on authentication that’s performed by an OpenID provider. The OpenID Connect specification indicates that there are other scope values which may be included in the authentication request to ask permission to access additional and specific resources. This guide shows how to configure additional scope values when securing a WildFly app with OpenID Connect on OpenShift. Prerequisites To complete this guide, you need: Roughly 15 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Access to an OpenShift cluster (try the Red Hat Developer Sandbox for free) OpenShift CLI Helm Chart Example Application We will use a simple web application in this guide that consists of a single servlet. We will secure this servlet using OIDC. We will use the example in the elytron-oidc-client-scope directory in this repo. To obtain this example, clone the elytron-examples repository to your local machine: git clone git@github.com:wildfly-security-incubator/elytron-examples.git Log Into the OpenShift Cluster Before we can deploy our application, we need to log in to an OpenShift cluster. You can log in via the OpenShift CLI: oc login -u myUserName Alternatively, you can log in using an API token: oc login --token=myToken --server=myServerUrl You can request the token via the Copy Login Command link in the OpenShift web console. If you don’t already have a project created, you can create one using: oc new-project myProjectName Start Keycloak We will be using Keycloak as our OpenID provider. To start a Keycloak server in your project on OpenShift, use the following command: oc process -f https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/latest/openshift/keycloak.yaml \ -p KEYCLOAK_ADMIN=admin \// (1) -p KEYCLOAK_ADMIN_PASSWORD=admin \// (2) -p NAMESPACE=<PROJECT_NAME> \// (3) | oc create -f - Replace admin with the user name you would like to use when accessing the Keycloak Administration Console. Replace admin with the password you would like to use when accessing the Keycloak Administration Console. Replace <PROJECT_NAME> with your project name. After running the above command, you should see the following output: service/keycloak created route.route.openshift.io/keycloak created Warning: apps.openshift.io/v1 DeploymentConfig is deprecated in v4.14+, unavailable in v4.10000+ deploymentconfig.apps.openshift.io/keycloak created. It will take a few minutes for OpenShift to provision the Keycloak pod and its related resources. You can use the OpenShift CLI or the OpenShift web console, depending on your preference, to check if your Keycloak server has been provisioned. OpenShift CLI To make sure your Keycloak server has been provisioned using the OpenShift CLI, run: oc get pods After a little while, check for a message similar to the following message that indicates the pod is ready: NAME READY STATUS RESTARTS AGE keycloak-1-deploy 0/1 Completed 0 1h keycloak-1-l9kdx 1/1 Running 0 1h Once the Keycloak server has been provisioned, use the following command to find the URL for your Keycloak instance’s Admin Console: KEYCLOAK_URL=https://$(oc get route keycloak --template='{{ .spec.host }}') && echo "" && echo "Keycloak Admin Console: $KEYCLOAK_URL/admin" && echo "" OpenShift Web Console To make sure your Keycloak server has been provisioned using the OpenShift web console, navigate to the Topology view in the Developer perspective. You can click on your keycloak app to check its status. Once it is running, you can click on Open URL and then access Keycloak’s Administration Console. OpenShift Web Console To make sure your Keycloak server has been provisioned using the OpenShift web console, navigate to the Topology view in the Developer perspective. You can click on your keycloak app to check its status. Once it is running, you can click on Open URL and then access Keycloak’s Administration Console. Configure Keycloak Log into the Keycloak Admin Console using the admin username and password you specified earlier. Next, create a realm called myrealm and register a client called myclient as follows: General settings: Client type (or Client Protocol, depending on your keycloak version): OpenID Connect Client ID: myclient Capability config: Authentication flow: Standard flow, Direct access grants Login Settings: For the Valid Redirect URIs, enter a * for now. We will come back to edit it later. Navigate to the Client scopes tab for myclient and change the Assigned type for all scope values from Default to Optional. When Client scopes are set to Default, the claims associated with them are automatically added to the access token you receive. Changing it to Optional ensures that they are not included by default and you will only get access to claims that you request using the scope values you configure. This list of scope are the values that Keycloak allows and it varies for different OpenID providers. Now, click on Realm roles and create two roles, user and admin. Finally, create a user called alice whose First name is Alice and Last name is Smith and assign her the user and admin roles. Steps for assigning roles can be found in the Keycloak documentation. We will be using different scopes to query these pieces of information about Alice. Next, navigate to the Credentials tab and create a password for Alice. Toggle the Temporary switch off so you are not prompted to update the password after the first login. Add Helm Configuration Obtain the URL for Keycloak. KEYCLOAK_URL=https://$(oc get route keycloak --template='{{ .spec.host }}') && echo "" && echo "Keycloak URL: $KEYCLOAK_URL" && echo "" Switch to the charts directory in the elytron-oidc-client-scope example. cd /PATH/TO/ELYTRON/EXAMPLES/elytron-oidc-client-scope/charts Notice there’s a helm.yaml file in this directory with the following content: build: uri: https://github.com/wildfly-security-incubator/elytron-examples.git contextDir: elytron-oidc-client-scope deploy: replicas: 1 env: - name: OIDC_PROVIDER_URL value: <KEYCLOAK_URL> (1) - name: SERVER_ARGS value: "--stability=preview" Replace <KEYCLOAK_URL> with the Keycloak URL obtained in the previous command. Stability Levels for OpenShift Deployment The WildFly server now includes different stability levels, that can be associated with functionality. Users can use the --stability argument when staring the WildFly server. Depending on the value of the stability levels, different features are available. You can learn more about stability levels here. The scope attribute under the elytron-oidc-client subsystem is a preview level feature, which means in order to access its functionality, the server’s stability level must be set to preview. When applications are deployed to OpenShift, the WildFly Cloud Galleon Feature-Pack is used to provision a server. Therefore, in order to use the scope attribute, we need to provision the server at the preview stability level. This is why we have added the environment variable named SERVER_ARGS with a value of --stability=preview, which specifies that the provisioned server should be started at the preview stability level. For more information about the server’s stability levels, please refer to WildFly Docs. Additionally, we have used the stability galleon option to specify the stability level used by the feature-pack when deploying the application using the tags below: <galleon-options> <stability-level>preview</stability-level> </galleon-options> Deploy the Example Application to WildFly on OpenShift If you haven’t already installed the WildFly Helm chart, install it: helm repo add wildfly https://docs.wildfly.org/wildfly-charts/ If you’ve already installed the WildFly Helm Chart, be sure to update it to ensure you have the latest one: helm repo update We can deploy our example application to WildFly on OpenShift using the WildFly Helm Chart: helm install oidc-app -f /PATH/TO/ELYTRON/EXAMPLES/elytron-oidc-client-scope/charts/helm.yaml wildfly/wildfly Notice that this command specifies the file we updated, helm.yaml, that contains the values needed to build and deploy our application. The application will now begin to build. This will take a couple of minutes. The build can be observed using: oc get build -w Once complete, you can follow the deployment of the application using: oc get deployment oidc-app -w Alternatively, you can check status directly from the OpenShift web console. Behind the Scenes While our application is building, let’s take a closer look at our application. Examine the pom.xml file. Notice that it contains an openshift profile. A profile in Maven lets you create a set of configuration values to customize your application build for different environments. The openshift profile in this example defines a configuration that will be used by the WildFly Helm Chart when provisioning the WildFly server on OpenShift. <profiles> <profile> <id>openshift</id> <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> (1) <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.wildfly}</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:${version.wildfly.cloud.galleon.pack}</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>elytron-oidc-client</layer> (2) </layers> <galleon-options> <stability-level>preview</stability-level> (3) </galleon-options> <filename>simple-webapp-oidc.war</filename> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> wildfly-maven-plugin provisions a WildFly server with the specified layers with our application deployed.Version 7.0.0.Beta2 or later must be used to allow for stability levels. elytron-oidc-client automatically adds the native OIDC client subsystem to our WildFly installation. stability-level for the feature-pack is set to preview since we are making use of a preview level feature. Examine the oidc.json file, which is used to configure the OIDC client. { "client-id" : "myclient", "provider-url" : "${env.OIDC_PROVIDER_URL:http://localhost:8080}/realms/myrealm", "public-client" : "true", "scope" : "profile email roles web-origins microprofile-jwt offline_access", "principal-attribute" : "preferred_username", "ssl-required" : "EXTERNAL" } Note that we have specified the scope values to be profile, email, web-origins, microprofile-jwt, roles and offline_access in a space delimited list inside the oidc.json file. profile, email and offline_access are OpenID built-in scopes, while web-origin, microprofile-jwt and roles are Keycloak specific scope values and allow access to additional claims. You can read the descriptions under the Client scope tab for myclient to learn more about the purpose of these scope values. Next, navigate to the OIDC application’s web.xml file and look for the following command: <login-config> <auth-method>OIDC</auth-method> (1) </login-config> Setting the auth-method to OIDC specifies that our application will use OpenID Connect to authenticate users. Get the Application URL Once the WildFly server has been provisioned, use the following command to find the URL for your example application: SIMPLE_WEBAPP_OIDC_URL=https://$(oc get route oidc-app --template='{{ .spec.host }}') && echo "" && echo "Application URL: $SIMPLE_WEBAPP_OIDC_URL/simple-webapp-oidc" && echo "Valid redirect URI: $SIMPLE_WEBAPP_OIDC_URL/simple-webapp-oidc/secured/*" && echo "" Finish Configuring Keycloak From your myclient client in the Keycloak Administration Console, in the client settings, set Valid Redirect URI to the Valid redirect URI that was output in the previous section and then click Save. Accessing the Application Now, let’s try accessing our application using the application URL. Click on Access Secured Servlet. Now, you’ll be redirected to Keycloak to log in. If you click on the url on the search bar, you will see the scope values specified in the redirect-uri field with the different scope values separated by a +. You will also notice that a new scope value, openid, has been added. This indicates that we are going to be using OpenID Connect to authenticate the user. Log in with alice and the password that you set when configuring Keycloak. Next, you’ll be redirected back to our application and you should see the Secured Servlet page. That means that we were able to successfully log in to our application using the Keycloak OpenID provider! This page will display the current principal, and a list of claim values obtained using the scope values you configured. This is what it will look like: Current Principal 'alice' Claims received using additional scope values: By configuring the "profile" scope, the "given_name" and "family_name" claims are present in the access token and have values : Alice and Smith By configuring the "email" scope, the "email_verified" claim is present in the access token and has value : false By configuring the "roles" scope, the "realm_access" claim is present in the access token and has value : {roles=[default-roles-myrealm, offline_access, admin, uma_authorization, user]} By configuring the "microprofile-jwt" scope, the "groups" claim is present in the access token and has value : [default-roles-myrealm, offline_access, admin, uma_authorization, user] By configuring the "web-origins" scope, the "allowed-origins" claim is present in the access token and has value : [http://localhost:8090] Note that the value for Current Principal may be different, and can be replaced by the unique client id assigned by keycloak. Notice that there are no claims obtained using the offline_access scope. To learn more about what this scope value does, please refer to the OpenID Documentation . Invalid Scope Values Different OpenID providers have their own set of valid scope values and they vary depending on the OpenID provider. Try changing the scope values to INVALID_SCOPE inside the oidc.json file. Deploy and access the webapp again using the command below: helm upgrade oidc-app -f charts/helm.yaml wildfly/wildfly Since INVALID_SCOPE is not one of the acceptable scope values, you will now see a Bad request page instead of being redirected to the Keycloak login page. You will notice that the url now contains error=invalid_scope&error_description=Invalid+scopes This indicates that your authentication request was rejected because it contains invalid scope values. What’s next? This example has demonstrated how to secure a WildFly application deployed to OpenShift using additional scope values. For more details on the elytron-oidc-client subsystem, please check out the documentation and for more details on OpenID Connect, checkout the OpenID documentation and the documentation of your OpenID provider. References Getting Started with WildFly on OpenShift OpenShift CLI WildFly Helm Chart Getting started with Keycloak on OpenShift Keycloak Server Administration Guide Using OpenID Connect to secure applications and services Feature stability levels WildFly Galleon feature-packs ### [Securing WildFly Apps with SAML on OpenShift](/guides/security-saml-openshift/) Securing WildFly Apps with SAML on OpenShift Table of Contents Prerequisites Example Application Log Into the OpenShift Cluster Start Keycloak OpenShift CLI OpenShift Web Console Configure Keycloak Download the SAML Keys Download and Edit the Keycloak Adapter Configuration File Add Helm Configuration Deploy the Example Application to WildFly on OpenShift Behind the Scenes Get the Application URL Finish Configuring Keycloak Access the Application What’s next? References You can secure your WildFly applications deployed on OpenShift with Security Assertion Markup Language (SAML). By using SAML to secure applications, you delegate authentication to SAML identity providers (IdPs). This guide shows how to secure an example application deployed to WildFly on OpenShift with SAML using Keycloak as the SAML IdP. Prerequisites To complete this guide, you need: Roughly 15 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Access to an OpenShift cluster (try the Red Hat Developer Sandbox for free) OpenShift CLI Helm Chart Example Application We will use a simple web application in this guide that consists of a single servlet. We will secure this servlet using SAML. We will use the example in the simple-webapp-saml directory in the elytron-examples repo. To obtain this example, clone the elytron-examples repository to your local machine: git clone git@github.com:wildfly-security-incubator/elytron-examples.git Log Into the OpenShift Cluster Before we can deploy our application, we need to log in to an OpenShift cluster. You can log in via the OpenShift CLI: oc login -u myUserName Alternatively, you can log in using an API token: oc login --token=myToken --server=myServerUrl You can request the token via the Copy Login Command link in the OpenShift web console. If you don’t already have a project created, you can create one using: oc new-project myProjectName Start Keycloak We will be using Keycloak as our SAML identity provider. To start a Keycloak server in your project on OpenShift, use the following command: oc process -f https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/latest/openshift/keycloak.yaml \ -p KEYCLOAK_ADMIN=admin \// (1) -p KEYCLOAK_ADMIN_PASSWORD=admin \// (2) -p NAMESPACE=<PROJECT_NAME> \// (3) | oc create -f - Replace admin with the user name you would like to use when accessing the Keycloak Administration Console. Replace admin with the password you would like to use when accessing the Keycloak Administration Console. Replace <PROJECT_NAME> with your project name. After running the above command, you should see the following output: service/keycloak created route.route.openshift.io/keycloak created Warning: apps.openshift.io/v1 DeploymentConfig is deprecated in v4.14+, unavailable in v4.10000+ deploymentconfig.apps.openshift.io/keycloak created. It will take a few minutes for OpenShift to provision the Keycloak pod and its related resources. You can use the OpenShift CLI or the OpenShift web console, depending on your preference, to check if your Keycloak server has been provisioned. OpenShift CLI To make sure your Keycloak server has been provisioned using the OpenShift CLI, run: oc get pods After a little while, check for a message similar to the following message that indicates the pod is ready: NAME READY STATUS RESTARTS AGE keycloak-1-deploy 0/1 Completed 0 1h keycloak-1-l9kdx 1/1 Running 0 1h Once the Keycloak server has been provisioned, use the following command to find the URL for your Keycloak instance’s Admin Console: KEYCLOAK_URL=https://$(oc get route keycloak --template='{{ .spec.host }}') && echo "" && echo "Keycloak Admin Console: $KEYCLOAK_URL/admin" && echo "" OpenShift Web Console To make sure your Keycloak server has been provisioned using the OpenShift web console, navigate to the Topology view in the Developer perspective. You can click on your keycloak app to check its status. Once it is running, you can click on Open URL and then access Keycloak’s Administration Console. Configure Keycloak Log into the Keycloak Admin Console. Create a new realm called myrealm. For more information, see the Keycloak documentation on how to create a realm. Add a role called user. This role will be required to access our simple web application. For more information, see the Keycloak documentation on how to create a role. Add a new user named alice. Set an email address for this new user, we’ll use alice@example.org. For more information, see the Keycloak documentation on how to create a user. Once the new user has been created, set a password for this new user from the Credentials tab. From the Role Mapping tab, assign alice the user role. For more information, see the Keycloak documentation on how to assign a role to a user. Create a new client as follows: General Settings: Client type (or Client Protocol, depending on your Keycloak version): SAML Client ID: simple-webapp-saml Login settings: Leave the fields blank for now. For more information, see the Keycloak documentation on how to Create SAML clients. Click Save to save the client. Once the new client has been created, in the Settings tab, scroll down to the SAML capabilities section and set the Name ID format to email. When accessing our servlet later on, we will see that this results in HttpServletRequest.getUserPrincipal().getName() returning the logged in user’s email address. Then set Force name ID format to On. Then click on Save. Download the SAML Keys From your simple-webapp-saml client in the Keycloak Admin Console, click on the Keys tab. Click on the Export button in the Signing keys config to export the SAML keys to a keystore. Set the Key alias to simple-webapp-saml, the Key password to password, the Realm certificate alias to myrealm, and the Store password to password. Take note of the aliases and passwords that you specify here since these will be used when updating the keycloak-saml.xml file. Click on Export to download the corresponding keystore.jks file. Create an OpenShift secret using this keystore by running the following command: oc create secret generic simple-webapp-saml-secret --from-file=/PATH/TO/keystore.jks Download and Edit the Keycloak Adapter Configuration File From your simple-webapp-saml client in the Keycloak Admin Console, click on the Action dropdown in the top right corner and select Download Adapter Config. For the Format option, select the Keycloak SAML Adapter keycloak-saml.xml, and download the file and place it in the example application’s WEB-INF directory, i.e., place the keycloak-saml.xml file in /PATH/TO/ELYTRON/EXAMPLES/simple-webapp-saml/src/main/webapp/WEB-INF. Update the keycloak-saml.xml file as follows: Set the SP entityID to "simple-webapp-saml" Set the SP logoutPage to "/simple-webapp-saml" Replace the SP Keys configuration with the following configuration, being sure to use the aliases and passwords you specified when exporting the SAML keys to the keystore.jks file: <Keys> <Key signing="true"> <KeyStore password="password" file="/etc/keycloak-saml-secret-volume/keystore.jks"> <PrivateKey alias="simple-webapp-saml" password="password"/> <Certificate alias="myrealm"/> </KeyStore> </Key> </Keys> Push this new file to the simple-webapp-saml directory in your elytron-examples fork, making sure to push the changes to your fork’s default branch. cd /PATH/TO/ELYTRON/EXAMPLES/simple-webapp-saml git add src/main/webapp/WEB-INF/keycloak-saml.xml git commit -m "Added Keycloak adapter deployment descriptor file" git push origin main Add Helm Configuration Let’s switch to the charts directory in our simple-webapp-saml example: cd /PATH/TO/ELYTRON/EXAMPLES/simple-webapp-saml/charts Notice there’s a helm.yaml file in this directory with the following content: build: uri: https://github.com/YOUR_GITHUB_USERNAME/elytron-examples (1) contextDir: simple-webapp-saml deploy: volumes: - name: saml-keystore-volume secret: secretName: simple-webapp-saml-secret volumeMounts: - name: saml-keystore-volume mountPath: /etc/keycloak-saml-secret-volume readOnly: true Replace YOUR_GITHUB_USERNAME in the build uri with your own GitHub username. The helm.yaml file specifies the Git repository that contains our application’s source code. Because we have modified the application’s source code by adding a keycloak-saml.xml file, you need to set the build uri in the helm.yaml file to point to your own fork. Notice that our helm.yaml file also refers to the OpenShift secret, simple-webapp-saml-secret we created earlier. This will be used to mount the keystore.jks file on our WildFly server pod. Deploy the Example Application to WildFly on OpenShift We can deploy our example application to WildFly on OpenShift using the WildFly Helm Chart: helm install saml-app -f /PATH/TO/ELYTRON/EXAMPLES/simple-webapp-saml/charts/helm.yaml wildfly/wildfly Notice that this command specifies the file we updated, helm.yaml, that contains the values needed to build and deploy our application. The application will now begin to build. This will take a couple of minutes. The build can be observed using: oc get build -w Once complete, you can follow the deployment of the application using: oc get deployment oidc-app -w Alternatively, you can check status directly from the OpenShift web console. Behind the Scenes While our application is building, let’s take a closer look at our application’s pom.xml file. Notice that it contains the following wildfly-maven-plugin configuration: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.plugin}</version> <configuration> <feature-packs> <feature-pack> <location>org.wildfly:wildfly-galleon-pack:${version.wildfly}</location> </feature-pack> <feature-pack> <location>org.wildfly.cloud:wildfly-cloud-galleon-pack:${version.wildfly.cloud.galleon.pack}</location> </feature-pack> <feature-pack> <location>org.keycloak:keycloak-saml-adapter-galleon-pack:${version.keycloak}</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>keycloak-client-saml</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> This configuration is used to provision a WildFly server with the specified layers and with our application deployed. The keycloak-client-saml layer automatically adds the Keycloak SAML adapter to our WildFly installation. Get the Application URL Once the WildFly server has been provisioned, use the following command to find the URL for your example application: SIMPLE_WEBAPP_SAML_URL=https://$(oc get route saml-app --template='{{ .spec.host }}') && echo "" && echo "Application URL: $SIMPLE_WEBAPP_SAML_URL/simple-webapp-saml" && echo "Master SAML Processing URL: $SIMPLE_WEBAPP_SAML_URL/simple-webapp-saml/saml" && echo "" We’ll make use of these URLs in the next two sections. Finish Configuring Keycloak From your simple-webapp-saml client in the Keycloak Administration Console, In the client settings, set Master SAML Processing URL to the Master SAML Processing URL that was output in the previous section and then click Save. Access the Application From your browser, navigate to the Application URL. Click on Access Secured Servlet. You will be redirected to Keycloak to log in. Log in using the alice user we created earlier. Upon successful authentication, you will be redirected back to the example application. The example application simply outputs the email address associated with our logged in user. You should see the following output: Current Principal 'alice@example.org' This indicates that we have successfully logged into our application! What’s next? This guide has shown how to secure an application deployed to WildFly on OpenShift with SAML. For additional information, feel free to check out the resources linked below. References Getting Started with WildFly on OpenShift OpenShift CLI WildFly Helm Chart Getting started with Keycloak on OpenShift Keycloak Server Administration Guide Using SAML to secure applications and services ### [TITLE OF THE GUIDE](/guides/template/) TITLE OF THE GUIDE Table of Contents Prerequisites A section Another section What’s next? References TODO: Add a summary of what you achieve in this guide. Something like: In this guide, you will learn how to setup and use Eclipse MicroProfile Config in your application. Prerequisites To complete this guide, you need: Roughly 10 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Any additional prerequisites specific to this guide (eg you have completed a previous guide) A section Lorem ipsum Another section What’s next? Something like: MicroProfile Config provides multiple options to read the configuration from various sources (System properties, environment variables, ConfigMaps and Secrets from Kubernetes), you can learn more by reading WildFly’s MicroProfile Config Subsystem Configuration Guide or reading the specification at Eclipse MicroProfile Config website. References Eclipse MicroProfile Config MicroProfile Config Subsystem Configuration ### [Testing WildFly Applications with Arquillian and JUnit 5](/guides/testing-arquillian-junit5/) Testing WildFly Applications with Arquillian and JUnit 5 Table of Contents Prerequisites Add JUnit and Arquillian Dependencies Configure POM for Provisioning Writing Tests Client Test In Container Test What’s next? References In this guide you will learn how to setup your project for testing with Arquillian and JUnit 5. We will use the arquillian-junt5 example project in this guide. Prerequisites To complete this guide, you need: Roughly 15 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Add JUnit and Arquillian Dependencies In order to use JUnit and Arquillian for your tests, you need to update the Maven pom.xml. The best practice is to import the Arquillian, JUnit 5 and WildFly Arquillian BOM’s. <dependencyManagement> <dependencies> <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-bom</artifactId> <version>${version.jakarta.ee}</version> <scope>import</scope> <type>pom</type> </dependency> <dependency> <groupId>org.jboss.arquillian</groupId> <artifactId>arquillian-bom</artifactId> <version>${version.org.jboss.arquillian}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.wildfly.arquillian</groupId> <artifactId>wildfly-arquillian-bom</artifactId> <version>${version.org.wildfly.arquillian}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.junit</groupId> <artifactId>junit-bom</artifactId> <version>${version.org.junit}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> You then need a minimum of the following dependencies. <dependencies> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.junit5</groupId> <artifactId>arquillian-junit5-container</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.wildfly.arquillian</groupId> <artifactId>wildfly-arquillian-container-managed</artifactId> <scope>test</scope> </dependency> </dependencies> In this section we will work on writing a test for our application. We will assume here you already have experience writing EE applications for WildFly. For the purpose of this test, we will use the wildfly-maven-plugin to provision a server for testing. Configure POM for Provisioning <build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly-maven-plugin}</version> <configuration> <jboss-home>${jboss.home}</jboss-home> <provisioning-dir>${jboss.home}</provisioning-dir> <feature-packs> <feature-pack> <groupId>org.wildfly</groupId> <artifactId>wildfly-ee-galleon-pack</artifactId> </feature-pack> </feature-packs> <channels> <channel> <manifest> <groupId>org.wildfly.channels</groupId> <artifactId>wildfly-ee</artifactId> </manifest> </channel> </channels> <layers> <layer>ee-core-profile-server</layer> <layer>jpa</layer> <layer>h2-default-datasource</layer> <layer>transactions</layer> </layers> <galleon-options> <jboss-fork-embedded>true</jboss-fork-embedded> </galleon-options> </configuration> <executions> <execution> <id>provision-server</id> <goals> <goal>provision</goal> </goals> <phase>process-test-resources</phase> </execution> </executions> </plugin> </plugins> </build> The above configuration will provision a server based with EE Core Profile specifications, Jakarta Persistence, Jakarta Transactions and the default H2 data source. The layers can be removed to provision a full WildFly server. The provisioning is bound to the process-test-resources phase. This is the last phase before the test phase which is when our tests will be executed by default. We need a server before we can use Arquillian for our tests. Writing Tests Now that our POM is configured, we can write a test for our application. The first step is to tell JUnit 5 we want to extend the functionality with Arquillian. The simplest approach is to annotate your test with @ArquillainTest. The other option is to annotate the test with @ExtendWith(ArquillianExtension.class). @ArquillianTest public class AddTaskResourceTest { } Client Test Arquillian can run both in the container or as a client. For the first example we will run as a client. When running as a client the test runs outside the container. The simplest way to run as a client is to use the @RunAsClient annotation. @ArquillianTest @RunAsClient public class AddTaskResourceTest { } The next thing Arquillian needs is a deployment. You can use Shrinkwrap to create a deployment. Note Shrinkwrap is a transitive dependency of Arquillian. @ArquillianTest @RunAsClient public class AddTaskResourceTest { @Deployment public static WebArchive createDeployment() { return ShrinkWrap.create(WebArchive.class) .addPackages(true, "org.wildfly.guide.testing") .addAsResource("META-INF/persistence.xml") .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); } } We can now add a test method using standard JUnit 5 testing strategies. @ArquillianTest @RunAsClient public class AddTaskResourceTest { @ArquillianResource private URI uri; @Deployment public static WebArchive createDeployment() { return ShrinkWrap.create(WebArchive.class) .addPackages(true, "org.wildfly.guide.testing") .addAsResource("META-INF/persistence.xml") .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); } @Test public void addTask() { final Task toAdd = new Task(); toAdd.setSummary("This is a test task"); toAdd.setDescription("This the test tasks description"); try ( Client client = ClientBuilder.newClient(); Response createdResponse = client.target(UriBuilder.fromUri(uri).path("api/task/")).request() .post(Entity.json(toAdd))) { Assertions.assertEquals(Response.Status.CREATED, createdResponse.getStatusInfo(), () -> String.format("Invalid status: %s", createdResponse.readEntity(String.class))); // We should have the location try (Response response = client.target(createdResponse.getLocation()).request().get()) { Assertions.assertEquals(Response.Status.OK, response.getStatusInfo(), () -> String.format("Invalid status: %s - %s", createdResponse.readEntity(String.class), createdResponse.getLocation())); final Task resolvedTask = response.readEntity(Task.class); Assertions.assertNotNull(resolvedTask); Assertions.assertTrue(resolvedTask.getId() > 0, () -> String.format("Expected the task to have an ID greater than 0: %s", resolvedTask.getId())); } } } } Note The @ArquillianResource can be used in inject various resources from Arquillian and WildFly Arquillian. In this example we inject a URI for the deployment. In Container Test In container tests have a similar structure to client based test. However, the test itself runs inside the container. This allows you to use CDI to inject beans into your test for example. @ArquillianTest @RequestScoped @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class TaskRegistryTest { @Inject private TaskRegistry taskRegistry; @Deployment public static WebArchive createDeployment() { return ShrinkWrap.create(WebArchive.class) // Note for this test we don't use the REST endpoints so we don't need the REST resources .addClasses(TaskRegistry.class, Priority.class, Task.class, Producers.class, TaskListener.class) .addAsResource("META-INF/persistence.xml") .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); } @Test @Order(1) public void addTask(final TestInfo testInfo) { final Task task = new Task(); task.setAdded(Instant.now()); task.setDescription("This is a test task from " + testInfo.getTestMethod() .map(Method::getName) .orElse("<unknown>")); task.setPriority(Priority.IMPORTANT); task.setSummary("Test summary"); final var addedTask = taskRegistry.add(task); Assertions.assertEquals(task, addedTask); } } What’s next? Using JUnit 5 and Arquillian for testing offers several options for testing your application with WildFly. WildFly Arquillian includes some additional utilities not discussed in this guide such as the ability to configure server settings before your test executes. An advanced guide will dig deeper into the additional options for using Arquillian on WildFly. References Arquillian WildFly Maven Plugin Example Project ### [guides/use-microprofile-amqp-connector-with-ssl-openshift.adoc](/guides/use-microprofile-amqp-connector-with-ssl-openshift/) Use MicroProfile Reactive Messaging with AMQP Connector with SSL Connection to AMQ 7 on OpenShift Table of Contents Prerequisites Deploy AMQ 7 using operator Install AMQ 7 operator Generate self-signed certificates for keystore and truststore Deploy AMQ 7 broker Build Reactive Messaging application using WildFly Glow What’s next? References In this guide, we will learn how to set up MicroProfile Reactive Messaging application with AMQP Connector to connect to AMQ 7 deployed on OpenShift. Communication will be secured using SSL/TLS. Prerequisites To complete this guide, you need: Roughly 15 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Access to an OpenShift cluster (try the "Self-managed" variant of local development machine Red Hat OpenShift for free) OpenShift CLI == Log Into the OpenShift Cluster Before we can deploy our application, we need to log in to an OpenShift cluster. You can log in via the OpenShift CLI: oc login -u myUserName Alternatively, you can log in using an API token: oc login --token=myToken --server=myServerUrl You can request the token via the Copy Login Command link in the OpenShift web console. If you don’t already have a project created, you can create one using: oc new-project myProjectName Deploy AMQ 7 using operator Install AMQ 7 operator Follow instruction in Installing the Operator using OperatorHub Generate self-signed certificates for keystore and truststore To establish an SSL/TLS connection we need keystore and truststore. Here for demonstration purposes we prepare a self-signed certificate. Note To ensure that the broker certificate has the correct domain of the OpenShift cluster for hostname verification during TLS handshake, you must be logged in using the 'oc' command. This step is crucial as the client verifies the broker’s hostname in the certificate. # Generate broker's key pair using obtained OpenShift cluster domain for `apps` keytool -genkeypair -alias broker -keyalg RSA -storetype PKCS12 -keystore broker.ks -storepass changeit -validity 365 -dname "CN=*.`oc get ingresscontroller default -o jsonpath='{.status.domain}' -n openshift-ingress-operator `, OU=My Org Unit, O=My Organization, L=My City, S=My State, C=My Country" # Generate key pair for Reactive Messaging application keytool -genkeypair -alias client -keyalg RSA -storetype PKCS12 -keystore client.ks -storepass changeit -validity 365 -dname "CN=localhost, OU=My Org Unit, O=My Organization, L=My City, S=My State, C=My Country" # Export broker certificate keytool -export -alias broker -file broker.cert -keystore broker.ks -storepass changeit # Export client certificate keytool -export -alias client -file client.cert -keystore client.ks -storepass changeit # Import broker and client certificate into a single truststore for simplicity keytool -import -v -trustcacerts -alias client -file client.cert -keystore client.ts -storepass changeit -noprompt keytool -import -v -trustcacerts -alias broker -file broker.cert -keystore client.ts -storepass changeit -noprompt Deploy AMQ 7 broker First we need to create secret with server keystore and truststore which will be used by AMQ 7 broker: oc create secret generic brokeramqp-ssl-secret --from-file=broker.ks --from-file=client.ts --from-literal=keyStorePassword='changeit' --from-literal=trustStorePassword='changeit' Then create file broker.yaml with following content referencing above secret: apiVersion: broker.amq.io/v1beta1 kind: ActiveMQArtemis metadata: name: amq-broker application: amq-broker-app spec: acceptors: - port: 61617 verifyHost: false needClientAuth: true expose: true multicastPrefix: jms.topic. name: all connectionsAllowed: 10 sslEnabled: true protocols: all sslSecret: brokeramqp-ssl-secret sslProvider: JDK anycastPrefix: jms.queue. console: expose: true deploymentPlan: journalType: nio messageMigration: false persistenceEnabled: false requireLogin: false size: 1 upgrades: enabled: false minor: false To simplify this example, there is set verifyHost: false to avoid need to set correct hostname in the "client" certificate for Reactive Messaging application. Run following command to deploy AMQ 7 broker with secured acceptor: oc create -f broker.yaml Check that AMQ 7 broker is in Running state by checking running pods: $ oc get pods NAME READY STATUS RESTARTS AGE amq-broker-ss-0 1/1 Running 0 79m ... Build Reactive Messaging application using WildFly Glow We will use an example of Reactive Messaging application in this guide, that consists of a single ProducingBean and ConsumingBean. Where ProducingBean periodically produces messages into the channel and ConsumingBean consumes them. It also contains needed scripts and yaml files to set up AMQ 7 broker on OpenShift. Example application is available on GitHub: git clone git@github.com:wildfly-extras/guides.git cd guides/microprofile-reactive-messaging-amqp-connector-example/ The important part of the application is microprofile-config.properties file configuring secured AMQP connector to remote AMQ 7 broker: amqp-host=${AMQ_HOST} amqp-port=443 amqp-username=admin amqp-password=admin amqp-use-ssl=true mp.messaging.connector.smallrye-amqp.wildfly.elytron.ssl.context=amqp-ssl-context mp.messaging.outgoing.source.connector=smallrye-amqp mp.messaging.incoming.in.connector=smallrye-amqp mp.messaging.incoming.in.address=source amqp-host - url of remote AMQ 7 broker deployed on OpenShift, for example "amq-broker-all-0-svc-rte-mnovak.apps.mnovak-oegn.psi.domain.com". amqp-port - port where AMQ 7 broker is listening, in case of OpenShift there is used port 443 for secured communication amqp-username and amqp-password - username and password for authentication to AMQ 7 broker. admin/admin is default used in AMQ 7 broker amqp-use-ssl=true - specifies that we want to use a secure connection when connecting to the broker. mp.messaging.outgoing.source.connector=amqp-ssl-context - this is not needed if there are CA signed certificates. However, in our case we’re using self-signed certificates, so we need to specify a truststore in the Elytron subsystem and create an SSLContext referencing that. The value of this property is used to look up the SSLContext in the Elytron subsystem under /subsystem=elytron/client-ssl-context=* in the WildFly management model. In this case the property value is amqp-ssl-context, so we look up the SSLContext defined by /subsystem=elytron/client-ssl-context=amqp-ssl-context and use that to configure the truststore to use for the connection to AMQ broker. For this reason there is defined CLI script scripts/config.cli which will be used to configure client-ssl-context when the WildFly server is provisioned and configured: batch /subsystem=elytron/key-store=truststore-ssl-test:add(credential-reference={clear-text=changeit}, path=<path-to>/client.ts, type=PKCS12) /subsystem=elytron/trust-manager=truststore-ssl-test:add(key-store=truststore-ssl-test) /subsystem=elytron/key-store=keystore-ssl-test:add(credential-reference={clear-text=changeit}, path=<path-to>/client.ks, type=PKCS12) /subsystem=elytron/key-manager=keystore-ssl-test:add(key-store=keystore-ssl-test,credential-reference={clear-text=changeit}) /subsystem=elytron/client-ssl-context=amqp-ssl-context:add(trust-manager=truststore-ssl-test,key-manager=keystore-ssl-test) run-batch Note Update <path-to> in above cli script to directory with generated truststore and keystore. You can build the application by running: mvn package The application uses the WildFly Maven Plugin to provision an application server that is trimmed with only the required modules to run the application. It deploys reactive messaging app into it and package all as Bootable Jar which can be started like: AMQ_HOST=<amq-broker-route> java -jar ./target/server-bootable.jar You can figure out value for AMQ_HOST by checking oc get routes for amq-broker-all-0-svc-rte route. Like: $ oc get routes NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD amq-broker-all-0-svc-rte amq-broker-all-0-svc-rte-mnovak.apps.eapqe-034-nvf2.eapqe.psi.redhat.com amq-broker-all-0-svc all-0 passthrough/None None ... Once application starts you should see output like: 17:28:45,819 INFO [stdout] (vert.x-eventloop-thread-0) ----> Calling generate!!!! 17:28:45,820 INFO [stdout] (vert.x-eventloop-thread-0) =====> Creating Next with 1 17:28:45,821 INFO [io.smallrye.reactive.messaging.amqp] (vert.x-eventloop-thread-0) SRMSG16203: AMQP Receiver listening address source 17:28:45,921 INFO [stdout] (pool-13-thread-1) ---> Sending 1 17:28:45,926 INFO [stdout] (pool-13-thread-1) ----> Calling generate!!!! 17:28:45,927 INFO [stdout] (pool-13-thread-1) =====> Creating Next with 2 17:28:46,027 INFO [stdout] (pool-13-thread-1) ---> Sending 2 17:28:46,027 INFO [stdout] (pool-13-thread-1) ----> Calling generate!!!! 17:28:46,027 INFO [stdout] (pool-13-thread-1) =====> Creating Next with 4 17:28:46,046 INFO [stdout] (vert.x-eventloop-thread-0) ---> Received 1 17:28:46,128 INFO [stdout] (pool-13-thread-1) ---> Sending 4 17:28:46,128 INFO [stdout] (pool-13-thread-1) ----> Calling generate!!!! 17:28:46,128 INFO [stdout] (pool-13-thread-1) =====> Creating Next with 8 17:28:46,140 INFO [stdout] (vert.x-eventloop-thread-0) ---> Received 2 What’s next? WildFly MicroProfile Reactive Messaging provides multiple options to connect to different messaging brokers like Kafka. Read the configuration from MicroProfile Reactive Messaging Subsystem Configuration References SmallRye Reactive Messaging Setting up SSL connections with ArtemisCloud Operator MicroProfile Reactive Messaging Subsystem Configuration WildFly Glow Documentation ### [Using MicroProfile Config](/guides/use-microprofile-config/) Using MicroProfile Config Table of Contents Prerequisites Configure Your App to make use of MicroProfile Config Add Dependency on the WildFly MicroProfile BOM Add Dependency to MicroProfile Config API Use the MicroProfile Config API What’s next? References In this guide, you will learn how to setup and use Eclipse MicroProfile Config in your application. Prerequisites To complete this guide, you need: Roughly 10 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Configure Your App to make use of MicroProfile Config In order to use MicroProfile Config in your application, you need to update the Maven pom.xml at different places: Add a dependency on WildFly BOM for MicroProfile in the <dependencyManagement> section Add a dependency on the MicroProfile Config API in the <dependencies> section Once these 2 steps have been completed, you will be able to use MicroProfile Config in your application. Add Dependency on the WildFly MicroProfile BOM You need to add a dependency on the WildFly MicroProfile BOM org.wildfly.bom:wildfly-microprofile in the <dependencyManagement> section so your application will use the correct version of the MicroProfile Config provided by WildFly. The dependency is defined as: <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>wildfly-microprofile</artifactId> <version>${version.wildfly}</version> <type>pom</type> <scope>import</scope> </dependency> It must be added to the <dependencyManagement> of your pom.xml: <dependencyManagement> <dependencies> ... <!-- copy the dependency here --> </dependencies> </dependencyManagement> Note WildFly BOMS are the only dependencies that must be added to the <dependencyManagement><dependencies> section. Other dependencies are added directly to the <dependencies> section of the Maven pom.xml. Add Dependency to MicroProfile Config API Next, you need to add a dependency on the MicroProfile Config API org.eclipse.microprofile.config:microprofile-config-api. The dependency is defined as: <dependency> <groupId>org.eclipse.microprofile.config</groupId> <artifactId>microprofile-config-api</artifactId> <scope>provided</scope> </dependency> It must be added to the <dependencies> of your pom.xml: <dependencies> ... <!-- copy the dependency here --> </dependencies> Use the MicroProfile Config API You can now use Eclipe MicroProfile Config in your application. As an example, you can update the GettingStartedService.java file to configure the text that displays "Hello": package org.wildfly.examples; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import org.eclipse.microprofile.config.inject.ConfigProperty; @ApplicationScoped public class GettingStartedService { @Inject @ConfigProperty(name = "hello.text", defaultValue = "Hello") String helloText; public String hello(String name) { return String.format(helloText + " '%s'.", name); } } In this example, you have annotated a helloText String with a ConfigProperty annotation. You can now use the hello.text system property or the HELLO_TEXT environment variable to change the output of the hello method. The default value of the helloText is configured in the ConfigProperty annotation with the defaultValue attribute. Once the GettingStartedService.java file is modified, you can repackage your application and restart it with the HELLO_TEXT environment variable set to Bonjour: mvn clean package HELLO_TEXT="Bonjour" ./target/server/bin/standalone.sh If you now access the application at http://localhost:8080 and type World in the text field, it now returns Bonjour, World. What’s next? MicroProfile Config provides multiple options to read the configuration from various sources (System properties, environment variables, ConfigMaps and Secrets from Kubernetes), you can learn more by reading WildFly’s MicroProfile Config Subsystem Configuration Guide or reading the specification at Eclipse MicroProfile Config website. References Eclipse MicroProfile Config MicroProfile Config Subsystem Configuration ### [Using MicroProfile LRA](/guides/use-microprofile-lra/) Using MicroProfile LRA Table of Contents Prerequisites Introduction Overview of the LRA protocol Enabling the MicroProfile LRA subsystems Required extensions and subsystems configuration Running the LRA coordinator in a Docker container Using LRA in user deployments What’s next? In this guide, you will learn how to setup and use Eclipse MicroProfile LRA in your application. Prerequisites To complete this guide, you need: Roughly 15 minutes JDK 17+ installed with JAVA_HOME configured appropriately Apache Maven 3.9+ Introduction MicroProfile Long Running Actions (LRA) is a specification that defines the protocol and an API for distributed transactions based on the saga pattern and user-defined compensations. In WildFly 28.0.0.Final, we introduced the integration of Narayana LRA which implements this specification. In this guide, we look into how you can enable LRA in your WildFly installation and how you can use LRA in your applications. Overview of the LRA protocol We provide only a high-level overview of the LRA protocol in this post. The full overview of the protocol is available at https://download.eclipse.org/microprofile/microprofile-lra-2.0/microprofile-lra-spec-2.0.html. In LRA, the specification API utilizes annotations from the org.eclipse.microprofile.lra.annotation package. The main annotation is @LRA which controls the life cycle of the long running action. It’s use might seem similar to the use of @Transactional annotation from JTA, however, the transaction characteristics differ greatly. If you are interested in the comparison of the saga pattern to the ACID transactions, you can find an explanation in this talk from DevoxxUK - https://www.youtube.com/watch?v=7DI4xXv1xGU. The Narayana implementation utilizes the coordinator orchestration of the LRAs. The LRA coordinator is a standalone service that is responsible for the management operations of the LRAs started in the system. When any LRA participant (user service) wants to start a new LRA, it contacts the LRA coordinator that in turn returns the LRA ID of the newly started LRA that can be propagated by the LRA participant to any other services. When an LRA-aware service receives the LRA ID, it can optionally enlist within the same LRA, which is again done by the enlistment call to the coordinator. When the LRA finishes (success or failure), the LRA coordinator is responsible for invocations of the completions or the compensations callbacks of all enlisted LRA participants. Enabling the MicroProfile LRA subsystems The integration of the LRA specification is included in two separate subsystems: microprofile-lra-coordinator - The LRA coordinator responsible for starting, managing, and recovery of the LRAs. microprofile-lra-participant - The client library utilized in user deployments to participate in distributed LRAs and define compensation and completition callbacks. Required extensions and subsystems configuration The LRA extensions are not included in the standard configurations included with the WildFly application server. They need to be explicitly enabled either in the configuration XML or by using CLI operations: [standalone@localhost:9990 /] /extension=org.wildfly.extension.microprofile.lra-coordinator:add {"outcome" => "success"} [standalone@localhost:9990 /] /subsystem=microprofile-lra-coordinator:add { "outcome" => "success", "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } } [standalone@localhost:9990 /] /extension=org.wildfly.extension.microprofile.lra-participant:add {"outcome" => "success"} [standalone@localhost:9990 /] /subsystem=microprofile-lra-participant:add { "outcome" => "success", "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } } [standalone@localhost:9990 /] reload Running the LRA coordinator in a Docker container The LRA coordinator is also provided as a standalone Docker image that you can simply run with the following command: $ docker run -p 8080:8080 quay.io/jbosstm/lra-coordinator Using LRA in user deployments The @LRA annotation can be placed on any JAX-RS method to declare that the LRA should be started before the method is entered and closed (finished successfully) when the method ends. By default, if the JAX-RS method returns any of the 4xx or 5xx error HTTP status codes the LRA will be cancelled instead. @LRA @GET @Path("/doInLRA") public Response doInLRA(@HeaderParam(LRA.LRA_HTTP_CONTEXT_HEADER) String lraId) { LOG.info("Work LRA ID = " + lraId); ... When LRA closes successfully, the LRA coordinator calls the completion callback if the participant defined it: @Complete @PUT @Path("/complete") public Response complete(@HeaderParam(LRA.LRA_HTTP_CONTEXT_HEADER) String lraId) { LOG.info("Complete ID = " + lraId); ... Or, in the case of LRA cancel, the compensation callback will be invoked instead: @Compensate @PUT @Path("/compensate") public Response compensate(@HeaderParam(LRA.LRA_HTTP_CONTEXT_HEADER) String lraId) { LOG.info("Compensate ID = " + lraId); ... The full example is available at https://github.com/xstefank/lra-wildfly-example. If you deploy this application to WildFly (28.0.0+) with both microprofile-lra-coordinator and microprofile-lra-participant subsystems enabled, you can make the following HTTP invocation to see how the coordinator invokes the complete callbacks or the compensation callbacks of the two defined participants: $ curl localhost:8080/lra-participant/lra-participant-1/doInLRA # in WFLY console log 15:14:50,128 INFO [io.xstefank.LRAParticipant1] (default task-1) Work LRA ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_14 15:14:50,158 INFO [io.xstefank.LRAParticipant2] (default task-2) Work LRA ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_14 15:14:50,183 INFO [io.xstefank.LRAParticipant1] (default task-3) Complete ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_14 15:14:50,191 INFO [io.xstefank.LRAParticipant2] (default task-3) Complete ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_14 $ curl "localhost:8080/lra-participant/lra-participant-1/doInLRA?fail=true" # in WFLY console log 15:15:33,516 INFO [io.xstefank.LRAParticipant1] (default task-1) Work LRA ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_1c 15:15:33,531 INFO [io.xstefank.LRAParticipant2] (default task-2) Work LRA ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_1c 15:15:33,543 INFO [io.xstefank.LRAParticipant1] (default task-3) Compensate ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_1c 15:15:33,550 INFO [io.xstefank.LRAParticipant2] (default task-3) Compensate ID = http://localhost:8080/lra-coordinator/lra-coordinator/0_ffff0aca8851_-3330598e_646cbc18_1c You can also always check the currently active LRAs with a direct call to the coordinator API: $ curl localhost:8080/lra-coordinator/lra-coordinator []% What’s next? In this guide, we showed you how to configure and use the MicroProfile LRA specification in your WildFly applications. LRA provides a very broad feature set which we can’t cover here. If you are interested in learning more, you can find the full specification at https://download.eclipse.org/microprofile/microprofile-lra-2.0/microprofile-lra-spec-2.0.html. ### [Using the WildFly EE 10 Feature-pack](/guides/wildfly-ee-10-feature-pack/) Using the WildFly EE 10 Feature-pack Starting with WildFly 40, the default WildFly distribution provides EE 11 APIs and implementations. If your applications use the EE 10 version, you can continue to run them on WildFly by using the new WildFly EE 10 feature-pack and its associated distribution and BOMs. In this guide, you will learn how to: Download the WildFly EE 10 distribution archive Provision a WildFly server with EE 10 support using the wildfly-maven-plugin Use the EE 10 BOMs in your application’s pom.xml Use the WildFly EE 10 container images Downloading the WildFly EE 10 Distribution If you prefer to download a pre-built WildFly server with EE 10 support, the WildFly EE 10 Distribution is available from the WildFly Downloads page. This distribution is a full WildFly server pre-configured with EE 10 APIs and implementations. You can use it as a drop-in replacement for the standard WildFly distribution if your applications rely on EE 10. Download and unzip the archive, then start the server: unzip wildfly-ee-10-40.0.0.Final.zip cd wildfly-ee-10-40.0.0.Final ./bin/standalone.sh You can then deploy your EE 10 applications to this server as you would with any version of WildFly. Provisioning WildFly with the EE 10 Feature-Pack If you use the wildfly-maven-plugin to provision WildFly, you need to update its configuration to use the EE 10 feature-pack instead of the default one. The EE 10 feature-pack Maven coordinates are: Group ID org.wildfly Artifact ID wildfly-ee-10-feature-pack Using <feature-packs> configuration You can configure the wildfly-maven-plugin to provision WildFly with the EE 10 feature-pack by specifying it explicitly in the feature-packs configuration before the existing org.wildfly:wildfly-galleon-pack feature-pack: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <feature-packs> <feature-pack> <groupId>org.wildfly</groupId> <artifactId>wildfly-ee-10-feature-pack</artifactId> <version>40.0.0.Final</version> </feature-pack> <feature-pack> <groupId>org.wildfly</groupId> <artifactId>wildfly-galleon-pack</artifactId> <version>40.0.0.Final</version> </feature-pack> </feature-packs> <layers> […​] </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> Important The order of the <feature-pack> elements is significant: the org.wildfly:wildfly-ee-10-feature-pack feature-pack must be listed before the org.wildfly:wildfly-galleon-pack feature-pack. As an alternative to the Maven coordinate org.wildfly:wildfly-ee-10-feature-pack:${wildfly.version}, you can also use the feature-pack location wildfly-ee-10@maven(org.jboss.universe:community-universe) that resolves to the latest version of the EE 10 feature-pack from the WildFly community universe. Using WildFly Glow discovery If you use WildFly Glow to automatically discover the Galleon layers needed by your application, you can specify the EE 10 feature-pack in the discover-provisioning-info configuration with the server-variant property set to ee-10: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <discover-provisioning-info> <version>${version.wildfly.bom}</version> <server-variant>ee-10</server-variant> </discover-provisioning-info> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> Using a WildFly Channel You can also use the WildFly EE 10 channel to resolve the feature-pack version. The channel manifest coordinates are org.wildfly.channels:wildfly-compat-ee-10 and it must be configured instead of the org.wildfly.channels:wildfly channel: <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>${version.wildfly.maven.plugin}</version> <configuration> <channels> <channel> <manifest> <groupId>org.wildfly.channels</groupId> <artifactId>wildfly-compat-ee-10</artifactId> </manifest> </channel> </channels> <feature-packs> <feature-pack> <groupId>org.wildfly</groupId> <artifactId>wildfly-ee-10-feature-pack</artifactId> </feature-pack> <feature-pack> <groupId>org.wildfly</groupId> <artifactId>wildfly-galleon-pack</artifactId> </feature-pack> </feature-packs> <layers> […​] </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> Important The order of the <feature-pack> elements is significant: the org.wildfly:wildfly-ee-10-feature-pack feature-pack must be listed before the org.wildfly:wildfly-galleon-pack feature-pack. Using the EE 10 BOMs Starting with WildFly 40, the existing org.wildfly.bom:wildfly-ee and org.wildfly.bom:wildfly-ee-with-tools BOMs provide EE 11 dependencies. To continue using EE 10 dependencies, update your pom.xml to use the EE 10 BOMs instead: EE 11 BOM (default) EE 10 BOM org.wildfly.bom:wildfly-ee org.wildfly.bom:wildfly-ee-10 org.wildfly.bom:wildfly-ee-with-tools org.wildfly.bom:wildfly-ee-10-with-tools For example, if your pom.xml currently imports the wildfly-ee BOM: <dependencyManagement> <dependencies> <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>wildfly-ee</artifactId> <version>${version.wildfly}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> Update it to use the EE 10 BOM: <dependencyManagement> <dependencies> <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>wildfly-ee-10</artifactId> <version>${version.wildfly}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> Similarly, if you use wildfly-ee-with-tools, replace it with wildfly-ee-10-with-tools. Container Images The standard WildFly container images are available from the quay.io/wildfly/wildfly images (see the WildFly Container Image documentation for details). Starting with WildFly 40, these images provide the default EE 11 distribution. To run the EE 10 distribution in a container, use the dedicated quay.io/wildfly/wildfly-ee-10 container images. Image Tags The EE 10 container images are available with the following tags: Tag Description 40.0.0.Final-jdk17 WildFly 40.0.0.Final EE 10 Distribution on JDK 17 40.0.0.Final-jdk21 WildFly 40.0.0.Final EE 10 Distributionon JDK 21 latest-jdk17 Latest WildFly EE 10 Distribution on JDK 17 latest-jdk21 Latest WildFly EE 10 Distribution on JDK 21 latest Latest WildFly EE 10 Distribution on latest TLS JDK. For example, to run the latest WildFly EE 10 distribution on JDK 21: podman run -p 8080:8080 quay.io/wildfly/wildfly-ee-10:latest-jdk21 Note Instead of using the latest tag, we recommend using a floating tag with the JDK version (e.g. latest-jdk21) to guarantee the use of the same JDK version across WildFly releases. What’s next? The WildFly EE 10 feature-pack is intended to ease the transition from EE 10 to EE 11 for your applications. It is planned to be available for a limited number of WildFly releases, so we encourage you to start planning your migration to EE 11. References WildFly Downloads WildFly Maven Plugin WildFly Glow WildFly Container Images ### [WildFly Release Announcements](/releases/) ### [Reporting of CVEs and Security Issues](/security/) ### [WildFly Project News](/news/) ### [WildFly Project News](/news/page/2/) ### [WildFly Project News](/news/page/3/) ### [WildFly Project News](/news/page/4/) ### [WildFly Project News](/news/page/5/) ### [WildFly Project News](/news/page/6/) ### [WildFly Project News](/news/page/7/) ### [WildFly Project News](/news/page/8/) ### [WildFly Project News](/news/page/9/) ### [WildFly Project News](/news/page/10/) ### [WildFly Project News](/news/page/11/) ### [WildFly Project News](/news/page/12/) ### [WildFly Project News](/news/page/13/) ### [WildFly Project News](/news/page/14/) ### [WildFly Project News](/news/page/15/) ### [WildFly Project News](/news/page/16/) ### [WildFly Project News](/news/page/17/) ### [WildFly Project News](/news/page/18/) ### [WildFly Project News](/news/page/19/) ### [WildFly Project News](/news/page/20/) ### [WildFly Project News](/news/page/21/) ### [WildFly Project News](/news/page/22/) ### [WildFly Project News](/news/page/23/) ### [WildFly Project News](/news/page/24/) ### [WildFly Project News](/news/page/25/) ### [WildFly Project News](/news/page/26/) ### [WildFly Project News](/news/page/27/) ### [WildFly Project News](/news/page/28/) ### [WildFly Project News](/news/page/29/) ### [WildFly Project News](/news/page/30/) ### [WildFly Project News](/news/page/31/) ### [WildFly Project News](/news/page/32/) ### [WildFly Project News](/news/page/33/) ### [WildFly Project News](/news/page/34/) ### [WildFly Project News](/news/page/35/)