You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:16:45 UTC
[sling-org-apache-sling-tenant] 11/18: SLING-2710 Define
TenantManager API
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.tenant-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-tenant.git
commit 9308e05d6cdbf94f99dbdaf00a9d7f53c517645e
Author: Felix Meschberger <fm...@apache.org>
AuthorDate: Fri Mar 1 08:04:08 2013 +0000
SLING-2710 Define TenantManager API
- Add service interface as a provider type
(not to be implemented by consumers)
- Implement TenantManager in the TenantProviderImpl
- Use latest Repository API to leverage repository CRUD
- Move tenant resolution for the AdapterFactory to the
TenantAdapterFactory (just handing the configuration
over on construction).
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/tenant@1451514 13f79535-47bb-0310-9956-ffa450edef68
---
pom.xml | 10 +-
.../org/apache/sling/tenant/TenantManager.java | 131 +++++++
.../tenant/internal/TenantAdapterFactory.java | 31 +-
.../sling/tenant/internal/TenantProviderImpl.java | 412 +++++++++++----------
.../tenant/internal/console/WebConsolePlugin.java | 36 +-
5 files changed, 396 insertions(+), 224 deletions(-)
diff --git a/pom.xml b/pom.xml
index 7b1c7d8..2554d0f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -82,7 +82,7 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
- <version>2.2.0</version>
+ <version>2.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -104,15 +104,9 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
- <version>4.3.1</version>
+ <version>4.3.1</version><!--$NO-MVN-MAN-VER$-->
<scope>provided</scope>
</dependency>
<dependency>
diff --git a/src/main/java/org/apache/sling/tenant/TenantManager.java b/src/main/java/org/apache/sling/tenant/TenantManager.java
new file mode 100644
index 0000000..23b1c1a
--- /dev/null
+++ b/src/main/java/org/apache/sling/tenant/TenantManager.java
@@ -0,0 +1,131 @@
+/*
+ * 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;
+
+import java.util.Map;
+
+import aQute.bnd.annotation.ProviderType;
+
+/**
+ * The <code>TenantManager</code> service interface defines the API that
+ * administrative tools will use to created, update or remove Tenants.
+ * <p>
+ * The implementation will make use of
+ * {@link org.apache.sling.tenant.spi.TenantCustomizer} services to customize
+ * management of tenants.
+ * <p>
+ * Tenant properties can be created, modified, and removed with the
+ * {@link #setProperty(Tenant, String, Object)},
+ * {@link #setProperties(Tenant, Map)} and
+ * {@link #removeProperties(Tenant, String...)} methods. Please note that every
+ * call to any of these methods causes the
+ * {@link org.apache.sling.tenant.spi.TenantCustomizer} services to be called.
+ * To limit these calls for multiple changes the
+ * {@link #setProperties(Tenant, Map)} method should be called.
+ */
+@ProviderType
+public interface TenantManager {
+
+ /**
+ * Creates a new tenant with the given tenant ID and the initial set of
+ * properties.
+ * <p>
+ * After creating the tenant, the
+ * {@link org.apache.sling.tenant.spi.TenantCustomizer#setup(Tenant, org.apache.sling.api.resource.ResourceResolver)}
+ * method is called to allow customizers to configure additional properties.
+ * <p>
+ * Before returning the newly created tenant object the data is persisted.
+ *
+ * @param tenantId The name of the new tenant. This name must not be
+ * {@code null} or an empty string. It must also not be the same
+ * name as that of an existing tenant.
+ * @param properties An optional map of initial properties. This may be
+ * {@code null} to not preset any properties. It is recommended,
+ * though, that this map contain at least the
+ * {@link Tenant#PROP_NAME} and {@link Tenant#PROP_DESCRIPTION}
+ * properties.
+ * @return The newly created {@link Tenant} instance.
+ * @throws NullPointerException if {@code tenantId} is {@code null}.
+ * @throws IllegalArgumentException if a tenant with the same
+ * {@code tentantId} already exists.
+ */
+ Tenant create(String tenantId, Map<String, Object> properties);
+
+ /**
+ * Sets a single property of the tenant to a new value or removes the
+ * 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)}
+ * method is called to allow customizers to configure additional properties.
+ *
+ * @param tenant The tenant whose property is to be set or remove.
+ * @param name The name of the property to set or remove.
+ * @param value The new value of the property. If this value is {@code null}
+ * the property is actually removed.
+ * @throws NullPointerException if {@code tenant} or {@code name} is
+ * {@code null}.
+ */
+ void setProperty(Tenant tenant, String name, Object value);
+
+ /**
+ * 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)}
+ * method is called to allow customizers to configure additional properties.
+ *
+ * @param tenant The tenant whose properties are to be modified.
+ * @param properties The map of properties to set or remove. A property
+ * whose value is {@code null} is removed from the tenant.
+ * @throws NullPointerException if {@code tenant} or {@code properties} is
+ * {@code null}.
+ */
+ void setProperties(Tenant tenant, Map<String, Object> properties);
+
+ /**
+ * 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)}
+ * method is called to allow customizers to configure additional properties
+ * unless the {@code properties} parameter is {@code null} or empty.
+ *
+ * @param tenant The tenant from which to remove properties.
+ * @param properties The list of properties to be removed. If this is
+ * {@code null} or empty, nothing happens and the
+ * {@link org.apache.sling.tenant.spi.TenantCustomizer} is not
+ * called.
+ * @throws NullPointerException if {@code tenant} is {@code null}.
+ */
+ void removeProperties(Tenant tenant, String... propertyNames);
+
+ /**
+ * Removes the given tenant.
+ * <p>
+ * Before returning the
+ * {@link org.apache.sling.tenant.spi.TenantCustomizer#remove(Tenant, org.apache.sling.api.resource.ResourceResolver)}
+ * method is called to allow customizers to implement further cleanup upon
+ * tenant removal.
+ *
+ * @param tenant The tenant to remove.
+ * @throws NullPointerException if {@code tenant} is {@code null}
+ */
+ void remove(Tenant tenant);
+}
diff --git a/src/main/java/org/apache/sling/tenant/internal/TenantAdapterFactory.java b/src/main/java/org/apache/sling/tenant/internal/TenantAdapterFactory.java
index 4b364c7..691f956 100644
--- a/src/main/java/org/apache/sling/tenant/internal/TenantAdapterFactory.java
+++ b/src/main/java/org/apache/sling/tenant/internal/TenantAdapterFactory.java
@@ -18,8 +18,12 @@
*/
package org.apache.sling.tenant.internal;
+import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.jcr.Session;
@@ -57,9 +61,16 @@ class TenantAdapterFactory implements AdapterFactory {
private final ServiceRegistration<?> service;
- TenantAdapterFactory(final BundleContext bundleContext, final TenantProviderImpl tenantProvider) {
+ private final List<Pattern> pathPatterns;
+
+ TenantAdapterFactory(final BundleContext bundleContext, final TenantProviderImpl tenantProvider, final String[] pathMatchers) {
this.tenantProvider = tenantProvider;
+ this.pathPatterns = new ArrayList<Pattern>();
+ for (String matcherStr : pathMatchers) {
+ this.pathPatterns.add(Pattern.compile(matcherStr));
+ }
+
Dictionary<String, Object> props = new Hashtable<String, Object>();
props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling JCR Tenant Adapter");
props.put(AdapterFactory.ADAPTER_CLASSES, new String[]{ TENANT_CLASS.getName() });
@@ -124,7 +135,7 @@ class TenantAdapterFactory implements AdapterFactory {
private <AdapterType> AdapterType getAdapter(String path,
Class<AdapterType> type) {
if (type == TENANT_CLASS) {
- Tenant tenant = tenantProvider.resolveTenantByPath(path);
+ Tenant tenant = resolveTenantByPath(path);
if (tenant != null) {
return (AdapterType) tenant;
@@ -135,4 +146,20 @@ class TenantAdapterFactory implements AdapterFactory {
return null;
}
+ private Tenant resolveTenantByPath(String path) {
+ // find matching path identifier
+ for (Pattern pathPattern : pathPatterns) {
+ Matcher matcher = pathPattern.matcher(path);
+ if (matcher.find()) {
+ // assuming that first group is tenantId in the path, we can
+ // make group number configurable.
+ if (matcher.groupCount() >= 1) {
+ String tenantId = matcher.group(1);
+ return this.tenantProvider.getTenant(tenantId);
+ }
+ }
+ }
+ return null;
+ }
+
}
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 a45b83f..cc4d3cc 100644
--- a/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java
+++ b/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java
@@ -21,19 +21,13 @@ package org.apache.sling.tenant.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -44,18 +38,17 @@ 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.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
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.TenantManager;
import org.apache.sling.tenant.TenantProvider;
import org.apache.sling.tenant.internal.console.WebConsolePlugin;
import org.apache.sling.tenant.spi.TenantCustomizer;
@@ -84,7 +77,7 @@ import org.slf4j.LoggerFactory;
referenceInterface = TenantCustomizer.class,
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
policy = ReferencePolicy.DYNAMIC)
-public class TenantProviderImpl implements TenantProvider {
+public class TenantProviderImpl implements TenantProvider, TenantManager {
/** default log */
private final Logger log = LoggerFactory.getLogger(getClass());
@@ -109,10 +102,6 @@ public class TenantProviderImpl implements TenantProvider {
description = "Defines tenants path matcher i.e. /content/sample/([^/]+)/*, used while resolving path to tenant")
private static final String TENANT_PATH_MATCHER = "tenant.path.matcher";
- private String[] pathMatchers;
-
- private List<Pattern> pathPatterns = new ArrayList<Pattern>();
-
private String tenantRootPath = JCR_TENANT_ROOT;
@Reference
@@ -122,20 +111,10 @@ public class TenantProviderImpl implements TenantProvider {
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) {
- this.pathPatterns.add(Pattern.compile(matcherStr));
- }
-
- this.adapterFactory = new TenantAdapterFactory(bundleContext, this);
+ this.adapterFactory = new TenantAdapterFactory(bundleContext, this, PropertiesUtil.toStringArray(properties.get(TENANT_PATH_MATCHER), DEFAULT_PATH_MATCHER));
this.plugin = new WebConsolePlugin(bundleContext, this);
}
@@ -152,10 +131,12 @@ public class TenantProviderImpl implements TenantProvider {
}
}
+ @SuppressWarnings("unused")
private synchronized void bindTenantSetup(TenantCustomizer action, Map<String, Object> config) {
registeredTenantHandlers.put(ServiceUtil.getComparableForServiceRanking(config), action);
}
+ @SuppressWarnings("unused")
private synchronized void unbindTenantSetup(TenantCustomizer action, Map<String, Object> config) {
registeredTenantHandlers.remove(ServiceUtil.getComparableForServiceRanking(config));
}
@@ -164,23 +145,14 @@ public class TenantProviderImpl implements TenantProvider {
return registeredTenantHandlers.values();
}
- public Tenant getTenant(String tenantId) {
- if (StringUtils.isBlank(tenantId)) {
- return null;
- }
-
- final ResourceResolver adminResolver = getAdminResolver();
- if (adminResolver != null) {
- try {
- Resource tenantRootRes = adminResolver.getResource(tenantRootPath);
-
- Resource tenantRes = tenantRootRes.getChild(tenantId);
- if (tenantRes != null) {
- return new TenantImpl(tenantRes);
+ public Tenant getTenant(final String tenantId) {
+ if (tenantId != null && tenantId.length() > 0) {
+ return call(new ResourceResolverTask<Tenant>() {
+ public Tenant call(ResourceResolver resolver) {
+ Resource tenantRes = getTenantResource(resolver, tenantId);
+ return (tenantRes != null) ? new TenantImpl(tenantRes) : null;
}
- } finally {
- adminResolver.close();
- }
+ });
}
// in case of some problem
@@ -188,208 +160,246 @@ public class TenantProviderImpl implements TenantProvider {
}
public Iterator<Tenant> getTenants() {
- final ResourceResolver adminResolver = getAdminResolver();
- if (adminResolver != null) {
+ return getTenants(null);
+ }
+
+ public Iterator<Tenant> getTenants(final String tenantFilter) {
+ final Filter filter;
+ if (tenantFilter != null && tenantFilter.length() > 0) {
try {
- Resource tenantRootRes = adminResolver.getResource(tenantRootPath);
-
- 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();
- }
- } finally {
- adminResolver.close();
+ filter = FrameworkUtil.createFilter(tenantFilter);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(e.getMessage(), e);
}
+ } else {
+ filter = null;
}
- // in case of some problem return an empty iterator
- return Collections.<Tenant> emptyList().iterator();
- }
+ Iterator<Tenant> result = call(new ResourceResolverTask<Iterator<Tenant>>() {
+ public Iterator<Tenant> call(ResourceResolver resolver) {
+ Resource tenantRootRes = resolver.getResource(tenantRootPath);
- /**
- * 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);
+ List<Tenant> tenantList = new ArrayList<Tenant>();
+ Iterator<Resource> tenantResourceList = tenantRootRes.listChildren();
+ while (tenantResourceList.hasNext()) {
+ Resource tenantRes = tenantResourceList.next();
- if (tenantRootRes == null) {
- // create the root path
- JcrUtils.getOrCreateByPath(tenantRootPath, null, adminSession);
- tenantRootRes = adminResolver.getResource(tenantRootPath);
+ if (filter == null || filter.matches(ResourceUtil.getValueMap(tenantRes))) {
+ TenantImpl tenant = new TenantImpl(tenantRes);
+ tenantList.add(tenant);
+ }
}
+ return tenantList.iterator();
+ }
+ });
- // check if tenantId already exists
- Resource child = tenantRootRes.getChild(tenantId);
+ if (result == null) {
+ // no filter or no resource resolver for calling
+ result = Collections.<Tenant> emptyList().iterator();
+ }
+
+ return result;
+ }
- if (child != null) {
- throw new PersistenceException("Tenant already exists with Id " + tenantId);
+ public Tenant create(final String tenantId, final Map<String, Object> properties) {
+ return call(new ResourceResolverTask<Tenant>() {
+ public Tenant call(ResourceResolver adminResolver) {
+ try {
+ // create the tenant
+ Resource tenantRes = createTenantResource(adminResolver, tenantId, properties);
+ TenantImpl tenant = new TenantImpl(tenantRes);
+ customizeTenant(tenantRes, tenant);
+ adminResolver.commit();
+
+ // refresh tenant instance, as it copies property from
+ // resource
+ tenant.loadProperties(tenantRes);
+
+ return tenant;
+
+ } catch (PersistenceException e) {
+ log.error("create: Failed creating Tenant {}", tenantId, e);
+ } finally {
+ adminResolver.close();
}
- // create the tenant
- Node rootNode = tenantRootRes.adaptTo(Node.class);
- Node tenantNode = rootNode.addNode(tenantId);
- tenantNode.setProperty(Tenant.PROP_NAME, name);
- 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()) {
- try {
- Map<String, Object> props = ts.setup(tenant, adminResolver);
- if (props != null) {
- tenantProps.putAll(props);
+ // no new tenant in case of problems
+ return null;
+ }
+ });
+ }
+
+ public void remove(final Tenant tenant) {
+ call(new ResourceResolverTask<Void>() {
+ public Void call(ResourceResolver resolver) {
+ try {
+ Resource tenantRes = getTenantResource(resolver, tenant.getId());
+ if (tenantRes != null) {
+ // call tenant setup handler
+ for (TenantCustomizer ts : getTenantHandlers()) {
+ try {
+ ts.remove(tenant, resolver);
+ } catch (Exception e) {
+ log.info("removeTenant: Unexpected problem calling TenantCustomizer " + ts, e);
+ }
}
- } catch (Exception e) {
- log.info("addTenant: Unexpected problem calling TenantCustomizer " + ts, e);
+
+ resolver.delete(tenantRes);
+ resolver.commit();
}
+ } catch (PersistenceException e) {
+ log.error("remove({}): Cannot persist Tenant removal", tenant.getId(), e);
}
- // 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);
- } finally {
- adminResolver.close();
- }
- }
- throw new PersistenceException("Cannot create the tenant");
+ return null;
+ }
+ });
}
- /**
- * 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;
+ public void setProperty(final Tenant tenant, final String name, final Object value) {
+ updateProperties(tenant, new PropertiesUpdater() {
+ public void update(ModifiableValueMap properties) {
+ if (value != null) {
+ properties.put(name, value);
+ } else {
+ properties.remove(name);
}
+ }
+ });
+ }
- // 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()) {
- try {
- ts.remove(tenant, adminResolver);
- } catch (Exception e) {
- log.info("removeTenant: Unexpected problem calling TenantCustomizer " + ts, e);
- }
+ public void setProperties(final Tenant tenant, final Map<String, Object> properties) {
+ updateProperties(tenant, new PropertiesUpdater() {
+ public void update(ModifiableValueMap vm) {
+ for (Entry<String, Object> entry : properties.entrySet()) {
+ if (entry.getValue() != null) {
+ vm.put(entry.getKey(), entry.getValue());
+ } else {
+ vm.remove(entry.getKey());
}
-
- 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 void removeProperties(final Tenant tenant, final String... propertyNames) {
+ updateProperties(tenant, new PropertiesUpdater() {
+ public void update(ModifiableValueMap properties) {
+ for (String name : propertyNames) {
+ properties.remove(name);
+ }
+ }
+ });
}
- public Iterator<Tenant> getTenants(String tenantFilter) {
- if (StringUtils.isBlank(tenantFilter)) {
- return null;
+ @SuppressWarnings("serial")
+ private Resource createTenantResource(final ResourceResolver resolver, final String tenantId,
+ final Map<String, Object> properties) throws PersistenceException {
+
+ // check for duplicate first
+ if (getTenantResource(resolver, tenantId) != null) {
+ throw new PersistenceException("Tenant '" + tenantId + "' already exists");
}
- final ResourceResolver adminResolver = getAdminResolver();
- if (adminResolver != null) {
- try {
- Resource tenantRootRes = adminResolver.getResource(tenantRootPath);
+ Resource tenantRoot = resolver.getResource(tenantRootPath);
- List<Tenant> tenantList = new ArrayList<Tenant>();
- Iterator<Resource> tenantResourceList = tenantRootRes.listChildren();
- while (tenantResourceList.hasNext()) {
- Resource tenantRes = tenantResourceList.next();
- ValueMap vm = ResourceUtil.getValueMap(tenantRes);
+ if (tenantRoot == null) {
+ Resource current = resolver.getResource("/");
+ if (current == null) {
+ throw new PersistenceException("Cannot get root Resource");
+ }
- Filter filter = FrameworkUtil.createFilter(tenantFilter);
- if (filter.matches(vm)) {
- TenantImpl tenant = new TenantImpl(tenantRes);
- tenantList.add(tenant);
- }
+ String[] segments = this.tenantRootPath.split("/");
+ for (String segment : segments) {
+ Resource child = current.getChild(segment);
+ if (child == null) {
+ child = resolver.create(current, segment, new HashMap<String, Object>() {
+ {
+ put("jcr:primaryType", "sling:Folder");
+ }
+ });
}
- return tenantList.iterator();
- } catch (InvalidSyntaxException e) {
- throw new IllegalArgumentException(e.getMessage(), e);
- } finally {
- adminResolver.close();
}
+
+ tenantRoot = current;
}
- // in case of some problem return an empty iterator
- return Collections.<Tenant> emptyList().iterator();
+ return resolver.create(tenantRoot, tenantId, properties);
}
- /**
- * Helper for the {@link JcrTenantAdapterFactory} to resolve any resource
- * path to a tenant.
- */
- Tenant resolveTenantByPath(String path) {
- // find matching path identifier
- for (Pattern pathPattern : pathPatterns) {
- Matcher matcher = pathPattern.matcher(path);
- if (matcher.find()) {
- // assuming that first group is tenantId in the path, we can
- // make group number configurable.
- if (matcher.groupCount() >= 1) {
- String tenantId = matcher.group(1);
- return getTenant(tenantId);
+ private Resource getTenantResource(final ResourceResolver resolver, final String tenantId) {
+ return resolver.getResource(tenantRootPath + "/" + tenantId);
+ }
+
+ private void customizeTenant(final Resource tenantRes, final Tenant tenant) {
+
+ // call tenant setup handler
+ Map<String, Object> tenantProps = tenantRes.adaptTo(ModifiableValueMap.class);
+ if (tenantProps == null) {
+ log.warn(
+ "create({}): Cannot get ModifiableValueMap for new tenant; will not store changed properties of TenantCustomizers",
+ tenant.getId());
+ tenantProps = new HashMap<String, Object>();
+ }
+
+ for (TenantCustomizer ts : getTenantHandlers()) {
+ try {
+ Map<String, Object> props = ts.setup(tenant, tenantRes.getResourceResolver());
+ if (props != null) {
+ tenantProps.putAll(props);
}
+ } catch (Exception e) {
+ log.info("addTenant: Unexpected problem calling TenantCustomizer " + ts, e);
}
}
- return null;
}
- private ResourceResolver getAdminResolver() {
+ private <T> T call(ResourceResolverTask<T> task) {
+ ResourceResolver resolver = null;
+ T result = null;
+
try {
- return factory.getAdministrativeResourceResolver(null);
+ resolver = factory.getAdministrativeResourceResolver(null);
+ result = task.call(resolver);
} catch (LoginException le) {
// unexpected, thus ignore
+ } finally {
+ if (resolver != null) {
+ resolver.close();
+ }
}
- return null;
+ return result;
+ }
+
+ private void updateProperties(final Tenant tenant, final PropertiesUpdater updater) {
+ call(new ResourceResolverTask<Void>() {
+ public Void call(ResourceResolver resolver) {
+ try {
+ Resource tenantRes = getTenantResource(resolver, tenant.getId());
+ if (tenantRes != null) {
+ updater.update(tenantRes.adaptTo(ModifiableValueMap.class));
+ customizeTenant(tenantRes, tenant);
+ resolver.commit();
+
+ if (tenant instanceof TenantImpl) {
+ ((TenantImpl) tenant).loadProperties(tenantRes);
+ }
+ }
+ } catch (PersistenceException pe) {
+ log.error("setProperty({}): Cannot persist Tenant removal", tenant.getId(), pe);
+ }
+
+ return null;
+ }
+ });
+ }
+
+ private static interface ResourceResolverTask<T> {
+ T call(ResourceResolver resolver);
+ }
+
+ private static interface PropertiesUpdater {
+ void update(ModifiableValueMap properties);
}
}
diff --git a/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java b/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java
index f3eb471..fb7871e 100644
--- a/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java
+++ b/src/main/java/org/apache/sling/tenant/internal/console/WebConsolePlugin.java
@@ -21,6 +21,7 @@ package org.apache.sling.tenant.internal.console;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Dictionary;
+import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
@@ -29,7 +30,6 @@ 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;
@@ -96,11 +96,11 @@ public class WebConsolePlugin extends HttpServlet {
String msg = null;
final String cmd = req.getParameter("action");
if ("create".equals(cmd)) {
- try {
- Tenant t = this.createTenant(req);
+ Tenant t = this.createTenant(req);
+ if (t != null) {
msg = String.format("Created Tenant %s (%s)", t.getName(), t.getDescription());
- } catch (PersistenceException pe) {
- msg = "Cannot create tenant: " + pe.getMessage();
+ } else {
+ msg = "Cannot create tenant";
}
} else if ("remove".equals(cmd)) {
this.removeTenant(req);
@@ -119,9 +119,13 @@ public class WebConsolePlugin extends HttpServlet {
resp.sendRedirect(redirectTo);
}
- private void removeTenant(HttpServletRequest request) throws PersistenceException {
- String tenantId = request.getParameter(REQ_PRM_TENANT_ID);
- tenantProvider.removeTenant(tenantId);
+ private void removeTenant(HttpServletRequest request) {
+ final String tenantId = request.getParameter(REQ_PRM_TENANT_ID);
+ final Tenant tenant = this.tenantProvider.getTenant(tenantId);
+
+ if (tenant != null) {
+ this.tenantProvider.remove(tenant);
+ }
}
private void printForm(final PrintWriter pw, final Tenant t, final String buttonLabel, final String cmd) {
@@ -129,12 +133,18 @@ public class WebConsolePlugin extends HttpServlet {
+ "%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);
+ @SuppressWarnings("serial")
+ private Tenant createTenant(HttpServletRequest request) {
+ final String tenantName = request.getParameter(REQ_PRM_TENANT_NAME);
+ final String tenantId = request.getParameter(REQ_PRM_TENANT_ID);
+ final String tenantDesc = request.getParameter(REQ_PRM_TENANT_DESC);
- return tenantProvider.addTenant(tenantName, tenantId, tenantDesc);
+ return tenantProvider.create(tenantId, new HashMap<String, Object>() {
+ {
+ put(Tenant.PROP_NAME, tenantName);
+ put(Tenant.PROP_DESCRIPTION, tenantDesc);
+ }
+ });
}
@Override
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.