back to all blogsSee all blog posts

Java 19 and MicroProfile Telemetry 1.0 previews in Open Liberty 22.0.0.10-beta

image of author
Reece Nana on Sep 1, 2022
Post available in languages:

Java SE 19 and MicroProfile Telemetry 1.0 are released this month so we bring you previews of both in this Open Liberty 22.0.0.10-beta. Java 19 provides several new and changed features, including record patterns and virtual threads. MicroProfile Telemetry provides a standards-based set of APIs, SDKs, tooling and integrations that are designed for the creation and management of telemetry data such as traces, metrics, and logs.

Also in this beta, you can now programmatically choose an alternative XML Binding implementation when using Jakarta XML Binding 4.0, the tools, xjc and schemagen have been repackaged for Jakarta XML Binding 4.0, and the deprecated jakarta.xml.bind.Validator API has been removed. You can now also expose SPI interfaces as BELL services and inject properties into BELL services, which is simpler to use than writing a user feature. In a previous beta, we introduced distributed security caches which has now been updated so that you no longer need to include the distributedSecurityCache-1.0 feature in your server.xml.

The Open Liberty 22.0.0.10-beta includes the following beta features (along with all GA features):

Java SE 19 support

Java 19 is coming soon, and with it the following features and changes:

  • Record Patterns

  • Linux/RISC-V Port

  • Foreign Functions & Memory API

  • Virtual Threads

  • Vector API

  • Pattern Matching for switch

  • Structured Concurrency

Try out the new changes in Java 19 now so that you will be a step ahead in reviewing your applications, microservices, and runtime environments when it becomes generally available:

  1. Download the early access release of Java 19.

  2. Modify your Maven coordinates for the 22.0.0.10-beta version of Open Liberty.

  3. Edit your Liberty server’s server.env file to point JAVA_HOME to your Java 19 installation.

  4. Start testing your apps!

For more information on Java 19, visit the Java 19 release notes page and API Javadoc page.

As work is made towards full Java 19 support, there may be functionality that might not be 100% ready yet but is in progress to be complete soon!

Create and manage traces, metrics, and logs using OpenTelemetry open standards (MicroProfile Telemetry 1.0)

OpenTelemetry is a set of APIs, SDKs, tooling and integrations that are designed for the creation and management of telemetry data such as traces, metrics, and logs. MicroProfile Telemetry 1.0 adopts OpenTelemetry from CNCF to allow MicroProfile applications to benefit from OpenTelemetry and enable automatic tracing of Jakarta RESTful web services if configured.

To use this feature update your server.xml:

<featureManager>
  <feature>mpTelemetry-1.0</feature>
</featureManager>

You can view the telemetry data from your application in Jaeger and Zipkin. To export your traces to one of these exporters, configure the exporter with system properties, e.g. -Dotel.traces.exporter=jaeger or environment variables, e.g. OTEL_TRACES_EXPORTER=jaeger. You can also configure the exporter endpoints using OTEL_EXPORTER_JAEGER_ENDPOINT and OTEL_EXPORTER_ZIPKIN_ENDPOINT. To specify the name of the service, use OTEL_SERVICE_NAME.

For more information about MicroProfile Telemetry, see:

Programmatically choose an alternative XML binding implementation (Jakarta XML Binding 4.0)

Jakarta XML Binding 4.0 is an API for automating the mapping between XML documents and Java objects when writing XML documents in Java. By and large, the xmlBinding-4.0 feature is identical to xmlBinding-3.0, with a couple of exceptions. The 4.0 spec has removed the deprecated jakarta.xml.bind.Validator API. This means, if your application is using Validator to validate your JAX-B data types, you’ll need to update to use the more common schema validation method. Here’s an example of how to move from the Validator to schema validation:

  // With Validator:
  SomeJAXBDataOjbect dataObject = new SomeJAXBDataObject();

  JAXBContext context = JAXBContext.newInstance(new Class<>{]{ClassToBeBound.class, ClassToBeBound2.class, });
  JAXBSource source = new JAXBSource(context, dataObject);

  Validator validator = schema.newValidator();
  validator.setErrorHandler(c);
  validator.validate(source);

  // With Schema Validation - Suggested alternative since 2.0.

  JAXBContext context = JAXBContext.newInstance(new Class<>{]{ClassToBeBound.class, ClassToBeBound2.class, });

  Unmarshaller junmarshaller = jaxbContext.createUnmarshaller();

  SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
  Schema dataObjectSchema = schemaFactory.newSchema(new File("dataObjectSchema.xml"));
  jaxbUnmarshaller.setSchema(dataObjectSchema);

  SomeJAXBDataObject dataObject = (SomeJAXBDataObject dataObject) umarshaller.unmarshal(new       File("dataObjectSchema.xml"));

