diff options
6 files changed, 875 insertions, 180 deletions
diff --git a/utils/pom.xml b/utils/pom.xml index cf34bd7c..8375408e 100644 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -38,6 +38,11 @@ <dependencies> <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.4</version> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> 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 index 7253c746..e72ebaba 100644 --- 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 @@ -25,8 +25,11 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Properties; +import org.apache.commons.lang3.StringUtils; 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; @@ -35,7 +38,9 @@ import org.onap.policy.common.utils.properties.exception.PropertyMissingExceptio /** * 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. + * subclass. The values of the fields are set via <i>setXxx()</i> methods. As a result, if + * a field is annotated and there is no corresponding <i>setXxx()</i> method, then an + * exception will be thrown. * <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 @@ -104,7 +109,10 @@ public class PropertyConfiguration { checkModifiable(field, prop); - if (setValue(field, props, prop)) { + Method setter = getSetter(field, prop); + checkSetter(setter, prop); + + if (setValue(setter, field, props, prop)) { return true; } @@ -112,15 +120,33 @@ public class PropertyConfiguration { } /** + * @param field field whose value is to be set + * @param prop property of interest + * @return the method to be used to set the field's value + * @throws PropertyAccessException if a "set" method cannot be identified + */ + private Method getSetter(Field field, Property prop) throws PropertyAccessException { + String nm = "set" + StringUtils.capitalize(field.getName()); + + try { + return this.getClass().getMethod(nm, field.getType()); + + } catch (NoSuchMethodException | SecurityException e) { + throw new PropertyAccessException(prop.name(), nm, e); + } + } + + /** * Sets a field's value from a particular property. * + * @param setter method to be used to set the field's value * @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 { + protected boolean setValue(Method setter, Field field, Properties props, Property prop) throws PropertyException { try { Object val = getValue(field, props, prop); @@ -128,23 +154,15 @@ public class PropertyConfiguration { 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); + setter.invoke(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); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new PropertyAccessException(prop.name(), setter.getName(), e); } } @@ -203,6 +221,21 @@ public class PropertyConfiguration { } /** + * Verifies that the setter method is not <i>static</i>. + * + * @param setter method to be checked + * @param prop property of interest + * @throws PropertyAccessException if the method is static + */ + private void checkSetter(Method setter, Property prop) throws PropertyAccessException { + int mod = setter.getModifiers(); + + if (Modifier.isStatic(mod)) { + throw new PropertyAccessException(prop.name(), setter.getName(), "method is 'static'"); + } + } + + /** * Gets a property value, coercing it to a String. * * @param fieldName field whose value is to be set diff --git a/utils/src/main/java/org/onap/policy/common/utils/properties/SpecProperties.java b/utils/src/main/java/org/onap/policy/common/utils/properties/SpecProperties.java new file mode 100644 index 00000000..0f416c3a --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/properties/SpecProperties.java @@ -0,0 +1,117 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * 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; + +/** + * Properties with an optional specialization (e.g., session name, controller name). + */ +public class SpecProperties extends Properties { + private static final long serialVersionUID = 1L; + + /** + * The property prefix, ending with ".". + */ + private final String prefix; + + /** + * The specialized property prefix, ending with ".". + */ + private final String specPrefix; + + /** + * + * @param prefix the property name prefix that appears before any specialization, may + * be "" + * @param specialization the property name specialization (e.g., session name) + */ + public SpecProperties(String prefix, String specialization) { + this.prefix = withTrailingDot(prefix); + this.specPrefix = withTrailingDot(this.prefix + specialization); + } + + /** + * + * @param prefix the property name prefix that appears before any specialization, may + * be "" + * @param specialization the property name specialization (e.g., session name) + * @param props the default properties + */ + public SpecProperties(String prefix, String specialization, Properties props) { + super(props); + + this.prefix = withTrailingDot(prefix); + this.specPrefix = withTrailingDot(this.prefix + specialization); + } + + /** + * Adds a trailing "." to a String, if it doesn't already have one. + * + * @param text text to which the "." should be added + * @return the text, with a trailing "." + */ + private static String withTrailingDot(String text) { + return text.isEmpty() || text.endsWith(".") ? text : text + "."; + } + + /** + * Gets the property whose value has the given key, looking first for the specialized + * property name, and then for the generalized property name. + * + * @param key property name, without the specialization + * @return the value from the property set, or {@code null} if the property set does + * not contain the value + */ + @Override + public String getProperty(String key) { + if (!key.startsWith(prefix)) { + return super.getProperty(key); + } + + String suffix = key.substring(prefix.length()); + + String val = super.getProperty(specPrefix + suffix); + if (val != null) { + return val; + } + + return super.getProperty(key); + } + + protected String getPrefix() { + return prefix; + } + + protected String getSpecPrefix() { + return specPrefix; + } + + @Override + public final int hashCode() { + throw new UnsupportedOperationException("SpecProperties cannot be hashed"); + } + + @Override + public final boolean equals(Object obj) { + throw new UnsupportedOperationException("cannot compare SpecProperties"); + } +} 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 index cf823b5d..121ae384 100644 --- 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 @@ -68,15 +68,9 @@ public class PropertyConfigurationTest { @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(); + PlainStringConfig cfg = new PlainStringConfig(); assertEquals(null, cfg.value); cfg.setAllFields(props); @@ -85,18 +79,8 @@ public class PropertyConfigurationTest { @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); + PlainStringConfig cfg = new PlainStringConfig(props); assertEquals(STRING_VALUE, cfg.value); } @@ -111,6 +95,11 @@ public class PropertyConfigurationTest { @Property(name = "grandparent.value") protected boolean grandparentValue; + + @SuppressWarnings("unused") + public void setGrandparentValue(boolean grandparentValue) { + this.grandparentValue = grandparentValue; + } }; /* @@ -120,12 +109,22 @@ public class PropertyConfigurationTest { @Property(name = "parent.value") protected long parentValue; + + @SuppressWarnings("unused") + public void setParentValue(long parentValue) { + this.parentValue = parentValue; + } }; class Config extends ParentConfig { @Property(name = THE_VALUE) private String value; + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; @@ -158,6 +157,11 @@ public class PropertyConfigurationTest { class Config extends PropertyConfiguration { private String value; + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; @@ -171,18 +175,8 @@ public class PropertyConfigurationTest { @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); + PlainStringConfig cfg = new PlainStringConfig(props); assertEquals(STRING_VALUE, cfg.value); } @@ -196,6 +190,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; props.setProperty(THE_VALUE, STRING_VALUE); @@ -215,14 +214,19 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(Exception value) { + this.value = value; + } }; props.setProperty(THE_VALUE, STRING_VALUE); new Config(props); } - @Test(expected = PropertyMissingException.class) - public void testSetValueFieldPropertyProperties_NoProperty_NoDefault() throws PropertyException { + @Test(expected = PropertyAccessException.class) + public void testGetSetter_NoSetter() throws PropertyException { class Config extends PropertyConfiguration { @Property(name = THE_VALUE) @@ -233,15 +237,18 @@ public class PropertyConfigurationTest { } }; + props.setProperty(THE_VALUE, STRING_VALUE); new Config(props); } - @Test(expected = PropertyInvalidException.class) - public void testSetValueFieldPropertyProperties_InvalidValue() throws PropertyException { - class Config extends PropertyConfiguration { + @Test(expected = PropertyMissingException.class) + public void testSetValueMethodFieldPropertiesProperty_NoProperty_NoDefault() throws PropertyException { + new PlainStringConfig(props); + } - @Property(name = THE_VALUE) - private int value; + @Test(expected = PropertyInvalidException.class) + public void testSetValueMethodFieldPropertiesProperty_InvalidValue() throws PropertyException { + class Config extends PlainPrimIntConfig { public Config(Properties props) throws PropertyException { super(props); @@ -260,6 +267,24 @@ public class PropertyConfigurationTest { new Config(props); } + @Test(expected = PropertyAccessException.class) + public void testSetValueMethodFieldPropertiesProperty_MethodEx() throws PropertyException { + class Config extends PlainStringConfig { + + public Config(Properties props) throws PropertyException { + super(props); + } + + @Override + public void setValue(String value) { + throw new IllegalArgumentException("expected exception"); + } + }; + + props.setProperty(THE_VALUE, STRING_VALUE); + new Config(props); + } + @Test public void testGetValue() throws PropertyException { // this class contains all of the supported field types @@ -295,6 +320,96 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public String getStringValue() { + return stringValue; + } + + @SuppressWarnings("unused") + public void setStringValue(String stringValue) { + this.stringValue = stringValue; + } + + @SuppressWarnings("unused") + public Boolean getBoolTrueValue() { + return boolTrueValue; + } + + @SuppressWarnings("unused") + public void setBoolTrueValue(Boolean boolTrueValue) { + this.boolTrueValue = boolTrueValue; + } + + @SuppressWarnings("unused") + public Boolean getBoolFalseValue() { + return boolFalseValue; + } + + @SuppressWarnings("unused") + public void setBoolFalseValue(Boolean boolFalseValue) { + this.boolFalseValue = boolFalseValue; + } + + @SuppressWarnings("unused") + public boolean isPrimBoolTrueValue() { + return primBoolTrueValue; + } + + @SuppressWarnings("unused") + public void setPrimBoolTrueValue(boolean primBoolTrueValue) { + this.primBoolTrueValue = primBoolTrueValue; + } + + @SuppressWarnings("unused") + public boolean isPrimBoolFalseValue() { + return primBoolFalseValue; + } + + @SuppressWarnings("unused") + public void setPrimBoolFalseValue(boolean primBoolFalseValue) { + this.primBoolFalseValue = primBoolFalseValue; + } + + @SuppressWarnings("unused") + public Integer getIntValue() { + return intValue; + } + + @SuppressWarnings("unused") + public void setIntValue(Integer intValue) { + this.intValue = intValue; + } + + @SuppressWarnings("unused") + public int getPrimIntValue() { + return primIntValue; + } + + @SuppressWarnings("unused") + public void setPrimIntValue(int primIntValue) { + this.primIntValue = primIntValue; + } + + @SuppressWarnings("unused") + public Long getLongValue() { + return longValue; + } + + @SuppressWarnings("unused") + public void setLongValue(Long longValue) { + this.longValue = longValue; + } + + @SuppressWarnings("unused") + public long getPrimLongValue() { + return primLongValue; + } + + @SuppressWarnings("unused") + public void setPrimLongValue(long primLongValue) { + this.primLongValue = primLongValue; + } }; props.setProperty("string", "a string"); @@ -331,6 +446,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(Exception value) { + this.value = value; + } }; props.setProperty(THE_VALUE, STRING_VALUE); @@ -354,6 +474,21 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setPublicString(String publicString) { + this.publicString = publicString; + } + + @SuppressWarnings("unused") + public void setPrivateString(String privateString) { + this.privateString = privateString; + } + + @SuppressWarnings("unused") + public void setProtectedString(String protectedString) { + this.protectedString = protectedString; + } }; props.setProperty("public", "a public string"); @@ -370,7 +505,7 @@ public class PropertyConfigurationTest { @Test(expected = PropertyAccessException.class) public void testCheckModifiable_Static() throws PropertyException { props.setProperty(THE_VALUE, STRING_VALUE); - new StaticConfig(props); + new StaticPropConfig(props); } @Test(expected = PropertyAccessException.class) @@ -390,38 +525,24 @@ public class PropertyConfigurationTest { new Config(props); } + @Test(expected = PropertyAccessException.class) + public void testCheckSetter_Static() throws PropertyException { + props.setProperty(THE_VALUE, STRING_VALUE); + new StaticMethodConfig(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); + PlainStringConfig cfg = new PlainStringConfig(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); + PlainBooleanConfig cfg = new PlainBooleanConfig(props); assertEquals(true, cfg.value); } @@ -436,6 +557,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(Boolean value) { + this.value = value; + } }; props.setProperty(THE_VALUE, "true"); @@ -452,6 +578,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(Boolean value) { + this.value = value; + } }; // property not defined @@ -479,6 +610,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(Boolean value) { + this.value = value; + } }; // property not defined @@ -506,6 +642,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(Integer value) { + this.value = value; + } }; props.setProperty(THE_VALUE, "200"); @@ -524,6 +665,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(Integer value) { + this.value = value; + } }; props.setProperty(THE_VALUE, "200"); @@ -540,6 +686,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(Integer value) { + this.value = value; + } }; // property not defined @@ -562,6 +713,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(Long value) { + this.value = value; + } }; props.setProperty(THE_VALUE, "20000"); @@ -580,6 +736,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(Long value) { + this.value = value; + } }; props.setProperty(THE_VALUE, "20000"); @@ -596,6 +757,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(Long value) { + this.value = value; + } }; // property not defined @@ -610,18 +776,8 @@ public class PropertyConfigurationTest { @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); + PlainStringConfig cfg = new PlainStringConfig(props); assertEquals(STRING_VALUE, cfg.value); } @@ -636,6 +792,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; props.setProperty(THE_VALUE, STRING_VALUE); @@ -654,6 +815,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; props.setProperty(THE_VALUE, ""); @@ -672,6 +838,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; Config cfg = new Config(props); @@ -689,6 +860,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; Config cfg = new Config(props); @@ -706,6 +882,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; new Config(props); @@ -721,6 +902,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; Config cfg = new Config(props); @@ -730,10 +916,7 @@ public class PropertyConfigurationTest { @Test public void testGetRawPropertyValue() throws PropertyException { - class Config extends PropertyConfiguration { - - @Property(name = THE_VALUE) - private String value; + class Config extends PlainStringConfig { public Config(Properties props) throws PropertyException { super(props); @@ -747,144 +930,64 @@ public class PropertyConfigurationTest { Config cfg = new Config(props); - assertEquals(STRING_VALUE, cfg.value); + assertEquals(STRING_VALUE, cfg.getValue()); } @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); + PlainBooleanConfig cfg = new PlainBooleanConfig(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); + PlainBooleanConfig cfg = new PlainBooleanConfig(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); + new PlainBooleanConfig(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); + PlainPrimIntConfig cfg = new PlainPrimIntConfig(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); + new PlainPrimIntConfig(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); + new PlainPrimIntConfig(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); + PlainPrimLongConfig cfg = new PlainPrimLongConfig(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); + new PlainPrimLongConfig(props); } @Test @@ -897,6 +1000,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(long value) { + this.value = value; + } }; Config cfg = new Config(props); @@ -914,6 +1022,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(long value) { + this.value = value; + } }; new Config(props); @@ -929,6 +1042,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(long value) { + this.value = value; + } }; new Config(props); @@ -944,6 +1062,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; // missing property - should default to "" @@ -971,6 +1094,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(long value) { + this.value = value; + } }; new Config(props); @@ -986,6 +1114,11 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; Config cfg = new Config(props); @@ -1003,23 +1136,126 @@ public class PropertyConfigurationTest { public Config(Properties props) throws PropertyException { super(props); } + + @SuppressWarnings("unused") + public void setValue(long value) { + this.value = value; + } }; new Config(props); } /** - * A config whose annotated property is "static". + * Config with a String value having no qualifiers. */ - public static class StaticConfig extends PropertyConfiguration { + public class PlainStringConfig extends PropertyConfiguration { + + @Property(name = THE_VALUE) + private String value; + + public PlainStringConfig() { + + } + + public PlainStringConfig(Properties props) throws PropertyException { + super(props); + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + }; + + /** + * Config with a Boolean value having no qualifiers. + */ + public class PlainBooleanConfig extends PropertyConfiguration { + + @Property(name = THE_VALUE) + private Boolean value; + + public PlainBooleanConfig(Properties props) throws PropertyException { + super(props); + } + + public void setValue(Boolean value) { + this.value = value; + } + }; + + /** + * Config with an int value having no qualifiers. + */ + public class PlainPrimIntConfig extends PropertyConfiguration { + + @Property(name = THE_VALUE) + private int value; + + public PlainPrimIntConfig(Properties props) throws PropertyException { + super(props); + } + + public void setValue(int value) { + this.value = value; + } + }; + + /** + * Config with a long value having no qualifiers. + */ + public class PlainPrimLongConfig extends PropertyConfiguration { + + @Property(name = THE_VALUE) + private long value; + + public PlainPrimLongConfig(Properties props) throws PropertyException { + super(props); + } + + public void setValue(long value) { + this.value = value; + } + }; + + /** + * A config whose field is "static". + */ + public static class StaticPropConfig extends PropertyConfiguration { // "static" field cannot be set @Property(name = THE_VALUE) private static String value; - public StaticConfig(Properties props) throws PropertyException { + public StaticPropConfig(Properties props) throws PropertyException { super(props); } + + public static void setValue(String value) { + StaticPropConfig.value = value; + } + }; + + /** + * A config whose method is "static". + */ + public static class StaticMethodConfig extends PropertyConfiguration { + + // "static" field cannot be set + @Property(name = THE_VALUE) + private String value; + + public StaticMethodConfig(Properties props) throws PropertyException { + super(props); + } + + public static void setValue(String value) { + + } }; /** diff --git a/utils/src/test/java/org/onap/policy/common/utils/properties/SpecPropertiesTest.java b/utils/src/test/java/org/onap/policy/common/utils/properties/SpecPropertiesTest.java new file mode 100644 index 00000000..01f096d1 --- /dev/null +++ b/utils/src/test/java/org/onap/policy/common/utils/properties/SpecPropertiesTest.java @@ -0,0 +1,224 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * 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.util.Properties; +import org.junit.Before; +import org.junit.Test; + +public class SpecPropertiesTest { + + /** + * Property prefix of interest. + */ + private static final String MY_PREFIX = "my.prefix"; + + /** + * Specialization, which follows the prefix. + */ + private static final String MY_SPEC = "my.spec"; + + /** + * Generalized prefix (i.e., without the spec). + */ + private static final String PREFIX_GEN = MY_PREFIX + "."; + + /** + * Specialized prefix (i.e., with the spec). + */ + private static final String PREFIX_SPEC = PREFIX_GEN + MY_SPEC + "."; + + /** + * Suffix to add to property names to generate names of properties that are not + * populated. + */ + private static final String SUFFIX = ".suffix"; + + /** + * Property name without a prefix. + */ + private static final String PROP_NO_PREFIX = "other"; + + /** + * Generalized property name (i.e., without the spec). + */ + private static final String PROP_GEN = PREFIX_GEN + "generalized"; + + // property names that include the spec + private static final String PROP_SPEC = PREFIX_SPEC + "specialized"; + private static final String PROP_UNKNOWN = PREFIX_SPEC + "unknown"; + + // property values + private static final String VAL_NO_PREFIX = "no-prefix"; + private static final String VAL_GEN = "gen"; + private static final String VAL_SPEC = "spec"; + + private static final String VAL_DEFAULT = "default value"; + + private Properties supportingProps; + private SpecProperties props; + + @Before + public void setUp() { + supportingProps = new Properties(); + + supportingProps.setProperty(PROP_NO_PREFIX, VAL_NO_PREFIX); + supportingProps.setProperty(PROP_GEN, VAL_GEN); + supportingProps.setProperty(PROP_SPEC, VAL_SPEC); + + props = new SpecProperties(MY_PREFIX, MY_SPEC); + + props.putAll(supportingProps); + } + + @Test + public void testSpecPropertiesStringString() { + + // no supporting properties + props = new SpecProperties(MY_PREFIX, MY_SPEC); + + assertEquals(PREFIX_GEN, props.getPrefix()); + assertEquals(PREFIX_SPEC, props.getSpecPrefix()); + + // everything is null + assertNull(props.getProperty(gen(PROP_NO_PREFIX))); + assertNull(props.getProperty(gen(PROP_GEN))); + assertNull(props.getProperty(gen(PROP_SPEC))); + assertNull(props.getProperty(gen(PROP_UNKNOWN))); + } + + @Test + public void testSpecPropertiesStringStringProperties() { + + // use supportingProps as default properties + props = new SpecProperties(MY_PREFIX, MY_SPEC, supportingProps); + + assertEquals(PREFIX_GEN, props.getPrefix()); + assertEquals(PREFIX_SPEC, props.getSpecPrefix()); + + assertEquals(VAL_NO_PREFIX, props.getProperty(gen(PROP_NO_PREFIX))); + assertEquals(VAL_GEN, props.getProperty(gen(PROP_GEN))); + assertEquals(VAL_SPEC, props.getProperty(gen(PROP_SPEC))); + assertNull(props.getProperty(gen(PROP_UNKNOWN))); + } + + @Test + public void testSpecPropertiesStringStringProperties_EmptyPrefix() { + supportingProps = new Properties(); + + supportingProps.setProperty(PROP_NO_PREFIX, VAL_NO_PREFIX); + supportingProps.setProperty("a.value", VAL_GEN); + supportingProps.setProperty("b.value", VAL_GEN); + supportingProps.setProperty(MY_SPEC + ".b.value", VAL_SPEC); + + // no supporting properties + props = new SpecProperties("", MY_SPEC, supportingProps); + + assertEquals(VAL_NO_PREFIX, props.getProperty(gen(PROP_NO_PREFIX))); + assertEquals(VAL_GEN, props.getProperty(gen("a.value"))); + assertEquals(VAL_SPEC, props.getProperty(MY_SPEC + ".b.value")); + assertNull(props.getProperty(gen(PROP_UNKNOWN))); + } + + @Test + public void testWithTrailingDot() { + // neither has trailing dot + assertEquals(PREFIX_GEN, props.getPrefix()); + assertEquals(PREFIX_SPEC, props.getSpecPrefix()); + + // both have trailing dot + props = new SpecProperties(PREFIX_GEN, MY_SPEC + "."); + assertEquals(PREFIX_GEN, props.getPrefix()); + assertEquals(PREFIX_SPEC, props.getSpecPrefix()); + + // first is empty + props = new SpecProperties("", MY_SPEC); + assertEquals("", props.getPrefix()); + assertEquals(MY_SPEC + ".", props.getSpecPrefix()); + + // second is empty + props = new SpecProperties(PREFIX_GEN, ""); + assertEquals(PREFIX_GEN, props.getPrefix()); + assertEquals(PREFIX_GEN, props.getSpecPrefix()); + } + + @Test + public void testGetPropertyString() { + // the key does contain the prefix + assertEquals(VAL_NO_PREFIX, props.getProperty(gen(PROP_NO_PREFIX))); + assertNull(props.getProperty(gen(PROP_NO_PREFIX + SUFFIX))); + + // specialized value exists + assertEquals(VAL_GEN, props.getProperty(gen(PROP_GEN))); + assertNull(props.getProperty(gen(PROP_GEN + SUFFIX))); + + // generalized value exists + assertEquals(VAL_SPEC, props.getProperty(gen(PROP_SPEC))); + assertNull(props.getProperty(gen(PROP_SPEC + SUFFIX))); + + // not found + assertNull(props.getProperty(gen(PROP_UNKNOWN))); + assertNull(props.getProperty(gen(PROP_UNKNOWN + SUFFIX))); + } + + @Test + public void testGetPropertyStringString() { + // the key does contain the prefix + assertEquals(VAL_NO_PREFIX, props.getProperty(gen(PROP_NO_PREFIX), VAL_DEFAULT)); + assertEquals(VAL_DEFAULT, props.getProperty(gen(PROP_NO_PREFIX + SUFFIX), VAL_DEFAULT)); + + // specialized value exists + assertEquals(VAL_GEN, props.getProperty(gen(PROP_GEN), VAL_DEFAULT)); + assertEquals(VAL_DEFAULT, props.getProperty(gen(PROP_GEN + SUFFIX), VAL_DEFAULT)); + + // generalized value exists + assertEquals(VAL_SPEC, props.getProperty(gen(PROP_SPEC), VAL_DEFAULT)); + assertEquals(VAL_DEFAULT, props.getProperty(gen(PROP_SPEC + SUFFIX), VAL_DEFAULT)); + + // not found + assertEquals(VAL_DEFAULT, props.getProperty(gen(PROP_UNKNOWN), VAL_DEFAULT)); + assertEquals(VAL_DEFAULT, props.getProperty(gen(PROP_UNKNOWN + SUFFIX), VAL_DEFAULT)); + + // can return null + assertNull(props.getProperty(gen(PROP_UNKNOWN), null)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testHashCode() { + props.hashCode(); + } + + @Test(expected = UnsupportedOperationException.class) + public void testEquals() { + props.equals(props); + } + + private String gen(String propnm) { + if (propnm.startsWith(PREFIX_SPEC)) { + return PREFIX_GEN + propnm.substring(PREFIX_SPEC.length()); + } + + return propnm; + } + +} 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 index 39c8f01a..b5431c25 100644 --- 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 @@ -110,6 +110,66 @@ public class SpecPropertyConfigurationTest { public Config(String specialization, Properties props) throws PropertyException { super(specialization, props); } + + @SuppressWarnings("unused") + public void setNoSpec(String noSpec) { + this.noSpec = noSpec; + } + + @SuppressWarnings("unused") + public void setNoSpecBool(boolean noSpecBool) { + this.noSpecBool = noSpecBool; + } + + @SuppressWarnings("unused") + public void setType1NoPrefix(String type1NoPrefix) { + this.type1NoPrefix = type1NoPrefix; + } + + @SuppressWarnings("unused") + public void setType1NoSuffix(String type1NoSuffix) { + this.type1NoSuffix = type1NoSuffix; + } + + @SuppressWarnings("unused") + public void setType1Both(String type1Both) { + this.type1Both = type1Both; + } + + @SuppressWarnings("unused") + public void setType1Int(int type1Int) { + this.type1Int = type1Int; + } + + @SuppressWarnings("unused") + public void setType2NoPrefix(String type2NoPrefix) { + this.type2NoPrefix = type2NoPrefix; + } + + @SuppressWarnings("unused") + public void setType2NoSuffix(String type2NoSuffix) { + this.type2NoSuffix = type2NoSuffix; + } + + @SuppressWarnings("unused") + public void setType2NoSpecPrefix(String type2NoSpecPrefix) { + this.type2NoSpecPrefix = type2NoSpecPrefix; + } + + @SuppressWarnings("unused") + public void setType2NoSpecSuffix(String type2NoSpecSuffix) { + this.type2NoSpecSuffix = type2NoSpecSuffix; + } + + @SuppressWarnings("unused") + public void setType2Both(String type2Both) { + this.type2Both = type2Both; + } + + @SuppressWarnings("unused") + public void setType2Long(long type2Long) { + this.type2Long = type2Long; + } }; props.setProperty("prefix.suffix", "no.spec"); @@ -151,6 +211,11 @@ public class SpecPropertyConfigurationTest { public Config(String specialization, Properties props) throws PropertyException { super(specialization, props); } + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; props.setProperty("prefix.suffix", "no.spec"); @@ -174,6 +239,11 @@ public class SpecPropertyConfigurationTest { public Config(String specialization, Properties props) throws PropertyException { super(specialization, props); } + + @SuppressWarnings("unused") + public void setNotFound(String notFound) { + this.notFound = notFound; + } }; new Config("not found", props); @@ -196,6 +266,11 @@ public class SpecPropertyConfigurationTest { public Config(String specialization) { super(specialization); } + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } }; props.setProperty(specialize(propnm, SPEC), propval); @@ -224,6 +299,11 @@ public class SpecPropertyConfigurationTest { public Config(String specialization, Properties props) throws PropertyException { super(specialization, props); } + + @SuppressWarnings("unused") + public void setValue(int value) { + this.value = value; + } }; props.setProperty(specialize(propnm, SPEC), String.valueOf(propval)); |