Developing OSGi-enabled Java EE Applications

DRAFT


Previous Next Contents

13 Developing OSGi-enabled Java EE Applications

This chapter describes the features and interfaces that GlassFish Server provides to develop OSGi-enabled enterprise applications. This chapter includes the following sections:

Note

Many of the features and interfaces presented in this chapter are demonstrated in samples and video clips available from the OSGi section of the GlassFish Server wiki. See http://wikis.sun.com/display/GlassFish/Osgi for more information.

Overview of OSGi Application and GlassFish Server

GlassFish Server is fully-compliant with Java EE 8, so it provides the latest Java EE APIs and frameworks. It is built using OSGi technology, and includes as its OSGi module management subsystem the Apache Felix OSGi framework (http://felix.apache.org), which is a fully-compliant implementation of the OSGi Service Platform R4 Version 4.3 specification. GlassFish Server supports deployment of OSGi-based applications using this framework. OSGi applications can make use of core as well as enterprise OSGi features. GlassFish Server makes available many of its Java EE platform services, such as the transaction service, HTTP service, JDBC Service and JMS, as OSGi services. It also enables use of Java EE programming model in OSGi applications, so enterprise Java application developers can continue to leverage their existing skills in OSGi-based applications. See Benefits of Using OSGi in Enterprise Java Applications for more information.

OSGi applications are deployed as one or more OSGi bundles, and the GlassFish Server deployment and administration infrastructure enables you to deploy and manage your OSGi bundles. This chapter classifies OSGi bundles into two categories based on the features they use:

  • Plain OSGi Application Bundles - bundles that do not contain any Java EE components. See Developing Plain OSGi Bundles.

  • Hybrid Application Bundles - bundles that are an OSGi bundle as wells as a Java EE module. At runtime, such modules have both an OSGi bundle context and a Java EE context. GlassFish Server supports the following hybrid application bundles:

Benefits of Using OSGi in Enterprise Java Applications

Enterprise applications typically need transactional, secured access to data stores, messaging systems and other such enterprise information systems, and have to cater to a wide variety of clients such as web browsers and desktop applications, and so on. Java EE makes development of such applications easier with a rich set of APIs and frameworks. It also provides a scalable, reliable and easy to administer runtime to host such applications.

The OSGi platform complements these features with modularity. It enables applications to be separated into smaller, reusable modules with a well defined and robust dependency specification. A module explicitly specifies its capabilities and requirements. This explicit dependency specification encourages developers to visualize dependencies among their modules and help them make their modules highly cohesive and less coupled. The OSGi module system is dynamic: it allows modules to be added and removed at runtime. OSGi has very good support for versioning: it supports package versioning as well module versioning. In fact, it allows multiple versions of the same package to coexist in the same runtime, thus allowing greater flexibility to deployers. The service layer of the OSGi platform encourages a more service-oriented approach to build a system. The service-oriented approach and dynamic module system used together allow a system to be more agile during development as well as in production. It makes them better suited to run in an Platform-as-a-Service (PaaS) environment.

With GlassFish Server, you do not have to chose one of the two platforms. A hybrid approach like OSGi enabling your Java EE applications allows new capabilities to applications hitherto unavailable to applications built using just one of the two platforms.

Developing OSGi Application Bundles for GlassFish Server

GlassFish Server enables interaction between OSGi components and Java EE components. OSGi services managed by the OSGi framework can invoke Java EE components managed by the Java EE container and vice versa. For example, developers can declaratively export EJBs as OSGi services without having to write any OSGi code. This allows any plain OSGi component, which is running without the Java EE context, to discover the EJB and invoke it. Similarly, Java EE components can locate OSGi services provided by plain OSGi bundles and use them as well. GlassFish Server extends the Java EE Context and Dependency Injection (CDI) framework to make it easier for Java EE components to consume dynamic OSGi services in a type-safe manner.

Developing Plain OSGi Bundles

Java EE components (like an EJB or Servlet) can look up Java EE platform services using JNDI names in the associated Java EE naming context. Such code can rely on the Java EE container to inject the required services as well. Unfortunately, neither of them works when the code runs outside a Java EE context. An example of such code is the BundleActivator of an OSGi bundle. For such code to access Java EE platform services, GlassFish Server makes key services and resources of the underlying Java EE platform available as OSGi services. Thus, an OSGi bundle deployed in GlassFish Server can access these services using OSGi Service look-up APIs or by using a white board pattern. The following Java EE services are available as OSGi services:

HTTP Service

The GlassFish Server web container is made available as a service for OSGi users who do not use OSGi Web Application Bundles (WABs). This service is made available using the standard OSGi/HTTP service specification, which is a light API that predates the concept of a web application as we know it today. This simple API allows users to register servlets and static resources dynamically and draw a boundary around them in the form of a HttpContext. This simple API can be used to build feature-rich web application, such as the Felix Web Console for example.

The GlassFish Server web container has one or more virtual servers. A virtual server has one or more web application deployed in it. Each web application has a distinct context path. Each virtual server has a set of HTTP listeners. Each HTTP listener listens on a particular port. When multiple virtual servers are present, one of them is treated as the default virtual server. Every virtual server comes configured with a default web application. The default web application is used to serve static content from the docroot of GlassFish Server. This default web application uses / as the context path. A web application contains static and dynamic resources. Each virtual server is mapped to an org.osgi.services.http.HttpService instance. When there are multiple virtual servers present, there will be multiple occurrences of HttpService registered in the service registry. In order to distinguish one service from another, each service is registered with a service property named VirtualServer, whose value is the name of the virtual server. The service corresponding to default virtual server has the highest ranking, so when looking up a service of type HttpService without any additional criteria returns the HttpService corresponding to the default virtual server. In a typical GlassFish Server installation, the default virtual server is configured to listen on port 8080 for the HTTP protocol and port 8181 for the HTTPS protocol.

The context path / is reserved for the default web application. Every resource and servlet registered using the registerResource() and registerServlet() methods of HttpService are made available under a special context path named /osgi in the virtual server. The /osgi context path can be changed to some other value by setting an appropriate value in the OSGi configuration property or in a system property called org.glassfish.osgihttp.ContextPath.

For example, HelloWorldServlet will be available at http://localhost:8080/osgi/helloworld when the following code is executed:

HttpService httpService = getHttpService(); // Obtain HttpService
httpService.registerServlet(httpService.registerServlet("/helloworld",
new HelloWorldServlet(), null, ctx);

Transaction Service

The Java Transaction API (JTA) defines three interfaces to interact with the transaction management system: UserTransaction, TransactionManager, and TransactionSynchronizationRegistry. They all belong to the javax.transaction package. TransactionManager`and `TransactionSynchronizationRegistry are intended for system level code, such as a persistence provider. Whereas, UserTransaction is the entity that you should use to control transactions. All the objects of the underlying JTA layer are made available in the OSGi service registry using the following service interfaces:

  • javax.transaction.UserTransaction

  • javax.transaction.TransactionManager

  • javax.transaction.TransactionSynchronisationRegistry

There is no additional service property associated with them. Although UserTransaction appears to be a singleton, in reality any call to it gets rerouted to the actual transaction associated with the calling thread. Code that runs in the context of a Java EE component typically gets a handle on UserTransaction by doing a JNDI lookup in the component naming context or by using injection, as shown here:

(UserTransaction)(new InitialContext().lookup("java:comp/UserTransaction"));

or

@Resource UserTransaction utx;

When certain code (such as an OSGi Bundle Activator), which does not have a Java EE component context, wants to get hold of UserTransaction, or any of the other JTA artifacts, then they can look it up in the service registry. Here is an example of such code:

BundleContext context;
ServiceReference txRef =
    context.getServiceReference(UserTransaction.class.getName());
UserTransaction utx = (UserTransaction);
context.getService(txRef);

JDBC Data Source Service

Any JDBC data source created in GlassFish Server is automatically made available as an OSGi Service; therefore, OSGi bundles can track availability of JDBC data sources using the ServiceTracking facility of the OSGi platform. The life of the OSGi service matches that of the underlying data source created in GlassFish Server. For instructions on administering JDBC resources in GlassFish Server, see the GlassFish Server Open Source Edition Administration Guide.

GlassFish Server registers each JDBC data source as an OSGi service with objectClass = "javax.sql.DataSource" and a service property called jndi-name, which is set to the JNDI name of the data source. Here is a code sample that looks up a data source service:

  @Inject
  @OSGiService(true,
         "(jndi-name=jdbc/MyDS)")
  private DataSource ds;

JMS Resource Service

Like JDBC data sources, JMS administered objects, such as destinations and connection factories, are also automatically made available as OSGi services. Their service mappings are as follows.

JMS Object Service Interface Service Properties Comments

JMS Queue destination

javax.jms.Queue

jndi-name

jndi-name is set to the JNDI name of the queue

JMS Topic destination

javax.jms.Topic

jndi-name

jndi-name is set to the JNDI name of the topic

JMS connection factory

javax.jms.QueueConnectionFactory or javax.jms.TopicConnectionFactory or javax.jms.ConnectionFactory

jndi-name

jndi-name is set to the JNDI name of the topic.

The actual service interface depends on which type of connection factory was created.

Developing Web Application Bundles

When a web application is packaged and deployed as an OSGi bundle, it is called a Web Application Bundle (WAB). WAB support is based on the OSGi Web Application specification , which is part of the OSGi Service Platform, Enterprise Specification, Release 4, Version 4.3. A WAB is packaged as an OSGi bundle, so all the OSGi packaging rules apply to WAB packaging. When a WAB is not packaged like a WAR, the OSGi Web Container of GlassFish Server maps the WAB to the hierarchical structure of web application using the following rules:

  • The root of the WAB corresponds to the docroot of the web application.

  • Every JAR in the Bundle-ClassPath of the WAB is treated like a JAR in WEB-INF/lib/.

  • Every directory except "." in Bundle-ClassPath of the WAB is treated like WEB-INF/classes/.

  • Bundle-ClassPath entry of type "." is treated as if the entire WAB is a JAR in WEB-INF/lib/.

  • Bundle-ClassPath includes the Bundle-ClassPath entries of any attached fragment bundles.

The simplest way to avoid knowing these mapping rules is to avoid the problem in the first place. Moreover, there are many packaging tools and development time tools that understand WAR structure. Therefore, we strongly recommend that you package the WAB exactly like a WAR, with only additional OSGi metadata.

Required WAB Metadata

In addition to the standard OSGi metadata, the main attributes of META-INF/MANIFEST.MF of the WAB must have an additional attribute called Web-ContextPath. The Web-ContextPath attribute specifies the value of the context path of the web application. Since the root of a WAB is mapped to the docroot of the web application, it should not be used in the Bundle-ClassPath. Moreover, WEB-INF/classes/ should be specified ahead of WEB-INF/lib/ in the Bundle-ClassPath in order to be compliant with the search order used for traditional WAR files.

Assuming the WAB is structured as follows:

  foo.war/
       index.html
       foo.jsp
       WEB-INF/classes/
                      foo/BarServlet.class
       WEB-INF/lib/lib1.jar
       WEB-INF/lib/lib2.jar

Then the OSGi metadata for the WAB as specified in META-INF/MANIFEST.MF of the WAB would appear as follows:

  MANIFEST.MF:Manifest-Version: 1.0
  Bundle-ManifestVersion: 2
  Bundle-SymbolicName: com.acme.foo
  Bundle-Version: 1.0
  Bundle-Name: Foo Web Application Bundle Version 1.0
  Import-Package: javax.servlet; javax.servlet.http, version=[3.0, 4.0, 5.0)
  Bundle-ClassPath: WEB-INF/classes, WEB-INF/lib/lib1.jar, WEB-INF/lib/lib2.jar
  Web-ContextPath: /foo

How WABs Consume OSGi Services

Since a WAB has a valid Bundle-Context, it can consume OSGi services. Although you are free to use any OSGi API to locate OSGi services, GlassFish Server makes it easy for WAB users to use OSGi services by virtue of extending the Context and Dependency Injection (CDI) framework. Here’s an example of the injection of an OSGi Service into a Servlet:

  @WebServlet
  public class MyServlet extends HttpServlet {
    @Inject @OSGiService(dynamic=true)
    FooService fooService;
  }

To learn more about this feature, refer to OSGi CDI Extension for WABs.

OSGi CDI Extension for WABs

GlassFish Server includes a CDI extension that enables web applications, such as servlets, that are part of WABs to express a type-safe dependency on an OSGi service using CDI APIs. An OSGi service can be provided by any OSGi bundle without any knowledge of Java EE/CDI, and they are allowed to be injected transparently in a type-safe manner into a web application.

A custom CDI Qualifier, @org.glassfish.osgicdi.OSGiService, is used by the component to represent dependency on an OSGi service. The qualifier has additional metadata to customize the service discovery and injection behavior. The following @OsgiService attributes are currently available:

  • serviceCriteria — An LDAP filter query used for service selection in the OSGi service registry.

  • waitTimeout — Waits the specified duration for a service that matches the criteria specified to appear in the OSGi service registry.

  • dynamic — Dynamically obtain a service reference (true/false).
    Since OSGi services are dynamic, they may not match the life cycle of the application component that has injected a reference to the service. Through this attribute, you could indicate that a service reference can be obtained dynamically or not. For stateless or idempotent services, a dynamic reference to a service implementation would be useful. The container then injects a proxy to the service and dynamically switches to an available implementation when the current service reference is invalid.

Example 13-1 Example of a WAB Using CDI

In this example, Bundle B0 defines a service contract called com.acme.Foo and exports the com.acme package for use by other bundles. Bundle B1 in turn provides a service implementation, FooImpl, of the com.acme.Foo interface. It then registers the service FooImpl service with the OSGi service registry with com.acme.Foo as the service interface.

Bundle B2 is a hybrid application bundle that imports the com.acme package. It has a component called BarServlet that expresses a dependency to com.acme.Foo by adding a field/setter method and qualifies that injection point with @OsgiService. For instance, BarServlet could look like:

  @Servlet
  public void BarServlet extends HttpServlet{
      @Inject @OSGiService(dynamic=true)
      private com.acme.Foo f;
  }

Developing EJB Application Bundles

Another type of hybrid application bundle is the EJB Application Bundle. When an EJB Jar is packaged with additional OSGi metadata and deployed as an OSGi bundle it is called an EJB Application Bundle. GlassFish Serversupports only packaging the OSGi bundle as a simple JAR file with required OSGi metadata, just as you would package an ejb-jar file.

Required EJB Metadata

An EJB Application Bundle must have a manifest metadata called Export-EJB in order to be considered as an EJB Bundle. For syntax of Export-EJB header, please refer to the Publishing EJB as OSGi Service section. Here’s an example of an EJB Application Bundle with its metadata:

  myEjb.jar/
           com/acme/Foo
           com/acme/impl/FooEJB
           META-INF/MANIFEST.MF
  MANIFEST.MF:
  Manifest-Version: 1.0
  Bundle-ManifestVersion: 2
  Bundle-SymbolicName: com.acme.foo EJB bundle
  Bundle-Version: 1.0.0.BETA
  Bundle-Name: com.acme.foo EJB bundle version 1.0.0.BETA
  Export-EJB: ALL
  Export-Package: com.acme; version=1.0
  Import-Package: javax.ejb; version=[3.0, 4.0), com.acme; version=[1.0, 1.1)

How EJB Bundles Consume OSGi Services

Since an EJB has a valid Bundle-Context, it can consume OSGi services. Although you are free to use any OSGi API to locate OSGi services, GlassFish Server makes it easy to use OSGi services by virtue of extending the Context and Dependency Injection (CDI) framework. Here’s an example of injection of an OSGi Service into a servlet:

  @Stateless
  public class MyEJB {
    @Inject @OSGiService(dynamic=true)
    Foo foo;
    ...
  }

To learn more about this feature, refer to Using the OSGi CDI Extension With EJB Bundles.

Using the OSGi CDI Extension With EJB Bundles

GlassFish Server includes a CDI extension that enables EJB application bundles to express a type-safe dependency on an OSGi Service using CDI APIs. An OSGi service can be provided by any OSGi bundle without any knowledge of Java EE/CDI, and they are allowed to be injected transparently in a type-safe manner into an EJB bundle.

A custom CDI Qualifier, @org.glassfish.osgicdi.OSGiService, is used by the component to represent dependency on an OSGi service. The qualifier has additional metadata to customize the service discovery and injection behavior. The following @OsgiService attributes are currently available:

  • dynamic — Dynamically obtain a service reference (true/false).

  • waitTimeout — Waits for specified duration for a service to appear in the OSGi service registry.

  • serviceCriteria — An LDAP filter query used for service selection.

Deploying OSGi Bundles in GlassFish Server

For instruction on deploying OSGi bundle, see "OSGi Bundle Deployment Guidelines" in GlassFish Server Open Source Edition Application Deployment Guide.


Previous Next Contents
Eclipse Foundation Logo  Copyright © 2019, Oracle and/or its affiliates. All rights reserved.

DRAFT