3 Replies Latest reply on Dec 12, 2003 10:52 PM by juha

    Packaging/deployment issues: ejb's accessed across ears

    sblaes

      I am developing two applications that I wish to be hot deployable independently. By independently, I am cool with 'touching' both each time I deploy, to force a redeploy, but I do not want to have to repackage the other ear because I'm redeploying the other one.

      Further, I have written a loginmodule that uses EJB's to access a back-end database. I currently have the loginmodules and it's associated ejbs packaged as a third .ear file.

      Since I have essentially three applications, each of which uses other applications' ejbs externally, how can I best deploy these so that all classpath issues are taken into account. I've tried deploying them as three ear files. Initially, this caused problems with Struts (which is embedded within each ear file.) So, I attempted setting up the hierarchical classloader. After that, I had problems with classcastexceptions on the interfaces. In all my trials, I have had continuing problems with hot deployment. When I did package it such that the apps would work together on startup, as soon as I tried to redeploy either of the ears, everything would explode.

      All in all, if anybody out there has done this, and had maintained the ability to hot-deploy, could you please detail how this was done. I've trolled around these forums for the whole week, and tried all sorts of combinations that were mentioned, but none seem to work 100%. Have I gone off the deep end by building this such that I am calling ejb's remotely from other applications? Should I just fall back and use soap to call ejb's across applications?

        • 1. Re: Packaging/deployment issues: ejb's accessed across ears

          Is there a reason you've got duplicate classes of Struts across all these EAR files?

          Normally deploying everything into a single default loader repository works ok. The web classloader is a bit of an exception though.

          To get around that you could either

          deploy struts just once
          Try JBoss 3.2.3 which has better web classloader integration to unified loader repository


          As for hot-deploying packages independently, you need to make sure you're not holding on any existing class references to the package you're redeploying. Otherwise you'll get ClassCastExceptions. One workaround to this is to package all interface classes separately into a JAR which should be stable (you redeploy the implementation, not the interface types).

          HTH

          • 2. Re: Packaging/deployment issues: ejb's accessed across ears
            sblaes

            First off, thank you so much for your reply.

            I want to deploy struts with my application (inside of the war file which is in my ear file) so that when the next uber-cool struts (or whatever java library) release comes out, I can develop a new application using the new version, but I don't have to go back and test all of my old code against the new library, since it will continue using the old version of struts. If I deployed struts once, by putting it in server/default/lib or a common .jar file in the deployment directory, then I would be less flexible in moving to new libraries when they I develop new apps. Prior to deployment, I would have to perform extensive testing to ensure they didn't break any existing apps. A good example is a prior version upgrade of xerces, which changed the way they dealt with the root xml element. It broke almost every application we'd developed at a company I used to work for, dozens of them. They were actually putting xerces on the classpath of the command line, something I'd argued against vehemently, and it came back to bite them when they did it their way. I guess that I got my glory after all! :)

            So, long story short, I'm not really willing to deploy struts just once, because I want my webapps to be independent of one another as much as possible when it comes to third party libraries.

            However, I differ when it comes to sharing internal functionality. I like your solution of deploying interfaces seperately, and in fact have been attempting to go down that path already. I've been having trouble, however, getting it to deploy. I'll keep hacking down that path. If you could give me a bit more explicit direction on how you would do this, or have done it, I'd be massively appreciative.

            I'll also give 3.2.3 a shot this weekend. I've considered using soap for inter-application communication, though I fear this will require taking a huge performance hit.

            The problem I ran into with ClassCastExceptions was due to the fact that I was using the hierachical classloader on both .ears. I had to deploy the interfaces to my ejb's within both ears to make the deployer happy (otherwise, I got ClassNotFound exceptions.) The problem with that was that I could not access the ejb's from a seperate application, because the interfaces were loaded under different classloader contexts. I saw some postings that recommended switching to pass-by-value semantics for the interfaces, which may solve my problems, but I don't know where to set this parameter. Is there something I may have been screwing up here?

            • 3. Re: Packaging/deployment issues: ejb's accessed across ears

               

              "sblaes" wrote:

              The problem I ran into with ClassCastExceptions was due to the fact that I was using the hierachical classloader on both .ears. I had to deploy the interfaces to my ejb's within both ears to make the deployer happy (otherwise, I got ClassNotFound exceptions.) The problem with that was that I could not access the ejb's from a seperate application, because the interfaces were loaded under different classloader contexts. I saw some postings that recommended switching to pass-by-value semantics for the interfaces, which may solve my problems, but I don't know where to set this parameter. Is there something I may have been screwing up here?


              Isolating the applications (classloaders) means you're going to have to serialize any invocations going across the contexts (pass-by-value). By default JBoss is attempting to optimize this communication by passing a reference within the VM but since you now have two separate definitions of classes this won't work.

              You can do this by configuring a ByValueInvokerInterceptor into the EJB proxies. You probably want to create your own <invoker-proxy-binding> and reference this binding from your jboss.xml. Inside the proxy binding you can configure the client proxy interceptor stack. Just add the ByValueInterceptor as last one in the stack (replace the existing InvokerInterceptor). You can copy paste the default invoker configuration from standardjboss.xml as a template.

              The performance implication of this is that the invocations going across EAR modules are going to be an order of magnitude slower than reference passing. This is the same problem you're going to have with SOAP (+ the additional XML parsing).

              "sblaes" wrote:

              However, I differ when it comes to sharing internal functionality. I like your solution of deploying interfaces seperately, and in fact have been attempting to go down that path already. I've been having trouble, however, getting it to deploy. I'll keep hacking down that path. If you could give me a bit more explicit direction on how you would do this, or have done it, I'd be massively appreciative.


              This basically means collecting the EJB interface types into a separate JAR. This includes all EJB remote and home interfaces, all return value types, all argument value types and exception types.

              Deploy this JAR into your system before the apps that need the types. The default repository will do. Order the hierarchical repository to load to load from parent first in case you deploy duplicates of these types as part of your EAR's repository (I don't remember the default order of hierarchical repository, I think it's child before parent). Or just don't deploy the interface types as part of your EAR (they'll find them from the default repository JAR).

              This way, assuming your EJB interfaces don't change, your EAR1 using EAR2 does not have direct type dependencies (since inside EAR2 is only implementations) but EAR1 has a type dependency to JAR that actually contains the types you use (and cache) in EAR1 -- this you rarely redeploy as the component interface rarely changes.

              This should avoid ClassCastExceptions that occur after redeployment in case one component is still holding on to class type definition (as we have no way of relinking at runtime the old type using old classloader to the new type using new classloader).