| Summary: | WebAppClassLoader excludes symlinked jars from classpath (regression) | ||
|---|---|---|---|
| Product: | [RT] Jetty | Reporter: | Phil Clay <pilf_b> |
| Component: | server | Assignee: | Jesse McConnell <jesse.mcconnell> |
| Status: | CLOSED FIXED | QA Contact: | |
| Severity: | normal | ||
| Priority: | P3 | CC: | jetty-inbox, pilf_b |
| Version: | 7.4.3 | ||
| Target Milestone: | 7.5.x | ||
| Hardware: | PC | ||
| OS: | Linux | ||
| Whiteboard: | |||
|
Description
Phil Clay
How are you running your app, embedded or as the distribution? I just cobbled together some unit testing for this and its working fine, I can't reproduce your stated case here. createSymLink is a call out to Process since we its java 1.6 so I am a bit loathe to commit this as an honest unit test...but this works when tacked onto the end if the testWebAppLoad() test case. I am putting the jetty-test-policy jar file into the target directory with the dependency maven plugin so I have jar to work with on this. I am resolving (not closing) as works for me but am open to discussing further.
File symlinkTestDir = MavenTestingUtils.getTargetTestingDir("symlinkTest");
symlinkTestDir.mkdirs();
createSymLink(MavenTestingUtils.getTargetFile("jetty-test-policy.jar").toString(),symlinkTestDir.toString() + "/jetty-test-policy.jar");
_loader.addClassPath(symlinkTestDir.toString() + "/jetty-test-policy.jar");
//_loader.addJars(Resource.newResource(symlinkTestDir.toString()));
assertTrue(canLoadClass("org.eclipse.jetty.toolchain.test.policy.Tester"));
(In reply to comment #1) Thanks for taking a look at this so quickly! The problem is actually with the addJars method, not addClassPath. The following line in addJars is what is causing the problem. if (!fn.isDirectory() && isFileSupported(fnlc)) During war deployment, the addJars method is called with the META-INF/lib dir as the parameter. With the !fn.isDirectory() check, the end result is that addClasspath is not called for the symlink. In your test case, it looks like you thought about that, but you have it commented out. If you reverse the comments on these lines, you should be able to reproduce the behavior I am seeing. (i.e. comment the addClassPath call, and uncomment the addJars call) > _loader.addClassPath(symlinkTestDir.toString() + > "/jetty-test-policy.jar"); > //_loader.addJars(Resource.newResource(symlinkTestDir.toString())); > > > assertTrue(canLoadClass("org.eclipse.jetty.toolchain.test.policy.Tester")); Sorry, I should have mentioned it worked with both mechanisms in the test. I am testing on ubuntu, what are you working with this on? (In reply to comment #3) > Sorry, I should have mentioned it worked with both mechanisms in the test. > > I am testing on ubuntu, what are you working with this on? Ohhhhh, I see the problem in your testcase. Your symlink points to a file. My symlink points to a directory (containing the expanded contents of the jar, which happens to be the output path of the associated eclipse project). For example... $ ls -l WEB-INF/lib/ -rw-rw-r-- 1 someuser somegroup 96221 Jul 26 16:15 commons-pool.jar lrwxrwxrwx 1 someuser somegroup 44 Jul 26 2011 custom-module1.jar -> ../../../../../custom-module1/target/package $ ls -l WEB-INF/lib/custom-module1.jar/ -rw-rw-r-- 1 someuser somegroup 96221 Jul 26 16:15 com/ (I'm on Ubuntu as well.) I see what your doing. Since your doing all this for eclipse purposes I would point out that there has been some nice success with a project called Webby coupled with jrebel for webapp development in eclipe... but I'll take a look at this case as well now Hm, I don't like this...your basically trying to fool the webapp classloader by calling something a jar which it isn't. How are you starting this up, is it an embedded use case? Using addClasspath() works because it really is just a classpath entry, not in fact a jar file. That is to say that addClasspath on your symlinked jar file directory dealio does the right thing as would be expected. This is an embedded use case. We have full control over how jetty deploys our wars.
However, I would really prefer to not call addClasspath() manually. I would much prefer it to automatically happen.
Mainly because our "real" deployment will use a war file, as opposed to an expanded war. And therefore, our "real" deployment will not be using symlinks.
I would prefer that both cases remain the same. i.e. I want to avoid having to call addClasspath() in our dev case, but NOT call it in the "real" deployment scenario.
We use symlinks to speed up the development time. Meaning, that all we have to do is build with an IDE (some people use eclipse, some use intellij, whatever), and we don't have to worry about creating a jar file for every little change we make.
> your basically trying to fool the webapp classloader by
> calling something a jar which it isn't.
I don't really see a downside of this. I see it as comparable to being able
to deploy a war file OR an expanded war directory. The underlying URLClassLoader logic doesn't care if the entry is a file or a directory, so I don't believe jetty should enforce an additional constraint (considering it works fine without the !isDirectory() check).
ok, well I removed the check and we'll see if it passes muster |