views:

350

answers:

2

I have developed a Java EE web application. This application allows a user to upload a file with the help of a browser. Once the user has uploaded his file, this application first stores the uploaded file on the server (on which it is running) and then processes it.

At present, I am storing the file on the server as follows:

try {
    FormFile formFile = programForm.getTheFile(); // formFile represents the uploaded file
    String path = getServlet().getServletContext().getRealPath("") + "/" + formFile.getFileName();
    System.out.println(path);
    file = new File(path);
    outputStream = new FileOutputStream(file);
    outputStream.write(formFile.getFileData());
}

where, the formFile represents the uploaded file.

Now, the problem is that it is running fine on some servers but on some servers the getServlet().getServletContext().getRealPath("") is returning null so the final path that I am getting is null/filename and the file doesn't store on the server.

When I checked the API for ServletContext.getRealPath() method, I found the following:

public java.lang.String getRealPath(java.lang.String path)

Returns a String containing the real path for a given virtual path. For example, the path "/index.html" returns the absolute file path on the server's filesystem would be served by a request for "http://host/contextPath/index.html", where contextPath is the context path of this ServletContext.

The real path returned will be in a form appropriate to the computer and operating system on which the servlet container is running, including the proper path separators. This method returns null if the servlet container cannot translate the virtual path to a real path for any reason (such as when the content is being made available from a .war archive).

So, Is there any other way by which I can store files on those servers also which is returning null for getServlet().getServletContext().getRealPath("")

+4  A: 

By spec, the only "real" path you are guaranteed to get form a servlet container is a temp directory.

You can get that via the ServletContext.gerAttribute("javax.servlet.context.tempdir"). However, these files are not visible to the web context (i.e. you can not publish a simple URL to deliver those files), and the files are not guaranteed in any way to survive a web app or server restart.

If you simply need a place to store a working file for a short time, then this will work fine for you.

If you really need a directory, you can make it a configuration parameter (either an environment variable, a Java property (i.e. java -Dyour.file.here=/tmp/files ...), a context parameter set in the web.xml, a configuration parameter stored in your database via a web form, etc.). Then it's up to the deployer to set up this directory for you.

However, if you need to actually later serve up that file, you will either need a container specific mechanism to "mount" external directories in to your web app (Glassfish as "alternate doc roots", others have similar concepts), or you will need to write a servlet/filter to serve up file store outside of your web app. This FileServlet is quite complete, and as you can see, creating your own, while not difficult, isn't trivial to do it right.

Edit:

The basic gist is the same, but rather than using "getRealPath", simply use "getInitParameter".

So:

String filePath = getServletContext().getInitParameter("storedFilePath") + "/" + fileName;

And be on your way.

Edit again:

As for the contents of the path, I'd give it an absolute path. Otherwise, you would need to KNOW where the app server sets its default path to during exeuction, and each app server may well use different directories. For example, I believe the working directory for Glassfish is the config directory of the running domain. Not a particularly obvious choice.

So, use an absolute path, most definitely. That way you KNOW where the files will go, and you can control the access permissions at the OS level for that directory, if that's necessary.

Will Hartung
I need to store the files on a directory that can survive server and web-app restart. From you answer, I would like to make it a configuration parameter by setting a context parameter. But I didn't get how can I store file with that. Can you provide an example or a reference to an example?
Yatendra Goel
@Will You showed me how to retrieve the value of a context parameter which I know already. May be my comment was not clear. Actually, I meant what value would you give to the "storedFilePath" context parameter. A relative file path or absolute file path?
Yatendra Goel
If you give a relative path, the how will you convert it into absolute path?
Yatendra Goel
+2  A: 

Writing to the file system from a Java EE container is not really recommended, especially if you need to process the written data:

  • it is not transactional
  • it harms the portability (what if you are in a clustered environment)
  • it requires to setup external parameters for the target location

If this is an option, I would store the files in database or use a JCR repository (like Jackrabbit).

Pascal Thivent
@Pascal I want to store only a single file to be processed later. So I think that it would not be a good idea to store that file in the database? What do you think? The file is a .csv file. If you think that I should store it in the database, then should I store it in byte forms or any other form because the size of the file can be of 100 or 200 MBs. Second, I heard about "Jackrabbit" first time from you and I don't know what it is. I looked at its site but didn't find any tutorial. So could you please tell me which one would be better: using a database or using the "Jackrabbit"?
Yatendra Goel
@Yatendra I was underlying drawbacks of writing to the file system "for the record". For many applications, this might not be an option at all but is maybe not be a problem for your. Now, to answer your questions... 1) Writing to a database can be done (in a LOB); it's not ideal but if you don't write thousands of files per day, it should be ok. 2) Jackrabbit is an implementation of the JCR API (JSR-170), a standard API to write and store files to a content repository and is thus an alternative. But using a JCR repository sounds overkill for a small application. *I* would use the database.
Pascal Thivent