Author: fmeschbe
Date: Thu Nov 29 13:14:21 2012
New Revision: 1415151

URL: http://svn.apache.org/viewvc?rev=1415151&view=rev
Log:
SLING-2676 Simple tenant administration through the Web Console (thanks Amit 
Gupta for providing the patch).

Added:
    
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/console/
    
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java
    
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/spi/
    
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/spi/TenantCustomizer.java
    
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/spi/package-info.java
Modified:
    sling/trunk/contrib/extensions/tenant/pom.xml
    
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java

Modified: sling/trunk/contrib/extensions/tenant/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tenant/pom.xml?rev=1415151&r1=1415150&r2=1415151&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/tenant/pom.xml (original)
+++ sling/trunk/contrib/extensions/tenant/pom.xml Thu Nov 29 13:14:21 2012
@@ -98,6 +98,12 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-jcr-commons</artifactId>
+            <version>2.4.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>commons-lang</groupId>
             <artifactId>commons-lang</artifactId>
             <version>2.0</version>
@@ -118,6 +124,11 @@
             <artifactId>bndlib</artifactId>
             <scope>provided</scope>
         </dependency>
+        <!-- Webconsole -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+        </dependency>
 
         <!-- Testing -->
         <dependency>

Modified: 
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java?rev=1415151&r1=1415150&r2=1415151&view=diff
==============================================================================
--- 
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java
 (original)
+++ 
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java
 Thu Nov 29 13:14:21 2012
@@ -19,10 +19,13 @@
 package org.apache.sling.tenant.internal;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -38,8 +41,12 @@ import org.apache.felix.scr.annotations.
 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.Service;
+import org.apache.jackrabbit.commons.JcrUtils;
 import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.PersistableValueMap;
 import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
@@ -47,8 +54,11 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.commons.osgi.ServiceUtil;
 import org.apache.sling.tenant.Tenant;
 import org.apache.sling.tenant.TenantProvider;
