5 Replies Latest reply on Mar 15, 2007 7:34 AM by azhurakousky

    Class loader probelm

    xaleyba

      Hi

      I've a simple service that I use to start a JMS ActiveMQ broker configured in this way:

      
      <mbean code="com.xx.activemq.mbean.service.ActiveMQNetwork"
       name="jms.ActiveMQ:service=ActiveMQNetwork">
       <attribute name="PropertiesResource">remote-jndi.properties</attribute>
       <attribute name="MasterPropertiesResource">masterbroker.properties</attribute>
       <attribute name="SlavePropertiesResource">slavebroker.properties</attribute>
       <depends>jboss:service=Naming</depends>
       <depends>user:service=QuartzService,name=QuartzService</depends>
       </mbean>
      
       <!-- Proxy factory for MyService that will call target method on the target service -->
       <mbean code="org.jboss.invocation.jrmp.server.JRMPProxyFactory"
       name="jboss.jmx:type=adaptor,name=MyActiveMQNetworkInvokeTarget,protocol=jrmp,service=proxyFactory">
       <!-- Use the standard JRMPInvoker from conf/jboss-service.xxml -->
       <depends optional-attribute-name="InvokerName">jboss:service=invoker,type=jrmp</depends>
       <!-- The target MBean -->
       <depends optional-attribute-name="TargetName">jms.ActiveMQ:service=ActiveMQNetwork</depends>
       <!-- Where to bind the proxy factory -->
       <attribute name="JndiName">MyActiveMQNetworkInvokeTarget</attribute>
       <!-- Invoke target method instead of invoke(Invocation mi) -->
       <attribute name="InvokeTargetMethod">true</attribute>
       <!-- Comma-separated list of exported interfaces -->
       <attribute name="ExportedInterfaces">com.bs.activemq.mbean.service.ActiveMQNetworkMBean</attribute>
       <!-- client-side interceptors -->
       <attribute name="ClientInterceptors">
       <interceptors>
       <interceptor>org.jboss.proxy.ClientMethodInterceptor</interceptor>
       <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
       <interceptor>org.jboss.jmx.connector.invoker.client.InvokerAdaptorClientInterceptor</interceptor>
       <interceptor>org.jboss.invocation.InvokerInterceptor</interceptor>
       </interceptors>
       </attribute>
       </mbean>
      
      


      My application works very well till yesterday when I installed a new webapp that use Spring. As my JBoss service use Spring too, it started to generate problems.

      So, I need to isolate class loading in my service and I did it adding the following to jboss-service.xml file:

      
      <server>
       <loader-repository>
       com.notifications.broker:loader=activemq-broker-service.sar
       <loader-repository-config>java2ParentDelegation=false</loader-repository-config>
       </loader-repository>
      
      


      It worked well to solve my Spring problem but now I've a new problem. I got the error:

      
      09:13:32,429 INFO [NamingService] Started jndi bootstrap jnpPort=1099, rmiPort=1098, backlog=50, bindAddress=/0.0.0.0, Client SocketFactory=null, Server SocketFactory=org.jboss.net.sockets.DefaultSocketFactory@ad093076
      09:13:35,895 INFO [ServiceConfigurator] Problem configuring service jboss.jmx:type=adaptor,name=MyActiveMQNetworkInvokeTarget,protocol=jrmp,service=proxyFactory
      java.lang.IllegalArgumentException: Failed to find class: com.xx.activemq.mbean.service.ActiveMQNetworkMBean
       at org.jboss.util.propertyeditor.ClassArrayEditor.setAsText(ClassArrayEditor.java:38)
       at org.jboss.system.ServiceConfigurator.parseTextSerialData(ServiceConfigurator.java:541)
       at org.jboss.system.ServiceConfigurator.configure(ServiceConfigurator.java:311)
       at org.jboss.system.ServiceConfigurator.internalInstall(ServiceConfigurator.java:442)
       at org.jboss.system.ServiceConfigurator.install(ServiceConfigurator.java:153)
       at org.jboss.system.ServiceController.install(ServiceController.java:215)
       at jrockit.reflect.VirtualNativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
       at java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;I)Ljava.lang.Object;(Unknown Source)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:141)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:80)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:72)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:245)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:644)
       at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:176)
       at $Proxy4.install(Lorg.w3c.dom.Element;Ljavax.management.ObjectName;)Ljava.util.List;(Unknown Source)
       at org.jboss.deployment.SARDeployer.create(SARDeployer.java:232)
       at org.jboss.deployment.MainDeployer.create(MainDeployer.java:935)
       at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:789)
       at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:753)
       at jrockit.reflect.VirtualNativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
       at java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;I)Ljava.lang.Object;(Unknown Source)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:141)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:80)
       at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:118)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:74)
       at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:127)
      
      
      ----
      
      --- MBeans waiting for other MBeans ---
      ObjectName: jboss.jmx:type=adaptor,name=MyActiveMQNetworkInvokeTarget,protocol=jrmp,service=proxyFactory
       State: FAILED
       Reason: java.lang.IllegalArgumentException: Failed to find class: com.xx.activemq.mbean.service.ActiveMQNetworkMBean
       I Depend On:
       jboss:service=invoker,type=jrmp
       jms.ActiveMQ:service=ActiveMQNetwork
      
      --- MBEANS THAT ARE THE ROOT CAUSE OF THE PROBLEM ---
      ObjectName: jboss.jmx:type=adaptor,name=MyActiveMQNetworkInvokeTarget,protocol=jrmp,service=proxyFactory
       State: FAILED
       Reason: java.lang.IllegalArgumentException: Failed to find class: com.xx.activemq.mbean.service.ActiveMQNetworkMBean
       I Depend On:
       jboss:service=invoker,type=jrmp
       jms.ActiveMQ:service=ActiveMQNetwork
      
      



      I understand that proxyFactory could not load my service classes because class loaders isolation but, how could I solve it ?


      Thanks in advance

      C



        • 1. Re: Class loader probelm

          Can you please clarify how your Spring libraries are deployed:
          A) For your service
          B) For your web app

          Do Service and Webapp use the same version of Spring?

          Also, when you say web app do you mean WAR or EAR?

          Regards

          • 2. Re: Class loader probelm
            xaleyba

             

            "azhurakousky" wrote:
            Can you please clarify how your Spring libraries are deployed:
            A) For your service
            B) For your web app

            Do Service and Webapp use the same version of Spring?

            Also, when you say web app do you mean WAR or EAR?

            Regards


            Thanks for your reply.

            About your questions:

            A) Spring jars are in a lib directory inside my .sar

            B) I've a .war and spring jars inside WEB-INF\lib

            Both use the same spring version. (and I dont want to copy spring to my JBoss server instance lib directory.

            Thanks in advance

            C



            • 3. Re: Class loader probelm

              If you are using the same Spring versions, then your runtime of bothe WAR and SAR should use classes loaded by the same class loader, to avoid problems. There are several things you can do.
              1) The obvious one is to do what you don't want to do (why?) and that is to copy Spring JARs in the lib directory of JBoss. This way WAR and SAR will be using classes loaded by the same class loader.
              2) Since you don't want to copy to lib dir, and if I understand correctly your SAR and WAR have some type of reliance on one another, you can encapsulate your WAR inside of SAR.
              3) You can also enable JBoss Class Loading model for the WAR. By default it is desabled and that is why you are having problems whenever you are dealing with the same classes (WAR/SAR). You probably getting ClassCast/Linkage and other errors simply becouse those classes are loaded by different class loaders. To do that:
              a) Remove your loader isolation for the SAR
              b) Go to JBOSS_HOME/server/<your_configuration>/deploy/jbossweb-tomcat55.sar\META-INF\jboss-service.xml and change the following attribute to "true"

              <attribute name="UseJBossWebLoader">true</attribute>
              


              Let me know

              • 4. Re: Class loader probelm
                xaleyba

                 

                "azhurakousky" wrote:
                If you are using the same Spring versions, then your runtime of bothe WAR and SAR should use classes loaded by the same class loader, to avoid problems. There are several things you can do.
                1) The obvious one is to do what you don't want to do (why?) and that is to copy Spring JARs in the lib directory of JBoss. This way WAR and SAR will be using classes loaded by the same class loader.
                2) Since you don't want to copy to lib dir, and if I understand correctly your SAR and WAR have some type of reliance on one another, you can encapsulate your WAR inside of SAR.
                3) You can also enable JBoss Class Loading model for the WAR. By default it is desabled and that is why you are having problems whenever you are dealing with the same classes (WAR/SAR). You probably getting ClassCast/Linkage and other errors simply becouse those classes are loaded by different class loaders. To do that:
                a) Remove your loader isolation for the SAR
                b) Go to JBOSS_HOME/server/<your_configuration>/deploy/jbossweb-tomcat55.sar\META-INF\jboss-service.xml and change the following attribute to "true"
                <attribute name="UseJBossWebLoader">true</attribute>
                


                Let me know


                Thanks for your reply.

                I don't want to have my spring jars in the main jboss server instance lib directory because there are many other applications (made by other people) and I found this mix terrible. Anybody could install another app with another spring version that can generate problems to my app or viceversa.

                I found more clean to have my app´s isolated with their dependencies (except for those jar that come with JBoss by defualt.

                I can't use option 2 because tomcat service is used by other apps´.

                I'll try option 3 but I guess it will problematic too because same reasons that explain above.


                Thanks

                C





                • 5. Re: Class loader probelm

                  Try to realize, ot's not a JBoss problem. It is SUN problem that they allowed (after java 1.1) for same type classes not be be type safe if they are loaded by different clas loaders. Think about it; why should you be getting ClassCast exception on two classes with identical byte code?, but you will if class loaders are different.
                  JBoss Class Loading architecture attempting to override this rule where com.foo.Foo=com.foo.Foo if they are the same version by making sure that the class is loaded only once by a single class loader and is shared by many applications.

                  If you want to run appliations that are using different versions of the same packages, isolation could give you a way to do that, but you might also think about deploying such applications in different configurations of JBoss.
                  Just copy "default" or "all" rrename it and there you have another instance that can host anoher version of Foo
                  Regards