Martin Nielsen
Martin Nielsen

Reputation: 2047

Application can't find properties file on Tomcat server

I am trying to get Tomcat to load an external property file, which exists outside the classpath of the WAR file.

I have simple class called PropertiesSingleton, which is supposed the load the properties file into a java.util.Properties object.

package my.test.properties;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class PropertiesSingleton {
    private static String filenameProperty = "testprops";
    private static IProperties properties;      //This is an interface that defines a number of get methods for each property
    private final static Logger log = LoggerFactory
        .getLogger(PropertiesSingleton.class);

    public static void main(String[] args) {
    IProperties props = PropertiesSingleton.load();
    }

    public static synchronized IProperties load() {
    InputStream stream;
    if (properties == null) {
        try {
        String propertyFileName = System.getProperty(filenameProperty);
        String variableFileName = System.getenv(filenameProperty);
        log.debug("Value of "+filenameProperty+" parameter: "+propertyFileName);
        log.debug("Value of "+filenameProperty+" env variable: "+variableFileName);
        PropertiesImpl props = new PropertiesImpl(); //A subclass of java.util.Properties implementing the IProperties interface
        if(propertyFileName != null && !propertyFileName.isEmpty()){
            File file = new File(propertyFileName);
            log.debug("Loading properties from parameter '"+propertyFileName+"'" + (file.exists() ? "" : ", which does not exist") );
            stream = new FileInputStream(file);
        }else if(variableFileName != null && !variableFileName.isEmpty()){
            File file = new File(variableFileName);
            log.debug("Loading properties from environment variable'"+variableFileName+"'"+ (file.exists() ? "" : ", which does not exist"));
            stream = new FileInputStream(file);
        }else{
            log.debug("Loading properties from properties file");
            stream = ClassLoader.getSystemClassLoader().getResourceAsStream("my/test/properties/test.properties");
        }
        if(stream == null){
            log.warn("Could not load the properties file");
            return props;
        }

        props.load(stream);
        properties = props;
        log.info("Loaded properties " + properties);
        } catch (IOException ex) {
        log.error("Could not load properties", ex);
        } catch (Exception ex) {
        log.error("Unexpected Error: Could not load properties", ex);
        throw ex;
        }
    }
    return properties;
    }

    public static synchronized IProperties reload(){
    properties = null;
    return load();
    }

}

This seems to work as intended when i add an Env property and run the main method thorough my IDE.

2015-05-26 09:17:02,136 DEBUG Value of testprops parameter: null
2015-05-26 09:17:02,139 DEBUG Value of testprops env variable: C:\test\test.properties
2015-05-26 09:17:02,141 DEBUG Loading properties from environment variable'C:\test\test.properties'
2015-05-26 09:17:02,141 INFO Loaded properties {defaultLocale=dk, host=123.123.123.123}

However, when i have the nerve to WAR package this code and run it on my local Tomcat8, i get a new and exciting message. (The tomcat WAR calls PropertiesSingleton.load at some point):

2015-05-26 09:17:02,136 DEBUG Value of testprops parameter: null
2015-05-26 09:17:02,139 DEBUG Value of testprops env variable: C:\test\test.properties
2015-05-26 09:17:02,141 DEBUG Loading properties from environment variable'C:\test\test.properties', which does not exist
2015-05-26 09:42:36,114 ERROR Could not load properties
java.io.FileNotFoundException: C:\test\test.properties (The system cannot find the file specified)

Is there some security feature in Tomcat that does now allow me to access my filesystem, or is something else horribly wrong?

I should also note that i am doing this exercise because i need an external properties file that resides well outside the WAR context on the Tomcat server. There are several reasons for this. For example, several applications will share configuration from another running application. A properties file inside the WAR will be crazy impractical. If someone knows of another way to read an external properties file from a WAR, that will also be graciously accepted as an answer.

Upvotes: 0

Views: 5400

Answers (1)

Bewusstsein
Bewusstsein

Reputation: 1621

Accessing the underlying file system is not supported by the servlet specification and is not guaranteed to work, especially if the access happens from an unexploded .war-file (I'm assuming that's what's happening in your case).

It makes your app dependent on the underlying system - OS, server etc. The recommended way is to package your configuration inside the .war-file.

If you must do it though (and i agree an external configuration can be a good idea), here's a more OS-independent way that should work, using a java.net.URL and the file: URI scheme:

URL url = new URL("file:///test/test.properties");

URLConnection con = url.openConnection();
ResourceUtils.useCachesIfNecessary(con);

InputStream stream = con.getInputStream();

Adapted from org.springframework.core.io.UrlResource.getInputStream(). If you can, use a library/framework like Spring and its Resource abstraction.

Upvotes: 1

Related Questions