You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ss...@apache.org on 2016/09/19 15:39:18 UTC
svn commit: r1761468 [2/4] - in
/sling/trunk/contrib/extensions/contextaware-config: api/
api/src/main/java/org/apache/sling/contextaware/config/
api/src/main/java/org/apache/sling/contextaware/config/resource/spi/
api/src/main/java/org/apache/sling/co...
Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/ValueInfo.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/ValueInfo.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/ValueInfo.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/ValueInfo.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,80 @@
+/*
+ * 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.contextaware.config.management;
+
+import javax.annotation.CheckForNull;
+
+import org.apache.sling.contextaware.config.spi.metadata.PropertyMetadata;
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * Provides detailed information about a given configuration value.
+ * @param <T> Property type
+ */
+@ProviderType
+public interface ValueInfo<T> {
+
+ /**
+ * Property metadata.
+ * @return Property metadata. Null if no metadata exists.
+ */
+ @CheckForNull PropertyMetadata<T> getPropertyMetadata();
+
+ /**
+ * Get value stored for the current context path. No inherited value. No default value.
+ * @return Value
+ */
+ @CheckForNull T getValue();
+
+ /**
+ * Get value storedf or the current context path, or inherited from upper levels, or the default value.
+ * @return Value
+ */
+ @CheckForNull T getEffectiveValue();
+
+ /**
+ * Get the path of the configuration resource the value is stored in.
+ * @return Resource path or null if no resource associated.
+ */
+ @CheckForNull String getConfigSourcePath();
+
+ /**
+ * @return true if no value is defined but a default value is returned.
+ */
+ boolean isDefault();
+
+ /**
+ * @return true if the value is not defined for the current context path but inherited from upper levels.
+ */
+ // for future use
+ //boolean isInherited();
+
+ /**
+ * @return true if the value is overridden by an configuration override provider.
+ */
+ // for future use
+ //boolean isOverridden();
+
+ /**
+ * @return true if this value is locked on a higher level and is not allowed to be overridden.
+ */
+ // for future use
+ //boolean isLocked();
+
+}
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/ValueInfo.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/ValueInfo.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/ValueInfo.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationDataImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationDataImpl.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationDataImpl.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationDataImpl.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,97 @@
+/*
+ * 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.contextaware.config.management.impl;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.contextaware.config.management.ConfigurationData;
+import org.apache.sling.contextaware.config.management.ValueInfo;
+import org.apache.sling.contextaware.config.spi.metadata.ConfigurationMetadata;
+import org.apache.sling.contextaware.config.spi.metadata.PropertyMetadata;
+
+final class ConfigurationDataImpl implements ConfigurationData {
+
+ private final ValueMap properties;
+ private final String configSourcePath;
+ private final ConfigurationMetadata configMetadata;
+
+ public ConfigurationDataImpl(Resource configResource, ConfigurationMetadata configMetadata) {
+ this(configResource.getValueMap(), configResource.getPath(), configMetadata);
+ }
+
+ public ConfigurationDataImpl(ConfigurationMetadata configMetadata) {
+ this(ValueMap.EMPTY, null, configMetadata);
+ }
+
+ private ConfigurationDataImpl(ValueMap propertes, String configSourcePath, ConfigurationMetadata configMetadata) {
+ this.properties = propertes;
+ this.configSourcePath = configSourcePath;
+ this.configMetadata = configMetadata;
+ }
+
+ @Override
+ public Set<String> getPropertyNames() {
+ Set<String> propertyNames = new HashSet<>();
+ if (configMetadata != null) {
+ propertyNames.addAll(configMetadata.getPropertyMetadata().keySet());
+ }
+ propertyNames.addAll(properties.keySet());
+ return propertyNames;
+ }
+
+ @Override
+ public ValueMap getValues() {
+ return properties;
+ }
+
+ @Override
+ public ValueMap getEffectiveValues() {
+ 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());
+ }
+ }
+ }
+ props.putAll(properties);
+ return new ValueMapDecorator(props);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public ValueInfo<?> getValueInfo(String propertyName) {
+ PropertyMetadata propertyMetadata = configMetadata != null ? configMetadata.getPropertyMetadata().get(propertyName) : null;
+ Object value;
+ if (propertyMetadata != null) {
+ value = properties.get(propertyName, propertyMetadata.getType());
+ }
+ else {
+ value = properties.get(propertyName);
+ }
+ return new ValueInfoImpl(value, configSourcePath, propertyMetadata);
+ }
+
+}
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationDataImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationDataImpl.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationDataImpl.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationManagerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationManagerImpl.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationManagerImpl.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationManagerImpl.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,107 @@
+/*
+ * 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.contextaware.config.management.impl;
+
+import static org.apache.sling.contextaware.config.impl.ConfigurationNameConstants.CONFIGS_PARENT_NAME;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.contextaware.config.impl.metadata.ConfigurationMetadataProviderMultiplexer;
+import org.apache.sling.contextaware.config.management.ConfigurationData;
+import org.apache.sling.contextaware.config.management.ConfigurationManager;
+import org.apache.sling.contextaware.config.resource.ConfigurationResourceResolver;
+import org.apache.sling.contextaware.config.resource.impl.ConfigurationResourceResolvingStrategyMultiplexer;
+import org.apache.sling.contextaware.config.spi.ConfigurationPersistenceException;
+import org.apache.sling.contextaware.config.spi.metadata.ConfigurationMetadata;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+@Component(service = ConfigurationManager.class)
+public class ConfigurationManagerImpl implements ConfigurationManager {
+
+ @Reference
+ private ConfigurationResourceResolver configurationResourceResolver;
+ @Reference
+ private ConfigurationResourceResolvingStrategyMultiplexer configurationResourceResolvingStrategy;
+ @Reference
+ private ConfigurationMetadataProviderMultiplexer configurationMetadataProvider;
+ @Reference
+ private ConfigurationPersistenceStrategyMultiplexer configurationPersistenceStrategy;
+
+ @Override
+ public ConfigurationData get(Resource resource, String configName) {
+ ConfigurationMetadata configMetadata = configurationMetadataProvider.getConfigurationMetadata(configName);
+ Resource configResource = configurationResourceResolver.getResource(resource, CONFIGS_PARENT_NAME, configName);
+ if (configResource != null) {
+ return new ConfigurationDataImpl(configurationPersistenceStrategy.getResource(configResource), configMetadata);
+ }
+ if (configMetadata != null) {
+ // if no config resource found but config metadata exist return empty config data with default values
+ return new ConfigurationDataImpl(configMetadata);
+ }
+ return null;
+ }
+
+ @Override
+ public Collection<ConfigurationData> getCollection(Resource resource, String configName) {
+ ConfigurationMetadata configMetadata = configurationMetadataProvider.getConfigurationMetadata(configName);
+ Collection<Resource> configResources = configurationResourceResolver.getResourceCollection(resource, CONFIGS_PARENT_NAME, configName);
+ List<ConfigurationData> configData = new ArrayList<>();
+ for (Resource configResource : configResources) {
+ configData.add(new ConfigurationDataImpl(configurationPersistenceStrategy.getResource(configResource), configMetadata));
+ }
+ return configData;
+ }
+
+ @Override
+ public void persist(Resource resource, String configName, Map<String,Object> values) {
+ 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.");
+ }
+ if (!configurationPersistenceStrategy.persist(resource.getResourceResolver(), configResourcePath, values)) {
+ throw new ConfigurationPersistenceException("Unable to persist configuration: No persistence strategy found.");
+ }
+ }
+
+ @Override
+ public void persistCollection(Resource resource, String configName, Collection<Map<String,Object>> values) {
+ 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.");
+ }
+ if (!configurationPersistenceStrategy.persistCollection(resource.getResourceResolver(), configResourceParentPath, values)) {
+ throw new ConfigurationPersistenceException("Unable to persist configuration: No persistence strategy found.");
+ }
+ }
+
+ @Override
+ public ConfigurationData newCollectionItem(String configName) {
+ ConfigurationMetadata configMetadata = configurationMetadataProvider.getConfigurationMetadata(configName);
+ if (configMetadata != null) {
+ return new ConfigurationDataImpl(configMetadata);
+ }
+ return null;
+ }
+
+}
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationManagerImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationManagerImpl.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationManagerImpl.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationPersistenceStrategyMultiplexer.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationPersistenceStrategyMultiplexer.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationPersistenceStrategyMultiplexer.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationPersistenceStrategyMultiplexer.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,99 @@
+/*
+ * 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.contextaware.config.management.impl;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.commons.osgi.Order;
+import org.apache.sling.commons.osgi.RankedServices;
+import org.apache.sling.contextaware.config.spi.ConfigurationPersistenceStrategy;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+
+/**
+ * Detects all {@link ConfigurationPersistenceStrategy} implementations in the container
+ * and consolidates their result based on service ranking.
+ */
+@Component(service = ConfigurationPersistenceStrategyMultiplexer.class,
+reference={
+ @Reference(name="configurationResourcePersistenceStrategy", service=ConfigurationPersistenceStrategy.class,
+ bind="bindConfigurationResourcePersistenceStrategy", unbind="unbindConfigurationResourcePersistenceStrategy",
+ cardinality=ReferenceCardinality.MULTIPLE,
+ policy=ReferencePolicy.DYNAMIC, policyOption=ReferencePolicyOption.GREEDY)
+})
+public class ConfigurationPersistenceStrategyMultiplexer implements ConfigurationPersistenceStrategy {
+
+ private RankedServices<ConfigurationPersistenceStrategy> items = new RankedServices<>(Order.DESCENDING);
+
+ protected void bindConfigurationResourcePersistenceStrategy(ConfigurationPersistenceStrategy configurationResourcePersistenceStrategy, Map<String, Object> props) {
+ items.bind(configurationResourcePersistenceStrategy, props);
+ }
+
+ protected void unbindConfigurationResourcePersistenceStrategy(ConfigurationPersistenceStrategy configurationResourcePersistenceStrategy, Map<String, Object> props) {
+ items.unbind(configurationResourcePersistenceStrategy, props);
+ }
+
+ /**
+ * Transform the configuration resource by the first implementation that has an answer.
+ */
+ @Override
+ public Resource getResource(Resource resource) {
+ for (ConfigurationPersistenceStrategy item : items) {
+ Resource result = item.getResource(resource);
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Persist configuration data with the first implementation that accepts it.
+ */
+ @Override
+ public boolean persist(ResourceResolver resourceResolver, String configResourcePath, Map<String,Object> properties) {
+ for (ConfigurationPersistenceStrategy item : items) {
+ if (item.persist(resourceResolver, configResourcePath, properties)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Persist configuration data with the first implementation that accepts it.
+ */
+ @Override
+ public boolean persistCollection(ResourceResolver resourceResolver, String configResourceCollectionParentPath,
+ Collection<Map<String,Object>> propertiesCollection) {
+ for (ConfigurationPersistenceStrategy item : items) {
+ if (item.persistCollection(resourceResolver, configResourceCollectionParentPath, propertiesCollection)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationPersistenceStrategyMultiplexer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationPersistenceStrategyMultiplexer.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationPersistenceStrategyMultiplexer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ValueInfoImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ValueInfoImpl.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ValueInfoImpl.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ValueInfoImpl.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,64 @@
+/*
+ * 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.contextaware.config.management.impl;
+
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.sling.contextaware.config.management.ValueInfo;
+import org.apache.sling.contextaware.config.spi.metadata.PropertyMetadata;
+
+final class ValueInfoImpl<T> implements ValueInfo<T> {
+
+ private final T value;
+ private final T defaultValue;
+ private final String configSourcePath;
+ private final PropertyMetadata<T> propertyMetadata;
+
+ public ValueInfoImpl(T value, String configSourcePath, PropertyMetadata<T> propertyMetadata) {
+ this.value = value;
+ this.defaultValue = propertyMetadata != null ? propertyMetadata.getDefaultValue() : null;
+ this.configSourcePath = configSourcePath;
+ this.propertyMetadata = propertyMetadata;
+ }
+
+ @Override
+ public PropertyMetadata<T> getPropertyMetadata() {
+ return propertyMetadata;
+ }
+
+ @Override
+ public T getValue() {
+ return value;
+ }
+
+ @Override
+ public T getEffectiveValue() {
+ return ObjectUtils.defaultIfNull(value, defaultValue);
+ }
+
+ @Override
+ public String getConfigSourcePath() {
+ return configSourcePath;
+ }
+
+ @Override
+ public boolean isDefault() {
+ return value == null && defaultValue != null;
+ }
+
+}
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ValueInfoImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ValueInfoImpl.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ValueInfoImpl.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/package-info.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/package-info.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/package-info.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+/**
+ * Management API of the Context-Aware configuration implementation.
+ * This API is only indented for advanced use cases like writing a configuration editor,
+ * not for "normal" applications just reading configuration.
+ */
+@org.osgi.annotation.versioning.Version("1.0.0")
+package org.apache.sling.contextaware.config.management;
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/package-info.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/package-info.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/package-info.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolverImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolverImpl.java?rev=1761468&r1=1761467&r2=1761468&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolverImpl.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolverImpl.java Mon Sep 19 15:39:17 2016
@@ -20,255 +20,37 @@ package org.apache.sling.contextaware.co
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
-import java.util.Set;
import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.contextaware.config.resource.ConfigurationResourceResolver;
-import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Deactivate;
-import org.osgi.service.metatype.annotations.AttributeDefinition;
-import org.osgi.service.metatype.annotations.Designate;
-import org.osgi.service.metatype.annotations.ObjectClassDefinition;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.osgi.service.component.annotations.Reference;
@Component(service=ConfigurationResourceResolver.class, immediate=true)
-@Designate(ocd=ConfigurationResourceResolverImpl.Config.class)
public class ConfigurationResourceResolverImpl implements ConfigurationResourceResolver {
- @ObjectClassDefinition(name="Apache Sling Context Aware Configuration Resolver",
- description="Standardized access to configurations in the resource tree.")
- public static @interface Config {
-
- @AttributeDefinition(name="Allowed paths",
- description = "Whitelist of paths where configurations can reside in.")
- String[] allowedPaths() default {"/conf", "/apps/conf", "/libs/conf"};
-
- @AttributeDefinition(name="Fallback paths",
- description = "Global fallback configurations, ordered from most specific (checked first) to least specific.")
- String[] fallbackPaths() default {"/conf/global", "/apps/conf", "/libs/conf"};
- }
-
- private static final String PROPERTY_CONFIG = "sling:config-ref";
-
- private final Logger logger = LoggerFactory.getLogger(this.getClass());
-
- private volatile Config configuration;
-
- Config getConfiguration() {
- return this.configuration;
- }
-
- @Activate
- private void activate(final Config config) {
- this.configuration = config;
- }
-
- @Deactivate
- private void deactivate() {
- this.configuration = null;
- }
-
- List<String> getResolvePaths(final Resource contentResource) {
- final List<String> refPaths = new ArrayList<>();
-
- // add all config references found in resource hierarchy
- final List<ConfigReference> refs = new ArrayList<>();
- findConfigRefs(refs, contentResource);
- for (ConfigReference ref : refs) {
- refPaths.add(ref.getConfigReference());
- }
-
- // finally add the global fallbacks
- if ( this.configuration.fallbackPaths() != null ) {
- for(final String path : this.configuration.fallbackPaths()) {
- logger.debug("[{}] fallback config => {}", refs.size(), path);
- refPaths.add(path);
- }
- }
-
- return refPaths;
- }
-
- /**
- * Check the name.
- * A name must not be null and relative.
- * @param name The name
- * @return {@code true} if it is valid
- */
- private boolean checkName(final String name) {
- if (name == null || name.isEmpty() || name.startsWith("/") || name.contains("../") ) {
- return false;
- }
- return true;
- }
-
- /**
- * Find next configuration refrence for given resource or one of it's parents.
- * @param startResource Resource to start searching
- * @return Config reference or null if none found
- */
- private ConfigReference findNextConfigRef(final Resource startResource) {
- // start at resource, go up
- Resource resource = startResource;
- while (resource != null) {
- String ref = getReference(resource);
- if (ref != null) {
- // if absolute path found we are (probably) done
- if (ref.startsWith("/")) {
- // combine full path if relativeRef is present
- ref = ResourceUtil.normalize(ref);
-
- if (ref != null && !isAllowedConfigPath(ref)) {
- logger.warn("Ignoring reference to {} from {} - not in allowed paths.", ref, resource.getPath());
- ref = null;
- }
-
- if (ref != null && isFallbackConfigPath(ref)) {
- logger.warn("Ignoring reference to {} from {} - already a fallback path.", ref, resource.getPath());
- ref = null;
- }
-
- if (ref != null) {
- return new ConfigReference(resource, ref);
- }
-
- } else {
- logger.error("Invalid relative reference found for {} : {}. This entry is ignored", resource.getPath(), ref);
- }
- }
- // if getParent() returns null, stop
- resource = resource.getParent();
- }
-
- // if hit root and nothing found, return null
- return null;
- }
-
- /**
- * Searches the resource hierarchy upwards for all config references and returns them.
- * @param refs List to add found resources to
- * @param startResource Resource to start searching
- */
- private void findConfigRefs(final List<ConfigReference> refs, final Resource startResource) {
- ConfigReference ref = findNextConfigRef(startResource);
- if (ref != null) {
- refs.add(ref);
- findConfigRefs(refs, ref.getContentResource().getParent());
- }
- }
-
- private String getReference(final Resource resource) {
- final String ref = resource.getValueMap().get(PROPERTY_CONFIG, String.class);
- logger.trace("Reference '{}' found at {}", ref, resource.getPath());
-
- return ref;
- }
-
- private boolean isAllowedConfigPath(String path) {
- if (this.configuration.allowedPaths() == null) {
- return false;
- }
- for (String pattern : this.configuration.allowedPaths()) {
- if (logger.isTraceEnabled()) {
- logger.trace("- checking if '{}' starts with {}", path, pattern);
- }
- if (path.equals(pattern) || path.startsWith(pattern + "/")) {
- return true;
- }
- }
- return false;
- }
-
- private boolean isFallbackConfigPath(final String ref) {
- if ( this.configuration.fallbackPaths() != null ) {
- for(final String name : this.configuration.fallbackPaths()) {
- if ( name.equals(ref) ) {
- return true;
- }
- }
- }
- return false;
- }
+ @Reference
+ private ContextPathStrategyMultiplexer contextPathStrategy;
+ @Reference
+ private ConfigurationResourceResolvingStrategyMultiplexer configurationResourceResolvingStrategy;
@Override
- public Resource getResource(final Resource contentResource, final String bucketName, final String configName) {
- if (contentResource == null || !checkName(bucketName) || !checkName(configName)) {
- return null;
- }
- String name = bucketName + "/" + configName;
- logger.debug("Searching {} for resource {}", name, contentResource.getPath());
-
- // strategy: find first item among all configured paths
- int idx = 1;
- for (final String path : getResolvePaths(contentResource)) {
- final Resource item = contentResource.getResourceResolver().getResource(ResourceUtil.normalize(path + "/" + name));
- if (item != null) {
- logger.debug("Resolved config item at [{}]: {}", idx, item.getPath());
-
- return item;
- }
- idx++;
- }
-
- logger.debug("Could not resolve any config item for '{}' (or no permissions to read it)", name);
-
- // nothing found
- return null;
+ public Resource getResource(Resource resource, String bucketName, String configName) {
+ return configurationResourceResolvingStrategy.getResource(resource, bucketName, configName);
}
@Override
- public Collection<Resource> getResourceCollection(final Resource contentResource, final String bucketName, final String configName) {
- if (contentResource == null || !checkName(bucketName) || !checkName(configName)) {
- return Collections.emptyList();
- }
- String name = bucketName + "/" + configName;
- if (logger.isTraceEnabled()) {
- logger.trace("- searching for list '{}'", name);
- }
-
- final Set<String> names = new HashSet<>();
- final List<Resource> result = new ArrayList<>();
- int idx = 1;
- for (String path : this.getResolvePaths(contentResource)) {
- Resource item = contentResource.getResourceResolver().getResource(ResourceUtil.normalize(path + "/" + name));
- if (item != null) {
- if (logger.isTraceEnabled()) {
- logger.trace("+ resolved config item at [{}]: {}", idx, item.getPath());
- }
-
- for (Resource child : item.getChildren()) {
- if ( !child.getName().contains(":") && !names.contains(child.getName()) ) {
- result.add(child);
- names.add(child.getName());
- }
- }
-
- } else {
- if (logger.isTraceEnabled()) {
- logger.trace("- no item '{}' under config '{}'", name, path);
- }
- }
- idx++;
- }
-
- if (logger.isTraceEnabled()) {
- logger.trace("- final list has {} items", result.size());
- }
-
- return result;
+ public Collection<Resource> getResourceCollection(Resource resource, String bucketName, String configName) {
+ return configurationResourceResolvingStrategy.getResourceCollection(resource, bucketName, configName);
}
@Override
public String getContextPath(Resource resource) {
- ConfigReference ref = findNextConfigRef(resource);
- if (ref != null) {
- return ref.getContentResource().getPath();
+ Iterator<Resource> it = contextPathStrategy.findContextResources(resource);
+ if (it.hasNext()) {
+ return it.next().getPath();
}
else {
return null;
@@ -278,28 +60,11 @@ public class ConfigurationResourceResolv
@Override
public Collection<String> getAllContextPaths(Resource resource) {
final List<String> contextPaths = new ArrayList<>();
- final List<ConfigReference> refs = new ArrayList<>();
- findConfigRefs(refs, resource);
- for (ConfigReference ref : refs) {
- contextPaths.add(ref.getContentResource().getPath());
+ Iterator<Resource> contextResources = contextPathStrategy.findContextResources(resource);
+ while (contextResources.hasNext()) {
+ contextPaths.add(contextResources.next().getPath());
}
return contextPaths;
}
- private static class ConfigReference {
- private final Resource contentResource;
- private final String configReference;
-
- public ConfigReference(Resource contentResource, String configReference) {
- this.contentResource = contentResource;
- this.configReference = configReference;
- }
- public Resource getContentResource() {
- return contentResource;
- }
- public String getConfigReference() {
- return configReference;
- }
- }
-
}
Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,113 @@
+/*
+ * 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.contextaware.config.resource.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.commons.osgi.Order;
+import org.apache.sling.commons.osgi.RankedServices;
+import org.apache.sling.contextaware.config.resource.spi.ConfigurationResourceResolvingStrategy;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+
+/**
+ * Detects all {@link ConfigurationResourceResolvingStrategy} implementations in the container
+ * and consolidates their result based on service ranking.
+ */
+@Component(service = ConfigurationResourceResolvingStrategyMultiplexer.class,
+reference={
+ @Reference(name="configurationResourceResolvingStrategy", service=ConfigurationResourceResolvingStrategy.class,
+ bind="bindConfigurationResourceResolvingStrategy", unbind="unbindConfigurationResourceResolvingStrategy",
+ cardinality=ReferenceCardinality.MULTIPLE,
+ policy=ReferencePolicy.DYNAMIC, policyOption=ReferencePolicyOption.GREEDY)
+})
+public class ConfigurationResourceResolvingStrategyMultiplexer implements ConfigurationResourceResolvingStrategy {
+
+ private RankedServices<ConfigurationResourceResolvingStrategy> items = new RankedServices<>(Order.DESCENDING);
+
+ protected void bindConfigurationResourceResolvingStrategy(ConfigurationResourceResolvingStrategy contextPathStrategy, Map<String, Object> props) {
+ items.bind(contextPathStrategy, props);
+ }
+
+ protected void unbindConfigurationResourceResolvingStrategy(ConfigurationResourceResolvingStrategy contextPathStrategy, Map<String, Object> props) {
+ items.unbind(contextPathStrategy, props);
+ }
+
+ /**
+ * Gets the configuration resource from the first implementation that has an answer.
+ */
+ @Override
+ public Resource getResource(Resource resource, String bucketName, String configName) {
+ for (ConfigurationResourceResolvingStrategy item : items) {
+ Resource result = item.getResource(resource, bucketName, configName);
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Merge the configuration resources from all implementations into a combined list.
+ */
+ @Override
+ public Collection<Resource> getResourceCollection(Resource resource, String bucketName, String configName) {
+ List<Resource> result = new ArrayList<>();
+ for (ConfigurationResourceResolvingStrategy item : items) {
+ result.addAll(item.getResourceCollection(resource, bucketName, configName));
+ }
+ return result;
+ }
+
+ /**
+ * Gets the configuration resource path from the first implementation that has an answer.
+ */
+ @Override
+ public String getResourcePath(Resource resource, String bucketName, String configName) {
+ for (ConfigurationResourceResolvingStrategy item : items) {
+ String result = item.getResourcePath(resource, bucketName, configName);
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the configuration resource collection parent path from the first implementation that has an answer.
+ */
+ @Override
+ public String getResourceCollectionParentPath(Resource resource, String bucketName, String configName) {
+ for (ConfigurationResourceResolvingStrategy item : items) {
+ String result = item.getResourceCollectionParentPath(resource, bucketName, configName);
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+}
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ContextPathStrategyMultiplexer.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ContextPathStrategyMultiplexer.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ContextPathStrategyMultiplexer.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ContextPathStrategyMultiplexer.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,127 @@
+/*
+ * 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.contextaware.config.resource.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.Predicate;
+import org.apache.commons.collections.iterators.CollatingIterator;
+import org.apache.commons.collections.iterators.FilterIterator;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.commons.osgi.Order;
+import org.apache.sling.commons.osgi.RankedServices;
+import org.apache.sling.contextaware.config.resource.spi.ContextPathStrategy;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+
+/**
+ * Detects all {@link ContextPathStrategy} implementations in the container
+ * and consolidates their result based on service ranking.
+ */
+@Component(service = ContextPathStrategyMultiplexer.class,
+reference={
+ @Reference(name="contextPathStrategy", service=ContextPathStrategy.class,
+ bind="bindContextPathStrategy", unbind="unbindContextPathStrategy",
+ cardinality=ReferenceCardinality.MULTIPLE,
+ policy=ReferencePolicy.DYNAMIC, policyOption=ReferencePolicyOption.GREEDY)
+})
+public class ContextPathStrategyMultiplexer implements ContextPathStrategy {
+
+ private static Comparator<Resource> PATH_LENGTH_COMPARATOR = new Comparator<Resource>() {
+ @Override
+ public int compare(Resource o1, Resource o2) {
+ Integer length1 = o1.getPath().length();
+ Integer length2 = o2.getPath().length();
+ return length2.compareTo(length1);
+ }
+ };
+
+ private RankedServices<ContextPathStrategy> items = new RankedServices<>(Order.DESCENDING);
+
+ protected void bindContextPathStrategy(ContextPathStrategy contextPathStrategy, Map<String, Object> props) {
+ items.bind(contextPathStrategy, props);
+ }
+
+ protected void unbindContextPathStrategy(ContextPathStrategy contextPathStrategy, Map<String, Object> props) {
+ items.unbind(contextPathStrategy, props);
+ }
+
+ /**
+ * Merges all results from the detected implementations into a single answer.
+ */
+ @Override
+ public Iterator<Resource> findContextResources(Resource resource) {
+ List<Iterator<Resource>> allResults = getAllResults(resource);
+ if (allResults.isEmpty()) {
+ return Collections.emptyIterator();
+ }
+ if (allResults.size() == 1) {
+ return allResults.get(0);
+ }
+ return mergeResults(allResults);
+ }
+
+ /**
+ * Get all results from all registered context path strategies.
+ * @param resource Start resource
+ * @return List of all results
+ */
+ private List<Iterator<Resource>> getAllResults(Resource resource) {
+ List<Iterator<Resource>> results = new ArrayList<>();
+ for (ContextPathStrategy item : items) {
+ Iterator<Resource> result = item.findContextResources(resource);
+ if (result.hasNext()) {
+ results.add(result);
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Merges results from different context path strategy implementations.
+ * Eliminating of duplicates and sorting is done solely based on path length.
+ * The contract of the ContextPathStrategy defines that only parents or the resource itself
+ * is returned, so the assumption should be safe.
+ * @param allResults List of all results
+ * @return Merged result
+ */
+ @SuppressWarnings("unchecked")
+ private Iterator<Resource> mergeResults(List<Iterator<Resource>> allResults) {
+ return new FilterIterator(new CollatingIterator(PATH_LENGTH_COMPARATOR, allResults),
+ // eliminate duplicate resources reported by different implementations
+ new Predicate() {
+ private Set<String> resourcePaths = new HashSet<>();
+ @Override
+ public boolean evaluate(Object object) {
+ return resourcePaths.add(((Resource)object).getPath());
+ }
+ });
+ }
+
+}
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ContextPathStrategyMultiplexer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ContextPathStrategyMultiplexer.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ContextPathStrategyMultiplexer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,301 @@
+/*
+ * 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.contextaware.config.resource.impl.def;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.collections.PredicateUtils;
+import org.apache.commons.collections.Transformer;
+import org.apache.commons.collections.iterators.ArrayIterator;
+import org.apache.commons.collections.iterators.FilterIterator;
+import org.apache.commons.collections.iterators.IteratorChain;
+import org.apache.commons.collections.iterators.TransformIterator;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.contextaware.config.resource.impl.ContextPathStrategyMultiplexer;
+import org.apache.sling.contextaware.config.resource.spi.ConfigurationResourceResolvingStrategy;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(service=ConfigurationResourceResolvingStrategy.class)
+@Designate(ocd=DefaultConfigurationResourceResolvingStrategy.Config.class)
+public class DefaultConfigurationResourceResolvingStrategy implements ConfigurationResourceResolvingStrategy {
+
+ @ObjectClassDefinition(name="Apache Sling Context-Aware Default Configuration Resource Resolving Strategy",
+ description="Standardized access to configurations in the resource tree.")
+ static @interface Config {
+
+ @AttributeDefinition(name="Enabled",
+ description = "Enable this configuration resourcer resolving strategy.")
+ boolean enabled() default true;
+
+ @AttributeDefinition(name="Allowed paths",
+ description = "Whitelist of paths where configurations can reside in.")
+ String[] allowedPaths() default {"/conf", "/apps/conf", "/libs/conf"};
+
+ @AttributeDefinition(name="Fallback paths",
+ description = "Global fallback configurations, ordered from most specific (checked first) to least specific.")
+ String[] fallbackPaths() default {"/conf/global", "/apps/conf", "/libs/conf"};
+ }
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private volatile Config config;
+
+ @Reference
+ private ContextPathStrategyMultiplexer contextPathStrategy;
+
+ Config getConfiguration() {
+ return this.config;
+ }
+
+ @Activate
+ private void activate(final Config config) {
+ this.config = config;
+ }
+
+ @Deactivate
+ private void deactivate() {
+ this.config = null;
+ }
+
+ @SuppressWarnings("unchecked")
+ Iterator<String> getResolvePaths(final Resource contentResource) {
+ return new IteratorChain(
+ // add all config references found in resource hierarchy
+ findConfigRefs(contentResource),
+ // finally add the global fallbacks
+ new ArrayIterator(this.config.fallbackPaths())
+ );
+ }
+
+ /**
+ * Check the name.
+ * A name must not be null and relative.
+ * @param name The name
+ * @return {@code true} if it is valid
+ */
+ private boolean checkName(final String name) {
+ if (name == null || name.isEmpty() || name.startsWith("/") || name.contains("../") ) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Searches the resource hierarchy upwards for all config references and returns them.
+ * @param refs List to add found resources to
+ * @param startResource Resource to start searching
+ */
+ @SuppressWarnings("unchecked")
+ private Iterator<String> findConfigRefs(final Resource startResource) {
+ Iterator<Resource> contextResources = contextPathStrategy.findContextResources(startResource);
+ // get config resource path for each context resource, filter out items where not reference could be resolved
+ return new FilterIterator(new TransformIterator(contextResources, new Transformer() {
+ @Override
+ public Object transform(Object input) {
+ return getReference((Resource)input);
+ }
+ }), PredicateUtils.notNullPredicate());
+ }
+
+ private String getReference(final Resource resource) {
+ String ref = resource.getValueMap().get(DefaultContextPathStrategy.PROPERTY_CONFIG, String.class);
+
+ if (ref != null) {
+ // if absolute path found we are (probably) done
+ if (ref.startsWith("/")) {
+ // combine full path if relativeRef is present
+ ref = ResourceUtil.normalize(ref);
+
+ if (ref != null && !isAllowedConfigPath(ref)) {
+ logger.warn("Ignoring reference to {} from {} - not in allowed paths.", ref, resource.getPath());
+ ref = null;
+ }
+
+ if (ref != null && isFallbackConfigPath(ref)) {
+ logger.warn("Ignoring reference to {} from {} - already a fallback path.", ref, resource.getPath());
+ ref = null;
+ }
+
+ } else {
+ logger.error("Invalid relative reference found for {} : {}. This entry is ignored", resource.getPath(), ref);
+ }
+ }
+
+ if (ref != null) {
+ logger.trace("Reference '{}' found at {}", ref, resource.getPath());
+ }
+
+ return ref;
+ }
+
+ private boolean isAllowedConfigPath(String path) {
+ for (String pattern : this.config.allowedPaths()) {
+ if (logger.isTraceEnabled()) {
+ logger.trace("- checking if '{}' starts with {}", path, pattern);
+ }
+ if (path.equals(pattern) || path.startsWith(pattern + "/")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isFallbackConfigPath(final String ref) {
+ for(final String name : this.config.fallbackPaths()) {
+ if ( name.equals(ref) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isEnabledAndParamsValid(final Resource contentResource, final String bucketName, final String configName) {
+ return config.enabled() && contentResource != null && checkName(bucketName) && checkName(configName);
+ }
+
+ private String buildResourcePath(String path, String name) {
+ return ResourceUtil.normalize(path + "/" + name);
+ }
+
+ @Override
+ public Resource getResource(final Resource contentResource, final String bucketName, final String configName) {
+ if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
+ return null;
+ }
+ String name = bucketName + "/" + configName;
+ logger.debug("Searching {} for resource {}", name, contentResource.getPath());
+
+ // strategy: find first item among all configured paths
+ int idx = 1;
+ Iterator<String> paths = getResolvePaths(contentResource);
+ while (paths.hasNext()) {
+ final String path = paths.next();
+ final Resource item = contentResource.getResourceResolver().getResource(buildResourcePath(path, name));
+ if (item != null) {
+ logger.debug("Resolved config item at [{}]: {}", idx, item.getPath());
+
+ return item;
+ }
+ idx++;
+ }
+
+ logger.debug("Could not resolve any config item for '{}' (or no permissions to read it)", name);
+
+ // nothing found
+ return null;
+ }
+
+ @Override
+ public Collection<Resource> getResourceCollection(final Resource contentResource, final String bucketName, final String configName) {
+ if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
+ return Collections.emptyList();
+ }
+ String name = bucketName + "/" + configName;
+ if (logger.isTraceEnabled()) {
+ logger.trace("- searching for list '{}'", name);
+ }
+
+ final Set<String> names = new HashSet<>();
+ final List<Resource> result = new ArrayList<>();
+ int idx = 1;
+ Iterator<String> paths = getResolvePaths(contentResource);
+ while (paths.hasNext()) {
+ final String path = paths.next();
+ Resource item = contentResource.getResourceResolver().getResource(buildResourcePath(path, name));
+ if (item != null) {
+ if (logger.isTraceEnabled()) {
+ logger.trace("+ resolved config item at [{}]: {}", idx, item.getPath());
+ }
+
+ for (Resource child : item.getChildren()) {
+ if ( !child.getName().contains(":") && !names.contains(child.getName()) ) {
+ result.add(child);
+ names.add(child.getName());
+ }
+ }
+
+ } else {
+ if (logger.isTraceEnabled()) {
+ logger.trace("- no item '{}' under config '{}'", name, path);
+ }
+ }
+ idx++;
+ }
+
+ if (logger.isTraceEnabled()) {
+ logger.trace("- final list has {} items", result.size());
+ }
+
+ return result;
+ }
+
+ @Override
+ public String getResourcePath(Resource contentResource, String bucketName, String configName) {
+ if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
+ return null;
+ }
+ String name = bucketName + "/" + configName;
+
+ Iterator<String> configPaths = this.findConfigRefs(contentResource);
+ if (configPaths.hasNext()) {
+ String configPath = buildResourcePath(configPaths.next(), name);
+ logger.debug("Building configuration path {} for resource {}: {}", name, contentResource.getPath(), configPath);
+ return configPath;
+ }
+ else {
+ logger.debug("No configuration path {} foundfor resource {}.", name, contentResource.getPath());
+ return null;
+ }
+ }
+
+ @Override
+ public String getResourceCollectionParentPath(Resource contentResource, String bucketName, String configName) {
+ if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
+ return null;
+ }
+ String name = bucketName + "/" + configName;
+
+ Iterator<String> configPaths = this.findConfigRefs(contentResource);
+ if (configPaths.hasNext()) {
+ String configPath = buildResourcePath(configPaths.next(), name);
+ logger.debug("Building configuration collection parent path {} for resource {}: {}", name, contentResource.getPath(), configPath);
+ return configPath;
+ }
+ else {
+ logger.debug("No configuration collection parent path {} foundfor resource {}.", name, contentResource.getPath());
+ return null;
+ }
+ }
+
+}
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultContextPathStrategy.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultContextPathStrategy.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultContextPathStrategy.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultContextPathStrategy.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,132 @@
+/*
+ * 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.contextaware.config.resource.impl.def;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.contextaware.config.resource.spi.ContextPathStrategy;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(service = ContextPathStrategy.class)
+@Designate(ocd=DefaultContextPathStrategy.Config.class)
+public class DefaultContextPathStrategy implements ContextPathStrategy {
+
+ @ObjectClassDefinition(name="Apache Sling Context-Aware Default Context Path Strategy",
+ description="Detects context path by existence of " + PROPERTY_CONFIG + " properties.")
+ static @interface Config {
+
+ @AttributeDefinition(name="Enabled",
+ description = "Enable this context path strategy.")
+ boolean enabled() default true;
+
+ }
+
+ /**
+ * Property that points to the configuration to be used.
+ * Additionally each resource having this property marks the beginning of a new context sub-tree.
+ */
+ public static final String PROPERTY_CONFIG = "sling:config-ref";
+
+ private final Logger log = LoggerFactory.getLogger(this.getClass());
+
+ private volatile Config config;
+
+ @Activate
+ private void activate(ComponentContext componentContext, Config config) {
+ this.config = config;
+ }
+
+ @Override
+ public Iterator<Resource> findContextResources(Resource resource) {
+ if (!config.enabled()) {
+ return Collections.emptyIterator();
+ }
+ return new ConfigResourceIterator(resource);
+ }
+
+ /**
+ * Searches the resource hierarchy upwards for all context and returns the root resource for each of them.
+ */
+ private class ConfigResourceIterator implements Iterator<Resource> {
+
+ private Resource next;
+
+ public ConfigResourceIterator(Resource startResource) {
+ next = findNextContextResource(startResource);
+ }
+
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ @Override
+ public Resource next() {
+ if (next == null) {
+ throw new NoSuchElementException();
+ }
+ Resource result = next;
+ next = findNextContextResource(next.getParent());
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Find next configuration context root for given resource.
+ * @param startResource Resource to start searching
+ * @return Next resource with sling:config-ref property or null if none found.
+ */
+ private Resource findNextContextResource(Resource startResource) {
+ // start at resource, go up
+ Resource resource = startResource;
+
+ while (resource != null) {
+ if (hasConfigRef(resource)) {
+ log.trace("Found context path '{}'.", resource.getPath());
+ return resource;
+ }
+ // if getParent() returns null, stop
+ resource = resource.getParent();
+ }
+
+ // if hit root and nothing found, return null
+ return null;
+ }
+
+ private boolean hasConfigRef(final Resource resource) {
+ return resource.getValueMap().get(PROPERTY_CONFIG, String.class) != null;
+ }
+
+ }
+
+}
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultContextPathStrategy.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultContextPathStrategy.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultContextPathStrategy.java
------------------------------------------------------------------------------
svn:mime-type = text/plain