java how to access file in WEB-INF folder WITHOUT servlet context

siliconchris picture siliconchris · Oct 14, 2014 · Viewed 14k times · Source

I searched the internet since yesterday, but I seem unable to cope with the task at hand. I have a central class (RuntimeConfiguration) that holds around 100 parameters for my application. These parameters are taken from an XML file which I stored in the WEB-INF folder. On my development box I hard-coded the path, but for very obvious reasons, this is not a productive solution.

For portability reasons (my application might be executed on a tomcat or a jetty and under Windows OR Unix), I want to have a generic access way to this file from within my RuntimeConfiguration class.

I know, I can use getRealPath in case I have a servlet, BUT RuntimeConfiguration is NOT started within a servlet context. It is invoked from a job (a crawler) which in turn is started from quartz job control via applicationContext.xml. Now this seems to be the core of my problem.

Can anyone tell me, how to get the absolute path to my XML in this environment?

I tried this ClassLoader approach, but it gives me a null-pointer exception:

ClassLoader loader = this.getClass().getClassLoader();
loader.getResource("WEB-INF");
result = loader.getSystemResource(RTCF).toString(); 

I also tried

URL url = this.getClass().getClassLoader().getResource("WEB-INF");

which also throws a null pointer exception

Can anyone give me a portable solution, one that works on my dev-machine and on a production system where my application is deployed as a WAR-file??? By the way, the method should at best be able to handle Windows AND Mac OS X / Unix based systems.

Thabks in advance,

Christian

Answer

Serge Ballesta picture Serge Ballesta · Oct 14, 2014

You can always use the holder pattern : you create a class, with a static field (with its static getter) that will contain the real path of the WEB-INF directory. This class should implement ApplicationContextAware

You create in root spring application context an instance of this holder class, Spring give it a pointer to the ApplicationContext that will be a WebApplicationContext as you are in a web application.

In the init method, you use the WebApplicationContext to get the path and store it in the static field. Thanks to Spring, you are sure that the method is called once and only once before the application really starts.

Now anywhere in the application where you want to get the path, you can use it by calling the static getter.

public class ResourcePathHolder implements ApplicationContextAware, InitializingBean{
    private WebApplicationContext wac;
    private static String resourcePath;
    private static ServletContext sc;
    private String path = "WEB-INF";

    public static String getResourcePath() {
        return resourcePath;
    }

    public static ServletContext getServletContext() {
        return sc;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        wac = (WebApplicationContext) applicationContext;
    }

    public void setPath(String path) {
        this.path = path;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        ResourcePathHolder.sc = wac.getServletContext();
        ResourcePathHolder.resourcePath = sc.getRealPath(path);
    }
}

This implementation also gives you access to the ServletContext to allow you to use ServletContext.getResource()

EDIT :

Using the full path may not work on production servers that would not explode the war. From the javadoc for ServletContext.getRealPath() : This method returns null if the servlet container is unable to translate the given virtual path to a real path. But in that case, you can always access to the files as resources with ServletContext.getResource() or ServletContext.getResourceAsStream()