Writing files into a WAR – Another BAD IDEA
I’ve always recommended against this. For one thing, a WAR is a ZIP file and Java has no builtin support for updating ZIP files.
A lot of people abuse the fact that many JEE servers unpack (explode) WARs into a directory such as Tomcat’s webapps directory. They then proceed to use the ServletContext getRealPath() method to translate a subdirectory in the WAR into an absolute filename path.
There are 4 problems with that idea.
- If the server doesn’t explode the WAR, there won’t be a real path. So the pathname returned will be null and the code will probably throw an exception. This can be a problem when transporting the application to a different vendor’s server or when the configuration of the current server is changed.
- It’s generally good practice to keep executable code, forms, and other potentially-hackable constructs in a write-protected location. Plop down a writable directory in the middle of the WAR and you’ve opened up a potential exploit.
- If you write “permanent” files to the WAR directory, a redeployment may nuke the entire WAR substructure, losing the files forever. I’ve always preferred to explicitly erase a WAR before updating it anyway, since otherwise old stale stuff hangs around and pollutes the application. Sometimes with unfortunate results.
- If you hardcode the write directory relative to the WAR, what do you do when the disk fills up? Unix and Linux provide a special directory tree (/var) to hold things that may grow, but there’s no fixed relationship between the WAR directory and the /var directory. Coding an absolute path can work, but it’s not very flexible, either.
What to do? I normally get my writable directory location via JNDI lookup. For example: “java:comp/env/wardata”. The advantage of this is that I can relocate the directory any time I want. I put the default location in the web.xml resource definitions, but in Tomcat I can override this. Which is convenient when testing.