2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * =============================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * ============LICENSE_END=========================================================
24 package org.onap.appc.configuration;
26 import java.io.IOException;
27 import java.io.InputStream;
29 import java.security.CodeSource;
30 import java.security.ProtectionDomain;
31 import java.security.Provider;
32 import java.security.Provider.Service;
33 import java.security.Security;
34 import java.util.Map.Entry;
35 import java.util.Properties;
36 import java.util.jar.JarFile;
37 import java.util.jar.Manifest;
38 import java.util.regex.Matcher;
39 import java.util.regex.Pattern;
40 import org.onap.appc.encryption.EncryptionTool;
41 import org.onap.appc.util.UnmodifiableProperties;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 * This class provides the implementation of the <code>Configuration</code> interface. It is created
47 * by the ConfigurationFactory and initialized with the configuration values for the process.
51 public final class DefaultConfiguration implements Configuration, Cloneable {
53 private static final Logger logger = LoggerFactory.getLogger(DefaultConfiguration.class);
56 * The framework configuration properties.
58 private Properties properties = new Properties();
61 * Construct the configuration object.
63 DefaultConfiguration() {}
66 * Clears all properties
73 * @see java.lang.Object#clone()
76 protected Object clone() throws CloneNotSupportedException {
77 DefaultConfiguration clone = (DefaultConfiguration) super.clone();
79 clone.properties = new Properties(this.properties);
80 clone.properties.putAll(this.properties);
86 * Decrypts an encrypted value, if it is encrypted, and returns the clear text. Performs no
87 * operation on the string if it is not encrypted.
89 * @param value The value to (optionally) be decrypted
90 * @return The clear text
92 @SuppressWarnings("nls")
93 private static String decrypt(String value) {
94 if (value != null && value.startsWith(EncryptionTool.ENCRYPTED_VALUE_PREFIX)) {
96 return EncryptionTool.getInstance().decrypt(value);
97 } catch (Exception e) {
98 StringBuilder out = new StringBuilder();
99 for (Provider p : Security.getProviders()) {
100 for (Service s : p.getServices()) {
101 String algo = s.getAlgorithm();
102 out.append(String.format(
103 "\n==Found Algorithm [ %s ] in provider [ %s ] and service [ %s ]",
104 algo, p.getName(), s.getClassName()));
107 logger.debug(out.toString());
108 logger.warn(String.format("Could not decrypt the configuration value [%s]", value),
116 * Decrypts all elements in the properties object
118 private void decryptAllProperties() {
119 if (properties != null) {
120 for (Entry<Object, Object> e : properties.entrySet()) {
121 if (e.getValue() != null) {
122 e.setValue(decrypt(e.getValue().toString()));
129 * @see java.lang.Object#equals(java.lang.Object)
132 public boolean equals(Object obj) {
138 if (this.getClass() != obj.getClass()) {
142 DefaultConfiguration other = (DefaultConfiguration) obj;
144 return (this.properties.size() == other.properties.size())
145 && (this.properties.entrySet().containsAll(other.properties.entrySet()))
146 && (other.properties.entrySet().containsAll(this.properties.entrySet()));
151 * This method will use the properties object to expand any variables that may be present in the
152 * template provided. Variables are represented by the string "${name}", where "name" is the
153 * name of a property defined in either the current configuration object, or system properties
154 * if undefined. If the value cannot be found, the variable is removed and an empty string is
155 * used to replace the variable.
157 * @param template The template to be expanded
158 * @return The expanded template where each variable is replaced with its value
160 @SuppressWarnings("nls")
161 private String expandVariables(String template) {
162 if (template == null) {
166 // Decrypt the template if needed
167 // template = decrypt(template); DH: Do not assign values to parameters, bad form! Also,
171 StringBuilder builder = new StringBuilder(decrypt(template));
172 Pattern pattern = Pattern.compile("\\$\\{([^\\}]+)\\}");
173 Matcher matcher = pattern.matcher(builder);
174 while (matcher.find()) {
175 String variable = matcher.group(1);
176 String value = properties.getProperty(variable);
178 value = System.getProperty(variable);
183 builder.replace(matcher.start(), matcher.end(), value);
187 return builder.toString().trim();
191 * This method is called to obtain a property expressed as a boolean value (true or false). The
192 * standard rules for Boolean.parseBoolean() are used.
194 * @param key The property key
195 * @return The value of the property expressed as a boolean, or false if it does not exist.
197 @SuppressWarnings("nls")
199 public boolean getBooleanProperty(String key) {
200 return Boolean.valueOf(getProperty(key, "false"));
204 * This method is called to obtain a property expressed as a boolean value (true or false). The
205 * standard rules for Boolean.valueOf(String) are used.
207 * @param key The property key
208 * @param defaultValue The default value to be returned if the property does not exist
209 * @return The value of the property expressed as a boolean, or false if it does not exist.
210 * @see org.onap.appc.configuration.Configuration#getBooleanProperty(java.lang.String, boolean)
213 public boolean getBooleanProperty(String key, boolean defaultValue) {
214 if (isPropertyDefined(key)) {
215 return getBooleanProperty(key);
221 * Returns the indicated property value expressed as a floating point double-precision value
224 * @param key The property to retrieve
225 * @return The value of the property, or 0.0 if not found
226 * @see org.onap.appc.configuration.Configuration#getDoubleProperty(java.lang.String)
228 @SuppressWarnings("nls")
230 public double getDoubleProperty(String key) {
232 return Double.valueOf(getProperty(key, "0.0"));
233 } catch (NumberFormatException e) {
239 * This method is called to obtain a property as a string value
241 * @param key The key of the property
242 * @param defaultValue The default value to be returned if the property does not exist
243 * @return The string value, or null if it does not exist.
244 * @see org.onap.appc.configuration.Configuration#getDoubleProperty(java.lang.String, double)
247 public double getDoubleProperty(String key, double defaultValue) {
248 if (isPropertyDefined(key)) {
249 return getDoubleProperty(key);
255 * Returns the property indicated expressed as an integer. The standard rules for
256 * {@link Integer#parseInt(String, int)} using a radix of 10 are used.
258 * @param key The property name to retrieve.
259 * @return The value of the property, or 0 if it does not exist or is invalid.
260 * @see org.onap.appc.configuration.Configuration#getIntegerProperty(java.lang.String)
262 @SuppressWarnings("nls")
264 public int getIntegerProperty(String key) {
266 return Integer.parseInt(getProperty(key, "0"), 10);
267 } catch (NumberFormatException e) {
273 * Returns the property indicated expressed as an integer. The standard rules for
274 * Integer.parseInt(String, int) using a radix of 10 are used.
276 * @param key The property name to retrieve.
277 * @param defaultValue The default value to be returned if the property does not exist
278 * @return The value of the property, or 0 if it does not exist or is invalid.
279 * @see org.onap.appc.configuration.Configuration#getIntegerProperty(java.lang.String, int)
282 public int getIntegerProperty(String key, int defaultValue) {
283 if (isPropertyDefined(key)) {
284 return getIntegerProperty(key);
290 * Returns the specified property as a long integer value, if it exists, or zero if it does not.
292 * @param key The key of the property desired.
293 * @return The value of the property expressed as an integer long value, or zero if the property
294 * does not exist or is not a valid integer long.
295 * @see org.onap.appc.configuration.Configuration#getLongProperty(java.lang.String)
297 @SuppressWarnings("nls")
299 public long getLongProperty(String key) {
301 return Long.parseLong(getProperty(key, "0"), 10);
302 } catch (NumberFormatException e) {
308 * Returns the specified property as a long integer value, if it exists, or the default value if
309 * it does not exist or is invalid.
311 * @param key The key of the property desired.
312 * @param defaultValue the value to be returned if the property is not valid or does not exist.
313 * @return The value of the property expressed as an integer long value, or the default value if
314 * the property does not exist or is not a valid integer long.
315 * @see org.onap.appc.configuration.Configuration#getLongProperty(java.lang.String, long)
318 public long getLongProperty(String key, long defaultValue) {
319 if (isPropertyDefined(key)) {
320 return getLongProperty(key);
326 * This method can be called to retrieve a properties object that is immutable. Any attempt to
327 * modify the properties object returned will result in an exception. This allows a caller to
328 * view the current configuration as a set of properties.
330 * @return An unmodifiable properties object.
331 * @see org.onap.appc.configuration.Configuration#getProperties()
334 public Properties getProperties() {
335 return new UnmodifiableProperties(properties);
339 * This method is called to obtain a property as a string value
341 * @param key The key of the property
342 * @return The string value, or null if it does not exist.
345 public String getProperty(String key) {
346 String value = properties.getProperty(key);
350 return expandVariables(value.trim());
354 * This method is called to obtain a property as a string value
356 * @param key The key of the property
357 * @param defaultValue The default value to be returned if the property does not exist
358 * @return The string value, or null if it does not exist.
359 * @see org.onap.appc.configuration.Configuration#getProperty(java.lang.String,
363 public String getProperty(String key, String defaultValue) {
364 if (isPropertyDefined(key)) {
365 return getProperty(key);
368 if (defaultValue == null) {
372 return expandVariables(defaultValue.trim());
376 * @see java.lang.Object#hashCode()
379 public int hashCode() {
380 return properties == null ? 0 : properties.hashCode();
384 * Returns true if the named property is defined, false otherwise.
386 * @param key The key of the property we are interested in
387 * @return True if the property exists.
390 public boolean isPropertyDefined(String key) {
391 return properties.containsKey(key);
395 * Returns an indication of the validity of the boolean property. A boolean property is
396 * considered to be valid only if it has the value "true" or "false" (ignoring case).
398 * @param key The property to be checked
399 * @return True if the value is a boolean constant, or false if it does not exist or is not a
401 * @see org.onap.appc.configuration.Configuration#isValidBoolean(java.lang.String)
403 @SuppressWarnings("nls")
405 public boolean isValidBoolean(String key) {
406 String value = getProperty(key);
408 value = value.toLowerCase();
409 return value.matches("true|false");
415 * Returns an indication if the indicated property represents a valid double-precision floating
418 * @param key The property to be examined
419 * @return True if the property is a valid representation of a double, or false if it does not
420 * exist or contains illegal characters.
421 * @see org.onap.appc.configuration.Configuration#isValidDouble(java.lang.String)
424 public boolean isValidDouble(String key) {
425 String value = getProperty(key);
428 Double.valueOf(value);
430 } catch (NumberFormatException e) {
438 * Returns an indication if the property is a valid integer value or not.
440 * @param key The key of the property to check
441 * @return True if the value is a valid integer string, or false if it does not exist or
442 * contains illegal characters.
443 * @see org.onap.appc.configuration.Configuration#isValidInteger(java.lang.String)
446 public boolean isValidInteger(String key) {
447 String value = getProperty(key);
450 Integer.parseInt(value.trim(), 10);
452 } catch (NumberFormatException e) {
460 * Determines is the specified property exists and is a valid representation of an integer long
463 * @param key The property to be checked
464 * @return True if the property is a valid representation of an integer long value, and false if
465 * it either does not exist or is not valid.
466 * @see org.onap.appc.configuration.Configuration#isValidLong(java.lang.String)
469 public boolean isValidLong(String key) {
470 String value = getProperty(key);
473 Long.parseLong(value.trim(), 10);
475 } catch (NumberFormatException e) {
483 * This method allows an implementation to load configuration properties that may override
486 * @param is An input stream that contains the properties to be loaded
488 public void setProperties(InputStream is) {
491 } catch (IOException e) {
492 logger.warn("setProperties with inputStream got exception", e);
497 * This method allows an implementation to load configuration properties that may override
500 * @param props An optional Properties object to be merged into the configuration, replacing any
501 * same-named properties.
502 * @see org.onap.appc.configuration.Configuration#setProperties(java.util.Properties)
505 public void setProperties(Properties props) {
506 properties.putAll(props);
507 decryptAllProperties();
511 * This method allows a caller to insert a new property definition into the configuration
512 * object. This allows the application to adjust or add to the current configuration. If the
513 * property already exists, it is replaced with the new value.
515 * @param key The key of the property to be defined
516 * @param value The value of the property to be defined
517 * @see org.onap.appc.configuration.Configuration#setProperty(java.lang.String,
521 public void setProperty(String key, String value) {
522 properties.setProperty(key, decrypt(value));
526 * @see java.lang.Object#toString()
528 @SuppressWarnings("nls")
530 public String toString() {
531 return String.format("Configuration: %d properties, keys:[%s]", properties.size(),
532 properties.keySet().toString());
536 * This is a helper method to read the manifest of the jar file that this class was loaded from.
537 * Note that this will only work if the code is packaged in a jar file. If it is an open
538 * deployment, such as under eclipse, this will not work and there is code added to detect that
541 * @return The manifest object from the jar file, or null if the code is not packaged in a jar
544 @SuppressWarnings({"unused", "nls"})
545 private Manifest getManifest() {
546 ProtectionDomain domain = getClass().getProtectionDomain();
547 CodeSource source = domain.getCodeSource();
548 URL location = source.getLocation();
549 String path = location.getPath();
550 int index = path.indexOf('!');
552 path = path.substring(0, index);
554 if (path.endsWith(".jar")) {
555 try (JarFile jar = new JarFile(location.getFile())) {
556 return jar.getManifest();
557 } catch (IOException e) {
558 logger.error("getManifest", e);