| /* |
| * 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.management.impl; |
| |
| import java.lang.reflect.Array; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| import org.apache.commons.collections.IteratorUtils; |
| import org.apache.commons.lang3.ClassUtils; |
| 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; |
| import org.apache.sling.api.wrappers.ValueMapDecorator; |
| import org.apache.sling.caconfig.management.ConfigurationData; |
| import org.apache.sling.caconfig.management.ConfigurationManagementSettings; |
| import org.apache.sling.caconfig.management.ConfigurationManager; |
| import org.apache.sling.caconfig.management.ValueInfo; |
| import org.apache.sling.caconfig.management.multiplexer.ConfigurationOverrideMultiplexer; |
| import org.apache.sling.caconfig.spi.ConfigurationPersistenceStrategy2; |
| import org.apache.sling.caconfig.spi.metadata.ConfigurationMetadata; |
| import org.apache.sling.caconfig.spi.metadata.PropertyMetadata; |
| import org.jetbrains.annotations.NotNull; |
| |
| final class ConfigurationDataImpl implements ConfigurationData { |
| |
| private final ConfigurationMetadata configMetadata; |
| private final Resource resolvedConfigurationResource; |
| private final Resource writebackConfigurationResource; |
| private final List<Resource> configurationResourceInheritanceChain; |
| private final Resource contextResource; |
| private final String configName; |
| private final ConfigurationManager configurationManager; |
| private final ConfigurationManagementSettings configurationManagementSettings; |
| private final ConfigurationOverrideMultiplexer configurationOverrideMultiplexer; |
| private final ConfigurationPersistenceStrategy2 configurationPersistenceStrategy; |
| private final boolean configResourceCollection; |
| private final String collectionItemName; |
| private final boolean isAllOverridden; |
| |
| private Set<String> propertyNamesCache; |
| private ValueMap valuesCache; |
| private ValueMap effectiveValuesCache; |
| |
| @SuppressWarnings("unchecked") |
| public ConfigurationDataImpl(ConfigurationMetadata configMetadata, |
| Resource resolvedConfigurationResource, Resource writebackConfigurationResource, |
| Iterator<Resource> configurationResourceInheritanceChain, |
| Resource contextResource, String configName, |
| ConfigurationManager configurationManager, |
| ConfigurationManagementSettings configurationManagementSettings, |
| ConfigurationOverrideMultiplexer configurationOverrideMultiplexer, |
| ConfigurationPersistenceStrategy2 configurationPersistenceStrategy, |
| boolean configResourceCollection, String collectionItemName) { |
| this.configMetadata = configMetadata; |
| this.resolvedConfigurationResource = resolvedConfigurationResource; |
| this.writebackConfigurationResource = writebackConfigurationResource; |
| this.configurationResourceInheritanceChain = configurationResourceInheritanceChain != null |
| ? IteratorUtils.toList(configurationResourceInheritanceChain) : null; |
| this.contextResource = contextResource; |
| this.configName = configName; |
| this.configurationManager = configurationManager; |
| this.configurationManagementSettings = configurationManagementSettings; |
| this.configurationOverrideMultiplexer = configurationOverrideMultiplexer; |
| this.configurationPersistenceStrategy = configurationPersistenceStrategy; |
| this.configResourceCollection = configResourceCollection; |
| this.collectionItemName = collectionItemName; |
| this.isAllOverridden = contextResource != null ? configurationOverrideMultiplexer.isAllOverridden(contextResource.getPath(), configName) : false; |
| } |
| |
| public ConfigurationDataImpl(ConfigurationMetadata configMetadata, |
| Resource contextResource, String configName, |
| ConfigurationManager configurationManager, |
| ConfigurationManagementSettings configurationManagementSettings, |
| ConfigurationOverrideMultiplexer configurationOverrideMultiplexer, |
| ConfigurationPersistenceStrategy2 configurationPersistenceStrategy, |
| boolean configResourceCollection) { |
| this(configMetadata, null, null, null, |
| contextResource, configName, |
| configurationManager, |
| configurationManagementSettings, |
| configurationOverrideMultiplexer, |
| configurationPersistenceStrategy, |
| configResourceCollection, null); |
| } |
| |
| @Override |
| public @NotNull String getConfigName() { |
| return configName; |
| } |
| |
| @Override |
| public String getCollectionItemName() { |
| return collectionItemName; |
| } |
| |
| @Override |
| public String getResourcePath() { |
| if (writebackConfigurationResource != null) { |
| return writebackConfigurationResource.getPath(); |
| } |
| if (resolvedConfigurationResource != null) { |
| return resolvedConfigurationResource.getPath(); |
| } |
| return null; |
| } |
| |
| @Override |
| public @NotNull Set<String> getPropertyNames() { |
| if (propertyNamesCache == null) { |
| propertyNamesCache = new LinkedHashSet<>(); |
| if (configMetadata != null) { |
| propertyNamesCache.addAll(configMetadata.getPropertyMetadata().keySet()); |
| } |
| if (resolvedConfigurationResource != null) { |
| propertyNamesCache.addAll(new TreeSet<>(ResourceUtil.getValueMap(resolvedConfigurationResource).keySet())); |
| } |
| PropertiesFilterUtil.removeIgnoredProperties(propertyNamesCache, configurationManagementSettings); |
| } |
| return propertyNamesCache; |
| } |
| |
| @Override |
| public @NotNull ValueMap getValues() { |
| if (valuesCache == null) { |
| Map<String,Object> props = new HashMap<>(); |
| if (writebackConfigurationResource != null) { |
| props.putAll(ResourceUtil.getValueMap(writebackConfigurationResource)); |
| } |
| PropertiesFilterUtil.removeIgnoredProperties(props, configurationManagementSettings); |
| resolveNestedConfigs(props); |
| valuesCache = new ValueMapDecorator(props); |
| } |
| return valuesCache; |
| } |
| |
| @Override |
| public @NotNull ValueMap getEffectiveValues() { |
| if (effectiveValuesCache == null) { |
| Map<String,Object> props = new HashMap<>(); |
| if (configMetadata != null) { |
| for (PropertyMetadata<?> propertyMetadata : configMetadata.getPropertyMetadata().values()) { |
| if (propertyMetadata.getDefaultValue() != null) { |
| props.put(propertyMetadata.getName(), propertyMetadata.getDefaultValue()); |
| } |
| } |
| } |
| if (resolvedConfigurationResource != null) { |
| props.putAll(ResourceUtil.getValueMap(resolvedConfigurationResource)); |
| } |
| PropertiesFilterUtil.removeIgnoredProperties(props, configurationManagementSettings); |
| resolveNestedConfigs(props); |
| effectiveValuesCache = new ValueMapDecorator(props); |
| } |
| return effectiveValuesCache; |
| } |
| |
| private void resolveNestedConfigs(Map<String,Object> props) { |
| if (configMetadata == null) { |
| return; |
| } |
| for (PropertyMetadata<?> propertyMetadata : configMetadata.getPropertyMetadata().values()) { |
| if (propertyMetadata.isNestedConfiguration()) { |
| ConfigurationMetadata nestedConfigMetadata = propertyMetadata.getConfigurationMetadata(); |
| String relatedConfigPath = resolvedConfigurationResource != null ? resolvedConfigurationResource.getPath() : null; |
| String nestedConfigName; |
| if (configResourceCollection) { |
| String collectionItemName = StringUtils.defaultString(getCollectionItemName(), "newItem"); |
| nestedConfigName = configurationPersistenceStrategy.getCollectionParentConfigName(configName, relatedConfigPath) |
| + "/" + configurationPersistenceStrategy.getCollectionItemConfigName(collectionItemName, relatedConfigPath) |
| + "/" + nestedConfigMetadata.getName(); |
| } |
| else { |
| nestedConfigName = configurationPersistenceStrategy.getConfigName(configName, relatedConfigPath) + "/" + nestedConfigMetadata.getName(); |
| } |
| if (propertyMetadata.getType().equals(ConfigurationMetadata.class)) { |
| ConfigurationData configData = configurationManager.getConfiguration(contextResource, nestedConfigName); |
| props.put(propertyMetadata.getName(), configData); |
| } |
| else if (propertyMetadata.getType().equals(ConfigurationMetadata[].class)) { |
| Collection<ConfigurationData> configDatas = configurationManager.getConfigurationCollection(contextResource, nestedConfigName).getItems(); |
| props.put(propertyMetadata.getName(), configDatas.toArray(new ConfigurationData[configDatas.size()])); |
| } |
| } |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public ValueInfo<?> getValueInfo(String propertyName) { |
| PropertyMetadata<?> propertyMetadata = getPropertyMetadata(propertyName); |
| Object value; |
| Object effectiveValue; |
| if (propertyMetadata != null) { |
| Class<?> type = propertyMetadata.getType(); |
| if (type == ConfigurationMetadata.class) { |
| type = ConfigurationData.class; |
| } |
| else if (type == ConfigurationMetadata[].class) { |
| type = ConfigurationData[].class; |
| } |
| else { |
| type = primitiveToWrapper(type); |
| } |
| value = getValues().get(propertyName, type); |
| effectiveValue = getEffectiveValues().get(propertyName, type); |
| } |
| else { |
| value = getValues().get(propertyName); |
| effectiveValue = getEffectiveValues().get(propertyName); |
| } |
| return new ValueInfoImpl(propertyName, value, effectiveValue, propertyMetadata, |
| resolvedConfigurationResource, |
| writebackConfigurationResource, |
| configurationResourceInheritanceChain, |
| contextResource, |
| configName, |
| configurationOverrideMultiplexer, |
| isAllOverridden); |
| } |
| |
| private Class<?> primitiveToWrapper(Class<?> type) { |
| if (type.isArray()) { |
| return Array.newInstance(ClassUtils.primitiveToWrapper(type.getComponentType()), 0).getClass(); |
| } |
| else { |
| return ClassUtils.primitiveToWrapper(type); |
| } |
| } |
| |
| private PropertyMetadata<?> getPropertyMetadata(String propertyName) { |
| if (configMetadata == null) { |
| return null; |
| } |
| else { |
| return configMetadata.getPropertyMetadata().get(propertyName); |
| } |
| } |
| |
| @Override |
| public boolean isInherited() { |
| // detect if the whole config or config item was inherited |
| if (resolvedConfigurationResource != null && resolvedConfigurationResource.getPath() != null) { |
| if (writebackConfigurationResource == null) { |
| return true; |
| } |
| else { |
| return !StringUtils.equals(writebackConfigurationResource.getPath(), resolvedConfigurationResource.getPath()); |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean isOverridden() { |
| return isAllOverridden; |
| } |
| |
| } |