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;
41 import org.onap.appc.encryption.EncryptionTool;
42 import org.onap.appc.util.UnmodifiableProperties;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
47 * This class provides the implementation of the <code>Configuration</code> interface. It is created
48 * by the ConfigurationFactory and initialized with the configuration values for the process.
52 public final class DefaultConfiguration implements Configuration, Cloneable {
54 private static final Logger logger = LoggerFactory.getLogger(DefaultConfiguration.class);
57 * The framework configuration properties.
59 private Properties properties = new Properties();
62 * Construct the configuration object.
64 DefaultConfiguration() {}
67 * Clears all properties
74 * @see java.lang.Object#clone()
77 protected Object clone() throws CloneNotSupportedException {
78 DefaultConfiguration clone = (DefaultConfiguration) super.clone();
80 clone.properties = new Properties(this.properties);
81 clone.properties.putAll(this.properties);
87 * Decrypts an encrypted value, if it is encrypted, and returns the clear text. Performs no
88 * operation on the string if it is not encrypted.
90 * @param value The value to (optionally) be decrypted
91 * @return The clear text
93 @SuppressWarnings("nls")
94 private static String decrypt(String value) {
95 if (value != null && value.startsWith(EncryptionTool.ENCRYPTED_VALUE_PREFIX)) {
97 return EncryptionTool.getInstance().decrypt(value);
98 } catch (Exception e) {
99 StringBuilder out = new StringBuilder();
100 for (Provider p : Security.getProviders()) {
101 for (Service s : p.getServices()) {
102 String algo = s.getAlgorithm();
103 out.append(String.format(
104 "\n==Found Algorithm [ %s ] in provider [ %s ] and service [ %s ]",
105 algo, p.getName(), s.getClassName()));
108 logger.debug(out.toString());
109 logger.warn(String.format("Could not decrypt the configuration value [%s]", value),
117 * Decrypts all elements in the properties object
119 private void decryptAllProperties() {
120 if (properties != null) {
121 for (Entry<Object, Object> e : properties.entrySet()) {
122 if (e.getValue() != null) {
123 e.setValue(decrypt(e.getValue().toString()));
130 * @see java.lang.Object#equals(java.lang.Object)
133 public boolean equals(Object obj) {
139 if (this.getClass() != obj.getClass()) {
143 DefaultConfiguration other = (DefaultConfiguration) obj;
145 return (this.properties.size() == other.properties.size())
146 && (this.properties.entrySet().containsAll(other.properties.entrySet()))
147 && (other.properties.entrySet().containsAll(this.properties.entrySet()));
152 * This method will use the properties object to expand any variables that may be present in the
153 * template provided. Variables are represented by the string "${name}", where "name" is the
154 * name of a property defined in either the current configuration object, or system properties
155 * if undefined. If the value cannot be found, the variable is removed and an empty string is
156 * used to replace the variable.
158 * @param template The template to be expanded
159 * @return The expanded template where each variable is replaced with its value
161 @SuppressWarnings("nls")
162 private String expandVariables(String template) {
163 if (template == null) {
167 // Decrypt the template if needed
168 // template = decrypt(template); DH: Do not assign values to parameters, bad form! Also,
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
193 * standard rules for 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
206 * standard rules for 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
225 * @param key The property to retrieve
226 * @return The value of the property, or 0.0 if not found
227 * @see org.onap.appc.configuration.Configuration#getDoubleProperty(java.lang.String)
229 @SuppressWarnings("nls")
231 public double getDoubleProperty(String key) {
233 return Double.valueOf(getProperty(key, "0.0"));
234 } catch (NumberFormatException e) {
240 * This method is called to obtain a property as a string value
242 * @param key The key of the property
243 * @param defaultValue The default value to be returned if the property does not exist
244 * @return The string value, or null if it does not exist.
245 * @see org.onap.appc.configuration.Configuration#getDoubleProperty(java.lang.String, double)
248 public double getDoubleProperty(String key, double defaultValue) {
249 if (isPropertyDefined(key)) {
250 return getDoubleProperty(key);
256 * Returns the property indicated expressed as an integer. The standard rules for
257 * {@link Integer#parseInt(String, int)} using a radix of 10 are used.
259 * @param key The property name to retrieve.
260 * @return The value of the property, or 0 if it does not exist or is invalid.
261 * @see org.onap.appc.configuration.Configuration#getIntegerProperty(java.lang.String)
263 @SuppressWarnings("nls")
265 public int getIntegerProperty(String key) {
267 return Integer.parseInt(getProperty(key, "0"), 10);
268 } catch (NumberFormatException e) {
274 * Returns the property indicated expressed as an integer. The standard rules for
275 * Integer.parseInt(String, int) using a radix of 10 are used.
277 * @param key The property name to retrieve.
278 * @param defaultValue The default value to be returned if the property does not exist
279 * @return The value of the property, or 0 if it does not exist or is invalid.
280 * @see org.onap.appc.configuration.Configuration#getIntegerProperty(java.lang.String, int)
283 public int getIntegerProperty(String key, int defaultValue) {
284 if (isPropertyDefined(key)) {
285 return getIntegerProperty(key);
291 * Returns the specified property as a long integer value, if it exists, or zero if it does not.
293 * @param key The key of the property desired.
294 * @return The value of the property expressed as an integer long value, or zero if the property
295 * does not exist or is not a valid integer long.
296 * @see org.onap.appc.configuration.Configuration#getLongProperty(java.lang.String)
298 @SuppressWarnings("nls")
300 public long getLongProperty(String key) {
302 return Long.parseLong(getProperty(key, "0"), 10);
303 } catch (NumberFormatException e) {
309 * Returns the specified property as a long integer value, if it exists, or the default value if
310 * it does not exist or is invalid.
312 * @param key The key of the property desired.
313 * @param defaultValue the value to be returned if the property is not valid or does not exist.
314 * @return The value of the property expressed as an integer long value, or the default value if
315 * the property does not exist or is not a valid integer long.
316 * @see org.onap.appc.configuration.Configuration#getLongProperty(java.lang.String, long)
319 public long getLongProperty(String key, long defaultValue) {
320 if (isPropertyDefined(key)) {
321 return getLongProperty(key);
327 * This method can be called to retrieve a properties object that is immutable. Any attempt to
328 * modify the properties object returned will result in an exception. This allows a caller to
329 * view the current configuration as a set of properties.
331 * @return An unmodifiable properties object.
332 * @see org.onap.appc.configuration.Configuration#getProperties()
335 public Properties getProperties() {
336 return new UnmodifiableProperties(properties);
340 * This method is called to obtain a property as a string value
342 * @param key The key of the property
343 * @return The string value, or null if it does not exist.
346 public String getProperty(String key) {
347 String value = properties.getProperty(key);
351 return expandVariables(value.trim());
355 * This method is called to obtain a property as a string value
357 * @param key The key of the property
358 * @param defaultValue The default value to be returned if the property does not exist
359 * @return The string value, or null if it does not exist.
360 * @see org.onap.appc.configuration.Configuration#getProperty(java.lang.String,
364 public String getProperty(String key, String defaultValue) {
365 if (isPropertyDefined(key)) {
366 return getProperty(key);
369 if (defaultValue == null) {
373 return expandVariables(defaultValue.trim());
377 * @see java.lang.Object#hashCode()
380 public int hashCode() {
381 return properties == null ? 0 : properties.hashCode();
385 * Returns true if the named property is defined, false otherwise.
387 * @param key The key of the property we are interested in
388 * @return True if the property exists.
391 public boolean isPropertyDefined(String key) {
392 return properties.containsKey(key);
396 * Returns an indication of the validity of the boolean property. A boolean property is
397 * considered to be valid only if it has the value "true" or "false" (ignoring case).
399 * @param key The property to be checked
400 * @return True if the value is a boolean constant, or false if it does not exist or is not a
402 * @see org.onap.appc.configuration.Configuration#isValidBoolean(java.lang.String)
404 @SuppressWarnings("nls")
406 public boolean isValidBoolean(String key) {
407 String value = getProperty(key);
409 value = value.toLowerCase();
410 return value.matches("true|false");
416 * Returns an indication if the indicated property represents a valid double-precision floating
419 * @param key The property to be examined
420 * @return True if the property is a valid representation of a double, or false if it does not
421 * exist or contains illegal characters.
422 * @see org.onap.appc.configuration.Configuration#isValidDouble(java.lang.String)
425 public boolean isValidDouble(String key) {
426 String value = getProperty(key);
429 Double.valueOf(value);
431 } catch (NumberFormatException e) {
439 * Returns an indication if the property is a valid integer value or not.
441 * @param key The key of the property to check
442 * @return True if the value is a valid integer string, or false if it does not exist or
443 * contains illegal characters.
444 * @see org.onap.appc.configuration.Configuration#isValidInteger(java.lang.String)
447 public boolean isValidInteger(String key) {
448 String value = getProperty(key);
451 Integer.parseInt(value.trim(), 10);
453 } catch (NumberFormatException e) {
461 * Determines is the specified property exists and is a valid representation of an integer long
464 * @param key The property to be checked
465 * @return True if the property is a valid representation of an integer long value, and false if
466 * it either does not exist or is not valid.
467 * @see org.onap.appc.configuration.Configuration#isValidLong(java.lang.String)
470 public boolean isValidLong(String key) {
471 String value = getProperty(key);
474 Long.parseLong(value.trim(), 10);
476 } catch (NumberFormatException e) {
484 * This method allows an implementation to load configuration properties that may override
487 * @param is An input stream that contains the properties to be loaded
489 public void setProperties(InputStream is) {
492 } catch (IOException e) {
493 logger.warn("setProperties with inputStream got exception", e);
498 * This method allows an implementation to load configuration properties that may override
501 * @param props An optional Properties object to be merged into the configuration, replacing any
502 * same-named properties.
503 * @see org.onap.appc.configuration.Configuration#setProperties(java.util.Properties)
506 public void setProperties(Properties props) {
507 properties.putAll(props);
508 decryptAllProperties();
512 * This method allows a caller to insert a new property definition into the configuration
513 * object. This allows the application to adjust or add to the current configuration. If the
514 * property already exists, it is replaced with the new value.
516 * @param key The key of the property to be defined
517 * @param value The value of the property to be defined
518 * @see org.onap.appc.configuration.Configuration#setProperty(java.lang.String,
522 public void setProperty(String key, String value) {
523 properties.setProperty(key, decrypt(value));
527 * @see java.lang.Object#toString()
529 @SuppressWarnings("nls")
531 public String toString() {
532 return String.format("Configuration: %d properties, keys:[%s]", properties.size(),
533 properties.keySet().toString());
537 * This is a helper method to read the manifest of the jar file that this class was loaded from.
538 * Note that this will only work if the code is packaged in a jar file. If it is an open
539 * deployment, such as under eclipse, this will not work and there is code added to detect that
542 * @return The manifest object from the jar file, or null if the code is not packaged in a jar
545 @SuppressWarnings({"unused", "nls"})
546 private Manifest getManifest() {
547 ProtectionDomain domain = getClass().getProtectionDomain();
548 CodeSource source = domain.getCodeSource();
549 URL location = source.getLocation();
550 String path = location.getPath();
551 int index = path.indexOf('!');
553 path = path.substring(0, index);
555 if (path.endsWith(".jar")) {
556 try (JarFile jar = new JarFile(location.getFile())) {
557 return jar.getManifest();
558 } catch (IOException e) {
559 logger.error("getManifest", e);