3
\$\begingroup\$

I was attempting to implement my first singleton using an enum, was a bit of a struggle for me and I'm not sure if its right and more importantly thread safe?

Property provider enum:

public enum PropertyProvider implements CanProvideProperties {

    INSTANCE;
    private final HashMap<String, String> properties;

    PropertyProvider() {
        properties = buildSettingsMap();
    }

    @Override
    public HashMap<String, String> getAllProperties() {
        return properties;
    }

    @Override
    public String getProperty(Property prop) {
        return properties.get(prop.toString());
    }

    @Override
    public HashMap<String, String> buildSettingsMap() {
        HashMap<String, String> temp = new HashMap<>();
        Properties prop = new Properties();
        try {
            prop.load(readFile("src/test/resources/framework.properties"));
        } catch (IOException ignore) {
            throw new RuntimeException("Framework properties file non accessible");
        }

        Enumeration<Object> KeyValues = prop.keys();
        while (KeyValues.hasMoreElements()) {
            String key = (String) KeyValues.nextElement();
            String value = prop.getProperty(key);
            temp.put(key, System.getProperty(key, value));
        }
        return temp;
    }

    @Override
    public FileInputStream readFile(String file) throws FileNotFoundException {
        return new FileInputStream(new File(file));
    }

}

Which implements the following interface:

public interface CanProvideProperties {
    String getProperty(Property prop);
    HashMap<String, String> getAllProperties();
    HashMap<String, String> buildSettingsMap();
    FileInputStream readFile(String file) throws FileNotFoundException;

}

and lastly another enum to hold some settings:

public enum Property {
    BROWSER {
        @Override
        public String toString() {
            return "browser";
        }
    },

    TESTENVIRONMENT {
        @Override
        public String toString() {
            return "env.baseurl";
        }
    },

    GRIDADDRESS {
        @Override
        public String toString() {
            return "grid.endpoint";
        }
    },

    LOCALORGRID    {
        @Override
        public String toString() {
        return "grid.or.local";
    }
    },

    PLATFORM {
        @Override
        public String toString() {
            return "platform";
        }
    },

    LANGUAGE {
        @Override
        public String toString() {
            return "application.language";
        }
    },

    PRODUCTNAME {
        @Override
        public String toString() {
            return "product.name";
        }
    },

    DATABASEURL {
        @Override
        public String toString() {
            return "database.url";
        }
    },

    BASEADMINACCOUNT {
        @Override
        public String toString() {
            return "base.admin.account";
        }
    },

    BASEADMINUSERNAME {
        @Override
        public String toString() {
            return "base.admin.username";
        }
    },

    BASEADMINPASSWORD {
        @Override
        public String toString() {
            return "base.admin.password";
        }
    },    
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Can you show any examples on how you are using PropertyProvider? \$\endgroup\$ – Simon Forsberg Feb 3 '18 at 11:58
1
\$\begingroup\$

Property-enum

An enum can have a constructor, allowing us to shorten the code to setup all the enum values.

public enum Property {
    BROWSER("browser"),    
    TESTENVIRONMENT("env.baseurl"),
    ... // add more here.
    ;

    private final String key;

    Property(String key) {
        this.key = key;
    }

    public String getKey() {
        return this.key;
    }

    @Override public String toString() {
        return getKey();
    }
}

Do not have any logic based on toString. That method is mainly meant for debugging purposes. Using a getKey() instead (as above) allows you to use getKey() for your application logic.

Is a singleton really necessary?

Ask yourself if you really really NEED a singleton (Hint: Answer is most likely "no"). You might be able to use dependency injection to pass the object to the classes that needs it.

You might even not need a single instance, is there anything wrong with having multiple instances? All it does is read from a resource file, so worst case scenario is that you might spend a few nanoseconds reading a resource file from different places?

\$\endgroup\$
  • \$\begingroup\$ excellent thanks Simon, if i load the properties from this file and they are final, unable to change is a singleton not the best approach here? rather than instantiating multiple Property instances, It seemed like the best idea to me, but I'm quite new to this concept \$\endgroup\$ – symon Feb 3 '18 at 12:37
  • \$\begingroup\$ I used to use di with spring for this, but since I've started using TestNG I was having trouble getting everything working. Will look into that again \$\endgroup\$ – symon Feb 3 '18 at 12:39
  • \$\begingroup\$ @SKay Why is it that you want a singleton? Is it because you think it will save you performance? Do you need to save this performance? \$\endgroup\$ – Simon Forsberg Feb 3 '18 at 15:56
  • \$\begingroup\$ honestly I am just focusing as much as I can on learning as much about good design as I can, so any information is valuable thanks \$\endgroup\$ – symon Feb 3 '18 at 18:51
  • \$\begingroup\$ @SKay Generally, the singleton pattern is one of the most criticized patterns there is. The way you have implemented it is perfectly fine, but I'd recommend considering whether or not you want/need it. If you would show how you are using it though, I could maybe provide more details. \$\endgroup\$ – Simon Forsberg Feb 3 '18 at 20:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.