Robert Rogers
Robert Rogers

Reputation: 63

Where to store properties from properties file in java webapp

Not sure if this question was previously asked, but I cannot seem to find the answer.

Where does one store the properties when loaded in a webapp. I have a web application which has settings to allow system administrators via a user interface to change settings in the app.

For example the app allows only selected user groups to be able to go a certain page. I wanted to allow system admins to go in and set the user groups that can go to the above mentioned page, and then change it at a later date.

The issue I'm facing is that once loaded the properties file, where do I store the data rather than continuously loading the properties file each time a user goes into the page.

I'm probably not getting the full concept of how properties are used so any guidance would be greatly appreciated.

Just make sure I can read the user groups in, can change the user groups without reloading the class/app and allow it to be thread safe and quick without two different threads having two different properties because we are using a load balanced environment. With a content share which is where the properties files are stored and accessed (not having any issues with this so not looking for help with where to store the properties file).

Any help greatly appreciated.

EDIT 1

The application runs on a clustered environment which means that other application servers could potentially have different values due to multiple ServletContexts.

Upvotes: 3

Views: 3555

Answers (3)

Braj
Braj

Reputation: 46881

Register ServletContextListener to load Init parameters and properties at server start-up.

Load properties at single time and make it visible to other classes statically or you can store it in application context as well to access it from anywhere such as JSP and Servlet.

Note: Make the properties file location configurable in web.xml rather than hard-coding it in Java class. You can retrieve the properties file location as system environment variable as well.

Sample code:

public class AppServletContextListener implements ServletContextListener {
    private static Properties properties;
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        String cfgfile = servletContextEvent.getServletContext().getInitParameter("config_file");
        properties.load(new FileInputStream(cfgfile));

        // store it in application scope as well
        servletContextEvent.getServletContext().setAttribute("prop",properties);
    }
    
    public static Properties getProperties(){
        return properties;
    }
}

web.xml:

<listener>
    <listener-class>com.x.y.z.AppServletContextListener</listener-class>
</listener>

<context-param>
      <param-name>config_file</param-name>
      <param-value>config_file_location</param-value>
</context-param>

Please have a look at my another post that is asked in the same context:


EDIT

If you are changing the properties at run-time then don't use Servlet context according to the ServletContext javadoc:

In the case of a web application marked "distributed" in its deployment descriptor, there will be one context instance for each virtual machine. In this situation, the context cannot be used as a location to share global information (because the information won't be truly global). Use an external resource like a database instead.

The Servlet specification also states in "SRV.4.4.1 Context Attributes in a Distributed Container":

Context attributes are local to the JVM in which they were created. This prevents ServletContext attributes from being a shared memory store in a distributed container. When information needs to be shared between servlets running in a distributed environment, the information should be placed into a session (See Chapter SRV.7, “Sessions”), stored in a database, or set in an Enterprise JavaBeansTM component.

In that case you can try with some third party cache that works in distributed environment as well as mentioned below:

OR store all the properties in the database.

Upvotes: 1

NickJ
NickJ

Reputation: 9579

The Servlet container offers the concept of Contexts. I find it helpful to consider a Context as a useful box for storing things in, and operates like a Map.

There are a number of different Contexts available to a Java Webapp, and they differ in scope (that is, how long the data held in the context lasts for, and where it can be accessed from). There is the Page Context, the Session Context and the Servlet Context

The Page Context has the narrowest scope, and is only lasts as long as a single page takes to process.

The Session Context has a greater scope, and lasts as long as single user session, i.e. multiple requests from a browser. It is useful if your webapp requires authentication - information about the authenticated user will be stored in the Session Context.

The Servlet Context is effectively global and is always available to the whole application. This is where I would recommend storing configuration properties which effect the functioning of the application.

In a Servlet, you may access the Servlet Context like this:

ServletContext context = request.getSession().getServletContext();

You can store something in the context like this:

context.setAttribute("key", object);

Where key is a String - the name of the attribute.

You may retrieve it again like this:

object = context.getAttribute("key");

Which returns an Object. You may cast it to whatever type it really is. If you want to, you can store a Properties object in it:

Properties props = //... get the properties from file
context.setAttribute("props", props);

And then retrieve them:

Properties props = (Properties) context.getAttribute("props");

Or you can store the individual properties as separate attributes in the context.

All contexts are accessed the same way.

Upvotes: 1

Smutje
Smutje

Reputation: 18173

You could go with the classic singleton pattern, where you have a single ApplicationProperties class which holds globally valid values for your application backed by a property file so no part of your application has to care about how to store the properties. Pseudo code:

public class ApplicationProperties {

    private static final String PATH = "app.properties";

    private static final ApplicationProperties INSTANCE = new ApplicationProperties();

    private String userGroup;

    private ApplicationProperties() {
        // Load properties from PATH and populate fields.
        this.userGroup = ...
    }

    public static ApplicationProperties getInstance() {
        return INSTANCE;
    }

    public String getUserGroup() {
        return this.userGroup;
    }

    public String setUserGroup(String userGroup) {
        // Save to property file to persist.
        this.userGroup = userGroup;
    }
}

You just have to synchronize access to the fields that no two threads overwrite properties and create race conditions.

Upvotes: 0

Related Questions