You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by an...@apache.org on 2019/08/23 18:45:24 UTC

[sling-org-apache-sling-models-impl] 01/01: SLING-8655 - Updated dependency on API, provided Externalized Path Injector (with default Provider) and an unit test

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

andysch pushed a commit to branch issues/SLING-8655
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit bb865a6c60acdf7f9d2addd774def6fa2d3575d2
Author: Andreas Schaefer <sc...@iMac.local>
AuthorDate: Fri Aug 23 11:45:08 2019 -0700

    SLING-8655 - Updated dependency on API, provided Externalized Path Injector (with default Provider) and an unit test
---
 pom.xml                                            |   2 +-
 .../impl/injectors/ExternalizedPathInjector.java   | 113 ++++++++++++++++++
 .../injectors/ExternalizedPathInjectorTest.java    | 128 +++++++++++++++++++++
 3 files changed, 242 insertions(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 5b8b548..a663fd3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -110,7 +110,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.models.api</artifactId>
-            <version>1.3.6</version>
+            <version>1.3.9-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <!-- OSGi annotations -->
diff --git a/src/main/java/org/apache/sling/models/impl/injectors/ExternalizedPathInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/ExternalizedPathInjector.java
new file mode 100644
index 0000000..9aded00
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/injectors/ExternalizedPathInjector.java
@@ -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.models.impl.injectors;
+
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.models.annotations.ExternalizePath;
+import org.apache.sling.models.annotations.injectorspecific.ExternalizedPathProvider;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.Injector;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.framework.Constants;
+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 java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+@Component(
+    property=Constants.SERVICE_RANKING+":Integer=1000",
+    service={
+        Injector.class
+    }
+)
+public class ExternalizedPathInjector
+    extends AbstractInjector
+    implements Injector
+{
+    List<ExternalizedPathProvider> providerList = new ArrayList<>();
+
+    @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL)
+    void bindExternalizedPathProvider(ExternalizedPathProvider provider) {
+        providerList.add(provider);
+        // The providers are sorted so that the one with the highest priority is the first entry
+        Collections.sort(
+            providerList,
+            Comparator.comparingInt(ExternalizedPathProvider::getPriority).reversed()
+        );
+    }
+
+    void unbindExternalizedPathProvider(ExternalizedPathProvider provider) {
+        providerList.remove(provider);
+    }
+
+    public ExternalizedPathInjector() {
+        bindExternalizedPathProvider(new DefaultExternalizedPathProvider());
+    }
+
+    @Override
+    public @NotNull String getName() {
+        return "externalize-path";
+    }
+
+    @Override
+    public Object getValue(@NotNull Object adaptable, String name, @NotNull Type type, @NotNull AnnotatedElement element,
+            @NotNull DisposalCallbackRegistry callbackRegistry) {
+        if (adaptable == ObjectUtils.NULL) {
+            return null;
+        }
+        if (element.isAnnotationPresent(ExternalizePath.class)) {
+            ValueMap properties = getValueMap(adaptable);
+            if(properties != ObjectUtils.NULL) {
+                String imagePath = properties.get(name, String.class);
+                if(imagePath != null) {
+                    ExternalizedPathProvider provider = providerList.get(0);
+                    return provider.externalize(adaptable, imagePath);
+                }
+            }
+        }
+        return null;
+    }
+
+    /** Fallback Implementation of the Externalized Path Provider that uses the Resource Resolver's map function **/
+    private class DefaultExternalizedPathProvider
+        implements ExternalizedPathProvider
+    {
+        @Override
+        public int getPriority() {
+            return FALLBACK_PRIORITY;
+        }
+
+        @Override
+        public String externalize(@NotNull Object adaptable, String sourcePath) {
+            String answer = sourcePath;
+            ResourceResolver resourceResolver = getResourceResolver(adaptable);
+            if(sourcePath != null && resourceResolver != null) {
+                answer = resourceResolver.map(sourcePath);
+            }
+            return answer;
+        }
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/impl/injectors/ExternalizedPathInjectorTest.java b/src/test/java/org/apache/sling/models/impl/injectors/ExternalizedPathInjectorTest.java
new file mode 100644
index 0000000..2f40e01
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/injectors/ExternalizedPathInjectorTest.java
@@ -0,0 +1,128 @@
+package org.apache.sling.models.impl.injectors;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.models.annotations.ExternalizePath;
+import org.apache.sling.models.annotations.injectorspecific.ExternalizedPathProvider;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ExternalizedPathInjectorTest {
+
+    @Test
+    public void testNoResolveInjection() {
+        String imagePath = "/content/test/image/test-image.jpg";
+
+        ExternalizedPathInjector injector = new ExternalizedPathInjector();
+        Resource adaptable = mock(Resource.class);
+        ValueMap valueMap = mock(ValueMap.class);
+        when(adaptable.adaptTo(eq(ValueMap.class))).thenReturn(valueMap);
+        String name = "imagePath";
+        when(valueMap.get(eq(name), eq(String.class))).thenReturn(imagePath);
+        Type type = String.class;
+        AnnotatedElement element = mock(AnnotatedElement.class);
+        when(element.isAnnotationPresent(eq(ExternalizePath.class))).thenReturn(true);
+        DisposalCallbackRegistry callbackRegistry = mock(DisposalCallbackRegistry.class);
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        when(adaptable.getResourceResolver()).thenReturn(resourceResolver);
+        when(resourceResolver.map(imagePath)).thenReturn(imagePath);
+
+        Object value = injector.getValue(adaptable, name, type, element, callbackRegistry);
+        assertEquals("No Mapping was expected", imagePath, value);
+    }
+
+    @Test
+    public void testResolveInjection() {
+        String imagePath = "/content/test/image/test-image.jpg";
+        String mappedImagePath = "/image/test-image.jpg";
+
+        ExternalizedPathInjector injector = new ExternalizedPathInjector();
+        Resource adaptable = mock(Resource.class);
+        ValueMap valueMap = mock(ValueMap.class);
+        when(adaptable.adaptTo(eq(ValueMap.class))).thenReturn(valueMap);
+        String name = "imagePath";
+        when(valueMap.get(eq(name), eq(String.class))).thenReturn(imagePath);
+        Type type = String.class;
+        AnnotatedElement element = mock(AnnotatedElement.class);
+        when(element.isAnnotationPresent(eq(ExternalizePath.class))).thenReturn(true);
+        DisposalCallbackRegistry callbackRegistry = mock(DisposalCallbackRegistry.class);
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        when(adaptable.getResourceResolver()).thenReturn(resourceResolver);
+        when(resourceResolver.map(imagePath)).thenReturn(mappedImagePath);
+
+        Object value = injector.getValue(adaptable, name, type, element, callbackRegistry);
+        assertEquals("Mapping was expected", mappedImagePath, value);
+    }
+
+    @Test
+    public void testCustomProviderInjection() {
+        String imagePath = "/content/test/image/test-image.jpg";
+        String from = "/content/test/image/";
+        String to1 = "/image1/";
+        String to2 = "/image2/";
+        String to3 = "/image3/";
+        String mappedImagePath = "/image/test-image.jpg";
+        String mappedImagePath1 = "/image1/test-image.jpg";
+        String mappedImagePath2 = "/image2/test-image.jpg";
+        String mappedImagePath3 = "/image3/test-image.jpg";
+
+        ExternalizedPathInjector injector = new ExternalizedPathInjector();
+        Resource adaptable = mock(Resource.class);
+        ValueMap valueMap = mock(ValueMap.class);
+        when(adaptable.adaptTo(eq(ValueMap.class))).thenReturn(valueMap);
+        String name = "imagePath";
+        when(valueMap.get(eq(name), eq(String.class))).thenReturn(imagePath);
+        Type type = String.class;
+        AnnotatedElement element = mock(AnnotatedElement.class);
+        when(element.isAnnotationPresent(eq(ExternalizePath.class))).thenReturn(true);
+        DisposalCallbackRegistry callbackRegistry = mock(DisposalCallbackRegistry.class);
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        when(adaptable.getResourceResolver()).thenReturn(resourceResolver);
+        when(resourceResolver.map(imagePath)).thenReturn(mappedImagePath);
+
+        TestExternalizedPathProvider provider1 = new TestExternalizedPathProvider(100, from, to1);
+        injector.bindExternalizedPathProvider(provider1);
+        TestExternalizedPathProvider provider3 = new TestExternalizedPathProvider(300, from, to3);
+        injector.bindExternalizedPathProvider(provider3);
+        TestExternalizedPathProvider provider2 = new TestExternalizedPathProvider(200, from, to2);
+        injector.bindExternalizedPathProvider(provider2);
+
+        Object value = injector.getValue(adaptable, name, type, element, callbackRegistry);
+        assertEquals("Wrong Provider was selected", mappedImagePath3, value);
+    }
+
+    private class TestExternalizedPathProvider
+        implements ExternalizedPathProvider
+    {
+        private int priority;
+        private String from = "/";
+        private String to = "/";
+
+        public TestExternalizedPathProvider(int priority, String from, String to) {
+            this.priority = priority;
+            this.from = from;
+            this.to = to;
+        }
+        @Override
+        public int getPriority() { return priority; }
+
+        @Override
+        public String externalize(@NotNull Object adaptable, String sourcePath) {
+            String answer = sourcePath;
+            if(sourcePath.startsWith(from)) {
+                answer = to + sourcePath.substring(from.length());
+            }
+            return answer;
+        }
+    }
+}