SLING-5240 : Remove getAdministrativeResourceResolver() usage from org.apache.sling.tenant

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1722866 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/tenant/TenantManager.java b/src/main/java/org/apache/sling/tenant/TenantManager.java
index 23b1c1a..63f3a07 100644
--- a/src/main/java/org/apache/sling/tenant/TenantManager.java
+++ b/src/main/java/org/apache/sling/tenant/TenantManager.java
@@ -47,7 +47,7 @@
      * properties.
      * <p>
      * After creating the tenant, the
-     * {@link org.apache.sling.tenant.spi.TenantCustomizer#setup(Tenant, org.apache.sling.api.resource.ResourceResolver)}
+     * {@link org.apache.sling.tenant.spi.TenantManagerHook#setup(Tenant)}
      * method is called to allow customizers to configure additional properties.
      * <p>
      * Before returning the newly created tenant object the data is persisted.
@@ -72,7 +72,7 @@
      * property if the value is {@code null}.
      * <p>
      * Before returning the
-     * {@link org.apache.sling.tenant.spi.TenantCustomizer#setup(Tenant, org.apache.sling.api.resource.ResourceResolver)}
+     * {@link org.apache.sling.tenant.spi.TenantManagerHook#change(Tenant)}
      * method is called to allow customizers to configure additional properties.
      *
      * @param tenant The tenant whose property is to be set or remove.
@@ -88,7 +88,7 @@
      * Sets or removes multiple properties on the tenant.
      * <p>
      * Before returning the
-     * {@link org.apache.sling.tenant.spi.TenantCustomizer#setup(Tenant, org.apache.sling.api.resource.ResourceResolver)}
+     * {@link org.apache.sling.tenant.spi.TenantManagerHook#change(Tenant)}
      * method is called to allow customizers to configure additional properties.
      *
      * @param tenant The tenant whose properties are to be modified.
@@ -103,7 +103,7 @@
      * Removes one or more properties from the tenant.
      * <p>
      * Before returning the
-     * {@link org.apache.sling.tenant.spi.TenantCustomizer#setup(Tenant, org.apache.sling.api.resource.ResourceResolver)}
+     * {@link org.apache.sling.tenant.spi.TenantManagerHook#change(Tenant)}
      * method is called to allow customizers to configure additional properties
      * unless the {@code properties} parameter is {@code null} or empty.
      *
@@ -120,7 +120,7 @@
      * Removes the given tenant.
      * <p>
      * Before returning the
-     * {@link org.apache.sling.tenant.spi.TenantCustomizer#remove(Tenant, org.apache.sling.api.resource.ResourceResolver)}
+     * {@link org.apache.sling.tenant.spi.TenantManagerHook#remove(Tenant)}
      * method is called to allow customizers to implement further cleanup upon
      * tenant removal.
      *
diff --git a/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java b/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java
index 72fe197..83be26e 100644
--- a/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java
+++ b/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java
@@ -32,12 +32,12 @@
 import org.apache.felix.scr.annotations.Activate;

 import org.apache.felix.scr.annotations.Component;

 import org.apache.felix.scr.annotations.Deactivate;

-import org.apache.felix.scr.annotations.Properties;

 import org.apache.felix.scr.annotations.Property;

 import org.apache.felix.scr.annotations.PropertyUnbounded;

 import org.apache.felix.scr.annotations.Reference;

 import org.apache.felix.scr.annotations.ReferenceCardinality;

 import org.apache.felix.scr.annotations.ReferencePolicy;

+import org.apache.felix.scr.annotations.References;

 import org.apache.felix.scr.annotations.Service;

 import org.apache.sling.api.resource.LoginException;

 import org.apache.sling.api.resource.ModifiableValueMap;

@@ -53,6 +53,7 @@
 import org.apache.sling.tenant.TenantProvider;

 import org.apache.sling.tenant.internal.console.WebConsolePlugin;

 import org.apache.sling.tenant.spi.TenantCustomizer;

+import org.apache.sling.tenant.spi.TenantManagerHook;

 import org.osgi.framework.BundleContext;

 import org.osgi.framework.Constants;

 import org.osgi.framework.Filter;

@@ -69,15 +70,20 @@
         label = "Apache Sling Tenant Provider",

         description = "Service responsible for providing Tenants",

         immediate = true)

-@Service

-@Properties(value = {

-    @Property(name = Constants.SERVICE_DESCRIPTION, value = "Apache Sling Tenant Provider")

-})

-@Reference(

+@Service(value = {TenantProvider.class, TenantManager.class})

+@Property(name = Constants.SERVICE_DESCRIPTION, value = "Apache Sling Tenant Provider")

+@References({

+    @Reference(

         name = "tenantSetup",

         referenceInterface = TenantCustomizer.class,

         cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,

-        policy = ReferencePolicy.DYNAMIC)

+        policy = ReferencePolicy.DYNAMIC),

+    @Reference(

+            name = "hook",

+            referenceInterface = TenantManagerHook.class,

+            cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,

+            policy = ReferencePolicy.DYNAMIC)

+})

 public class TenantProviderImpl implements TenantProvider, TenantManager {

 

     /** default log */

@@ -96,6 +102,9 @@
     private SortedMap<Comparable<Object>, TenantCustomizer> registeredTenantHandlers = new TreeMap<Comparable<Object>, TenantCustomizer>(

         Collections.reverseOrder());

 

+    private SortedMap<Comparable<Object>, TenantManagerHook> registeredHooks = new TreeMap<Comparable<Object>, TenantManagerHook>(

+            Collections.reverseOrder());

+

     @Property(

             value = {},

             unbounded = PropertyUnbounded.ARRAY,

@@ -146,9 +155,25 @@
         return registeredTenantHandlers.values();

     }

 

+    @SuppressWarnings("unused")

+    private synchronized void bindHook(TenantManagerHook action, Map<String, Object> config) {

+        registeredHooks.put(ServiceUtil.getComparableForServiceRanking(config), action);

+    }

+

+    @SuppressWarnings("unused")

+    private synchronized void unbindHook(TenantManagerHook action, Map<String, Object> config) {

+        registeredHooks.remove(ServiceUtil.getComparableForServiceRanking(config));

+    }

+

+    private synchronized Collection<TenantManagerHook> getHooks() {

+        return registeredHooks.values();

+    }

+

+    @Override

     public Tenant getTenant(final String tenantId) {

         if (tenantId != null && tenantId.length() > 0) {

             return call(new ResourceResolverTask<Tenant>() {

+                @Override

                 public Tenant call(ResourceResolver resolver) {

                     Resource tenantRes = getTenantResource(resolver, tenantId);

                     return (tenantRes != null) ? new TenantImpl(tenantRes) : null;

@@ -160,10 +185,12 @@
         return null;

     }

 

+    @Override

     public Iterator<Tenant> getTenants() {

         return getTenants(null);

     }

 

+    @Override

     public Iterator<Tenant> getTenants(final String tenantFilter) {

         final Filter filter;

         if (tenantFilter != null && tenantFilter.length() > 0) {

@@ -177,6 +204,7 @@
         }

 

         Iterator<Tenant> result = call(new ResourceResolverTask<Iterator<Tenant>>() {

+            @Override

             public Iterator<Tenant> call(ResourceResolver resolver) {

                 Resource tenantRootRes = resolver.getResource(tenantRootPath);

 

@@ -202,15 +230,17 @@
         return result;

     }

 

+    @Override

     public Tenant create(final String tenantId, final Map<String, Object> properties) {

         return call(new ResourceResolverTask<Tenant>() {

+            @Override

             public Tenant call(ResourceResolver adminResolver) {

                 try {

                     // create the tenant

                     Resource tenantRes = createTenantResource(adminResolver, tenantId, properties);

                     TenantImpl tenant = new TenantImpl(tenantRes);

                     adminResolver.commit();

-                    customizeTenant(tenantRes, tenant);

+                    customizeTenant(tenantRes, tenant, true);

                     adminResolver.commit();

 

                     // refresh tenant instance, as it copies property from

@@ -231,8 +261,10 @@
         });

     }

 

+    @Override

     public void remove(final Tenant tenant) {

         call(new ResourceResolverTask<Void>() {

+            @Override

             public Void call(ResourceResolver resolver) {

                 try {

                     Resource tenantRes = getTenantResource(resolver, tenant.getId());

@@ -245,6 +277,14 @@
                                 log.info("removeTenant: Unexpected problem calling TenantCustomizer " + ts, e);

                             }

                         }

+                        // call tenant hooks

+                        for (TenantManagerHook ts : getHooks()) {

+                            try {

+                                ts.remove(tenant);

+                            } catch (Exception e) {

+                                log.info("removeTenant: Unexpected problem calling TenantManagerHook " + ts, e);

+                            }

+                        }

 

                         resolver.delete(tenantRes);

                         resolver.commit();

@@ -258,8 +298,10 @@
         });

     }

 

+    @Override

     public void setProperty(final Tenant tenant, final String name, final Object value) {

         updateProperties(tenant, new PropertiesUpdater() {

+            @Override

             public void update(ModifiableValueMap properties) {

                 if (value != null) {

                     properties.put(name, value);

@@ -270,8 +312,10 @@
         });

     }

 

+    @Override

     public void setProperties(final Tenant tenant, final Map<String, Object> properties) {

         updateProperties(tenant, new PropertiesUpdater() {

+            @Override

             public void update(ModifiableValueMap vm) {

                 for (Entry<String, Object> entry : properties.entrySet()) {

                     if (entry.getValue() != null) {

@@ -284,8 +328,10 @@
         });

     }

 

+    @Override

     public void removeProperties(final Tenant tenant, final String... propertyNames) {

         updateProperties(tenant, new PropertiesUpdater() {

+            @Override

             public void update(ModifiableValueMap properties) {

                 for (String name : propertyNames) {

                     properties.remove(name);

@@ -334,7 +380,7 @@
         return resolver.getResource(tenantRootPath + "/" + tenantId);

     }

 

-    private void customizeTenant(final Resource tenantRes, final Tenant tenant) {

+    private void customizeTenant(final Resource tenantRes, final Tenant tenant, boolean isCreate) {

 

         // call tenant setup handler

         Map<String, Object> tenantProps = tenantRes.adaptTo(ModifiableValueMap.class);

@@ -355,6 +401,17 @@
                 log.info("addTenant: Unexpected problem calling TenantCustomizer " + ts, e);

             }

         }

+        // call tenant hooks

+        for (TenantManagerHook ts : getHooks()) {

+            try {

+                Map<String, Object> props = (isCreate ? ts.setup(tenant) : ts.change(tenant));

+                if (props != null) {

+                    tenantProps.putAll(props);

+                }

+            } catch (Exception e) {

+                log.info("removeTenant: Unexpected problem calling TenantManagerHook " + ts, e);

+            }

+        }

     }

 

     private <T> T call(ResourceResolverTask<T> task) {

@@ -377,6 +434,7 @@
 

     private void updateProperties(final Tenant tenant, final PropertiesUpdater updater) {

         call(new ResourceResolverTask<Void>() {

+            @Override

             public Void call(ResourceResolver resolver) {

                 try {

                     Resource tenantRes = getTenantResource(resolver, tenant.getId());

@@ -388,7 +446,7 @@
                             ((TenantImpl) tenant).loadProperties(tenantRes);

                         }

 

-                        customizeTenant(tenantRes, tenant);

+                        customizeTenant(tenantRes, tenant, false);

                         resolver.commit();

 

                         if (tenant instanceof TenantImpl) {

diff --git a/src/main/java/org/apache/sling/tenant/spi/TenantCustomizer.java b/src/main/java/org/apache/sling/tenant/spi/TenantCustomizer.java
index 18785da..345197b 100644
--- a/src/main/java/org/apache/sling/tenant/spi/TenantCustomizer.java
+++ b/src/main/java/org/apache/sling/tenant/spi/TenantCustomizer.java
@@ -30,7 +30,11 @@
  *
  * Tools can hook into the tenant creation, changing a tenant and removing
  * thereof by implementing this interface.
+ *
+ * @deprecated This interface will not be supported in future versions. Use
+ *             {@link TenantManagerHook} instead.
  */
+@Deprecated
 @ConsumerType
 public interface TenantCustomizer {
 
@@ -54,7 +58,7 @@
      *         property accessor methods. {@code null} or an empty map may be
      *         returned to not add properties.
      */
-    public Map<String, Object> setup(Tenant tenant, ResourceResolver resolver);
+    Map<String, Object> setup(Tenant tenant, ResourceResolver resolver);
 
     /**
      * Called to remove the setup for the given Tenant. This reverts all changes
@@ -72,5 +76,5 @@
      *            persistence for further cleanup. Note, that this
      *            {@code resolver} will have administrative privileges.
      */
-    public void remove(Tenant tenant, ResourceResolver resolver);
+    void remove(Tenant tenant, ResourceResolver resolver);
 }
diff --git a/src/main/java/org/apache/sling/tenant/spi/TenantManagerHook.java b/src/main/java/org/apache/sling/tenant/spi/TenantManagerHook.java
new file mode 100644
index 0000000..612f086
--- /dev/null
+++ b/src/main/java/org/apache/sling/tenant/spi/TenantManagerHook.java
@@ -0,0 +1,78 @@
+/*
+ * 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.tenant.spi;
+
+import java.util.Map;
+
+import org.apache.sling.tenant.Tenant;
+
+import aQute.bnd.annotation.ConsumerType;
+
+/**
+ * This is a service interface to customize tenant setup and administration.
+ *
+ * Tools can hook into the tenant creation, changing a tenant and removing
+ * thereof by implementing this interface.
+ *
+ * @since 1.1
+ */
+@ConsumerType
+public interface TenantManagerHook {
+
+    /**
+     * Method called to create the given tenant. The method may return
+     * additional properties to be added to the Tenant's property list.
+     * <p>
+     * This method is not expected to throw an exception. Any exception thrown
+     * is logged but otherwise ignored.
+     *
+     * @param tenant The {@link Tenant} to be configured by this call
+     * @return Additional properties to be added to the tenant. These properties
+     *         may later be accessed through the {@linkplain Tenant tenant's}
+     *         property accessor methods. {@code null} or an empty map may be
+     *         returned to not add properties.
+     */
+    Map<String, Object> setup(Tenant tenant);
+
+    /**
+     * Method called to update the given tenant. The method may return
+     * additional properties to be added to the Tenant's property list.
+     * <p>
+     * This method is not expected to throw an exception. Any exception thrown
+     * is logged but otherwise ignored.
+     *
+     * @param tenant The {@link Tenant} to be configured by this call
+     * @return Additional properties to be added to the tenant. These properties
+     *         may later be accessed through the {@linkplain Tenant tenant's}
+     *         property accessor methods. {@code null} or an empty map may be
+     *         returned to not add properties.
+     */
+    Map<String, Object> change(Tenant tenant);
+
+    /**
+     * Called to remove the setup for the given Tenant. This reverts all changes
+     * done by the #setup method.
+     * <p>
+     * This method is not expected to throw an exception. Any exception thrown
+     * is logged but otherwise ignored.
+     *
+     * @param tenant The {@link Tenant} about to be removed
+     */
+    void remove(Tenant tenant);
+}
diff --git a/src/main/java/org/apache/sling/tenant/spi/package-info.java b/src/main/java/org/apache/sling/tenant/spi/package-info.java
index fa458c7..aa5c3f6 100644
--- a/src/main/java/org/apache/sling/tenant/spi/package-info.java
+++ b/src/main/java/org/apache/sling/tenant/spi/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@Version("1.0")
+@Version("1.1")
 package org.apache.sling.tenant.spi;
 
 import aQute.bnd.annotation.Version;