19 Developing OSGi Bundles for WebLogic Server Applications
For general information about OSGi, see https://www.osgi.org/.
Understanding OSGi
OSGi defines a modular, service-oriented component model for Java. Bundles declare package dependencies and versions, and communicate through an OSGi service registry. The OSGi Working Group at the Eclipse Foundation continues the mission of the former OSGi Alliance. See OSGi Working Group and the OSGi specification and Javadoc index.
See OSGi Working Group; OSGi specification and Javadoc index.
OSGi offers you the following benefits:
-
Versioning of package wiring, for both implementors and users of interfaces.
-
The "uses" directive allows for intelligent wiring of class loaders and helps ensure a consistent class space.
-
Service and package access controls where the required security mechanisms are configured and supported by the Java runtime.
-
Dynamic service wiring through an active registry.
-
Various standard OSGi specifications provided by multiple vendors.
Features Provided in WebLogic Server OSGi Implementation
WebLogic Server allows you to configure and manage one or more instances of an OSGi framework. You can also create and deploy your own OSGi bundles.
WebLogic Server manages configured OsgiFrameworkMBean framework instances. An application can select one bundle for classloader and application-JNDI integration, as described in Accessing Deployed Bundle Objects From JNDI.Accessing Deployed Bundle Objects From JNDI
Applications can also deploy their own OSGi bundles. One specific OSGi bundle from the chosen framework instance can be used in the application classloader hierarchy.
WebLogic Server allows you to:
-
Configure and manage one or more instances of an OSGi framework using WLST.
WebLogic Server includes the Apache Felix implementation of the OSGi framework. See
http://felix.apache.orgfor information on Felix. -
Create and deploy your own OSGi bundles.
WebLogic Server includes an OSGi bundle containing the OSGi API. You can use this API to create your own OSGi bundles.
-
One specific OSGi bundle from the chosen framework instance can be used in the application classloader hierarchy.
-
Access OSGi bundles directly from JNDI.
-
Deploy and undeploy OSGi bundles.
-
Log OSGi status via the WebLogic Server logging mechanism.
-
Incorporate the OSGi services of your choice.
-
Manage OSGi bundle start levels for deployed bundles.
These topics are described in the sections that follow.
Configuring the OSGi Framework
WebLogic Server manages Apache Felix framework instances and their initialization properties.
An OSGi framework manages bundle installation, lifecycle and package wiring. WebLogic Server embeds and manages Apache Felix framework instances. Configure service availability and any required access controls for the deployed environment.
Note:
WebLogic Server supports only the Felix framework. Other OSGi Frameworks are not supported and have not been tested.
Configuring OSGi Framework Instances
WebLogic Server includes an OSGi framework by default, but it does not automatically start it.
Configure and target an OSGi framework before use.
-
Use WLST or a Java JMX client to create an OsgiFrameworkMBean in the domain edit configuration, assign its targets, save and activate the change. The resulting domain configuration is persisted in DOMAIN_HOME/config/config.xml.
In either case, configuration of an OSGi framework instance is controlled by the OsgiFrameworkMBean. For each framework associated with an OsgiFrameworkMBean, WebLogic Server boots an OSGi framework with a unique name.
You configure the OSGi framework attributes shown in Table 19-1.
Table 19-1 OSGi Framework Attributes
| Attribute | Usage |
|---|---|
| Targets | TargetMBean[]; select one or more configured servers or clusters on which this framework is to run. |
| Name | String; the name of the OsgiFrameworkMBean in its containing domain. Use a unique framework name in that domain. |
| FactoryImplementationClass | String; FrameworkFactory implementation class; default org.apache.felix.framework.FrameworkFactory. |
| DeployInstallationBundles | String; legal values populate (default) and ignore. Controls loading bundles from WL_HOME/server/osgi-lib; it does not disable bundles packaged in applications. |
| DynamicallyCreated | Read-only boolean reporting whether the bean was dynamically created; this is not a persistence setting for the writer or administrator to set. |
| InitProperties | java.util.Properties passed to framework initialization, subject to WebLogic overrides described in Configuring OSGi Framework Persistence. Standard framework properties and implementation-specific properties may be supplied. |
| OrgOsgiFrameworkBootdelegation |
The name of the |
| OrgOsgiFrameworkSystemPackagesExtra |
The name of the |
| RegisterGlobalDataSources |
Boolean. Returns true if global data sources should be added to the OSGi service registry. Default: true. |
| RegisterGlobalWorkManagers |
Boolean. Returns true if global work managers should be added to the OSGi service registry. Default: true. |
See Apache Felix Framework Configuration Properties: Framework configuration properties
OSGi Framework Configuration in config.xml
Example 18-1 illustrates the persisted domain configuration for a framework named test-osgi-frame targeted to AdminServer. Create this configuration through the WLST procedure below. Do not paste the fragment into a running domain’s config.xml. Multiple frameworks require distinct names in the containing domain. Activation applies supported dynamic changes; follow the activation result for any required restart.
Example 19-1 Persisted OSGi Framework Configuration
<osgi-framework>
<name>test-osgi-frame</name>
<target>AdminServer</target>
</osgi-framework>Configuring OSGi Framework Instance From WLST
Mode: WLST online configuration edit, connected to the Administration Server for this domain, in a fresh dedicated named edit session. Run this script with WLST after setting WLS_ADMIN_URL, WLS_USER_CONFIG, WLS_USER_KEY, WLS_TARGET_SERVER, WLS_OSGI_FRAMEWORK and WLS_OSGI_EDIT_SESSION to your values. WLS_ADMIN_URL is the configured t3s:// administration endpoint; configure its trusted certificate and hostname validation. The credential configuration/key pair must already exist, be protected, and authorize this edit. Use a new, unused edit-session name with no unrelated pending changes and a new framework name. The script looks up an existing server target; it does not create servers or replace an existing framework.
WL_HOME/common/bin/wlst.sh create_framework.py
Save as create_framework.py. Use wlst.cmd on Windows.
Example 19-2 Configuring OSGi Framework Instance From WLST
# Online configuration edit; run with WLST, not CPython.
import os
admin_url = os.environ['WLS_ADMIN_URL']
user_config = os.environ['WLS_USER_CONFIG']
user_key = os.environ['WLS_USER_KEY']
server_name = os.environ['WLS_TARGET_SERVER']
framework_name = os.environ['WLS_OSGI_FRAMEWORK']
session_name = os.environ['WLS_OSGI_EDIT_SESSION']
if not admin_url.startswith('t3s://'):
raise ValueError('WLS_ADMIN_URL must use the configured TLS administration endpoint')
connect(userConfigFile=user_config, userKeyFile=user_key, url=admin_url)
locked = False
activation_started = False
try:
edit(session_name)
startEdit(60000, 120000, 'true')
locked = True
cd('/')
domain = cmo
target = domain.lookupServer(server_name)
if target is None:
raise ValueError('No configured server named ' + server_name)
if domain.lookupOsgiFramework(framework_name) is not None:
raise ValueError('Framework already exists: ' + framework_name)
framework = domain.createOsgiFramework(framework_name)
framework.addTarget(target)
framework.setDeployInstallationBundles('populate')
framework.setOrgOsgiFrameworkSystemPackagesExtra(
'javax.naming,javax.sql,weblogic.work')
print('Framework: ' + framework.getName())
print('Targets: ' + str([t.getName() for t in framework.getTargets()]))
save()
activation_started = True
activate(block='true')
locked = False
except:
if locked and not activation_started:
try:
undo('true', 'y')
finally:
cancelEdit('y')
elif activation_started:
print('Inspect the activation task and named edit session before retrying; '
'do not cancel another session or assume rollback completed.')
raise
finally:
disconnect()
save persists pending changes; activate applies them. If activation fails or the connection is lost during activation, inspect the activation task and this dedicated edit session before cleanup or retry. Follow any reported restart requirement; do not assume that saved configuration alone proves a running framework.
Configuring OSGi Framework Instance from a Java Program
Mode: online configuration edit through the Administration Server’s edit MBean server. This standalone client creates one new OSGi framework and targets it to one existing server by name. It uses the framework’s default initialization settings. Run it in a terminal against a domain with no unrelated pending changes and with edit activity coordinated for this operation. The client requests an exclusive edit lock, refuses existing pending changes and refuses an existing framework name. It prompts for an authorized administrator user/password; credentials are not embedded in the source or passed on the command line. The endpoint must provide T3S with a certificate trusted by the client, and hostname verification must succeed. Substitute your actual host, TLS port, configured server name and new framework name in the command. An administration port, when configured, must be used as required by your domain.
Use the release-matched supported JDK and a full WebLogic installation with WL_HOME set to its wlserver directory. Compile and run from the directory containing OsgiFrameworkClient.java. On Windows, use a semicolon classpath separator.
javac -cp "$WL_HOME/server/lib/weblogic.jar" OsgiFrameworkClient.java
java -cp ".:$WL_HOME/server/lib/weblogic.jar" OsgiFrameworkClient admin.example.com 9002 managed1 osgi-example
admin.example.com, 9002, managed1 and osgi-example are illustrative argument values, not a preconfigured domain. Configure client TLS trust for your domain before running; do not disable certificate/hostname verification to make the example connect.
Example 19-3 Creating and Targeting an OSGi Framework Using JMX
import java.io.Console;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.Context;
import weblogic.management.configuration.DomainMBean;
import weblogic.management.configuration.OsgiFrameworkMBean;
import weblogic.management.configuration.ServerMBean;
import weblogic.management.jmx.MBeanServerInvocationHandler;
import weblogic.management.mbeanservers.edit.ActivationTaskMBean;
import weblogic.management.mbeanservers.edit.ConfigurationManagerMBean;
import weblogic.management.mbeanservers.edit.EditServiceMBean;
public final class OsgiFrameworkClient {
public static void main(String[] args) throws Exception {
if (args.length != 4) {
throw new IllegalArgumentException(
"Usage: OsgiFrameworkClient adminHost tlsPort targetServer frameworkName");
}
Console console = System.console();
if (console == null) {
throw new IllegalStateException("Run from a terminal to enter credentials");
}
String user = console.readLine("Administrator user: ");
char[] password = console.readPassword("Password: ");
if (user == null || password == null) {
throw new IllegalStateException("Credential entry was cancelled");
}
JMXServiceURL url = new JMXServiceURL("t3s", args[0],
Integer.parseInt(args[1]), "/jndi/" + EditServiceMBean.MBEANSERVER_JNDI_NAME);
Map<String, Object> environment = new HashMap<>();
environment.put(Context.SECURITY_PRINCIPAL, user);
environment.put(Context.SECURITY_CREDENTIALS, new String(password));
environment.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES,
"weblogic.management.remote");
Arrays.fill(password, '\0');
try (JMXConnector connector = JMXConnectorFactory.connect(url, environment)) {
MBeanServerConnection connection = connector.getMBeanServerConnection();
EditServiceMBean edit = (EditServiceMBean)
MBeanServerInvocationHandler.newProxyInstance(connection,
new ObjectName(EditServiceMBean.OBJECT_NAME),
EditServiceMBean.class, false);
configure(edit.getConfigurationManager(), args[2], args[3]);
}
}
static void configure(ConfigurationManagerMBean manager,
String serverName, String frameworkName) throws Exception {
DomainMBean domain = manager.startEdit(30000, 120000, true);
boolean cleanStart = false;
try {
if (manager.haveUnactivatedChanges()) {
throw new IllegalStateException("Resolve existing pending edits before running");
}
cleanStart = true;
ServerMBean server = domain.lookupServer(serverName);
if (server == null) {
throw new IllegalArgumentException("Unknown server: " + serverName);
}
if (domain.lookupOsgiFramework(frameworkName) != null) {
throw new IllegalArgumentException("Framework already exists: " + frameworkName);
}
OsgiFrameworkMBean framework = domain.createOsgiFramework(frameworkName);
framework.addTarget(server);
System.out.println("Creating " + framework.getName() + " on " + server.getName());
manager.save();
} catch (Exception failure) {
try {
try {
if (cleanStart) manager.undoUnactivatedChanges();
} finally {
manager.stopEdit();
}
} catch (Exception cleanup) {
failure.addSuppressed(cleanup);
}
throw failure;
}
// After activation starts, do not cancel a possibly different editor's session.
try {
ActivationTaskMBean task = manager.activate(120000);
System.out.println(task.getDetails());
if (task.getState() != ActivationTaskMBean.STATE_COMMITTED) {
throw new IllegalStateException("Activation did not commit", task.getError());
}
} catch (Exception failure) {
System.err.println("Inspect the activation task and pending edits before retrying; "
+ "saved changes may still be pending.");
throw failure;
}
}
}
See Accessing WebLogic Server MBeans with JMX. Managing a Domain’s Configuration with JMX.
WebLogic’s MBeanServerInvocationHandler maps returned MBean ObjectNames to typed proxies. The client looks up the target by name, creates a framework, adds that target, saves, and waits for activation. It prints the proposed framework/target and the activation details. save alone does not activate a change. A non-committed activation or a lost connection during activation requires inspection of the activation task and pending edits before retrying; saved changes may remain pending. Follow any reported restart requirement. Before activation begins, errors undo this attempt’s changes and release its edit lock; existing saved pending edits detected at the start are retained. The client closes its JMX connection on exit. It does not verify live bundle deployment or expose every OsgiFrameworkMBean option.
Parameter Required for Installing Bundles in the Framework
The OsgiFrameWorkMBean MBean Deploy Installation Bundles attribute controls whether or not bundles present in the osgi-lib directory (described later in this chapter in Deploying OSGi Bundles in the osgi-lib Directory) are actually installed into the framework.
The Deploy Installation Bundles parameter accepts the following values:
-
ignore— None of the bundles in this directory are installed and started. -
populate— The bundles are installed and started if possible. This is the default. Furthermore, a few extra packages are added to the boot delegation classpath parameters in order to enable the bundles in theosgi-libdirectory if they are not already there.It is not be considered a failure that causes the system to not boot if these bundles do not properly resolve and therefore cannot be started.
Configuring OSGi Framework Persistence
OSGi frameworks define persistent bundle state and autostart behavior. WebLogic Server recreates its managed framework cache on first initialization of each framework instance: it sets org.osgi.framework.storage to the WebLogic-selected cache directory and org.osgi.framework.storage.clean to onFirstInit. These values override corresponding InitProperties entries. Do not rely on setting standard Felix cache properties in InitProperties to retain installed bundles across WebLogic framework restarts. Keep required bundles in the configured installation directory or in application packaging so they can be installed again. WebLogic Server does not replicate or fail over this framework cache to another server.
Using OSGi Services
Import the packages required by the services your bundle uses, and install/enable the service-provider bundles where needed. An Import-Package declaration alone does not create a service. Obtain services from BundleContext, handle their dynamic availability, and release acquired services. Existing Package Admin and org.osgi.service.startlevel.StartLevel APIs are compatibility APIs; new introspection code can use Bundle.adapt with BundleWiring and BundleStartLevel as appropriate. Service availability and permission checks depend on the framework configuration and Java runtime.
See the Apache Felix Tutorial Example 1, Service Event Listener Bundle for an example of creating a simple bundle that listens for OSGi service events.
Connecting to an OSGi Console
You can inspect a configured framework through the OSGi API, as shown in Accessing Deployed Bundle Objects From JNDI. An optional Felix shell provides interactive administration. This WebLogic Server 26.1 branch includes Apache Felix 7.0.5; use the release’s third-party licensing information for the component inventory. The distribution retains the compatibility filename WL_HOME/server/lib/org.apache.felix.org.apache.felix.main.jar. Additional console bundles are not enabled merely by configuring the framework.
Use this optional procedure only in an isolated development environment. Felix Remote Shell provides no authentication or encrypted transport; a connected user can control the framework. Keep it bound to loopback and do not expose or forward its port. Use API introspection instead when an interactive shell is unnecessary.
- Obtain the Felix Shell (org.apache.felix.shell) and Remote Shell (org.apache.felix.shell.remote) bundles from the Apache Felix HTTPS downloads page.
- Before creating the development framework, set its InitProperties entries osgi.shell.telnet.ip=127.0.0.1 and osgi.shell.telnet.port=6666. Set DeployInstallationBundles to populate. Use this port for only one framework instance; assign distinct loopback ports to any others that load a remote-shell bundle.
- Put the two bundle JARs in WL_HOME/server/osgi-lib before creating/starting that framework; this directory is shared by framework instances configured to populate it.
- Create and target the framework using the WLST procedure. From the same host, connect with telnet 127.0.0.1 6666. help lists commands; ps lists bundle identities and states. End the local session and remove the optional shell bundles from the development configuration when finished; existing running frameworks require their normal lifecycle procedure to remove installed bundles.
See Apache Felix Remote Shell reference
from java.util import Properties
props = Properties()
props.setProperty('osgi.shell.telnet.ip', '127.0.0.1')
props.setProperty('osgi.shell.telnet.port', '6666')
framework.setInitProperties(props)
Apply distinct per-framework loopback ports to every framework that loads the shared shell bundles. Before save in the fresh-framework WLST example, insert the following while preserving any other required initialization entries:
-
helplists all the available commands -
pslists all bundles and what state they are in
Creating OSGi Bundles
You use the OSGi API bundle that is located in wlserver/server/lib/org.apache.felix.org.apache.felix.main.jar to create your own OSGi bundle.
See the Apache Felix Tutorial Example 1, Service Event Listener Bundle for an example of creating a simple bundle. As described in this example, the Import-Package attribute of the manifest file informs the framework of the bundle's dependencies on external packages. All bundles with an activator must import org.osgi.framework because it contains the core OSGi class definitions.
Deploying OSGi Bundles
Deploy OSGi bundle JARs either through a configured framework’s installation directory or by packaging them in an EAR or WAR with an osgi-framework-reference.
Preparing to Deploy an OSGi Bundle on a Target System
You can deploy OSGi bundles from inside a JAR, EAR, or WAR file, as appropriate for your application.
Before you do this, you must first specify which OSGi framework you want your bundle to use, and identity the bundle to WebLogic Server.
Note:
If the OSGi framework instance you specify does not exist on the target server, the OSGi bundle fails to deploy.
How you do this depends on whether your bundle is inside a WAR file or an EAR file:
-
WAR — The framework instance and bundle name must be in an element in the Web application's
weblogic.xmldeployment descriptor file. -
EAR — The framework instance and bundle name must be in an element in the application's
weblogic-application.xmldeployment descriptor file.If the EAR file contains WAR files, then the bundles inside the WAR files are deployed using the
weblogic.xmldeployment descriptor file from the embedded WAR files.
The sections that follow describe the required steps in detail.
For more information about WebLogic Server deployment descriptors, see Deploying Applications to Oracle WebLogic Server.
Preparing to Deploy Bundles as Enterprise Applications
Before you deploy your OSGi bundle, you must first:
- Use either the
DOMAIN_HOME\config\config.xmldeployment descriptor file or WLST to add an entry for the OSGi framework, as described in Configuring OSGi Framework Instances. - In the EAR file that contains the OSGi bundle, add both the name of the OSGi framework and the name of the bundle itself to the
weblogic-application.xmldeployment descriptor file.
Example 19-1 shows an example of updating config.xml to add the OSGi framework used by the WebLogic Server.
Example 19-4 shows an example of updating weblogic-application.xml to add both the name of the OSGi framework and the name and location of the bundle.
Example 19-4 Adding the Framework and Bundle to weblogic-application.xml
<osgi-framework-reference>
<name>test-osgi-frame</name>
<application-bundle-symbolic-name>com.oracle.weblogic.test.client
</application-bundle-symbolic-name>
<bundles-directory>rashi/osgi-lib</bundles-directory>
</osgi-framework-reference>
The stanza in Example 19-4 tells the WebLogic Server to attach to the OSGi framework named "test-osgi-frame" and to find the bundle in that server with the symbolic name com.oracle.weblogic.test.client in order to find classes from that OSGi framework.
Preparing to Deploy Bundles as Web Applications
Before you install your bundle as a WAR file, you must first:
- Use either the
DOMAIN_HOME\config\config.xmldeployment descriptor file or WLST to add an entry for the OSGi framework, as described in Configuring OSGi Framework Instances. - Add both the name of the OSGi framework and the name of the bundle itself to the web application's
weblogic.xmldeployment descriptor file.
Example 19-1 shows an example of updating config.xml to add the OSGi framework used by the WebLogic Server.
Example 19-5 shows an example of updating weblogic.xml to add both the name of the OSGi framework and the name and location of the bundle.
Example 19-5 Adding the Framework and Bundle to weblogic.xml
<osgi-framework-reference>
<name>test-osgi-frame</name>
<application-bundle-symbolic-name>com.oracle.weblogic.test.client
</application-bundle-symbolic-name>
<bundles-directory>rashi/osgi-lib</bundles-directory>
</osgi-framework-reference>
The stanza in Example 19-4 tells the WebLogic Server to attach to the OSGi framework named "test-osgi-frame" and to find the bundle in that server with the symbolic name com.oracle.weblogic.test.client in order to find classes from that OSGi framework.
Global Work Managers
Work Managers prioritize work based on rules you define and by monitoring actual run time performance statistics. This information is then used to optimize the performance of your application. See Using Work Managers to Optimize Scheduled Work in Administering Server Environments for Oracle WebLogic Server.
The OSGi implementation can take advantage of global work managers if the Register Global Work Managers MBean attribute is set to true, as described in Table 19-1.
You can determine which global work manager is in use from a Java application, as shown in Example 19-6.
Call names with the valid BundleContext supplied to your active bundle’s activator, or obtained through the selected bundle described in Accessing Deployed Bundle Objects From JNDI. Configure and target a global Work Manager named GlobalScopedWorkManager and leave RegisterGlobalWorkManagers enabled; substitute your configured service name in the filter. An empty result means no matching visible service is available. The returned names are a snapshot, not a guarantee that a service remains registered. The bundle must import org.osgi.framework and weblogic.work; weblogic.work must be visible in the framework system packages, as supplied by the WLST example.
Example 19-6 Determining Global Work Managers
package examples.osgi;
import java.util.ArrayList;
import java.util.List;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import weblogic.work.WorkManager;
public final class WorkManagerLookup {
private WorkManagerLookup() { }
public static List<String> names(BundleContext context)
throws InvalidSyntaxException {
List<String> names = new ArrayList<>();
for (ServiceReference<WorkManager> reference :
context.getServiceReferences(WorkManager.class,
"(Name=GlobalScopedWorkManager)")) {
WorkManager manager = context.getService(reference);
if (manager == null) {
continue; // The service may have been unregistered.
}
try {
names.add(manager.getName());
} finally {
context.ungetService(reference);
}
}
return names;
}
}
Global Data Sources
In WebLogic Server, you can configure database connectivity by configuring JDBC data sources and multi data sources and then targeting or deploying the JDBC resources to servers or clusters in your WebLogic domain, as described in WebLogic Server Data Sources in Understanding Oracle WebLogic Server.
The OSGi implementation can take advantage of global data sources if the Register Global Data Sources MBean attribute is set to true, as described in Table 19-1.
You can determine which global data source is in use from a Java application, as shown in Example 19-7.
This example assumes an Oracle Database data source named OsgiDS is configured, deployed and targeted to this server and RegisterGlobalDataSources is enabled. Substitute the configured data-source service name in the Name filter. The fixed SELECT 1 FROM DUAL query is Oracle-specific; use an appropriate fixed query for another database. Call readValues with a valid BundleContext. An empty list means no matching visible service was obtained; handle or propagate SQLException and InvalidSyntaxException at the calling component boundary. try-with-resources closes ResultSet, Statement and Connection on success or failure; the finally block separately releases the acquired OSGi service. Import org.osgi.framework and javax.sql in the bundle manifest and make javax.sql visible to the framework. java.sql and javax.sql are Java SE APIs. Do not close the DataSource itself.
Example 19-7 Determining Global Data Sources
package examples.osgi;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
public final class DataSourceLookup {
private DataSourceLookup() { }
public static List<String> readValues(BundleContext context)
throws InvalidSyntaxException, SQLException {
List<String> values = new ArrayList<>();
for (ServiceReference<DataSource> reference :
context.getServiceReferences(DataSource.class, "(Name=OsgiDS)")) {
DataSource dataSource = context.getService(reference);
if (dataSource == null) {
continue;
}
try {
// Oracle Database example; use an appropriate query for other databases.
try (Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet rows = statement.executeQuery("SELECT 1 FROM DUAL")) {
while (rows.next()) {
values.add(rows.getString(1));
}
}
} finally {
context.ungetService(reference);
}
}
return values;
}
}
Deploying OSGi Bundles in the osgi-lib Directory
Note:
OsgiFrameworkMBean.DeployInstallationBundles controls installation-directory bundles as described in Parameter Required for Installing Bundles in the Framework. The default value is populate, which attempts to install the bundles in WL_HOME/server/osgi-lib and start those that can be started.
To deploy a bundle with the start-level of 1, create the WL_HOME/server/osgi-lib directory if it does not already exist, and then copy the OSGi bundle JAR file to it.
The scanner attempts to install readable files with the case-sensitive .jar suffix. Each file must be a valid OSGi bundle JAR; files ending in .ear or .war are not scanned as bundles.
The directory is scanned when each configured framework is initialized, and it is not monitored afterward. To load a new directory bundle through this mechanism, reinitialize the affected framework through its managed lifecycle, for example by a controlled restart of its targeted WebLogic Server. Coordinate this with dependent applications.
Setting Bundle and Framework Start Levels
Bundle JARs directly in WL_HOME/server/osgi-lib are assigned start level 1. One-level subdirectories whose complete names parse as positive Java int values, for example 2 or 3, assign that bundle start level to their JARs. Names such as 3-startup and 0 are not valid numbered directories. A bundle whose start level is above the framework’s active start level remains inactive until the framework reaches that level. The default beginning framework level is 1. To start bundles assigned level 3 during framework startup, set InitProperties entry org.osgi.framework.startlevel.beginning to the string 3 before that framework is initialized. Start levels control lifecycle ordering; they do not replace correct package/service dependencies.
For a new framework, optionally insert the following before save in the WLST script. For an existing framework preserve its other initialization entries.
from java.util import Properties
props = Properties()
props.setProperty('org.osgi.framework.startlevel.beginning', '3')
framework.setInitProperties(props)
Accessing Deployed Bundle Objects From JNDI
When an application’s osgi-framework-reference selects an application-bundle-symbolic-name, WebLogic Server finds the matching bundle in that framework, attaches its class finder to the application, and binds that Bundle object at java:app/osgi/Bundle in the application’s naming environment. An optional application-bundle-version constrains the version match; without a constraint, the highest matching bundle version is selected. This binding is not automatically created merely by starting a framework or deploying bundles without selecting an application bundle. The selected bundle must exist; a failed selection prevents application deployment. A caller can obtain its BundleContext while that selected bundle has an active context. Do not cache and reuse the context after the bundle stops.
Example 19-8 shows how to access a bundle that you create from JNDI.
Call describe() from a component of the deployed application whose reference selects a bundle. It returns a snapshot of installed bundles and registered-service metadata. Bundle states are the numeric Bundle constants; ACTIVE identifies an active bundle. The listing does not acquire service objects or change framework state. A stopped bundle can invalidate its context during inspection; handle NamingException and lifecycle failures at the component boundary and repeat inspection only while the selected bundle is active. Require framework visibility and bundle imports for org.osgi.framework, org.osgi.framework.startlevel and javax.naming. The WLST example exports javax.naming. Use WorkManagerLookup and DataSourceLookup to acquire service objects.
Example 19-8 Reading Bundle Metadata From Application JNDI
package examples.osgi;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.startlevel.BundleStartLevel;
public final class BundleInfo {
private BundleInfo() { }
public static List<String> describe() throws NamingException {
InitialContext naming = new InitialContext();
Bundle selected;
try {
selected = (Bundle) naming.lookup("java:app/osgi/Bundle");
} finally {
naming.close();
}
BundleContext context = selected.getBundleContext();
if (context == null) {
throw new IllegalStateException("The selected bundle has no active context");
}
return describe(context);
}
public static List<String> describe(BundleContext context) {
List<String> lines = new ArrayList<>();
for (Bundle bundle : context.getBundles()) {
BundleStartLevel level = bundle.adapt(BundleStartLevel.class);
lines.add("id=" + bundle.getBundleId()
+ " name=" + bundle.getSymbolicName()
+ " version=" + bundle.getVersion()
+ " state=" + bundle.getState()
+ " startLevel=" + (level == null ? "n/a" : level.getStartLevel()));
ServiceReference<?>[] references = bundle.getRegisteredServices();
if (references != null) {
for (ServiceReference<?> reference : references) {
lines.add(" service=" + reference.getProperty(Constants.SERVICE_ID)
+ " types=" + Arrays.toString((String[])
reference.getProperty(Constants.OBJECTCLASS))
+ " Name=" + reference.getProperty("Name"));
}
}
}
return lines;
}
}
Using OSGi Logging Via WebLogic Server
With installation bundles enabled, the supplied OSGi bridge forwards log events to WebLogic Server logging.
The installation supplies org.apache.felix.log-1.3.0.jar and com.oracle.weblogic.osgi.logger.jar in WL_HOME/server/osgi-lib. With DeployInstallationBundles=populate, the framework attempts to install and start these bundles; the bridge listens to OSGi log events and forwards them to WebLogic logging. Setting ignore skips these installation-directory bundles, so this bridge is not automatically loaded by that mechanism.
The logger system name is OSGiForApps. The messages severity levels are mapped between OSGi and WebLogic Server as shown in Table 19-2.
The legacy integer constants are defined by org.osgi.service.log.LogService. The WebLogic severity constants are defined by weblogic.i18n.logging.Severities; this table describes the bridge’s mapping of those integer log levels.
Table 19-2 OSGi and WebLogic Server Logging Severity Mapping
| OSGi Severity Levels | WebLogic Server Severity Level |
|---|---|
|
LogService.LOG_ERROR |
Severities.ERROR |
|
LogService.LOG_WARNING |
Severities.WARNING |
|
LogService.LOG_INFO |
Severities.INFO |
|
LogService.LOG_DEBUG |
Severities.DEBUG |
Configuring a Filtering ClassLoader for OSGi Bundles
A filtering classloader controls application package preference; configure bundle selection and package wiring separately.
Filtering controls whether matching application packages are preferred over parent packages. It does not install a dependency, export an OSGi package, or make an unavailable class visible. Select and attach the intended bundle through osgi-framework-reference before relying on its classes from the application. In an EAR, configure prefer-application-packages in META-INF/weblogic-application.xml at application scope. In a standalone WAR, configure it under container-descriptor in WEB-INF/weblogic.xml; keep prefer-web-inf-classes false when using this filter. For ordinary WAR libraries, package the JARs in WEB-INF/lib. For WAR-contained OSGi bundles, use WEB-INF/osgi-lib or the configured bundles directory. Bundle dependencies still require correct Import-Package/Export-Package wiring. OrgOsgiFrameworkSystemPackagesExtra can expose packages already available to the framework parent; it cannot supply an absent library. Export only the packages required by your integration. Keep Java SE javax.naming and javax.sql names unchanged; Jakarta EE APIs use their actual jakarta package names. See Using a Filtering ClassLoader in Chapter 12.Using a Filtering Classloader
<!-- Inside weblogic-application -->
<prefer-application-packages>
<package-name>org.example.library.*</package-name>
</prefer-application-packages>
<!-- Inside weblogic-web-app for a standalone WAR -->
<container-descriptor>
<prefer-web-inf-classes>false</prefer-web-inf-classes>
<prefer-application-packages>
<package-name>org.example.library.*</package-name>
</prefer-application-packages>
</container-descriptor>
OSGI Example
WebLogic Server includes two simple example OSGi bundles: client and server. The server bundle (ServerBundle) exports a packet that the client bundle (ClientBundle) imports. The example produces an HTML page that displays the deployed OSGi bundles.
WebLogic Server includes an example that demonstrates how to deploy OSGi bundles to WebLogic Server. If you installed the WebLogic Server examples, the OSGi example source code is available in ORACLE_HOMEwl_server/examples/src/examples/osgi/osgiApp, where ORACLE_HOME represents the directory in which the WebLogic Server code examples are configured. For more information about the WebLogic Server code examples, see Sample Applications and Code Examples in Understanding Oracle WebLogic Server.