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

dulvac pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-rules.git


The following commit(s) were added to refs/heads/master by this push:
     new f5c886a  SLING-7272 [Testing Rules] Allow customizing the Sling Client 
Builder from an Instance junit rule
f5c886a is described below

commit f5c886a770c1fe8244e2ccb5e12fe10e7f85e83c
Author: Andrei Dulvac <[email protected]>
AuthorDate: Mon Nov 27 11:44:57 2017 +0100

    SLING-7272 [Testing Rules] Allow customizing the Sling Client Builder from 
an Instance junit rule
---
 .../junit/rules/instance/AbstractInstance.java     | 108 ++++++++++++++++++---
 .../junit/rules/instance/BuilderCustomizer.java    |  26 +++++
 .../testing/junit/rules/instance/Instance.java     |  35 ++++++-
 3 files changed, 152 insertions(+), 17 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/testing/junit/rules/instance/AbstractInstance.java
 
b/src/main/java/org/apache/sling/testing/junit/rules/instance/AbstractInstance.java
index 0dfd448..2aa343f 100644
--- 
a/src/main/java/org/apache/sling/testing/junit/rules/instance/AbstractInstance.java
+++ 
b/src/main/java/org/apache/sling/testing/junit/rules/instance/AbstractInstance.java
@@ -17,61 +17,141 @@
 package org.apache.sling.testing.junit.rules.instance;
 
 
