blob: 54553fb634173ecd9e9cf5016fca732ee09803d5 [file] [log] [blame]
/*
* 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;
}
}