4 Replies Latest reply on Sep 3, 2009 9:30 PM by oren

    How to add spring javaagent to the fuse jsvm?

    oren

      Hello all,

      How do I add the spring-agent.jar to my FUSE ESB 4.1.0.2 JVM, so that bundles can use load-time weaving?

       

      My Cygwin start up shell looks like that:

      -


      #!/bin/bash

      ...

      1. Debug mode. Hook in an eclipse debugger on port 5005 when the following variable is set.

      export SERVICEMIX_DEBUG=true

       

      1. Enable load-time weaving and other memory options in the bus

      export JAVA_OPTS="$JAVA_OPTS -javaagent:/path/to/my/spring-agent.jar"

      echo $JAVA_OPTS

       

      bin/servicemix.bat $1

      -


       

      Upon running the script, I get

       

      $ sm

      -XX:MaxPermSize=256m -Xms256m -Xmx1000m -Dprof=win -DdownloadSources=true -javaa

      gent:c:\further\tools\lib\spring-agent.jar

      servicemix.bat: Enabling Java debug options: -Xdebug -Xnoagent -Djava.compiler=N

      ONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005

      Listening for transport dt_socket at address: 5005

       

      ... which looks fine. However, when I start a bundle that uses <context:load-time-weaver/> in its spring context, I see the error message

       

      smx@root:osgi> Exception in thread "SpringOsgiExtenderThread-67" org.springframe

      work.beans.factory.BeanCreationException: Error creating bean with name 'loadTim

      eWeaver': Initialization of bean failed; nested exception is java.lang.IllegalSt

      ateException: ClassLoader [org.springframework.osgi.util.BundleDelegatingClassLo

      ader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify

      a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent:

      -javaagent:spring-agent.jar

              at org.springframework.beans.factory.support.AbstractAutowireCapableBean

      Factory.doCreateBean(AbstractAutowireCapableBeanFactory.java:480)

              at org.springframework.beans.factory.support.AbstractAutowireCapableBean

      Factory$1.run(AbstractAutowireCapableBeanFactory.java:409)

              at java.security.AccessController.doPrivileged(Native Method)

              at org.springframework.beans.factory.support.AbstractAutowireCapableBean

      Factory.createBean(AbstractAutowireCapableBeanFactory.java:380)

              at org.springframework.beans.factory.support.AbstractBeanFactory$1.getOb

      ject(AbstractBeanFactory.java:264)

              at org.springframework.beans.factory.support.DefaultSingletonBeanRegistr

      y.getSingleton(DefaultSingletonBeanRegistry.java:222)

              at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBe

      an(AbstractBeanFactory.java:261)

              at org.springframework.beans.factory.support.AbstractBeanFactory.getBean

      (AbstractBeanFactory.java:185)

              at org.springframework.beans.factory.support.AbstractBeanFactory.getBean

      (AbstractBeanFactory.java:164)

              at org.springframework.beans.factory.support.DefaultListableBeanFactory.

      preInstantiateSingletons(DefaultListableBeanFactory.java:429)

              at org.springframework.context.support.AbstractApplicationContext.finish

      BeanFactoryInitialization(AbstractApplicationContext.java:728)

              at org.springframework.osgi.context.support.AbstractDelegatedExecutionAp

      plicationContext.access$1600(AbstractDelegatedExecutionApplicationContext.java:6

      8)

              at org.springframework.osgi.context.support.AbstractDelegatedExecutionAp

      plicationContext$4.run(AbstractDelegatedExecutionApplicationContext.java:343)

              at org.springframework.osgi.util.internal.PrivilegedUtils.executeWithCus

      tomTCCL(PrivilegedUtils.java:85)

              at org.springframework.osgi.context.support.AbstractDelegatedExecutionAp

      plicationContext.completeRefresh(AbstractDelegatedExecutionApplicationContext.ja

      va:308)

              at org.springframework.osgi.extender.internal.dependencies.startup.Depen

      dencyWaiterApplicationContextExecutor$CompleteRefreshTask.run(DependencyWaiterAp

      plicationContextExecutor.java:138)

              at java.lang.Thread.run(Thread.java:619)

      Caused by: java.lang.IllegalStateException: ClassLoader [org.springframework.osg

      i.util.BundleDelegatingClassLoader] does NOT provide an 'addTransformer(ClassFil

      eTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtua

      l machine with Spring's agent: -javaagent:spring-agent.jar

              at org.springframework.context.weaving.DefaultContextLoadTimeWeaver.setB

      eanClassLoader(DefaultContextLoadTimeWeaver.java:82)

              at org.springframework.beans.factory.support.AbstractAutowireCapableBean

      Factory.initializeBean(AbstractAutowireCapableBeanFactory.java:1322)

              at org.springframework.beans.factory.support.AbstractAutowireCapableBean

      Factory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)

              ... 16 more

       

      which indicates that spring-agent is not found.

        • 1. Re: How to add spring javaagent to the fuse jsvm?
          joe.luo

          I guess you did not deploy/run the spring-javaagent.jar as a bundle into the ESB container. Am I correct?

           

          I am not familar with the spring-javaagent.jar. But from the stack trace, it looks like that classes from the spring-javaagent.jar are not accessible by other bundles but are necessary for creating the bean called "loadTimeWeaver".

           

          One workaround could be put the jar into the kernal BootClasspath so the classes from the jar will be visiable to all bundles in the container. In order to do that, you will need to modify "etc/config.properties" and find the line:

           

          org.osgi.framework.bootdelegation=sun.\*,com.sun.management\*

           

          and append your package as comma seperated list onto the "org.osgi.framework.bootdelegation" property and restart the servicemix to see if it works for you.

          • 2. Re: How to add spring javaagent to the fuse jsvm?
            oren

            Thanks so much for your reply. However, I think that spring-agent.jar is not just another library that can be bundled up and exposed to all bundles. As explained in the Spring AOP manual, one needs to add it as an instrumentation agent (-javaagent option) to the JVM:

             

            http://static.springsource.org/spring/docs/2.5.x/reference/aop.html#aop-using-aspectj

             

            "The introduction to this section did say that one could switch on LTW selectively on a per-ClassLoader basis with Spring, and this is true. However, just for this example, we are going to use a Java agent (supplied with Spring) to switch on the LTW. This is the command line we will use to run the above Main class:

             

            java -javaagent:C:/projects/foo/lib/global/spring-agent.jar foo.Main

             

            The '-javaagent' is a Java 5+ flag for specifying and enabling agents to instrument programs running on the JVM. The Spring Framework ships with such an agent, the InstrumentationSavingAgent, which is packaged in the spring-agent.jar that was supplied as the value of the -javaagent argument in the above example."

             

            See sections 6.8.4, 6.8.4.1 for more details. Although in some environments the javaagent option is not needed, OSGi is not mentioned as one of them. The question is how to add a javaagent option to the ESB's JVM, and how to make sure that it is visible to all bundles. Would that automatically happen because they are on the same JVM, or are separate JVMs started for bundles? In which case, your comment of exposing the package to all bundles might help. But still, the first step is to introduce the javaagent.

             

            Any ideas how to do that?

             

            Thanks so much in advance.

            • 3. Re: How to add spring javaagent to the fuse jsvm?
              oren

              P.S. Another link that explains instrumentation agents:

              http://java.sun.com/j2se/1.5.0/docs/api/java/lang/instrument/package-summary.html

              • 4. Re: How to add spring javaagent to the fuse jsvm?
                oren

                Because spring-agent does not seem to integrate well with FUSE, I eliminated all @Configurable references and now use the alternative service locator pattern.