Basic Extensions using Liberty Libraries1.0
This feature enables the configuration of Basic Extensions using Liberty Libraries (BELL).
The BELL feature enables libraries to define the implementation of an Open Liberty SPI or API with Java ServiceLoader
configuration files. These files are included in the /META-INF/services/
directory of the library JAR file.
With the BELL feature, a library declares a /META-INF/services/
resource with the name of the fully qualified API or SPI interface and provides a class that implements the interface. The feature processes the /META-INF/services/
resources and provides the library interface implementation to the Open Liberty runtime.
Enabling this feature
To enable the Basic Extensions using Liberty Libraries 1.0 feature, add the following element declaration into your server.xml
file, inside the featureManager
element:
<feature>bells-1.0</feature>
Examples
Configure a BELL
The minimum server.xml
configuration for the BELL feature requires a library
element and a bell
element that references the library.
<library id="servicesLib">
<file name="path to jar">
</library>
<bell libraryRef="servicesLib" />
The BELL feature discovers all services in the META-INF/services
folder of the referenced library. Alternatively, you can configure the service
attribute to specify the name of the service the feature looks up in the META-INF/service
folder, as shown in the following example.
<bell libraryRef="servicesLib"
service="name.of.fully.qualified.api.or.spi.interface" />
For every service that is discovered or specified, the BELL feature registers the service interface and implementation class as an OSGi service, which makes the service available to the Open Liberty runtime.
Be sure to enable the Open Liberty features that provide the API or SPI packages that are required by the library.
Enable SPI access for libraries
Shared libraries do not support access for SPI packages. When a library provides an implementation of an SPI interface, set the spiVisibility
attribute to true
in the BELL configuration. This attribute enables the library classloader to access SPI packages that are provided by Open Liberty.
<bell libraryRef="servicesLib" spiVisibility="true"/>
SPI visibility is disabled by default and applies only to the library that is referenced in the BELL configuration. SPI visibility is not supported for the Open Liberty global
shared library.
For more information, see Expose a new REST endpoint.
Enable services to receive configuration properties
Services can receive properties that are declared in the BELL configuration. To configure properties, add a properties
element to your BELL configuration and declare one or more name="value"
attributes. Properties are String
type and inject into all services that are enabled to receive them. The following example declares the hello
and serverHome
properties.
<bell libraryRef="servicesLib">
<properties hello="WORLD" serverHome="${server.output.dir}" />
</bell>
To enable a service to receive configuration properties, define an updateBell
public method or a public constructor in the service implementation class. The method signature must declare a single parameter of the java.util.Map<String,String>
type. The following example defines both methods to receive properties in a BELL configuration.
public class YourServiceImpl implements api.or.spi.Interface {
public YourServiceImpl(java.util.Map<String,String> bellProperties) {...}
// OR
public void updateBell(java.util.Map<String,String> bellProperties) {...}
}
At service creation, the BELL feature invokes the updateBell
or constructor methods to inject an unmodifiable map that contains a key/value
pair for each property. For the previous examples, the resulting map contains the pairs "hello"/"WORLD"
and "serverHome"/"<resolved value of ${server.out.dir}>"
The BELL feature does not support nondestructive updates. When you update a BELL configuration while the server is running, the feature does not inject updated properties
into existing service instances. However, it affords this future enhancement by allowing users to define the updateBell
method within the service implementation class. If you define the updateBell
method to receive properties, ensure that the class can tolerate multiple calls to the updateBell
method on the same instance.
For more information, see Expose a new REST endpoint.
Configure a servlet filter for applications
In certain scenarios, a servlet filter implementation must be applied to all applications that are deployed to Open Liberty. For example, a servlet filter might be used to add new headers to each request. The jakarta.servlet.ServletContainerInitializer
interface provides an onStartup
method that you can use to add a servlet filter implementation class to all applications.
You can use the BELL feature to configure a library that provides a ServletContainerInitializer
implementation as a service. The ServletContainerInitializer
service onStartup
method is called by Open Liberty for each application that starts. In the following example, a ServletContainerInitializer
implementation is configured to add a servlet filter implementation with each ServletContext
object that is in a Java file. The ServletContext.addFilter(String, Filter)
method is used by the onStartup
method to add the servlet filter implementation.
public class SCI implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> arg0, ServletContext arg1)
throws ServletException {
arg1.addFilter("myFilter", MyFilter.class).addMappingForUrlPatterns(null, false, "/*");
}
}
To register the ServletContainerInitializer
interface that adds the servlet filter for an application, a class name is specified in the library JAR file. The library JAR file contains a META-INF/services/jakarta.servlet.ServletContainerInitializer
file that specifies the fully qualified ServletContainerInitializer
implementation class name that is contained in the library. The following example uses the file
element to specify a path to the JAR file and add it to the library. It also specifies the service that the BELL feature looks up and registers.
<library id="servletExtLib">
<file name="path to jar"/>
</library>
<bell libraryRef="servletExtLib"
service="jakarta.servlet.ServletContainerInitializer" />
Expose a new REST endpoint
The REST Handler framework provides the com.ibm.wsspi.rest.handler.RESTHandler
interface, which Open Liberty extension developers use to expose new REST endpoints. You can use the BELL feature to configure a library that provides a RESTHandler
implementation as a service. This library enables the REST Handler framework to register the service as a listener for a new specified endpoint URL.
In the following service implementation example, the BellEndpoint
class overrides the handleRequest
method and defines a single-argument constructor to receive BELL configuration properties at service creation.
package your.org.rest.example;
import com.ibm.wsspi.rest.handler.*;
public class BellEndpoint implements RESTHandler {
java.util.Map<String,String> props;
public BellEndpoint(java.util.Map<String, String> bellProperties) {props=bellProperties;}
@Override
public void handleRequest(RESTRequest request, RESTResponse response) {...}
}
For this example, the following service resource and implementation class files are packaged in the RestEpLib.jar
file.
META-INF/services/com.ibm.wsspi.rest.handler.RESTHandler your/org/rest/example/BellEndpoint.class
To enable the endpoint, the /META-INF/services/com.ibm.wsspi.rest.handler.RESTHandler
service resource must declare both the com.ibm.wsspi.rest.handler.root
OSGi service property in addition to the fully qualified name of the service implementation class. This OSGI service property is required by the RESTHandler
SPI to register the service as a listener for the specified subroot of the /ibm/api
URL path. Set the property to equal the name of the endpoint that you want to expose on the /ibm/api/
URL path.
You can configure OSGi properties that are specific to a service implementation class by adding one or more properties, prefixed by the #
character, to the service resource. Add the properties immediately before the name of the service implementation class to which they apply. The BELL feature registers the service interface with the implementation class and the specific OSGi properties.
The com.ibm.wsspi.rest.handler.root
OSGi property in the following example enables an endpoint with the /ibm/api/bellEP
URL path.
#com.ibm.wsspi.rest.handler.root=/bellEP
your.org.rest.example.BellEndpoint
The following example shows the BELL configuration in the server.xml
file that references the RestEpLib
library. The configuration specifies the spiVisibility="true"
attribute to enable the RestEpLib
library to access the REST Handler SPI packages. It also declares one BELL property. Notice that the RestEpLib.jar
library JAR is copied to the ${server.config.dir}/sharedlib
directory.
<library id=”RestEpLib">
<fileset dir="${server.config.dir}/sharedLib" includes="RestEpLib.jar" />
</library>
<bell libraryRef=”RestEpLib” spiVisibility=”true">
<properties hello=“WORLD” />
</bell>
The server.xml
file requires more configuration than just the BELL to expose the endpoint. In addition to the BELL feature, you must enable the Admin REST Connector (restConnector-2.0
) and Transport Security (transportSecurity-1.0
) features. The Admin REST Connector feature provides the REST Handler framework SPI. Endpoint access requires secure transport and a user who is mapped to the administrator role. The Transport Security feature and the related keyStore
, basicRegistry
, and administrator-role
configurations support secure access to the endpoint. The following server.xml
file example shows a possible configuration, including the BELL configuration from the previous example.
<featureManager>
<feature>bells-1.0</feature>
<feature>restConnector-2.0</feature>
<feature>transportSecurity-1.0</feature>
</featureManager>
<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>
<library id=”RestEpLib">
<fileset dir="${server.config.dir}/sharedLib" includes="RestEpLib.jar" />
</library>
<bell libraryRef=”RestEpLib” spiVisibility=”true">
<properties hello=“WORLD” />
</bell>
When this server starts, the BELL feature registers the RESTHandler
interface with the BellEndpoint
class and the com.ibm.wsspi.rest.handler.root=/bellEP
OSGi service property into the OSGi framework. The REST Handler framework then registers the service and makes the endpoint available at the https://<host>:8020/ibm/api/bellEP
URL.
When you make calls to the endpoint, the REST Handler framework handles the initial request by getting an instance of the service. The BELL feature creates an instance of the BellEndpoint
class that is injected with an unmodifiable map that contains the "hello"/"WORLD"
key/value pair. The framework then services the initial and subsequent requests by calling the handleRequest
method on the BellEnpoint
instance.