11 Replies Latest reply on Jul 21, 2003 1:00 AM by Bernd Zeitler

    ClassCastException with EJB calling EJB (different EARs)

    Bernd Zeitler Expert

      Hi,

      this question came up in several threads in this forum with slightly different circumstances, but wasn't answered for now (well, I couldn't find a satisfying answer).

      I want to deploy SessionBean1 in ear1, SessionBean2 in ear2. SB1 is client of SB2. Both ears must bring along all their resources needed, so the remote interface and the home interface of bean2 is deployed twice (in ear1 and ear2). Every ear has its own loader repository, defined in its jboss-app.xml for scoping reasons.

      When SB1 tries to access SB2, I get a ClassCastException while narrowing the home interface of SB2.

      How can I avoid this?

      1. I don't want to share ressources between the ears by deploying them in the "all-repository". And I don't want do deploy the SBs there.
      2. I want to call EJBs even if they are not deployed in the same ear. I want some work to be done by EJBs no matter how they are deployed and where they reside as far as I can do a JNDI lookup and have access to the home and remote interface deployed in this ear. I think it would work if ear1 and ear2 are deployed in different VMs.

      I think JBoss is not doing serialization between remote bean calls. But this must be done to resolve the problem above. At least for beans deployed in the manner described above and similar deployments.

      I hope someone of the JBoss guys will comment this thread and answer the questions (Juha?).

      Greetings,
      Frito

        • 1. Re: ClassCastException with EJB calling EJB (different EARs)
          Bernd Zeitler Expert

          BTW, I am using JBoss 3.2.0 .

          Reading the FAQ, I found someone who made some tests on this topic. It was suggested to put all the remote interfaces and other shared ressources in a .jar located in the lib directory (well, I think you can get the same result by deploying these ressources on top level).
          But this is not really what I want nor what I expected. For me, this is a bug in JBoss. When two EJBs are loaded by different classloaders, the bean to bean call must be a real remote call. This must not raise a ClassCastException since the compatibility of the "remote" classes should be checked by java serialization, right?

          Greetings,
          Frito

          • 2. Re: ClassCastException with EJB calling EJB (different EARs)
            Paul Newbie

            I found a way to get this to work by forcing access to your remote ejb's to be invoked by value.

            To do this:
            For each ejb you want to reference from an external ear add an invoker-bindings tag like this in the jboss.xml:


            <ejb-name>WebTrafficLogger</ejb-name>
            <jndi-name>aaWebTrafficLoggerEJB</jndi-name>
            <invoker-bindings>

            <invoker-proxy-binding-name>by-value-stateless-rmi-invoker</invoker-proxy-binding-name>

            </invoker-bindings>


            Then, in the conf/standardjboss.xml add this invoker-proxy-binding tag to the existing invoker-proxy-binding tags:

            <invoker-proxy-binding>
            by-value-stateless-rmi-invoker
            <invoker-mbean>jboss:service=invoker,type=jrmp</invoker-mbean>
            <proxy-factory>org.jboss.proxy.ejb.ProxyFactory</proxy-factory>
            <proxy-factory-config>
            <client-interceptors>

            org.jboss.proxy.ejb.HomeInterceptor
            org.jboss.proxy.SecurityInterceptor
            org.jboss.proxy.TransactionInterceptor
            org.jboss.invocation.ByValueInvokerInterceptor


            org.jboss.proxy.ejb.StatelessSessionInterceptor
            org.jboss.proxy.SecurityInterceptor
            org.jboss.proxy.TransactionInterceptor
            org.jboss.invocation.ByValueInvokerInterceptor

            </client-interceptors>
            </proxy-factory-config>
            </invoker-proxy-binding>

            Finally, to get it to work I had to add -Djava.naming.provider.url=localhost:1099 to the server startup line.

            Because each application I deploy can have different versions of classes I am using the local loader-repository for each ear. I am packaging the externally referenced ejb's remote interfaces with the referencing ear. No need for any ugly classpath changes.

            Hope this helps,
            Paul.

            • 3. Re: ClassCastException with EJB calling EJB (different EARs)
              Bernd Zeitler Expert

              Hi Paul,

              thanks for your answer. I tried this at once an it worked for me... with some constraints.

              On JBoss 3.2 (even 3.2.2beta):
              If my bean needs a transaction (e.g. trans-attribute set to Required), I can see this:

              [pre]
              java.rmi.MarshalException: error marshalling arguments; nested exception is:
              java.io.NotSerializableException: org.jboss.tm.TransactionImpl
              at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:129)
              at org.jboss.invocation.jrmp.server.JRMPInvoker_Stub.invoke(Unknown Source)
              at org.jboss.invocation.jrmp.interfaces.JRMPInvokerProxy.invoke(JRMPInvokerProxy.java:135)
              at org.jboss.invocation.ByValueInvokerInterceptor.invoke(ByValueInvokerInterceptor.java:62)
              at org.jboss.proxy.TransactionInterceptor.invoke(TransactionInterceptor.java:46)
              at org.jboss.proxy.SecurityInterceptor.invoke(SecurityInterceptor.java:45)
              at org.jboss.proxy.ejb.HomeInterceptor.invoke(HomeInterceptor.java:173)
              at org.jboss.proxy.ClientContainer.invoke(ClientContainer.java:85)
              at $Proxy56.create(Unknown Source)
              at test.cltest.bean1.Bean1.doIt(Bean1.java:81)
              at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
              at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
              at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
              at java.lang.reflect.Method.invoke(Method.java:324)
              at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:629)
              at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:186)
              at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:72)
              at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:84)
              at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:243)
              at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:104)
              at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:117)
              at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:191)
              at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:122)
              at org.jboss.ejb.StatelessSessionContainer.internalInvoke(StatelessSessionContainer.java:322)
              at org.jboss.ejb.Container.invoke(Container.java:673)
              at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
              [/pre]

              Is this a hack you were providing or is this the real JBoss feature? If it is the implemented feature I will report this as bug.

              Thanks again for your help,

              Frito

              • 4. Re: ClassCastException with EJB calling EJB (different EARs)
                Bernd Zeitler Expert

                I reported this as bug and Scott Stark fixed it ;-)

                Greetings,
                Frito

                • 5. Re: ClassCastException with EJB calling EJB (different EARs)
                  Juha Lindfors Master

                  Hey guys,

                  (just saw this)

                  This is worth of a FAQ entry.

                  • 6. Some more claryfication?
                    Bernd Zeitler Expert

                    For sure, Juha.
                    But help me out of some more questions coming up with this problem to clarify the issue and post a complete FAQ afterwards.

                    JBoss seems to optimize each remote call without really marshalling. Does this mean, JBoss is doing these calls by reference (as default)?
                    I thought this must be the reason why I get the ClassCastExceptions using bean-to-bean-calls with beans in different ears and different repositories while narrowing the home interface (which exists in both ears).
                    But then, I don't understand what Scott wrote, commenting my bug report: "Just because a call
                    spans loaders does not mean it cannot be done by reference."

                    Optimizing each remote call is a bug IMHO. Deploying these ears in different JBoss instances will work, while deploying both of them in one instance doesn't? This is not really the behaviour I expected.

                    Greetings,
                    Frito

                    • 8. Re: Some more claryfication?
                      Juha Lindfors Master

                      > JBoss seems to optimize each remote call without
                      > really marshalling. Does this mean, JBoss is doing
                      > these calls by reference (as default)?

                      yes.

                      > Optimizing each remote call is a bug IMHO. Deploying
                      > these ears in different JBoss instances will work,
                      > while deploying both of them in one instance doesn't?
                      > This is not really the behaviour I expected.

                      I guess a solution might be to implement proxies that not only check if the invocation is local but check if it's going into the same loader repository domain as well.

                      • 9. Re: Some more claryfication?
                        Tom Döhler Newbie

                        Hi,

                        are there any new issues on that?? We face the same problem with scoped classloading. Has anybody implemented a proxy that also checks if invokations target the same loader repository domain ?

                        • 10. Re: Some more claryfication?
                          chris humphrey Newbie

                          So, if I want to talk to another EJB deployed from a different ear file (not through the local interface but using the remote interface), I have to add all of this into my deployment? It seems to me that this should just work (its a remote interface after all!)

                          There was a posting from someone who wanted to fix this problem so it would be optimized when it could, and serialize the data when crossing classloaders when needed. That seems to be the correct way to fix this.

                          So, is there a posibility that this bug could be fixed or does all of our ejb deployements have to change? The project I are working on has around 20 or 25 ejb's deployed in different ear files (so we can replace a single ejb when we want to upgrade it) using wls. We are trying to move to jboss, but its meaning we basically have to change ALOT of things to get this move done...

                          • 11. Re: Some more claryfication?
                            Bernd Zeitler Expert

                            Well, I don't think this is a real bug. It is an optimisation and instead of using the slow ByValueInvoker as default (like other app servers do), JBoss is unsing standard invoker which is calling by reference. Well, this leads to ClassCastExceptions when scoping the same resources with different repositories or when hot redeploying resources where other objects are still holding references on.

                            This is a quotation of Scott Stark regarding your question:
                            "The invokers should not have to deal with class loading knowledge as this ties them to features that are outside of the scope of handling the transport."

                            But there is a way out of this: use the ByValueInvoker with remote interfaces (all the time). Use local interfaces if you want to optimize calls.
                            You can achieve the same by configuring your beans with both invoker-proxy-bindings, using different JNDI names. If the beans are only using the comp/env JNDI scope, you are able to configure with your deployment descriptors which invoker should be used.

                            Greetings,
                            Frito

                            (I would love an invoker doing all this magically ;-)