Deploying a Spring-based WAR with its JAR dependencies externalized - java

I have a Spring app that has a lot of dependencies (18 megabytes of JAR files..) - Now, when I am testing on the remote Tomcat 6.0 server, I'd like to not have to upload that 19 megabytes of dependencies, and just upload the classes. Pretty simple, right?
I can't get the damn thing to work.
I'm using Eclipse 3.4, and if in Java Build Path->Order and Export I remove the export of all of the dependencies, I get a nice small WAR.
So here's what I tried:
I uploaded all of the libs to the server, and stuck them in common/lib in Tomcat. The directory didn't exist, so I created it and modified catalina.properties:
shared.loader=${catalina.home}/common/lib/*.jar
I've tried a bunch of other configs, but none worked. Restart the server, deployed war fails to start. Specifically:
SEVERE: Error configuring application listener of class org.springframework.web.context.ContextLoaderList$java.lang.ClassNotFoundException:org.springframework.web.context.ContextLoaderListener at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1
It's dying trying to load the Log4J listener, which it can't find in its classpath. The spring lib that listener is in is in common/lib.
Also - when I deploy the full 18 megabyte war, it works just fine. Everything inits and the app starts. Of course it works fine locally as well.
Oh - and I've replaced the hardcoded logging JARs with the ones out of the extras folder to allow Log4j to work.
Any help here? I have no idea why this isn't working.

"I have a Spring app that has a lot of dependencies (18 megabytes of JAR files..) - Now, when I am testing on the remote Tomcat 6.0 server, I'd like to not have to upload that 19 megabytes of dependencies, and just upload the classes. Pretty simple, right?"
I don't understand this - 19MB is not a lot. You'd be much better off just packaging a WAR and be done with it.
I recommend that you do your testing locally on your own identical Tomcat instance, get it all working, and then deploy the WAR to the remote Tomcat instance.
UPDATE: One issue I have with putting those JARs in Tomcat's /lib directory is that now every app that you deploy to that instance sees those JARs - change them for one, all are affected. If you put the JARs in each individual WEB-INF/lib, you can modify each application without affecting others. The cost is duplicate JARs and disk space, which is cheap.
Another problem if you have to migrate from devl->test->prod, now every environment has to have the identical JARs deployed in order for your app to work. Miss one and you're broken. Your app depends on having those dependencies available. If they aren't on the server you're out of luck. Keep control in your own hands and package the JARs in the WAR file.

You need to be careful externalizing the dependencies like that in a web server environment. Depending on the server there can be unexpected class-loading issues even when it seems to start up fine.
I agree with duffymo... 19MB is not really all that big... is there some reasoning behind wanting to do this? I wouldn't recommend it.

find the webapp folder
upload the files direct into the folder
for example
/path-to-tomcat/webapp/myapp/
keep the /path-to-tomcat/webapp/myapp/WEB-INF/lib folder and upload the changes to ur /path-to-tomcat/webapp/myapp/classes folder
then use tomcat manager to restart the app

I second the suggestion of sending updates directly to ${CATALINA_HOME}/webapps/<your-app> on the target server. WARs are for production deployment, but if you have a slow connection and a large WAR that's no fun.
You'll want your web app to restart after the update, of course. Tomcat in development mode will monitor a few files for changes; by default WEB-INF/web.xml is one of them, so update that along with whatever else you're updating and you should get an app restart soon. In a pinch, you can use the Manager web app to kick the app awake.
For more control and convenience, you'd eventually do well to use the Tomcat ant tasks (found near the Tomcat distribution, not included with ant!) to restart the server, and perhaps to deploy your changes as well. Takes some fiddling but this is well worth it as you'll want to re-use it for each project you do.

Is WEB-INF/lib empty?
Where is log4j.jar?
Where is spring.jar?
This looks like classloader visibility problem.

Listen to duffymo and cjstehno.
Adding jars to tomcat's is a sure recipe for disaster.
Keep your jars in your webapps directory.

It is strange that Tomcat can't find the jar files. Anyway, place all jars in the common folder (${catalina.home}/lib). (This is even worse than using the shared.folder, but it should work for you).
Of course, like others said, you shouldn't do that in your production system. I believe that is OK for a development system though - especially if you need to do extensive testing with the production system anyway.
Another note: you should only do this if you have full control of the server and you are the only one installing applications.

Why would you change the default ${shared.loader} property of tomcat?

Related

Tomcat WAR file deploy failure in Windows

I have an application running in a tomcat container in Windows environment.
When I have to update the application, the tomcat windows service is stopped, new ROOT.war file is copied in the webapps folder and tomcat service is restarted.
Sometimes it happens that the ROOT.war extraction fails and the extracted ROOT folder has only few subfolder and few files. Obviously the following application startup fails.
To solve this problem I have to stop tomcat, delete ROOT folder and run in again to let tomcat re-extract the ROOT.war again from the beginning.
I cannot understand why sometimes it happens and sometimes no. However, it makes impossibile to me to create an automatic update. It is too risky.
Do you have any idea why it can happen?
Resources are not released. So, when you try to update the existing war file, tomcat is not able to delete the older files before deployment/redeployment.
To resolve this issue, ensure that:
The application is not open/running on web browser.
You're not stuck in debug mode when you click on update.
All processes/requests are completed before redeployment.
All files/streams are closed within the code.
When all else fails, you may want to stop the application. Then update. There are ways to stop applications on tomcat using command line, batch files, etc. You can then automate the process.
If you want a more reliable way to do this, you may use jrebel or a free version of the same. There are other ways to update code. Basically, standalone tomcat is not worth anything more than a development server.
Remark: if you are updating the application while Tomcat is running you need to either:
use Tomcat Manager to deploy it,
call tryAddServiced (before Tomcat 9.0 addServiced/isServiced) before any modification to the webapps directory and removeServiced afterwards. This can be done through JMX on the bean Catalina:type=Deployer,host=<your_host_name>,
replace the WAR file (almost) atomically: e.g. deleting the old one and moving (renaming) the new one from another location on the same filesystem should work.
which prevents Tomcat from immediately deploying the application until the copy operation is finished.
To prevent the OS from locking the files in the webapps/ROOT folder you have two options:
Use antiResourceLocking="true" as already suggested by Svetlin, which basically forces Tomcat to copy webapps/ROOT to a uniquely named temporary directory before deployment (the copy will be locked, webapps/ROOT will not),
Use parallel deployment by naming your WAR files: ROOT##001.war, ROOT##002.war, etc. This is basically an explicit version of the antiResourceLocking feature with the additional advantage of letting clients transition fluently between the old and new app version.

JBOSS explode war file on build (hot deployment)

The last Java project I was on used Tomcat as the server my new Java project is using JBOSS.
I am a front-end designer that needs to make frequent and rapid changes to JSP, HTML, CSS and JS files. Here is a rundown of what is happening...
In Tomcat, when an app is deployed into the webapps directory, it is automatically exploded. From there I can stop the server, create symbolic links pointing from the webapps/myapp directory to my GIT repository, ~/somedir/myapp and then restart tomcat. This way I am always working on my local repository and when I make a change in my IDE then go to the browser and refresh, the changes are there instantly.
In JBOSS, things are a bit different. When an app is deployed into the standalone/deployments directory, it remains compressed as a .war file.
I have tried expanding the .war file manually and renaming the folder to myapp.war and that seemed to work, however, JBOSS still re-deployed the app once it noticed there was a change to one of the files, which kinda defeats the purpose.
I have been searching for a couple of days now before asking this question as a last resort.
Does anyone happen to know of a way to accomplish in JBOSS what I was able to accomplish in Tomcat?
Thank you in advance!

Updating WLS_HOME/server/lib contents without a restart

Does anyone know how to update the content of a WebLogic Server's WLS_HOME/server/lib/ folder without having to restart it?
A colleague of mine did a deployment which involved an updated .jar file that was used by all the .ears in the user_projects directory, so he decided to place it in WLS_HOME/server/lib. Whilst the web apps he deployed to user_projects deployed ok, we noticed in the server log it was getting repeated NoClassDefFound exceptions for classes we knew were in the updated .jar - and it didn't pick up the new classes till after a restart.
I need ideally to be able to deploy new shared libraries to this /lib folder without having to restart the server as that involves an outage.
Does anyone know how to do this?
This is not possible. You should move to shared Java EE libraries if you need more flexibility. For your current situation, the only thing you can do, provided you have a clustered environment, is to do a rolling restart of the instances to avoid downtime.
From Understanding WebLogic Server Application Classloading :
WebLogic Server includes a lib subdirectory, located in the domain directory, that you can use to add one or more JAR files to the WebLogic Server system classpath when servers start up. The lib subdirectory is intended for JAR files that change infrequently and are required by all or most applications deployed in the server, or by WebLogic Server itself. For example, you might use the lib directory to store third-party utility classes that are required by all deployments in a domain. You can also use it to apply patches to WebLogic Server.
The lib directory is not recommended as a general-purpose method for sharing a JARs between one or two applications deployed in a domain, or for sharing JARs that need to be updated periodically. If you update a JAR in the lib directory, you must reboot all servers in the domain in order for applications to realize the change. If you need to share a JAR file or Java EE modules among several applications, use the Java EE libraries feature described in Creating Shared Java EE Libraries and Optional Packages.

Can Eclipse automatically refresh Tomcat app?

I use Eclipse Indigo (EE) to build applications in Java framework Vaadin,
using Tomcat 7.0 server. After changes in code I wont see result in a browser,
so I need to click option "Clean Tomcat Work Directory.." and wait until
Tomcat stop and start a server.
Otherwise, when I refresh app page, I don't see any changes.
Even when I restart server (and when eclipse automatically restart it when I save changes), without cleaning tomcat directory.
Option "Automatically publish when resources change" is enabled.
Is any faster way to do that? or can I automate that process?
Additionally to the answer of Kowser, it is possible do hot code changes when running tomcat in debug mode.
Otherwise you could investigate in JRebel
In your "Modules" tab of your Tomcat, you hace to clic on 'Edit' and uncheck the 'Auto reloading enables' option.
With that, several changes won't need a restart (as long as you start your server in debug mode).
If you setup your project to use ant for building and deploying, you can simply add Ant builder to your project Builders to run your ant build and deploy targets every time after you have saved a file. Then provided that tomcat is configured to support auto-deploy, this should achieve what you want, with two caveats:
If your project takes more than a few seconds to build, building after every save is not practical.
You may run out of memory for the tomcat instance if the same app is deployed to it repeatedly for a number of times. This can happen if tomcat is somehow unable to recover all the memory from undeployed resources.
It might be possible. But your setup is a bit different from what I use. I am just using tomcat+eclipse to do Servlet development using Velocity and Torque.
The following works for me where changes are visible in the browser as soon as I save in eclipse.
I assume that you have a project directory such as
apache-tomcat-7.0.11/webapps/$YOU_PROJECT/WEB-INF/classes/
Create a symbolic link with ln -s from your eclipse project directory and to the classes directory in WEB-INF.
Then configure eclipse to write all .class files to this directory. (Done by right clicking on the project in Eclipse and choosing Properties and then Java build path.
In your $tomcat/conf/context.xml config file first tag should be:
<Context allowLinking="true" reloadable="true">
Also add the following as a child to if it is not already there.
<WatchedResource>WEB-INF/web.xml</WatchedResource>
That is what I have done, but I am not sure it works with your EE tools.
ps: This solution assumes that you are using linux/unix. I don't know if it works with windows. The major problem is that eclipse can't write class files outside the project directory (Which is why that symlink is required).
btw: Tomcat may(Depending on class loader, used .jar files and other complicated details) leak a lot of memory when automatic reload is enabled so you may want to increase the allowed memory(Mostly permgen) to prevent out of memmory exceptions from tomcat.
I know this has been asked and answered very long ago. But use this info if it is helpful to anyone of you. I use Eclipse Kepler and configured Tomcat 7 server inside eclipse. I don't have to do any other configuration but to just uncheck Update context paths check box. That is all. Leave other setting as default.
In this way, changes to the resources files (xhtml pages, css files etc.) as well as the java source code files show up in the browser. Only for class files the web application would be redeployed (no server restart auto as well as manual required).
Location of Update context paths: Double click on the tomcat server under Server tab. Under Publishing tab you would find this Update context paths check box.
Absolutely no other change needs to be done for the auto publishing. This works both in normal and debug mode of tomcat.
Screen shot from my eclipse below:
No, there is no other way.
You will notice immediate changes only while updating a JSP/HTML/etc.... Classes will not be loaded/refreshed automatically. It will be contradictory to change a loaded/instantiated class when server is live, isn't it? At least it should not be possible.
It's better to perform Unit Test while developing something. It can help you to reduce the amount of annoying server restarts.

How to avoid copying 40M of java lib's within a WAR when the WAR's size is 41M?

At the moment my build process consists of repackaging the war file with all required java libraries under WEB-INF/lib and then copying the war file to development/demo/production server to be redeployed by tomcat.
The packaged war file's size is about 41M and it has at the moment something like 40M of external java libraries. There has to be a better way. How have you solved this issue?
My development machine is a windows box with Eclipse as my IDE and Ant as my build tool. The servers are all linux boxes with Tomcat 5.5.
Should I maybe add the jar files to the war package at server side?
I can see what you are saying, and have had the same frustration with some of our webapps, but for consistency sake, I would suggest you keep things as they are. If copying the libraries to the tomcat/lib directory you may run into issues with the system classpath vs. the webapp classpath.
By keeping things as they are you are sure you are deploying the same stuff in development/demo as you are in production. Life sucks when you are manually tweaking stuff in production, or you have some crazy error because you forgot to update XYZ.jar from version 1.6 to 1.6.1_b33 in production and now it's behaving differently than what you believe is the exact same code on demo.
When working with something vital enough to have dev/demo/production systems, I think consistency is much more of an issue than .war file size.
We use the rsync tool for this (in our case, using cygwin under windows) to copy the deployments to the servers (which run linux). We use exploded WAR/EAR files (i.e. a directory structure called MyApp.war rather than a zip file called MyApp.war), rsync will only transfer the files that have changed.
In general use, rsync will transfer our 30-40 megabyte exploded EARs in about 5 seconds.
Tomcat has a shared/lib directory, which is the proper place for global application dependencies. However, these will be visible to all applications, which will affect dependency management and may have consequences for things like static variables. I'm not sure if you can configure anything better in Tomcat.
An alternative is to switch to a more sophisticated web container. For example, WebSphere Application Server Community Edition (a blue-washed version of Geronimo) supports per-asset libraries. Other free and commercial servers support this, too. I know WebSphere Application Server does and I'm pretty sure you can do it in Glassfish.
#McDowell, when mentioning those J2EE servers, you should precise that they are J2EE servers(servlet container + the rest).
Like #digitaljoel, I suggest to keep things like they are. It looks like you haven't done much web application deployment yet. The issues that you'll have are not worth the price(version conflicts, deployment errors, etc.).
Can you add the non-changing Jars to the Java Library Path on the server side, and only include the regularly changing Jars in your WAR?
you could include the external java libraries in the Tomcat/lib directory. That way they stay on the server.
You could just deploy as a JAR file, replicate your deployment environment locally and just copy over the files that have changed and the jar itself. The pathing is the only real issue.
Or you could look into setting up an EAR.
I work with the 'exploded web application' in the development servers, and occasionally in production as well. The deployment process (based on ANT) updates the JARs in WEB-INF/lib with our packages. Only in the development server, we activate Tomcat reloading which takes care of restarting the application when something changes. You should assign some extra permanent memory to these Tomcats and have a way to restart the server, as the reloading may crash Tomcat from time to time.
I know it's a weird configuration, but I can't understand how constantly repackaging the 30MB (and growing) of our typical application could do any better. May one day the development descriptor allow for external references to libraries which the container may download and cache. ??
Excuse my poor English.
What you need is a version control tool and a build process.
Use CSV,SVN,GIT or whatever fit you to keep your source under control.
use a build tool to build your application : Maven,ant,...
Now, when you want to deploy your application on your server ,you just have to commit your updates on your computer,update your source on your server,build your application and deploy it from the server.
This way , the server will just have to load your modifications and it should be much faster.

Categories