1

When a third-party library I'm using tries to access a file, I'm getting "Error opening ... file ... (No such file or directory)" even though I KNOW the file is in the WAR. I've tried both packaged (.war) and "exploded" (directory) deployment, and the file is definitely there. I've tried setting full permissions on it too. It's on Unix (Ubuntu). File is war/dict/index.sense and the error is "dict/index.sense (No such file or directory)".

It works fine on my Windows computer when running in hosted mode as a GWT app from Eclipse, just not when I transfer it to the Unix machine for deployment.

My question is: has anybody experienced this before and/or are there differences in relative path that I should consider i.e. what's the root path for relative file access in a war?

Navigateur
  • 1,852
  • 3
  • 23
  • 39
  • 2
    show us some code (that hopefully includes servletContext.getRealPath) – Thilo Dec 27 '10 at 13:03
  • It's a third-party library that's trying to access the file. So I don't have control over how it does it. The only code I put is "System.setProperty("wordnet.database.dir", "dict");" as per their instructions on using their library. – Navigateur Dec 27 '10 at 13:22

2 Answers2

8

You should never rely on relative paths in file IO while reading a resource. The working directory is namely dependent on the way how the application is started. You have total no control over this. Always use absolute paths in file IO.

The normal approaches are:

  • Put the resource in the classpath or add its path to the classpath. Then you can obtain it by the classloader as follows:

    String classPathLocation = "filename.ext";
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    InputStream input = classLoader.getResourceAsStream(classPathLocation);
    // ...
    

    Note the way how the classloader and the resource is obtained. You should not obtain it from the current class like as getClass().getResourceAsStream(). In a WAR there is namely possibly means of multiple classloaders. The classloader of the current class might not know about the desired resource per se, the context one will.

  • Put the resource in webcontent (there where the WEB-INF folder is and all other public web resources). Then you can obtain its absolute path as follows which you can just continue to use in the usual file IO code:

    String relativeWebPath = "/filename.ext";
    String absoluteDiskPath = getServletContext().getRealPath(relativeWebPath);
    InputStream input = new FileInputStream(absoluteDiskPath);
    // ...
    

    Note that this only works when the WAR is expanded, else it will just return null.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
0

I owe this answer to BalusC, but since I didn't really understand it at first, I simplified it:

The working directory (the starting point for relative paths) depends on the way the application is started, so you don't really have control over this. Luckily there's a way to get the absolute path of anything in your web application's root directory, which is as follows:

getServletContext().getRealPath("pathToAnyFileInYourWebAppDocumentRoot.ext")

(This gives a String)

That's all you have to do. Unfortunately this only works when your app is deployed as a directory, not as a .war file (where it will return null).

(See BalusC's answer for another way, and where this answer came from).

Navigateur
  • 1,852
  • 3
  • 23
  • 39