Featured Image: OpenLiberty support for gRPC and Java

Open Liberty 20.0.0.12 now supports gRPC 1.0 and gRPC Client 1.0. This universal, open source framework is an efficient way to connect remote services across data centers. We've also added custom names support for the Java Naming and Directory Interface (JNDI), making it easier to look up and inject Jakarta Enterprise Beans (EJBs) in your Open Liberty applications. Finally, this new release is compatible with Java SE 15, the latest Java Standard Edition version. We'll introduce these features and show you how to set up and configure the new gRPC and custom JNDI names support in Open Liberty 20.0.0.12.

Note: See the Open Liberty 20.0.0.12 issues page for a list of recently fixed bugs.

Run your applications using Open Liberty 20.0.0.12

In Maven, add the following coordinates to update to Open Liberty 20.0.0.12:

<dependency>
    <groupId>io.openliberty</groupId>
    <artifactId>openliberty-runtime</artifactId>
    <version>20.0.0.12</version>
    <type>zip</type>
</dependency>

If you are using Gradle, enter:

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

For Docker, it's:

FROM open-liberty

gRPC moves out of beta in Open Liberty 20.0.0.12

The gRPC framework is a universal open source technology for efficiently connecting remote services. The framework's benefits include great performance, simple service definitions (via protocol buffers), cross-platform and cross-language support, and widespread industry adoption. You can both provide and consume gRPC services from your web applications.

Open Liberty 20.0.0.12 lets you use gRPC more easily than ever. Two features that were previously only available in beta are now generally available:

  • grpc-1.0 lets you use the gRPC service.
  • grpcClient-1.0 lets you use a gRPC client for outbound calls.

Using gRPC services

The grpc-1.0 feature works by scanning web applications for gRPC service implementations through io.grpc.BindableService. To qualify as a gRPC service implementation, a web application must include the protocol buffer compiler-generated code for the services it intends to provide. Additionally, the service class must provide a no-argument constructor. The web application does not need to include any core gRPC libraries; the Open Liberty runtime provides those. Once a gRPC service is scanned and started, it becomes accessible to remote gRPC clients on the configured HTTP ports.

The gRPC client

The grpcClient-1.0 feature provides applications with access to a Netty gRPC client and related libraries. A web application must provide a client implementation and stubs, and can make outbound calls with a io.grpc.ManagedChannel without needing to provide the supporting client libraries.

A gRPC example implementation

As an example implementation, consider this basic Hello World service, where we're adding the grpc-1.0 feature to the application's server.xml:

package com.ibm.ws.grpc;

import com.ibm.ws.grpc.beans.GreetingBean;

import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.stub.StreamObserver;

public class HelloWorldService extends GreeterGrpc.GreeterImplBase {

    public HelloWorldService(){}

    @Override
    public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
        HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
        responseObserver.onNext(reply);
        responseObserver.onCompleted();
    }
}

In this case, the application must provide the helloworld protobuf definition along with the protobuf compiler output. We do not need to provide any additional libraries. Once it's started, the Hello World greeter service will be accessible on the server's HTTP endpoints.

For a client example, we can define a basic servlet using gRPC and the grpcClient-1.0 feature:

package com.ibm.ws.grpc;

import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
...
@WebServlet(name = "grpcClient", urlPatterns = { "/grpcClient" }, loadOnStartup = 1)
public class GrpcClientServlet extends HttpServlet {

        ManagedChannel channel;
        private GreeterGrpc.GreeterBlockingStub greetingService;

        private void startService(String address, int port)
        {
            channel = ManagedChannelBuilder.forAddress(address , port).usePlaintext().build();
            greetingService = GreeterGrpc.newBlockingStub(channel);
        }

        private void stopService()
        {
            channel.shutdownNow();
        }

        @Override
        protected void doGet(HttpServletRequest reqest, HttpServletResponse response)
            throws ServletException, IOException
        {

            // set user, address, port params
        }

        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
        {

        // grab user, address, port params
        startService(address, port);
        HelloRequest person = HelloRequest.newBuilder().setName(user).build();
        HelloReply greeting = greetingService.sayHello(person);

        // send the greeting in a response
        stopService();
        }
    }
}

As with the service example, the application must provide the helloworld protobuf definition and the protobuf compiler output. All of the required gRPC client libraries are provided by the grpcClient-1.0 feature.

Note: See the instructions and examples in the Open Liberty sample gRPC GitHub repository for more about using the new gRPC features in Open Liberty.

Use custom JNDI names to look up or inject EJBs

We've enhanced Open Liberty's existing EJB features by adding support for custom JNDI names in this release. An application can now configure and use custom JDNI names to look up or inject enterprise beans. Applications can still use the legacy default JNDI names, as well.

Before this enhancement, Open Liberty only supported looking up enterprise beans using the specification-defined JNDI names : java:global/<app>/<module>/<bean>!<interface> and variations for java:app and java:module. You can still use the legacy JNDI names by default, but you now have the option to specify a custom name for each EJB in the ibm-ejb-jar-bnd.xml file (or ibm-ejb-jar-bnd.xmi for EJB 2 and EJB 1 modules).

The new JNDI name options are available in addition to the existing specification-required names. For EJB 3 modules, the following defaults will be available if you do not provide a custom name:

  • Short-form local interfaces and homes:
    ejblocal:<package.qualified.interface>
  • Short-form remote interfaces and homes:
    <package.qualified.interface>
  • Long-form local interfaces and homes:
    ejblocal:<component-id>#<package.qualified.interface>
  • Long-form remote interfaces and homes:
    ejb/<component-id>#<package.qualified.interface>

