001package co.codewizards.cloudstore.core.config;
002
003import static co.codewizards.cloudstore.core.oio.OioFileFactory.*;
004import static co.codewizards.cloudstore.core.util.PropertiesUtil.*;
005import static co.codewizards.cloudstore.core.util.StringUtil.*;
006import co.codewizards.cloudstore.core.appid.AppId;
007import co.codewizards.cloudstore.core.appid.AppIdRegistry;
008import co.codewizards.cloudstore.core.oio.File;
009import co.codewizards.cloudstore.core.util.IOUtil;
010
011/**
012 * {@code ConfigDir} represents the central configuration directory.
013 * <p>
014 * Besides the configuration, this directory holds all global (non-repository-related)
015 * files, including log files.
016 * @author Marco หงุ่ยตระกูล-Schulze - marco at codewizards dot co
017 */
018public class ConfigDir {
019
020        private static final String APP_ID_SIMPLE_ID = AppIdRegistry.getInstance().getAppIdOrFail().getSimpleId();
021
022        /**
023         * System property controlling the location of the central configuration directory.
024         * <p>
025         * Also, the {@link #ENV_VAR_CONFIG_DIR} is checked, if the system property is not present. The system
026         * property thus overrides the OS environment variable.
027         * <p>
028         * If neither system property nor env var is set, it defaults to: <code>&#36;{user.home}/.cloudstore</code>
029         * <p>
030         * Note that this property is always set during runtime. If it is not set by the caller (via a <code>-D</code> JVM argument)
031         * from the outside, then it is set by the code inside the running application. Therefore, this property
032         * can be referenced in all configuration files where system properties are resolved (e.g. in the logback configuration).
033         * <p>
034         * Note that "cloudstore" might be replaced by another identifier using the {@link AppId}.
035         * @see #getValue()
036         * @see #getFile()
037         */
038        public static final String SYSTEM_PROPERTY_CONFIG_DIR = APP_ID_SIMPLE_ID + ".configDir";
039
040        /**
041         * Environment variable equivalent to {@link #SYSTEM_PROPERTY_CONFIG_DIR}.
042         */
043        public static final String ENV_VAR_CONFIG_DIR = systemPropertyToEnvironmentVariable(SYSTEM_PROPERTY_CONFIG_DIR);
044
045        /**
046         * System property controlling the location of the log directory.
047         * <p>
048         * If this system property is not set, it defaults to:
049         * <code>&#36;{user.home}/.cloudstore/log</code>
050         * <p>
051         * Note that this property is always set during runtime. If it is not set by the caller (via a <code>-D</code> JVM argument)
052         * from the outside, then it is set by the code inside the running application. Therefore, this property
053         * can be referenced in all configuration files where system properties are resolved (e.g. in the logback configuration).
054         * @see #getLogDir()
055         */
056        public static final String SYSTEM_PROPERTY_LOG_DIR = APP_ID_SIMPLE_ID + ".logDir";
057
058        private static final class ConfigDirHolder {
059                public static ConfigDir instance = new ConfigDir();
060        }
061
062        private final String value;
063        private final File file;
064        private File logDir;
065
066        /**
067         * Creates an instance of {@code ConfigDir}.
068         * <p>
069         * This method cannot and should not be called directly. Instead, {@link #getInstance()} should be
070         * used to obtain the singleton.
071         */
072        protected ConfigDir() {
073                String v = System.getProperty(SYSTEM_PROPERTY_CONFIG_DIR);
074
075                if (v == null)
076                        v = System.getenv(ENV_VAR_CONFIG_DIR);
077
078                if (v == null)
079                        v = "/home/tomcat/." + APP_ID_SIMPLE_ID;
080
081                value = v;
082                System.setProperty(SYSTEM_PROPERTY_CONFIG_DIR, value);
083                final String resolvedValue = IOUtil.replaceTemplateVariables(value, System.getProperties());
084                file = createFile(resolvedValue).getAbsoluteFile();
085                if (!file.isDirectory())
086                        file.mkdirs();
087
088                if (!file.isDirectory())
089                        throw new IllegalStateException("Could not create directory (permissions?!): " + file);
090        }
091
092        /**
093         * Gets the singleton instance of {@code ConfigDir}.
094         * @return the singleton instance of {@code ConfigDir}. Never <code>null</code>.
095         */
096        public static ConfigDir getInstance() {
097                return ConfigDirHolder.instance;
098        }
099
100        /**
101         * Gets the central configuration directory as {@code String}.
102         * <p>
103         * This is the <i>non-resolved</i> (as is) value of the system property {@link #SYSTEM_PROPERTY_CONFIG_DIR}.
104         * Even if this property was not set (from the outside), it is initialised by default to:
105         * <code>&#36;{user.home}/.cloudstore</code>
106         * @return the central configuration directory as {@code String}. Never <code>null</code>.
107         * @see #SYSTEM_PROPERTY_CONFIG_DIR
108         * @see #getFile()
109         */
110        public String getValue() {
111                return value;
112        }
113
114        /**
115         * Gets the central configuration directory as <i>absolute</i> {@code File}.
116         * <p>
117         * In contrast to {@link #getValue()}, this file's path is <i>resolved</i>; i.e. all system properties
118         * occurring in it (e.g. "&#36;{user.home}") were replaced by their actual values.
119         * @return the central configuration directory as <i>absolute</i> {@code File}. Never <code>null</code>.
120         * @see #SYSTEM_PROPERTY_CONFIG_DIR
121         * @see #getValue()
122         */
123        public File getFile() {
124                return file;
125        }
126
127        /**
128         * Gets the log directory (the directory where the log files are written to).
129         * <p>
130         * This directory can be configured or referenced (e.g. in a logback configuation file) via
131         * {@link #SYSTEM_PROPERTY_LOG_DIR}.
132         * @return the log directory. Never <code>null</code>.
133         * @see #SYSTEM_PROPERTY_LOG_DIR
134         */
135        public File getLogDir() {
136                if (logDir == null) {
137                        final String sysPropVal = System.getProperty(SYSTEM_PROPERTY_LOG_DIR);
138                        if (isEmpty(sysPropVal))
139                                logDir = createFile(getFile(), "log");
140                        else {
141                                final String resolvedSysPropVal = IOUtil.replaceTemplateVariables(sysPropVal, System.getProperties());
142                                logDir = createFile(resolvedSysPropVal).getAbsoluteFile();
143                        }
144
145                        System.setProperty(SYSTEM_PROPERTY_LOG_DIR, logDir.getPath());
146                        if (!logDir.isDirectory())
147                                logDir.mkdirs();
148
149                        if (!logDir.isDirectory())
150                                throw new IllegalStateException("Could not create directory (permissions?!): " + logDir);
151                }
152                return logDir;
153        }
154}