2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 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 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 * ============LICENSE_END=========================================================
25 package org.onap.appc.configuration;
27 import java.io.IOException;
28 import java.io.InputStream;
30 import java.security.CodeSource;
31 import java.security.ProtectionDomain;
32 import java.security.Provider;
33 import java.security.Provider.Service;
34 import java.security.Security;
35 import java.util.Map.Entry;
36 import java.util.Properties;
37 import java.util.jar.JarFile;
38 import java.util.jar.Manifest;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
42 import org.onap.appc.encryption.EncryptionTool;
43 import org.onap.appc.util.UnmodifiableProperties;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
48 * This class provides the implementation of the <code>Configuration</code> interface. It is created by the
49 * ConfigurationFactory and initialized with the configuration values for the process.
54 public final class DefaultConfiguration implements Configuration, Cloneable {
56 private static final Logger logger = LoggerFactory.getLogger(DefaultConfiguration.class);
59 * The framework configuration properties.
61 private Properties properties = new Properties();
64 * Construct the configuration object.
66 DefaultConfiguration() {
71 * Clears all properties
78 * @see java.lang.Object#clone()
81 protected Object clone() throws CloneNotSupportedException {
82 DefaultConfiguration clone = (DefaultConfiguration) super.clone();
84 clone.properties = new Properties(this.properties);
85 clone.properties.putAll(this.properties);
91 * Decrypts an encrypted value, if it is encrypted, and returns the clear text. Performs no operation on the string
92 * if it is not encrypted.
94 * @param value The value to (optionally) be decrypted
95 * @return The clear text
97 @SuppressWarnings("nls")
98 private static String decrypt(String value) {
99 if (value != null && value.startsWith(EncryptionTool.ENCRYPTED_VALUE_PREFIX)) {
101 return EncryptionTool.getInstance().decrypt(value);
102 } catch (Exception e) {
103 StringBuilder out = new StringBuilder();
104 for (Provider p : Security.getProviders()) {
105 for (Service s : p.getServices()) {
106 String algo = s.getAlgorithm();
107 out.append(String.format("\n==Found Algorithm [ %s ] in provider [ %s ] and service [ %s ]",
108 algo, p.getName(), s.getClassName()));
111 logger.debug(out.toString());
112 logger.warn(String.format("Could not decrypt the configuration value [%s]", value), e);
119 * Decrypts all elements in the properties object
121 private void decryptAllProperties() {
122 if (properties != null) {
123 for (Entry<Object, Object> e : properties.entrySet()) {
124 if (e.getValue() != null) {
125 e.setValue(decrypt(e.getValue().toString()));
132 * @see java.lang.Object#equals(java.lang.Object)
135 public boolean equals(Object obj) {
141 if (this.getClass() != obj.getClass()) {
145 DefaultConfiguration other = (DefaultConfiguration) obj;
147 return (this.properties.size() == other.properties.size())
148 && (this.properties.entrySet().containsAll(other.properties.entrySet()))
149 && (other.properties.entrySet().containsAll(this.properties.entrySet()));
154 * This method will use the properties object to expand any variables that may be present in the template provided.
155 * Variables are represented by the string "${name}", where "name" is the name of a property defined in either the
156 * current configuration object, or system properties if undefined. If the value cannot be found, the variable is
157 * removed and an empty string is used to replace the variable.
159 * @param template The template to be expanded
160 * @return The expanded template where each variable is replaced with its value
162 @SuppressWarnings("nls")
163 private String expandVariables(String template) {
164 if (template == null) {
168 // Decrypt the template if needed
169 // template = decrypt(template); DH: Do not assign values to parameters, bad form! Also, Sonar complains
172 StringBuilder builder = new StringBuilder(decrypt(template));
173 Pattern pattern = Pattern.compile("\\$\\{([^\\}]+)\\}");
174 Matcher matcher = pattern.matcher(builder);
175 while (matcher.find()) {
176 String variable = matcher.group(1);
177 String value = properties.getProperty(variable);
179 value = System.getProperty(variable);
184 builder.replace(matcher.start(), matcher.end(), value);
188 return builder.toString().trim();
192 * This method is called to obtain a property expressed as a boolean value (true or false). The standard rules for
193 * Boolean.parseBoolean() are used.
195 * @param key The property key
196 * @return The value of the property expressed as a boolean, or false if it does not exist.
198 @SuppressWarnings("nls")
200 public boolean getBooleanProperty(String key) {
201 return Boolean.valueOf(getProperty(key, "false"));
205 * This method is called to obtain a property expressed as a boolean value (true or false). The standard rules for
206 * Boolean.valueOf(String) are used.
208 * @param key The property key
209 * @param defaultValue The default value to be returned if the property does not exist
210 * @return The value of the property expressed as a boolean, or false if it does not exist.
211 * @see org.onap.appc.configuration.Configuration#getBooleanProperty(java.lang.String, boolean)
214 public boolean getBooleanProperty(String key, boolean defaultValue) {
215 if (isPropertyDefined(key)) {
216 return getBooleanProperty(key);
222 * Returns the indicated property value expressed as a floating point double-precision value (double).
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 Integer.parseInt(String, int)
274 * 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 does not exist or
294 * 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 it does not exist
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 the property does
314 * 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 modify the properties
327 * object returned will result in an exception. This allows a caller to view the current configuration as a set of
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, java.lang.String)
362 public String getProperty(String key, String defaultValue) {
363 if (isPropertyDefined(key)) {
364 return getProperty(key);
367 if (defaultValue == null) {
371 return expandVariables(defaultValue.trim());
375 * @see java.lang.Object#hashCode()
378 public int hashCode() {
379 return properties == null ? 0 : properties.hashCode();
383 * Returns true if the named property is defined, false otherwise.
385 * @param key The key of the property we are interested in
386 * @return True if the property exists.
389 public boolean isPropertyDefined(String key) {
390 return properties.containsKey(key);
394 * Returns an indication of the validity of the boolean property. A boolean property is considered to be valid only
395 * if it has the value "true" or "false" (ignoring case).
397 * @param key The property to be checked
398 * @return True if the value is a boolean constant, or false if it does not exist or is not a correct string
399 * @see org.onap.appc.configuration.Configuration#isValidBoolean(java.lang.String)
401 @SuppressWarnings("nls")
403 public boolean isValidBoolean(String key) {
404 String value = getProperty(key);
406 value = value.toLowerCase();
407 return value.matches("true|false");
413 * Returns an indication if the indicated property represents a valid double-precision floating point number.
415 * @param key The property to be examined
416 * @return True if the property is a valid representation of a double, or false if it does not exist or contains
417 * illegal characters.
418 * @see org.onap.appc.configuration.Configuration#isValidDouble(java.lang.String)
421 public boolean isValidDouble(String key) {
422 String value = getProperty(key);
425 Double.valueOf(value);
427 } catch (NumberFormatException e) {
435 * Returns an indication if the property is a valid integer value or not.
437 * @param key The key of the property to check
438 * @return True if the value is a valid integer string, or false if it does not exist or contains illegal
440 * @see org.onap.appc.configuration.Configuration#isValidInteger(java.lang.String)
443 public boolean isValidInteger(String key) {
444 String value = getProperty(key);
447 Integer.parseInt(value.trim(), 10);
449 } catch (NumberFormatException e) {
457 * Determines is the specified property exists and is a valid representation of an integer long value.
459 * @param key The property to be checked
460 * @return True if the property is a valid representation of an integer long value, and false if it either does not
461 * exist or is not valid.
462 * @see org.onap.appc.configuration.Configuration#isValidLong(java.lang.String)
465 public boolean isValidLong(String key) {
466 String value = getProperty(key);
469 Long.parseLong(value.trim(), 10);
471 } catch (NumberFormatException e) {
479 * This method allows an implementation to load configuration properties that may override default values.
481 * @param is An input stream that contains the properties to be loaded
483 public void setProperties(InputStream is) {
486 } catch (IOException e) {
487 logger.warn("setProperties with inputStream got exception", e);
492 * This method allows an implementation to load configuration properties that may override default values.
494 * @param props An optional Properties object to be merged into the configuration, replacing any same-named
496 * @see org.onap.appc.configuration.Configuration#setProperties(java.util.Properties)
499 public void setProperties(Properties props) {
500 properties.putAll(props);
501 decryptAllProperties();
505 * This method allows a caller to insert a new property definition into the configuration object. This allows the
506 * application to adjust or add to the current configuration. If the property already exists, it is replaced with
509 * @param key The key of the property to be defined
510 * @param value The value of the property to be defined
511 * @see org.onap.appc.configuration.Configuration#setProperty(java.lang.String, java.lang.String)
514 public void setProperty(String key, String value) {
515 properties.setProperty(key, decrypt(value));
519 * @see java.lang.Object#toString()
521 @SuppressWarnings("nls")
523 public String toString() {
524 return String.format("Configuration: %d properties, keys:[%s]",
525 properties.size(), properties.keySet().toString());
529 * This is a helper method to read the manifest of the jar file that this class was loaded from. Note that this will
530 * only work if the code is packaged in a jar file. If it is an open deployment, such as under eclipse, this will
531 * not work and there is code added to detect that case.
533 * @return The manifest object from the jar file, or null if the code is not packaged in a jar file.
538 private Manifest getManifest() {
539 ProtectionDomain domain = getClass().getProtectionDomain();
540 CodeSource source = domain.getCodeSource();
541 URL location = source.getLocation();
542 String path = location.getPath();
543 int index = path.indexOf('!');
545 path = path.substring(0, index);
547 if (path.endsWith(".jar")) {
548 try (JarFile jar = new JarFile(location.getFile())) {
549 return jar.getManifest();
550 } catch (IOException e) {
551 logger.error("getManifest", e);