+import org.apache.sling.testing.clients.ClientException;
 import org.apache.sling.testing.clients.SlingClient;
 import org.apache.sling.testing.clients.instance.InstanceConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.net.URI;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 public abstract class AbstractInstance implements Instance {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(AbstractInstance.class);
+    // Caches a client
+    private final Map<String, SlingClient> clientsCache = new 
ConcurrentHashMap<>(1);
+
+
+    /**
+     * Customizes the builder and returns it. Default implementation does 
nothing to the builder.
+     * This should be overridden in subclasses, if needed. This method will be 
called internally before building a client.
+     * @param builder the builder to customize
+     * @return the builder after customization.
+     */
+    @Override
+    public <T extends SlingClient.InternalBuilder> T customize(T builder) {
+        return builder;
+    }
 
     /**
      * {@inheritDoc}
      */
     @Override
-    public <T extends SlingClient> T getClient(Class<T> clientClass, String 
user, String pass) {
+    public <T extends SlingClient> T newClient(Class<T> clientClass, String 
user, String pass, BuilderCustomizer... customizers) {
         InstanceConfiguration configuration = getConfiguration();
+        try {
+            T.InternalBuilder<T> builder = getBuilder(clientClass, 
configuration.getUrl(), user, pass);
+            for (BuilderCustomizer customizer: customizers) {
+                builder = customizer.customize(builder);
+            }
+            T client = builder.build();
+            clientsCache.put(user + pass, client);
+            return client;
+        } catch (ClientException e) {
+            return null;
+        }
+    }
 
-        Constructor<T> constructor;
+    private Class getBuilderClass(Class clientClass) {
 
-        try {
-            constructor = clientClass.getConstructor(URI.class, String.class, 
String.class);
-        } catch (NoSuchMethodException e) {
+        // If the passed class is not a client, nothing to do;
+        if (!SlingClient.class.isAssignableFrom(clientClass)) {
+            return null;
+        }
+
+        // If it's SlingClient, just return the builder
+        if (clientClass == SlingClient.class) {
+            return SlingClient.Builder.class;
+        }
+
+        // First class that is not abstract and extends 
SlingClient.InternalBuilder is our builder
+        for (Class clazz : clientClass.getDeclaredClasses()) {
+            if (SlingClient.InternalBuilder.class.isAssignableFrom(clazz)
+                    && !Modifier.isAbstract(clazz.getModifiers())) {
+                return clazz;
+            }
+        }
+
+        // Not declared on this class, looking at the parent
+        if (null == clientClass.getSuperclass()) {
             return null;
+        } else {
+            return getBuilderClass(clientClass.getSuperclass());
         }
+    }
 
-        T client;
+    protected <B extends SlingClient.InternalBuilder, T extends SlingClient> B 
getBuilder(Class<T> clientClass, URI url, String user, String password) {
+        Class<B> builderClass = getBuilderClass(clientClass);
+        B builder;
 
         try {
-            client = constructor.newInstance(configuration.getUrl(), user, 
pass);
-        } catch (Exception e) {
+            Method create = builderClass.getMethod("create", URI.class, 
String.class, String.class);
+            builder = (B) create.invoke(null, url, user, password);
+        } catch (NoSuchMethodException e) {
+            return null;
+        } catch (IllegalAccessException e) {
+            return null;
+        } catch (InvocationTargetException e) {
             return null;
         }
 
-        return client;
+        // return the customized builder
+        return customize(builder);
     }
 
     /**
      * {@inheritDoc}
      */
     @Override
-    public <T extends SlingClient> T getAdminClient(Class<T> clientClass) {
-        return getClient(clientClass, getConfiguration().getAdminUser(), 
getConfiguration().getAdminPassword());
+    public SlingClient newAdminClient(BuilderCustomizer... customizers) {
+        return newClient(SlingClient.class, getConfiguration().getAdminUser(), 
getConfiguration().getAdminPassword(), customizers);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <T extends SlingClient> T getClient(Class<T> clientClass, String 
user, String pass) {
+        if (clientsCache.containsKey(user + pass)) {
+            try {
+                return clientsCache.get(user + pass).adaptTo(clientClass);
+            } catch (ClientException e) {
+                return null;
+            }
+        } else {
+            return newClient(clientClass, user, pass);
+        }
+    }
 
     /**
      * {@inheritDoc}
      */
     @Override
     public SlingClient getAdminClient() {
-       return getAdminClient(SlingClient.class);
+        return getAdminClient(SlingClient.class);
     }
 
-
-
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <T extends SlingClient> T getAdminClient(Class<T> clientClass) {
+        return getClient(clientClass, getConfiguration().getAdminUser(), 
getConfiguration().getAdminPassword());
+    }
 }
diff --git 
a/src/main/java/org/apache/sling/testing/junit/rules/instance/BuilderCustomizer.java
 
b/src/main/java/org/apache/sling/testing/junit/rules/instance/BuilderCustomizer.java
new file mode 100644
index 0000000..b53b1f3
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/testing/junit/rules/instance/BuilderCustomizer.java
@@ -0,0 +1,26 @@
+/*
+ * 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.junit.rules.instance;
+
+import org.apache.sling.testing.clients.SlingClient;
+
+/**
+ * Customizes a Sling Client Builder.
+ */
+public interface BuilderCustomizer {
+    <T extends SlingClient.InternalBuilder> T customize(T builder);
+}
diff --git 
a/src/main/java/org/apache/sling/testing/junit/rules/instance/Instance.java 
b/src/main/java/org/apache/sling/testing/junit/rules/instance/Instance.java
index 0f92ff2..d12cb47 100644
--- a/src/main/java/org/apache/sling/testing/junit/rules/instance/Instance.java
+++ b/src/main/java/org/apache/sling/testing/junit/rules/instance/Instance.java
@@ -21,7 +21,9 @@ import 
org.apache.sling.testing.clients.instance.InstanceConfiguration;
 import org.apache.sling.testing.clients.instance.InstanceSetup;
 import org.junit.rules.TestRule;
 
-public interface Instance extends TestRule {
+import java.beans.Customizer;
+
+public interface Instance extends TestRule, BuilderCustomizer {
 
     Instance withRunMode(String runMode);
 
@@ -31,6 +33,7 @@ public interface Instance extends TestRule {
 
     /**
      * Return <strong>a new client</strong> pointing to the instance 
corresponding to this {{AbstractInstance}}
+     * if it was never created with this username and password, or the 
existing client if it has been created before
      *
      * @param clientClass the class of the returned client
      * @param user the username used in the client
@@ -42,7 +45,8 @@ public interface Instance extends TestRule {
 
     /**
      * Return <strong>a new client</strong> pointing to the instance 
corresponding to this {{AbstractInstance}},
-     * with the admin user and password.
+     * with the admin user and password, if it was not previously created, or 
the existing client if it has been created before
+     *
      * See {@link InstanceSetup#INSTANCE_CONFIG_ADMINUSER} and {@link 
InstanceSetup#INSTANCE_CONFIG_ADMINPASSWORD}
      *
      * @return a new {{SlingClient}}
@@ -51,7 +55,8 @@ public interface Instance extends TestRule {
 
     /**
      * Return <strong>a new client</strong> pointing to the instance 
corresponding to this {{AbstractInstance}},
-     * with the admin user and password.
+     * with the admin user and password, if it was not previously created, or 
the existing client if it has been created before
+     *
      * See {@link InstanceSetup#INSTANCE_CONFIG_ADMINUSER} and {@link 
InstanceSetup#INSTANCE_CONFIG_ADMINPASSWORD}
      *
      * @param clientClass the class of the returned client
@@ -60,4 +65,28 @@ public interface Instance extends TestRule {
      */
     <T extends SlingClient> T getAdminClient(Class<T> clientClass);
 
+
+
+    /**
+     * Return <strong>a new client</strong> pointing to the instance 
corresponding to this {{AbstractInstance}},
+     * replacing the internally-cached client with this username and password
+     *
+     * @param clientClass the class of the returned client
+     * @param user the username used in the client
+     * @param pass the password used in the client
+     * @param <T> the type of the returned client
+     * @return a new client extending {{SlingClient}}
+     */
+    <T extends SlingClient> T newClient(Class<T> clientClass, String user, 
String pass, BuilderCustomizer... customizers);
+
+    /**
+     * Return <strong>a new client</strong> pointing to the instance 
corresponding to this {{AbstractInstance}},
+     * replacing the internally-cached client with this username and password
+     *
+     * See {@link InstanceSetup#INSTANCE_CONFIG_ADMINUSER} and {@link 
InstanceSetup#INSTANCE_CONFIG_ADMINPASSWORD}
+     *
+     * @return a new {{SlingClient}}
+     */
+    SlingClient newAdminClient(BuilderCustomizer... customizers);
+
 }

-- 
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].

Reply via email to