This week's book giveaway is in the OCAJP 8 forum. We're giving away four copies of OCA Java SE 8 Programmer I Study Guide and have Edward Finegan & Robert Liguori on-line! See this thread for details.
I am curious - should the Tomcat (6, 7) obey the Class-Path section of META-INF/MANIFEST.MF file?
I have an application packed as a WAR and a manifest file as follows:
I don't have this myTest.jar file which is pointed in the manifest file.
I was expecting the tomcat to "reject the application with an invormative error message." (as you can read in Servlet 3.0 final spec in section 10.7.1 "Dependencies On Extensions")
Is this whole Class-Path WAR manifest file dependency information just optional for the container to support, or am I doing something wrong?
The class-path specification is for use when executing Java applications via the "java -jar" command. It doesn't apply to webapps (WARs).
Two reasons for this:
1. Unlike Applications, which normally would only include their containing JAR in the classpath, webapps have a designated location for class libraries (the WEB-INF/classes and WEB-INF/lib directories).
2. WARs must be self-contained. That is, no references to JARs or classpath directories external to the directory structure of the WAR itself. Since there's already a designated location internal to the WAR, it's better (and more secure) to use that instead of allowing people to splatter code resources any old place.
In cases where there is some reason why a library isn't feasible in the standard location, your options are basically to put it in the container's classpath as is the case for things like the jdbc drivers, or you could add a custom classpath manager to the WAR.
An IDE is no substitute for an Intelligent Developer.
But then again, I am looking at Servlet 3.0 final spec, 10.7.1 Dependencies On Extensions and read:
Application developers need to know what extensions are installed on a Web container, and containers need to know what dependencies servlets in a WAR have
on such libraries in order to preserve portability.
The application developer depending on such an extension or extensions must provide a META-INF/MANIFEST.MF entry in the WAR file listing all extensions needed by the WAR. The format of the manifest entry should follow standard JAR manifest format. During deployment of the Web application, the Web container must make the correct versions of the extensions available to the application following the rules defined by the Optional Package Versioning mechanism (http://java.sun.com/j2se/1.4/docs/guide/extensions/).
Web containers must also be able to recognize declared dependencies expressed in the manifest entry of any of the library JARs under the WEB-INF/lib entry in a WAR. If a Web container is not able to satisfy the dependencies declared in this manner, it should reject the application with an informative error message.
The value of this attribute specifies the relative URLs of the extensions or libraries that this application or extension needs. URLs are separated by one or more spaces. The application or extension class loader uses the value of this attribute to construct its internal search path.
So I assume that the 'extensions' mentioned in Servlet specification is the same as 'extensions' in the manifest manual, so it points to the Class-Path attribute.
I understand that a WAR has fixed locations where the libraries can be located. But what about dependencies on server-level libraries?
Can't I have a WAR which relies on some library which is NOT a part of a WAR?
Can't I assume that it's the servlet container responsibility to provide me the appropriate JAR (some kind of /server/lib/ directory) and if it can't - stop the deployment process?
I would like to be sure that before I deploy my application I have been provided with needed jars. That was my understanding of this section in servlet specification.
However, these questions seems to be in conflict with "WARs must be self-contained" you said in your post, so how does it looks like for real?
Do I understand it correctly? If not, what does this "Dependencies On Extensions" talks about? Perhaps I did some wrong low-level assumptions or misunderstood something...
Well, Tomcat6 doesn't support servlet 3.0. And, if I'm not TOO full of on the subject (which is possible!), the extensions mechanism is brand new for JEE 5/Servlet 3.0.
Java code never actually references libraries except in the sense that jars can be added to the classpath. The actual application code, however, references the resources in those jars without knowing or caring which jar (if any) the resources are in. The classpath loader cares, since if you have conflicts, it has to deal with them, but the app code shouldn't.
I'd have to go back and read the latest on JEE 5 to be clear on extensions, but I think that's so you can add new subsystems like maybe JMS support (since that's not part of standard Tomcat).
For more general stuff, however, whatever jars you drop into the TOMCAT_HOME/lib directory will automatically show in the webapp's classpath. If you need to confirm that they're installed, just try a Class.forName() operation on one of the core resources. If the library isn't there, the operation would normally fail unless another version of the class existed somewhere else in the webapp classpath.
One obvious difference here, however, is that stuff in TOMCAT_HOME/lib will be in the classpaths of ALL deployed webapps, as opposed to just a specific app as would be the case in a manifest-defined JAR.
A caveat, however on use of the manifest is that it's not good practice to use absolute filesystem paths for the jars. However, that raises the question of what the anchor point for relative paths would be. Normally it would be the webapp root, which brings us back to "why not just use WEB-INF/lib"?
I realize that Tomcat 6.x is not supporting Servlet 3.0 specification (which is a part of JEE 6), but the Tomcat 7.0 does and I did download it.
I also checked out and the quoted specification part in my last post is also in Servlet 2.4 which is supported even by Tomcat 6.x.
Moreover, take a look at Head First Servlets & JSP by Bert & Kathy book:
What matters to us here is what’s required by the spec, and the answer is—it makes almost no difference whether the app is deployed in or out of a WAR! In other words, you still need WEB-INF, web.xml, etc. [...]
There is one thing you can do when you use a WAR file that you can’t do when you deploy without one—declare library dependencies.
In a WAR file, you can declare library dependencies in the META-INF/MANIFEST.MF file, which gives you a deploy-time check for whether the Container can find the packages and classes your app depends on. That means you don’t have to wait until a resource is requested before the whole thing blows up because the Container doesn’t have a particular class in its classpath that the requested resource needs.
I agree with you that absolute paths are bad, but... do I really need to care about the path? Can't I just say that I need "hibernate.jar" and I don't care where it is, as long as the container can provide me one. If it cannot - I don't want my application to be deployed.
I just want to make it straight - what the B&K and Servlet spec are talking about and what the hell is going on!? ;-)
This is definitely not a widely used feature, since someone made similar inquiries to Craig McClannahan back around Tomcat 4.1 and he wasn't entirely clear on the details himself. And Craig has done some really gnarly stuff, including the design and development of both Struts and JSF.
You should not attempt to place hibernate.jar in a shared location:
Even if you did, the normal place to put stuff like that would have been TOMCAT_HOME/lib. However, you shouldn't, so you must place hibernate.jar in your WAR. Which means that you already know whether the hibernate.jar is available. In any event, it's not all that big considering how important it is.
I think the MANIFEST.MF facility may come into more prominence in Tomcat7 as they move to add-ons for non-traditional protocols and non-traditional languages such as scripting languages, but for bog-standard J2EE it doesn't seem to be very useful. Which is why I'm so bloody ignorant of it myself.
Going back to the absolute/relative path issue, the JVM doesn't support the idea of a "library directory" the way it does for loose classes, so you can't just put a generic jarfile name in and let it find it. Tomcat adds a special classloader that permits it to rummage around in the WEB-INF/lib directory, but that's the only place it's going to look. Relative library paths are relative to the URL of the JAR/WAR, but I've already mentioned the issues with that. And I should note that putting executable code anywhere in the webapp context tree except under WEB-INF is a security problem.
Hi, I was reading this because I wanted a way of adding a folder to the classpath which contains resources like XML and properties files. We keep these things external to our app so we can change them without redeploying the WAR/EAR file. we use tomcat to develope against (wayyyyy faster), the servers run Websphere. So until now, I just added a folder to tomcat within eclipse server connector configuration, easy. I am now working on a nightly build/deploy setup and would like to deploy the WAR to a tomcat server that runs outside of eclipse, so I was looking into getting our config folder added to the classpath by adding it to the manifest file, but it did not work. not a big deal, its only for the nightly builds...
the reason why I post here is that once i removed the path from the manifest again, i got this exception (apparently it needs to have at least a space/' ' character left:
14-Apr-2011 10:14:03 org.apache.catalina.core.StandardContext start
SEVERE: Error in dependencyCheck
java.io.IOException: invalid header field
... so it does some dependency checking after all!?
btw, this is on tomcat 6 but changed to work with JEE6/JSF2.