Skip to main content

Our second hybrid application - EJB as OSGi Service

Posted by ss141213 on June 16, 2009 at 1:02 AM PDT

Last time, we talked about our first hybrid (Java EE + OSGi) application where we discussed not only about development of hybrid applications including kind of maven plugins to use, deployment steps, etc., but also about the lifecycle of OSGi bundle and Java EE artifacts. Now, it's time for our second hybrid application which demonstrates an EJB as an OSGi service.

Set up
1. Download the latest nightly build of GlassFish v3, install and start glassfish:

java -jar glassfishv3/glassfish/modules/glassfish.jar

2. Start embedded JavaDB by running

glassfishv3/glassfish/bin/asadmin start-database

3. Download "OSGi web container" bundle from here and install it by copying it:

cp osgi-web-container-3.0-SNAPSHOT.jar glassfishv3/glassfish/domains/domain1/autodeploy-bundles/

Sample Application
You can download the complete sample from here. Unzip it. Let's look at the UML diagrams below. The first one is a package diagram showing dependencies, the second one shows the components of the system and the third one shows that they are all deployed in the same node.
uml.jpg
As you can see, we have three modules and the source code organization reflects that as well. Let's briefly go over the modules:
1. common
This is just an OSGi bundle. It exports sahoo.hybridapp.example2 package which contains a single interface called UserAuthService.

2. service
This is a web application bundle, i.e., a hybrid application containing both OSGi and Java EE artifact. It imports sahoo.hybridapp.example2 package. It has following components:
2a. UserAuthServiceEJB This is a Singleton EJB designated to be initialized at startup. It is annotated like this:

@Singleton
@Startup
public class UserAuthServiceEJB implements UserAuthService

Please refer to EJB 3.1 spec for more information on these annotations.
UserAuthServiceEJB has a static variable called

static volatile UserAuthService selfRef;

which is initialized by an ejb reference in the postConstruct() method of the EJB:

    
    @PostConstruct
    public void postConstruct() {
        selfRef = sessionContext.getBusinessObject(UserAuthService.class);
        System.out.println("UserAuthServiceEJB.postConstruct: " + selfRef);
    }

2b. Activator - This is an OSGi bundle activator which looks up a data source in JNDI, ceates a table there and then registers the EJB reference (selfRef) in OSGi service registry under the service interface sahoo.hybridapp.example2.UserAuthService. For simplicity, we have not used any service properties here.

3. client
This is just an OSGi bundle. It imports sahoo.hybridapp.example2 package. It has an activator which waits for UserAuthService to be available and then invokes it. Look carefully at the activator code and see how it uses ServiceTracker to be notified of service availability. When it sees the service, it invokes it. All this is accomplished in these few lines:

    private class UserAuthServiceTracker extends ServiceTracker {
        UserAuthServiceTracker() {
            super(bctx, UserAuthService.class.getName(), null);
        }

        @Override
        public Object addingService(ServiceReference reference)
        {
            UserAuthService service = (UserAuthService)context.getService(reference);
            service.register("f..", "b..");
            return service;
        }
        
    }

Build and Test
1. If you don't want to build, then the final artifacts are in target dir, else simply run

mvn clean install

in hybridapp2 directory.

2. To deploy, simply copy the artifacts like this (please note, because of a bug as described last time), while copying the .war file, give it a .jar extension as a work around.

cp common/target/hybridapp2-common.jar glassfish/domains/domain1/autodeploy-bundles/
cp client/target/hybridapp2-client.jar glassfish/domains/domain1/autodeploy-bundles/
cp service/target/hybridapp2-service.war glassfish/domains/domain1/autodeploy-bundles/hybridapp2-service.jar

Since deployment order is immaterial, you can copy them in any order.

Benefits of EJB as OSGi service
1. An OSGi service is able to take advantage of Java EE container services like declarative transaction, declarative security, resource pooling, etc.

2. Local client views of an EJB are accessible from other applications collocated in the same JVM. Please note, since Java EE can not assume a module management system is in place, it takes a safer route of isolated class space for application classes. This does not have to be the case when we are using hybrid applications. We can safely cross application boundaries and call local EJBs.

3. Better modularity of application: as shown here, the app has been broken into three independent deployment units. Once they are deployed, they can be managed (e.g., patched) separately.

4. Deployment order is a thing of past. OSGi takes care of class loading dependencies and then application can take advantage of facilities like Service Tracking to build very dynamic application. As shown in this example:

if client bundle comes up before service bundle, then it simply waits for the service to be available.

You can observe this by removing hybridapp2-service.jar from autodeploy-bundles/ and copy it back.I hope you find this example useful. Let us know what you want to hear. As always, your feedback is very welcome. Please visit The Aquarium to know the latest news about GlassFish. If you have questions about how to use this feature, please use our forum.

Thank you,
Sahoo.

Related Topics >>

Comments

That´s great. I like de idea

