The directory where the WAR is exploded is, essentially, "owned" by the app server, and, as you discovered, destroyed on a redeploy.
There are a couple of things you can do.
One, is that you can do a directory deploy rather than a WAR deploy. In this case, you take the WAR file and explode it yourself in to the directory of your choice, then deploy directly from that directory. You have total control over this directory, and the app server won't harm it.
At the same time, along with control, you have total responsibility for this directory. For example, if you were to, say, remove a JSP file from your WAR, when you redeployed from the WAR, the old version is destroyed and the new version created, and your old JSP would, in fact, be gone. But if you were to simply extract your new WAR over the directory of your old WAR, then that could easily leave files behind (like the old JSP in this case). So, just something to be aware of.
The bright side, tho, is that your "upload" directory would remain.
Since most app servers support some kind of exploded WAR deployment, this is also a reasonably portable mechanism across application containers. It's not portable "to spec", but it's portable in the real world.
Next, you can work around this using code. You create a directory in some random place on the server, and then create a Filter or Servlet that intercepts URLs, and then serves those files itself rather than letting the container do it.
This is reasonably straightforward to do, and completely portable. The downside is that you won't explicitly handle a potential chunk of the HTTP spec (like chunking, If-Modified Headers, and such) "automatically", you'd have to write code to support all of that. But it can be done. Of course, you can port the DefaultServlet from the GF code base (complying with the license of course). That's the code that does this job in Glassfish.
So, the bright side of that is simply that you can place the resources anyplace you want on the server (even in a database), and serve them up just like normal to your clients. It's portable, but it's more code to maintain, more work for you to pull it off, but it's "one time" work vs having to maintain your own deploy.
Finally, there's a glassfish specific feature, which is obviously not portable (tho Tomcat offers a similar functionality I believe), called Alternate Doc Roots (see
http://docs.sun.com/app/docs/doc/819-3672/geqpl?a=view ).
These let you map a space outside of your WAR in to the web space. These work great for static content.
If you're going to stick with Glassfish, then these are the solution of choice.
[Message sent by forum member 'whartung' (whartung)]
http://forums.java.net/jive/thread.jspa?messageID=251997