-1

I want to create a class that wraps Properties and specifically hides the file I/O operations. I have come up with the abridged code below. This is intended to read the properties from a file at a fixed location outside of the class path. It also has a method to write the properties to the same file.

    //
 /* Defines key properties of the iFlag application.
  * Methods read and write properties.
 */

public  class ClientProperties {
    private Properties props;
    private static String xPanelSizeStg = "32"; 
    private static int    xPanelSize = 32;
    private static String configFilename = "/home/myname/config/client_config.properties";  

    public ClientProperties() {
        props = new Properties();
    }


  /**
     * Reads properties from file
     * Reads the current properties object from file.
     * The file is stored in /home/mimibox/config/flag_config.properties
     */            

    public  Properties readPropertiesFromFile( ){
        // create and load default properties
        InputStream input = null;
        logger.trace("Read flag config properties.");
        try {
            input = new FileInputStream( configFilename );
            //load a properties file from class path, inside static method     
            props.load(input);
            //get the property values and save
            xPanelSizeStg =  props.getProperty("xPanelsize","32");
            yPanelSizeStg =  props.getProperty("yPanelsize", "32");
         } 
        catch (IOException ex) {
            logger.error("Could not open config file" + configFilename,ex );
        } 
        finally{
            if(input!=null){
                try {
                  input.close();
                } 
                catch (IOException e) {
                logger.error( "Could not close config file" + configFilename,e );
                }
            }
        }
        return props;
    }
    /**
     * Writes properties to file
     * Writes the current properties object to file.
     * The file is stored in /home/mimibox/config/flag_config.properties
     */

    public void writePropertiesToFile() {
   //saves the current properties to file.  Overwrites the existing properties.
    Properties props = new Properties(); //a list of properties
    OutputStream outStrm = null;
    logger.info("Writing default flag config properties.");
                 System.out.println("Panel size x = " + xPanelSizeStg );
    try {
        outStrm = new FileOutputStream( configFilename );
        // set the properties values
        props.setProperty("xPanelsize", xPanelSizeStg);
        props.setProperty("yPanelsize", yPanelSizeStg);
         // save properties to file, include a header comment 
        props.store(outStrm, "This is the Server configuration file");

        } catch (IOException io) {
            logger.error( "The file :{0} could not be opened", configFilename,io);
        } finally {
            if (outStrm!= null) {
                try {
                    outStrm.close();
                } catch (IOException e) {
                  logger.error("The file :{0} could not be closed", configFilename, e);
                }
            }
        }
    } 
}

