blob: aa254ce400077c8e777d2d5dcc46bc07f21aea42 [file] [log] [blame]
type=page
status=published
title=Developing OSGi-enabled Jakarta EE Applications
next=part-services-and-apis.html
prev=lifecycle-listeners.html
~~~~~~
= Developing OSGi-enabled Jakarta EE Applications
[[GSDVG00015]][[gkpch]]
[[developing-osgi-enabled-java-ee-applications]]
== 13 Developing OSGi-enabled Jakarta EE Applications
This chapter describes the features and interfaces that {productName}
provides to develop OSGi-enabled enterprise applications. This chapter
includes the following sections:
* link:#gkpay[Overview of OSGi Application and {productName}]
* link:#gkqff[Developing OSGi Application Bundles for {productName}]
* link:#gkveh[Deploying OSGi Bundles in {productName}]
[[gkpay]][[GSDVG00173]][[overview-of-osgi-application-and-glassfish-server]]
=== Overview of OSGi Application and {productName}
{productName} is fully-compliant with Jakarta EE 10, so it provides the
latest Jakarta EE APIs and frameworks. It is built using OSGi technology,
and includes as its OSGi module management subsystem the
http://felix.apache.org[Apache Felix OSGi framework]
(`http://felix.apache.org`), which is a fully-compliant implementation
of the OSGi Service Platform R4 Version 4.3 specification. {productName} supports deployment of OSGi-based applications using this
framework. OSGi applications can make use of core as well as enterprise
OSGi features. {productName} makes available many of its Jakarta EE
platform services, such as the transaction service, HTTP service, JDBC
Service and JMS, as OSGi services. It also enables use of Jakarta EE
programming model in OSGi applications, so enterprise Java application
developers can continue to leverage their existing skills in OSGi-based
applications. See link:#glhek[Benefits of Using OSGi in Enterprise Java
Applications] for more information.
OSGi applications are deployed as one or more OSGi bundles, and the
{productName} 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 link:#gkupd[Developing Plain OSGi Bundles].
* Hybrid Application Bundles - bundles that are an OSGi bundle as wells
as a Jakarta EE module. At runtime, such modules have both an OSGi bundle
context and a Jakarta EE context. {productName} supports the following
hybrid application bundles:
** Web Application Bundles (or WABs) , see link:#gkunr[Developing Web
Application Bundles].
** EJB Application Bundles, see link:#gkunh[Developing EJB Application
Bundles].
[[glhek]][[GSDVG00488]][[benefits-of-using-osgi-in-enterprise-java-applications]]
==== 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. Jakarta 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 {productName}, you do not have to chose one of the two
platforms. A hybrid approach like OSGi enabling your Jakarta EE
applications allows new capabilities to applications hitherto
unavailable to applications built using just one of the two platforms.
[[gkqff]][[GSDVG00174]][[developing-osgi-application-bundles-for-glassfish-server]]
=== Developing OSGi Application Bundles for {productName}
{productName} enables interaction between OSGi components and Jakarta EE
components. OSGi services managed by the OSGi framework can invoke Java
EE components managed by the Jakarta 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 Jakarta EE context, to discover the
EJB and invoke it. Similarly, Jakarta EE components can locate OSGi
services provided by plain OSGi bundles and use them as well. {productName} extends the Jakarta EE Context and Dependency Injection (CDI)
framework to make it easier for Jakarta EE components to consume dynamic
OSGi services in a type-safe manner.
* link:#gkupd[Developing Plain OSGi Bundles]
* link:#gkunr[Developing Web Application Bundles]
* link:#gkunh[Developing EJB Application Bundles]
[[gkupd]][[GSDVG00489]][[developing-plain-osgi-bundles]]
==== Developing Plain OSGi Bundles
Jakarta EE components (like an EJB or Servlet) can look up Jakarta EE platform
services using JNDI names in the associated Jakarta EE naming context. Such
code can rely on the Jakarta EE container to inject the required services
as well. Unfortunately, neither of them works when the code runs outside
a Jakarta EE context. An example of such code is the `BundleActivator` of
an OSGi bundle. For such code to access Jakarta EE platform services,
{productName} makes key services and resources of the underlying Java
EE platform available as OSGi services. Thus, an OSGi bundle deployed in
{productName} can access these services using OSGi Service look-up
APIs or by using a white board pattern. The following Jakarta EE services
are available as OSGi services:
* link:#gkunk[HTTP Service]
* link:#gkunn[Transaction Service]
* link:#gkuof[JDBC Data Source Service]
* link:#gkuoq[JMS Resource Service]
[[gkunk]][[GSDVG00319]][[http-service]]
===== HTTP Service
The {productName} 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 {productName} 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 {productName}. 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 {productName}
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:
[source,java]
----
HttpService httpService = getHttpService(); // Obtain HttpService
httpService.registerServlet(httpService.registerServlet("/helloworld",
new HelloWorldServlet(), null, ctx);
----
[[gkunn]][[GSDVG00320]][[transaction-service]]
===== 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 Jakarta 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:
[source,java]
----
(UserTransaction)(new InitialContext().lookup("java:comp/UserTransaction"));
----
or
[source,java]
----
@Resource UserTransaction utx;
----
When certain code (such as an OSGi Bundle Activator), which does not
have a Jakarta 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:
[source,java]
----
BundleContext context;
ServiceReference txRef =
context.getServiceReference(UserTransaction.class.getName());
UserTransaction utx = (UserTransaction);
context.getService(txRef);
----
[[gkuof]][[GSDVG00321]][[jdbc-data-source-service]]
===== JDBC Data Source Service
Any JDBC data source created in {productName} 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 {productName}. For instructions on
administering JDBC resources in {productName}, see the
link:administration-guide.html#GSADG[{productName} Administration Guide].
{productName} 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:
[source,java]
----
@Inject
@OSGiService(true, "(jndi-name=jdbc/MyDS)")
private DataSource ds;
----
[[gkuoq]][[GSDVG00322]][[jms-resource-service]]
===== 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.
[width="100%",cols="12%,39%,12%,37%",options="header",]
|===
|JMS Object |Service Interface |Service Properties |Comments
|JMS Queue destination
|`jakarta.jms.Queue`
|`jndi-name`
|`jndi-name` is set to the JNDI name of the queue
|JMS Topic destination
|`jakarta.jms.Topic`
|`jndi-name`
|`jndi-name` is set to the JNDI name of the topic
|JMS connection factory
|`jakarta.jms.QueueConnectionFactory` +
or +
`jakarta.jms.TopicConnectionFactory` +
or +
`jakarta.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.
|===
[[gkunr]][[GSDVG00490]][[developing-web-application-bundles]]
==== 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 {productName} 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.
[[gkvau]][[GSDVG00323]][[required-wab-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:
[source]
----
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:
[source]
----
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
----
[[gkvat]][[GSDVG00324]][[how-wabs-consume-osgi-services]]
===== 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,
{productName} 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:
[source,java]
----
@WebServlet
public class MyServlet extends HttpServlet {
@Inject @OSGiService(dynamic=true)
FooService fooService;
}
----
To learn more about this feature, refer to link:#gkvbi[OSGi CDI
Extension for WABs].
[[gkvbi]][[GSDVG00325]][[osgi-cdi-extension-for-wabs]]
===== OSGi CDI Extension for WABs
{productName} 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 Jakarta 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.
[[GSDVG00044]][[gkvbk]]
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:
[source,java]
----
@Servlet
public void BarServlet extends HttpServlet{
@Inject @OSGiService(dynamic=true)
private com.acme.Foo f;
}
----
[[gkunh]][[GSDVG00491]][[developing-ejb-application-bundles]]
==== 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. {productName}supports only packaging the OSGi bundle as a simple JAR file with
required OSGi metadata, just as you would package an `ejb-jar` file.
[[gkvck]][[GSDVG00326]][[required-ejb-metadata]]
===== 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:
[source]
----
myEjb.jar/
com/acme/Foo
com/acme/impl/FooEJB
META-INF/MANIFEST.MF
----
MANIFEST.MF:
[source]
----
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)
----
[[gkvcj]][[GSDVG00327]][[how-ejb-bundles-consume-osgi-services]]
===== 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,
{productName} 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:
[source,java]
----
@Stateless
public class MyEJB {
@Inject @OSGiService(dynamic=true)
Foo foo;
...
}
----
To learn more about this feature, refer to link:#gkvbj[Using the OSGi
CDI Extension With EJB Bundles].
[[gkvbj]][[GSDVG00328]][[using-the-osgi-cdi-extension-with-ejb-bundles]]
===== Using the OSGi CDI Extension With EJB Bundles
{productName} 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 Jakarta 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.
[[gkveh]][[GSDVG00175]][[deploying-osgi-bundles-in-glassfish-server]]
=== Deploying OSGi Bundles in {productName}
For instruction on deploying OSGi bundle, see
"link:application-deployment-guide/deploying-applications.html#GSDPG00073[
OSGi Bundle Deployment Guidelines]"
in {productName} Application Deployment Guide.