Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 354068

Summary: Serve modules without publishing generated invalid server.xml for Tomcat 7.0.x
Product: [WebTools] WTP ServerTools Reporter: Steve Ash <stevemash>
Component: jst.serverAssignee: Larry Isaacs <larryisaacs>
Status: RESOLVED DUPLICATE QA Contact: Elson Yuen <eyuen7>
Severity: major    
Priority: P3 CC: slaurent
Version: 3.3   
Target Milestone: ---   
Hardware: PC   
OS: Linux   
Whiteboard:

Description Steve Ash CLA 2011-08-06 02:57:20 EDT
Build Identifier: 20110615-0604

This seems like its the same issue as bug 318449.  When my dynamic web project is published to a tomcat 7.0.19 server, it generated a server.xml context:

<Context ... extraResourcePaths="/WEB-INF/classes|/home/ashsteph/workspace/fuzzy-project_trunk/fuzzy-admin-webapp/target/classes;/home/ashsteph/workspace/fuzzy-project_trunk/fuzzy-admin-webapp/target/m2e-wtp/web-resources;/home/ashsteph/workspace/fuzzy-project_trunk/fuzzy-admin-webapp/src/main/webapp" virtualClasspath=...

This prepended /WEB-INF/classes| seems to be the root of my problem.  This ends up creating a path of:

log4j:ERROR Could not read configuration file from URL [file:/home/ashsteph/workspace/fuzzy-project_trunk/fuzzy-admin-webapp/src/main/resources/WEB-INF/classes/log4j.properties].
java.io.FileNotFoundException: /home/ashsteph/workspace/fuzzy-project_trunk/fuzzy-admin-webapp/src/main/resources/WEB-INF/classes/log4j.properties (No such file or directory)

which doesn't exist of course, and my web app fails to start.

If I manually edit the server xml and restart then it works fine.  It appears that this was removed in revision 1.8 of TomcatPublishModuleVisitor and then re-added in 1.9 due to 333102.

So I'm lost with what is happening.  Marking as major because there is no workaround that I can find, except just to avoid using the "serve modules without publishing" feature entirely, which is unacceptable because it dramatically decreases developer productivity.

Reproducible: Always

Steps to Reproduce:
1. Create a new blank Dynamic Web Project for Tomcat7
2. Create a new servlet in the src folder: com.test.TestServlet (note this is a servlet 3.0 @WebServlet servlet)
3. Create a new empty file: src/test.txt (place nothing in WebContent)
4. Edit com.testTestServlet init method to be:
public void init(ServletConfig config) throws ServletException {
   System.out.println("Entered init");
   InputStream openStream = null;
   try {
      InputStream openStream = Thread.currentThread().getContextClassLoader().getResource("test.txt").openStream();
      System.out.println("Found the file correctly");
   } catch (IOException e) {
      System.out.println("Didn't find the file at all: " + e.toString());
   }
}

5. Run this project and navigate to the servlet url triggering the init method.  

When you run this with "serve modules without publishing" UNCHECKED then you see console output of "Found the file correctly".  When you run this with the "serve modules without publishing" CHECKED then you see "Didnt find the file at all".
Comment 1 Steve Ash CLA 2011-08-08 10:57:49 EDT
As a followup: I reverted the change introduced in bug 333102 and now (as expected) my webapp launches from the workspace correctly.  But now my test with the @WebServlet does _not_ work (also as expected).  Clearly, I don't understand the plugin enough to better help to get both bug 318449 and bug 333102 to co-exist in WTP 3.3 + Tomcat7
Comment 2 Larry Isaacs CLA 2011-08-08 11:23:32 EDT
This is a known issue which is a side effect of fixing Bug 333102.  The "/WEB-INF/classes" aliasing you cite is required for Servlet annotations to work.  Given that Tomcat is written assuming the webapp lives under a single folder, I'm surprised the "Serve modules without publishing" hack works as well as it does. For the record, here is the explanation provided on the WTP newsgroup:

To get servlet annotations working, the servlet classes have to be accessible as resources in addition to being accessible via classloading.  As a result, when Tomcat "asks" if "WEB-INF/classes" exists as a resource, the answer from the custom classloader used by the "Serve modules without publishing" is "yes".  Tomcat then asks for the URL to "/WEB-INF/classes" in your project, appends the name of the resource (such as "log4j.properties") to that URL and tries to use the URL to read the resource.  Since resources destined for "WEB-INF/classes" exist in multiple locations in your project, the URL returned above can only work for one of them.

Since you are serving the project directly, "file:" URLs are going to be used.  There is no way for the "Serve modules without publishing" option to make it possible for Tomcat to append various resources to the end of a URL and have it access resources that live in multiple locations within the project.  The only way to fix this is to change Tomcat to not assume it can modify URLs in this fashion.

Twisting a quote from Abraham Lincoln: The "Serve modules without publishing" hack can fool some of Tomcat all of the time, and it can fool all of Tomcat some of the time, but it can't fool _all_ of Tomcat _all_ of the time.

*** This bug has been marked as a duplicate of bug 333102 ***
Comment 3 Sylvain Laurent CLA 2011-10-01 17:28:51 EDT
This should be fixed with tomcat 7.0.22 which has just bee released
Comment 4 Larry Isaacs CLA 2011-10-06 14:31:41 EDT
FYI: Use of Tomcat 7.0.22 is impacted by Eclipse Bug 360012 if you are using Servlet 3.0 Web applications with "Serve modules without publishing".  See the bug for details.