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 2020/10/08 15:26:06 UTC

[sling-org-apache-sling-testing-sling-mock] branch feature/SLING-9680-custom-bindingsvaluesprovider created (now a5de1c2)

This is an automated email from the ASF dual-hosted git repository.

sseifert pushed a change to branch feature/SLING-9680-custom-bindingsvaluesprovider
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git.


      at a5de1c2  SLING-9680 support custom BindingsValuesProvider in a way that keeps the dynamic nature of the "OOTB" bindings depending on current resource

This branch includes the following new commits:

     new a5de1c2  SLING-9680 support custom BindingsValuesProvider in a way that keeps the dynamic nature of the "OOTB" bindings depending on current resource

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[sling-org-apache-sling-testing-sling-mock] 01/01: SLING-9680 support custom BindingsValuesProvider in a way that keeps the dynamic nature of the "OOTB" bindings depending on current resource

Posted by ss...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sseifert pushed a commit to branch feature/SLING-9680-custom-bindingsvaluesprovider
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit a5de1c21362966799ef5bf69d35632542297d23d
Author: sseifert <ss...@pro-vision.de>
AuthorDate: Thu Oct 8 17:17:16 2020 +0200

    SLING-9680 support custom BindingsValuesProvider in a way that keeps the dynamic nature of the "OOTB" bindings depending on current resource
---
 .../mock/sling/context/MockSlingBindings.java      |  39 +++++++-
 .../mock/sling/context/SlingContextImpl.java       |  14 ++-
 .../testing/mock/sling/SlingBindingsTest.java      |  58 -----------
 .../mock/sling/context/SlingBindingsTest.java      | 106 +++++++++++++++++++++
 .../sling/context/models/SlingBindingsModel.java   |  12 ++-
 5 files changed, 164 insertions(+), 65 deletions(-)

diff --git a/core/src/main/java/org/apache/sling/testing/mock/sling/context/MockSlingBindings.java b/core/src/main/java/org/apache/sling/testing/mock/sling/context/MockSlingBindings.java
index 0f6f464..8bcb9d8 100644
--- a/core/src/main/java/org/apache/sling/testing/mock/sling/context/MockSlingBindings.java
+++ b/core/src/main/java/org/apache/sling/testing/mock/sling/context/MockSlingBindings.java
@@ -20,28 +20,39 @@ package org.apache.sling.testing.mock.sling.context;
 
 import javax.jcr.Node;
 import javax.jcr.Session;
+import javax.script.SimpleBindings;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.scripting.api.BindingsValuesProvider;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
 
 /**
  * Mock extension of {@link SlingBindings} that dynamically evaluates properties read from SlingBindings from the current mock context.
  * Normally the SlingBingings are set statically for each script execution, but in mocks where no script is really executed
  * it's easier to evaluate them from current context. 
  */
