Author: sseifert Date: Thu Dec 1 18:05:41 2016 New Revision: 1772244 URL: http://svn.apache.org/viewvc?rev=1772244&view=rev Log: SLING-6338 enhance nested configuration handling refactor SPI metadata classes to make them fluent
Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtil.java (with props) sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtilTest.java (with props) Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBuilderImpl.java sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/metadata/AnnotationClassParser.java sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/ConfigurationManager.java sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImpl.java sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImpl.java sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolverImpl.java sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/metadata/ConfigurationMetadataProviderMultiplexerTest.java sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImplTest.java sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplNoDefaultTest.java sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplTest.java sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/console/CAConfigInventoryPrinterTest.java sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/ConfigurationPersistenceStrategy.java sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/AbstractMetadata.java sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/ConfigurationMetadata.java sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/PropertyMetadata.java sling/trunk/contrib/extensions/contextaware-config/spi/src/test/java/org/apache/sling/caconfig/spi/metadata/ConfigurationMetadataTest.java sling/trunk/contrib/extensions/contextaware-config/spi/src/test/java/org/apache/sling/caconfig/spi/metadata/PropertyMetadataTest.java Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBuilderImpl.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBuilderImpl.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBuilderImpl.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBuilderImpl.java Thu Dec 1 18:05:41 2016 @@ -27,7 +27,6 @@ import java.util.Iterator; import org.apache.commons.collections.IteratorUtils; import org.apache.commons.collections.Transformer; -import org.apache.commons.lang3.StringUtils; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceUtil; import org.apache.sling.api.resource.ValueMap; @@ -37,6 +36,7 @@ import org.apache.sling.caconfig.Configu import org.apache.sling.caconfig.impl.ConfigurationProxy.ChildResolver; import org.apache.sling.caconfig.impl.metadata.AnnotationClassParser; import org.apache.sling.caconfig.impl.override.ConfigurationOverrideManager; +import org.apache.sling.caconfig.resource.impl.util.ConfigNameUtil; import org.apache.sling.caconfig.resource.spi.ConfigurationResourceResolvingStrategy; import org.apache.sling.caconfig.spi.ConfigurationInheritanceStrategy; import org.apache.sling.caconfig.spi.ConfigurationPersistenceStrategy; @@ -68,26 +68,12 @@ class ConfigurationBuilderImpl implement @Override public ConfigurationBuilder name(String configName) { - if (!isNameValid(configName)) { - throw new IllegalArgumentException("Invalid configuration name: " + configName); - } + ConfigNameUtil.ensureValidConfigName(configName); this.configName = configName; return this; } /** - * Check the name. - * A name must not be null and relative. - * @param name The name - * @return {@code true} if it is valid - */ - private boolean isNameValid(final String name) { - return !StringUtils.isBlank(name) - && !StringUtils.startsWith(name, "/") - && !StringUtils.contains(name, "../"); - } - - /** * Validate the configuration name. * @param name Configuration name or relative path */ Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/metadata/AnnotationClassParser.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/metadata/AnnotationClassParser.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/metadata/AnnotationClassParser.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/metadata/AnnotationClassParser.java Thu Dec 1 18:05:41 2016 @@ -19,8 +19,11 @@ package org.apache.sling.caconfig.impl.metadata; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -119,16 +122,14 @@ public final class AnnotationClassParser throw new IllegalArgumentException("Class has not @Configuration annotation: " + clazz.getName()); } - // configuration metadata + // configuration metadata and property metadata String configName = getConfigurationName(clazz, configAnnotation); - ConfigurationMetadata configMetadata = new ConfigurationMetadata(configName); - configMetadata.setLabel(emptyToNull(configAnnotation.label())); - configMetadata.setDescription(emptyToNull(configAnnotation.description())); - configMetadata.setProperties(propsArrayToMap(configAnnotation.property())); - configMetadata.setCollection(configAnnotation.collection()); - - // property metadata - configMetadata.setPropertyMetadata(buildConfigurationMetadata_PropertyMetadata(clazz)); + ConfigurationMetadata configMetadata = new ConfigurationMetadata(configName, + buildConfigurationMetadata_PropertyMetadata(clazz), + configAnnotation.collection()) + .label(emptyToNull(configAnnotation.label())) + .description(emptyToNull(configAnnotation.description())) + .properties(propsArrayToMap(configAnnotation.property())); return configMetadata; } @@ -138,21 +139,18 @@ public final class AnnotationClassParser * @param clazz Configuration annotation class * @return Configuration metadata */ - private static ConfigurationMetadata buildConfigurationMetadata_Nested(Class<?> clazz, String configName) { - ConfigurationMetadata configMetadata = new ConfigurationMetadata(configName); - - // property metadata - configMetadata.setPropertyMetadata(buildConfigurationMetadata_PropertyMetadata(clazz)); - - return configMetadata; + private static ConfigurationMetadata buildConfigurationMetadata_Nested(Class<?> clazz, String configName, boolean collection) { + return new ConfigurationMetadata(configName, + buildConfigurationMetadata_PropertyMetadata(clazz), + collection); } - private static Map<String,PropertyMetadata<?>> buildConfigurationMetadata_PropertyMetadata(Class<?> clazz) { - Map<String,PropertyMetadata<?>> propertyMetadataList = new HashMap<>(); + private static Collection<PropertyMetadata<?>> buildConfigurationMetadata_PropertyMetadata(Class<?> clazz) { + List<PropertyMetadata<?>> propertyMetadataList = new ArrayList<>(); Method[] propertyMethods = clazz.getDeclaredMethods(); for (Method propertyMethod : propertyMethods) { PropertyMetadata<?> propertyMetadata = buildPropertyMetadata(propertyMethod, propertyMethod.getReturnType()); - propertyMetadataList.put(propertyMetadata.getName(), propertyMetadata); + propertyMetadataList.add(propertyMetadata); } return propertyMetadataList; } @@ -161,34 +159,34 @@ public final class AnnotationClassParser private static <T> PropertyMetadata<T> buildPropertyMetadata(Method propertyMethod, Class<T> type) { String propertyName = getPropertyName(propertyMethod.getName()); - PropertyMetadata propertyMetadata; + PropertyMetadata<?> propertyMetadata; if (type.isArray() && type.getComponentType().isAnnotation()) { - ConfigurationMetadata nestedConfigMetadata = buildConfigurationMetadata_Nested(type.getComponentType(), propertyName); - propertyMetadata = new PropertyMetadata<>(propertyName, ConfigurationMetadata[].class); - propertyMetadata.setConfigurationMetadata(nestedConfigMetadata); + ConfigurationMetadata nestedConfigMetadata = buildConfigurationMetadata_Nested(type.getComponentType(), propertyName, true); + propertyMetadata = new PropertyMetadata<>(propertyName, ConfigurationMetadata[].class) + .configurationMetadata(nestedConfigMetadata); } else if (type.isAnnotation()) { - ConfigurationMetadata nestedConfigMetadata = buildConfigurationMetadata_Nested(type, propertyName); - propertyMetadata = new PropertyMetadata<>(propertyName, ConfigurationMetadata.class); - propertyMetadata.setConfigurationMetadata(nestedConfigMetadata); + ConfigurationMetadata nestedConfigMetadata = buildConfigurationMetadata_Nested(type, propertyName, false); + propertyMetadata = new PropertyMetadata<>(propertyName, ConfigurationMetadata.class) + .configurationMetadata(nestedConfigMetadata); } else { - propertyMetadata = new PropertyMetadata<>(propertyName, type); - propertyMetadata.setDefaultValue((T)propertyMethod.getDefaultValue()); + propertyMetadata = new PropertyMetadata<>(propertyName, type) + .defaultValue((T)propertyMethod.getDefaultValue()); } Property propertyAnnotation = propertyMethod.getAnnotation(Property.class); if (propertyAnnotation != null) { - propertyMetadata.setLabel(emptyToNull(propertyAnnotation.label())); - propertyMetadata.setDescription(emptyToNull(propertyAnnotation.description())); - propertyMetadata.setProperties(propsArrayToMap(propertyAnnotation.property())); + propertyMetadata.label(emptyToNull(propertyAnnotation.label())) + .description(emptyToNull(propertyAnnotation.description())) + .properties(propsArrayToMap(propertyAnnotation.property())); } else { Map<String,String> emptyMap = Collections.emptyMap(); - propertyMetadata.setProperties(emptyMap); + propertyMetadata.properties(emptyMap); } - return propertyMetadata; + return (PropertyMetadata)propertyMetadata; } private static String emptyToNull(String value) { Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/ConfigurationManager.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/ConfigurationManager.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/ConfigurationManager.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/ConfigurationManager.java Thu Dec 1 18:05:41 2016 @@ -92,6 +92,13 @@ public interface ConfigurationManager { * @param configName Configuration name * @return Configuration metadata or null if none exists for the given name. */ - @CheckForNull ConfigurationMetadata getConfigurationMetadata(String configName); + @CheckForNull ConfigurationMetadata getConfigurationMetadata(@Nonnull String configName); + + /** + * Rewrite given resource path or configuration name according to current persistence strategies. + * @param configResourcePath Resource path or config name + * @return Rewritten resoure path or config name + */ + @CheckForNull String getPersistenceResourcePath(@Nonnull String configResourcePath); } Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImpl.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImpl.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImpl.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImpl.java Thu Dec 1 18:05:41 2016 @@ -43,7 +43,7 @@ import org.apache.sling.caconfig.spi.met final class ConfigurationDataImpl implements ConfigurationData { - private ConfigurationMetadata configMetadata; + private final ConfigurationMetadata configMetadata; private final Resource resolvedConfigurationResource; private final Resource writebackConfigurationResource; private final List<Resource> configurationResourceInheritanceChain; @@ -96,10 +96,6 @@ final class ConfigurationDataImpl implem configResourceCollection, null); } - void setConfigMetadata(ConfigurationMetadata configMetadata) { - this.configMetadata = configMetadata; - } - @Override public String getConfigName() { return configName; @@ -186,8 +182,8 @@ final class ConfigurationDataImpl implem return; } for (PropertyMetadata<?> propertyMetadata : configMetadata.getPropertyMetadata().values()) { - ConfigurationMetadata nestedConfigMetadata = propertyMetadata.getConfigurationMetadata(); - if (nestedConfigMetadata != null) { + if (propertyMetadata.isNestedConfiguration()) { + ConfigurationMetadata nestedConfigMetadata = propertyMetadata.getConfigurationMetadata(); String nestedConfigName; if (configResourceCollection) { nestedConfigName = configurationPersistenceStrategy.getResourcePath(configName + "/" + getCollectionItemName()) + "/" + nestedConfigMetadata.getName(); @@ -197,16 +193,10 @@ final class ConfigurationDataImpl implem } if (propertyMetadata.getType().equals(ConfigurationMetadata.class)) { ConfigurationData configData = configurationManager.getConfiguration(contextResource, nestedConfigName); - if (configData != null) { - ((ConfigurationDataImpl)configData).setConfigMetadata(nestedConfigMetadata); - } props.put(propertyMetadata.getName(), configData); } else if (propertyMetadata.getType().equals(ConfigurationMetadata[].class)) { Collection<ConfigurationData> configDatas = configurationManager.getConfigurationCollection(contextResource, nestedConfigName).getItems(); - for (ConfigurationData configData : configDatas) { - ((ConfigurationDataImpl)configData).setConfigMetadata(nestedConfigMetadata); - } props.put(propertyMetadata.getName(), configDatas.toArray(new ConfigurationData[configDatas.size()])); } } @@ -220,8 +210,15 @@ final class ConfigurationDataImpl implem Object value; Object effectiveValue; if (propertyMetadata != null) { - value = getValues().get(propertyName, propertyMetadata.getType()); - effectiveValue = getEffectiveValues().get(propertyName, ClassUtils.primitiveToWrapper(propertyMetadata.getType())); + Class<?> type = ClassUtils.primitiveToWrapper(propertyMetadata.getType()); + if (type == ConfigurationMetadata.class) { + type = ConfigurationData.class; + } + else if (type == ConfigurationMetadata[].class) { + type = ConfigurationData[].class; + } + value = getValues().get(propertyName, type); + effectiveValue = getEffectiveValues().get(propertyName, type); } else { value = getValues().get(propertyName); @@ -244,5 +241,5 @@ final class ConfigurationDataImpl implem return configMetadata.getPropertyMetadata().get(propertyName); } } - + } Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImpl.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImpl.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImpl.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImpl.java Thu Dec 1 18:05:41 2016 @@ -31,6 +31,7 @@ import org.apache.commons.collections.It import org.apache.commons.collections.ResettableIterator; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.iterators.ListIteratorWrapper; +import org.apache.commons.lang3.StringUtils; import org.apache.sling.api.resource.Resource; import org.apache.sling.caconfig.impl.ConfigurationInheritanceStrategyMultiplexer; import org.apache.sling.caconfig.impl.metadata.ConfigurationMetadataProviderMultiplexer; @@ -39,10 +40,12 @@ import org.apache.sling.caconfig.managem import org.apache.sling.caconfig.management.ConfigurationData; import org.apache.sling.caconfig.management.ConfigurationManager; import org.apache.sling.caconfig.resource.impl.ConfigurationResourceResolvingStrategyMultiplexer; +import org.apache.sling.caconfig.resource.impl.util.ConfigNameUtil; import org.apache.sling.caconfig.spi.ConfigurationCollectionPersistData; import org.apache.sling.caconfig.spi.ConfigurationPersistData; import org.apache.sling.caconfig.spi.ConfigurationPersistenceException; import org.apache.sling.caconfig.spi.metadata.ConfigurationMetadata; +import org.apache.sling.caconfig.spi.metadata.PropertyMetadata; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @@ -63,7 +66,8 @@ public class ConfigurationManagerImpl im @SuppressWarnings("unchecked") @Override public ConfigurationData getConfiguration(Resource resource, String configName) { - ConfigurationMetadata configMetadata = configurationMetadataProvider.getConfigurationMetadata(configName); + ConfigNameUtil.ensureValidConfigName(configName); + ConfigurationMetadata configMetadata = getConfigurationMetadata(configName); Resource configResource = null; Iterator<Resource> configResourceInheritanceChain = configurationResourceResolvingStrategy .getResourceInheritanceChain(resource, CONFIGS_PARENT_NAME, configName); @@ -97,7 +101,8 @@ public class ConfigurationManagerImpl im @SuppressWarnings("unchecked") @Override public ConfigurationCollectionData getConfigurationCollection(Resource resource, String configName) { - ConfigurationMetadata configMetadata = configurationMetadataProvider.getConfigurationMetadata(configName); + ConfigNameUtil.ensureValidConfigName(configName); + ConfigurationMetadata configMetadata = getConfigurationMetadata(configName); String writebackConfigResourceCollectionParentPath = configurationResourceResolvingStrategy.getResourceCollectionParentPath(resource, CONFIGS_PARENT_NAME, configName); List<ConfigurationData> configData = new ArrayList<>(); @@ -177,6 +182,7 @@ public class ConfigurationManagerImpl im @Override public void persistConfiguration(Resource resource, String configName, ConfigurationPersistData data) { + ConfigNameUtil.ensureValidConfigName(configName); String configResourcePath = configurationResourceResolvingStrategy.getResourcePath(resource, CONFIGS_PARENT_NAME, configName); if (configResourcePath == null) { throw new ConfigurationPersistenceException("Unable to persist configuration: Configuration resolving strategy returned no path."); @@ -188,6 +194,7 @@ public class ConfigurationManagerImpl im @Override public void persistConfigurationCollection(Resource resource, String configName, ConfigurationCollectionPersistData data) { + ConfigNameUtil.ensureValidConfigName(configName); String configResourceParentPath = configurationResourceResolvingStrategy.getResourceCollectionParentPath(resource, CONFIGS_PARENT_NAME, configName); if (configResourceParentPath == null) { throw new ConfigurationPersistenceException("Unable to persist configuration collection: Configuration resolving strategy returned no parent path."); @@ -199,7 +206,8 @@ public class ConfigurationManagerImpl im @Override public ConfigurationData newCollectionItem(Resource resource, String configName) { - ConfigurationMetadata configMetadata = configurationMetadataProvider.getConfigurationMetadata(configName); + ConfigNameUtil.ensureValidConfigName(configName); + ConfigurationMetadata configMetadata = getConfigurationMetadata(configName); if (configMetadata != null) { return new ConfigurationDataImpl(configMetadata, resource, configName, this, configurationOverrideManager, configurationPersistenceStrategy, true); @@ -214,7 +222,70 @@ public class ConfigurationManagerImpl im @Override public ConfigurationMetadata getConfigurationMetadata(String configName) { - return configurationMetadataProvider.getConfigurationMetadata(configName); + ConfigNameUtil.ensureValidConfigName(configName); + ConfigurationMetadata metadata = configurationMetadataProvider.getConfigurationMetadata(configName); + if (metadata != null) { + return metadata; + } + + // if no metadata found with direct match try to resolve nested configuration metadata references + for (String partialConfigName : ConfigNameUtil.getAllPartialConfigNameVariations(configName)) { + ConfigurationMetadata partialConfigMetadata = getConfigurationMetadata(partialConfigName); + if (partialConfigMetadata != null) { + ConfigurationMetadata nestedConfigMetadata = getNestedConfigurationMetadata(partialConfigMetadata, configName, partialConfigName); + if (nestedConfigMetadata != null) { + return nestedConfigMetadata; + } + } + } + return null; + } + + private ConfigurationMetadata getNestedConfigurationMetadata(ConfigurationMetadata configMetadata, String configName, String partialConfigName) { + if (StringUtils.startsWith(configName, partialConfigName + "/")) { + String prefixToRemove; + if (configMetadata.isCollection()) { + String collectionItemName = StringUtils.substringBefore(StringUtils.substringAfter(configName, partialConfigName + "/"), "/"); + prefixToRemove = configurationPersistenceStrategy.getResourcePath(partialConfigName + "/" + collectionItemName) + "/"; + } + else { + prefixToRemove = configurationPersistenceStrategy.getResourcePath(partialConfigName) + "/"; + } + String remainingConfigName = StringUtils.substringAfter(configName, prefixToRemove); + // try direct match + ConfigurationMetadata nestedConfigMetadata = getNestedConfigurationMetadataFromProperty(configMetadata, remainingConfigName); + if (nestedConfigMetadata != null) { + return nestedConfigMetadata; + } + // try to find partial match for deeper nestings + for (String partialRemainingConfigName : ConfigNameUtil.getAllPartialConfigNameVariations(remainingConfigName)) { + ConfigurationMetadata partialConfigMetadata = getNestedConfigurationMetadataFromProperty(configMetadata, partialRemainingConfigName); + if (partialConfigMetadata != null) { + nestedConfigMetadata = getNestedConfigurationMetadata(partialConfigMetadata, remainingConfigName, partialRemainingConfigName); + if (nestedConfigMetadata != null) { + return nestedConfigMetadata; + } + } + } + } + return null; + } + + private ConfigurationMetadata getNestedConfigurationMetadataFromProperty(ConfigurationMetadata partialConfigMetadata, String configName) { + for (PropertyMetadata<?> propertyMetadata : partialConfigMetadata.getPropertyMetadata().values()) { + if (propertyMetadata.isNestedConfiguration()) { + ConfigurationMetadata nestedConfigMetadata = propertyMetadata.getConfigurationMetadata(); + if (StringUtils.equals(configName, nestedConfigMetadata.getName())) { + return nestedConfigMetadata; + } + } + } + return null; } + @Override + public String getPersistenceResourcePath(String configResourcePath) { + return configurationPersistenceStrategy.getResourcePath(configResourcePath); + } + } Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolverImpl.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolverImpl.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolverImpl.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolverImpl.java Thu Dec 1 18:05:41 2016 @@ -25,6 +25,7 @@ import java.util.List; import org.apache.sling.api.resource.Resource; import org.apache.sling.caconfig.resource.ConfigurationResourceResolver; +import org.apache.sling.caconfig.resource.impl.util.ConfigNameUtil; import org.apache.sling.caconfig.resource.spi.ContextResource; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @@ -39,11 +40,13 @@ public class ConfigurationResourceResolv @Override public Resource getResource(Resource resource, String bucketName, String configName) { + ConfigNameUtil.ensureValidConfigName(configName); return configurationResourceResolvingStrategy.getResource(resource, bucketName, configName); } @Override public Collection<Resource> getResourceCollection(Resource resource, String bucketName, String configName) { + ConfigNameUtil.ensureValidConfigName(configName); return configurationResourceResolvingStrategy.getResourceCollection(resource, bucketName, configName); } @@ -67,5 +70,5 @@ public class ConfigurationResourceResolv } return contextPaths; } - + } Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtil.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtil.java?rev=1772244&view=auto ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtil.java (added) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtil.java Thu Dec 1 18:05:41 2016 @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.sling.caconfig.resource.impl.util; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; + +/** + * Helper methods for configuration names. + */ +public final class ConfigNameUtil { + + private ConfigNameUtil() { + // static methods only + } + + /** + * Check if the config name is valid. + * @param configName The name + * @return {@code true} if it is valid + */ + public static boolean isValid(final String configName) { + return !StringUtils.isBlank(configName) + && !StringUtils.startsWith(configName, "/") + && !StringUtils.contains(configName, "../"); + } + + /** + * Ensure that the config name is valid. + * @param configName The name + * @throws IllegalArgumentException if the config name is not valid + */ + public static void ensureValidConfigName(final String configName) { + if (!isValid(configName)) { + throw new IllegalArgumentException("Invalid configuration name: " + configName); + } + } + + /** + * Returns all partial combinations like: a, a/b, a/b/c from config name a/b/c/d + * @param configName Config name + * @return All partial combinations + */ + public static String[] getAllPartialConfigNameVariations(String configName) { + String[] configNameParts = StringUtils.splitPreserveAllTokens(configName, "/"); + if (configNameParts.length < 2) { + return ArrayUtils.EMPTY_STRING_ARRAY; + } + String[] partialConfigNameVariations = new String[configNameParts.length - 1]; + for (int i = 0; i < configNameParts.length - 1; i++) { + partialConfigNameVariations[i] = StringUtils.join(ArrayUtils.subarray(configNameParts, 0, i + 1), "/"); + } + return partialConfigNameVariations; + } + +} Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtil.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtil.java ------------------------------------------------------------------------------ --- svn:keywords (added) +++ svn:keywords Thu Dec 1 18:05:41 2016 @@ -0,0 +1 @@ +LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtil.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/metadata/ConfigurationMetadataProviderMultiplexerTest.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/metadata/ConfigurationMetadataProviderMultiplexerTest.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/metadata/ConfigurationMetadataProviderMultiplexerTest.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/metadata/ConfigurationMetadataProviderMultiplexerTest.java Thu Dec 1 18:05:41 2016 @@ -29,11 +29,13 @@ import java.util.TreeSet; import org.apache.sling.caconfig.spi.ConfigurationMetadataProvider; import org.apache.sling.caconfig.spi.metadata.ConfigurationMetadata; +import org.apache.sling.caconfig.spi.metadata.PropertyMetadata; import org.apache.sling.testing.mock.sling.junit.SlingContext; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSortedSet; public class ConfigurationMetadataProviderMultiplexerTest { @@ -89,7 +91,7 @@ public class ConfigurationMetadataProvid private void registerConfigurationMetadataProvider(String... names) { final Map<String,ConfigurationMetadata> metadata = new HashMap<>(); for (String name : names) { - metadata.put(name, new ConfigurationMetadata(name)); + metadata.put(name, new ConfigurationMetadata(name, ImmutableList.<PropertyMetadata<?>>of(), false)); } context.registerService(ConfigurationMetadataProvider.class, new ConfigurationMetadataProvider() { @Override Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImplTest.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImplTest.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImplTest.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImplTest.java Thu Dec 1 18:05:41 2016 @@ -40,7 +40,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @RunWith(MockitoJUnitRunner.class) @@ -66,11 +66,11 @@ public class ConfigurationDataImplTest { configResource = context.create().resource("/conf/test", "prop1", "value1", "prop4", true); - configMetadata = new ConfigurationMetadata("testName"); - configMetadata.setPropertyMetadata(ImmutableMap.<String,PropertyMetadata<?>>of( - "prop1", new PropertyMetadata<>("prop1", "defValue"), - "prop2", new PropertyMetadata<>("prop2", String.class), - "prop3", new PropertyMetadata<>("prop3", 5))); + configMetadata = new ConfigurationMetadata("testName", ImmutableList.<PropertyMetadata<?>>of( + new PropertyMetadata<>("prop1", "defValue"), + new PropertyMetadata<>("prop2", String.class), + new PropertyMetadata<>("prop3", 5)), + false); } @Test Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplNoDefaultTest.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplNoDefaultTest.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplNoDefaultTest.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplNoDefaultTest.java Thu Dec 1 18:05:41 2016 @@ -44,7 +44,6 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; /** @@ -77,18 +76,18 @@ public class ConfigurationManagerImplNoD contextResourceNoConfig = context.create().resource("/content/testNoConfig", PROPERTY_CONFIG_REF, "/conf/testNoConfig"); - configMetadata = new ConfigurationMetadata(CONFIG_NAME); - configMetadata.setPropertyMetadata(ImmutableMap.<String,PropertyMetadata<?>>of( - "prop1", new PropertyMetadata<>("prop1", "defValue"), - "prop2", new PropertyMetadata<>("prop2", String.class), - "prop3", new PropertyMetadata<>("prop3", 5))); + configMetadata = new ConfigurationMetadata(CONFIG_NAME, ImmutableList.<PropertyMetadata<?>>of( + new PropertyMetadata<>("prop1", "defValue"), + new PropertyMetadata<>("prop2", String.class), + new PropertyMetadata<>("prop3", 5)), + false); when(configurationMetadataProvider.getConfigurationMetadata(CONFIG_NAME)).thenReturn(configMetadata); - configMetadata = new ConfigurationMetadata(CONFIG_COL_NAME); - configMetadata.setPropertyMetadata(ImmutableMap.<String,PropertyMetadata<?>>of( - "prop1", new PropertyMetadata<>("prop1", "defValue"), - "prop2", new PropertyMetadata<>("prop2", String.class), - "prop3", new PropertyMetadata<>("prop3", 5))); + configMetadata = new ConfigurationMetadata(CONFIG_COL_NAME, ImmutableList.<PropertyMetadata<?>>of( + new PropertyMetadata<>("prop1", "defValue"), + new PropertyMetadata<>("prop2", String.class), + new PropertyMetadata<>("prop3", 5)), + true); when(configurationMetadataProvider.getConfigurationMetadata(CONFIG_COL_NAME)).thenReturn(configMetadata); } Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplTest.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplTest.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplTest.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplTest.java Thu Dec 1 18:05:41 2016 @@ -123,61 +123,77 @@ public class ConfigurationManagerImplTes PROPERTY_CONFIG_PROPERTY_INHERIT, true); // test fixture nested configuration - context.create().resource(getConfigPropsPath("/conf/test/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME), + context.create().resource(getConfigPropsPath("/conf/test/level2/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME), "prop1", "value1", "prop4", true); - context.create().resource(getConfigPropsPath(getConfigPropsPath("/conf/global/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME) + "/propSub"), + context.create().resource(getConfigPropsPath(getConfigPropsPath("/conf/test/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME) + "/propSub"), "prop1", "propSubValue1", "prop4", true); - context.create().resource(getConfigPropsPath(getConfigPropsPath("/conf/test/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME) + "/propSubList/item1"), + context.create().resource(getConfigPropsPath(getConfigPropsPath(getConfigPropsPath("/conf/test/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME) + "/propSub") + "/propSubLevel2"), + "prop1", "propSubLevel2Value1", + "prop4", true); + context.create().resource(getConfigPropsPath(getConfigPropsPath("/conf/test/level2/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME) + "/propSubList/item1"), "prop1", "propSubListValue1.1"); - context.create().resource(getConfigPropsPath(getConfigPropsPath("/conf/test/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME) + "/propSubList/item2"), + context.create().resource(getConfigPropsPath(getConfigPropsPath("/conf/test/level2/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME) + "/propSubList/item2"), "prop1", "propSubListValue1.2"); - context.create().resource(getConfigPropsPath(getConfigPropsPath(getConfigPropsPath("/conf/global/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME) + "/propSubList/item1") + "/propSub"), + context.create().resource(getConfigPropsPath(getConfigPropsPath(getConfigPropsPath("/conf/test/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME) + "/propSubList/item1") + "/propSub"), "prop1", "propSubList1_proSubValue1", "prop4", true); // config metadata singleton config - ConfigurationMetadata configMetadata = new ConfigurationMetadata(CONFIG_NAME); - configMetadata.setPropertyMetadata(ImmutableMap.<String,PropertyMetadata<?>>of( - "prop1", new PropertyMetadata<>("prop1", "defValue"), - "prop2", new PropertyMetadata<>("prop2", String.class), - "prop3", new PropertyMetadata<>("prop3", 5))); + ConfigurationMetadata configMetadata = new ConfigurationMetadata(CONFIG_NAME, ImmutableList.<PropertyMetadata<?>>of( + new PropertyMetadata<>("prop1", "defValue"), + new PropertyMetadata<>("prop2", String.class), + new PropertyMetadata<>("prop3", 5)), + false); when(configurationMetadataProvider.getConfigurationMetadata(CONFIG_NAME)).thenReturn(configMetadata); // config metadata config collection - configMetadata = new ConfigurationMetadata(CONFIG_COL_NAME); - configMetadata.setPropertyMetadata(ImmutableMap.<String,PropertyMetadata<?>>of( - "prop1", new PropertyMetadata<>("prop1", "defValue"), - "prop2", new PropertyMetadata<>("prop2", String.class), - "prop3", new PropertyMetadata<>("prop3", 5))); - when(configurationMetadataProvider.getConfigurationMetadata(CONFIG_COL_NAME)).thenReturn(configMetadata); + ConfigurationMetadata configColMetadata = new ConfigurationMetadata(CONFIG_COL_NAME, ImmutableList.<PropertyMetadata<?>>of( + new PropertyMetadata<>("prop1", "defValue"), + new PropertyMetadata<>("prop2", String.class), + new PropertyMetadata<>("prop3", 5)), + true); + when(configurationMetadataProvider.getConfigurationMetadata(CONFIG_COL_NAME)).thenReturn(configColMetadata); // config metadata nested config - configMetadata = new ConfigurationMetadata(CONFIG_NESTED_NAME); - configMetadata.setPropertyMetadata(ImmutableMap.<String,PropertyMetadata<?>>of( - "prop1", new PropertyMetadata<>("prop1", "defValue"), - "propSub", new PropertyMetadata<>("propSub", ConfigurationMetadata.class), - "propSubList", new PropertyMetadata<>("propSubList", ConfigurationMetadata[].class))); - ConfigurationMetadata propSubMetadata = new ConfigurationMetadata("propSub"); - propSubMetadata.setPropertyMetadata(ImmutableMap.<String,PropertyMetadata<?>>of( - "prop1", new PropertyMetadata<>("prop1", "defValue"), - "prop2", new PropertyMetadata<>("prop2", String.class), - "prop3", new PropertyMetadata<>("prop3", 5))); - ConfigurationMetadata propSubListMetadata = new ConfigurationMetadata("propSubList"); - propSubListMetadata.setPropertyMetadata(ImmutableMap.<String,PropertyMetadata<?>>of( - "prop1", new PropertyMetadata<>("prop1", String.class), - "propSub", new PropertyMetadata<>("propSub", ConfigurationMetadata.class))); - configMetadata.getPropertyMetadata().get("propSub").setConfigurationMetadata(propSubMetadata); - configMetadata.getPropertyMetadata().get("propSubList").setConfigurationMetadata(propSubListMetadata); - propSubListMetadata.getPropertyMetadata().get("propSub").setConfigurationMetadata(propSubMetadata); + /* + * testConfigNested + * | + * +- propSub + * | | + * | +- propSubLevel2 + * | + * +- propSubList + * | + * +- <collection> + * | + * +- propSub + * | + * +- propSubLevel2 + */ + ConfigurationMetadata propSubLevel2Metadata = new ConfigurationMetadata("propSubLevel2", ImmutableList.<PropertyMetadata<?>>of( + new PropertyMetadata<>("prop1", "defValueLevel2")), + false); + ConfigurationMetadata propSubMetadata = new ConfigurationMetadata("propSub", ImmutableList.<PropertyMetadata<?>>of( + new PropertyMetadata<>("prop1", "defValue"), + new PropertyMetadata<>("prop2", String.class), + new PropertyMetadata<>("prop3", 5), + new PropertyMetadata<>("propSubLevel2", ConfigurationMetadata.class).configurationMetadata(propSubLevel2Metadata)), + false); + ConfigurationMetadata propSubListMetadata = new ConfigurationMetadata("propSubList", ImmutableList.<PropertyMetadata<?>>of( + new PropertyMetadata<>("prop1", "defValueSubList"), + new PropertyMetadata<>("propSub", ConfigurationMetadata.class).configurationMetadata(propSubMetadata)), + true); + ConfigurationMetadata configNestedMetadata = new ConfigurationMetadata(CONFIG_NESTED_NAME, ImmutableList.<PropertyMetadata<?>>of( + new PropertyMetadata<>("prop1", "defValue"), + new PropertyMetadata<>("propSub", ConfigurationMetadata.class).configurationMetadata(propSubMetadata), + new PropertyMetadata<>("propSubList", ConfigurationMetadata[].class).configurationMetadata(propSubListMetadata)), + false); + when(configurationMetadataProvider.getConfigurationMetadata(CONFIG_NESTED_NAME)).thenReturn(configNestedMetadata); when(configurationMetadataProvider.getConfigurationNames()).thenReturn(ImmutableSortedSet.of(CONFIG_NAME, CONFIG_COL_NAME, CONFIG_NESTED_NAME)); - - - when(configurationMetadataProvider.getConfigurationMetadata(CONFIG_NESTED_NAME)).thenReturn(configMetadata); - } protected String getConfigPropsPath(String path) { @@ -541,9 +557,10 @@ public class ConfigurationManagerImplTes @Test public void testGetConfigurationNested() { - ConfigurationData configData = underTest.getConfiguration(contextResource, CONFIG_NESTED_NAME); + ConfigurationData configData = underTest.getConfiguration(contextResourceLevel2, CONFIG_NESTED_NAME); assertNotNull(configData); + // root level assertEquals(ImmutableSet.of("prop1", "propSub", "propSubList", "prop4"), configData.getPropertyNames()); assertEquals("value1", configData.getValues().get("prop1", String.class)); assertEquals("value1", configData.getEffectiveValues().get("prop1", String.class)); @@ -553,21 +570,45 @@ public class ConfigurationManagerImplTes assertEquals(ConfigurationMetadata.class, configData.getValueInfo("propSub").getPropertyMetadata().getType()); assertEquals(ConfigurationMetadata[].class, configData.getValueInfo("propSubList").getPropertyMetadata().getType()); + // propSub ConfigurationData subData = configData.getValues().get("propSub", ConfigurationData.class); ConfigurationData subDataEffective = configData.getEffectiveValues().get("propSub", ConfigurationData.class); assertNotNull(subData); assertNotNull(subDataEffective); + assertTrue(ConfigurationData.class.isAssignableFrom(configData.getValueInfo("propSub").getValue().getClass())); + assertTrue(ConfigurationData.class.isAssignableFrom(configData.getValueInfo("propSub").getEffectiveValue().getClass())); + assertTrue(ConfigurationData[].class.isAssignableFrom(configData.getValueInfo("propSubList").getValue().getClass())); + assertTrue(ConfigurationData[].class.isAssignableFrom(configData.getValueInfo("propSubList").getEffectiveValue().getClass())); + assertNull(subData.getValues().get("prop1", String.class)); assertEquals("propSubValue1", subData.getEffectiveValues().get("prop1", String.class)); assertNull(subData.getValues().get("prop4", String.class)); assertEquals(true, subData.getEffectiveValues().get("prop4", false)); + // propSub/propSubLevel2 + ConfigurationData subDataLevel2 = subData.getValues().get("propSubLevel2", ConfigurationData.class); + ConfigurationData subDataLevel2Effective = subData.getEffectiveValues().get("propSubLevel2", ConfigurationData.class); + assertNotNull(subDataLevel2); + assertNotNull(subDataLevel2Effective); + + assertTrue(ConfigurationData.class.isAssignableFrom(subData.getValueInfo("propSubLevel2").getValue().getClass())); + assertTrue(ConfigurationData.class.isAssignableFrom(subData.getValueInfo("propSubLevel2").getEffectiveValue().getClass())); + + assertNull(subDataLevel2.getValues().get("prop1", String.class)); + assertEquals("propSubLevel2Value1", subDataLevel2.getEffectiveValues().get("prop1", String.class)); + assertNull(subDataLevel2.getValues().get("prop4", String.class)); + assertEquals(true, subDataLevel2.getEffectiveValues().get("prop4", false)); + + // propSubList ConfigurationData[] subListData = configData.getValues().get("propSubList", ConfigurationData[].class); ConfigurationData[] subListDataEffective = configData.getEffectiveValues().get("propSubList", ConfigurationData[].class); assertNotNull(subListData); assertNotNull(subListDataEffective); + assertTrue(ConfigurationData[].class.isAssignableFrom(configData.getValueInfo("propSubList").getValue().getClass())); + assertTrue(ConfigurationData[].class.isAssignableFrom(configData.getValueInfo("propSubList").getEffectiveValue().getClass())); + assertEquals(2, subListData.length); assertEquals("propSubListValue1.1", subListData[0].getValues().get("prop1", String.class)); assertEquals("propSubListValue1.1", subListData[0].getEffectiveValues().get("prop1", String.class)); @@ -585,4 +626,122 @@ public class ConfigurationManagerImplTes assertEquals(true, subListDataItem1Sub.getEffectiveValues().get("prop4", false)); } + @Test + public void testGetConfigurationNested_NoConfigResource() { + ConfigurationData configData = underTest.getConfiguration(contextResourceNoConfig, CONFIG_NESTED_NAME); + assertNotNull(configData); + + assertEquals(ImmutableSet.of("prop1", "propSub", "propSubList"), configData.getPropertyNames()); + assertNull(configData.getValues().get("prop1", String.class)); + assertEquals("defValue", configData.getEffectiveValues().get("prop1", String.class)); + + assertEquals(ConfigurationMetadata.class, configData.getValueInfo("propSub").getPropertyMetadata().getType()); + assertEquals(ConfigurationMetadata[].class, configData.getValueInfo("propSubList").getPropertyMetadata().getType()); + + ConfigurationData subData = configData.getValues().get("propSub", ConfigurationData.class); + ConfigurationData subDataEffective = configData.getEffectiveValues().get("propSub", ConfigurationData.class); + assertNotNull(subData); + assertNotNull(subDataEffective); + + assertTrue(ConfigurationData.class.isAssignableFrom(configData.getValueInfo("propSub").getValue().getClass())); + assertTrue(ConfigurationData.class.isAssignableFrom(configData.getValueInfo("propSub").getEffectiveValue().getClass())); + assertTrue(ConfigurationData[].class.isAssignableFrom(configData.getValueInfo("propSubList").getValue().getClass())); + assertTrue(ConfigurationData[].class.isAssignableFrom(configData.getValueInfo("propSubList").getEffectiveValue().getClass())); + + assertNull(subData.getValues().get("prop1", String.class)); + assertEquals("defValue", subData.getEffectiveValues().get("prop1", String.class)); + + ConfigurationData[] subListData = configData.getValues().get("propSubList", ConfigurationData[].class); + ConfigurationData[] subListDataEffective = configData.getEffectiveValues().get("propSubList", ConfigurationData[].class); + assertNotNull(subListData); + assertNotNull(subListDataEffective); + + assertTrue(ConfigurationData[].class.isAssignableFrom(configData.getValueInfo("propSubList").getValue().getClass())); + assertTrue(ConfigurationData[].class.isAssignableFrom(configData.getValueInfo("propSubList").getEffectiveValue().getClass())); + + assertEquals(0, subListData.length); + } + + @Test + public void testGetConfigurationNames() { + assertEquals(ImmutableSortedSet.of(CONFIG_NAME, CONFIG_COL_NAME, CONFIG_NESTED_NAME), underTest.getConfigurationNames()); + } + + @Test + public void testGetConfigurationMetadata() { + ConfigurationMetadata configMetadata = underTest.getConfigurationMetadata(CONFIG_NAME); + assertNotNull(configMetadata); + assertEquals(CONFIG_NAME, configMetadata.getName()); + } + + @Test + public void testGetConfigurationMetadata_Nested() { + ConfigurationMetadata configMetadata = underTest.getConfigurationMetadata(CONFIG_NESTED_NAME); + assertNotNull(configMetadata); + assertEquals(CONFIG_NESTED_NAME, configMetadata.getName()); + } + + @Test + public void testGetConfigurationMetadata_Nested_Sub() { + ConfigurationMetadata configMetadataSub = underTest.getConfigurationMetadata(getConfigPropsPath(CONFIG_NESTED_NAME) + "/propSub"); + assertNotNull(configMetadataSub); + assertEquals("propSub", configMetadataSub.getName()); + } + + @Test + public void testGetConfigurationMetadata_Nested_SubLevel2() { + ConfigurationMetadata configMetadataSubLevel2 = underTest.getConfigurationMetadata(getConfigPropsPath(getConfigPropsPath(CONFIG_NESTED_NAME) + + "/propSub") + "/propSubLevel2"); + assertNotNull(configMetadataSubLevel2); + assertEquals("propSubLevel2", configMetadataSubLevel2.getName()); + } + + @Test + public void testGetConfigurationMetadata_Nested_SubList() { + ConfigurationMetadata configMetadataSubList = underTest.getConfigurationMetadata(getConfigPropsPath(CONFIG_NESTED_NAME) + "/propSubList"); + assertNotNull(configMetadataSubList); + assertEquals("propSubList", configMetadataSubList.getName()); + } + + @Test + public void testGetConfigurationMetadata_Nested_SubList_Sub() throws Exception { + // delete resource already existing in test fixture to test with non-existing resource but existing collection item as parent + context.resourceResolver().delete(context.resourceResolver().getResource( + getConfigPropsPath(getConfigPropsPath(getConfigPropsPath("/conf/test/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME) + + "/propSubList/item1") + "/propSub"))); + + ConfigurationMetadata subListDataItem1Sub = underTest.getConfigurationMetadata(getConfigPropsPath(getConfigPropsPath(CONFIG_NESTED_NAME) + + "/propSubList/item1") + "/propSub"); + assertNotNull(subListDataItem1Sub); + assertEquals("propSub", subListDataItem1Sub.getName()); + } + + @Test + public void testGetConfigurationMetadata_Nested_SubList_SubLevel2() throws Exception { + // delete resource already existing in test fixture to test with non-existing resource but existing collection item as parent + context.resourceResolver().delete(context.resourceResolver().getResource( + getConfigPropsPath(getConfigPropsPath(getConfigPropsPath("/conf/test/" + CONFIGS_PARENT_NAME + "/" + CONFIG_NESTED_NAME) + + "/propSubList/item1") + "/propSub"))); + + ConfigurationMetadata subListDataItem1SubLevel2 = underTest.getConfigurationMetadata(getConfigPropsPath(getConfigPropsPath(getConfigPropsPath(CONFIG_NESTED_NAME) + + "/propSubList/item1") + "/propSub") + "/propSubLevel2"); + assertNotNull(subListDataItem1SubLevel2); + assertEquals("propSubLevel2", subListDataItem1SubLevel2.getName()); + } + + @Test + public void testNewCollectionItem_Nested_SubList() { + ConfigurationData configData = underTest.newCollectionItem(contextResource, getConfigPropsPath(CONFIG_NESTED_NAME) + "/propSubList"); + assertEquals(getConfigPropsPath(CONFIG_NESTED_NAME) + "/propSubList", configData.getConfigName()); + + assertNull(configData.getValues().get("prop1", String.class)); + assertEquals("defValueSubList", configData.getEffectiveValues().get("prop1", String.class)); + } + + @Test + public void testGetPersistenceResourcePath() { + assertEquals(getConfigPropsPath("/a/b/c"), underTest.getPersistenceResourcePath("/a/b/c")); + assertEquals(getConfigPropsPath("a/b"), underTest.getPersistenceResourcePath("a/b")); + } + } Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/console/CAConfigInventoryPrinterTest.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/console/CAConfigInventoryPrinterTest.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/console/CAConfigInventoryPrinterTest.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/console/CAConfigInventoryPrinterTest.java Thu Dec 1 18:05:41 2016 @@ -43,7 +43,6 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedSet; @RunWith(MockitoJUnitRunner.class) @@ -70,11 +69,11 @@ public class CAConfigInventoryPrinterTes ConfigurationTestUtils.registerConfigurationResolver(context); underTest = context.registerInjectActivateService(new CAConfigInventoryPrinter()); - ConfigurationMetadata configMetadata = new ConfigurationMetadata(SAMPLE_CONFIG_NAME); - configMetadata.setPropertyMetadata(ImmutableMap.<String,PropertyMetadata<?>>of( - "prop1", new PropertyMetadata<>("prop1", "defValue"), - "prop2", new PropertyMetadata<>("prop2", String.class), - "prop3", new PropertyMetadata<>("prop3", 5))); + ConfigurationMetadata configMetadata = new ConfigurationMetadata(SAMPLE_CONFIG_NAME, ImmutableList.<PropertyMetadata<?>>of( + new PropertyMetadata<>("prop1", "defValue"), + new PropertyMetadata<>("prop2", String.class), + new PropertyMetadata<>("prop3", 5)), + false); when(configurationMetadataProvider.getConfigurationMetadata(SAMPLE_CONFIG_NAME)).thenReturn(configMetadata); when(configurationMetadataProvider.getConfigurationNames()).thenReturn(ImmutableSortedSet.of(SAMPLE_CONFIG_NAME)); Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtilTest.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtilTest.java?rev=1772244&view=auto ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtilTest.java (added) +++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtilTest.java Thu Dec 1 18:05:41 2016 @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.sling.caconfig.resource.impl.util; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class ConfigNameUtilTest { + + @Test + public void testIsValid() { + assertTrue(ConfigNameUtil.isValid("a")); + assertTrue(ConfigNameUtil.isValid("a/b")); + assertTrue(ConfigNameUtil.isValid("a/b/c")); + assertTrue(ConfigNameUtil.isValid("a/jcr:content/b/c")); + + assertFalse(ConfigNameUtil.isValid(null)); + assertFalse(ConfigNameUtil.isValid("")); + assertFalse(ConfigNameUtil.isValid("/a")); + assertFalse(ConfigNameUtil.isValid("/a/b/c")); + assertFalse(ConfigNameUtil.isValid("a/b/../c")); + } + + @Test + public void testGetAllPartialConfigNameVariations() { + assertArrayEquals(new String[0], ConfigNameUtil.getAllPartialConfigNameVariations("")); + assertArrayEquals(new String[0], ConfigNameUtil.getAllPartialConfigNameVariations("a")); + assertArrayEquals(new String[] {"a"}, ConfigNameUtil.getAllPartialConfigNameVariations("a/b")); + assertArrayEquals(new String[] {"a","a/b"}, ConfigNameUtil.getAllPartialConfigNameVariations("a/b/c")); + assertArrayEquals(new String[] {"a","a/b","a/b/c"}, ConfigNameUtil.getAllPartialConfigNameVariations("a/b/c/d")); + } + +} Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtilTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtilTest.java ------------------------------------------------------------------------------ --- svn:keywords (added) +++ svn:keywords Thu Dec 1 18:05:41 2016 @@ -0,0 +1 @@ +LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/util/ConfigNameUtilTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/ConfigurationPersistenceStrategy.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/ConfigurationPersistenceStrategy.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/ConfigurationPersistenceStrategy.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/ConfigurationPersistenceStrategy.java Thu Dec 1 18:05:41 2016 @@ -43,7 +43,7 @@ public interface ConfigurationPersistenc /** * Allows the strategy to transform the given configuration resource path according to it's persistent strategies, * e.g. fetching the data from a child resource instead of the given resource. - * @param resource Configuration resource path + * @param resource Configuration resource path or part of it (e.g. config name) * @return Transformed configuration resource path. If null is returned this strategy does not support the given configuration resource path. */ @CheckForNull String getResourcePath(@Nonnull String resourcePath); Modified: sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/AbstractMetadata.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/AbstractMetadata.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/AbstractMetadata.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/AbstractMetadata.java Thu Dec 1 18:05:41 2016 @@ -25,7 +25,7 @@ import javax.annotation.Nonnull; /** * Common properties for configuration and properties. */ -abstract class AbstractMetadata { +abstract class AbstractMetadata<T> { private final String name; private String label; @@ -55,9 +55,12 @@ abstract class AbstractMetadata { /** * @param label Label + * @return this; */ - public void setLabel(String label) { + @SuppressWarnings("unchecked") + public T label(String label) { this.label = label; + return (T)this; } /** @@ -69,9 +72,12 @@ abstract class AbstractMetadata { /** * @param description Description + * @return this; */ - public void setDescription(String description) { + @SuppressWarnings("unchecked") + public T description(String description) { this.description = description; + return (T)this; } /** @@ -83,9 +89,12 @@ abstract class AbstractMetadata { /** * @param properties Further properties for documentation and configuration of behavior in configuration editor. + * @return this; */ - public void setProperties(Map<String,String> properties) { + @SuppressWarnings("unchecked") + public T properties(Map<String,String> properties) { this.properties = properties; + return (T)this; } @Override Modified: sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/ConfigurationMetadata.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/ConfigurationMetadata.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/ConfigurationMetadata.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/ConfigurationMetadata.java Thu Dec 1 18:05:41 2016 @@ -18,6 +18,8 @@ */ package org.apache.sling.caconfig.spi.metadata; +import java.util.Collection; +import java.util.HashMap; import java.util.Map; import javax.annotation.Nonnull; @@ -28,16 +30,31 @@ import org.osgi.annotation.versioning.Pr * Defines a configuration. */ @ProviderType -public final class ConfigurationMetadata extends AbstractMetadata { +public final class ConfigurationMetadata extends AbstractMetadata<ConfigurationMetadata> { - private boolean collection; - private Map<String,PropertyMetadata<?>> propertyMetadata; + private final Map<String,PropertyMetadata<?>> propertyMetadata; + private final boolean collection; /** * @param name Configuration name */ - public ConfigurationMetadata(@Nonnull String name) { + public ConfigurationMetadata(@Nonnull String name, + Collection<PropertyMetadata<?>> propertyMetadata, + boolean collection) { super(name); + this.propertyMetadata = toMap(propertyMetadata); + this.collection = collection; + } + + private static Map<String,PropertyMetadata<?>> toMap(Collection<PropertyMetadata<?>> propertyMetadata) { + Map<String,PropertyMetadata<?>> map = new HashMap<>(); + for (PropertyMetadata<?> item : propertyMetadata) { + if (map.containsKey(item.getName())) { + throw new IllegalArgumentException("Duplicate property name: " + item.getName()); + } + map.put(item.getName(), item); + } + return map; } /** @@ -55,24 +72,10 @@ public final class ConfigurationMetadata } /** - * @param isList true if configuration is collection - */ - public void setCollection(boolean value) { - this.collection = value; - } - - /** * @return Configuration properties */ public Map<String,PropertyMetadata<?>> getPropertyMetadata() { return this.propertyMetadata; } - /** - * @param propertyMetadata Configuration properties - */ - public void setPropertyMetadata(Map<String,PropertyMetadata<?>> propertyMetadata) { - this.propertyMetadata = propertyMetadata; - } - } Modified: sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/PropertyMetadata.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/PropertyMetadata.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/PropertyMetadata.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/metadata/PropertyMetadata.java Thu Dec 1 18:05:41 2016 @@ -33,7 +33,7 @@ import org.osgi.annotation.versioning.Pr * @param <T> Property value type */ @ProviderType -public final class PropertyMetadata<T> extends AbstractMetadata { +public final class PropertyMetadata<T> extends AbstractMetadata<PropertyMetadata<T>> { // these are all types supported for fields of annotation classes (plus class which indicates nested configurations) private static final Class<?>[] SUPPORTED_TYPES_ARRAY = { @@ -119,9 +119,11 @@ public final class PropertyMetadata<T> e /** * @param value Default value if parameter is not set for configuration + * @return this; */ - public void setDefaultValue(T value) { + public PropertyMetadata<T> defaultValue(T value) { this.defaultValue = value; + return this; } /** @@ -133,9 +135,20 @@ public final class PropertyMetadata<T> e /** * @param configurationMetadata Metadata for nested configuration + * @return this; */ - public void setConfigurationMetadata(ConfigurationMetadata configurationMetadata) { + public PropertyMetadata<T> configurationMetadata(ConfigurationMetadata configurationMetadata) { this.configurationMetadata = configurationMetadata; + return this; + } + + /** + * @return true if this property describes a nested configuration. + * In this case it is ensured configuration metadata is present, and the type is ConfigurationMetadata or ConfigurationMetadata[]. + */ + public boolean isNestedConfiguration() { + return configurationMetadata != null + && (this.type.equals(ConfigurationMetadata.class) || this.type.equals(ConfigurationMetadata[].class)); } @Override Modified: sling/trunk/contrib/extensions/contextaware-config/spi/src/test/java/org/apache/sling/caconfig/spi/metadata/ConfigurationMetadataTest.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/spi/src/test/java/org/apache/sling/caconfig/spi/metadata/ConfigurationMetadataTest.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/spi/src/test/java/org/apache/sling/caconfig/spi/metadata/ConfigurationMetadataTest.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/spi/src/test/java/org/apache/sling/caconfig/spi/metadata/ConfigurationMetadataTest.java Thu Dec 1 18:05:41 2016 @@ -26,28 +26,51 @@ import java.util.Map; import org.junit.Test; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; public class ConfigurationMetadataTest { @Test public void testProps() { - ConfigurationMetadata underTest = new ConfigurationMetadata("name1"); + ConfigurationMetadata underTest = new ConfigurationMetadata("name1", ImmutableList.<PropertyMetadata<?>>of(), false); assertEquals("name1", underTest.getName()); assertTrue(underTest.isSingleton()); assertFalse(underTest.isCollection()); - underTest.setLabel("label1"); - underTest.setDescription("desc1"); - underTest.setCollection(true); Map<String,String> props = ImmutableMap.of("p1", "v1"); - underTest.setProperties(props); + underTest.label("label1") + .description("desc1") + .properties(props); assertEquals("label1", underTest.getLabel()); assertEquals("desc1", underTest.getDescription()); + assertEquals(props, underTest.getProperties()); + } + + @Test + public void testCollectionProps() { + ConfigurationMetadata underTest = new ConfigurationMetadata("name1", ImmutableList.<PropertyMetadata<?>>of(), true); + assertEquals("name1", underTest.getName()); assertFalse(underTest.isSingleton()); assertTrue(underTest.isCollection()); - assertEquals(props, underTest.getProperties()); + } + + @Test + public void testPropertyMap() { + ConfigurationMetadata underTest = new ConfigurationMetadata("name1", ImmutableList.<PropertyMetadata<?>>of( + new PropertyMetadata<>("prop1", "devValue"), + new PropertyMetadata<>("prop2", 5)), false); + assertEquals(2, underTest.getPropertyMetadata().size()); + assertTrue(underTest.getPropertyMetadata().containsKey("prop1")); + assertTrue(underTest.getPropertyMetadata().containsKey("prop2")); + } + + @Test(expected = IllegalArgumentException.class) + public void testDuplicateKey() { + new ConfigurationMetadata("name1", ImmutableList.<PropertyMetadata<?>>of( + new PropertyMetadata<>("prop1", "devValue"), + new PropertyMetadata<>("prop1", 5)), false); } } Modified: sling/trunk/contrib/extensions/contextaware-config/spi/src/test/java/org/apache/sling/caconfig/spi/metadata/PropertyMetadataTest.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/spi/src/test/java/org/apache/sling/caconfig/spi/metadata/PropertyMetadataTest.java?rev=1772244&r1=1772243&r2=1772244&view=diff ============================================================================== --- sling/trunk/contrib/extensions/contextaware-config/spi/src/test/java/org/apache/sling/caconfig/spi/metadata/PropertyMetadataTest.java (original) +++ sling/trunk/contrib/extensions/contextaware-config/spi/src/test/java/org/apache/sling/caconfig/spi/metadata/PropertyMetadataTest.java Thu Dec 1 18:05:41 2016 @@ -25,6 +25,7 @@ import java.util.Map; import org.junit.Test; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; public class PropertyMetadataTest { @@ -35,14 +36,13 @@ public class PropertyMetadataTest { assertEquals("name1", underTest.getName()); assertEquals(String.class, underTest.getType()); - underTest.setLabel("label1"); - underTest.setDescription("desc1"); - underTest.setDefaultValue("value1"); + ConfigurationMetadata configMetadata = new ConfigurationMetadata("test", ImmutableList.<PropertyMetadata<?>>of(), false); Map<String,String> props = ImmutableMap.of("p1", "v1"); - underTest.setProperties(props); - - ConfigurationMetadata configMetadata = new ConfigurationMetadata("test"); - underTest.setConfigurationMetadata(configMetadata); + underTest.label("label1") + .description("desc1") + .defaultValue("value1") + .properties(props) + .configurationMetadata(configMetadata); assertEquals("label1", underTest.getLabel()); assertEquals("desc1", underTest.getDescription());