views:

50

answers:

4

I have a bunch of properties (configurations) that can change per environment. However these values do not change once the web application is deployed.So consider that there is an application.properties file that I want to read lots of times during normal program flow.

I know that I can probably load these at server startup time. However whats the best practice as far as accessing these from simple java classes at the backend? These business classes have nothing to do with servlets etc and have no dependencies on a webapp.

So today I load the properties via a ServletContext. Then what? Where should I keep them so as to be easily accessible to other objects without having to do a fileInputStream.load again?

Thanks.

+2  A: 

Implement a ServletContextListener.

Here's a basic kickoff example:

public class Config implements ServletContextListener {
    private static final String ATTRIBUTE_NAME = "config";
    private Properties config = new Properties();

    @Override
    public void contextInitialized(ServletContextEvent event) {
        try {
            config.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
        } catch (IOException e) {
            throw new SomeRuntimeException("Loading config failed", e);
        }
        event.getServletContext().setAttribute(ATTRIBUTE_NAME, this);
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        // NOOP.
    }

    public static Config getInstance(ServletContext context) {
        return (Config) context.getAttribute(ATTRIBUTE_NAME);
    }

    public String getProperty(String key) {
        return config.getProperty(key);
    }
}

which you register as follows in web.xml:

<listener>
    <listener-class>com.example.Config</listener-class>
</listener>

and which you can access in your servlets as follows:

Config config = Config.getInstance(getServletContext());
String property = config.getProperty("somekey");

After having a second thought, those properties are thus 100% specific to business layer, not to the webapplication itself? Then a ServletContextListener is indeed clumsy and too tight coupled. Just give the business layer its own Config class which loads the properties from the classpath and caches it in some static variable (Map<String, Properties> maybe?).

BalusC
Thank you for the response. Exactly what I am doing. Maybe I should have been clearer. I am trying to avoid using ServletContext or ServletContextListener in my domain objects. I want to store it in a POJO and access it. However i am grappling with whether to create a singleton properties object and load the properties there. Any ideas?
Kapsh
Use a (MVC) framework which supports the "application scoped bean" concept. Like JSF, Spring, etc. Else you really need to hassle with ServletContext yourself (which the average (MVC) framework by the way also is doing "under the hoods"). You could on the other hand also consider to declare the `Properties` `public static`, but this would not have my vote...
BalusC
A singleton is considerable, but just assigning the `Properties` as `static` variable in some class is also more than enough.
BalusC
Can you explain on why the static is a bad solution? I would hate to introduce a framework dependency to load config files...Mainly, I am trying to avoid ServletContext etc because the junit tests are a pain then for the business classes. Today I can test them quite merrily...
Kapsh
`static` + unit tests = aaaaargh!! Btw: a framework is not necessary to load config files. Just for the case you're already using one. Else just reinvent what the average framework already does. `ServletContextListener` and so on.
BalusC
I agree with the static issues. But I dont know a quick slap it in and get it to work type jar that I can include. I am using RESTEasy btw. I just dont have a good hook except for ServletContextListener. Any concrete example otherwise?
Kapsh
As long as you obtain the propertiesfile by the `ClassLoader` from `Thread#contextClassLoader()`, it should work regardless the way you use/include the JAR with domain objects. You can find [here](http://balusc.blogspot.com/2008/07/dao-tutorial-data-layer.html#PropertiesFileLoader) a concrete (basic) example I ever wrote.
BalusC
+1  A: 

You should have a static reference to these properties, and access them that way. You will end up reading them into memory once, and keeping them there. That way, you won't have to access the disk so many times at runtime.

So, suppose you have a class AppProperties:

public class AppProperties {
  private static Properties props;

  protected static loadProperties(File propsFile) {
    ... read from disk, and set props static member ...
  }

  public static getProperties() {
    return props;
  }
}

From your initializer servlet, you would call loadProperties to read the properties from disk. Then, in your application code, to access the properties:

String myProp = AppProperties.getProperties().getProperty("myProp");
pkaeding
Can you elaborate? Static reference from where?
Kapsh
Yeah, sorry, I meant to fill this answer out more from the beginning, but I got distracted by something in the "real world" :)
pkaeding
I guess this is in combination to the ServletContextListener that I have. It does seem to be the simplest solution at this time.
Kapsh
Yeah, the biggest benefit is that the business logic code only needs to reference the `AppProperties` class, and not anything that requires any JEE stuff. You can then have your unit test `setup` method initialize the properties, just like your ServletContextListener would normally.
pkaeding
A: 

Put your configuration classes/properties in a jar file, and put that jar file in WEB-INF/lib. Then you can access them through the normal classpath resource facilities whereever you need to in your web application.

Thorbjørn Ravn Andersen
A: 

You can use JNDI if your app server supports it.

See my question (and the answer) here: http://stackoverflow.com/questions/2775276/spring-deployment-level-configuration

Robert Wilson