+import org.apache.sling.tenant.internal.console.WebConsolePlugin;
+import org.apache.sling.tenant.spi.TenantCustomizer;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.Filter;
@@ -61,11 +71,17 @@ import org.osgi.framework.InvalidSyntaxE
 @Component(
         metatype = true,
         label = "Apache Sling JCR Tenant Provider",
-        description = "Service responsible for providing Tenants")
+        description = "Service responsible for providing Tenants",
+        immediate = true)
 @Service
 @Properties(value = {
     @Property(name = Constants.SERVICE_DESCRIPTION, value = "Apache Sling JCR 
Tenant Provider")
 })
+@Reference(
+        name = "tenantSetup",
+        referenceInterface = TenantCustomizer.class,
+        cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
+        policy = ReferencePolicy.DYNAMIC)
 public class TenantProviderImpl implements TenantProvider {
     /**
      * Root path for tenant
@@ -77,6 +93,9 @@ public class TenantProviderImpl implemen
 
     private static final String[] DEFAULT_PATH_MATCHER = {};
 
+    private SortedMap<Comparable<Object>, TenantCustomizer> 
registeredTenantHandlers = new TreeMap<Comparable<Object>, TenantCustomizer>(
+        Collections.reverseOrder());
+
     @Property(
             value = {},
             unbounded = PropertyUnbounded.ARRAY,
@@ -95,10 +114,15 @@ public class TenantProviderImpl implemen
 
     private TenantAdapterFactory adapterFactory;
 
+    private WebConsolePlugin plugin;
+
+    private BundleContext bundleContext;
+
     @Activate
     private void activate(final BundleContext bundleContext, final Map<String, 
Object> properties) {
         this.tenantRootPath = 
PropertiesUtil.toString(properties.get(TENANT_ROOT), JCR_TENANT_ROOT);
         this.pathMatchers = 
PropertiesUtil.toStringArray(properties.get(TENANT_PATH_MATCHER), 
DEFAULT_PATH_MATCHER);
+        this.bundleContext = bundleContext;
 
         this.pathPatterns.clear();
         for (String matcherStr : this.pathMatchers) {
@@ -106,6 +130,7 @@ public class TenantProviderImpl implemen
         }
 
         this.adapterFactory = new TenantAdapterFactory(bundleContext, this);
+        this.plugin = new WebConsolePlugin(bundleContext, this);
     }
 
     @Deactivate
@@ -114,6 +139,23 @@ public class TenantProviderImpl implemen
             this.adapterFactory.dispose();
             this.adapterFactory = null;
         }
+
+        if (this.plugin != null) {
+            this.plugin.dispose();
+            this.plugin = null;
+        }
+    }
+
+    private synchronized void bindTenantSetup(TenantCustomizer action, 
Map<String, Object> config) {
+        
registeredTenantHandlers.put(ServiceUtil.getComparableForServiceRanking(config),
 action);
+    }
+
+    private synchronized void unbindTenantSetup(TenantCustomizer action, 
Map<String, Object> config) {
+        
registeredTenantHandlers.remove(ServiceUtil.getComparableForServiceRanking(config));
+    }
+
+    private synchronized Collection<TenantCustomizer> getTenantHandlers() {
+        return registeredTenantHandlers.values();
     }
 
     public Tenant getTenant(String tenantId) {
@@ -145,13 +187,15 @@ public class TenantProviderImpl implemen
             try {
                 Resource tenantRootRes = 
adminResolver.getResource(tenantRootPath);
 
-                List<Tenant> tenantList = new ArrayList<Tenant>();
-                Iterator<Resource> tenantResourceList = 
tenantRootRes.listChildren();
-                while (tenantResourceList.hasNext()) {
-                    Resource tenantRes = tenantResourceList.next();
-                    tenantList.add(new TenantImpl(tenantRes));
+                if (tenantRootRes != null) {
+                    List<Tenant> tenantList = new ArrayList<Tenant>();
+                    Iterator<Resource> tenantResourceList = 
tenantRootRes.listChildren();
+                    while (tenantResourceList.hasNext()) {
+                        Resource tenantRes = tenantResourceList.next();
+                        tenantList.add(new TenantImpl(tenantRes));
+                    }
+                    return tenantList.iterator();
                 }
-                return tenantList.iterator();
             } finally {
                 adminResolver.close();
             }
@@ -161,11 +205,27 @@ public class TenantProviderImpl implemen
         return Collections.<Tenant> emptyList().iterator();
     }
 
-    public Tenant addTenant(String name, String tenantId) throws 
PersistenceException {
+    /**
+     * Creates a new tenant (not exposed as part of the api)
+     *
+     * @param name
+     * @param tenantId
+     * @param description
+     * @return
+     * @throws PersistenceException
+     */
+    public Tenant addTenant(String name, String tenantId, String description) 
throws PersistenceException {
         final ResourceResolver adminResolver = getAdminResolver();
         if (adminResolver != null) {
             try {
                 Resource tenantRootRes = 
adminResolver.getResource(tenantRootPath);
+                Session adminSession = adminResolver.adaptTo(Session.class);
+
+                if (tenantRootRes == null) {
+                    // create the root path
+                    JcrUtils.getOrCreateByPath(tenantRootPath, null, 
adminSession);
+                    tenantRootRes = adminResolver.getResource(tenantRootPath);
+                }
 
                 // check if tenantId already exists
                 Resource child = tenantRootRes.getChild(tenantId);
@@ -177,8 +237,27 @@ public class TenantProviderImpl implemen
                     Node rootNode = tenantRootRes.adaptTo(Node.class);
                     Node tenantNode = rootNode.addNode(tenantId);
                     tenantNode.setProperty(Tenant.PROP_NAME, name);
-                    adminResolver.adaptTo(Session.class).save();
-                    return new 
TenantImpl(adminResolver.getResource(tenantNode.getPath()));
+                    tenantNode.setProperty(Tenant.PROP_DESCRIPTION, 
description);
+
+                    Resource resource = 
adminResolver.getResource(tenantNode.getPath());
+                    Tenant tenant = new TenantImpl(resource);
+                    PersistableValueMap tenantProps = 
resource.adaptTo(PersistableValueMap.class);
+                    // call tenant setup handler
+                    for (TenantCustomizer ts : getTenantHandlers()) {
+                        Map<String, Object> props = ts.setup(tenant, 
adminResolver);
+                        if (props != null) {
+                            tenantProps.putAll(props);
+                        }
+                    }
+                    // save the properties
+                    tenantProps.save();
+
+                    // save the session
+                    adminSession.save();
+                    // refersh tenant instance, as it copies property from
+                    // resource
+                    tenant = new TenantImpl(resource);
+                    return tenant;
                 }
             } catch (RepositoryException e) {
                 throw new PersistenceException("Unexpected RepositoryException 
while adding tenant", e);
@@ -190,6 +269,51 @@ public class TenantProviderImpl implemen
         throw new PersistenceException("Cannot create the tenant");
     }
 
+    /**
+     * Removes the tenant (not exposed as part of the api)
+     *
+     * @param tenantId tenant identifier
+     * @return
+     * @throws PersistenceException
+     */
+    public void removeTenant(String tenantId) throws PersistenceException {
+        final ResourceResolver adminResolver = getAdminResolver();
+        if (adminResolver != null) {
+            try {
+                Resource tenantRootRes = 
adminResolver.getResource(tenantRootPath);
+
+                if (tenantRootRes == null) {
+                    // if tenant home is null just return
+                    return;
+                }
+
+                // check if tenantId already exists
+                Resource tenantRes = tenantRootRes.getChild(tenantId);
+
+                if (tenantRes != null) {
+                    Node tenantNode = tenantRes.adaptTo(Node.class);
+                    Tenant tenant = new TenantImpl(tenantRes);
+                    // call tenant setup handler
+                    for (TenantCustomizer ts : getTenantHandlers()) {
+                        ts.remove(tenant, adminResolver);
+                    }
+
+                    tenantNode.remove();
+                    adminResolver.adaptTo(Session.class).save();
+                    return;
+                }
+                // if there was no tenant found, just return
+                return;
+            } catch (RepositoryException e) {
+                throw new PersistenceException("Unexpected RepositoryException 
while removing tenant", e);
+            } finally {
+                adminResolver.close();
+            }
+        }
+
+        throw new PersistenceException("Cannot remove the tenant");
+    }
+
     public Iterator<Tenant> getTenants(String tenantFilter) {
         if (StringUtils.isBlank(tenantFilter)) {
             return null;

Added: 
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java?rev=1415151&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java
 (added)
+++ 
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java
 Thu Nov 29 13:14:21 2012
@@ -0,0 +1,197 @@
+/*
+ * 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.internal.console;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.servlet.Servlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.tenant.Tenant;
+import org.apache.sling.tenant.internal.TenantProviderImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * This is a webconsole plugin displaying the active queues, some statistics 
and
+ * the configurations.
+ */
+public class WebConsolePlugin extends HttpServlet {
+
+    private static final long serialVersionUID = -6983227434841706385L;
+
+    private static final String LABEL = "tenants";
+
+    private static final String TITLE = "Tenant Administration";
+
+    private static final String CATEGORY = "Sling";
+
+    /** tenant name parameter */
+    private static final String REQ_PRM_TENANT_NAME = "tenantName";
+
+    /** tenant id parameter */
+    private static final String REQ_PRM_TENANT_ID = "tenantId";
+
+    /** tenant description parameter */
+    private static final String REQ_PRM_TENANT_DESC = "tenantDesc";
+
+    private TenantProviderImpl tenantProvider;
+
+    private final ServiceRegistration<?> service;
+
+    /** Escape the output for html. */
+    private String escape(final String text) {
+        if (text == null) {
+            return "";
+        }
+        return text.replace("&", "&amp;").replace("<", "&lt;").replace(">", 
"&gt;");
+    }
+
+    public WebConsolePlugin(final BundleContext bundleContext, final 
TenantProviderImpl tenantProvider) {
+        this.tenantProvider = tenantProvider;
+
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Tenant 
Management Console");
+        props.put("felix.webconsole.label", LABEL);
+        props.put("felix.webconsole.title", TITLE);
+        props.put("felix.webconsole.category", CATEGORY);
+        // props.put("felix.webconsole.configprinter.modes", new 
String[]{"zip",
+        // "txt"});
+
+        this.service = 
bundleContext.registerService(Servlet.class.getCanonicalName(), this, props);
+    }
+
+    public void dispose() {
+        if (this.service != null) {
+            this.service.unregister();
+        }
+    }
+
+    @Override
+    protected void doPost(final HttpServletRequest req, final 
HttpServletResponse resp) throws IOException {
+        String msg = null;
+        final String cmd = req.getParameter("action");
+        if ("create".equals(cmd)) {
+            try {
+                Tenant t = this.createTenant(req);
+                msg = String.format("Created Tenant %s (%s)", t.getName(), 
t.getDescription());
+            } catch (PersistenceException pe) {
+                msg = "Cannot create tenant: " + pe.getMessage();
+            }
+        } else if ("remove".equals(cmd)) {
+            this.removeTenant(req);
+        } else {
+            msg = "Unknown command";
+        }
+
+        final String path = LABEL;
+        final String redirectTo;
+        if (msg == null) {
+            redirectTo = path;
+        } else {
+            redirectTo = path + "?message=" + msg;
+        }
+
+        resp.sendRedirect(redirectTo);
+    }
+
+    private void removeTenant(HttpServletRequest request) throws 
PersistenceException {
+        String tenantId = request.getParameter(REQ_PRM_TENANT_ID);
+        tenantProvider.removeTenant(tenantId);
+    }
+
+    private void printForm(final PrintWriter pw, final Tenant t, final String 
buttonLabel, final String cmd) {
+        pw.printf("<button class='ui-state-default ui-corner-all' 
onclick='javascript:cmdsubmit(\"%s\", \"%s\");'>"
+            + "%s</button>", cmd, (t != null ? t.getId() : ""), buttonLabel);
+    }
+
+    private Tenant createTenant(HttpServletRequest request) throws 
PersistenceException {
+        String tenantName = request.getParameter(REQ_PRM_TENANT_NAME);
+        String tenantId = request.getParameter(REQ_PRM_TENANT_ID);
+        String tenantDesc = request.getParameter(REQ_PRM_TENANT_DESC);
+
+        return tenantProvider.addTenant(tenantName, tenantId, tenantDesc);
+    }
+
+    @Override
+    protected void doGet(final HttpServletRequest req, final 
HttpServletResponse res) throws IOException {
+        final PrintWriter pw = res.getWriter();
+
+        pw.println("<form method='POST' name='cmd'>" + "<input type='hidden' 
name='action' value=''/>"
+            + "<input type='hidden' name='tenantId' value=''/>" + "</form>");
+        pw.println("<script type='text/javascript'>");
+        pw.println("function cmdsubmit(action, tenantId) {" + " 
document.forms['cmd'].action.value = action;"
+            + " document.forms['cmd'].tenantId.value = tenantId;" + " 
document.forms['cmd'].submit();" + "} "
+            + "function createsubmit() {" + " 
document.forms['editorForm'].submit();" + "} " + "</script>");
+        pw.printf("<p class='statline ui-state-highlight'>Apache Sling Tenant 
Support</p>");
+
+        pw.println("<div class='ui-widget-header ui-corner-top buttonGroup'>");
+        pw.println("<span style='float: left; margin-left: 1em'>Add New Tenant 
</span>");
+        pw.println("<button class='ui-state-default ui-corner-all' 
onclick='javascript:createsubmit();'> Create </button></div></td></tr>");
+        pw.println("</div>");
+        pw.println("<table id='editortable' class='nicetable'><tbody>");
+
+        pw.println("<tr width='100%'><td colspan='2'><form id='editorForm' 
method='POST'>");
+        pw.println("<input name='action' type='hidden' value='create' 
class='ui-state-default ui-corner-all'>");
+        pw.println("<table border='0' width='100%'><tbody>");
+        pw.println("<tr><td style='width: 30%;'>Identifier</td><td>");
+        pw.println("<div><input name='tenantId' type='text' value=''></div>");
+        pw.println("</td></tr>");
+        pw.println("<tr><td style='width: 30%;'>Name</td><td>");
+        pw.println("<div><input name='tenantName' type='text' 
value=''></div>");
+        pw.println("</td></tr>");
+        pw.println("<tr><td style='width: 30%;'>Description</td><td>");
+        pw.println("<div><input name='tenantDesc' type='text' 
value=''></div>");
+        pw.println("</td></tr>");
+        pw.println("</tbody></table></form>");
+        pw.println("</tbody></table>");
+
+        Iterator<Tenant> tenants = this.tenantProvider.getTenants();
+        int count = 0;
+        while (tenants.hasNext()) {
+            count++;
+            Tenant tenant = tenants.next();
+            if (count == 1) {
+                pw.printf("<p class='statline ui-state-highlight'>Registered 
Tenants</p>");
+            }
+            pw.println("<div class='ui-widget-header ui-corner-top 
buttonGroup'>");
+            pw.printf("<span style='float: left; margin-left: 1em'>Tenant : %s 
</span>", escape(tenant.getName()));
+            this.printForm(pw, tenant, "Remove", "remove");
+            pw.println("</div>");
+            pw.println("<table class='nicetable'><tbody>");
+
+            pw.printf("<tr><td style='width: 
30%%;'>Identifier</td><td>%s</td></tr>", escape(tenant.getId()));
+            pw.printf("<tr><td style='width: 
30%%;'>Name</td><td>%s</td></tr>", escape(tenant.getName()));
+            pw.printf("<tr><td style='width: 
30%%;'>Description</td><td>%s</td></tr>", escape(tenant.getDescription()));
+            pw.println("</tbody></table>");
+        }
+        // no existing tenants
+        if (count == 0) {
+            pw.printf("<p class='statline ui-state-highlight'>There are not 
registered tenants</p>");
+        }
+    }
+}

Added: 
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/spi/TenantCustomizer.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/spi/TenantCustomizer.java?rev=1415151&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/spi/TenantCustomizer.java
 (added)
+++ 
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/spi/TenantCustomizer.java
 Thu Nov 29 13:14:21 2012
@@ -0,0 +1,71 @@
+/*
+ * 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.api.resource.ResourceResolver;
+import org.apache.sling.tenant.Tenant;
+
+/**
+ * This is a service interface which services are called by the WebConsole
+ * plugin (or admin tool) to complete the Tenant setup.
+ */
+public interface TenantCustomizer {
+
+    /**
+     * Method called to create or update the given tenant. The method may 
return
+     * additional properties to be added to the Tenant's property list. The
+     * ResourceResolver allows for access to the persistence.
+     * <p>
+     * The {@code ResourceResolver.commit} method must not be called by this
+     * method.
+     * <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
+     * @param resolver The {@code ResourceResolver} providing access to the
+     *            persistence for further setup. Note, that this
+     *            {@code resolver} will have administrative privileges.
+     * @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.
+     */
+    public Map<String, Object> setup(Tenant tenant, ResourceResolver resolver);
+
+    /**
+     * Called to remove the setup for the given Tenant. This reverts all 
changes
+     * done by the #setup method. The ResourceResolver allows for access to the
+     * persistence.
+     * <p>
+     * The {@code ResourceResolver.commit} method must not be called by this
+     * 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
+     * @param resolver The {@code ResourceResolver} providing access to the
+     *            persistence for further cleanup. Note, that this
+     *            {@code resolver} will have administrative privileges.
+     */
+    public void remove(Tenant tenant, ResourceResolver resolver);
+}

Added: 
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/spi/package-info.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/spi/package-info.java?rev=1415151&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/spi/package-info.java
 (added)
+++ 
sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/spi/package-info.java
 Thu Nov 29 13:14:21 2012
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+@Version("1.0")
+package org.apache.sling.tenant.spi;
+
+import aQute.bnd.annotation.Version;
+


Reply via email to