The component-id defaults to:
<application-name>/<module-jar-name>/<ejb-name>

Easier migration for EJB applications

Custom JNDI name support for enterprise beans provides an easier migration path for applications from other platforms, including WebSphere traditional.

Before Java EE 6, the EJB specification did not prescribe the JNDI names required for enterprise beans, so every platform provided platform-specific default names and custom binding file formats. Open Liberty only supported the specification-defined JNDI names, so migrating applications from other platforms often required code changes.

The new custom JNDI name support lets you migrate your applications from other platforms without code changes. Now, you only need to migrate platform-specific binding files to the new Open Liberty platform-specific binding file format. In some cases, using the new legacy default names could allow applications to migrate to Open Liberty without specifying custom JNDI names in a binding file.

Configuring the custom bindings

There are three locations where you can configure an application's custom bindings.

Specify custom bindings in ibm-ejb-jar-bnd.xml for EJB 3

There are a few ways to configure custom bindings for EJB 3 beans in an EJB JAR module or WAR module in ibm-ejb-jar-bnd.xml. To start, here's how to specify a binding per interface:

<session name="NoInterceptorBasicStateless">
      <interface class="com.ejbs.InventoryService" binding-name="ejb/Inventory"/>
   </session>

Here's how to specify a component ID (a prefix for default long-form bindings):

<session name="AccountServiceBean" component-id="Dept549/AccountProcessor"/>

You can specify a simple binding name (one name used for both local and remote services):

<session name="AccountServiceBean" simple-binding-name="ejb/AccountService"/>

You can also specify local and remote home-specific binding names:

 <session name="AccountServiceBean" local-home-binding-name="ejblocal:AccountService"/>
   <session name="AccountServiceBean" remote-home-binding-name="ejb/services/AccountService"/>

Note: See EJB 3.0 and EJB 3.1 application bindings overview for more about the legacy default bindings and the new syntax for declaring custom JNDI names in ibm-ejb-jar-bnd.xml.

Specify custom bindings in server.xml

Next, look at this example of how to configure custom bindings for EJB 3 beans in an EJB JAR module or WAR module in server.xml. We use the <application> or <ejbApplication> elements, as shown here:

<ejbApplication location="EJBTest.jar">
      <ejb-jar-bnd>
         <session name="InventoryServiceBean">
            <interface class="com.ejbs.InventoryService" binding-name="ejb/Inventory"/>
         </session>
      </ejb-jar-bnd>
   </ejbApplication>

Specify custom bindings in ibm-ejb-jar-bnd.xmi for EJB 1 or EJB 2

Finally, here is how to configure custom bindings for EJB 1 or EJB 2 beans in an EJB JAR module in ibm-ejb-jar-bnd.xmi. Note that EJB 1 and EJB 2 provide a single JNDI name that applies to both the remote and local home:

<ejbBindings xmi:id="BeanBinding_8" jndiName="suite/r6x/base/misc/poollimits/SLCMTTxTimeoutHome">
      <enterpriseBean xmi:type="ejb:Session" href="META-INF/ejb-jar.xml#SLCMTTxTimeout"/>
   </ejbBindings>

For a bean with both a remote and local home, the above configuration provides these custom bindings:

Remote Home : suite/r6x/base/misc/poollimits/SLCMTTxTimeoutHome
   Local Home  : local:suite/r6x/base/misc/poollimits/SLCMTTxTimeoutHome

Configuring custom JNDI names

Support for custom and legacy default JNDI names is on by default for all EJB features. This support does not interfere with the existing specification-defined java: support. However, it is possible to disable the new support with the following setting in server.xml:

<ejbContainer bindToServerRoot="false"/>

It is also possible to disable just the legacy short-form default JNDI name support, where the bean is bound using the interface name. Use the following setting in server.xml:

   <ejbContainer disableShortDefaultBindings="true"/>

Because the new support for custom JNDI names and legacy defaults provides alternative JNDI names, you can now disable the JNDI names required by the EJB specification. Add the following to the server.xml:

   <ejbContainer bindToJavaGlobal="false"/>

Finally, you can add the following new configuration attribute on the <ejbContainer> element in open-liberty:

    <ejbContainer customBindingsOnError="FAIL"/>

This attribute enables a failing-application start when multiple beans are bound to the same JNDI name.

Open Liberty support for Java SE 15

Any official Java SE 15 release from AdoptOpenJDK, Oracle, or other OpenJDK vendors will work with Open Liberty. Although Java SE 15 is currently the latest available version, it is not a long-term supported release. Standard support is scheduled to end in March 2021.

Keep in mind that Eclipse OpenJ9 typically offers faster startup times than Hotspot.

The primary features added in this release include:

For more information on downloading a version of Java 15, see AdoptOpenJDK.net, Eclipse.org, or OpenJDK.java.net.

For more about working with the server.env file in Open Liberty, see the Configuration Files section of Open Liberty's server configuration documentation.

Try Open Liberty 20.0.0.12 in Red Hat Runtimes

Open Liberty is part of the Red Hat Runtimes offering and is available to Red Hat Runtimes subscribers. To learn more about deploying Open Liberty applications to Red Hat OpenShift, see our Open Liberty guide to deploying microservices to OpenShift.

Last updated: February 11, 2024