|
|
|||||||||||||||||||||||||||||||||||||||||||||
Sahoo's Blog
Our second hybrid application - EJB as OSGi ServicePosted by ss141213 on June 16, 2009 at 01:02 AM | Permalink | Comments (0)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 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 2. service @Singleton Please refer to EJB 3.1 spec for more information on these annotations. static volatile UserAuthService selfRef; which is initialized by an ejb reference in the postConstruct() method of the EJB:
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
Build and Test mvn clean installin 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/ Since deployment order is immaterial, you can copy them in any order. Benefits of EJB as OSGi service 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. Developing Hybrid (OSGi + Java EE) applications in GlassFishPosted by ss141213 on June 14, 2009 at 01:02 AM | Permalink | Comments (0)(If you are in a hurry, then download the sample and jump to "build and test" section after doing the necessary set up.) In my last blog, I mentioned about adding a new module in GlassFish called "OSGi web container for GlassFish." I am glad to say that, it is fully functional now. I have been able to use JSPs, JSFs, Servlets (of course), annotations, resource injection, transactions, EJBs, etc. in a hybrid application (more on hybrid application below). If you noticed, I mentioned EJBs. Although I call it "OSGi web container," since GlassFish now supports "EJB inside war" as standardized by Java EE 6, the new container allows you to use both Web and EJB components in a hybrid application. What exactly is a hybrid application? I call an application that uses both Java EE & OSGi a hybrid application. Both the technologies have their strengths. While Java EE excels when it comes to security, transaction management, rich component model, persistence, resource pooling, messaging, etc., OSGi brings modularity, dynamism, life cycle management to the table. They make a very powerful combination. Since their combined use is a new development, to make things easier, I shall walk you through the steps of developing and deploying hybrid applications in GlassFish v3. Setting the stage: java -jar glassfishv3/glassfish/modules/glassfish.jar (You need Java SE 6 to run GlassFish v3) 2. Start embedded JavaDB by running glassfish/bin/asadmin start-database 3. Download "OSGi web container" bundle from here. Sample Application Download the complete sample from here and unzip it. Those who don't want to build, the final war file is inside hybridapp1/target folder of the zip file. Let's look at the relevant details: 1. pom.xml 2. Java EE artifacts 3. Activator.java - the OSGi bundle activator. Build and test That's it. If your server is running, you will see the OSGi bundle getting installed and started as part of which the web application gets deployed. If it is not running, start it for this to happen. You can manage the life cycle of the OSGi bundle by file system commands like cp, rm, touch, etc. See an earlier blog on this. Now that the application is deployed, you can point your browser to http://localhost:8080/hybridapp1 Follow the registration link and then login link. You can see the server.log to see that user name and password got stored in database. Now, let's delete hybridapp1.jar from autodeploy-bundles folder. As soon as you do that, server's output will show that the bundle got uninstalled and the application got undeployed as well. Now if you try to visit any of the aforementioned URLs, you will get a 404 error. Relationship between life cycle of OSGi bundle and Java EE Application The actual state transition of the bundle looks like this: The sequence of events is like this: Understanding bundle life cycle and deployment sequence I will use the former one as I prefer command line tools. telnet localhost 6666 I hope this is sufficient for you to get started. Now, let your imagination take over and let us know how you are able to take advantage of this hybrid approach. In my next article, I show how you can use an EJB as an OSGi service. OSGi enabled web applications inGlassFishPosted by ss141213 on June 04, 2009 at 03:29 PM | Permalink | Comments (0)Since the OSGi-fication of GlassFish started, the initial response was very encouraging, but we were often asked as to how we planned to expose the benefits of OSGi platform to end users in a more direct way. We are committed to making this possible as is evident from the following quote from our initial proposal: "If GlassFish can benefit from OSGi, why not applications deployed in GlassFish? Application developers would like to use sophisticated versioning, class loading, dependency management and component model of OSGi. There is a growing demand for servers that expose such facilities to application developers. So, we shall investigate the use of OSGi by applications." I am glad to say that we have made considerable progress in this area. I just now put back a very preliminary implementation of OSGi EEG RFC #66 in GlassFish workspace that allows web applications (war files) to be deployed as OSGi bundles and there by taking advantage of OSGi platform as well as Java EE platform. Web applications and OSGi is a subject which is being actively discussed in OSGi Enterprise Expert Group (EEG) as RFC #66. As I said, what I have put back is just the start. Basic servlet. JSP, JSF, JDBC, JNDI, etc. works. Injection should work, but I have not tried yet. I know for sure JPA does not yet work as JPA classloading requirements conflict with OSGi's. Work is in progress to resolve it - stay tuned. So, how do you use these features in GlassFish? There are basically two starting points: a) You have a plain vanilla war file. b) You have a war file that has OSGi metadata in it.
(telnet support in GlassFish is provided by use of remote shell as described here.) The above commands will make your web app available at localhost:8080/mybundle/. Now you can control the life cycle of the web app via the OSGi bundle. e.g., if you stop the bundle by issuing stop #bundle_id, the web app gets undeployed. To deploy it again, issue the start command. In the latter case, i.e., case #b above, you just have to add a specific meta-data called Web-ContextPath in the manifest.mf to mark the OSGi bundle as a Web Application Bundle, (WAB) in short. Once you have done that, you can either install and start by running the shell commands without using webbundle protocol or simply copy the bundle to glassfish/domains/domain1/autodeploy-bundles/ dir. How this directory works is already described in a previous blog. Although I want to write more now, it's pretty late here. SO, catch you soon with instructions to install the new feature in GlassFish with some concrete example. Thanks. Running GlassFish on other OSGi platformsPosted by ss141213 on May 30, 2009 at 12:05 PM | Permalink | Comments (0)Although GlassFish v3 Preview comes with Felix pre-installed, it's pretty easy to make it run on Equinox and other platforms. Given below are the simple steps... 1. Download Equinox or if you have it, use that. 2. cp org.eclipse.osgi_3.3.2.R33x_v20080105.jar $GlassFish_HOME/osgi/equinox/ 3. Start GlassFish, but while starting let it know that you want to run on Equinox, else by default it uses Felix. To do this, you have couple of choices: a) You can set an environment variable called GlassFish_Platform as Equinox. b) You can set a system property called GlassFish_Platform as Equinox. Why do we have these two options? The system property is handy when you are starting using "java -jar" command. The environment variable is useful when you are starting using the classic way, i.e., "asadmin start-domain." Putting them in practice: (I am using Bash shell in the following example)
2. In the example below, asadmin start-domain is used to start GlassFish, but you are able to specify the enviornment variable on the same command.
3. If you are used to "java -jar" style of starting GlassFish (a new thing in GlassFish v3), then do this:
Frequently Asked Questions: 1. What is the order of precedence? In our bootstrap code that decides which platform to use, System property takes precedence over environment. So, if you set GlassFish_Platform in both system property and in environment, system property wins. 2. What are the allowable values for GlassFish_Platform? The set of acceptable values are statically defined in an Enum like this: So, you can specify any one of them. The default value is Felix. 3. What platform does "Static" mean in the above Enum? Well, GlassFish can run without OSGi as well. Static refers to that mode. There appears to be some use case for this mode. 4. OK, I see Knopflerfish being mentioned as one of the platforms. How can I run on that? When we started our OSGi effort, we were using only R4 APIs and hence we could run on all three popular, open source OSGi platforms. Later on, we had to rely on some R4 version 4.1 APIs - to be precise, on "transient" start/stop of bundles supported via new API called Bundle.start(int), Bundle.stop(int). Knopflerfish still does not implement them. Last time, when I checked with them, they told that they will switch from R4 to R4.2 directly. So, latest GlassFish v3 (something like GlassFish 3.0-Preview) does not currently run on Knopflerfish. Having said that, GlassFish 3.0-Prelude can run on Knopflerfish. 5. Where do I find configuration file for each platform? Here is where you can locate the configuration files: 6. Must I have my OSGi framework jars copied to GlassFish installation directory? What if I am sharing an installation and don't have permission to change the installation? No, you don't have to copy the OSGi framework jars to glassfish/osgi directory. You can keep them on a separate location and refer to that using environment or system variables. e.g., you can do this: Of course, you can set those properties using environment variables as well if you don't want to set them every time. 7. While running on Equinox, I get a WARNING like this: It is coming because our management agent, which goes through modules dir to install all the modules, is trying to install a module called osgi-main.jar, but that module is already configured in config.ini to be autostarted. You can safely ignore the warning. 8. How do I add support for other OSGi platforms? Conclusion Use of Framework Extension Bundles in GlassFish V3Posted by ss141213 on May 29, 2009 at 08:49 AM | Permalink | Comments (0)When you run an application in a plain vanilla Java platform, your code can access publicly visible internal JDK classes. While I understand it is a bad thing, but I do understand that sometimes developers have genuine reasons to access those internal APIs. e.g., our security module in GlassFish has to use some of the JDK Security classes. When one moves those programs to an OSGi environment, the assumption that every public JDK class is always visible to applications goes for a toss. When we started with our OSGi effort in GlassFish V3, we immediately faced the problems. So, how does one manage the situation? There are basically two ways to manage it in OSGi, viz: a) Parent Delegation: b) system packages: Please consult the OSGi spec for accurate description of these features. The spec is very nicely written. The description above is not as clear as you will find in the spec, which is obvious. Parent Delegation is a necessary evil. It is there to primarily help avoid strong assumptions made by some JDK classes about class loading, but it is also helpful in solving class loading problems as explained in one of my earlier blogs. It breaks modularity, so it should be used at the last resort. So, we decided to use the second option. In the second option, there is also a challenge. How do we know the list of all such internal packages? The list is a union of internal packages needed by all the modules running in GlassFish. There lies the problem. The list of modules is not fixed. After all, GlassFish V3 has multiple profiles (or distributions), e.g., web profile, classic profile, etc. The problem is compounded by the fact that user can install new modules and they may have newer requirements about system packages. So, managing them via a single property does not scale. Fortunately, framework extension bundles come to the rescue. framework extension bundles Fragment-Host: system.bundle; extension:=framework There are restrictions about what headers it can use, but like any other fragment, it can use Export-Package header to export additional packages. All those additional packages eventually get exported via system bundle only. Now, imagine this: system bundle is already backed by parent class loader. It actually has access to all the classes loadable via parent class loader, but for modularity reasons, it does not export all of them. If you want some packages to be exported by system bundle, just come up a framework extension bundle which contains no actual class. It only contains some manifest headers like this:
Isn't this a powerful technique? This is actually one of the very few good use cases for fragment bundles. This allows us to decentralize the information which is so important in an extensible system like GlassFish V3. More over, system properties can't be controlled when a program is embedded in a host JVM. GlassFish use case LinkageError caused by org.omg.CORBA package in OSGi environmentPosted by ss141213 on May 27, 2009 at 02:17 AM | Permalink | Comments (0)Recently my colleague observed an unusual class loading error while experimenting in GlassFish V3. I really enjoyed analysing the issue and getting to the root of the problem. I will share my experience here. JDK has a portion of OMG CORBA APIs belonging to org.omg.CORBA and similar package names. The bad thing is org.omg.CORBA package is an extensible package in the sense that different OMG CORBA services contribute classes to this package. I guess this is because they share the same IDL namespace and hence IDL compiler generates the same package name for all of them. Given that JDK does not have all the OMG CORBA services, not all org.omg.CORBA classes are part of JDK. e.g., CORBA Object Service - Transaction is one example. It is not there in JDK, yet it is required in an Java EE environment, as Java Transaction Service depends on it. So, our CORBA engineer produced an OSGi bundle called glassfish-corba-omgapi which contained all the org.omg.CORBA apis needed by GlassFish v3. The system.bundle also exports org.omg.CORBA package. Both the bundles exported with same version, which in itself is a mistake. If you are following me so far, then you can see that org.omg.CORBA package is exported by two bundles with identical version: Our JTS engineer realized that her JTS module is always importing org.omg.CORBA from system.bundle (this is a correct behavior) and hence she is not able to locate some COSTransaction class. To work around it, she removed org.omg.CORBA from org.osgi.framework.system.packages list, as a result now only glassfish-corba-omgapi bundle exports org.omg.CORBA package. Although this made the COSTransaction classes available, it resulted in the following LinkageError:
Now the investigation begins.
Basically, it translates to something like this: org.omg.CORBA.ORB this.something = com.sun.corba.ee.spi.osgi.ORBFactory.create(properties); As you can see com.sun.corba.ee.spi.osgi.ORBFactory.create(Properties) returns com.sun.corba.ee.spi.orb.ORB, which definitely extends org.omg.CORBA.ORB for the code to compile. So, let's inspect the hierarchy of this class: (-> means extends and within bracket the jar that supplies the class is mentioned as well. Each jar has a separate class loader)
Note a *duplication* of class in the runtime: Since org.omg.CORBA is no longer exported by system.bundle, GlassFishORBManager, which is loaded from org-iiop.jar module, gets org.omg.CORBA.ORB.class from glassfish-corba-omgapi.jar. As a result, the simple assignment is now looking like this: org.omg.CORBA.ORB(glassfish-corba-omgapi.jar) = org.omg.CORBA.ORB (JDK's rt.jar) As you can see, they are two different types and hence the VerificationError. There are several ways to solve it. 2. If we remove all the org.omg CORBA related packages (including org.omg.CORBA_2_3) from system packages list and ensure that they are exported by glassfish-corba-omgapi bundle, then also every one will see one version of classes and the problem will be solved. There is an assumption here that no other JDK class other than the CORBA implementation has direct reference to these packages. This assumption may not be true. 3. If we can put glassfish-corba-omgapi.jar in one of the java.endorsed.dirs and add all the new packages to system.packages list, then also everyone see one consistent version of classes. Since we can't assume we are using jre/lib/endorsed, this has the disadvantage of requiring user to specify -Djava.endorsed.dirs in command line, something which does not fly with "java -jar glassfish.jar" style invocation. For now, I think we can start with option #2 and if we face any issues, we can go to #1. Now let's see why the error was so cryptic in an OSGi environment. After all, OSGi is supposed to give us more helpful errors. The problem is our system packages are exported without any "uses" clause. "uses" clause plays a vital role in package resolution and correct specification of uses attribute might have given us a better error stating the class space was not consistent. Having said that, I still don't understand why we didn't get a "loader constraint violation" when GlassFishORBManager was loaded. Is this because ORBFactory returns com.sun.corba.ee.spi.orb.ORB, where as GlassFishORBManager has a field of type org.omg.CORBA.ORB? Needs further investigation. Interested readers should look at the excellent classloading discussion by Liang and Bracha. Be careful while using EntityManager.getDelegate()Posted by ss141213 on May 25, 2009 at 02:01 AM | Permalink | Comments (2)Recently a GlassFish user, who is using Hibernate JPA provider, asked how they can access the underlying Hibernate Session object from the injected EntityManager object. My answer was to use: org.hibernate.Session session = ((org.hibernate.ejb.EntityManagerImpl) em.getDelegate()).getSession();. If it is that simple, why am I making an issue out of it? It is a highly non-portable API and you really have to write different code in different application servers even while using the same persistence provider. Well, read on to find out why... In enterprise platform, when you look up and EntityManager in JNDI or when your component is injected with an EntityManager (by using @PersistenceContext), you really don't get the actual EntityManagerImpl of the provider. What you typically get is a wrapper which acts a frontend to the underlying object. The reasons for having such a wrapper are manifold. e.g., the wrapper is designed as a Serializable object so that it can be bound in JNDI, where as the provider's implementation may not be. More importantly, it's the wrapper which implements the EE semantics like persistence context propagation. If you are interested in looking at how such a Wrapper looks like, take a look at this GlassFish Wrapper implementation. As you can see, in GlassFish, getDelegate() returns the underlying provider's EntityManager implementation. So, if you are using Hibernate in GlassFish, then getDelegate() returns org.hibernate.ejb.EntityManagerImpl As a result, returns Hibernate Session object in GlassFish. But, the above code would not work in JBoss. They suggest the following:
It is difficult to say which implementation is correct, when the spec, in the javadoc of getDelegate, calls out the non-portability of the API like this: Lack of clarity of the spec leads to pain for programmers. You think you have written to JPA spec and your code is portable as long as you are using Hibernate JPA provider, but it is not. It now varies from one application server to another. I would really love to know what WebLogic and WebSphere return for the above method, but that's a separate point. Actually, once a user filed the following bug in GlassFish: From a design pattern point of view, the wrapper should call underlying object's method. So, this mean, EntityManagerWrapper.getDelegate() should call delegate.getDelegate(). It is a more logical choice. I guess this is what happens in JBoss, but in GlassFish, we return the delegate itself. But, returning the delegate in getDelegate() (just like what GlassFish does) means user now have access to to a much richer set of APIs that what is available via javax.persistence.EntityManager. One such extra API could be to get the Session object. So, I am inclined to favour GlassFish's implementation. I really wish this is something that gets addressed in the upcoming JPA 2.0 spec. If it has already been addressed, even better. Please don't make the programmer suffer. They don't always have the time and resource to get to the underlying problem and they end up making value judgment about implementations. Using Felix Web Console in GlassFish v3Posted by ss141213 on May 05, 2009 at 04:25 AM | Permalink | Comments (2)In a previous blog, I had shown how one could use Apache Felix Remote Shell to connect to GlassFish and administer the underlying OSGi runtime. Since, GlassFish installs some 100 odd bundles, it is not very easy to explore them using the shell. There are some improvements planned for Felix shell to address this issues, but then there are a lot of people who are just comfortable with GUI as opposed to CLI. For them, we have an answer - use Apache Felix Web Console. One of the primary requirements to use Felix Web Console is an implementation of OSGi/HTTP Service. I have made available an initial implementation of the OSGi/HTTP service on top of GlassFish web container. So, we are all set to use Felix web console in GlassFish v3. Steps to install & use Web Console 1. Download GlassFish OSGi HTTP Service bundle from http://download.java.net/maven/glassfish/org/glassfish/web/osgi-http/3.0-SNAPSHOT/osgi-http-3.0-SNAPSHOT.jar. 2. Download Apache Felix Web Console bundle from here. 3. Copy these two jars to glassfish/domains/domain1/autodeploy-bundles/ dir. Now, the bundles are up & running. Don't worry about some messages like Failed to instantiate plugin org.apache.felix.webconsole.internal.misc.ConfigurationRender. Reason: java.lang.NoClassDefFoundError: org/osgi/service/prefs/BackingStoreException appearing in the log. 4. Point http://localhost:8080/osgi/system/console/bundles in your favorite browser. Use admin/admin as username/password combination. How does the web console look
Screenshot below shows details about a particular bundle. You can see wiring details here, i.e., which bundles are importing packages from this bundle. I find this information very useful.
You can find a lot more screenshots in Web Console homepage. Please wait for 5th may 2009 nightly build of GFv3 to be out before you try out, as I fixed a stopper bug in HTTP service. As usual, your feedback is always welcome. Happy GlassFishing. Using filesystem operations to manage OSGi bundles in GlassFishPosted by ss141213 on May 03, 2009 at 11:51 PM | Permalink | Comments (1)A few days back, Jerome blogged about how to deploy OSGi bundles in GlassFish using "asadmin deploy --type=osgi" command. In his blog, he also mentioned why you should not copy your bundles to glassfish/modules directory. In this blog, I will talk about a filesystem based management agent that I have integrated in GlassFish and how you can take advantage of the same. We have integrated Apache Felix File Install in GlassFish v3. It is a simple yet very powerful bundle. It even takes care of the dependencies among bundles. It can use "configuration admin service" to configure bundles by reading configuration data from properties file placed in the watched dir. Quoting from File Install homepage verbatim: It uses a directory in the file system to install and start a bundle when it is first placed there. It updates the bundle when you update the bundle file in the directory and, when the file is deleted, it will stop and uninstall the bundle. File Install can do the same for configuration files. In the default installation of GlassFish v3, we have configured FileInstall to watch a directory called ${domain_dir}/autodeploy-bundles. ${domain_dir} typically expands to glassfish/domains/domain1, but it really depends how you have configured GlassFish. This is very similar to autodeploy directory that exists in GlassFish for non-OSGi JavaEE applications. Basically, it works like this: You copy a bundle (a .jar file) to the watched dir (autodeploy-bundles) -> the bundles gets installed and then get started. To watch some other directory (let's say /tmp/bundles), create a properties file with following content and name it as org.apache.felix.fileinstall-something.cfg and copy it to autodeploy-bundles dir: # directory to watch You will immediately see fileinstall creating /tmp/bundles and dedicating a thread to watch it. If you want to explore this feature, I suggest you take a look at File Install homepage. This feature is not available in any promoted builds yet; you will find it in trunk nightly builds of GlassFish v3 after 5th May 2009 or in promotion #b47a onwards. |
June 2009
Search this blog:CategoriesCommunity: GlassfishCommunity: Java Enterprise Community: JDK J2EE J2SE Archives
June 2009 Recent EntriesOur second hybrid application - EJB as OSGi Service Developing Hybrid (OSGi + Java EE) applications in GlassFish OSGi enabled web applications inGlassFish | ||||||||||||||||||||||||||||||||||||||||||||
|
|