Oracle GlassFish Server Application Development Guide Release 3.1.2 Part Number E24930-01 |
|
|
View PDF |
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.
GlassFish Server is fully-compliant with Java EE 6, 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, 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:
Web Application Bundles (or WABs) , see Developing Web Application Bundles.
EJB Application Bundles, see Developing EJB Application Bundles.
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.
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.
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:
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);
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);
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 Oracle GlassFish Server 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;
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 |
|
|
|
JMS Topic destination |
|
|
|
JMS connection factory |
|
|
The actual service interface depends on which type of connection factory was created. |
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.
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) Bundle-ClassPath: WEB-INF/classes, WEB-INF/lib/lib1.jar, WEB-INF/lib/lib2.jar Web-ContextPath: /foo
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.
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; }
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.
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)
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.
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.
For instruction on deploying OSGi bundle, see "OSGi Bundle Deployment Guidelines" in Oracle GlassFish Server Application Deployment Guide.