That´s great. I like de idea of combining OSGi with J2EE.
I wonder if I could access to an hybrid EJB from a non OSGi war application that is running in the same server.
As far as I understand the EJB from de example above is in OSGi context ... so I don´t know if this is possible.
I´ve been able to create an hybrid WAB and an Hybrid EJB but ...
My intention is to be able to work with OSGi and to use BlazeDS to develop Adobe Flex applications.
So I tried to convert the BlazeDS war file to a hybrid BlazeDS WAB, but I faced the problem that BlazeDS seems to not been supported.
It seems that OSGi run an embeded glassfish that does not support it.
The error is:
org.apache.catalina.LifecycleException: java.lang.IllegalArgumentException: javax.servlet.ServletException: com.sun.enterprise.container.common.spi.util.InjectionException: Error creating managed object for class flex.messaging.HttpFlexSession
at org.apache.catalina.core.StandardContext.start(StandardContext.java:5159)
at com.sun.enterprise.web.WebModule.start(WebModule.java:499)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:928)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:912)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:694)
at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1933)
at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1605)
at com.sun.enterprise.web.WebApplication.start(WebApplication.java:90)
at org.glassfish.internal.data.EngineRef.start(EngineRef.java:126)
at org.glassfish.internal.data.ModuleInfo.start(ModuleInfo.java:241)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:236)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:339)
at org.glassfish.kernel.embedded.EmbeddedDeployerImpl.deploy(EmbeddedDeployerImpl.java:214)

Perhaps, in the future BlazeDS will be supported in embeded mode ... but, for now, I was thinking if I have another option.
For example, to make an hybrid EJB and then access it from the non OSGi BlazeDS war application.
Is this posible? Do you think I should think on another options?
Thanks!

Thanks Sahoo, I was looking

Thanks Sahoo, I was looking for that combination of OSGi and EJB where I wanted to have each EJB providing a new service to be deployed at runtime and make it self available to a client EJB. When I ran into runtime redeployment limitations with the standard EAR/EJB-JAR, I thought OSGi would help. According to your example it seems that the EJB as OSGi service is possible only with Singleton where registration happens on static initialisation at the startup time. I wonder how same architecture would be possible with other types of session beans. BR, Mohamed

EJB as OSGi service

It's being worked on. See https://glassfish.dev.java.net/issues/show_bug.cgi?id=11374

Doesn't work :(

Hi, I tried this on installed Glassfish V3 (GlassFish v3 (build 74.2)) and this simple lookup doesn't work. I made only bundle activator and tried to lookup datasource and got weird exceptions below. Is it a bug or am I doing it wrong? Thanks in advance. SEVERE: RAR6035 : Resource adapter start failed : {0} javax.validation.ValidationException: Unable to find a default provider ...
SEVERE: RAR8061: failed to load resource-adapter-config or RA [ __ds_jdbc_ra ], com.sun.appserv.connectors.internal.api.ConnectorRuntimeException: Failed to start resource adapter : Unable to find a default provider
SEVERE: RAR8060: Unable to lookup pool [ DerbyPool ], javax.naming.NamingException: Lookup failed for '__SYSTEM/pools/DerbyPool' in SerialContext [Root exception is javax.naming.NameNotFoundException: pools]
SEVERE: RAR6017 : Failed to get connection pool object via JNDI lookup : DerbyPool
SEVERE: com.sun.appserv.connectors.internal.api.ConnectorRuntimeException: rardeployment.jndi_lookup_failed ...
Caused by: javax.naming.NamingException: Lookup failed for '__SYSTEM/pools/DerbyPool' in SerialContext [Root exception is javax.naming.NameNotFoundException: pools]
Caused by: javax.naming.NameNotFoundException: pools
SEVERE: javax.naming.NamingException: Lookup failed for 'jdbc/__default' in SerialContext [Root exception is javax.naming.NamingException: Unable to lookup resource : jdbc/__default [Root exception is com.sun.appserv.connectors.internal.api.ConnectorRuntimeException: rardeployment.jndi_lookup_failed]]
Caused by: javax.naming.NamingException: Unable to lookup resource : jdbc/__default [Root exception is com.sun.appserv.connectors.internal.api.ConnectorRuntimeException: rardeployment.jndi_lookup_failed]
Caused by: com.sun.appserv.connectors.internal.api.ConnectorRuntimeException: rardeployment.jndi_lookup_failed
Caused by: javax.naming.NamingException: Lookup failed for '__SYSTEM/pools/DerbyPool' in SerialContext [Root exception is javax.naming.NameNotFoundException: pools]
Caused by: javax.naming.NameNotFoundException: pools

You came across a bug

See https://glassfish.dev.java.net/issues/show_bug.cgi?id=11436

In future, please try to use our forum.

session context is always null?

Hi Sahoo, Thanks for the great post! In the above example, is the session context in the services module always null? Thanks, J

Why do you say session context is null?

Why do you say session context is null? Can you elaborate? Were it null, we would have got NullPointerException while trying to use it, won't we? Please provide more information.

Thanks,
Sahoo