summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/src/main/java/org/onap/policy/common/utils/properties/PropertyConfiguration.java465
-rw-r--r--utils/src/main/java/org/onap/policy/common/utils/properties/SpecPropertyConfiguration.java233
-rw-r--r--utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyAccessException.java70
-rw-r--r--utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyAnnotationException.java69
-rw-r--r--utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyException.java142
-rw-r--r--utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyInvalidException.java70
-rw-r--r--utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyMissingException.java38
-rw-r--r--utils/src/test/java/org/onap/policy/common/utils/properties/PropertyConfigurationTest.java1031
-rw-r--r--utils/src/test/java/org/onap/policy/common/utils/properties/SpecPropertyConfigurationTest.java331
-rw-r--r--utils/src/test/java/org/onap/policy/common/utils/properties/exception/BasicPropertyExceptionTester.java130
-rw-r--r--utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyAccessExceptionTest.java66
-rw-r--r--utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyAnnotationExceptionTest.java70
-rw-r--r--utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyExceptionTest.java69
-rw-r--r--utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyInvalidExceptionTest.java70
-rw-r--r--utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyMissingExceptionTest.java42
15 files changed, 2896 insertions, 0 deletions
diff --git a/utils/src/main/java/org/onap/policy/common/utils/properties/PropertyConfiguration.java b/utils/src/main/java/org/onap/policy/common/utils/properties/PropertyConfiguration.java
new file mode 100644
index 00000000..7253c746
--- /dev/null
+++ b/utils/src/main/java/org/onap/policy/common/utils/properties/PropertyConfiguration.java
@@ -0,0 +1,465 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Properties;
+import org.onap.policy.common.utils.properties.exception.PropertyAccessException;
+import org.onap.policy.common.utils.properties.exception.PropertyException;
+import org.onap.policy.common.utils.properties.exception.PropertyInvalidException;
+import org.onap.policy.common.utils.properties.exception.PropertyMissingException;
+
+/**
+ * Configuration whose fields are initialized by reading from a set of {@link Properties},
+ * as directed by the {@link Property} annotations that appear on fields within the
+ * subclass.
+ * <p>
+ * It is possible that an invalid <i>defaultValue</i> is specified via the
+ * {@link Property} annotation. This could remain undetected until an optional property is
+ * left out of the {@link Properties}. Consequently, this class will always validate a
+ * {@link Property}'s default value, if the <i>defaultValue</i> is not empty or if
+ * <i>accept</i> includes the "empty" option.
+ */
+public class PropertyConfiguration {
+
+ /**
+ * The "empty" option that may appear within the {@link Property}'s <i>accept</i>
+ * attribute.
+ */
+ public static final String ACCEPT_EMPTY = "empty";
+
+ /**
+ * Constructs a configuration, without populating any fields; fields should be
+ * populated later by invoking {@link #setAllFields(Properties)}.
+ */
+ public PropertyConfiguration() {
+ super();
+ }
+
+ /**
+ * Initializes each "@Property" field with its value, as found in the properties.
+ *
+ * @param props properties from which to extract the values
+ * @throws PropertyException if an error occurs
+ */
+ public PropertyConfiguration(Properties props) throws PropertyException {
+ setAllFields(props);
+ }
+
+ /**
+ * Walks the class hierarchy of "this" object, populating fields defined in each
+ * class, using values extracted from the given property set.
+ *
+ * @param props properties from which to extract the values
+ * @throws PropertyException if an error occurs
+ */
+ public void setAllFields(Properties props) throws PropertyException {
+ Class<?> clazz = getClass();
+
+ while (clazz != PropertyConfiguration.class) {
+ for (Field field : clazz.getDeclaredFields()) {
+ setValue(field, props);
+ }
+
+ clazz = clazz.getSuperclass();
+ }
+ }
+
+ /**
+ * Sets a field's value, within an object, based on what's in the properties.
+ *
+ * @param field field whose value is to be set
+ * @param props properties from which to get the value
+ * @return {@code true} if the property's value was set, {@code false} otherwise
+ * @throws PropertyException if an error occurs
+ */
+ protected boolean setValue(Field field, Properties props) throws PropertyException {
+ Property prop = field.getAnnotation(Property.class);
+ if (prop == null) {
+ return false;
+ }
+
+ checkModifiable(field, prop);
+
+ if (setValue(field, props, prop)) {
+ return true;
+ }
+
+ throw new PropertyAccessException(prop.name(), field.getName(), "unsupported field type");
+ }
+
+ /**
+ * Sets a field's value from a particular property.
+ *
+ * @param field field whose value is to be set
+ * @param props properties from which to get the value
+ * @param prop property of interest
+ * @return {@code true} if the property's value was set, {@code false} otherwise
+ * @throws PropertyException if an error occurs
+ */
+ protected boolean setValue(Field field, Properties props, Property prop) throws PropertyException {
+
+ try {
+ Object val = getValue(field, props, prop);
+ if (val == null) {
+ return false;
+
+ } else {
+
+ /*
+ * According to java docs & blogs, "field" is our own copy, so we're free
+ * to change the flags without impacting the real permissions of the field
+ * within the real class.
+ */
+ field.setAccessible(true);
+
+ field.set(this, val);
+ return true;
+ }
+
+ } catch (IllegalArgumentException e) {
+ throw new PropertyInvalidException(prop.name(), field.getName(), e);
+
+ } catch (IllegalAccessException e) {
+ throw new PropertyAccessException(prop.name(), field.getName(), e);
+ }
+ }
+
+ /**
+ * Gets a property value, coercing it to the field's type.
+ *
+ * @param field field whose value is to be set
+ * @param props properties from which to get the value
+ * @param prop property of interest
+ * @return the value extracted from the property, or {@code null} if the field type is
+ * not supported
+ * @throws PropertyException if an error occurs
+ */
+ protected Object getValue(Field field, Properties props, Property prop) throws PropertyException {
+
+ Class<?> clazz = field.getType();
+ String fieldName = field.getName();
+
+ // can still add support for short, float, double, enum
+
+ if (clazz == String.class) {
+ return getStringValue(fieldName, props, prop);
+
+ } else if (clazz == Boolean.class || clazz == boolean.class) {
+ return getBooleanValue(fieldName, props, prop);
+
+ } else if (clazz == Integer.class || clazz == int.class) {
+ return getIntegerValue(fieldName, props, prop);
+
+ } else if (clazz == Long.class || clazz == long.class) {
+ return getLongValue(fieldName, props, prop);
+
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Verifies that the field can be modified, i.e., it's neither <i>static</i>, nor
+ * <i>final</i>.
+ *
+ * @param field field whose value is to be set
+ * @param prop property of interest
+ * @throws PropertyAccessException if the field is not modifiable
+ */
+ protected void checkModifiable(Field field, Property prop) throws PropertyAccessException {
+ int mod = field.getModifiers();
+
+ if (Modifier.isStatic(mod)) {
+ throw new PropertyAccessException(prop.name(), field.getName(), "'static' variable cannot be modified");
+ }
+
+ if (Modifier.isFinal(mod)) {
+ throw new PropertyAccessException(prop.name(), field.getName(), "'final' variable cannot be modified");
+ }
+ }
+
+ /**
+ * Gets a property value, coercing it to a String.
+ *
+ * @param fieldName field whose value is to be set
+ * @param props properties from which to get the value
+ * @param prop property of interest
+ * @return the value extracted from the property
+ * @throws PropertyException if an error occurs
+ */
+ protected String getStringValue(String fieldName, Properties props, Property prop) throws PropertyException {
+
+ /*
+ * Note: the default value for a String type is always valid, thus no need to
+ * check it.
+ */
+
+ return getPropValue(fieldName, props, prop);
+ }
+
+ /**
+ * Gets a property value, coercing it to a Boolean.
+ *
+ * @param fieldName field whose value is to be set
+ * @param props properties from which to get the value
+ * @param prop property of interest
+ * @return the value extracted from the property
+ * @throws PropertyException if an error occurs
+ */
+ protected Boolean getBooleanValue(String fieldName, Properties props, Property prop) throws PropertyException {
+ // validate the default value
+ checkDefaultValue(fieldName, prop, xxx -> makeBoolean(fieldName, prop, prop.defaultValue()));
+
+ return makeBoolean(fieldName, prop, getPropValue(fieldName, props, prop));
+ }
+
+ /**
+ * Gets a property value, coercing it to an Integer.
+ *
+ * @param fieldName field whose value is to be set
+ * @param props properties from which to get the value
+ * @param prop property of interest
+ * @return the value extracted from the property
+ * @throws PropertyException if an error occurs
+ */
+ protected Integer getIntegerValue(String fieldName, Properties props, Property prop) throws PropertyException {
+ // validate the default value
+ checkDefaultValue(fieldName, prop, xxx -> makeInteger(fieldName, prop, prop.defaultValue()));
+
+ return makeInteger(fieldName, prop, getPropValue(fieldName, props, prop));
+ }
+
+ /**
+ * Gets a property value, coercing it to a Long.
+ *
+ * @param fieldName field whose value is to be set
+ * @param props properties from which to get the value
+ * @param prop property of interest
+ * @return the value extracted from the property
+ * @throws PropertyException if an error occurs
+ */
+ protected Long getLongValue(String fieldName, Properties props, Property prop) throws PropertyException {
+ // validate the default value
+ checkDefaultValue(fieldName, prop, xxx -> makeLong(fieldName, prop, prop.defaultValue()));
+
+ return makeLong(fieldName, prop, getPropValue(fieldName, props, prop));
+ }
+
+ /**
+ * Gets a value from the property set.
+ *
+ * @param fieldName field whose value is to be set
+ * @param props properties from which to get the value
+ * @param prop property of interest
+ * @return the value extracted from the property, or the <i>defaultValue</i> if the
+ * value does not exist
+ * @throws PropertyMissingException if the property does not exist and the
+ * <i>defaultValue</i> is empty and <i>emptyOk</i> is {@code false}
+ */
+ protected String getPropValue(String fieldName, Properties props, Property prop) throws PropertyMissingException {
+ String propnm = prop.name();
+
+ String val = getRawPropertyValue(props, propnm);
+ if (val != null && isEmptyOk(prop, val)) {
+ return val;
+ }
+
+ val = prop.defaultValue();
+ if (val != null && isEmptyOk(prop, val)) {
+ return val;
+ }
+
+ throw new PropertyMissingException(prop.name(), fieldName);
+ }
+
+ /**
+ * Gets the property value, straight from the property set.
+ *
+ * @param props properties from which to get the value
+ * @param propnm name of the property of interest
+ * @return
+ */
+ protected String getRawPropertyValue(Properties props, String propnm) {
+ return props.getProperty(propnm);
+ }
+
+ /**
+ * Coerces a String value into a Boolean.
+ *
+ * @param fieldName field whose value is to be set
+ * @param prop property of interest
+ * @param value value to be coerced
+ * @return the Boolean value represented by the String value
+ * @throws PropertyInvalidException if the value does not represent a valid Boolean
+ */
+ private Boolean makeBoolean(String fieldName, Property prop, String value) throws PropertyInvalidException {
+ if ("true".equals(value.toLowerCase())) {
+ return Boolean.TRUE;
+
+ } else if ("false".equals(value.toLowerCase())) {
+ return Boolean.FALSE;
+
+ } else {
+ throw new PropertyInvalidException(prop.name(), fieldName, "expecting 'true' or 'false'");
+ }
+ }
+
+ /**
+ * Coerces a String value into an Integer.
+ *
+ * @param fieldName field whose value is to be set
+ * @param prop property of interest
+ * @param value value to be coerced
+ * @return the Integer value represented by the String value
+ * @throws PropertyInvalidException if the value does not represent a valid Integer
+ */
+ private Integer makeInteger(String fieldName, Property prop, String value) throws PropertyInvalidException {
+ try {
+ return Integer.valueOf(value);
+
+ } catch (NumberFormatException e) {
+ throw new PropertyInvalidException(prop.name(), fieldName, e);
+ }
+ }
+
+ /**
+ * Coerces a String value into a Long.
+ *
+ * @param fieldName field whose value is to be set
+ * @param prop property of interest
+ * @param value value to be coerced
+ * @return the Long value represented by the String value
+ * @throws PropertyInvalidException if the value does not represent a valid Long
+ */
+ private Long makeLong(String fieldName, Property prop, String value) throws PropertyInvalidException {
+ try {
+ return Long.valueOf(value);
+
+ } catch (NumberFormatException e) {
+ throw new PropertyInvalidException(prop.name(), fieldName, e);
+ }
+ }
+
+ /**
+ * Applies a function to check a property's default value. If the function throws an
+ * exception about an invalid property, then it's re-thrown as an exception about an
+ * invalid <i>defaultValue</i>.
+ *
+ * @param fieldName name of the field being checked
+ * @param prop property of interest
+ * @param func function to invoke to check the default value
+ */
+ private void checkDefaultValue(String fieldName, Property prop, CheckDefaultValueFunction func)
+ throws PropertyInvalidException {
+
+ if (isEmptyOk(prop, prop.defaultValue())) {
+ try {
+ func.apply(null);
+
+ } catch (PropertyInvalidException ex) {
+ throw new PropertyInvalidException(ex.getPropertyName(), fieldName, "defaultValue is invalid",
+ ex.getCause());
+ }
+ }
+ }
+
+ /**
+ * Determines if a value is OK, even if it's empty.
+ *
+ * @param prop property specifying what's acceptable
+ * @param value value to be checked
+ * @return {@code true} if the value is not empty or empty is allowed, {@code false}
+ * otherwise
+ */
+ protected boolean isEmptyOk(Property prop, String value) {
+ return !value.isEmpty() || isEmptyOk(prop);
+ }
+
+ /**
+ * Determines if a {@link Property}'s <i>accept</i> attribute includes the "empty"
+ * option.
+ *
+ * @param prop property whose <i>accept</i> attribute is to be examined
+ * @return {@code true} if the <i>accept</i> attribute includes "empty"
+ */
+ protected boolean isEmptyOk(Property prop) {
+ for (String option : prop.accept().split(",")) {
+ if (ACCEPT_EMPTY.equals(option)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Functions to check a default value.
+ */
+ @FunctionalInterface
+ private static interface CheckDefaultValueFunction {
+
+ /**
+ * Checks the default value.
+ *
+ * @param arg always {@code null}
+ * @throws PropertyInvalidException if an error occurs
+ */
+ public void apply(Void arg) throws PropertyInvalidException;
+ }
+
+ /**
+ * Annotation that declares a variable to be configured via {@link Properties}.
+ */
+ @Target(ElementType.FIELD)
+ @Retention(RetentionPolicy.RUNTIME)
+
+ protected static @interface Property {
+
+ /**
+ * Name of the property.
+ *
+ * @return the property name
+ */
+ public String name();
+
+ /**
+ * Default value, used when the property does not exist.
+ *
+ * @return the default value
+ */
+ public String defaultValue() default "";
+
+ /**
+ * Comma-separated options identifying what's acceptable. The word, "empty",
+ * indicates that an empty string, "", is an acceptable value.
+ *
+ * @return options identifying what's acceptable
+ */
+ public String accept() default "";
+
+ }
+}
diff --git a/utils/src/main/java/org/onap/policy/common/utils/properties/SpecPropertyConfiguration.java b/utils/src/main/java/org/onap/policy/common/utils/properties/SpecPropertyConfiguration.java
new file mode 100644
index 00000000..9e3767c1
--- /dev/null
+++ b/utils/src/main/java/org/onap/policy/common/utils/properties/SpecPropertyConfiguration.java
@@ -0,0 +1,233 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties;
+
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.onap.policy.common.utils.properties.exception.PropertyException;
+
+/**
+ * PropertyConfiguration whose property names are specialized, using a specialization. A
+ * property name can take one of the following forms:
+ * <dl>
+ * <dt>aaa{$}Ddd</dt>
+ * <dd>if the specialization is "Xxx", then it looks for the value associated with the
+ * property named "aaaXxxDdd"</dd>
+ * <dt>aaa{Bbb?Ccc}Ddd</dt>
+ * <dd>if the specialization is "Xxx", then it looks for the value associated with the
+ * property named "aaaBbbXxxCccDdd". If the property does not exist, then it looks for the
+ * value associated with the property named "aaaDdd" (i.e., without the
+ * specialization)</dd>
+ * <dt>aaa</dt>
+ * <dd>simply looks for the value associated with the property named "aaa", without using
+ * the specialization</dd>
+ * </dl>
+ * <p>
+ * In the above examples, any of the components (e.g., "aaa") may be empty.
+ */
+public class SpecPropertyConfiguration extends PropertyConfiguration {
+
+ /**
+ * Pattern to extract the specializer from a property name. Group 1 matches the form,
+ * "{$}", while groups 2 and 3 match the prefix and suffix, respectively, of the form,
+ * "{prefix?suffix}".
+ */
+ private static final Pattern SPEC_PAT = Pattern.compile(""
+ // start of specialization info
+ + "\\{(?:"
+ // specialization type 1
+ + "(\\$)"
+ // alternative
+ + "|"
+ // specialization type 2
+ + "(?:"
+ // specialization type 2 prefix, may be empty
+ + "([^}?]*)"
+ // place-holder for the specialization, itself
+ + "\\?"
+ // specialization type 2 suffix, may be empty
+ + "([^}]*)"
+ // end of specialization type 2
+ + ")"
+ // end of specialization info
+ + ")\\}");
+
+ /**
+ * The specialization to be used within property names.
+ */
+ private final String specialization;
+
+ /**
+ * Constructs a configuration, without populating any fields; fields should be
+ * populated later by invoking {@link #setAllFields(Properties)}.
+ *
+ * @param specialization specialization to be substituted within property names
+ */
+ public SpecPropertyConfiguration(String specialization) {
+ super();
+
+ this.specialization = specialization;
+ }
+
+ /**
+ *
+ * Initializes each "@Property" field with its value, as found in the properties.
+ *
+ * @param specialization specialization to be substituted within property names
+ * @param props properties from which to extract the values
+ * @throws PropertyException if an error occurs
+ */
+ public SpecPropertyConfiguration(String specialization, Properties props) throws PropertyException {
+ super();
+
+ this.specialization = specialization;
+
+ setAllFields(props);
+ }
+
+ /**
+ * Gets a property's value, examining the property name for each of the types of
+ * specialization.
+ */
+ @Override
+ protected String getRawPropertyValue(Properties props, String propnm) {
+ Matcher mat = SPEC_PAT.matcher(propnm);
+
+ if (!mat.find()) {
+ // property name isn't specialized - use it as is
+ return super.getRawPropertyValue(props, propnm);
+
+ } else if (mat.group(1) != null) {
+ // replace "{$}" with the specialization name
+ return super.getRawPropertyValue(props, specializeType1(propnm, specialization, mat));
+
+ } else {
+ // first try to get the property using the specialization info
+ String val = super.getRawPropertyValue(props, specializeType2(propnm, specialization, mat));
+ if (val != null) {
+ return val;
+ }
+
+ // wasn't found - try again, without any specialization info
+ return super.getRawPropertyValue(props, generalizeType2(propnm, mat));
+ }
+ }
+
+ /**
+ * Generalizes a property name by stripping any specialization info from it. This is
+ * typically used to construct property names for junit testing.
+ *
+ * @param propnm property name to be stripped of specialization info
+ * @return the generalized property name
+ * @throws IllegalArgumentException if the property name requires specialization
+ * (i.e., contains "{$}")
+ */
+ public static String generalize(String propnm) {
+ Matcher mat = SPEC_PAT.matcher(propnm);
+
+ if (!mat.find()) {
+ // property name has no specialization info
+ return propnm;
+
+ } else if (mat.group(1) != null) {
+ // the "{$}" form requires specialization
+ throw new IllegalArgumentException("property requires specialization");
+
+ } else {
+ // property name has specialization info - strip it out
+ return generalizeType2(propnm, mat);
+ }
+ }
+
+ /**
+ *
+ * Generalizes a property name of specialization type 2 (i.e., "{xxx?yyy}" form).
+ *
+ * @param propnm property name to be stripped of specialization info
+ * @param matcher the matcher that matched the "{xxx?yyy}"
+ * @return the generalized property name
+ */
+ private static String generalizeType2(String propnm, Matcher mat) {
+ String prefix = propnm.substring(0, mat.start());
+ String suffix = propnm.substring(mat.end());
+
+ return prefix + suffix;
+ }
+
+ /**
+ * Specializes a property name by applying the specialization. This is typically used
+ * to construct property names for junit testing.
+ *
+ * @param propnm property name to be stripped of specialization info
+ * @param spec specialization to apply
+ * @return the specialized property name
+ */
+ public static String specialize(String propnm, String spec) {
+ Matcher mat = SPEC_PAT.matcher(propnm);
+
+ if (!mat.find()) {
+ // property name has no specialization info - leave it as is
+ return propnm;
+
+ } else if (mat.group(1) != null) {
+ // the "{$}" form requires specialization
+ return specializeType1(propnm, spec, mat);
+
+ } else {
+ // the "{xxx?yyy}" form requires specialization
+ return specializeType2(propnm, spec, mat);
+ }
+ }
+
+ /**
+ * Specializes a property name of specialization type 1 (i.e., "{$}" form).
+ *
+ * @param propnm property name to be stripped of specialization info
+ * @param spec specialization to apply
+ * @param matcher the matcher that matched the "{$}"
+ * @return the specialized property name
+ */
+ private static String specializeType1(String propnm, String spec, Matcher mat) {
+ String prefix = propnm.substring(0, mat.start());
+ String suffix = propnm.substring(mat.end());
+
+ return prefix + spec + suffix;
+ }
+
+ /**
+ * Specializes a property name of specialization type 2 (i.e., "{xxx?yyy}" form).
+ *
+ * @param propnm property name to be stripped of specialization info
+ * @param spec specialization to apply
+ * @param matcher the matcher that matched the "{xxx?yyy}"
+ * @return the specialized property name
+ */
+ private static String specializeType2(String propnm, String spec, Matcher matcher) {
+ String prefix = propnm.substring(0, matcher.start());
+ String suffix = propnm.substring(matcher.end());
+
+ String specPrefix = matcher.group(2);
+ String specSuffix = matcher.group(3);
+
+ return (prefix + specPrefix + spec + specSuffix + suffix);
+ }
+}
diff --git a/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyAccessException.java b/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyAccessException.java
new file mode 100644
index 00000000..568a8a79
--- /dev/null
+++ b/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyAccessException.java
@@ -0,0 +1,70 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties.exception;
+
+/**
+ * Exception indicating that a property's value cannot be converted to the type required
+ * by the target field.
+ */
+public class PropertyAccessException extends PropertyException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ */
+ public PropertyAccessException(String propnm, String fieldName) {
+ super(propnm, fieldName);
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param message error message
+ */
+ public PropertyAccessException(String propnm, String fieldName, String message) {
+ super(propnm, fieldName, message);
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param cause cause of the exception
+ */
+ public PropertyAccessException(String propnm, String fieldName, Throwable cause) {
+ super(propnm, fieldName, cause);
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param message error message
+ * @param cause cause of the exception
+ */
+ public PropertyAccessException(String propnm, String fieldName, String message, Throwable cause) {
+ super(propnm, fieldName, message, cause);
+ }
+
+}
diff --git a/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyAnnotationException.java b/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyAnnotationException.java
new file mode 100644
index 00000000..2803ddfe
--- /dev/null
+++ b/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyAnnotationException.java
@@ -0,0 +1,69 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties.exception;
+
+/**
+ * Exception indicating that a property annotation's definition (e.g., null name).
+ */
+public class PropertyAnnotationException extends PropertyException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ */
+ public PropertyAnnotationException(String propnm, String fieldName) {
+ super(propnm, fieldName);
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param message error message
+ */
+ public PropertyAnnotationException(String propnm, String fieldName, String message) {
+ super(propnm, fieldName, message);
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param cause cause of the exception
+ */
+ public PropertyAnnotationException(String propnm, String fieldName, Throwable cause) {
+ super(propnm, fieldName, cause);
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param message error message
+ * @param cause cause of the exception
+ */
+ public PropertyAnnotationException(String propnm, String fieldName, String message, Throwable cause) {
+ super(propnm, fieldName, message, cause);
+ }
+
+}
diff --git a/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyException.java b/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyException.java
new file mode 100644
index 00000000..8df4fb8e
--- /dev/null
+++ b/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyException.java
@@ -0,0 +1,142 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties.exception;
+
+/**
+ * Exception associated with a Property.
+ */
+public class PropertyException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Name of the property for which the exception was thrown.
+ */
+ private final String propertyName;
+
+ /**
+ * Name of the field for which the exception was thrown.
+ */
+ private final String fieldName;
+
+ /**
+ *
+ * @param propName name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ */
+ public PropertyException(String propName, String fieldName) {
+ super(makeMessage(propName, fieldName));
+
+ this.propertyName = propName;
+ this.fieldName = fieldName;
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param message error message
+ */
+ public PropertyException(String propnm, String fieldName, String message) {
+ super(makeMessage(propnm, fieldName, message));
+
+ this.propertyName = propnm;
+ this.fieldName = fieldName;
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param cause cause of the exception
+ */
+ public PropertyException(String propnm, String fieldName, Throwable cause) {
+ super(makeMessage(propnm, fieldName), cause);
+
+ this.propertyName = propnm;
+ this.fieldName = fieldName;
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param message error message
+ * @param cause cause of the exception
+ */
+ public PropertyException(String propnm, String fieldName, String message, Throwable cause) {
+ super(makeMessage(propnm, fieldName, message), cause);
+
+ this.propertyName = propnm;
+ this.fieldName = fieldName;
+ }
+
+ /**
+ *
+ * @return name of the property for which the exception was thrown, or {@code null} if
+ * no name was provided
+ */
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ /**
+ *
+ * @return name of the field for which the exception was thrown, or {@code null} if no
+ * field was provided
+ */
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ /**
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param message error message, never {@code null}
+ * @return an error message composed of the three items
+ */
+ private static String makeMessage(String propnm, String fieldName, String message) {
+ return makeMessage(propnm, fieldName) + ": " + message;
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @return an error message composed of the two items
+ */
+ private static String makeMessage(String propnm, String fieldName) {
+ StringBuilder bldr = new StringBuilder(50);
+
+ if (propnm == null) {
+ bldr.append("property exception");
+
+ } else {
+ bldr.append("exception for property " + propnm);
+ }
+
+ if (fieldName != null) {
+ bldr.append(" with field " + fieldName);
+ }
+
+ return bldr.toString();
+ }
+
+}
diff --git a/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyInvalidException.java b/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyInvalidException.java
new file mode 100644
index 00000000..da1b6ae8
--- /dev/null
+++ b/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyInvalidException.java
@@ -0,0 +1,70 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties.exception;
+
+/**
+ * Exception indicating that a property's value cannot be converted to the type required
+ * by the target field.
+ */
+public class PropertyInvalidException extends PropertyException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ */
+ public PropertyInvalidException(String propnm, String fieldName) {
+ super(propnm, fieldName);
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param message error message
+ */
+ public PropertyInvalidException(String propnm, String fieldName, String message) {
+ super(propnm, fieldName, message);
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param cause cause of the exception
+ */
+ public PropertyInvalidException(String propnm, String fieldName, Throwable cause) {
+ super(propnm, fieldName, cause);
+ }
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ * @param message error message
+ * @param cause cause of the exception
+ */
+ public PropertyInvalidException(String propnm, String fieldName, String message, Throwable cause) {
+ super(propnm, fieldName, message, cause);
+ }
+
+}
diff --git a/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyMissingException.java b/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyMissingException.java
new file mode 100644
index 00000000..de542e6a
--- /dev/null
+++ b/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyMissingException.java
@@ -0,0 +1,38 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties.exception;
+
+/**
+ * Exception indicating that a property is missing.
+ */
+public class PropertyMissingException extends PropertyException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ * @param propnm name of the property causing the exception, or {@code null}
+ * @param fieldName name of the field causing the exception, or {@code null}
+ */
+ public PropertyMissingException(String propnm, String fieldName) {
+ super(propnm, fieldName);
+ }
+
+}
diff --git a/utils/src/test/java/org/onap/policy/common/utils/properties/PropertyConfigurationTest.java b/utils/src/test/java/org/onap/policy/common/utils/properties/PropertyConfigurationTest.java
new file mode 100644
index 00000000..cf823b5d
--- /dev/null
+++ b/utils/src/test/java/org/onap/policy/common/utils/properties/PropertyConfigurationTest.java
@@ -0,0 +1,1031 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import java.lang.reflect.Field;
+import java.util.Properties;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.common.utils.properties.exception.PropertyAccessException;
+import org.onap.policy.common.utils.properties.exception.PropertyException;
+import org.onap.policy.common.utils.properties.exception.PropertyInvalidException;
+import org.onap.policy.common.utils.properties.exception.PropertyMissingException;
+
+/**
+ *
+ */
+public class PropertyConfigurationTest {
+
+ /**
+ * Property used for most of the simple configuration subclasses.
+ */
+ private static final String THE_VALUE = "the.value";
+
+ /**
+ * String property value.
+ */
+ private static final String STRING_VALUE = "a string";
+
+ /**
+ * Default value for string property.
+ */
+ private static final String STRING_VALUE_DEFAULT = "another string";
+
+ /**
+ * Value that cannot be coerced into any other type.
+ */
+ private static final String INVALID_VALUE = "invalid";
+
+ /**
+ * Properties used when invoking constructors.
+ */
+ private Properties props;
+
+ @Before
+ public void setUp() {
+ props = new Properties();
+ }
+
+ @Test
+ public void testPropertyConfiguration() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private String value;
+ };
+
+ props.setProperty(THE_VALUE, STRING_VALUE);
+
+ Config cfg = new Config();
+ assertEquals(null, cfg.value);
+
+ cfg.setAllFields(props);
+ assertEquals(STRING_VALUE, cfg.value);
+ }
+
+ @Test
+ public void testPropertyConfigurationProperties() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ Config cfg = new Config(props);
+
+ assertEquals(STRING_VALUE, cfg.value);
+ }
+
+ @Test
+ public void testSetAllFields() throws Exception {
+
+ /*
+ * Implements an extra interface, just to see that it doesn't cause issues.
+ */
+ class GrandParentConfig extends PropertyConfiguration implements DoesNothing {
+
+ @Property(name = "grandparent.value")
+ protected boolean grandparentValue;
+ };
+
+ /*
+ * Implements the extra interface, too.
+ */
+ class ParentConfig extends GrandParentConfig implements DoesNothing {
+
+ @Property(name = "parent.value")
+ protected long parentValue;
+ };
+
+ class Config extends ParentConfig {
+
+ @Property(name = THE_VALUE)
+ private String value;
+ };
+
+
+ Config cfg = new Config();
+
+ // try one set of values
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ props.setProperty("parent.value", "50000");
+ props.setProperty("grandparent.value", "true");
+ cfg.setAllFields(props);
+
+ assertEquals(STRING_VALUE, cfg.value);
+ assertEquals(50000L, cfg.parentValue);
+ assertEquals(true, cfg.grandparentValue);
+
+ // now a different set of values
+ props.setProperty(THE_VALUE, STRING_VALUE + "x");
+ props.setProperty("parent.value", "50001");
+ props.setProperty("grandparent.value", "false");
+ cfg.setAllFields(props);
+
+ assertEquals(STRING_VALUE + "x", cfg.value);
+ assertEquals(50001L, cfg.parentValue);
+ assertEquals(false, cfg.grandparentValue);
+ }
+
+ @Test
+ public void testSetAllFields_NoProperties() throws Exception {
+
+ class Config extends PropertyConfiguration {
+
+ private String value;
+ };
+
+
+ Config cfg = new Config();
+
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ cfg.setAllFields(props);
+
+ assertEquals(null, cfg.value);
+ }
+
+ @Test
+ public void testSetValueFieldProperties_FieldSet() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ Config cfg = new Config(props);
+
+ assertEquals(STRING_VALUE, cfg.value);
+ }
+
+ @Test
+ public void testSetValueFieldProperties_NoAnnotation() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ Config cfg = new Config(props);
+
+ assertNull(cfg.value);
+ }
+
+ @Test(expected = PropertyAccessException.class)
+ public void testSetValueFieldProperties_WrongFieldType() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ // Cannot set a property into an "Exception" field
+ @Property(name = THE_VALUE)
+ private Exception value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ new Config(props);
+ }
+
+ @Test(expected = PropertyMissingException.class)
+ public void testSetValueFieldPropertyProperties_NoProperty_NoDefault() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ new Config(props);
+ }
+
+ @Test(expected = PropertyInvalidException.class)
+ public void testSetValueFieldPropertyProperties_InvalidValue() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private int value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+
+ /**
+ * This returns a boolean, but the field is an "int", so it should throw an
+ * exception when it tries to stuff the value into the field.
+ */
+ @Override
+ protected Object getValue(Field field, Properties props, Property prop) throws PropertyException {
+ return Boolean.TRUE;
+ }
+ };
+
+ new Config(props);
+ }
+
+ @Test
+ public void testGetValue() throws PropertyException {
+ // this class contains all of the supported field types
+ class Config extends PropertyConfiguration {
+
+ @Property(name = "string")
+ private String stringValue;
+
+ @Property(name = "boolean.true")
+ private Boolean boolTrueValue;
+
+ @Property(name = "boolean.false")
+ private Boolean boolFalseValue;
+
+ @Property(name = "primitive.boolean.true")
+ private boolean primBoolTrueValue;
+
+ @Property(name = "primitive.boolean.false")
+ private boolean primBoolFalseValue;
+
+ @Property(name = "integer")
+ private Integer intValue;
+
+ @Property(name = "primitive.integer")
+ private int primIntValue;
+
+ @Property(name = "long")
+ private Long longValue;
+
+ @Property(name = "primitive.long")
+ private long primLongValue;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty("string", "a string");
+ props.setProperty("boolean.true", "true");
+ props.setProperty("boolean.false", "false");
+ props.setProperty("primitive.boolean.true", "true");
+ props.setProperty("primitive.boolean.false", "false");
+ props.setProperty("integer", "100");
+ props.setProperty("primitive.integer", "101");
+ props.setProperty("long", "10000");
+ props.setProperty("primitive.long", "10001");
+
+ Config cfg = new Config(props);
+
+ assertEquals("a string", cfg.stringValue);
+ assertEquals(true, cfg.boolTrueValue);
+ assertEquals(false, cfg.boolFalseValue);
+ assertEquals(true, cfg.primBoolTrueValue);
+ assertEquals(false, cfg.primBoolFalseValue);
+ assertEquals(100, cfg.intValue.intValue());
+ assertEquals(101, cfg.primIntValue);
+ assertEquals(10000, cfg.longValue.longValue());
+ assertEquals(10001, cfg.primLongValue);
+ }
+
+ @Test(expected = PropertyAccessException.class)
+ public void testGetValue_UnsupportedType() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ // Cannot set a property into an "Exception" field
+ @Property(name = THE_VALUE)
+ private Exception value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ new Config(props);
+ }
+
+ @Test
+ public void testCheckModifiable_OtherModifiers() throws PropertyException {
+ // this class contains all of the supported field types
+ class Config extends PropertyConfiguration {
+
+ @Property(name = "public")
+ public String publicString;
+
+ @Property(name = "private")
+ private String privateString;
+
+ @Property(name = "protected")
+ protected String protectedString;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty("public", "a public string");
+ props.setProperty("private", "a private string");
+ props.setProperty("protected", "a protected string");
+
+ Config cfg = new Config(props);
+
+ assertEquals("a public string", cfg.publicString);
+ assertEquals("a private string", cfg.privateString);
+ assertEquals("a protected string", cfg.protectedString);
+ }
+
+ @Test(expected = PropertyAccessException.class)
+ public void testCheckModifiable_Static() throws PropertyException {
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ new StaticConfig(props);
+ }
+
+ @Test(expected = PropertyAccessException.class)
+ public void testCheckModifiable_Final() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ // Cannot set a property into an "final" field
+ @Property(name = THE_VALUE)
+ private final String value = "";
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ new Config(props);
+ }
+
+ @Test
+ public void testGetStringValue() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ Config cfg = new Config(props);
+
+ assertEquals(STRING_VALUE, cfg.value);
+ }
+
+ @Test
+ public void testGetBooleanValue_NoDefault() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private Boolean value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, "true");
+ Config cfg = new Config(props);
+
+ assertEquals(true, cfg.value);
+ }
+
+ @Test(expected = PropertyInvalidException.class)
+ public void testGetBooleanValue_InvalidDefault() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = INVALID_VALUE)
+ private Boolean value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, "true");
+ new Config(props);
+ }
+
+ @Test
+ public void testGetBooleanValue_ValidDefault_True() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = "true")
+ private Boolean value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ // property not defined
+ Config cfg = new Config(props);
+ assertEquals(true, cfg.value);
+
+ // try again, with the property defined as true
+ props.setProperty(THE_VALUE, "true");
+ cfg = new Config(props);
+ assertEquals(true, cfg.value);
+
+ // try again, with the property defined as false
+ props.setProperty(THE_VALUE, "false");
+ cfg = new Config(props);
+ assertEquals(false, cfg.value);
+ }
+
+ @Test
+ public void testGetBooleanValue_ValidDefault_False() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = "false")
+ private Boolean value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ // property not defined
+ Config cfg = new Config(props);
+ assertEquals(false, cfg.value);
+
+ // try again, with the property defined as true
+ props.setProperty(THE_VALUE, "true");
+ cfg = new Config(props);
+ assertEquals(true, cfg.value);
+
+ // try again, with the property defined as false
+ props.setProperty(THE_VALUE, "false");
+ cfg = new Config(props);
+ assertEquals(false, cfg.value);
+ }
+
+ @Test
+ public void testGetIntegerValue_NoDefault() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private Integer value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, "200");
+ Config cfg = new Config(props);
+
+ assertEquals(200, cfg.value.intValue());
+ }
+
+ @Test(expected = PropertyInvalidException.class)
+ public void testGetIntegerValue_InvalidDefault() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = INVALID_VALUE)
+ private Integer value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, "200");
+ new Config(props);
+ }
+
+ @Test
+ public void testGetIntegerValue_ValidDefault() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = "201")
+ private Integer value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ // property not defined
+ Config cfg = new Config(props);
+ assertEquals(201, cfg.value.intValue());
+
+ // try again, with the property defined
+ props.setProperty(THE_VALUE, "200");
+ cfg = new Config(props);
+ assertEquals(200, cfg.value.intValue());
+ }
+
+ @Test
+ public void testGetLongValue_NoDefault() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private Long value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, "20000");
+ Config cfg = new Config(props);
+
+ assertEquals(20000L, cfg.value.longValue());
+ }
+
+ @Test(expected = PropertyInvalidException.class)
+ public void testGetLongValue_InvalidDefault() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = INVALID_VALUE)
+ private Long value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, "20000");
+ new Config(props);
+ }
+
+ @Test
+ public void testGetLongValue_ValidDefault() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = "20001")
+ private Long value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ // property not defined
+ Config cfg = new Config(props);
+ assertEquals(20001L, cfg.value.longValue());
+
+ // try again, with the property defined
+ props.setProperty(THE_VALUE, "20000");
+ cfg = new Config(props);
+ assertEquals(20000L, cfg.value.longValue());
+ }
+
+ @Test
+ public void testGetPropValue_Prop_NoDefault() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ Config cfg = new Config(props);
+
+ assertEquals(STRING_VALUE, cfg.value);
+ }
+
+ @Test
+ public void testGetPropValue_Prop_Default() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = STRING_VALUE_DEFAULT)
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ Config cfg = new Config(props);
+
+ assertEquals(STRING_VALUE, cfg.value);
+ }
+
+ @Test
+ public void testGetPropValue_EmptyProp_EmptyOk() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, accept = "empty")
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, "");
+ Config cfg = new Config(props);
+
+ assertEquals("", cfg.value);
+ }
+
+ @Test
+ public void testGetPropValue_EmptyDefault_EmptyOk() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = "", accept = "empty")
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ Config cfg = new Config(props);
+
+ assertEquals("", cfg.value);
+ }
+
+ @Test
+ public void testGetPropValue_Default_EmptyOk() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = STRING_VALUE, accept = "empty")
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ Config cfg = new Config(props);
+
+ assertEquals(STRING_VALUE, cfg.value);
+ }
+
+ @Test(expected = PropertyMissingException.class)
+ public void testGetPropValue_EmptyDefault_EmptyNotOk() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = "")
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ new Config(props);
+ }
+
+ @Test
+ public void testGetPropValue_Default_EmptyNotOk() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = STRING_VALUE, accept = "")
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ Config cfg = new Config(props);
+
+ assertEquals(STRING_VALUE, cfg.value);
+ }
+
+ @Test
+ public void testGetRawPropertyValue() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+
+ @Override
+ protected String getRawPropertyValue(Properties props, String propnm) {
+ return STRING_VALUE;
+ }
+ };
+
+ Config cfg = new Config(props);
+
+ assertEquals(STRING_VALUE, cfg.value);
+
+ }
+
+ @Test
+ public void testMakeBoolean_True() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private Boolean value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, "true");
+ Config cfg = new Config(props);
+
+ assertEquals(true, cfg.value);
+ }
+
+ @Test
+ public void testMakeBoolean_False() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private Boolean value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, "false");
+ Config cfg = new Config(props);
+
+ assertEquals(false, cfg.value);
+ }
+
+ @Test(expected = PropertyInvalidException.class)
+ public void testMakeBoolean_Invalid() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private Boolean value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, INVALID_VALUE);
+ new Config(props);
+ }
+
+ @Test
+ public void testMakeInteger_Valid() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private int value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, "300");
+ Config cfg = new Config(props);
+
+ assertEquals(300, cfg.value);
+ }
+
+ @Test(expected = PropertyInvalidException.class)
+ public void testMakeInteger_Invalid() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private int value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, INVALID_VALUE);
+ new Config(props);
+ }
+
+ @Test(expected = PropertyInvalidException.class)
+ public void testMakeInteger_TooBig() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private int value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, String.valueOf(Integer.MAX_VALUE + 10L));
+ new Config(props);
+ }
+
+ @Test
+ public void testMakeLong_Valid() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private long value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, "30000");
+ Config cfg = new Config(props);
+
+ assertEquals(30000L, cfg.value);
+ }
+
+ @Test(expected = PropertyInvalidException.class)
+ public void testMakeLong_Invalid() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE)
+ private long value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ props.setProperty(THE_VALUE, INVALID_VALUE);
+ new Config(props);
+ }
+
+ @Test
+ public void testCheckDefaultValue_NotEmpty_Valid() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = "700")
+ private long value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ Config cfg = new Config(props);
+
+ assertEquals(700L, cfg.value);
+ }
+
+ @Test(expected = PropertyInvalidException.class)
+ public void testCheckDefaultValue_NotEmpty_Invalid() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = INVALID_VALUE)
+ private long value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ new Config(props);
+ }
+
+ @Test(expected = PropertyInvalidException.class)
+ public void testCheckDefaultValue_Empty_EmptyOk_Invalid() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = "", accept = "empty")
+ private long value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ new Config(props);
+ }
+
+ @Test
+ public void testIsEmptyOkPropertyString_True() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = "", accept = "empty")
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ // missing property - should default to ""
+ Config cfg = new Config(props);
+ assertEquals("", cfg.value);
+
+ // add an empty property - should take the property's value
+ props.setProperty(THE_VALUE, "");
+ cfg.setAllFields(props);
+ assertEquals("", cfg.value);
+
+ // add the property - should take the property's value
+ props.setProperty(THE_VALUE, STRING_VALUE);
+ cfg.setAllFields(props);
+ assertEquals(STRING_VALUE, cfg.value);
+ }
+
+ @Test(expected = PropertyMissingException.class)
+ public void testIsEmptyOkPropertyString_False() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = "", accept = "")
+ private long value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ new Config(props);
+ }
+
+ @Test
+ public void testIsEmptyOkProperty_True() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = "", accept = "empty")
+ private String value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ Config cfg = new Config(props);
+
+ assertEquals("", cfg.value);
+ }
+
+ @Test(expected = PropertyMissingException.class)
+ public void testIsEmptyOkProperty_False() throws PropertyException {
+ class Config extends PropertyConfiguration {
+
+ @Property(name = THE_VALUE, defaultValue = "", accept = "")
+ private long value;
+
+ public Config(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ new Config(props);
+ }
+
+ /**
+ * A config whose annotated property is "static".
+ */
+ public static class StaticConfig extends PropertyConfiguration {
+
+ // "static" field cannot be set
+ @Property(name = THE_VALUE)
+ private static String value;
+
+ public StaticConfig(Properties props) throws PropertyException {
+ super(props);
+ }
+ };
+
+ /**
+ * This is just used as a mix-in to ensure that the configuration ignores interfaces.
+ */
+ public static interface DoesNothing {
+
+ }
+}
diff --git a/utils/src/test/java/org/onap/policy/common/utils/properties/SpecPropertyConfigurationTest.java b/utils/src/test/java/org/onap/policy/common/utils/properties/SpecPropertyConfigurationTest.java
new file mode 100644
index 00000000..39c8f01a
--- /dev/null
+++ b/utils/src/test/java/org/onap/policy/common/utils/properties/SpecPropertyConfigurationTest.java
@@ -0,0 +1,331 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties;
+
+import static org.junit.Assert.*;
+import java.util.Properties;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.common.utils.properties.exception.PropertyException;
+import org.onap.policy.common.utils.properties.exception.PropertyMissingException;
+import static org.onap.policy.common.utils.properties.SpecPropertyConfiguration.*;
+
+/**
+ *
+ */
+public class SpecPropertyConfigurationTest {
+
+ /**
+ * The specializer.
+ */
+ private static final String SPEC = "my.name";
+
+ /**
+ * Properties used when invoking constructors.
+ */
+ private Properties props;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ props = new Properties();
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.SpecPropertyConfiguration#getRawPropertyValue(java.util.Properties, java.lang.String)}.
+ * @throws PropertyException
+ */
+ @Test
+ public void testGetRawPropertyValue() throws PropertyException {
+ class Config extends SpecPropertyConfiguration {
+
+ // no spec
+ @Property(name = "prefix.suffix")
+ private String noSpec;
+
+ // no spec, other type
+ @Property(name = "no.spec.bool")
+ private boolean noSpecBool;
+
+ // type 1, no prefix
+ @Property(name = "{$}.suffix")
+ private String type1NoPrefix;
+
+ // type 1, no suffix
+ @Property(name = "prefix.{$}")
+ private String type1NoSuffix;
+
+ // type 1, both prefix and suffix
+ @Property(name = "prefix.{$}.suffix")
+ private String type1Both;
+
+ // type 1, other type
+ @Property(name = "an.{$}.int")
+ private int type1Int;
+
+ // type 2, no prefix
+ @Property(name = "{abc.?.def}.suffix")
+ private String type2NoPrefix;
+
+ // type 2, no suffix
+ @Property(name = "prefix.{abc.?.def}")
+ private String type2NoSuffix;
+
+ // type 2, no spec prefix
+ @Property(name = "prefix.{?.def}.suffix")
+ private String type2NoSpecPrefix;
+
+ // type 2, no spec suffix
+ @Property(name = "prefix{.abc.?}.suffix")
+ private String type2NoSpecSuffix;
+
+ // type 2, all components
+ @Property(name = "prefix.{abc.?.def.}suffix")
+ private String type2Both;
+
+ // type 2, other type
+ @Property(name = "a.{abc.?.def.}long")
+ private long type2Long;
+
+ public Config(String specialization, Properties props) throws PropertyException {
+ super(specialization, props);
+ }
+ };
+
+ props.setProperty("prefix.suffix", "no.spec");
+ props.setProperty("no.spec.bool", "true");
+ props.setProperty("world.suffix", "type1.no.prefix");
+ props.setProperty("prefix.world", "type1.no.suffix");
+ props.setProperty("prefix.world.suffix", "type1.both");
+ props.setProperty("an.world.int", "200");
+ props.setProperty("abc.world.def.suffix", "type2.no.prefix");
+ props.setProperty("prefix.abc.world.def", "type2.no.suffix");
+ props.setProperty("prefix.world.def.suffix", "type2.no.spec.prefix");
+ props.setProperty("prefix.abc.world.suffix", "type2.no.spec.suffix");
+ props.setProperty("prefix.abc.world.def.suffix", "type2.both");
+ props.setProperty("a.abc.world.def.long", "3000");
+
+ Config cfg = new Config("world", props);
+
+ assertEquals("no.spec", cfg.noSpec);
+ assertEquals(true, cfg.noSpecBool);
+ assertEquals("type1.no.prefix", cfg.type1NoPrefix);
+ assertEquals("type1.no.suffix", cfg.type1NoSuffix);
+ assertEquals("type1.both", cfg.type1Both);
+ assertEquals(200, cfg.type1Int);
+ assertEquals("type2.no.prefix", cfg.type2NoPrefix);
+ assertEquals("type2.no.suffix", cfg.type2NoSuffix);
+ assertEquals("type2.no.spec.prefix", cfg.type2NoSpecPrefix);
+ assertEquals("type2.no.spec.suffix", cfg.type2NoSpecSuffix);
+ assertEquals("type2.both", cfg.type2Both);
+ assertEquals(3000L, cfg.type2Long);
+ }
+ @Test
+ public void testGetRawPropertyValue_Type2_Generalized() throws PropertyException {
+ class Config extends SpecPropertyConfiguration {
+
+ // type 2, all components
+ @Property(name = "prefix.{abc.?.def.}suffix")
+ private String value;
+
+ public Config(String specialization, Properties props) throws PropertyException {
+ super(specialization, props);
+ }
+ };
+
+ props.setProperty("prefix.suffix", "no.spec");
+
+ Config cfg = new Config("world", props);
+
+ assertEquals("no.spec", cfg.value);
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.SpecPropertyConfiguration#getRawPropertyValue(java.util.Properties, java.lang.String)}.
+ * @throws PropertyException
+ */
+ @Test(expected = PropertyMissingException.class)
+ public void testGetRawPropertyValue_NotFound() throws PropertyException {
+ class Config extends SpecPropertyConfiguration {
+
+ @Property(name = "not.found")
+ private String notFound;
+
+ public Config(String specialization, Properties props) throws PropertyException {
+ super(specialization, props);
+ }
+ };
+
+ new Config("not found", props);
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.SpecPropertyConfiguration#SpecPropertyConfiguration(java.lang.String)}.
+ * @throws PropertyException
+ */
+ @Test
+ public void testSpecPropertyConfigurationString() throws PropertyException {
+ final String propnm = "string.{$}.prop";
+ final String propval = "hello";
+
+ class Config extends SpecPropertyConfiguration {
+
+ @Property(name = propnm)
+ private String value;
+
+ public Config(String specialization) {
+ super(specialization);
+ }
+ };
+
+ props.setProperty(specialize(propnm, SPEC), propval);
+
+ Config cfg = new Config(SPEC);
+ assertEquals(null, cfg.value);
+
+ cfg.setAllFields(props);
+ assertEquals(propval, cfg.value);
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.SpecPropertyConfiguration#SpecPropertyConfiguration(java.lang.String, java.util.Properties)}.
+ * @throws PropertyException
+ */
+ @Test
+ public void testSpecPropertyConfigurationStringProperties() throws PropertyException {
+ final String propnm = "int.{$}.prop";
+ final int propval = 10;
+
+ class Config extends SpecPropertyConfiguration {
+
+ @Property(name = propnm)
+ private int value;
+
+ public Config(String specialization, Properties props) throws PropertyException {
+ super(specialization, props);
+ }
+ };
+
+ props.setProperty(specialize(propnm, SPEC), String.valueOf(propval));
+
+ Config cfg = new Config(SPEC, props);
+
+ assertEquals(propval, cfg.value);
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.SpecPropertyConfiguration#generalize(java.lang.String)}.
+ */
+ @Test
+ public void testGeneralize_NoSpec() {
+ final String xyzPdq = "xyz.pdq";
+
+ // no spec
+ assertEquals(xyzPdq, generalize(xyzPdq));
+
+ // spec type 1 throws an exception - we'll test it separately
+
+ // spec type 2
+ assertEquals(xyzPdq, generalize("xyz.{xxx.?.yyy.}pdq"));
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.SpecPropertyConfiguration#generalize(java.lang.String)}.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testGeneralize_Spec1() {
+ generalize("abc.{$}.def");
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.SpecPropertyConfiguration#generalizeType2(java.lang.String, java.util.regex.Matcher)}.
+ */
+ @Test
+ public void testGeneralizeType2() {
+ assertEquals("abc.def", generalize("abc.{xyz?pdq}def"));
+
+ assertEquals("", generalize("{xyz?pdq}"));
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.SpecPropertyConfiguration#specialize(java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testSpecialize() {
+ final String spec = "get.spec";
+ final String abcDef = "abc.def";
+
+ // no spec
+ assertEquals(abcDef, specialize(abcDef, spec));
+
+ // spec type 1
+ assertEquals("abc.get.spec.def", specialize("abc.{$}.def", spec));
+
+ // spec type 2
+ assertEquals("abc.xxx.get.spec.yyy.def", specialize("abc.{xxx.?.yyy.}def", spec));
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.SpecPropertyConfiguration#specializeType1(java.lang.String, java.lang.String, java.util.regex.Matcher)}.
+ */
+ @Test
+ public void testSpecializeType1() {
+ final String spec = "spec1";
+
+ // no prefix
+ assertEquals("spec1.def", specialize("{$}.def", spec));
+
+ // no suffix
+ assertEquals("abc.spec1", specialize("abc.{$}", spec));
+
+ // with both prefix and suffix
+ assertEquals("abc.spec1.def", specialize("abc.{$}.def", spec));
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.SpecPropertyConfiguration#specializeType2(java.lang.String, java.lang.String, java.util.regex.Matcher)}.
+ */
+ @Test
+ public void testSpecializeType2() {
+ final String spec = "spec2";
+
+ // no prefix
+ assertEquals("xxx.spec2.yyy.def", specialize("{xxx.?.yyy.}def", spec));
+
+ // no suffix
+ assertEquals("abc.xxx.spec2.yyy", specialize("abc{.xxx.?.yyy}", spec));
+
+ // no spec prefix
+ assertEquals("abc.spec2.yyy.def", specialize("abc.{?.yyy.}def", spec));
+
+ // no spec suffix
+ assertEquals("abc.xxx.spec2.def", specialize("abc.{xxx.?}.def", spec));
+
+ // no components
+ assertEquals(spec, specialize("{?}", spec));
+
+ // all components
+ assertEquals("abc.xxx.spec2.yyy.def", specialize("abc.{xxx.?.yyy.}def", spec));
+ }
+
+}
diff --git a/utils/src/test/java/org/onap/policy/common/utils/properties/exception/BasicPropertyExceptionTester.java b/utils/src/test/java/org/onap/policy/common/utils/properties/exception/BasicPropertyExceptionTester.java
new file mode 100644
index 00000000..1e5fcfcd
--- /dev/null
+++ b/utils/src/test/java/org/onap/policy/common/utils/properties/exception/BasicPropertyExceptionTester.java
@@ -0,0 +1,130 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties.exception;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import org.hamcrest.CoreMatchers;
+
+/**
+ * Superclass used to test subclasses of {@link PropertyException}.
+ */
+public class BasicPropertyExceptionTester {
+
+ /**
+ * The "message" that's passed each time an exception is constructed.
+ */
+ protected static final String MESSAGE = "some error";
+
+ /**
+ * The "throwable" that's passed each time an exception is constructed.
+ */
+ protected static final Throwable THROWABLE = new Throwable();
+
+ /**
+ * Name of the "property" to be passed each time an exception is constructed.
+ */
+ protected static final String PROPERTY = "myName";
+
+ /**
+ * Name of the "property" field.
+ */
+ protected static final String FIELD = "PROPERTY";
+
+ /*
+ * Methods to perform various tests on the except subclass.
+ */
+
+ protected void doTestPropertyExceptionStringField_AllPopulated(PropertyException ex) {
+ standardTests(ex);
+ }
+
+ protected void doTestPropertyExceptionStringField_NullProperty(PropertyException ex) {
+ assertEquals(null, ex.getPropertyName());
+ assertEquals(FIELD, ex.getFieldName());
+ assertNotNull(ex.getMessage());
+ assertNotNull(ex.toString());
+ }
+
+ protected void doTestPropertyExceptionStringField_NullField(PropertyException ex) {
+ assertEquals(PROPERTY, ex.getPropertyName());
+ assertEquals(null, ex.getFieldName());
+ assertNotNull(ex.getMessage());
+ assertNotNull(ex.toString());
+ }
+
+ protected void doTestPropertyExceptionStringField_BothNull(PropertyException ex) {
+ assertEquals(null, ex.getPropertyName());
+ assertEquals(null, ex.getFieldName());
+ assertNotNull(ex.getMessage());
+ assertNotNull(ex.toString());
+ }
+
+ protected void doTestPropertyExceptionStringFieldString(PropertyException ex) {
+ standardTests(ex);
+ standardMessageTests(ex);
+ }
+
+ protected void doTestPropertyExceptionStringFieldThrowable(PropertyException ex) {
+ standardTests(ex);
+ standardThrowableTests(ex);
+ }
+
+ protected void doTestPropertyExceptionStringFieldStringThrowable(PropertyException ex) {
+ standardTests(ex);
+ standardMessageTests(ex);
+ standardThrowableTests(ex);
+ }
+
+ /**
+ * Performs standard tests that should apply to all subclasses.
+ *
+ * @param ex exception to test
+ */
+ protected void standardTests(PropertyException ex) {
+ assertEquals(PROPERTY, ex.getPropertyName());
+ assertEquals(FIELD, ex.getFieldName());
+ assertNotNull(ex.getMessage());
+ assertNotNull(ex.toString());
+ }
+
+ /**
+ * Performs standard tests for exceptions that were provided a message in their
+ * constructor.
+ *
+ * @param ex exception to test
+ */
+ protected void standardMessageTests(PropertyException ex) {
+ assertThat(ex.getMessage(), CoreMatchers.endsWith(MESSAGE));
+ }
+
+ /**
+ * Performs standard tests for exceptions that were provided a throwable in their
+ * constructor.
+ *
+ * @param ex exception to test
+ */
+ protected void standardThrowableTests(PropertyException ex) {
+ assertEquals(THROWABLE, ex.getCause());
+ }
+
+}
diff --git a/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyAccessExceptionTest.java b/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyAccessExceptionTest.java
new file mode 100644
index 00000000..304df9df
--- /dev/null
+++ b/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyAccessExceptionTest.java
@@ -0,0 +1,66 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties.exception;
+
+import org.junit.Test;
+
+/**
+ *
+ */
+public class PropertyAccessExceptionTest extends BasicPropertyExceptionTester {
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.exception.PropertyAccessException#PropertyAccessException(java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testPropertyAccessExceptionStringField() {
+ doTestPropertyExceptionStringField_AllPopulated( new PropertyAccessException(PROPERTY, FIELD));
+ doTestPropertyExceptionStringField_NullProperty( new PropertyAccessException(null, FIELD));
+ doTestPropertyExceptionStringField_NullField( new PropertyAccessException(PROPERTY, null));
+ doTestPropertyExceptionStringField_BothNull( new PropertyAccessException(null, null));
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.exception.PropertyAccessException#PropertyAccessException(java.lang.String, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testPropertyAccessExceptionStringFieldString() {
+ doTestPropertyExceptionStringFieldString(new PropertyAccessException(PROPERTY, FIELD, MESSAGE));
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.exception.PropertyAccessException#PropertyAccessException(java.lang.String, java.lang.String, java.lang.Throwable)}.
+ */
+ @Test
+ public void testPropertyAccessExceptionStringFieldThrowable() {
+ doTestPropertyExceptionStringFieldThrowable(new PropertyAccessException(PROPERTY, FIELD, THROWABLE));
+ }
+
+ /**
+ * Test method for {@link org.onap.policy.common.utils.properties.exception.PropertyAccessException#PropertyAccessException(java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable)}.
+ */
+ @Test
+ public void testPropertyAccessExceptionStringFieldStringThrowable() {
+ doTestPropertyExceptionStringFieldStringThrowable(
+ new PropertyAccessException(PROPERTY, FIELD, MESSAGE, THROWABLE));
+ }
+
+}
diff --git a/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyAnnotationExceptionTest.java b/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyAnnotationExceptionTest.java
new file mode 100644
index 00000000..2c033084
--- /dev/null
+++ b/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyAnnotationExceptionTest.java
@@ -0,0 +1,70 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties.exception;
+
+import org.junit.Test;
+
+/**
+ *
+ */
+public class PropertyAnnotationExceptionTest extends BasicPropertyExceptionTester {
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testPropertyExceptionStringField() {
+ doTestPropertyExceptionStringField_AllPopulated(new PropertyAnnotationException(PROPERTY, FIELD));
+ doTestPropertyExceptionStringField_NullProperty(new PropertyAnnotationException(null, FIELD));
+ doTestPropertyExceptionStringField_NullField(new PropertyAnnotationException(PROPERTY, null));
+ doTestPropertyExceptionStringField_BothNull(new PropertyAnnotationException(null, null));
+ }
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testPropertyExceptionStringFieldString() {
+ doTestPropertyExceptionStringFieldString(new PropertyAnnotationException(PROPERTY, FIELD, MESSAGE));
+ }
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String, java.lang.Throwable)}.
+ */
+ @Test
+ public void testPropertyExceptionStringFieldThrowable() {
+ doTestPropertyExceptionStringFieldThrowable(new PropertyAnnotationException(PROPERTY, FIELD, THROWABLE));
+ }
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable)}.
+ */
+ @Test
+ public void testPropertyExceptionStringFieldStringThrowable() {
+ doTestPropertyExceptionStringFieldStringThrowable(
+ new PropertyAnnotationException(PROPERTY, FIELD, MESSAGE, THROWABLE));
+ }
+
+}
diff --git a/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyExceptionTest.java b/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyExceptionTest.java
new file mode 100644
index 00000000..18186ba2
--- /dev/null
+++ b/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyExceptionTest.java
@@ -0,0 +1,69 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties.exception;
+
+import org.junit.Test;
+
+/**
+ *
+ */
+public class PropertyExceptionTest extends BasicPropertyExceptionTester {
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testPropertyExceptionStringField() {
+ doTestPropertyExceptionStringField_AllPopulated(new PropertyException(PROPERTY, FIELD));
+ doTestPropertyExceptionStringField_NullProperty(new PropertyException(null, FIELD));
+ doTestPropertyExceptionStringField_NullField(new PropertyException(PROPERTY, null));
+ doTestPropertyExceptionStringField_BothNull(new PropertyException(null, null));
+ }
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testPropertyExceptionStringFieldString() {
+ doTestPropertyExceptionStringFieldString(new PropertyException(PROPERTY, FIELD, MESSAGE));
+ }
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String, java.lang.Throwable)}.
+ */
+ @Test
+ public void testPropertyExceptionStringFieldThrowable() {
+ doTestPropertyExceptionStringFieldThrowable(new PropertyException(PROPERTY, FIELD, THROWABLE));
+ }
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable)}.
+ */
+ @Test
+ public void testPropertyExceptionStringFieldStringThrowable() {
+ doTestPropertyExceptionStringFieldStringThrowable(new PropertyException(PROPERTY, FIELD, MESSAGE, THROWABLE));
+ }
+
+}
diff --git a/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyInvalidExceptionTest.java b/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyInvalidExceptionTest.java
new file mode 100644
index 00000000..f83b7ed3
--- /dev/null
+++ b/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyInvalidExceptionTest.java
@@ -0,0 +1,70 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties.exception;
+
+import org.junit.Test;
+
+/**
+ *
+ */
+public class PropertyInvalidExceptionTest extends BasicPropertyExceptionTester {
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testPropertyExceptionStringField() {
+ doTestPropertyExceptionStringField_AllPopulated(new PropertyInvalidException(PROPERTY, FIELD));
+ doTestPropertyExceptionStringField_NullProperty(new PropertyInvalidException(null, FIELD));
+ doTestPropertyExceptionStringField_NullField(new PropertyInvalidException(PROPERTY, null));
+ doTestPropertyExceptionStringField_BothNull(new PropertyInvalidException(null, null));
+ }
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testPropertyExceptionStringFieldString() {
+ doTestPropertyExceptionStringFieldString(new PropertyInvalidException(PROPERTY, FIELD, MESSAGE));
+ }
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String, java.lang.Throwable)}.
+ */
+ @Test
+ public void testPropertyExceptionStringFieldThrowable() {
+ doTestPropertyExceptionStringFieldThrowable(new PropertyInvalidException(PROPERTY, FIELD, THROWABLE));
+ }
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable)}.
+ */
+ @Test
+ public void testPropertyExceptionStringFieldStringThrowable() {
+ doTestPropertyExceptionStringFieldStringThrowable(
+ new PropertyInvalidException(PROPERTY, FIELD, MESSAGE, THROWABLE));
+ }
+
+}
diff --git a/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyMissingExceptionTest.java b/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyMissingExceptionTest.java
new file mode 100644
index 00000000..f99ddd93
--- /dev/null
+++ b/utils/src/test/java/org/onap/policy/common/utils/properties/exception/PropertyMissingExceptionTest.java
@@ -0,0 +1,42 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP Policy Engine - Common Modules
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.properties.exception;
+
+import org.junit.Test;
+
+/**
+ *
+ */
+public class PropertyMissingExceptionTest extends BasicPropertyExceptionTester {
+
+ /**
+ * Test method for
+ * {@link org.onap.policy.common.utils.properties.exception.PropertyException#PropertyException(java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testPropertyExceptionStringField() {
+ doTestPropertyExceptionStringField_AllPopulated(new PropertyMissingException(PROPERTY, FIELD));
+ doTestPropertyExceptionStringField_NullProperty(new PropertyMissingException(null, FIELD));
+ doTestPropertyExceptionStringField_NullField(new PropertyMissingException(PROPERTY, null));
+ doTestPropertyExceptionStringField_BothNull(new PropertyMissingException(null, null));
+ }
+
+}