Configure your application using a properties file

When I first started out in programming, I made the same mistake I now see countless people make when starting.  I wrote code for me and that worked, and that was good enough for me.  As time passed and the code I produced expanded and became more ambitious so my bad habits became more ingrained.  I think it is something we all do; we all go through.  It is not until we encounter an issue, a reason to change, that we appreciate the error of our ways.  If we are fortunate we get an opportunity to work with other more worldly wise programmers who can help us adopt good habits; if not then we need hard lessons to alter our behaviour.

In my case, it was a hard lesson; the deployment of a web based application which hammered home the lesson.  To be fair it was not my code, and the deployment was to a test environment however, the problem was still of a significant magnitude to bring the lesson home to me.  As soon as we deployed the solution to the test server everything stopped working.  There was much debugging and checking of server deployment as the server was the only element which had altered.  It turned out that one of my colleagues had taken a short cut and typed the IP number of the development server into his code, intending to correct at a later date.  No one picked up this delicious oversight and of course, as soon as we moved to a different server everything ground to a halt.

If only we had put in place a standard way of defining values which might change over the development and deployment cycle we could have avoided the lost time.

So let us turn out attention to a solution to this, the use of a properties file.  As developers we can use a properties file to define values which our code needs access to but which might change when it comes to deployment.  This could be the location of resource files, application version numbers or a whole host of other information.  Here we are going to build a reusable Class which can be used in our Java programmes anytime we need flexible values.

To demonstrate this we will build a Java Class which handles accessing the properties file and retrieving the value associated with a key (label for the property).  All we have to do as a developer to use this is create a text file and place in the file a key and value pair.  We can then call the static method of the class and it returns us the value.  If the value in the file changes then so does the value returned to our program.

To start with we will power up Eclipse, the Java IDE we are using.  Next we create a Java project; I’ve call mine ‘Properties’.  We will start with building the class which will access the properties file.  Create a new class and call it AppProperties.  I placed mine in the package ‘softwarepulse.utils’.

package softwarepulse.utils;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;



/**
 * @author jmcneil
 * (c) copyright Software Pulse 2019
 */
public class AppProperties {
}

The idea for this class is that no matter where in the application you are you can access a property from the property file through the class.  So we will design it so that you do not need to create an instance of the class to use it but instead can ask the class to provide to you the instance of the class it holds.   The class has a private constructor which takes care of opening and reading the properties file.   This avoids the need to have a globally accessible variable.  You obtain the instance of the object using a call to the class static method.  Once you have an instance of the class you can call the getProperties method passing the key for which you want the value.

So turning back to the code for our class, we have class properties for the location and name of the properties file.  The class also has an instance of itself, a java utils properties object and a string to hold a message.  The location of the properties file is a string value and is also defined as final; we will not be changing this value at runtime.  The instance of this class is defined as static final so we will not be changing the instance of AppProperties once it is created and we will reference this variable via the class reference.  Next we have a properties object which will be used to hold the contents of the properties file in memory.  Lastly we have a message property which is a string value to hold a message.  This message property is set to a value when access to the properties file fails.

So our class now looks like this

package softwarepulse.utils;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;



/**
 * Singleton design pattern - simple
 * @author jmcneil
 * (c) copyright Software Pulse 2019
 */
public class AppProperties {
	private final String FILENAME = "app.properties";
	private static final AppProperties properties_file = new AppProperties();
	private Properties prop = new Properties();
	private String msg = "";
}

