• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Save file to Servlet context

 
Ranch Hand
Posts: 105
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello coderanch,

Huge thanks for any help or advice.

I'm trying to do two things:

1) Save a dynamically generated (by my Servlet) file to tomcat.
2) Expose a fully qualified URL to that file.

At the moment, when I run



it is saved to



Reading over this stackoverflow post http://stackoverflow.com/questions/2663204/how-to-store-a-file-on-a-serverweb-container-through-a-java-ee-web-application it doesn't seem a bad place to save my file.

My saved file is only going to exist for a few minutes (until the client makes a GET request to download it).

I'm not sure how to achieve what I want:

a) How can I map an external / full URL to my saved file?
b) Is there a better way (and place) to save and server this file?

Regards, Sam
 
Saloon Keeper
Posts: 27752
196
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
No, the Stackoverflow example is a very bad one.

You should NEVER upload files into your WAR.

First, because it's not guaranteed to work at all. A webapp server is not required to explode a deployed WAR into a physical directory structure. And in fact, I have server which are set up not to. In such cases, getRealPath() will return null.

Secondly (although not important for your case), because changes made within your WAR (where possible) will get wiped out when the WAR is replaced with a newer version.

Normally I would tell you to select an upload directory that's external to not only the WAR, but to Tomcat itself. But you only want short term-storage, so I'd recommend creating a temporary file using the standard java.io.File createTempFile() method.

In Tomcat, this method will normally create the temporary files in the TOMCAT_HOME/temp directory. That can be overridden at the JVM level, however the same way you would for a non-web JVM. The catalina script uses the value assigned to CATALINA_TMPDIR.
 
sam wootton
Ranch Hand
Posts: 105
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Tim Holloway,

Many thanks for your help and explanation.

Im already having the fil saved to tomcats temp dir, but I was only using above code posted.

I'll give this a try - but a bigger stumbling block I'm having, is how to expose this file (via a URL) to allow it to be downloaded from a GET request (in this case from a gwt client).

Regards, Sam

 
Sheriff
Posts: 67746
173
Mac Mac OS X IntelliJ IDE jQuery TypeScript Java iOS
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Write a servlet that runs as part of your program that can serve the file from whatever outside folder you store the file in.

And I will back up Tim's point vehemently: never store anything inside the web context.
 
sam wootton
Ranch Hand
Posts: 105
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Bear Bibeault,

Really appreciate the help.

So a temporary file under e.g.



would be okay?

serve the file from whatever outside folder you store the file in.



... thats the bit I cant work out how to do.

My file is dynamically generated e.g.



and it is stored in TOMCAT_HOME/temp/<servlet name>

how would I create a URL to point to that file?

Sorry if I'm missing something obvious

Regards, Sam
 
Bear Bibeault
Sheriff
Posts: 67746
173
Mac Mac OS X IntelliJ IDE jQuery TypeScript Java iOS
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

sam wootton wrote:
So a temporary file under e.g.



would be okay?


I wouldn't. It ties your app to Tomcat, and because it's a temp folder, I'd be worried it could be reclaimed at some point not under the app's control. I'd create a folder specifically for this app.

... thats the bit I cant work out how to do.


Write a servlet that can read a file from disk and stream it as the response. How the file is identified is up to you (path variable? request parameter?). Be sure to set the content headers appropriate for the type of the file.

You should be able to find examples of such servlets with a quick search. Many times such servlets are created to serve images from outside the context. That'd be easy to adapt to zip files.

 
sam wootton
Ranch Hand
Posts: 105
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Bear,

Many thanks for your continued help. Where should this separate folder sit? Does it have to be completely outside of my webapp i.e.

C:\Users\Sam\apache-tomcat-7.0.62\my_downloads\

What's the best way to retrieve or reference this path from within my webapp?

