Key Takeaways
- The wildfly-jar-maven-plugin allows you to package your application as an Uber JAR which includes only the parts of the WildFly application server and the Jakarta EE libraries which you deem appropriate for your application, and is suitable for various deployment scenarios including Kubernetes.
- The wildfly-jar-maven-plugin creates a nice, fast recompile and redeploy development experience not unlike those experiences found in projects like Quarkus, but this plugin is focused on Jakarta EE and WildFly.
- The wildfly-datasources-preview-galleon-pack enhances the already powerful wildfly-jar-maven-plugin by quickly enabling your application for JPA and related database-driven interaction by hot deploying current drivers and configuring the application server data sources on-the-fly via environment variables.
- Both tools are new and some best practices to fully employ the WildFly server in specific scenarios have yet to be addressed at least in a manner that is as efficient and slick as the wildfly-datasources-preview-galleon-pack.
- WildFly has a sub-project called wildfly-extras that has released these excellent tools to help you prepare for future versions of the WildFly Application Server that implements the Jakarta EE standard.
I love new toys. I really love new toys in technology stacks that are proven. I very much love new toys that allow me to play with new technology that is anticipated in products that are proven. Toys that are tools are the best of all.
In this article, I will discuss two new toys that, when used together, may very well become a must-have arrow for your software development quiver. These tools are the wildfly-jar-maven-plugin and the brand new wildfly-datasources-preview-galleon-pack from the WildFly project.
WildFly, an upstream project for the JBoss Application Server from RedHat, is a great solution for many projects. The application server is Jakarta EE 8 compatible and newer “preview” versions of the WildFly Application Server are compatible with Jakarta EE version 9.1.
The 2022 WildFly release plan includes preparing for the upcoming release of Jakarta 10 with a future “preview” of their Application Server so that developers can take the next release of the standard for a spin. Exciting.
For now, we’ll focus on WildFly 26.0.1 Preview – released in the last week of January – and Jakarta EE 9.1.
First New Toy
The wildfly-jar-maven-plugin allows developers to provision (determine what parts, dependencies or capabilities your application needs from the Application Server and perform any configuration required) a WildFly server and generate an Uber JAR that contains your application and the WildFly container using Maven. That is right. The whole Application Server and your application are bundled together in one tidy JAR file. Issue the command:
java -jar nameOfYourApplication-bootable.jar
and the server fires up and your application is ready to go. Drop that bootable JAR on a server on your LAN, deploy it on your edge device, deploy it in a containerized environment and, of course, in your target directory. You’ll still find your standard WAR file that holds your application ready for deployment in the Jakarta EE container running on bare metal or in a VM.
That is a lot of options and a whole bunch of configuration work, but this plugin makes it happen in a snap. This plugin appears to have been pushed to the Maven repository in 2020 and the most recent version, 7.0.0.Final, was pushed a couple of months ago. From the frequency of releases in the Maven repository, the plugin is clearly actively maintained.
As above with the application server and your application bundled up tightly together, you are a short hop away from a trivial Docker file in preparation for deployment on Kubernetes. Adding the plugin to your Maven pom.xml may look something like this:
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>**wildfly-jar-maven-plugin**</artifactId>
<version>${version.wildfly.jar.maven.plugin}</version>
<configuration>
<log-time>true</log-time>
<cloud>
<type>kubernetes</type>
</cloud>
<context-root>false</context-root>
<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>
<hollow-jar>false</hollow-jar>
<plugin-options>
<jboss-fork-embedded>true</jboss-fork-embedded>
</plugin-options>
<!-- Listen on all ports -->
<arguments>
<argument>-b=0.0.0.0</argument>
</arguments>
<!-- Make sure we can debug -->
<jvmArguments>
<arg>-agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=n</arg>
</jvmArguments>
<cli-sessions>
<cli-session>
<!-- Feed WildFly Some Properties -->
<properties-file>package_properties.properties</properties-file>
<!-- Run some jboss-cli.sh commands against WildFly -->
<script-files>
<script>package_script.cli</script>
</script-files>
</cli-session>
</cli-sessions>
<excluded-layers>
<!-- Just here to demonstrate one can take layers OUT of the Container -->
<layer>core-management</layer>
<layer>deployment-scanner</layer>
<layer>jmx-remoting</layer>
<layer>request-controller</layer>
<layer>security-manager</layer>
</excluded-layers>
<layers>
<!-- Some of these layers are redundant as Galleon dependencies take's care of most things -->
<layer>cloud-server</layer>
<layer>ejb-dist-cache</layer>
<layer>web-clustering</layer>
<layer>ee</layer>
<layer>ejb-lite</layer>
<layer>jaxrs</layer>
<layer>jpa</layer>
<layer>jsf</layer>
<layer>jsonb</layer>
<layer>jsonp</layer>
<!-- These go along with **wildfly-datasources-preview-galleon-pack** -->
<layer>datasources-web-server</layer>
<layer>postgresql-datasource</layer> <!-- Yes, there are other drivers available -->
</layers>
</configuration>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
The full documentation for building bootable JARs can be found here. To get you going quickly, I posted some sample code on GitHub. Clone this repository and issue the command:
mvn clean
mvn wildfly-jar:dev-watch
Second New Toy
Now that we’ve explored the first new toy, let’s take the “preview” version of WildFly for a spin. First, we’ll update the “feature pack” location from:
<location>wildfly@maven(org.jboss.universe:community-universe)#${version.wildfly}</location>
to
<location>wildfly-preview@maven(org.jboss.universe:community-universe)#${version.wildfly}</location>
We’ll also have to change the artifactId for the brand new wildfly-datasources-preview-galleon-pack so that we can connect our application to a database. After all, what is an application without data?
Next, update:
<artifactId>wildfly-datasources-galleon-pack</artifactId>
to
<artifactId>wildfly-datasources-preview-galleon-pack</artifactId>
The maintainers of the WildFly extras, the parent repository of Java community extras for WildFly, deserve much credit for making this available! This was really a nice addition and necessary to experiment with a database-driven application using the “preview” version of WildFly. It was pushed to Maven in the first week of February 2022.
Issue the command:
mvn wildfly-jar:dev-watch
and you are up-and-running. Your code is being watched and deployed as you save your files by the wildfly-jar-maven-plugin. And, with the wildfly-datasources-preview-galleon-pack, connecting to your database is trivial. Pretty nice.
Most IDE’s will allow you to issue the “mvn maven wildfly-jar:dev-watch” via their Maven GUI controls. Below is a screenshot from IntelliJ IDEA showing their Maven controls which includes the wildfly-jar-maven-plugin as configured in our pom.xml.
Just as on the command line, “mvn maven wildfly-jar:dev-watch”, the IDE will show the output of building, launching and configuring the sample application:
In the sample application’s persistence unit configuration, there is a jakarta.persistence.sql-load-script-source property that references the my_jpa_data_table.sql file located in the META-INF directory of the application. That SQL file is used to insert a few placeholder records into the database table used by the sample application. After launching the sample application, execute a quick SELECT command against the my_jpa_data_table table in PostgreSQL. In the screenshot below, this is what you will find after pointing the sample application at your database server and launching using the tools in this article:
And, just to demonstrate that the sample application fully round trips, you can pull up a browser to display the data in the application:
If you would like to see how these tools will speed up your application development time, leave the “mvn maven wildfly-jar:dev-watch” command running, edit the index.xhtml file in the sample application and save the file. You will see the application quickly redeploy and your changes reflected in the web browser. You can expect the same behavior, not only at the UI level of the application, but at every level; database up.
Cool. Toys.
A few tips if you take wildfly-preview along with the wildfly-datasources-preview-galleon-pack for a try using wildfly-jar-maven-plugin:
- The “layers” configuration handles any dependencies you may need from WildFly. If you know you are going to containerize, you can just start by adding the “cloud-server” layer and the “postgresql-datasource” or the datasource layer that matches your database.
- If there are “layers” you do not need, you can exclude them in order to thin up your Uber JAR. I excluded a few in my plugin configuration just to demonstrate that ability of the wildfly-jar-maven-plugin. Checkout the available layers and determine which are optional, or not necessary, for your needs.
- You will want to update the javax namespace in your application to jakarta. The regular version of WildFly will allow you to use either the older javax namespace or the newer jakarta namespace, but the preview version is focused on Jakarta EE, so you’ll need to consistently use import jakarta.* packages in your Java source code. The same should apply for your web.xml file if that applies to your project.
- Keep in mind that this is a preview, so it may very well be best to use the regular version in production.
One essential tip!
-
You will notice that nowhere did we define settings for the application to find our database server and the database within that server. The wildfly-datasources-preview-galleon-pack will read this information from environment variables. Now, you can set properties inside WildFly as well, but in practice, I’d recommend environment variables. This lends itself to containerization of the Application Server / Application Uber JAR.
Example of database environment variables on Linux:
export POSTGRESQL_HOST=server.withyourdatabase.com
export POSTGRESQL_PORT=5432
export POSTGRESQL_DATABASE=quickDb
export POSTGRESQL_USER=yourUsername
export POSTGRESQL_PASSWORD=yourSecretPassword
Alternatively, an example of database environment variables in an IDE:
After coming across the plugin and getting help from the WildFly community to ensure that I could connect to a database using the preview version, this combination of tools quickly hit a “can’t live without” status. I had to chide myself with “How did I miss this?” In combination, these Galleon “feature packs” and the wildfly-jar-maven-plugin is a really nice experience for the developer that can be enjoyed. This is especially true with mvn wildfly-jar:dev-watch!
Still, as useful as “mvn wildfly-jar:dev-watch” is when under active development, the goal is to get to a single database-aware JAR that has all the capabilities inherent in WildFly ready for deployment. This is simple enough with this plugin. Just issue the command:
mvn clean package wildfly-jar:package
Cool. Toys. Indeed!
Configuration Items to Consider
Basic configuration issues of your application can be addressed when using the wildfly-jar-maven-plugin. You will see that stubbed into the sample code in which there are a couple of (almost) empty files that can be used to add application environment variables and issue some additional configuration commands to complete your setup of WildFly.
You will see that in the package_script.cli file, I add the line:
/system-property=somePropertyName:add(value=somePropertyValue)
which sets the property “somePropertyName” to “somePropertyValue. Adding this line is essentially the same as issuing
${JBOSS_HOME}/bin/jboss-cli.sh /system-property=somePropertyName:add(value=somePropertyValue)
on the command line. The package_script.cli and package_properties.properties files referenced by the plugin in the sample code together seem to be sufficient for most of the application server configuration you may require.
Still, even with this provided flexibility, I haven’t yet determined the best practice for some configuration tasks. Not that there aren’t ways to address these configuration issues, but you will still need a plan.
Take, for example, a scenario where you need to keep credentials secure. If your application is going into a Kubernetes environment, you will likely use something like Bitnami’s Sealed Secrets or HashiCorp’s Vault so this is not a challenge. On your workstation, or server where you have the control of the operating environment, your application can reference this environment.
But, what if what is best for your application would be to store these credentials inside the WildFly container? WildFly includes an excellent security subsystem, Elytron, so this would be a natural fit to use the tool. The ability to store your credentials inside WildFly together with Elytron should be considered.
On your workstation or server, you would add a “secret-key-credential-store” using the ${JBOSS_HOME}/bin/jboss-cli.sh command. This series of commands might go something like:
history --disable
/subsystem=elytron/secret-key-credential-store=secret-key-credential-store:add(relative-to=jboss.server.config.dir, path=secretKeyCredentialStore.cs)
/subsystem=elytron/secret-key-credential-store=secret-key-credential-store:export-secret-key(alias=key)
/subsystem=elytron/expression=encryption:add(resolvers=[{name=secret-key-resolver, credential-store=secret-key-credential-store, secret-key=key}])
So far so good. But, the first obstacle in this “secure the credentials inside WildFly” configuration task now presents itself. The next two commands that you would need to issue, creating an expression for your clear text password (the input) to the first command and adding the output of this command to a “credential-store” are dependent:
/subsystem=elytron/expression=encryption:create-expression(resolver=secret-key-resolver, clear-text=passwordThatNoOneWillEverGuess)
/subsystem=elytron/credential-store=credential-store:add(relative-to=jboss.server.config.dir, path=credentialStoreCandela.cs, credential-reference={clear-text= OUTPUT_OF_PREVIOUS_COMMAND_AS_INPUT_HERE }, create=true)
Chaining outputs from one command to another while working in a terminal window is pretty straightforward. Or at worst, this is a once-in-a-while system administration task in which you would just cut-and-paste the expression from the first command into the second. Continuing on to complete the task is also pretty straightforward as you issue:
/subsystem=elytron/credential-store=credential-store:generate-secret-key(alias=key)
/subsystem=elytron/expression=encryption:list-add(name=resolvers, value={name=resolver, credential-store=credential-store, secret-key=key})
reload
/subsystem=elytron/expression=encryption:write-attribute(name=default-resolver, value=resolver)
reload
/subsystem=elytron/expression=encryption:create-expression(clear-text=passwordThatNoOneWillEverGuess)
history --enable
/subsystem=elytron/credential-store=credential-store:add-alias(alias=MyFirstCredential, secret-value=doNotShareThis)
/subsystem=elytron/credential-store=credential-store:add-alias(alias=MySecondCredential, secret-value=AlsoDoNotShareThis)
/subsystem=elytron/secret-key-credential-store=secret-key-credential-store:read-aliases
/subsystem=elytron/credential-store=credential-store:read-aliases
The “reload” commands shown above are necessary to complete the task and are not an issue on a workstation or server. Completing this task on-the-fly through the “mvn wildfly-jar:watch-dev” and “mvn clean package wildfly-jar:package” commands provide the process that appears to be “going forward.” This means the on-the-fly configuration performed by these tools doesn’t afford the opportunity to instruct the application server to reread and reload its master configuration file which, in this specific configuration task, is a required step.
Are there possible ways to approach a mildly complex configuration like this? Of course. Perhaps just copy in a configuration file and the appropriate supporting files in a chosen Maven phase. Perhaps see how far you can get by populating the package_script.cli and package_properties.properties with your particulars.
What would be ideal? I am not yet certain given my relatively short experience with the wildfly-jar-maven-plugin. My initial thoughts are that the wildfly-preview-datasources-galleon-pack is so slick that maybe a “wildfly-credential-store-galleon-pack” or some such new tooling artifact could be created in order to address this specific scenario. Perhaps adding the galleon-pack to the plugin configuration and let it read a whole number of environment variables (maybe with a predefined naming convention?) or read from a properties file safely stored outside of your application repository on your development workstation. This will enable you to load these credentials securely into Elytron on-the-fly just as the wildfly-preview-datasources-galleon-pack deals with database connectivity on-the-fly.
Again, I just chose securing credentials inside WildFly as a scenario where additional planning is required if you are going to use the plugin. I am sure you can imagine other configuration tasks for your application depending on your deployment needs should you bundle it in a bootable JAR.
Enough is Never Enough
This is so cool. What more could you want? I’m glad you asked because what kind of end user would I be if I didn’t want more?
I would like to use the Eclipse Vert.x drivers for connecting to my database and hope these make it into the wildfly-datasources-preview-galleon-pack. This wish presupposes that a new version of Hibernate, the JPA and ORM implementation in WildFly, pairs up with Hibernate Reactive. The Hibernate website indicates that this would be version 5.6. Hibernate 5.3 is the version packaged with wildfly-preview. Perhaps this becomes a non-issue if Hibernate ORM 6 reaches stable status in time for Jakarta EE 10. That Hibernate Reactive goodness is found in projects like Quarkus, and I’d love to see those capabilities available in WildFly. That is as long as these additions do not break compliance with the Jakarta EE standard. This shouldn’t be an issue as the standard typically doesn’t preclude “more” from an application server and/or tool vendor.
There is a WildFly MicroProfile Reactive Feature Pack but I didn’t see any specific references to Hibernate Reactive like Panache in that specific project repository.
Finally
These are not just new toys, but useful tools. Try out the wildfly-jar-maven-plugin and with it the wildfly-datasources-preview-galleon-pack if you are checking out wildfly-preview for your database driven application.
I posted a small sample project on GitHub if you’d like to take this combination of new tools for a try and are in a hurry. That trivial Dockerfile mentioned earlier and, for good measure, a sample Kubernetes YAML file are in the repository, too. The sample code has a reference SQL file, configured JPA persistence unit and JPA Object and a JSF page to display data if you choose to populate the table. The wildfly-datasources-preview-galleon-pack makes your bootable JAR database-aware with very little effort (just setting the environment variable to point to your database) and the sample application will fetch some data and display it.
Resources and Thank You
Jakarta EE really is a center of gravity in the Java ecosystem. It is very likely that if you are not using it directly by way of one or more of the many application servers, like WildFly, that implement the entire standard, you are using one of its libraries indirectly or as implemented by other Java projects in the ecosystem. The tools discussed in this article will make working with Jakarta EE and WildFly, in particular, a pleasant experience. There are so many great things happening in the Java and Jakarta EE space, a space where activity only seems to accelerate. It can be a challenge to not miss something that can really boost your productivity and improve your experience in working with this essential standard. Beyond the Eclipse Foundation, the steward organization for Jakarta EE, the Jakarta EE Ambassadors is a great community and resource for developers. It is a good way for you to be plugged in to happenings in, and related to, Jakarta EE. If you are not already a member, consider becoming a member of the Jakarta EE Ambassadors as a way of being professionally engaged in this part of the Java ecosystem!
Thanks again to the wildfly-extras team. So many good tools come out of the WildFly project and the tools we have discussed here are not the least of these good things. Each of these tools adds to the pleasure of developing applications using Jakarta EE and WildFly!