Saturday, February 27. 2021
Adding custom layers to bootable JAR
Two posts ago the bootable JAR was tested inside the blog. That time the same application that was previously used inside Spring Boot was modified to be packaged using this new technology. With this packaging technique the final executable JAR file contains the customized wildfly bundle (only the needed layers are included) and the application that runs inside it. Today's entry complements the previous one in order to manage your own layers. As I commented in the first post the final configuration can be modified with CLI commands, but adding your own layers is another way of customizing it, and layers can be used for configuring the standalone.xml file but also adding your own modules. The project wildfly-datasources-galleon-pack includes several layers to add the most common jdbc datasources (postgresql, mysql and oracle) inside the OpenShift Container Platform (OCP). Although it is not exactly done for bootable JAR, it is almost the same and the project is a perfect example for managing your own layers in your application.
A simple application has been developed for the entry. The app implements a jax-rs endpoint to perform CRUD operations over a hypothetical user entity. A mariadb server 10.4 will be installed in my laptop to be used as the backend database. The application project is divided in two sub-projects: mariadb-layer, which adds the custom layers for mariadb (module, driver and datasource/pool); and bootable-mariadb-war, the application itself that uses the bootable jar and includes the layer previously defined in the former project.
Let's compare how layers work instead of the common CLI commands.
The first thing to add is the jdbc client library for mariadb (the JAR file itself). A module is recommended to be used. In a common CLI configuration the jar should be downloaded and configured as a new module.
module add --name=org.mariadb --resources=/path/to/mariadb-java-client-2.7.2.jar --dependencies=javax.api,javax.transaction.api
But using layers, the library is defined as a maven dependency for the project and the file src/main/resources/modules/org/mariadb/main/module.xml is placed pointing to that dependency.
<?xml version="1.0" encoding="UTF-8"?> <module name="org.mariadb" xmlns="urn:jboss:module:1.8"> <resources> <artifact name="${org.mariadb.jdbc:mariadb-java-client}"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
Once the module is installed a driver is configured via CLI.
/subsystem=datasources/jdbc-driver=mariadb:add(driver-name=mariadb, driver-module-name=org.mariadb, driver-xa-datasource-class-name=org.mariadb.jdbc.MySQLDataSource)
But a layer can also be defined setting the same information in a layer-spec file inside the project (src/main/resources/layers/standalone/mariadb-driver/layer-spec.xml).
<?xml version="1.0" encoding="UTF-8"?> <layer-spec xmlns="urn:jboss:galleon:layer-spec:1.0" name="mariadb-driver"> <feature spec="subsystem.datasources"> <feature spec="subsystem.datasources.jdbc-driver"> <param name="driver-name" value="mariadb"/> <param name="jdbc-driver" value="mariadb"/> <param name="driver-xa-datasource-class-name" value="org.mariadb.jdbc.MySQLDataSource"/> <param name="driver-module-name" value="org.mariadb"/> </feature> </feature> <packages> <package name="org.mariadb"/> </packages> </layer-spec>
This file defines a new layer called mariadb-driver (that can be included like any other layer to the final wildfly JAR) which adds the exact same diver configuration than the previous CLI command. The layer also references the module previously created, that way it will also be included in the bootable JAR.
The last step is defining the datasource/pool.
data-source add --name=MariaDBDS --jndi-name=java:jboss/MariaDBDS --driver-name=mariadb --connection-url=jdbc:mariadb://localhost:3306/test --user-name=test --password=password --validate-on-match=true --background-validation=false --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
But again a layer can do exactly the same configuration. A new file in the project src/main/resources/layers/standalone/mariadb-datasource/layer-spec.xml is needed.
<?xml version="1.0" encoding="UTF-8"?> <layer-spec xmlns="urn:jboss:galleon:layer-spec:1.0" name="mariadb-datasource"> <dependencies> <layer name="mariadb-driver"/> </dependencies> <feature spec="subsystem.datasources.data-source"> <param name="data-source" value="MariaDBDS"/> <param name="jndi-name" value="java:jboss/MariaDBDS"/> <param name="driver-name" value="mariadb"/> <param name="connection-url" value="jdbc:mariadb://localhost:3306/test"/> <param name="user-name" value="test"/> <param name="password" value="password"/> <param name="background-validation" value="false"/> <param name="validate-on-match" value="true"/> <param name="valid-connection-checker-class-name" value="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker"/> <param name="exception-sorter-class-name" value="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter"/> </feature> </layer-spec>
Note that this layer mariadb-datasource depends on the previous layer mariadb-driver. Therefore if you include this one, the previous one is also added and, in turn, the client library/module.
Finally the war application project needs to reference the layer one. The wildfly-jar-maven-plugin should include the resulting maven artifact of the previous project es.rickyepoderi.bootablejar:mariadb-layer:0.0.1-SNAPSHOT as a feature-pack. The provided layer mariadb-datasource is incorporated over the base jaxrs-server.
<plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>2.0.2.Final</version> <configuration> <feature-packs> <feature-pack> <location>wildfly@maven(org.jboss.universe:community-universe)#22.0.1.Final</location> </feature-pack> <feature-pack> <groupId>es.rickyepoderi.bootablejar</groupId> <artifactId>mariadb-layer</artifactId> <version>0.0.1-SNAPSHOT</version> </feature-pack> </feature-packs> <layers> <layer>jaxrs-server</layer> <layer>mariadb-datasource</layer> </layers> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin>
This configuration adds the mariadb datasource, driver and module to the base jaxrs-server and constructs a bootable JAR able to connect to the local database. The application is finally complete.
Here it is the video that shows how the bootable JAR is created and started. Accessing to the swagger index page a new user is created and retrieved from the application. The local database is correctly working with the application.
And that is all for today. The goal was showing that the bootable JAR can also be extended with custom galleon layers. They can be defined in other maven projects and can include configuration and modules (jars) to the wildfly bundle. Layers can be combined with CLI commands in order to customize and extend the bootable JAR technology. In this entry a sub-project was created to add all the needed components to connect to a mariadb server (module/jar and configuration for the driver and the datasource). The application war sub-project adds the previous layer to a jax-rs base server to get a complete and functional application with access to the database. The final maven project for this entry can be downloaded from here.
Layered regards!
Saturday, January 23. 2021
Pissed off about installing updates at shutdown
Today the entry is just a quick one to show my complete disagreement about automatic software updates at shutdown/reboot. I really do not know if I have understood this completely (not much information is available or it is really hard to find) but I am not going to spend more time on this shit.
First I detected in my fedora laptop that, after upgrading to version 33, when I powered off the computer the popup window showed a check with an option to install pending software updates, and it was ticked by default. I do not know why it was activated, I have never manually clicked it before or manually enabled something (at least that I am aware of it). I think that it is because of the upgrade to gnome 3.38 but not sure. Maybe if I had unchecked the option it would have remained unchecked for the next shutdown or restart, I do not know. This was the window but with the checkbox ticked.
In my laptop I just removed the package-kit to avoid this nonsense completely. The option and the check are not even shown now at shutdown.
dnf remove gnome-packagekit-common PackageKit
But the biggest surprise came later from my desktop. It is a testing debian box and I upgraded it a few days ago. It was almost midnight and I power it off just going to sleep. The fucking box appeared enabled by default and I was so fast that I clicked the power off button mechanically. I had just the time to see that I had screwed it up. As I commented several times in the blog my sansumg TV does not send the modelines to my PC, so I have to set them forcefully and the console is lost. So the upgrade started and I could not see it. After some minutes I decided to force the shutdown and start the machine again. Obviously I needed to connect from my laptop (switching it on) and run a reconfigure, finish the upgrade and fix some issues with a corrupted locale. It could have been worse. I also removed the package-kit again to avoid this shit.
apt-get remove packagekit
It was 1 a.m. when I went to the bed that day. Thanks a lot!
I was searching about this behavior and found nothing. I do not know why the checkbox appeared clicked in my two computers (fedora and debian) or if it can be disabled or defaulted to unchecked. Removing package-kit seems to work for me. I hate when linux picks up windows habits. If you are not careful you will start an upgrade (how long could it be?) when you are shutting down your PC. Maybe you are in a hurry but, what the hell! Upgrade it now! I do not know if I am the only one seeing this nonsense but I have a terrible feeling that I will suffer this again.
Please default the option to disabled! Or give an easy way to disable it!
Sunday, December 27. 2020
Testing bootable JAR in wildfly
A few weeks ago wildfly added the bootable jar feature in order to offer a fat JAR packaging distribution. A big JAR file can now be generated which is directly the executable server with the application deployed inside it. The resulting file contains the jboss-modules to startup the server and all the needed layers that the specific app requires. More or less this feature pretends to achieve something similar to what I showed in the old Spring Boot series. For today's post I decided to accommodate the same application used in those entries but using the wildfly bootable JAR instead of Spring Boot.
The application is just a jaxrs hello world. It incorporates swagger to annotate the endpoint and keycloak to protect its access. Although using the bootable JAR feature, a common JavaEE server will be booted up, so the application is just the same WAR file that would be used in a standalone wildfly. It contains a restful application class and the endpoint, it is annotated with swagger, and, this time, keycloak will be added normally (just the OIDC adapter installed with a layer). The first thing in order to use the bootable JAR is adding its maven plugin, following the guide the server will be slimmed to the minimum layers: base-server, logging, jaxrs and keycloak-client-oidc.
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-jar-maven-plugin</artifactId>
<version>2.0.2.Final</version>
<configuration>
<feature-packs>
<feature-pack>
<location>wildfly@maven(org.jboss.universe:community-universe)#21.0.2.Final</location>
</feature-pack>
<feature-pack>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-galleon-pack</artifactId>
<version>12.0.1</version>
</feature-pack>
</feature-packs>
<layers>
<layer>base-server</layer>
<layer>logging</layer>
<layer>jaxrs</layer>
<layer>keycloak-client-oidc</layer>
</layers>
</configuration>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
The feature packs are the normal community-universe wildfy repository and the keycloak galleon pack, which is added as an extra. The swagger part is included inside the WAR application. So, this time, keycloak will added using a layer but swagger libraries are in the WEB-INF/lib folder. For the SSO part a public client should be defined in the usual way at server level. This entry will not cover the keycloak server configuration (it is very simple anyway). Inside the application the client is used twice, javascript is used to perform the login (public app) and the jaxrs endpoint is configured as a bearer only app. So the sample application contains code in the index.html page to perform the login which uses a keycloak.json configuration located in root folder, and the bearer java part is configured inside the web.xml file using another keycloak.json file in the WEB-INF directory. The same trick was used in the Spring Boot post.
If you remember in the old entry a jaxrs filter was developed to control the access to the endpoint via RBAC (Role-Based Access Control) . I commented that an EJB can be used instead for it if using a normal wildfly server. Using the bootable JAR now we can add EJB to the application. Besides it is a good way of complicating and testing this new feature. In order to transform the endpoint in a Stateless EJB two more layers are needed: ejb-lite and bean-validation. But the final JAR did not start. The problem is that the security domain used in the web part (jaxrs) is different to the one used in the EJB. In general each layer does not only include the needed modules and libraries to the final file, it also adds some configuration to the server. In the case of keycloak it creates all the security stuff needed for the web part and assigns it to the default other security domain. But nothing does the same for the EJB part. Hopefully the bootable JAR also lets you configure the server with CLI commands during the packaging, so we can change the default security domain for the EJB layer just using the following CLI line.
/subsystem=ejb3/application-security-domain=other:write-attribute(name=security-domain, value=KeycloakDomain)
A file with the line can also be included in the maven wildfly plugin configuration, and executing the CLI, the security domain for the EJB system will be the same one used in the web/undertow subsystem (I needed to check the files inside that keycloak layer distribution to get the correct name for the domain).
<cli-sessions>
<cli-session>
<script-files>
<script>src/scripts/ejb3.cli</script>
</script-files>
<resolve-expressions>false</resolve-expressions>
</cli-session>
</cli-sessions>
And this way it finally worked. But adding more layers means more modules, and, therefore, more size for the resulting JAR file. In this case it went from 62 to 95MB when adding the EJB stuff. It was a good exercise to play with the new wildfly plugin but I prefer to maintain the filter and save those 30GB. So I commented out the EJB part and went back to the original filter solution. This is the video that shows exactly the same steps that were presented in the Spring entry. First the keycloak server is started. Then the project is packaged (at this point the server is bundled in a JAR file) and started. Using the browser the swagger info is first requested, the hello endpoint is correctly protected and, after login into the keycloak server, the endpoint works as expected.
Today's entry is a little summary of the new bootable JAR. The same application that was previously used with Spring Boot was transformed to use this new wildfly feature. For one side there is the benefit (at least for me) of using a plain JavaEE application (no Spring at all) but the resulting JAR is not as slim as before. The first entry of the previous Spring Boot series generates a file of 31GB while the bootable JAR size is 62GB, but, considering that the full wildlfy distribution is around 200GB in size, it is not a small step. The project for the sample application can be download from here. During the entry different packs were used (wildfly packs and the keycloak one) and even the CLI integration was tested to configure keycloak and EJB at the same time (although I discarded it in the end, in the project this part is just commented out). I am quite happy with this new feature. I think that it is something useful to expand the wildfly adoption with containers.
Best regards!
Comments