Next we can create the constructor for the class.  This will be a private constructor as only the class can reference this constructor.   The constructor uses a FileInputStream to access the file.  If there is an error then the ‘msg’ property is set to an error message and the error is sent to the Stack Trace.  Finally, irrespective of success or failure, the input stream is closed.  If we successfully open the file using the file input stream then we load the file contents into the java utils Properties object ready for processing as required.  The constructor is called when the class is first referenced and hence our instance is created.  Our constructor looks like this:

	private AppProperties() { 
		InputStream input = null;
	 
		try {
	 
			input = new FileInputStream(FILENAME);
	 
			// load a properties file
			prop.load(input);
	 
	 
		} catch (IOException ex) {
			msg = "Error accessing properties file!";
			ex.printStackTrace();
		} finally {
			if (input != null) {
				try {
					input.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}

There are now three methods to add all of which are public.  We will start with the static method.  This is the method we can call directly from the class object and is how we will get hold of the instance of the object.  The method is public static, returns an object of type AppProperties, is called getInstance and takes no arguments.  As the name suggests it returns an instance of this class.  More importantly it returns the same instance each time it is called.  For those of you interested in design patterns this is an example of an implementation of the simple singleton design pattern.  The getInstance method simply returns the class property properties_file which is an instance of the class.  The method looks like this:

	public static AppProperties getInstance() {
			return properties_file;
	}

Then there is the method to access the ‘msg’ property.  Once the instance of the class is obtained the getMsg method can be called to see if the ‘msg’ property contains any message.  If it does then this indicates the file was not successfully opened and therefore the property values are not available to the application.  The method is public, returns a String and takes no arguments.  The method looks like this:

	public String getMsg() {
		return msg;
	}

The last method in our class is the one where you actually get the values to the keys in the property file.  This is another public method which returns a String and is passed a String which is the key to find in the properties file.   The method looks like:

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

That completes the class we will use to access our properties file now we need to make use of the file.  I have created a simple application that displays a JFrame containing a JPanel with a number of JLabels each of which displays a value from the properties file.  The class to use our properties class is this:

package softwarepulse.app;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import softwarepulse.utils.AppProperties;

/**
 * @author jmcneil
 * (c) copyright Software Pulse 2019
 *
 */
public class App extends JFrame {
	
	private JPanel panelMain;
	private JPanel panelLeft;
	private JPanel panelRight;
	private JLabel labelAuthor;
	private JLabel labelCopyright;
	private JLabel labelTitle;
	//private JLabel labelDescription;
	private JLabel labelVersion;
	

	/**
	 * 
	 */
	public App() {
		super();
		panelMain = new JPanel( new BorderLayout(2,3) );
		panelMain.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20)); 

		panelLeft = new JPanel( new GridLayout(4, 1, 2, 10));
		panelLeft.add(new JLabel("Title: ", JLabel.LEFT));
		panelLeft.add(new JLabel("Author: ", JLabel.LEFT));
		panelLeft.add(new JLabel("Version: ", JLabel.LEFT));
		panelLeft.add(new JLabel("Copyright: ", JLabel.LEFT));
		
		labelAuthor = new JLabel(AppProperties.getInstance().getProperty("Application_author"),JLabel.RIGHT );
		labelCopyright = new JLabel(AppProperties.getInstance().getProperty("Application_copyright"),JLabel.RIGHT);
		labelTitle = new JLabel(AppProperties.getInstance().getProperty("Application_title"),JLabel.RIGHT);
		labelVersion = new JLabel(AppProperties.getInstance().getProperty("Application_version"),JLabel.RIGHT);
		
		panelRight = new JPanel( new GridLayout(4, 1, 2, 10));
		panelRight.add(labelTitle);
		panelRight.add(labelAuthor);
		panelRight.add(labelVersion);
		panelRight.add(labelCopyright);
		
		panelMain.add(panelLeft, BorderLayout.WEST);
		panelMain.add(panelRight, BorderLayout.EAST);
		panelMain.add(new JLabel(""), BorderLayout.NORTH);
		panelMain.add(new JLabel(""), BorderLayout.SOUTH);
		
		this.getContentPane().setLayout(new GridLayout(1, 3, 3, 3));
		add(panelMain);
		this.pack();
		
        setTitle(AppProperties.getInstance().getProperty("Application_name"));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}



	/**
	 * @param args
	 */
	public static void main(String[] args) {

		AppProperties appProperties = AppProperties.getInstance();
		if( appProperties.getMsg().length() > 0 ) {
			System.exit(0);
		}

		EventQueue.invokeLater(new Runnable() {
			public void run() {
				App app = new App();

		        app.setVisible(true);
		        app.pack();
			}
		});
	}
}

Finally we create a properties file for the application to access.  Now in our AppProperties class we specified that our properties file would be called ‘app.properties’ therefore we need to ensure we call our properties file the same thing.  We also chose not to specify a directory path before the file name so the application will look for the file in the root directory of our application; in Eclipse that will be under the project folder.

The file itself is a simple text file, the contents of which is this:

Application_name=Properties file
Application_title=Using Properties file
Application_version=version 1.0.3.0
Application_author=John McNeil
Application_copyright=(c) Copyright 2019

As you can see each line has a key, followed by the equals sign and then the value to use.  You can add as many key and value pairs as you require.  When it comes to deployment these values can be changed to suit the environment to which you are deploying.   I find this a useful tool when build applications as there is always something that needs changing during the development process.

 

The full code for this example can be downloaded from here (email address required)

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.