How to safely read the property file in Java? - java

I have a property file which is like this -
emailFrom=hello#abc.com
emailTo=world#abc.com
# can be separated by comma
whichServer=UserServer,GuestServer
maxTestInSec=120
numberOfUsers=1000
Now I am reading this property file like this in Java which works if everything is set properly -
private static final Properties prop = new Properties();
private static String emailFrom;
private static String emailTo;
private static List<String> whichServer;
private static String maxTestInSec;
private static String numberOfUsers;
public static void main(String[] args) {
readConfig(args);
}
private void readConfig(String[] args) throws FileNotFoundException, IOException {
if (!TestUtils.isEmpty(args) && args.length != 0) {
prop.load(new FileInputStream(args[0]));
} else {
prop.load(TestTask.class.getClassLoader().getResourceAsStream("config.properties"));
}
emailFrom = prop.getProperty("emailFrom").trim();
emailTo = prop.getProperty("emailTo").trim();
whichServer = Arrays.asList(prop.getProperty("whichServer").trim().split(","));
maxTestInSec = prop.getProperty("maxTestInSec").trim();
numberOfUsers = prop.getProperty("numberOfUsers").trim();
}
Problem Statement:-
I need to make sure that if any of the property value is missing then I want to use default value for that and if by any chance that property is commented out, then also I want to use default value but I would log a warning message stating the property is missing or empty so using default values. I am trying to cover all the corner cases for reading the file -
Now let's say, if I am not specifying values to any of my property in the above file, then I want to use default values for the property which I haven't provided and log as a warning stating that, no values have been provided for this property so using the default values. For example : Let's say if I haven't provided any value for emailFrom field, then I would like to use default value as hello#abc.com for that and similar thing for others. The default values for all the property will be :
emailFrom=hello#abc.com
emailTo=world#abc.com
whichServer=UserServer
maxTestInSec=30
numberOfUsers=500
Also, if any of the property is commented out then the above code is going to through NPE exception. How can I use default values in that scenario as well?
Should I start using Command Line parser for this? What is the best and clean way to handle these stuffs?
I don't want to have lot of if blocks to add a check and then set the default values.

As of Java 8 the easiest thing to do is use getOrDefault() which lets you specify a default value at the get-site. For example:
String email = properties.getOrDefault("emailFrom", "hello#abc.com");
This is clean and concise, but does mean you need to specify the default everywhere you access the property.
If that won't work for you (i.e. you'll be reading values from the properties object more than once) you can use the built-in support for default values -notice the constructor that takes a default Properties object. This lets you construct a Properties object containing your defaults, and then when you load the user's properties file it will fall back on the defaults if the user doesn't specify a value.
private static final Properties DEFAULTS = new Properties();
static {
DEFAULTS.setProperty("emailFrom", "hello#abc.com");
}
public Properties getProperties() {
Properties props = new Properties(DEFAULTS);
props.load(...);
return props;
}
Just notice that this isn't identical to how Map's constructor works - the defaults are left as a separate map, and only .getProperty() also queries the defaults; the methods defined in Map like .get() don't. One of the many reasons it was a terrible decision for Properties to extend Hashtable, but c'est la vie...
These options work, but they're both error-prone since a) Properties is mutable and b) only some of its public methods fall back the default instance. I prefer to never expose Properties objects directly, and instead create a wrapper class with type-safe methods that expose the values my application will care about. This is a little more typing, but it's much safer to work with. It would look something like this:
public class ApplicationSettings {
private final Properties properties = new Properties();
public ApplicationSettings() {
properties.load(...);
}
public String emailFrom() {
// simple methods are concise, and encode the default right inline
return properties.getOrDefault("emailFrom", "hello#abc.com");
}
public int getMaxTestSeconds() {
// You can do more complex validation if you want, too
String value = properties.get("maxTestInSec");
if (value == null) {
return 30;
}
int maxTestSeconds = Integer.parseInt(value);
if (maxTestSeconds <= 0) {
// could instead log a warning and return the default if you want
throw new IllegalStateException(
"maxTestInSec must be positive - was " + maxTestSeconds);
}
return maxTestSeconds;
}
}
If you need you can also expose setters that similarly validate the values before adding them to the Properties object, though by default making everything read-only is generally a good practice.

In case of a property is commented out, the return will be null, so simply do a null check.
if (prop.getProperty("name")==null)
In case of a value is not filled, check whether its equal to empty space after trim operation.
if (prop.getProperty("name").trim().equals(""))

You can try cashing the properties into static map and process on that map before its being used actually.
private Map<String, String> rawProps = new HashMap<String, String>;
public static Map<String, String> actualProps = new HashMap<String, String>;
static {
checkMapForNullAndReport();
}
private static void checkMapForNullAndReport() {
// Null logic and Reporting logic
// Empty rawProps and populate the actualProps
}
Something like this would work for you i believe.

Related

java - Set final fields with reflection in Constructor

I'm trying to make a multi-language app with messages inside multiple *.properties files. I've started working on something like this:
public Language(#NotNull Map<String, String> info) {
Validate.notNull(info, "Language information cannot be null");
this.PLUGIN_PREFIX = info.get("PLUGIN_PREFIX");
this.ARGUMENT_CODE = info.get("ARGUMENT_CODE");
// etc...
}
Now, there's a lot of messages, and I don't feel like typing the same thing each time (plus there could me typos which could be an issue...).
The first solution I thought of was to loop through all of the fields that are like that (in caps, final, not static, etc.) and then use reflection to use the field name as a key to set it as the value. Obviously the compiler won't let me because it thinks that the final field hasn't been initialized.
Something like this:
public Language(#NotNull Map<String, String> info) {
Validate.notNull(info, "Language information cannot be null");
Field[] fields = /* TODO get fields */ new Field[0];
for (Field f : fields) f.set(f.getName(), info.get(f.getName()));
}
Is there a way this can work? Or is there a better solution?
Edit: Quick naming conventions question, should these final "constants" be in upper case?
Usually, you don't store text messages directly in constants, but rather just message keys. Then you use these keys to fetch the actual text messages in the map.
You can use a map directly, but in Java, there is ResourceBundle. A ResourceBundle can be loaded directly from a .properties file.
my-bundle_en.properties:
my.message=Hello, world!
my-bundle_fr.properties:
my.message=Bonjour tout le monde!
my-bundle_de.properties:
my.message=Hallo Welt!
Something.java:
public static final MY_MESSAGE = "my.message";
ResourceBundle bundle = ResourceBundle.getBundle("my-bundle");
String text = bundle.getMessage(MY_MESSAGE);
System.out.println(text);

Best way to implement a link between N constants

I couldn't find a better title (feel free to edit it if you find a better one), but the use case is the following. I have two lists of constants. One of those contains the constants I use in my application, the other contains the different constants that are sent to me via a CSV file (along with data).
To give a rough exemple : in the CSV file, there is a field called "id of the client". In my application, I want to use a field called "clientId". So I basically need to create a static link between the two constants, so that I can easily switch from one to the other depending on what I need to achieve.
I've thought about creating a static Map(String, String) of values, but I figured there might be better solutions.
Thanks !
EDIT : changed title to "N" constants instead of 2, because Hashmap doesn't seem to be an option any longer in that case.
you can use the double bracket innitializer idiom to keep map initialization close to the map declaration, so it would be not so "ugly" eg:
static Map<String, String> someMap = new HashMap<String, String>() {{
put("one", "two");
put("three", "four");
}};
Beware that without the static modifier each anonymous class (there is one created in this example) holds a refernce to the enclosing object and if you'll give a reference to this map to some other class it will prevent the enclosing class from being garbage collect.
Fortunatelly, there is a hope for us with java update, in java 9 there will be very handy Map.of() to help us do it more safely.
The best way to separate the mapping from your application code is to use a properties file where in which you define your mapping.
For example, you could have a csv-mapping.properties in the root of your resources and load them with the following code:
final Properties properties = new Properties();
properties.load( this.getClass().getResourceAsStream( "/csv-mapping.properties" ) );
This will work just like a Map, with the added separation of code from configuration.
There are many methods that you can use to easily solve these types of problem.
One way is to use a Properties file, or file containing the key value pair.
Here is the code for Properties.
import java.util.ResourceBundle;
public class ReadingPropertiesFile {
public static void main(String[] args) {
ResourceBundle messages;
messages = ResourceBundle.getBundle("msg");
System.out.println(messages.getString("ID"));
}
}
msg.properties file contains values::
ID = ClientID.
PRODUCT_ID = prod_ID
The output of the program is ClientID.
You can also read from a simple text file. Or you could use the map as you are using. But I would suggest you to use the properties file.
One good option would be to use an enum to create such mappings beetween multiple constants to a single common sense value, eg:
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public enum MappingEnum {
CLIENT_ID("clientId", "id of the client", "clientId", "IdOfTheClient"),
CLIENT_NAME("clientName", "name of the client", "clientName");
private Set<String> aliases;
private String commonSenseName;
private MappingEnum(String commonSenseName, String... aliases) {
this.commonSenseName = commonSenseName;
this.aliases = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(aliases)));
}
public static MappingEnum fromAlias(String alias) {
for (MappingEnum mappingEnum : values()) {
if (mappingEnum.getAliases().contains(alias)) {
return mappingEnum;
}
}
throw new RuntimeException("No MappingEnum for mapping: " + alias);
}
public String getCommonSenseName() {
return commonSenseName;
}
}
and then you can use it like:
String columnName = "id of the client";
String targetFieldName = MappingEnum.fromAlias(columnName).getCommonSenseName();

Property file based conditional patterns in java

I have a property file (a.txt) which has the values (Example values given below) like below
test1=10
test2=20
test33=34
test34=35
By reading this file, I need to produce an output like below
value = 35_20_34_10
which means => I have a pattern like test34_test2_test33_test1
Note, If the 'test33' has any value other than 34 then I need to produce the value like below
value = 35_20_10
which means => I have a pattern like test34_test2_test1
Now my problem is, every time when the customer is making the change in the logic, I am making the change in the code. So what I expect is, I want to keep the logic (pattern) in another property file so I will be sending the two inputs to the util (one input is the property file (A.txt) another input will be the 'pattern.txt'),
My util has to be compare the A.txt and the business logic 'pattern.txt' and produce the output like
value = 35_20_34_10 (or)
value = 35_20_10
If there an example for such pattern based logic as I expect?
Any predefined util / java class does this?
Any help would be Great.
thanks,
Harry
First of all, svasa's answer makes a lot of sense, but covers different level of
abstraction. I recommend you read his answer too, that pattern should
be useful.
You may wanna look at Apache Velocity and FreeMarker libraries to see how they structure their API.
Those are template engines - they usually have some abstraction of pattern or format, and abstraction of variable/value binding (or namespace, or source). You can render a template by binding it with a binding/namespace, which yields the result.
For example, you may wanna have a pattern "<a> + <b>", and binding that looks like a map: {a: "1", b: "2"}. By binding that binding to that pattern you'll get "1 + 2", when interpreting <...> as variables.
You basically load the pattern from your pattern.txt, then load your data file A.txt (for example, by treating it as properties and using Properties class) and construct binding based on these properties. You'll get your output and possibility to customize the pattern all the time.
You may call the sequences like test34_test2_test33_test1 as a pattern, let me call them as constraints when building something.
To me this problem best fits into a
builder pattern.
When building the value you want, you tell the builder that these are my constraints(pattern) and these are my original properties like below:
new MyPropertiesBuilder().setConstraints(constraints).setProperties(original).buildValue();
Details:
Set some constraints in a separate file where you specify the order of the properties and their values like :
test34=desiredvalue-could-be-empty
test2=desiredvalue-could-be-empty
test33=34
test1=desiredvalue-could-be-empty
The builder goes over the constraints in the order specified, but get the values from the original properties and build the desired string.
One way to achieve your requirement through builder pattern is to define classes like below :
Interface:
public interface IMyPropertiesBuilder
{
public void setConstraints( Properties properties );
public void setProperties( Properties properties );
public String buildValue();
}
Builder
public class MyPropertiesBuilder implements IMyPropertiesBuilder
{
private Properties constraints;
private Properties original;
#Override
public void setConstraints( Properties constraints )
{
this.constraints = constraints;
}
#Override
public String buildValue()
{
StringBuilder value = new StringBuilder();
Iterator it = constraints.keySet().iterator();
while ( it.hasNext() )
{
String key = (String) it.next();
if ( original.containsKey( key ) && constraints.getProperty( key ) != null && original.getProperty( key ).equals( constraints.getProperty( key ) ) )
{
value.append( original.getProperty( key ) );
value.append( "_" );
}
}
return value.toString();
}
#Override
public void setProperties( Properties properties )
{
this.original = properties;
}
}
User
public class MyPropertiesBuilderUser
{
private Properties original = new Properties().load(new FileInputStream("original.properties"));;
private Properties constraints = new Properties().load(new FileInputStream("constraints.properties"));
public String getValue()
{
String value = new MyPropertiesBuilder().setConstraints(constraints).setProperties(original).buildValue();
}
}

Is MemcacheService fundamentally a singleton

The answer to this question seems obvious, but I need to be completely sure. So if answer can provide authoritative reference with clear non-ambiguous statements, that would be great.
Say I have the following two methods
public CollectionResponse<Dog> getDogs(Identification request){
MemcacheService syncCacheDog = MemcacheServiceFactory.getMemcacheService();
syncCacheDog.setErrorHandler(ErrorHandlers.getConsistentLogAndContinue(Level.INFO));
// ........
value = (byte[]) syncCacheDog.get(key); // read from cache
if (value == null) {
// get value from other source
// ........
syncCacheDog.put(key, value); // populate cache
}
// ........
}
public CollectionResponse<Cat> getCats(Identification request){
MemcacheService syncCacheCat = MemcacheServiceFactory.getMemcacheService();
syncCacheCat.setErrorHandler(ErrorHandlers.getConsistentLogAndContinue(Level.INFO));
// ........
value = (byte[]) syncCacheCat.get(key); // read from cache
if (value == null) {
// get value from other source
// ........
syncCacheCat.put(key, value); // populate cache
}
// ........
}
Are syncCacheDog and syncCacheCat pointing to the same map? Or if I want them to be pointing to the same map, do I have to create
static MemcacheService syncCache = MemcacheServiceFactory.getMemcacheService();
and then use syncCache inside both methods?
On the other hand, if it is a singleton, how do I maintain two different caches? I.e. can someone please copy and paste one of my methods and show it written with a namespace and instead of dealing with generic byte to deal with a specific object such as Dog?
Yes, from my experience with GAE and its documentation, Memcache service is a singleton. Even more, different versions of the application all see the same cache.
In order to maintain different caches do the usual: use a prefix. Maintaining a unique set of prefixes for different classes should be relatively easy - have an enum somewhere, keeping track of the maximum prefix. And never reuse the old prefix numbers.
public enum MemcachePrefix {
DOGS(1),
CATS(2);
// Max: 2.
public final int value;
private MemcachePrefix (int value) {this.value = value;}
};
public class Dog {
static final MemcachePrefix MEMCACHE_PREFIX = MemcachePrefix.DOGS;
};
class Main {
public static void main (String[] args) {
Dog dog = new Dog();
System.out.println (dog.MEMCACHE_PREFIX);
}
}
There is also Namespaces. Instead of manually adding the prefix to the cache key you can use it as a namespace, letting GAE do the key manipulations for you.

Make parameters available in an application

What is the standard way of storing a command line argument so that it can be accessed when required?
I can see 2 scenarios:
The argument is consumed immediately (A logging level)
The argument is not needed immediately (On failure send email to address X)
With scenario 1 It would seem quite natural to configure it upfront, however when it is a scenario more in the vein of scenario 2 I would prefer to configure that component as and when necessary (IE not up front)
So to phrase the question slightly differently how do I make my configuration options available to my entire application?
You can have a singleton Configuration object, in which all relevant things are stored.
public class Configuration {
private static final Configuration conf = new Configuration();
public static Configuration get() {
return conf;
}
private String failureEmailAddress;
public String getFailureEmailAddress() {
return failureEmailAddress;
}
public void parseCommandLine(String[] args) {
// ...
}
}
You can use something like that (you can store the CommandLine somewhere or use the opions right away):
Options options = createOptions();
CommandLineParser parser = new GnuParser();
CommandLine cmdLine;
int timeoutHumanMove;
try
{
cmdLine = parser.parse(options, args, true);
timeoutHumanMove = getTimeoutOption(cmdLine, "thm", 300);
}
catch(ParseException e)
{
return;
}
private static int getTimeoutOption(CommandLine cmdLine, String opt, int defaultSeconds)
throws ParseException
{
if(cmdLine.hasOption(opt))
{
Number val = (Number)cmdLine.getParsedOptionValue(opt);
return (int)(val.doubleValue() * 1000D);
} else
{
return 1000 * defaultSeconds;
}
}
private static Options createOptions()
{
Options options = new Options();
options.addOption(OptionBuilder.withDescription("print this help and exit").create(OptionBuilder.withLongOpt("help"), 104));
// ...
return options;
}
There is no standard way to store application wide configuration information such as you describe. However, most of the time you store it in a class which is specific to the job (ApplicationContext), and then the instance is passed into the other classes as parameters or in a constructor or something like that. I usually make the ApplicationContext immutable.
Some applications I've come across use a static global context, effectively a global variable. This isn't necessarily a good idea, for the same reason that you should avoid global variables.
However, I would say that you should always verify that the command line options are valid up front. You don't want to do 3 hours of processing and then find out that someone hadn't configured the email address correctly on the command line. This should be a fail-fast situation.
You could store your command args into System properties using System.setProperty() then you can access your properties anywhere via System.getProperty()..

Categories