Here is a list of my top 10 OpenLiberty hidden features. They are not the "best" features by any means of »hidden knowledge«, but they are the most handy features I use regularly not everyone knows about. YMMV. 😉
10: Activating OpenAPI for a free OpenAPI description
Whether or not you add OpenAPI (aka Swagger) annotations to your JAX-RS endpoints, you can "just switch on" the OpenAPI feature. Enabling this feature will reveal two new endpoints: /openapi/
for a Swagger YAML document of your JAX-RS endpoints, and /openapi/ui/
for a really nice Web-UI. Over are the days of complicated maven plugins!
This is extremely useful for quick testing or publishing your API. No further configuration needed. The UI even includes a "try it out button", so you do not even need to set up Postman or Insomnia for quick tests!
<server>
<features>
<feature>mpOpenAPI-1.1</feature>
</features>
</server>
9: Disabling deferred servlet loading
This is a no-brainer for every web application I write. By default, Liberty does not eagerly initialise servlets, which usually is good for CPU usage when booting up multiple OpenLiberty servers at once.
With this option set, the servlets are initialized early, which will reduce the time for the first hit-to-response for the first user.
<server>
<webContainer deferServletLoad="false" />
</server>
8: Activating shared class cache
If you want to start the same application multiple times, a shared class cache will allow any Java OpenJ9 VM to re-use already compiled and optimized classes. This is also the default configuration if you run the official Docker Images and did a RUN configure.sh
in your Dockerfile
. Just make sure you use a OpenJ9 VM and point the VMs to the same directory using this line in your jvm.options
file.
-XX:+OriginalJDK8HeapSizeCompatibilityMode
-Xshareclasses:name=myapp,cacheDir=/tmp/myapp/.classCache/
You can also use an environment variable, e.g. in your server.env file.
IBM_JAVA_OPTIONS="-XX:+OriginalJDK8HeapSizeCompatibilityMode -Xshareclasses:name=myapp,cacheDir=/tmp/myapp/.classCache/"
7: Using different truststore and keystore configurations
Security is easily one of the most important issues when configuring an application container. You can change the truststore (e.g. for your custom PKI) or you can change the default (outgoing) protocols.
<server>
<ssl id="defaultSSLConfig" trustDefaultCerts="true" sslProtocol="TLSv1.2" />
</server>
Oddly enough, the default is sslProtocol="SSL_TLSv2"
, which is an alias for everything starting from SSLv3 (deprecated, insecure). Please note that such security-related configurations must be updated from time to time. For example, TLSv1.3 will soon be a new standard you might want to add to the list.
6: Using server.env for testing different JVM implementations
Different JVMs and Java versions will behave differently -- even for your app! If you want to try out some more JVMs, here are some intersting ones:
- Amazon Corretto -- https://aws.amazon.com/corretto/
- Adopt OpenJDK Hotspot -- https://adoptopenjdk.net/?variant=openjdk11&jvmVariant=hotspot
- Adopt OpenJDK OpenJ9 -- https://adoptopenjdk.net/?variant=openjdk11&jvmVariant=openj9
- Oracle OpenJDK -- https://openjdk.java.net/install/index.html
Now, open your server.env
file and add the corresponding environment variable.
JAVA_HOME=$HOME/.local/apps/adopt-openj9@1.11.0-6
5: Using includes to switch the database
Are you testing against more than just one database? You can control this by environment variables! Just include a environment variable DATABASE_TYPE=postgresql
in your server.env
file and then include the database configuration like so:
<server>
<include optional="false" location="/config/ds-${env.DATABASE_TYPE}.xml" />
</server>
This will include the file /config/ds-postgresql.xml
and fail the server startup if it does not exist. The content for such a file could be the following:
<server>
<!-- PostgreSQL Driver -->
<library id="postgresqllib"
>
<fileset dir="${shared.resource.dir}/postgresql/"
includes="postgre*.jar"
/>
</library>
<jdbcDriver id="postgresql"
libraryRef="postgresqllib"
/>
<dataSource id="mydb"
jndiName="jdbc/mydb"
jdbcDriverRef="postgresql"
type="javax.sql.Datasource"
>
<connectionManager maxPoolSize="2"
minPoolSize="10"
/>
<properties
URL="jdbc:postgresql://${env.DB_HOST}:${env.DB_PORT}/${env.DB_NAME}"
user="${env.DB_USER}"
password="${env.DB_PASSWORD}"
/>
</dataSource>
</server>
If you need more databases like this, just create similar configuration files with the same scheme. For example you coud create a file /config/ds-postgresql.xml
and replace everything PostgreSQL-related with H2.
4: Reading FFDCs for error analysis
Developing a new application? I bet you will have an uncought RuntimeException
at some point. Those might be hard to debug and hard to find in the first place. Starting any application container with a debugger attached (e.g. from IntelliJ) can be a pain in the neck, depending on your hardware.
Liberty to the rescue! For every first occurence of any uncought RuntimeException at a specific code position, Liberty will create an FFDC file (First Failure Data Capture). Look in $SERVER_DIR/logs/ffdc/
. The files contain a complete (i.e. no omnissions ) stack trace, a thread dump of the caller and some additional dumps. The stack trace alone is worth so much!
3: Disabling CDI scanning
If your application uses CDI, but every bean archive does have a beans.xml
file, you can bost Liberty’s startup time considerably by disabling archive scanning.
Background: CDI 1.2 introduced bean archives without even defining a beans.xml
at all. For this to work, the application container needs to scan *every* *single* *jar* *archive* included in your .war
or .ear
file.
The remedy to this is to add the following configuration to your server.xml
file. This will work for CDI 1.2 onwards.
<server>
<!-- this also works for CDI 2.0 and above -->
<cdi12 enableImplicitBeanArchives="false" />
</server>
2: Enabling ISO DateTime format
Now, have you ever sat in front of a developer machine with German Locale? OpenLiberty will use your machine’s locale by default for displaying timestamps in its main logfile messages.log
.
The remedy is to set isoDateFormat
option to true.
<server>
<logging isoDateFormat="true" />
</server>
# isoDateFormat=false and locale set to en_GB
[18/08/2020, 04:52:53:136 CEST] 00000001 com.ibm.ws.kernel.launch.internal.FrameworkManager A CWWKE0001I: The server jenkins has been launched.
# isoDateFormat=false and locale set to de_DE
# even the TZ is translated, yuck! And still the colon for ms
[18.08.20, 04:52:53:136 MESZ] 00000001 com.ibm.ws.kernel.launch.internal.FrameworkManager I CWWKE0002I: Der Kernel wurde nach 0,742 Sekunden gestartet.
# isoDateFormat=true and any locale
[2020-08-04:52:53.136+0200] 00000001 com.ibm.ws.kernel.launch.internal.FrameworkManager A CWWKE0001I: The server jenkins has been launched.
You can also set the option com.ibm.ws.logging.isoDateFormat=true
in your bootstrap.properties
(recommended).
1: Setting WLP_USER_DIR environment variable
This is the number one useful thing to do, whether you are a developer or responsible for production!
Setting the evinronment variable WLP_USER_DIR
to any value (must be a valid path on your local file system), the server directory and shared resource directory will be read from that location.
Why this is useful? Well, as a developer just imagine you want to test your application from your IDE with both OpenLiberty 20.0.0.8 and IBM Liberty Profile 19.0.0.12. If you did not set the environment variable, you had to create two servers, one in each installation directory. If you update your OpenLiberty installation, you must not forget to move all the servers and shared resources. With the option set, you can just execute the corresponding ./bin/server
binary and they will read the configuration from the same location. IntelliJ will pick it up after you logged in again.
As a production engineer, you will want to upgrade your (Open)Liberty installation from time to time -- maybe even for security reasons. If you do not want to move the server directories after each upgrade, this option is for you. It will make your life much easier.
Conclusion
Were some of the tips and tricks new to you? What is your favourite feature? Do you agree or disagree on my list? Leave me a comment here or on twitter!