Using Properties Files in Java Applications (And Autoload)
Properties files are one of the most frequently used mechanism for storing configuration information for applications. And so is the code to access these properties from the application. This article is intended to demonstrate (source code can be downloaded here) a simple way of configuring and using Properties files in Java applications.
Please note that, the mechanism is not limited to properties files. The approach supports XML configuration files as well.
The steps are defined below and as we move along, we’ll try and explain the rationale for each of the items:
1. Define System variable for properties file location. Define a system/environment variable that points to the folder, where the properties files will be placed. Finding the properties files through a system/environment variable is straight-forward and helps avoid the classpath issues often found using properties files in webapps. In cases where a system/environment variable cannot be defined, this variable can be passed to the application as an argument. For e.g., java –D APP_PROPS=d:/Properties App
Let’s say the environment variable is called APP_PROPS and it points to D:/Properties. For demonstration, let’s assume there’re two properties files:
a. app.properties
b. security.properties
2. The Properties Store. The properties store (class PropStore), will be used by the application code to fetch properties. For e.g., the following code reads the application title from the app.properties file.
String title = PropStore.getAppProps(“title”);
Let’s get into the code and see how the PropStore will be structured and how do we add new properties.
Structure. The properties store will have a static “Properties” field, for each “properties” file annotated with a custom annotation (PropertiesHolder, defined later). For e.g.,
public class PropStore {
@PropertiesHolder(file="app.properties", autoLoad=true)
private static Properties appProps;
@PropertiesHolder(file="security.properties")
private static Properties securityProps;
public static Properties getAppProps() {
return appProps;
}
public static Properties getSecurityProps() {
return securityProps;
}
protected static void setAppProps(Properties appProps) {
PropStore.appProps = appProps;
}
protected static void setSecurityProps(Properties securityProps) {
PropStore.securityProps = securityProps;
}
}
For now, assume, the properties appProps and securityProps are magically loaded. So, the following code sippet can be used in the application code to read securityProps:
String appUser = PropStore.getSecurityProps().getProperty("APP_USER");
To add another properties file, all that needs to be done is add a static field, annotate it with PropertiesHolder with the properties file name as the file attribute, and define a public getter.
3. PropertiesHolder. PropetiesHolder is a custom annotation, that we will use to annotate fields in the PropStore, and set the properties file that field will go against.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PropertiesHolder {
String file();
boolean autoLoad() default false;
}
4. Loading Properties. Properties file need to be loaded at application startup since the application code uses the properties files. We’ll load the properties using PropsLoader class as demonstrated below. PropsLoader can then be used by a startup class (a startup servlet in webapps, or a bootstrap class in a desktop application, for e.g.).
Here’s what the PropsLoader does to load the properties files:
i. Introspect the PropStore to get declared fields.
ii. Loop on the fields and check if the field is annotated with PropertiesHolder.
iii. If it is annotated with PropertiesHolder, create a “Properties” object and load the properties file (set with the file attribute of PropertiesHolder).
iv. Call the appropriate setter, on the PropStore with this “Properties” object.
v. Please note that if there’s a XML configuration file, another reading mechanism can be provided and a Properties object be built from that.
public class PropsLoader {
private static final String VAR_NAME = "APP_PROPS";
//TODO: Better Exception Handling
public static void load() throws Exception {
Field[] fields = PropStore.class.getDeclaredFields();
for(Field field:fields) {
if( field.isAnnotationPresent(PropertiesHolder.class) ) {
PropertiesHolder propsHolder = field.getAnnotation(PropertiesHolder.class);
loadPropsAndWatch( field.getName(), propsHolder );
}
}
}
//TODO: Better Exception Handling
private static void loadPropsAndWatch(String fieldName, PropertiesHolder propsHolder) throws Exception {
String propsFile = System.getProperty(VAR_NAME) + File.separator + propsHolder.file();
loadProperties(fieldName, propsFile);
if( propsHolder.autoLoad() ) {
PropsWatcherTask.watch( fieldName, propsFile, propsHolder );
}
}
//TODO: Better Exception Handling
protected static void loadProperties(String fieldName, String propsFile)
throws Exception {
String setterName = "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
Method setter = PropStore.class.getDeclaredMethod(setterName, Properties.class);
Properties props = new Properties();
props.load( new FileInputStream(new File(propsFile) ) );
setter.invoke(null, props);
}
}
5. Auto Load. Although, not an absolute essential, sometimes, the properties files need to be auto-loaded in case there’s a change while the application is running.
To auto load properties, the PropsWatcherTask:
a. Schedules itself to run every “x” minutes, and check the last modified time of the properties file to watch.
b. If the new modified timestamp is newer than the timestamp used to build the task, the properties file is reloaded and the local timestamp set accordingly.
public class PropsWatcherTask extends TimerTask {
private String propsFile;
private long lastMod;
private String fieldName;
private final static Timer timer = new Timer();
private static final long INITIAL_DELAY = 1000 * 60 * 5;
private static final long INTERVAL = 1000 * 60 * 5;
private PropsWatcherTask(long lastMod, String fieldName, String propsFileName) {
this.propsFile = propsFileName;
this.lastMod = lastMod;
this.fieldName = fieldName;
}
@Override
public void run() {
//check last modified time.
long newModTime = new File(propsFile).lastModified();
if( newModTime > lastMod ) {
try {
PropsLoader.loadProperties(fieldName, propsFile);
} catch (Exception e) {
e.printStackTrace();
}
this.lastMod = newModTime;
}
}
protected static void watch(String fieldName, String propsFileName, PropertiesHolder propsHolder) {
File propsFile = new File(propsFileName);
long lastMod = propsFile.lastModified();
timer.scheduleAtFixedRate( new PropsWatcherTask( lastMod, fieldName, propsFileName ) , INITIAL_DELAY, INTERVAL );
}
}
6. Test. The following simple JUnit can be used to test the PropsLoader for both auto load and otherwise.
public class PropStoreTest {
@Before
public void load() {
try {
PropsLoader.load();
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testProperties() throws Exception{
Assert.assertEquals("ABC Desktop", PropStore.getAppProps().getProperty("APP_TITLE"));
Assert.assertEquals("ADMIN", PropStore.getSecurityProps().getProperty("APP_USER"));
}
@Test
public void testAutoLoad() throws Exception {
write("APP_TITLE=New ABC Desktop");
synchronized(this) {
this.wait(45 * 1000);
}
Assert.assertEquals("New ABC Desktop", PropStore.getAppProps().getProperty("APP_TITLE"));
write("APP_TITLE=ABC Desktop");
}
private void write(String text) throws Exception {
PrintWriter pw = new PrintWriter( new FileWriter(System.getProperty("APP_PROPS") + File.separator + "app.properties"));
pw.print(text);
pw.close();
}
public static junit.framework.Test suite() {
return new JUnit4TestAdapter(PropStoreTest.class);
}
}
Note the PropsLoader.load() being called from the load method of PropStoreTest. The PropsLoader.load() call will generally be made from some startup class (like a startup servlet, etc). To run the test, make sure the APP_PROPS variable is passed as a JVM parameter, or is set in the system properties.
Click here to download the source code. Tester.zip contains the Tester folder, which can be directly imported into Eclipse. If you wish to run this with ant, use Tester/build/build.xml. (Please change the value for APP_PROPS on line 9 in build.xml).
<!--[endif]--><!--[if gte mso 9]> Normal 0 false false false MicrosoftInternetExplorer4 <![endif]--><!--[if gte mso 9]> <![endif]--> <!--[endif]-->
Properties files are one of the most frequently used mechanism for storing configuration information for applications. And so is the code to access these properties from the application. This article is intended to demonstrate a simple (Simple to use from the app and easy to maintain) way of configuring and using Properties files in Java applications.
Please note that, the mechanism is not limited to properties files. The approach supports XML configuration files as well.
The steps are defined below and as we move along, we’ll try and explain the rationale for each of the items:
<!--[if !supportLists]-->1. <!--[endif]-->Define System variable for properties file location. Define a system/environment variable that points to the folder, where the properties files will be placed. Finding the properties files through a system/environment variable is straight-forward and helps avoid the classpath issues often found using properties files in webapps. In cases where a system/environment variable cannot be defined, this variable can be passed to the application as an argument. For e.g., java –D APP_PROPS=d:/Properties App
Let’s say the environment variable is called APP_PROPS and it points to D:/Properties. For demonstration, let’s assume there’re two properties files:
<!--[if !supportLists]-->a. <!--[endif]-->app.properties
<!--[if !supportLists]-->b. <!--[endif]-->security.properties
<!--[if !supportLists]-->2. <!--[endif]-->The Properties Store. The properties store (class PropStore), will be used by the application code to fetch properties. For e.g., the following code reads the application title from the app.properties file.
String title = PropStore.getAppProps(“title”);
Let’s get into the code and see how the PropStore will be structured and how do we add new properties.
Structure. The properties store will have a static “Properties” field, for each “properties” file annotated with a custom annotation (PropertiesHolder, defined later). For e.g.,
<!--[if gte vml 1]> <![endif]--><!--[if !vml]--><!--[endif]-->
For now, assume, the properties appProps and securityProps are magically loaded. So, the following code sippet can be used in the application code to read securityProps:
String appUser =
PropStore.getSecurityProps().getProperty(“APP_USER”);
To add another properties file, all that needs to be done is add a static field, annotate it with PropertiesHolder with the properties file name as the file attribute, and define a public getter.
<!--[if !supportLists]-->3. <!--[endif]-->PropertiesHolder. PropetiesHolder is a custom annotation, that we will use to annotate fields in the PropStore, and set the properties file that field will go against.
<!--[if gte vml 1]> <![endif]--><!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->4. <!--[endif]-->Loading Properties. Properties file need to be loaded at application startup since the application code uses the properties files. We’ll load the properties using PropsLoader class as demonstrated below. PropsLoader can then be used by a startup class (a startup servlet in webapps, or a bootstrap class in a desktop application, for e.g.).
Here’s what the PropsLoader does to load the properties files:
<!--[if !supportLists]-->i. <!--[endif]-->Introspect the PropStore to get declared fields.
<!--[if !supportLists]-->ii. <!--[endif]-->Loop on the fields and check if the field is annotated with PropertiesHolder.
<!--[if !supportLists]-->iii. <!--[endif]-->If it is annotated with PropertiesHolder, create a “Properties” object and load the properties file (set with the file attribute of PropertiesHolder).
<!--[if !supportLists]-->iv. <!--[endif]-->Call the appropriate setter, on the PropStore with this “Properties” object.
<!--[if !supportLists]-->v. <!--[endif]-->Please note that if there’s a XML configuration file, another reading mechanism can be provided and a Properties object be built from that.
Below is the code snapshot that loads the properties.
<!--[if gte vml 1]> <![endif]--><!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->5. <!--[endif]-->Auto Load. Although, not an absolute essential, sometimes, the properties files need to be auto-loaded in case there’s a change while the application is running.
To auto load properties, the PropsWatcherTask:
<!--[if !supportLists]-->a. <!--[endif]-->Schedules itself to run every “x” minutes, and check the last modified time of the properties file to watch.
<!--[if !supportLists]-->b. <!--[endif]-->If the new modified timestamp is newer than the timestamp used to build the task, the properties file is reloaded and the local timestamp set accordingly.
<!--[if gte vml 1]> <![endif]--><!--[if !vml]--><!--[endif]-->
<!--[if !supportLists]-->6. <!--[endif]-->Testing. The following simple JUnit can be used to test the PropsLoader for both auto load and otherwise.
<!--[if gte vml 1]> <![endif]--><!--[if !vml]--><!--[endif]-->
Note the PropsLoader.load() being called from the load method of PropStoreTest. The PropsLoader.load() call will generally be made from some startup class (like a startup servlet, etc). To run the test, make sure the APP_PROPS variable is passed as a JVM parameter, or is set in the system properties.
The code is attached with this article. Tester.zip contains the Tester folder, which can be directly imported into Eclipse. If you wish to run this with ant, use Tester/build/build.xml. (Please change the value for APP_PROPS on line 9 in build.xml).
<!--[if gte vml 1]> <![endif]--><!--[if !vml]--><!--[endif]--><!--[if gte mso 9]> <![endif]-->