Skip to content
This repository has been archived by the owner on Oct 12, 2023. It is now read-only.

How do I provide files to the embedded Tomcat instance? Specifically a custom classloader jar. #83

Open
Jazzepi opened this issue Feb 20, 2014 · 9 comments

Comments

@Jazzepi
Copy link

Jazzepi commented Feb 20, 2014

I'm trying to put Spring's custom Tomcat classloader into my embedded Tomcat instance that I use for integration tests in my Gradle project because I plan on using load time weaving. It works fine in my normal install when I place spring-instrument-tomcat-3.2.5.RELEASE.jar into the apache-tomcat-7.0.40/lib folder, but how do I access that folder of an embedded Tomcat instance and place the jar in there before the boostrap classloader finds it?

I've included the stack overflow question if someone would rather answer there :) Either way I will x-post the answer to both places. Thanks in advance!

http://stackoverflow.com/questions/21895507/how-do-a-give-an-embedded-tomcat-instance-a-custom-classloader-when-using-gradle

@Emontis
Copy link

Emontis commented Feb 20, 2014

Related: I used a custom Java agent just fine until recently by setting org.gradle.jvmargs=[...] -javaagent: [...] in my gradle.properties to facilitate load-time weaving in gradle-tomcat-plugin but either since Gradle 1.11 or Tomcat 7.0.50 it stopped working by picking up the agent.

This leaves me with the same problem op has. Please provide some guidance.

@bmuschko
Copy link
Owner

@Jazzepi The plugin instantiates its own classloader to separate the project's classpath from Gradle's general classpath. You might want to try to add the JAR file to the tomcat configuration to see if that works. If not, it would be helpful if you could provide an example project on GitHub.

@Emontis Would you mind checking which makes a difference for your project - the new Gradle or Tomcat version?

@Jazzepi
Copy link
Author

Jazzepi commented Feb 25, 2014

Here's a stripped down example of the problem I'm having. The integration tests pass when they're running against a locally installed Tomcat instance on port 8090. When running them by invoking gradlew integrationTest I get a stack trace.

https://github.com/Jazzepi/tomcat-gradle-test

To run this you'll to start up a local mysql database, and set the application.properties. Should be very straightforward, let me know if you have any questions.

https://github.com/Jazzepi/tomcat-gradle-test/blob/master/src/main/resources/application.properties

@Emontis
Copy link

Emontis commented Feb 27, 2014

@bmuschko Finally had time to nail the culprit down. Turns out it is some change between Tomcat 7.0.50 and 7.0.52.

Up until 7.0.50 the -javaagent I configured for Gradle gets picked up:

2014-02-27 09:17:22.501 [localhost-startStop-1] INFO  o.s.c.w.DefaultContextLoadTimeWeaver - Could not obtain server-specific LoadTimeWeaver: Could not initialize TomcatLoadTimeWeaver because Tomcat API classes are not available
2014-02-27 09:17:22.503 [localhost-startStop-1] INFO  o.s.c.w.DefaultContextLoadTimeWeaver - Found Spring's JVM agent for instrumentation

Whereas with 7.0.52 it does not get picked up:

2014-02-27 09:17:57.788 [localhost-startStop-1] INFO  o.s.c.w.DefaultContextLoadTimeWeaver - Could not obtain server-specific LoadTimeWeaver: Could not initialize TomcatLoadTimeWeaver because Tomcat API classes are not available
2014-02-27 09:17:57.798 [localhost-startStop-1] ERROR o.s.w.c.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.weaving.AspectJWeavingEnabler#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loadTimeWeaver': Initialization of bean failed; nested exception is java.lang.IllegalStateException: ClassLoader [org.apache.catalina.loader.WebappClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar

Of course a solution that uses the TomcatLoadTimeWeaver would be much more preferable. I uploaded an MWE at https://github.com/Emontis/gtp-ltw-mwe

@bmuschko
Copy link
Owner

bmuschko commented Mar 7, 2014

@Emontis Hmm, I am not sure what I can do about this if is broken with a newer version of Tomcat. Would you mind asking about it on the Tomcat user mailing list? It's probably a bug on their end then.

@Emontis
Copy link

Emontis commented Mar 12, 2014

Will do.

It would be great and preferable, however, if you can point out/build a way to use the TomcatLoadTimeWeaver with gradle-tomcat-plugin.

@bmuschko
Copy link
Owner

Tomcat's API doesn't allow for just putting the JAR on the classpath.

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loadTimeWeaver': Initialization of bean failed; nested exception is java.lang.IllegalStateException: ClassLoader [org.apache.catalina.loader.WebappClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar

You will need to use -javagent. You'll have to ask on Tomcat's user mailing list why this was broken with 7.0.52. Maybe it's a bug or there's a reason for this not working anymore.

@Emontis
Copy link

Emontis commented Mar 19, 2014

Thats true, but usually you create a context.xml in META-INF to tell Tomcat to use a different class loader than org.apache.catalina.loader.WebappClassLoader, e.g. Spring’s org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver.

The -javaagent was a workaround because the different class loader was not picked up by gradle-tomcat-plugin. The use of an appropriate class loader is much more preferable and it would be nice if the plugin would support it.

@bmuschko
Copy link
Owner

This issue isn't necessarily high on my priority list. If you want this feature, you might want to look into contributing it. I'd be more than happy to review and pull it in. You should probably also have a look at the Gradle Cargo plugin. It let's you use an isolated and installed container that you can configure the way you want.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants