I think that it is very common to want to have different values such as connection destination information and authentication information for databases and external servers, one for development and the other for production operation. At that time, in the same definition file
conf.properties
#Production connection destination
#url=http://example.com/
#Test connection destination
url=http://test.example.com/
I sometimes see people who write like this and deal with it by replacing comments, but there are various things like writing a solid constant value on the source code side (although there is no clear reason to do so). Although it is far better than the unfortunate one, it is not a very good method. The main reason is that you have to be aware of which side the contents of the current definition file are for. No one wants to imagine an accident where they accidentally forgot to recomment a definition file and exposed what was connected to the test connection for production. Some of today's well-made frameworks respond properly to the demands of this area, but this time I would like to write an example that does not depend on the framework and does not take much time and effort. I will.
Configures.java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Properties;
/**
*Defined value container
*/
public class Configures {
/**System property key name*/
public static final String PropKey = "Config";
private static final Properties config = new Properties();
/**
*Initialization
* @param filePath Path to definition file
*/
synchronized public static void initialize(String filePath) {
try {
load(new FileInputStream(filePath));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
/**
*Initialization
* @param in Stream to definition file
*/
synchronized public static void initialize(InputStream in) {
load(in);
}
private static void load(InputStream in) {
try {
config.load(in);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
*Read definition value
* @param key key item
* @return definition value
*/
public static String get(Environment key) {
return get(key, null);
}
/**
*Read definition value
* @param key key item
* @param defaultValue Initial value
* @return definition value
*/
public static String get(Environment key, String defaultValue) {
if (key == null) {
throw new IllegalArgumentException("Environment is null");
}
return config.getProperty(key.getPropertyKey(), defaultValue);
}
private Configures() {
}
}
Environment.java
/**
*Key items in the definition file
*/
public enum Environment {
/**URL to connect to*/
ConnectUrl("url"),;
private final String key;
/**
*constructor
* @param key Key name in the definition file
*/
private Environment(String key) {
this.key = key;
}
/**
*Get property key
* @return key name
*/
public String getPropertyKey() {
return getPropertyKey(System.getProperty(Configures.PropKey));
}
/**
*Get property key
* @param envName environment name
* @return key name
*/
public String getPropertyKey(String envName) {
if (envName == null || "".equals(envName)) {
return key;
}
return String.format("%s.%s", key, envName);
}
}
After preparing the definition file as follows
conf.properties
url=http://localhost/
url.Test=http://test.example.com/
url.Release=http://example.com/
Define the system property "Config" with the value "Release" in the production environment. (* I think it's easiest to add "-DConfig = Release" to the runtime environment variables)
In the real code, at the beginning of the process
Configures.initialize(....)
(For Web applications, it is better to use around ServletContextListener)
String url = Configures.get(Environment.ConnectUrl);
Then, in the environment where the system property is not defined, the value of "http: // localhost /" and in the production environment, "http://example.com/" will be returned.
In the test case class etc., in the method for setup
System.setProperty(Configures.PropKey, "Test");
If you do, the value of "http://test.example.com/" will be passed.