| type=page |
| status=published |
| title=Developing OSGi-enabled Java EE Applications |
| next=part-services-and-apis.html |
| prev=lifecycle-listeners.html |
| ~~~~~~ |
| Developing OSGi-enabled Java EE Applications |
| ============================================ |
| |
| [[GSDVG00015]][[gkpch]] |
| |
| |
| [[developing-osgi-enabled-java-ee-applications]] |
| 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: |
| |
| * link:#gkpay[Overview of OSGi Application and GlassFish Server] |
| * link:#gkqff[Developing OSGi Application Bundles for GlassFish Server] |
| * link:#gkveh[Deploying OSGi Bundles in GlassFish Server] |
| |
| |
| [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. |
| |
| ======================================================================= |
| |
| |
| [[gkpay]][[GSDVG00173]][[overview-of-osgi-application-and-glassfish-server]] |
| |
| 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 |
| 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. 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 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 |
| 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 link:#gkupd[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 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. 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. |
| |
| [[gkqff]][[GSDVG00174]][[developing-osgi-application-bundles-for-glassfish-server]] |
| |
| 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. |
| |
| * 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 |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| 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: |
| |
| * 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 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: |
| |
| [source,oac_no_warn] |
| ---- |
| |
| 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 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: |
| |
| [source,oac_no_warn] |
| ---- |
| (UserTransaction)(new InitialContext().lookup("java:comp/UserTransaction")); |
| ---- |
| |
| or |
| |
| [source,oac_no_warn] |
| ---- |
| @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: |
| |
| [source,oac_no_warn] |
| ---- |
| |
| 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 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 |
| link:../administration-guide/toc.html#GSADG[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: |
| |
| [source,oac_no_warn] |
| ---- |
| @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` a| |
| `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 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. |
| |
| [[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,oac_no_warn] |
| ---- |
| |
| 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,oac_no_warn] |
| ---- |
| |
| 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, |
| 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: |
| |
| [source,oac_no_warn] |
| ---- |
| |
| @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 |
| +++++++++++++++++++++++++++ |
| |
| 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. |
| |
| [[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,oac_no_warn] |
| ---- |
| |
| @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. 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. |
| |
| [[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,oac_no_warn] |
| ---- |
| |
| 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) |
| ---- |
| |
| [[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, |
| 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: |
| |
| [source,oac_no_warn] |
| ---- |
| |
| @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 |
| +++++++++++++++++++++++++++++++++++++++++++++ |
| |
| 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. |
| |
| [[gkveh]][[GSDVG00175]][[deploying-osgi-bundles-in-glassfish-server]] |
| |
| Deploying OSGi Bundles in GlassFish Server |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| For instruction on deploying OSGi bundle, see "link:../application-deployment-guide/deploying-applications.html#GSDPG00073[OSGi |
| Bundle Deployment Guidelines]" in GlassFish Server Open Source Edition |
| Application Deployment Guide. |
| |
| |