The read and write methods work. What doesn't work is trying to change the value of a property, and then save it. The demo code below successfully reads the properties file and displays the correct value for XPanelsize. I then change that value and attempt to write the properties to a file. The new value 64 for xPanelsize is not written to the file.

    public static void main(String[] args) {
    Properties props;
    ClientProperties p = new ClientProperties();
    props = p.readPropertiesFromFile(); 
    String txt = props.getProperty("xPanelsize");
         System.out.println("Panel size x = " + txt );
    p.setProperty("xPanelsize","64");  //method not found error
    p.writePropertiesToFile();

So I would like to be able to use the Property.setProperty() method to set the value of a property. When I do that, the changed property is not written to the file. I can see that is because I have more than 1 Property instance and one is not visible to the other. I think I need to extend the built-in Properties class to achieve what I want to do, but I am not sure how to make it all work.

I have found plenty of examples of using Properties on the internet. What I haven't found are any examples that hide the related file I/O in a class. How would I do that??

dazz
  • 119
  • 2
  • 14
  • 1. Yoy should call props.setProperty() instead of p.setProperty(). 2. U are overriding the same key "xPanelsize" in method writePropertiesToFile() with old value, so it is not getting reflected. – Hemant Patel Sep 24 '17 at 03:10
  • Are you aware of `java.util.ResourceBundle`? – user207421 Sep 24 '17 at 08:01
  • Only vaguely. Not well enough to consider using it. – dazz Sep 24 '17 at 08:34
  • @dazz Not well enough to consider using it as against completely re-implementing it? There is a hint here: *get* aware of it. It is the solution to your problem. It wraps `Properties`, and it hides the I/O from you. – user207421 Sep 24 '17 at 10:02

3 Answers3

1

OK so thanks to the comments and answers above, I have made a number of changes. For the benefit of those that stumble upon this post, I have posted the working code in this answer. The main change is to extend Properties. This allows me to use the Properties methods directly.

package com.test;

import java.util.Properties;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;

public  class ClientProperties  extends Properties {

    //initiate  logger

    private final static Logger logger = LogManager.getLogger();

    private static String xPanelSizeStg = "32";   
    private static String yPanelSizeStg = "32"; 
    private final configFilename = "/home/myname/myConfig.properties";

    public ClientProperties() {

    }


    public  Properties readPropertiesFromFile( ){
        // create and load default properties
        InputStream input = null;
        logger.trace("Read flag config properties.");
        try {
            input = new FileInputStream( configFilename );
            //load a properties file from class path, inside static method     
            this.load(input);
            //get the property values and save
            xPanelSizeStg =  this.getProperty("xPanelsize","32");
            yPanelSizeStg =  this.getProperty("yPanelsize", "32");
        } 
        catch (IOException ex) {
            logger.error("Could not open config file" + configFilename,ex );
        } 
        finally{
            if(input!=null){
                try {
                  input.close();
                } 
                catch (IOException e) {
                logger.error( "Could not close config file" + configFilename,e );
                }
            }
        }
        return this;
    }

    public void writePropertiesToFile() {
   //saves the current properties to file.  Overwrites the existing properties.
    //Properties props = new Properties(); //a list of properties
    OutputStream outStrm = null;
    logger.info("Writing default flag config properties.");
                 System.out.println("Panel size x = " + xPanelSizeStg );
    try {
        outStrm = new FileOutputStream( configFilename );
        // save properties to file, include a header comment 
        this.store(outStrm, "This is the Server configuration file");

        } catch (IOException io) {
            logger.error( "The file :{0} could not be opened", configFilename,io);
        } finally {
            if (outStrm!= null) {
                try {
                    outStrm.close();
                } catch (IOException e) {
                  logger.error("The file :{0} could not be closed", configFilename, e);
                }
            }
        }
    } 
}

I have relied on the Properties parent to initiate Properties which I have accessed with "this". So now main looks like:

public static void main(String[] args) {

    ClientProperties p = new ClientProperties();
    p.readPropertiesFromFile(); 
    String txt = p.getProperty("xPanelsize");
         System.out.println("Panel size x = " + txt );
    p.setProperty("xPanelsize","64");
    p.writePropertiesToFile();


}

The class now hides all the admin around reading, writing and files. Crucially it avoids writing a setter/getter for each property (and I have a lot more properties than the two shown here). That is what I had in my first version.

Thanks for your help. It would have taken me a long time to figure all this out by myself.

dazz
  • 119
  • 2
  • 14
0

You should probably need to create a getter for your 'props' object.

public Properties getProps()
{
    return props;
}

And you will be able to invoke it like this:

p.getProps().setProperty("key", "value");

Or, if you are planning to make your ClientProperties class a children of Properties class, then you will need to use 'extends' and you would be able to invoke it by using

p.setProperty("key", "value");

And in this case you wouldn't need any Properties object in your class' fields.

  • OK, based on my very limited knowledge, extending Properties sounds like the best option. I will have a go at making the changes. – dazz Sep 24 '17 at 03:57
  • I ticked this as the answer because this gave me the info I needed to write working code. The working code is provided in my answer for the benefit of others. – dazz Sep 24 '17 at 08:04
0

This is my suggestion for your example.

First, you don't need to be edit again the properties in your writePropertiesToFile method like this:

public void writePropertiesToFile() {
    // saves the current properties to file. Overwrites the existing properties.
    // Properties props = new Properties(); // a list of properties
    OutputStream outStrm = null;
    logger.info("Writing default flag config properties.");
    logger.debug("Panel size x = " + xPanelSizeStg);
    try {
        outStrm = new FileOutputStream(configFilename);
        // set the properties values
        //props.setProperty("xPanelsize", xPanelSizeStg);
        //props.setProperty("yPanelsize", yPanelSizeStg);
        // save properties to file, include a header comment
        props.store(outStrm, "This is the Server configuration file");

    } catch (IOException io) {
        logger.error("The file :{0} could not be opened", configFilename, io);
    } finally {
        if (outStrm != null) {
            try {
                outStrm.close();
            } catch (IOException e) {
                logger.error("The file :{0} could not be closed", configFilename, e);
            }
        }
    }
}

Then, you just create a setProperty method using the global variable -props- in the class.

private void setProperty(String key, String value) {
   this.props.setProperty(key, value);
}

If your property file looks like image below:

enter image description here

The value of xPanelsize should be changed after running application.

public static void main(String[] args) {
    Properties props = null;
    ClientProperties p = new ClientProperties();
    props = p.readPropertiesFromFile();
    String xPanelsize = props.getProperty("xPanelsize");
    System.out.println("Panel size x = " + xPanelsize);
    p.setProperty("xPanelsize", "64"); // method not found error

    p.writePropertiesToFile();

    props = p.readPropertiesFromFile();
    xPanelsize = props.getProperty("xPanelsize");
    System.out.println("So, now the Panel size x = " + xPanelsize);
}

The debug message is, enter image description here

The property file contents will be:

enter image description here

Here is full source:

package stackoverflow;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import java.util.logging.Level;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/* Defines key properties of the iFlag application.
 * Methods read and write properties.
*/

public class ClientProperties {
    Logger logger = LoggerFactory.getLogger(ClientProperties.class.getSimpleName());
    private Properties props;
    private String xPanelSizeStg;
    private String yPanelSizeStg;
    private int xPanelSize;
    private int yPanelSize;
    // private static String configFilename =
    // "/home/myname/config/client_config.properties";
    private static String configFilename = "resource/client_config.properties";

    public ClientProperties() {
        props = new Properties();

        xPanelSizeStg = "32";
        yPanelSizeStg = "32";
        xPanelSize = 32;
        yPanelSize = 32;
    }

    /**
     * Reads properties from file Reads the current properties object from file. The
     * file is stored in /home/mimibox/config/flag_config.properties
     */

    public Properties readPropertiesFromFile() {
        // create and load default properties
        InputStream input = null;
        logger.trace("Read flag config properties.");
        try {
            input = new FileInputStream(configFilename);
            // load a properties file from class path, inside static method
            props.load(input);
            // get the property values and save
            xPanelSizeStg = props.getProperty("xPanelsize", "32");
            yPanelSizeStg = props.getProperty("yPanelsize", "32");
        } catch (IOException ex) {
            logger.error("Could not open config file" + configFilename, ex);
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    logger.error("Could not close config file" + configFilename, e);
                }
            }
        }
        return props;
    }

    /**
     * Writes properties to file Writes the current properties object to file. The
     * file is stored in /home/mimibox/config/flag_config.properties
     */

    public void writePropertiesToFile() {
        // saves the current properties to file. Overwrites the existing properties.
        // Properties props = new Properties(); // a list of properties
        OutputStream outStrm = null;
        logger.info("Writing default flag config properties.");
        logger.debug("Panel size x = " + xPanelSizeStg);
        try {
            outStrm = new FileOutputStream(configFilename);
            // set the properties values
            //props.setProperty("xPanelsize", xPanelSizeStg);
            //props.setProperty("yPanelsize", yPanelSizeStg);
            // save properties to file, include a header comment
            props.store(outStrm, "This is the Server configuration file");

        } catch (IOException io) {
            logger.error("The file :{0} could not be opened", configFilename, io);
        } finally {
            if (outStrm != null) {
                try {
                    outStrm.close();
                } catch (IOException e) {
                    logger.error("The file :{0} could not be closed", configFilename, e);
                }
            }
        }
    }

    private void setProperty(String key, String value) {
        this.props.setProperty(key, value);
    }

    public int getxPanelSize() {
        return this.xPanelSize;
    }

    public void setxPanelSize(int xPanelSize) {
        this.xPanelSize = xPanelSize;
    }

    public int getyPanelSize() {
        return yPanelSize;
    }

    public void setyPanelSize(int yPanelSize) {
        this.yPanelSize = yPanelSize;
    }

    public static void main(String[] args) {
        Properties props = null;
        ClientProperties p = new ClientProperties();
        props = p.readPropertiesFromFile();
        String xPanelsize = props.getProperty("xPanelsize");
        System.out.println("Panel size x = " + xPanelsize);
        p.setProperty("xPanelsize", "64"); // method not found error

        p.writePropertiesToFile();

        props = p.readPropertiesFromFile();
        xPanelsize = props.getProperty("xPanelsize");
        System.out.println("So, now the Panel size x = " + xPanelsize);
    }

}
tommybee
  • 2,409
  • 1
  • 20
  • 23