I have a web project that has a \META-INF\services\javax.servlet.ServletContainerInitializer file with its content pointing to the fully qualified name of a class that implements the ServletContainerInitializer interface. I basically followed the example given here: http://nullhaus.com/2011/03/using-servlets-3-0-servletcontainerinitializer/
I put debug lines in my class that implements the ServletContainerInitializer interface and it never makes it there. Not even the default constructor...
My application folder structure is as follows:
\MyApp
\META-INF\services\javax.servlet.ServletContainerInitializer
\WEB-INF\classes\
... [list of classes and packages go here]
Any ideas what I need to check for??
Note 1: My Tomcat publishes from an exploded external folder that contains my application
Note 2: I started my Tomcat from Eclipse - if that makes a difference!
Well, I think that you'll need to wrap your initializer class (and it's services-related META-INF directory) into a separate *.jar and put it in the WEB-INF/lib.
This is a JAR service, so I guess it could have something to do with problems with discovering services in a *.war file. Moreover, it doesn't even help if you put your META-INF directory inside WEB-INF/classes and set unpackWAR=false in your Tomcat's server.xml.
HTH.
The first thing to check is that you are actually using Servlet 3.0 and not an earlier version. For Tomcat, this means that you must be using Tomcat 7.0.22
Second, make sure that the \META-INF\services\javax.servlet.ServletContainerInitializer file actually exists in the exploded war file.
Third, when in doubt, configure and start Tomcat directly (not from Eclipse) - I've seen developers have endless problems with configuration of Tomcat using the Eclipse plugin.
For tomcat to load the META-INF directory , it has to be in classes folder . If you are using maven project , just put the META-INF directory inside src/main/resources directory .. on mvn package the same will be copied to classes directory .. No need of separerate jar .. if jar is prefered you can use
HandlesTypes annotation ..
I would like to quote some good explanation from Mark Thomas <markt#apache.org> given on the user mailing list of Tomcat:
Service files are loaded by class loaders from the META-INF/services
directory.
*.jar!/META-INF/services
and
*.war/WEB-INF/classes/META-INF/services
are visible to class loaders
*.war!/META-INF/services
is not.
The servlet expert group recently discussed WAR vs JAR in the context of
Java 9 and mutli-version JARs. The conclusion was (I'm paraphrasing)
that WARs are not a specialised form of JAR and while they share a
common format a feature that is available to a JAR is NOT automatically
available to a WAR unless the Servlet spec (of Java EE spec) explicitly
states otherwise.
Containers are free to add container specific extensions if they wish
but they come with the usual (lack of) interoperability warnings.
http://mail-archives.apache.org/mod_mbox/tomcat-users/201808.mbox/
Related
I have an executable jar with a war file in it. Running the jar extracts the war file and creates a WebAppContext from it using webAppContext.setWar(warFile). Although that works, it seems that webAppContext.setWarResource(warResource) should work. I've tried it creating a resource using new PathResource("file.war") which shows a path like "jar:file:/Users/.../jetty-1.0.0-jar-with-dependencies.jar!/file.war". Sounds promising and conventional, but when I try it I get "java.lang.IllegalArgumentException: not file: scheme". Do I really have to extract the war file or is there a trick?
That would be a nested jar content reference and no Java program can do that.
Option 1: use a live-war (aka an executable-war) instead.
This would be a war file that can be deployed traditionally if you want to, but can also be used standalone from the java command line (and will start it's own server if it needs to).
An example project is maintained by the Eclipse Jetty project at ...
https://github.com/jetty-project/embedded-jetty-live-war
Note: the live-war concept was inspired by work done by the Jenkins project and their live-war.
Option 2: eliminate the WAR file layer entirely in your JAR
Don't package the WAR contents in your JAR as a filename.war, consider using it as an exploded WAR (or war directory) instead.
Just unpack the WAR into your JAR file somewhere safe (like /META-INF/webapps/<app-id>/) and then reference that directory location in your JAR file instead.
Option 3: eliminate the need for the WAR concepts entirely
This is the number one most popular choice.
You deconstruct your WAR file into a ServletContextHandler with configured Servlets and Filters, this also eliminates the need for things like annotation scanning / bytecode scanning (which is quite complicated), you'll also not have to wrangle the nested / isolate classloader (your uber JAR file contains all of the classes and downstream dependencies needed to run your webapp), and this approach will definitely speed up your startup time.
It says here that the common classloader is visible to all web application. So what is the difference between having a JAR file within the WEB-INF/lib folder of my war application and having the same JAR file within Tomcat's lib folder?
This JAR is a provider for a Java SPI that I created. When I have it under WEB-INF/lib, everything works perfectly. But if I try to put this JAR under Tomcat's lib folder (or under shared/lib after configuring it in catalina.properties) I get errors. The second option is better for me because I need total decoupling of my application and the provider.
The error I get is a ClassNotFoundException for the interface that represents my service (which the JAR implements). This interface is in a third project, which is a dependency for my war application.
The tomcat/lib directory should be used for shared libraries for the whole web server and WEB-INF/lib only for one web application.
The difference is the classloader being used. Tomcat has very specific rules for it's classloaders, some of them are counter intuitive. Your problem here, is that a class loaded in one classloader is not compatible with a class loaded in another. Even Object to Object will fail.
The jar containing your interface is loaded by the webapp classloader since it is located in the war-file. The implementation is loaded by the common classloader. This does not contain your interface, so it throws a ClassNotFoundException.
The solution is to move all jars into the same classloader. Either everything in the lib-folder, or everything in your war.
Implementing a plug-in architecture with Tomcat is a rather difficult undertaking. Using something like OSGi would probably help. But for small problems, it's probably overkill. Fun, but overkill.
In my application I am calling a bean from JSP and displaying data.I have kept all required jars in lib folder and that is in build path.When I run this bean it fetches the data successfully. But when I call this bean in JSP it says No Class defination.I found a workaround for this that is putting all the jars also in the lib folder of Tomcat.(apart from keeping in classpath). Means now i have to deploy the war and also put jars in tomcat lib.but why do i have to do this when jars are already in classpath.
thanks.
It sounds like you might be having a conflict with some of the jars. If one of the jars is depending on something provided elsewhere in the tomcat class loader, or if it is providing the same functionality - you could end up with a problem. You used to see this often with a conflicting XML parser implementations.
This has some more information on what is included: http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html
I have same class file under classes folder and also in jar file inside lib folder.But the class is getting picked up from jar file. As per my understanding when this is the case , class under classes folder gets preference over jar file. At least this is the behaviour i have seen in glassfish. But this is not the behaviour in tomcat. Do i need to do any configuration in case of tomcat to give the preference to classes under classes folder? I am using tomcat 6.0.26.
The spec (2.4) says:
The Web application class loader must load classes from the
WEB-INF/classes directory first, and then from library JARs in the
WEB-INF/lib directory.
So if Tomcat loads from the jar first, it's not compliant with the spec.
Its documentation says:
Therefore, from the perspective of a web application, class or
resource loading looks in the following repositories, in this order:
Bootstrap classes of your JVM
System class loader classes (described above)
/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
Common class loader classes (described above)
So I'm surprised you're seeing such a behavior. If you're absolutely sure that the class is not in some jar in Tomcat's own classpath, file a bug report. Before doing that, also make sure to clear Tomcat's work directory, or even to start from a fresh install of Tomcat.
The workaround is of course to repackage the jar file to include your modified class instead of relying on the classloading order.
I'd like to package my Java EE6 web classes (beans, filters, servlets) into jar and place it into /WEB-INF/lib/ directory along with other utility jars and abandon /WEB-INF/classes/ directory totally.
Are there any substantial differences between the two in terms of classloading, acessing application context, etc?
Thanks.
PS: Whenever googling any of java specs I'm always redirected to Oracle documentation index which is dozen clicks away from original url. Anyone knows what's happening there?
I'd go for /WEB-INF/classes. It allows you to run your application in debug mode and hot-swap classes on change. If you package everything as a jar, you'd have to repackage and redeploy the app every time you change a class.
Well, shortly: Imagine you have class org.example.Test.class, if you put it into jar and in WEB-INF/lib/ directory, and copy the same class into WEB-INF/classes/ then classloader of that application will use last one (from WEB-INF/classes/).
Sometimes you can use it as advantage - I have a library, and it has a bug... I look for source of that class (where bug is; I miss the part of how I know that bug is in that class, that's another story), I add that class to the project with fixed code, and it is compiled into WEB-INF/classes/ while library still exist in WEB-INF/lib/. Fixed class will be used until library will be fixed.
In Tomcat Servlet container's definition: WEB-INF\classes is searched before WEB-INF\lib. You can choose to delegate your classloading to your custom classloader - even then the order above is maintained.
If you choose to go with a different provider e.g. JBOss, Glassfish, Jetty it might have a different order, but I am not sure about those.