In 4.0, you can now programmatically choose an alternative XML Binding implementation. Provided you package the implementation with the application, then you simply need to set the name of the implementation in a property map, and pass the map along when instantiating a JAXBContext object. Here’s an example doing just that with Eclipe’s Moxy implementation:

   String JAXB_CONTEXT_FACTORY = "jakarta.xml.bind.JAXBContextFactory";
   String MOXY_JAXB_CONTEXT_FACTORY = "org.eclipse.persistence.jaxb.XMLBindingContextFactory";

   ClassLoader classLoader = some.package.with.jaxb.data.objects.ObjectFactory.class.getClassLoader();
   Map<String, String> properties = new HashMap<String, String>();
   properties.put(JAXB_CONTEXT_FACTORY, MOXY_JAXB_CONTEXT_FACTORY);
   JAXBContext context = JAXBContext.newInstance("some.package.with.jaxb.data.objects",
                                   classLoader, properties);

To enable the Jakarta XML Binding 4.0 feature, add the xmlBinding-4.0 feature to your server.xml:

<featureManager>
    <feature>xmlBinding-4.0</feature>
</featureManager>

For more information see the Jakarta XML Binding specification.

Expose SPI interfaces as BELL services and inject properties into BELL services

The Basic extensions using Liberty libraries (BELL) 1.0 feature enables shared libraries to provide implementations of Liberty API interfaces using Java ServiceLoader configuration files.

22.0.0.10-beta introduces two capabilities for BELL services: SPI visibility, and properties configuration and injection. Previously these capabilities were available only to user feature extensions. User features offer more capabilities than BELL services, but come with a more complex development model. These capabilities allow extension developers greater opportunity to leverage the simplicity of BELL services.

BELL SPI visibility makes feature SPI packages visible only to shared libraries referenced in BELL configurations. The introduction of BELL SPI visibility enables developers to provide implementations of SPI interfaces as BELL services rather than user features, which typically require more time to develop.

BELL properties configuration and injection enables BELL services to receive properties configured in the server.xml file. The introduction of BELL properties allows users to exploit the benefits of the Liberty configuration and obviates the need to configure BELL services with environment variables or JVM system properties.

To enable SPI visibility declare Boolean attribute spiVisibility=“true” in your BELL configuration. SPI visibility is disabled by default.

To specify properties add a <properties/> element within your BELL configuration and declare one or more name="value" attributes. Properties are type String and apply to all services provided by the referenced library.

The configuration below enables SPI visibility for services provided by shared library ServletExtLib and declares two properties, servletName and servletMapping:

<library id=ServletExtLib">
    <fileset dir="${server.output.dir}/sharedLib" includes="ServletExtLib.jar" />
</library>

<bell libraryRef=ServletExtLib
        service="javax.servlet.ServletContainerInitializer"
        spiVisibility=true">
    <properties servletName=RestSciServlet servletMapping="/rest/*" />
</bell>

In order to receive properties at runtime, modify your service implementation classes by defining either a public constructor or a public method named updateBell, each having a single parameter of type java.util.Map<String,String>. The updateBell method is intended to support non-destructive updates and must tolerate multiple calls on the same service instance.

The example below defines method updateBell within service implementation class RestSci:

package my.servlet.extensions;
...
public class RestSci implements javax.servlet.ServletContainerInitializer {
    public RestSci() {}

    public void updateBell(java.util.Map<String, String> properties) {
        // Collect properties
    }
    ...
}

At runtime the server will make SPI packages visible only to a specialized classloader for library ServletExtLib. Applications can declare commonLibRef="ServletExtLib" in their <classloader/> configuration, but they will not see SPI packages. Regarding <properties/> the server will inject an unmodifiable map with key=value pairs "servletName"="RestSciServlet" and "servletMapping"="/rest/*" into all services when created during startup and after BELL configuration updates.

Bringing up a BELL service that implements the REST Handler SPI interface

