001/**
002 * Copyright 2010-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.common.util.spring.env;
017
018import java.io.File;
019import java.util.Properties;
020
021import org.kuali.common.util.Assert;
022import org.kuali.common.util.ModeUtils;
023import org.kuali.common.util.spring.env.model.EnvironmentServiceContext;
024
025/**
026 * <p>
027 * By default, an exception is thrown if a value cannot be located (unless a default value has been supplied).
028 * </p>
029 * 
030 * <p>
031 * By default, an exception is thrown if any placeholders cannot be resolved in any string values.
032 * </p>
033 * 
034 * <p>
035 * By default, string values are resolved before being returned
036 * </p>
037 * 
038 * <p>
039 * By default, environment variables are automatically checked if a normal property value cannot be found.
040 * 
041 * For example, given the key <code>db.vendor</code> the service will also automatically check <code>env.DB_VENDOR</code>
042 * </p>
043 */
044public final class BasicEnvironmentService implements EnvironmentService {
045
046        private final EnvironmentServiceContext context;
047
048        /**
049         * Uses system properties / environment variables to resolve values
050         */
051        public BasicEnvironmentService() {
052                this(new EnvironmentServiceContext.Builder().build());
053        }
054
055        /**
056         * Uses <code>properties</code> to resolve values
057         */
058        public BasicEnvironmentService(Properties properties) {
059                this(new EnvironmentServiceContext.Builder().env(properties).build());
060        }
061
062        /**
063         * Uses <code>context</code> to resolve values
064         */
065        public BasicEnvironmentService(EnvironmentServiceContext context) {
066                Assert.noNulls(context);
067                this.context = context;
068        }
069
070        @Override
071        public boolean containsProperty(String key) {
072                Assert.noBlanks(key);
073                return context.getEnv().containsProperty(key);
074        }
075
076        @Override
077        public <T> T getProperty(EnvContext<T> context) {
078
079                // If context is null, we have issues
080                Assert.noNulls(context);
081
082                // Extract a value from Spring's Environment abstraction
083                T springValue = getSpringValue(context.getKey(), context.getType());
084
085                // If that value is null, use whatever default value they gave us (this might also be null)
086                T returnValue = (springValue == null) ? context.getDefaultValue() : springValue;
087
088                // If we could not locate a value, we may need to error out
089                if (returnValue == null) {
090                        ModeUtils.validate(this.context.getMissingPropertyMode(), getMissingPropertyMessage(context.getKey()));
091                }
092
093                // Return the value we've located
094                return returnValue;
095        }
096
097        @Override
098        public <T> T getProperty(String key, Class<T> type, T provided) {
099                return getProperty(EnvContext.newCtx(key, type, provided));
100        }
101
102        @Override
103        public <T> T getProperty(String key, Class<T> type) {
104                return getProperty(EnvContext.newCtx(key, type, null));
105        }
106
107        protected String getMissingPropertyMessage(String key) {
108                if (context.isCheckEnvironmentVariables()) {
109                        String envKey = EnvUtils.getEnvironmentVariableKey(key);
110                        return "No value for [" + key + "] or [" + envKey + "]";
111                } else {
112                        return "No value for [" + key + "]";
113                }
114        }
115
116        protected <T> T getSpringValue(String key, Class<T> type) {
117                T value = context.getEnv().getProperty(key, type);
118                if (value == null && context.isCheckEnvironmentVariables()) {
119                        String envKey = EnvUtils.getEnvironmentVariableKey(key);
120                        return context.getEnv().getProperty(envKey, type);
121                } else {
122                        return value;
123                }
124        }
125
126        protected <T> Class<T> getSpringValueAsClass(String key, Class<T> type) {
127                Class<T> value = context.getEnv().getPropertyAsClass(key, type);
128                if (value == null && context.isCheckEnvironmentVariables()) {
129                        String envKey = EnvUtils.getEnvironmentVariableKey(key);
130                        return context.getEnv().getPropertyAsClass(envKey, type);
131                } else {
132                        return value;
133                }
134        }
135
136        @Override
137        public <T> Class<T> getClass(String key, Class<T> type) {
138                return getClass(key, type, null);
139        }
140
141        @Override
142        public <T> Class<T> getClass(String key, Class<T> type, Class<T> defaultValue) {
143                Class<T> springValue = getSpringValueAsClass(key, type);
144                Class<T> returnValue = (springValue == null) ? defaultValue : springValue;
145
146                // If we could not locate a value, we may need to error out
147                if (returnValue == null) {
148                        ModeUtils.validate(context.getMissingPropertyMode(), getMissingPropertyMessage(key));
149                }
150
151                // Return what we've got
152                return returnValue;
153        }
154
155        @Override
156        public String getString(String key) {
157                return getString(key, null);
158        }
159
160        @Override
161        public String getString(String key, String defaultValue) {
162                String string = getProperty(EnvContext.newString(key, defaultValue));
163                if (context.isResolveStrings()) {
164                        return context.getEnv().resolveRequiredPlaceholders(string);
165                } else {
166                        return string;
167                }
168        }
169
170        @Override
171        public Boolean getBoolean(String key) {
172                return getBoolean(key, null);
173        }
174
175        @Override
176        public Boolean getBoolean(String key, Boolean defaultValue) {
177                return getProperty(EnvContext.newBoolean(key, defaultValue));
178        }
179
180        @Override
181        public File getFile(String key) {
182                return getFile(key, null);
183        }
184
185        @Override
186        public File getFile(String key, File defaultValue) {
187                return getProperty(EnvContext.newFile(key, defaultValue));
188        }
189
190        @Override
191        public Integer getInteger(String key, Integer defaultValue) {
192                return getProperty(EnvContext.newInteger(key, defaultValue));
193        }
194
195        @Override
196        public Integer getInteger(String key) {
197                return getInteger(key, null);
198        }
199
200        public EnvironmentServiceContext getContext() {
201                return context;
202        }
203
204}