An example of a small work when you want to divide the definition value according to the environment but do not want to be aware of it

Introduction

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.

code

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);
    }
}

How to use

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.

Recommended Posts

An example of a small work when you want to divide the definition value according to the environment but do not want to be aware of it
A collection of patterns that you want to be aware of so as not to complicate the code
When you want to check whether the contents of a property can be converted to a specific type
A memo when you want to clear the time part of the calendar
Pay.JP Solution when it can be done locally but it does not work well in the production environment
I want to be aware of the contents of variables!
When you want to change the wording to be displayed when making a select box from enum
When you want to change the MySQL password of docker-compose
[Swift] When you want to know if the number of characters in a String matches a certain number ...
Is it easy for the user to use when implementing general-purpose functions? Let's be aware of
It should be the same as the sample when logging in to Twitter, but an error occurs ~ resolution
[RSpec] When you want to use the instance variable of the controller in the test [assigns is not recommended]
The first thing to do when you want to be happy with Heroku on GitHub with Eclipse in Java
What to do if Operation not permitted is displayed when you execute a command in the terminal
[Rails] What to do if you get an error saying "Could not find a JavaScript runtime." When executing the rails s command on Catalina
The end of catastrophic programming # 01 "Do it with the absolute value of an integer"
[Java small story] Monitor when a value is added to the List
What to do if you get an "A server is already running." Error when you try to start the rails server
[Note] [Beginner] How to write when changing the value of an array element in a Ruby iterative statement
A solution to an error that makes you angry that you are not following the MySQL default setting ONLY_FULL_GROUP_BY in a production environment and it is not unique.
What to do when you want to delete a migration file that is "NO FILE"
What to do when is invalid because it does not start with a'-'
What to do when ‘Could not find’ in any of the sources appears in the development environment with Docker × Rails × RSpec
[java tool] A useful tool when you want to send the ipmsg log of PC-A to the specified PC on a regular basis.
What to do if you get an error saying "Please enter a valid value" when getting with Rails datetime_field
[Ruby] When you want to assign the result obtained by conditional branching to a variable and put it in the argument
[Rails] What to do when you want to generate an error that cannot be destory when foreign key restrictions are applied
What to do if you get an error saying "Could not find a JavaScript runtime." When starting rails server