My client (gwt client) has to make a GET request (as you can't stream from gwt), so I need a URL that can be hit directly.

Or are you suggesting my client sends back unique id (i.e. the times-tamp in my dynamically generated 1458905006150_download.zip) to my server (that processes the GET requests > looks for the file) and sends it back to the gwt client?

The problem here is that get cant handle that streaming - hence the direct GET URL request, but im unsure how to generate a URL that maps to C:\Users\Sam\apache-tomcat-7.0.62\my_downloads\

Again, really appreciate your help.

Regards, Sam
 
Bear Bibeault
Sheriff
Posts: 67746
173
Mac Mac OS X IntelliJ IDE jQuery TypeScript Java iOS
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

sam wootton wrote:
Many thanks for your continued help. Where should this separate folder sit? Does it have to be completely outside of my webapp i.e.


Yes. Refer to Tim's point about what happens when you update the site. The proper way to do that is with a war file, which should replace everything that was there before. So, poof, your temporary files are gone. (And creating some over-complicated deployment band-aid to try to prevent that is a FAIL before it even starts.)

C:\Users\Sam\apache-tomcat-7.0.62\my_downloads\


I wouldn't put in your user folder. Create a folder owned by the same user that runs tomcat, and make it independent of every thing else. Not belonging to Tomcat or a specific user. Think about the future.

(Disclaimer: I don't use Windows so my understanding of file ownership and file systems is Unix and OS X based. But my main points still apply, I believe.)

What's the best way to retrieve or reference this path from within my webapp?


I generally have a properties file that contains configuration information for the web app. It's read and stored in application context at startup time by a context listener. That's where I would put stuff like the path to the folder where the files will be stored.

My client (gwt client) has to make a GET request (as you can't stream from gwt), so I need a URL that can be hit directly.


That's what the servlet is for. The GET request is made to the servlet, and the file is returned as the response. From the client point of view, it's just like any other request.

Or are you suggesting my client sends back unique id


There needs to be some way for the file to be returned to be identified in the URL. Easiest way to do that is to put some sort of id in a request parameter. Personally, I tend to try and make my URLs RESTful in nature and I'd make it part of the path. But either works.

but im unsure how to generate a URL that maps to C:\Users\Sam\apache-tomcat-7.0.62\my_downloads\


The whole point is that you don't. That folder is outside the purview of the web server and hence cannot be served via URL. Again, see above, that's what the servlet is for. The servlet is the agent that reads the files off disk and returns it to the client upon request.

So the URLs address the servlet, nothing else.
 
sam wootton
Ranch Hand
Posts: 105
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Bear,

Great, really appreciated.

Yeap, properties file, duh, why, why didn I think of that. Sorry, bit tired today.

This is just my own / 'bedroom' app, so im not too fussed about security, but thanks for your thoughts on it.

I'll get going on implementing this, as I've asked far too many questions already.

Ill let you know how it goes.

Thanks again.

Regards, Sam
 
Tim Holloway
Saloon Keeper
Posts: 27752
196
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In short:

Tomcat is not a file server it is a web server. URLs are not file paths, they are resource paths. They just happen to have a similar syntax, that's all.

Much of the confusion comes from the default behavior of the server. If no servlet is mapped to a URL and there is no JSP that matches either, then the server will use the resource path to locate the resource within the WAR, open it, and copy it to the HttpResponse stream. Or, if it's a directory and options allow it, create a directory listing page.

Again, however, this is NOT a file server. Resource paths are always relative to the root of the WAR and never resolved above that level (it would be a major security risk, otherwise).

If you create a tempfile in a webapp and save its File object for later URL retrieval, then a regular filesystem call made by a file-output servlet can open it, just like any other file. Because in fact, it is just another file, you just had help in locating it and naming it.

You yourself have to write the file-output servlet that opens that tempfile, copies its contents to HttpResponse output, and (presumably) deletes the tempfile afterwards. There are no pre-supplied or standard components that do that job.

A resource path, incidentally, is everything in the URL after the http(s)://server:port/context/ part of the URL up to the query parameter part (starts with "?") or anchor name (starts with "#"). The web.xml file maps URL resource paths in part or in full to servlets and if no definition in web.xml matches then the default mechanisms I mentioned previously take over. The tempfile is not a resource in the WAR, so it has no resource path itself.
 
sam wootton
Ranch Hand
Posts: 105
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Just an update (conclusion hopefully).

BIG thanks for everyone's help. I was having a bit of a 'slow' day yesterday, apologies. Anyway, its all working as expected.

downloads being saved by tomcat in a (server.properties configured) location



initial servlet response (xml and POST driven) includes a unique user / download id in the headers



gwt client reads this (as part of the POST response above), makes GET request sending back id in params



servlet writes download zip as part of GET response


gwt client, upon GET response open download dialog



Marking as resolved.

Regards, Sam



 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic