ClassLoader in JAR file not loading config file properly

Hi all,

I have an application that I am going to deploy using JavaWS, and everything works fine except for one little hitch. I have a configuration file, nvacconfig, located at NVAC.jar/config/nvacconfig. I'm trying to load this file into my application using a ClassLoader, but it does not seem to be working.

I have a method from a certain class that loads the configuration file. The class is not important, as it is part of an API that I cannot alter. This class has a load(String file) method, that loads the specified configuration file with a String argument. This works fine when I run my application from the command line and when the configuration file is not located in the JAR, but I need to include this configuration file in my JAR, so I can run my app in the JWS sandbox.

To load the file when it is NOT inside a JAR, and is simply located at config/nvacconfig, I just use:

id.properties.load("config/nvacconfig");

and it loads the configuration file, nvacconfig.

When I include the file in my JAR and try to load it using a ClassLoader, it does not seem to work, and the load method cannot find the file. This is how I am trying to accomplish this:

ClassLoader cl = this.getClass().getClassLoader();

URL url = cl.getResource("config/nvacconfig");

String file = url.toString();//I have also tried String file = url.getFile();

id.properties.load(file);

This does not work, and I'm not sure why.

Is there something I am doing wrong? Is this the wrong way to go about this?

Any advice would be greatly appreciated.

Thanks,

Dan

Message was edited by:

Djaunl

[1763 byte] By [Djaunla] at [2007-11-27 4:36:19]
# 1

If it helps, this is the part of the API that describes the load() method:

?load

This operation accepts a pathname to a configuration file and initializes the property set from that file. If the specified file cannot be read (for example, because it does not exist or the caller does not have read permission), the oper璦tion throws a FileException.

Also, the path that I print of the file is:

file:/T:/apache-tomcat-6.0.9/webapps/kdb/NVACdist/NVAC.jar!/config/nvacconfig

The first part of the path (everything up to "NVAC.jar!") changes according to where the JAR file is located on my filesystem.

Message was edited by:

Djaunl

Djaunla at 2007-7-12 9:46:29 > top of Java-index,Java Essentials,Java Programming...
# 2

> This class has a load(String file) method, that loads the specified

> configuration file with a String argument.

Here's your problem. Your configuration isn't in a File. I imagine your API that you can't alter is trying to feed that string into a FileInputStream, or something like that. Ain't gonna work. You need to call the ClassLoader's getResourceAsStream() method and pass the resulting InputStream to the API's load(InputStream) method.

After suitably repairing the bad design inherent in that API, if it really only accepts input from a File and nothing else, that is.

DrClapa at 2007-7-12 9:46:29 > top of Java-index,Java Essentials,Java Programming...
# 3
Here are 2 resources which should help you out: http://rachel.sourceforge.net/tutorial.html http://forum.java.sun.com/thread.jspa?threadID=278932&messageID=1470568
Dalzhima at 2007-7-12 9:46:29 > top of Java-index,Java Essentials,Java Programming...
# 4

Edit: or if that "properties" variable contains a java.util.Properties object, then create your own and assign it to that variable:Properties props = new Properties();

InputStream input = cl.getResourceAsStream("config/nvacconfig");

props.load(input); // catch IOException

input.close(); // in a finally block

id.properties = props;

DrClapa at 2007-7-12 9:46:29 > top of Java-index,Java Essentials,Java Programming...
# 5

try this:

import java.io.*;

import java.util.jar.*;

import java.util.zip.*;

public class ExtractFromJAR {

public void extractFileFromJAR(String dest, String fileName) {

try {

String home = getClass().getProtectionDomain().getCodeSource().getLocation().getPath().replaceAll("%20",

" ");

JarFile jar = new JarFile(home);

ZipEntry entry = jar.getEntry(fileName);

File efile = new File(dest, entry.getName());

InputStream in = new BufferedInputStream(jar.getInputStream(entry));

OutputStream out = new BufferedOutputStream(new FileOutputStream(efile));

byte[] buffer = new byte[2048];

for (;;) {

int nBytes = in.read(buffer);

if (nBytes <= 0)

break;

out.write(buffer, 0, nBytes);

}

out.flush();

out.close();

in.close();

} catch (Exception e) {

e.printStackTrace();

}

}

public static void main(String args[]) {

new ExtractFromJAR().extractFileFromJAR(".", "file.txt");

}

}

java_2006a at 2007-7-12 9:46:29 > top of Java-index,Java Essentials,Java Programming...
# 6

Hey guys,

Sorry for keeping you hanging. I just heard back from one of the designers of the API, who said, "No it's currently not possible to automatically load the configuration file from the Jar file".

I guess that takes the wind right out of my sails.

Thanks for the replies though, as they were informative, and they will definitely help in the future.

Djaunla at 2007-7-12 9:46:29 > top of Java-index,Java Essentials,Java Programming...
# 7

> Sorry for keeping you hanging. I just heard back from

> one of the designers of the API, who said, "No it's

> currently not possible to automatically load the

> configuration file from the Jar file".

Too bad about that. But take it as a design lesson -- if you ever have to design an API that reads properties files (or any input file, really), design it so its primary signature is "read(InputStream)". Then you can provide overloaded methods like "read(File)" and "read(URL)" and "read(String)" and so on.

DrClapa at 2007-7-12 9:46:29 > top of Java-index,Java Essentials,Java Programming...
# 8

> > Sorry for keeping you hanging. I just heard back

> from

> > one of the designers of the API, who said, "No

> it's

> > currently not possible to automatically load the

> > configuration file from the Jar file".

>

> Too bad about that. But take it as a design lesson --

> if you ever have to design an API that reads

> properties files (or any input file, really), design

> it so its primary signature is "read(InputStream)".

> Then you can provide overloaded methods like

> "read(File)" and "read(URL)" and "read(String)" and

> so on.

I definitely will.

Thanks a lot for your help.

Djaunla at 2007-7-12 9:46:29 > top of Java-index,Java Essentials,Java Programming...