-class MockSlingBindings extends SlingBindings {
+class MockSlingBindings extends SlingBindings implements EventHandler {
     private static final long serialVersionUID = 1L;
 
     private static final String PROP_CURRENT_NODE = "currentNode";
     private static final String PROP_CURRENT_SESSION = "currentSession";
     
+    /**
+     * OSGi service property to set to "true" on BindingsValuesProvider implementations that should be ignored
+     * when populating the "non-dynamic" bindings properties.
+     */
+    static final String SERVICE_PROPERTY_MOCK_SLING_BINDINGS_IGNORE = "MockSlingBindings-ignore";
+    
     private final SlingContextImpl context;
 
     public MockSlingBindings(SlingContextImpl context) {
         this.context = context;
+        populateFromBindingsValuesProvider();
     }
 
     @Override
@@ -54,7 +65,27 @@ class MockSlingBindings extends SlingBindings {
         }
         return super.get(key);
     }
-    
+
+    /**
+     * Removes all (non-dynamic) properties from bindings and populates them from all registered {@link BindingsValuesProvider} implementations.
+     */
+    private void populateFromBindingsValuesProvider() {
+        SimpleBindings bindings = new SimpleBindings();
+        for (BindingsValuesProvider provider : context.getServices(BindingsValuesProvider.class,
+                "(!(" + SERVICE_PROPERTY_MOCK_SLING_BINDINGS_IGNORE + "=true))")) {
+            provider.addBindings(bindings);
+        }
+        this.clear();
+        this.putAll(bindings);
+    }
+
+    @Override
+    public void handleEvent(Event event) {
+        // is triggered by OSGi events fired by {@link org.apache.sling.scripting.core.impl.BindingsValuesProvidersByContextImpl}
+        // whenever a new bindings value provider is added or removed
+        populateFromBindingsValuesProvider();
+    }
+
     static @Nullable Object resolveSlingBindingProperty(@NotNull SlingContextImpl context, @NotNull String property) {
 
         // -- Sling --
@@ -79,7 +110,7 @@ class MockSlingBindings extends SlingBindings {
         if (StringUtils.equals(property, OUT)) {
             return context.response().getWriter();
         }
-        
+
         // -- JCR --
         // this emulates behavior of org.apache.sling.jcr.resource.internal.scripting.JcrObjectsBindingsValuesProvider
         if (StringUtils.equals(property, PROP_CURRENT_NODE)) {
@@ -91,7 +122,7 @@ class MockSlingBindings extends SlingBindings {
         if (StringUtils.equals(property, PROP_CURRENT_SESSION)) {
             return context.resourceResolver().adaptTo(Session.class);
         }
-        
+
         return null;
     }
 
diff --git a/core/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java b/core/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
index 7389b97..8211bda 100644
--- a/core/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
+++ b/core/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
@@ -18,6 +18,9 @@
  */
 package org.apache.sling.testing.mock.sling.context;
 
+import static org.apache.sling.testing.mock.sling.context.MockSlingBindings.SERVICE_PROPERTY_MOCK_SLING_BINDINGS_IGNORE;
+import static org.osgi.service.event.EventConstants.EVENT_TOPIC;
+
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -63,6 +66,7 @@ import org.jetbrains.annotations.Nullable;
 import org.osgi.annotation.versioning.ConsumerType;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.EventHandler;
 
 /**
  * Defines Sling context objects with lazy initialization.
@@ -180,7 +184,8 @@ public class SlingContextImpl extends OsgiContextImpl {
         registerService(SlingSettingsService.class, new MockSlingSettingService(DEFAULT_RUN_MODES));
         registerService(MimeTypeService.class, new MockMimeTypeService());
         registerInjectActivateService(new ResourceBuilderFactoryService());
-        registerInjectActivateService(new JcrObjectsBindingsValuesProvider());
+        registerInjectActivateService(new JcrObjectsBindingsValuesProvider(),
+                SERVICE_PROPERTY_MOCK_SLING_BINDINGS_IGNORE, true);
         registerInjectActivateService(new MockResourceBundleProvider());
         registerInjectActivateService(new MockXSSAPIImpl());
         
@@ -283,7 +288,12 @@ public class SlingContextImpl extends OsgiContextImpl {
             this.request = new MockSlingHttpServletRequest(this.resourceResolver(), this.bundleContext());
 
             // initialize sling bindings
-            SlingBindings bindings = new MockSlingBindings(this);
+            MockSlingBindings bindings = new MockSlingBindings(this);
+            
+            // register as OSGi event handler to get notified on events fired by BindingsValuesProvidersByContextImpl
+            this.registerService(EventHandler.class, bindings,
+                    EVENT_TOPIC, "org/apache/sling/scripting/core/BindingsValuesProvider/*");
+            
             this.request.setAttribute(SlingBindings.class.getName(), bindings);
         }
         return this.request;
diff --git a/core/src/test/java/org/apache/sling/testing/mock/sling/SlingBindingsTest.java b/core/src/test/java/org/apache/sling/testing/mock/sling/SlingBindingsTest.java
deleted file mode 100644
index 9f1f823..0000000
--- a/core/src/test/java/org/apache/sling/testing/mock/sling/SlingBindingsTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.testing.mock.sling;
-
-import static org.junit.Assert.assertNotNull;
-
-import org.apache.sling.api.resource.Resource;
-import org.apache.sling.testing.mock.sling.context.models.SlingBindingsModel;
-import org.apache.sling.testing.mock.sling.junit.SlingContext;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-@SuppressWarnings("null")
-public class SlingBindingsTest {
-
-    @Rule
-    public SlingContext context = new SlingContext(ResourceResolverType.JCR_MOCK);
-
-    private Resource currentResource;
-
-    @Before
-    public void setUp() throws Exception {
-        context.addModelsForClasses(SlingBindingsModel.class);
-        currentResource = context.create().resource("/content/testPage/testResource");
-        context.currentResource(currentResource);
-    }
-
-    @Test
-    public void testBindings() {
-        SlingBindingsModel model = context.request().adaptTo(SlingBindingsModel.class);
-
-        assertNotNull(model);
-        assertNotNull(model.getResolver());
-        assertNotNull(model.getResource());
-        assertNotNull(model.getRequest());
-        assertNotNull(model.getResponse());
-        assertNotNull(model.getCurrentNode());
-        assertNotNull(model.getcurrentSession());
-    }
-
-}
diff --git a/core/src/test/java/org/apache/sling/testing/mock/sling/context/SlingBindingsTest.java b/core/src/test/java/org/apache/sling/testing/mock/sling/context/SlingBindingsTest.java
new file mode 100644
index 0000000..7a9495d
--- /dev/null
+++ b/core/src/test/java/org/apache/sling/testing/mock/sling/context/SlingBindingsTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.testing.mock.sling.context;
+
+import static org.apache.sling.testing.mock.sling.context.MockSlingBindings.SERVICE_PROPERTY_MOCK_SLING_BINDINGS_IGNORE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import javax.script.Bindings;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.scripting.api.BindingsValuesProvider;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.context.models.SlingBindingsModel;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+@SuppressWarnings("null")
+public class SlingBindingsTest {
+
+    @Rule
+    public SlingContext context = new SlingContext(ResourceResolverType.JCR_MOCK);
+
+    private Resource currentResource;
+
+    @Before
+    public void setUp() throws Exception {
+        // setup a custom BindingsValuesProvider
+        context.registerService(BindingsValuesProvider.class, new BindingsValuesProvider() {
+            @Override
+            public void addBindings(Bindings bindings) {
+                bindings.put("custom-param-1", "value-1");
+            }
+        });
+
+        // setup another custom BindingsValuesProvider which should be ignored
+        context.registerService(BindingsValuesProvider.class, new BindingsValuesProvider() {
+            @Override
+            public void addBindings(Bindings bindings) {
+                bindings.put("custom-param-2", "value-2");
+            }
+        }, SERVICE_PROPERTY_MOCK_SLING_BINDINGS_IGNORE, true);
+
+        context.addModelsForClasses(SlingBindingsModel.class);
+        currentResource = context.create().resource("/content/testPage/testResource");
+        context.currentResource(currentResource);
+
+        // setup a custom BindingsValuesProvider after touching request first time/setting current resource
+        context.registerService(BindingsValuesProvider.class, new BindingsValuesProvider() {
+            @Override
+            public void addBindings(Bindings bindings) {
+                bindings.put("custom-param-3", "value-3");
+            }
+        });
+        // wait a short time to get sure OSGi events get distributed announcing the new BindingsValueProvider
+        Thread.sleep(25);
+    }
+
+    @Test
+    public void testModelBindings() {
+        SlingBindingsModel model = context.request().adaptTo(SlingBindingsModel.class);
+
+        assertNotNull(model);
+        assertNotNull(model.getResolver());
+        assertNotNull(model.getResource());
+        assertEquals(currentResource.getPath(), model.getResource().getPath());
+        assertNotNull(model.getRequest());
+        assertNotNull(model.getResponse());
+        assertNotNull(model.getCurrentNode());
+        assertNotNull(model.getCurrentSession());
+        assertEquals("value-1", model.getCustomParam1());
+        assertNull(model.getCustomParam2());
+        assertEquals("value-3", model.getCustomParam3());
+    }
+
+    @Test
+    public void testCustomBindingsValuesProvider() {
+        SlingBindings bindings = (SlingBindings)context.request().getAttribute(SlingBindings.class.getName());
+        assertNotNull(bindings);
+        assertEquals(currentResource.getPath(), bindings.getResource().getPath());
+        assertEquals("value-1", bindings.get("custom-param-1"));
+        assertNull(bindings.get("custom-param-2"));
+        assertEquals("value-3", bindings.get("custom-param-3"));
+    }
+
+}
diff --git a/core/src/test/java/org/apache/sling/testing/mock/sling/context/models/SlingBindingsModel.java b/core/src/test/java/org/apache/sling/testing/mock/sling/context/models/SlingBindingsModel.java
index 0d26bea..6a15464 100644
--- a/core/src/test/java/org/apache/sling/testing/mock/sling/context/models/SlingBindingsModel.java
+++ b/core/src/test/java/org/apache/sling/testing/mock/sling/context/models/SlingBindingsModel.java
@@ -50,6 +50,16 @@ public interface SlingBindingsModel {
     Node getCurrentNode();
 
     @ScriptVariable(injectionStrategy = InjectionStrategy.OPTIONAL)
-    Session getcurrentSession();
+    Session getCurrentSession();
+
+    // -- Custom --
+    @ScriptVariable(name = "custom-param-1", injectionStrategy = InjectionStrategy.OPTIONAL)
+    String getCustomParam1();
+
+    @ScriptVariable(name = "custom-param-2", injectionStrategy = InjectionStrategy.OPTIONAL)
+    String getCustomParam2();
+
+    @ScriptVariable(name = "custom-param-3", injectionStrategy = InjectionStrategy.OPTIONAL)
+    String getCustomParam3();
 
 }