HttpService httpService = getHttpService(); // Obtain HttpService
httpService.registerServlet(httpService.registerServlet("/helloworld",
new HelloWorldServlet(), null, ctx);
Developing OSGi-enabled Java EE Applications |
Previous | Next | Contents |
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
|
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:
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
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;
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, 5.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 GlassFish Server Open Source Edition Application Deployment Guide.
Previous | Next | Contents |