The following steps describe how to bring up a BELL service that implements the REST Handler SPI interface com.ibm.wsspi.rest.handler.RESTHandler, which was impossible until now.

  1. Create the service resource and implementation class files.

    The resource file is named for the SPI interface and declares the fully-qualified name of the implementation class. The minimal resource file content is shown below. Notice the file also declares an OSGi property required by the RESTHandler interface — the entry starting with # — that enables the REST Handler framework to register the service as a listener for a specified URL sub-root. In this example the URL sub-root is /bellEP.

    #com.ibm.wsspi.rest.handler.root=/bellEP
    your.org.rest.example.BellEndpoint

    A skeletal implementation of SPI interface com.ibm.wsspi.rest.handler.RESTHandler. The implementation defines method updateBell to receive BELL properties. The updateBell method is intended for non-destructive updates and must tolerate multiple calls on the same service instance. Below is the skeletal implementation:

    package your.org.rest.example;
    import com.ibm.wsspi.rest.handler.*;
    ...
    public class BellEndpoint implements com.ibm.wsspi.rest.handler.RESTHandler {
        public BellEndpoint() {}
        public void updateBell(java.util.Map<String, String> properties) {...}
        @Override
        public void handleRequest(RESTRequest request, RESTResponse response) {...}
    }

    Package the files into a JAR file, say RestEpLib.jar:

    META-INF/services/com.ibm.wsspi.rest.handler.RESTHandler
    your/org/rest/example/BellEndpoint.class
  2. Configure the server.

    The restConnector-2.0 feature enables the REST Handler framework and exports the REST Handler SPI package required by the BELL service. Access to REST endpoints requires secure transport (transportSecurity-1.0) and that a user is mapped to the administrator role. Add the following features to the server.xml:

    <featureManager>
        <feature>bells-1.0</feature>
        <feature>restConnector-2.0</feature>
        <feature>transportSecurity-1.0</feature>
    </featureManager>

    Now add the shared library and BELL. The following configuration enables SPI visibility for the RestEpLib library and declares one property, hello="WORLD". Enable SPI visibility whenever a BELL service implementation requires SPI packages exported by a configured feature(s). Remember to copy file RestEpLib.jar to the directory specified in the library’s <fileset/>. The stated configuration below:

    <library id=RestEpLib">
        <fileset dir="${server.output.dir}/sharedLib" includes="RestEpLib.jar" />
    </library>
    
    <bell libraryRef=RestEpLib
            service="com.ibm.wsspi.rest.handler.RESTHandler"
            spiVisibility=true">
        <properties hello=WORLD />
    </bell>

    Add the keystore for transport security and map a user to the administrator role:

    <keyStore id="defaultKeyStore" password="keystorePassword" />
    <basicRegistry>
        <user name="you" password="yourPassword" />
        <group name="yourGroup" />
    </basicRegistry>
    <administrator-role>
        <user>you</user>
        <group>yourGroup</group>
    </administrator-role>
  3. Save your changes and start the server.

    Look for messages CWWKL0059I and CWWKL0050I in server logs indicating the server enabled BELL SPI visiblity and registered the BELL service. The server makes REST Handler SPI packages visible to a unique classloader for library RestEpLib. Applications may declare a common library reference to RestEpLib (commonLibRef="RestEpLib") in their <classloader/> configuration, but they will not see SPI packages.

    [...] 00000001 com.ibm.ws.classloading.bells.internal.Bell                  I BETA: BELL SPI Visibility and BELL Properties has been invoked by class com.ibm.ws.classloading.bells.internal.Bell for the first time.
    [...] 00000001 com.ibm.ws.classloading.bells.internal.Bell                  I CWWKL0059I: BELL SPI visibility is enabled for the RestEpLib library. The BELL references the RestEpLib library through a unique class loader that can see SPI packages.
    [...] 00000001 com.ibm.ws.classloading.bells.internal.Bell                  I CWWKL0050I: The RestEpLib library registered the service that is declared in the wsjar:file:/<your_wlp>/usr/servers/bell_ep_server/sharedLib/RestEpLib!/META-INF/services/com.ibm.wsspi.rest.handler.RESTHandler file, using your.org.rest.example.BellEndpoint implementation class.

    When the server registers the BELL service with the OSGi framework it triggers the REST Handler framework to register the service as a listener for URL sub-root /bellEP. The /bellEP endpoint is now accessible.

    You can now make calls to https://<host>:8020/ibm/api/bellEP.

    The REST handler framework references the BELL service to serve the /bellEP endpoint. During the first reference the server creates an instance of class BellEndpoint and injects an unmodifiable map with key/value pair "hello"/"WORLD". The server injects BELL properties at service creation and after BELL configuration updates.

To find out more, see:

Distributed security caches

Distributed security cache support has been introduced so that multiple Liberty servers can share caches via a JCache provider. Prior to this feature, the authentication (subject) and logged out cookie caches were restricted to be local and in-memory. Multiple servers were unable to benefit from their peers' caches and each server started with a cold cache. As part of this feature, both caches can be stored in a distributed JCache provider. This can improve performance and failure recovery, reduce the load on backend user registries, and improve the security posture of the server.

You can find out more in our Open Liberty 22.0.04-beta blog post but note the following changes:

  1. It is no longer necessary to enable the distributedSecurityCache-1.0 feature in the server.xml.

  2. The libraryRef attribute has been replaced by two attributes: jCacheLibraryRef and commonLibraryRef. The jCacheLibraryRef references the library that contains the JCache caching provider implementation. The commonLibraryRef is optional and can reference libraries that contain any custom classes that may be serialized and stored in the cache (define multiple libraries by separating them by a comma).

    <cachingProvider libraryRef="JCacheProviderLib,CustomLib" />

    is now:

    <cachingProvider jCacheLibraryRef="JCacheProviderLib" commonLibraryRef="CustomLib" />

Try it now

To try out these features, just update your build tools to pull the Open Liberty All Beta Features package instead of the main release. The beta works with Java SE 19, Java SE 18, Java SE 17, Java SE 11, and Java SE 8, however, the Jakarta EE 10 features are only compatible with Java SE 11 and later.

If you’re using Maven, here are the coordinates:

<dependency>
  <groupId>io.openliberty.beta</groupId>
  <artifactId>openliberty-runtime</artifactId>
  <version>22.0.0.10-beta</version>
  <type>pom</type>
</dependency>

Or for Gradle:

dependencies {
    libertyRuntime group: 'io.openliberty.beta', name: 'openliberty-runtime', version: '[22.0.0.10-beta,)'
}

Or take a look at our Downloads page.

We welcome your feedback

Let us know what you think on our mailing list. If you hit a problem, post a question on StackOverflow. If you hit a bug, please raise an issue.