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/12/09 16:28:25 UTC

svn commit: r1773428 - in /sling/trunk/contrib/extensions/contextaware-config/impl: ./ src/main/java/org/apache/sling/caconfig/impl/ src/test/java/org/apache/sling/caconfig/impl/

Author: sseifert
Date: Fri Dec  9 16:28:24 2016
New Revision: 1773428

URL: http://svn.apache.org/viewvc?rev=1773428&view=rev
Log:
SLING-6384 Context-Aware Config: Bindings Value Provider for HTL/Sightly

Added:
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProvider.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProviderTest.java   (with props)
Modified:
    sling/trunk/contrib/extensions/contextaware-config/impl/pom.xml

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/pom.xml?rev=1773428&r1=1773427&r2=1773428&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/pom.xml (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/pom.xml Fri Dec  9 16:28:24 2016
@@ -111,6 +111,12 @@
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.scripting.api</artifactId>
+            <version>2.1.6</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.json</artifactId>
             <version>2.0.10</version>
             <scope>compile</scope>

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProvider.java?rev=1773428&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProvider.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProvider.java Fri Dec  9 16:28:24 2016
@@ -0,0 +1,206 @@
+/*
+ * 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.impl;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.script.Bindings;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.caconfig.ConfigurationBuilder;
+import org.apache.sling.caconfig.impl.metadata.ConfigurationMetadataProviderMultiplexer;
+import org.apache.sling.caconfig.spi.ConfigurationMetadataProvider;
+import org.apache.sling.caconfig.spi.metadata.ConfigurationMetadata;
+import org.apache.sling.scripting.api.BindingsValuesProvider;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+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;
+
+/**
+ * Binds a script variable "caconfig" to the current configuration value map to be
+ * used in HTL (Sightly).
+ */
+@Component(immediate = true, service = BindingsValuesProvider.class, property = {
+        "javax.script.name=sightly",
+        Constants.SERVICE_RANKING + "=100" })
+@Designate(ocd = ConfigurationBindingsValueProvider.Config.class)
+public class ConfigurationBindingsValueProvider implements BindingsValuesProvider {
+
+    /**
+     * Name of the variable to which the config value map is bound to in script
+     * configuration.
+     */
+    public static final String BINDING_VARIABLE = "caconfig";
+
+    @ObjectClassDefinition(name = "Apache Sling Context-Aware Configuration HTL Binding Values Provider", 
+            description = "Binds a script variable '" + BINDING_VARIABLE + "' to the HTL/Sightly scripting context.")
+    static @interface Config {
+
+        @AttributeDefinition(name = "Enabled", description = "Enable provider.")
+        boolean enabled() default true;
+
+    }
+
+    @Reference
+    private ConfigurationMetadataProviderMultiplexer configMetadataProvider;
+
+    private boolean enabled;
+
+    @Override
+    public void addBindings(Bindings bindings) {
+        if (!enabled || !bindings.containsKey(SlingBindings.REQUEST)) {
+            return;
+        }
+        SlingHttpServletRequest request = (SlingHttpServletRequest)bindings.get(SlingBindings.REQUEST);
+        Resource resource = request.getResource();
+        if (resource == null) {
+            return;
+        }
+        Map<String,Object> configMap = new ConfigMap(resource, configMetadataProvider);
+        bindings.put(BINDING_VARIABLE, configMap);
+    }
+
+    @Activate
+    void activate(Config config) {
+        this.enabled = config.enabled();
+    }
+
+    
+    /**
+     * This is a "virtual" containing configuration names as keys, and the underlying value maps/value map collections as values.
+     * The map accesses only the data that is really required in a lazy fashion.
+     */
+    private static class ConfigMap implements Map<String, Object> {
+        
+        private final Resource resource;
+        private final ConfigurationMetadataProvider configMetadataProvider;
+        private Set<String> configNamesCache;
+        private Map<String,Object> valuesCache = new HashMap<>();
+        
+        ConfigMap(Resource resource, ConfigurationMetadataProvider configMetadataProvider) {
+            this.resource = resource;
+            this.configMetadataProvider = configMetadataProvider;
+        }
+        
+        private Set<String> getConfigNames() {
+            if (configNamesCache == null) {
+                configNamesCache = configMetadataProvider.getConfigurationNames();
+            }
+            return configNamesCache;
+        }
+
+        @Override
+        public int size() {
+            return getConfigNames().size();
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return getConfigNames().isEmpty();
+        }
+
+        @Override
+        public boolean containsKey(Object key) {
+            return getConfigNames().contains(key);
+        }
+
+        @Override
+        public Object get(Object key) {
+            Object value = valuesCache.get(key);
+            if (value == null) {
+                value = getConfigValue((String)key);
+                if (value != null) {
+                    valuesCache.put((String)key, value);
+                }
+            }
+            return value;
+        }
+        
+        private Object getConfigValue(String configName) {
+            ConfigurationBuilder configBuilder = resource.adaptTo(ConfigurationBuilder.class).name(configName);
+            if (isCollection(configName)) {
+                return configBuilder.asValueMapCollection();
+            }
+            else {
+                return configBuilder.asValueMap();
+            }
+        }
+        
+        private boolean isCollection(String configName) {
+            ConfigurationMetadata configMetadata = configMetadataProvider.getConfigurationMetadata(configName);
+            if (configMetadata != null) {
+                return configMetadata.isCollection();
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public Set<String> keySet() {
+            return getConfigNames();
+        }
+
+        @Override
+        public boolean containsValue(Object value) {
+            throw new UnsupportedOperationException();
+        }
+        
+        @Override
+        public Object put(String key, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Object remove(Object key) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void putAll(Map<? extends String, ? extends Object> m) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void clear() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Collection<Object> values() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Set<java.util.Map.Entry<String, Object>> entrySet() {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+}

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProvider.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Dec  9 16:28:24 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProvider.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProviderTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProviderTest.java?rev=1773428&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProviderTest.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProviderTest.java Fri Dec  9 16:28:24 2016
@@ -0,0 +1,139 @@
+/*
+ * 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.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Map;
+import java.util.SortedSet;
+
+import javax.script.Bindings;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.caconfig.ConfigurationBuilder;
+import org.apache.sling.caconfig.impl.metadata.ConfigurationMetadataProviderMultiplexer;
+import org.apache.sling.caconfig.spi.ConfigurationMetadataProvider;
+import org.apache.sling.caconfig.spi.metadata.ConfigurationMetadata;
+import org.apache.sling.caconfig.spi.metadata.PropertyMetadata;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSortedSet;
+
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("unchecked")
+public class ConfigurationBindingsValueProviderTest {
+
+    private final static ValueMap VALUEMAP = new ValueMapDecorator(
+            ImmutableMap.<String, Object> of("param1", "value1"));
+    
+    private static final SortedSet<String> CONFIG_NAMES = ImmutableSortedSet.of("name1", "name.2");
+
+    @Rule
+    public SlingContext context = new SlingContext();
+
+    @Mock
+    private SlingHttpServletRequest request;
+    @Mock
+    private Resource resource;
+    @Mock
+    private Bindings bindings;
+    @Mock
+    private ConfigurationBuilder configBuilder;
+    @Mock
+    private ConfigurationMetadataProvider configMetadataProvider;
+
+    private ConfigurationBindingsValueProvider underTest;
+
+    @Before
+    public void setUp() {
+        context.registerInjectActivateService(new ConfigurationMetadataProviderMultiplexer());
+        context.registerService(ConfigurationMetadataProvider.class, configMetadataProvider);
+        when(configMetadataProvider.getConfigurationNames()).thenReturn(CONFIG_NAMES);
+        
+        when(bindings.containsKey(SlingBindings.REQUEST)).thenReturn(true);
+        when(bindings.get(SlingBindings.REQUEST)).thenReturn(request);
+        when(request.getResource()).thenReturn(resource);
+        when(resource.adaptTo(ConfigurationBuilder.class)).thenReturn(configBuilder);
+        when(configBuilder.name(anyString())).thenReturn(configBuilder);
+        when(configBuilder.asValueMap()).thenReturn(VALUEMAP);
+        when(configBuilder.asValueMapCollection()).thenReturn(ImmutableList.of(VALUEMAP));
+        
+        when(configMetadataProvider.getConfigurationMetadata("name1")).thenReturn(
+                new ConfigurationMetadata("name1", ImmutableList.<PropertyMetadata<?>>of(), false));
+        when(configMetadataProvider.getConfigurationMetadata("name.2")).thenReturn(
+                new ConfigurationMetadata("name.2", ImmutableList.<PropertyMetadata<?>>of(), true));
+    }
+
+    @Test
+    public void testWithConfig() {
+        underTest = context.registerInjectActivateService(new ConfigurationBindingsValueProvider(), "enabled", true);
+        underTest.addBindings(bindings);
+
+        ArgumentCaptor<Map<String, ValueMap>> configMapCaptor = ArgumentCaptor.forClass(Map.class);
+        verify(bindings).put(eq(ConfigurationBindingsValueProvider.BINDING_VARIABLE), configMapCaptor.capture());
+        
+        Map<String, ValueMap> configMap = configMapCaptor.getValue();
+        assertEquals(CONFIG_NAMES, configMap.keySet());
+        assertEquals(VALUEMAP, configMap.get("name1"));
+        assertEquals(ImmutableList.of(VALUEMAP), configMap.get("name.2"));
+    }
+
+    @Test
+    public void testNoResource() {
+        when(request.getResource()).thenReturn(null);
+        underTest = context.registerInjectActivateService(new ConfigurationBindingsValueProvider(), "enabled", true);
+        underTest.addBindings(bindings);
+        verify(bindings, never()).put(anyString(), any(Object.class));
+    }
+
+    @Test
+    public void testNoRequest() {
+        underTest = context.registerInjectActivateService(new ConfigurationBindingsValueProvider(), "enabled", true);
+        when(bindings.containsKey(SlingBindings.REQUEST)).thenReturn(false);
+        underTest.addBindings(bindings);
+        verify(bindings, never()).put(anyString(), any(Object.class));
+    }
+
+    @Test
+    public void testDisabled() {
+        underTest = context.registerInjectActivateService(new ConfigurationBindingsValueProvider(), "enabled", false);
+        underTest.addBindings(bindings);
+        verify(bindings, never()).put(anyString(), any(Object.class));
+    }
+
+}

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProviderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProviderTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Dec  9 16:28:24 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationBindingsValueProviderTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain