Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 6DAEAD544 for ; Fri, 9 Nov 2012 22:26:33 +0000 (UTC) Received: (qmail 81314 invoked by uid 500); 9 Nov 2012 22:26:33 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 81248 invoked by uid 500); 9 Nov 2012 22:26:33 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 81241 invoked by uid 99); 9 Nov 2012 22:26:33 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 09 Nov 2012 22:26:33 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 09 Nov 2012 22:26:27 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 5C44B23888E7; Fri, 9 Nov 2012 22:26:05 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1407672 - in /sling/trunk/contrib/extensions/tenant: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/sling/ src/main/java/org/apache/sling/tenant/ src/main/java/org/apache/sling/tenant... Date: Fri, 09 Nov 2012 22:26:04 -0000 To: commits@sling.apache.org From: fmeschbe@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20121109222605.5C44B23888E7@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: fmeschbe Date: Fri Nov 9 22:26:03 2012 New Revision: 1407672 URL: http://svn.apache.org/viewvc?rev=1407672&view=rev Log: SLING-2656 Commit a first shot at Multi Tenancy Support Added: sling/trunk/contrib/extensions/tenant/ (with props) sling/trunk/contrib/extensions/tenant/pom.xml sling/trunk/contrib/extensions/tenant/src/ sling/trunk/contrib/extensions/tenant/src/main/ sling/trunk/contrib/extensions/tenant/src/main/java/ sling/trunk/contrib/extensions/tenant/src/main/java/org/ sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/ sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/ sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/ sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/Tenant.java sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/TenantProvider.java sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/ sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantAdapterFactory.java sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantImpl.java sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/package-info.java sling/trunk/contrib/extensions/tenant/src/main/resources/ sling/trunk/contrib/extensions/tenant/src/test/ sling/trunk/contrib/extensions/tenant/src/test/java/ sling/trunk/contrib/extensions/tenant/src/test/resources/ Propchange: sling/trunk/contrib/extensions/tenant/ ------------------------------------------------------------------------------ --- svn:ignore (added) +++ svn:ignore Fri Nov 9 22:26:03 2012 @@ -0,0 +1,4 @@ +.classpath +.settings +target +.project Added: sling/trunk/contrib/extensions/tenant/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tenant/pom.xml?rev=1407672&view=auto ============================================================================== --- sling/trunk/contrib/extensions/tenant/pom.xml (added) +++ sling/trunk/contrib/extensions/tenant/pom.xml Fri Nov 9 22:26:03 2012 @@ -0,0 +1,142 @@ + + + + 4.0.0 + + org.apache.sling + sling + 13 + ../../../parent/pom.xml + + + org.apache.sling.tenant + 0.0.1-SNAPSHOT + bundle + + Apache Sling Tenant + + This bundle provides the Tenant Provider Implementation and API. + + + + + scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/tenant + + + scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/tenant + + + http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tenant + + + + + + + org.apache.felix + maven-scr-plugin + + + org.apache.sling + maven-sling-plugin + + + generate-adapter-metadata + process-classes + + generate-adapter-metadata + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + + + + org.apache.felix + org.apache.felix.scr.annotations + + + org.apache.sling + org.apache.sling.api + 2.2.0 + provided + + + org.apache.sling + org.apache.sling.commons.osgi + 2.1.0 + provided + + + org.apache.jackrabbit + jackrabbit-api + 2.4.0 + provided + + + commons-lang + commons-lang + 2.0 + provided + + + org.osgi + org.osgi.core + 4.3.1 + provided + + + org.slf4j + slf4j-api + + + biz.aQute + bndlib + provided + + + + + org.apache.sling + org.apache.sling.commons.testing + 2.0.6 + test + + + org.mockito + mockito-all + 1.8.2 + test + + + junit-addons + junit-addons + 1.4 + test + + + Added: sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/Tenant.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/Tenant.java?rev=1407672&view=auto ============================================================================== --- sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/Tenant.java (added) +++ sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/Tenant.java Fri Nov 9 22:26:03 2012 @@ -0,0 +1,96 @@ +/* + * 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.Iterator; + +/** + * The Tenant interface represents a tenant which may be used to + * further customize request and other processing. + *

+ * This interface is intended to be implemented by the implementor of the + * {@link TenantProvider} interface to be returned for it tenant accessor + * methods. + */ +public interface Tenant { + + /** + * The name of the {@link #getProperty(String) property} whose string + * representation is used as this tenant's {@link #getName() name} (value is + * "sling.tenant.name"). + * + * @see #getName() + * @see #getProperty(String) + */ + String PROP_NAME = "tenant.name"; + + /** + * The name of the {@link #getProperty(String) property} whose string + * representation is used as this tenant's {@link #getDescription() + * description} (value is "sling.tenant.description"). + * + * @see #getDescription() + * @see #getProperty(String) + */ + String PROP_DESCRIPTION = "tenant.description"; + + /** + * Returns the unique identifier of this tenant. + *

+ * The tenant identifier has not predefined mapping to a property and may be + * generated automatically by the TenantProvider. + */ + String getId(); + + /** + * Returns the name of the tenant. This is a short name for quickly + * identifying this tenant. This name is not required to be globally unique. + *

+ * The name of the tenant is the string representation of the + * {@link #PROP_NAME} property. + */ + String getName(); + + /** + * Returns a human readable description of this tenant. + *

+ * The description of the tenant is the string representation of the + * {@link #PROP_DESCRIPTION} property. + */ + String getDescription(); + + /** + * Returns the named property or null if no such property + * exists or if the property value itself is null. + */ + Object getProperty(String name); + + /** + * Returns the named property converted to the requested type or + * null if the property does not exist, the property value + * itself is null or cannot be converted to the requested type. + */ + Type getProperty(String name, Type type); + + /** + * Returns an iterator or String values representing the names of defined + * properties of this tenant. + */ + Iterator getPropertyNames(); +} Added: sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/TenantProvider.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/TenantProvider.java?rev=1407672&view=auto ============================================================================== --- sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/TenantProvider.java (added) +++ sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/TenantProvider.java Fri Nov 9 22:26:03 2012 @@ -0,0 +1,60 @@ +/* + * 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.Iterator; + +import org.osgi.framework.InvalidSyntaxException; + +/** + * The TenantProvider defines the service interface of for a sevice + * which may be asked for {@link Tenant tenant instances}. + *

+ * For now this provider interface provides access to a tenant applying to a + * particular request as well as to all tenants known to this provider. + */ +public interface TenantProvider { + + /** + * Returns the {@link Tenant} with the given tenantId or + * null if no such tenant exists. + */ + Tenant getTenant(String tenantId); + + /** + * Returns an iterator of all {@link Tenant tenants} known to this provider. + * If no tenants are known the iterator is empty. + */ + Iterator getTenants(); + + /** + * Returns an iterator of {@link Tenant tenants} matching the given + * tenantFilter. + *

+ * The tenantFilter is a valid OSGi filter string as defined in + * Section 3.2.6, Filter Syntax, of the OSGi Core Specification, Release 4. + *

+ * If no tenants match the tenantFilter or the + * tenantFilter is not a valid filter string the iterator is + * empty. + * + * @throws InvalidSyntaxException if filter syntax is invalid + */ + Iterator getTenants(String tenantFilter) throws InvalidSyntaxException; +} Added: sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantAdapterFactory.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantAdapterFactory.java?rev=1407672&view=auto ============================================================================== --- sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantAdapterFactory.java (added) +++ sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantAdapterFactory.java Fri Nov 9 22:26:03 2012 @@ -0,0 +1,138 @@ +/* + * 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; + +import java.util.Dictionary; +import java.util.Hashtable; + +import javax.jcr.Session; + +import org.apache.jackrabbit.api.JackrabbitSession; +import org.apache.jackrabbit.api.security.user.Authorizable; +import org.apache.sling.api.adapter.AdapterFactory; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.tenant.Tenant; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceRegistration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * JCR based tenant adapter factory, that adapts ResourceResolver + * and Resource to Tenant. + * + * It tries to resolve the tenant based on logged in user by looking at the user + * home path i.e. /home/users/tenant1/a/admin + * + * For resource, it tries to resolve Tenant using resource path. + * + */ +class TenantAdapterFactory implements AdapterFactory { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + static final Class RESOURCERESOLVER_CLASS = ResourceResolver.class; + private static final Class RESOURCE_CLASS = Resource.class; + private static final Class TENANT_CLASS = Tenant.class; + + private final TenantProviderImpl tenantProvider; + + private final ServiceRegistration service; + + TenantAdapterFactory(final BundleContext bundleContext, final TenantProviderImpl tenantProvider) { + this.tenantProvider = tenantProvider; + + Dictionary props = new Hashtable(); + props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling JCR Tenant Adapter"); + props.put(AdapterFactory.ADAPTER_CLASSES, new String[]{ TENANT_CLASS.getName() }); + props.put(AdapterFactory.ADAPTABLE_CLASSES, new String[] { RESOURCERESOLVER_CLASS + .getName(), RESOURCE_CLASS.getName() }); + + this.service = bundleContext.registerService(AdapterFactory.SERVICE_NAME, this, props); + } + + void dispose() { + if (this.service != null) { + this.service.unregister(); + } + } + + // ---------- AdapterFactory ----------------------------------------------- + + /* + * (non-Javadoc) + * + * @see + * org.apache.sling.api.adapter.AdapterFactory#getAdapter(java.lang.Object, + * java.lang.Class) + */ + public AdapterType getAdapter(Object adaptable, + Class type) { + if (adaptable instanceof ResourceResolver) { + return getAdapter( + ((ResourceResolver) adaptable).adaptTo(Session.class), type); + } + + if (adaptable instanceof Resource) { + return getAdapter(((Resource) adaptable).getPath(), type); + } + + log.warn("Unable to handle adaptable {}", adaptable.getClass() + .getName()); + return null; + } + + private AdapterType getAdapter(Session session, + Class type) { + String userID = session.getUserID(); + + JackrabbitSession jrSession = (JackrabbitSession) session; + try { + Authorizable authorizable = jrSession.getUserManager() + .getAuthorizable(userID); + String userHome = authorizable.getPath(); + + // tries to get tenant information from user home + // i.e. /home/users/tenant1/a/admin + return getAdapter(userHome, type); + } catch (Exception e) { + log.error("can not get user from session", e); + } + log.debug("Unable to adapt to resource of type {}", type.getName()); + return null; + } + + @SuppressWarnings("unchecked") + private AdapterType getAdapter(String path, + Class type) { + if (type == TENANT_CLASS) { + Tenant tenant = tenantProvider.resolveTenantByPath(path); + + if (tenant != null) { + return (AdapterType) tenant; + } + + } + log.debug("Unable to adapt to resource of type {}", type.getName()); + return null; + } + +} Added: sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantImpl.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantImpl.java?rev=1407672&view=auto ============================================================================== --- sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantImpl.java (added) +++ sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantImpl.java Fri Nov 9 22:26:03 2012 @@ -0,0 +1,84 @@ +/* + * 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; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceUtil; +import org.apache.sling.api.resource.ValueMap; +import org.apache.sling.api.wrappers.ValueMapDecorator; +import org.apache.sling.tenant.Tenant; + +/** + * A resource backed tenant implementation. + */ +class TenantImpl implements Tenant { + private String id; + + private ValueMap vm; + + TenantImpl(Resource resource) { + this.id = resource.getName(); + // vm = ResourceUtil.getValueMap(resource); + // create local detached value map + vm = getLocalValueMap(resource); + } + + private ValueMap getLocalValueMap(Resource resource) { + ValueMap jcrVM = ResourceUtil.getValueMap(resource); + + Map localMap = new HashMap(); + // copy all items to local map + localMap.putAll(jcrVM); + + // decoarate it as value map + ValueMapDecorator localVM = new ValueMapDecorator(localMap); + + return localVM; + + } + + public String getId() { + return id; + } + + public String getName() { + return vm.get(Tenant.PROP_NAME, ""); + } + + public String getDescription() { + return vm.get(Tenant.PROP_DESCRIPTION, ""); + } + + public Object getProperty(String name) { + return vm.get(name); + } + + public Type getProperty(String name, Type type) { + return vm.get(name, type); + } + + public Iterator getPropertyNames() { + return vm.keySet().iterator(); + } + +} \ No newline at end of file Added: 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=1407672&view=auto ============================================================================== --- sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java (added) +++ sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/internal/TenantProviderImpl.java Fri Nov 9 22:26:03 2012 @@ -0,0 +1,258 @@ +/* + * 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; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +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; +import org.apache.felix.scr.annotations.Properties; +import org.apache.felix.scr.annotations.Property; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.Service; +import org.apache.sling.api.resource.LoginException; +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.tenant.Tenant; +import org.apache.sling.tenant.TenantProvider; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.Filter; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.InvalidSyntaxException; + +/** + * JCR Tenant Provider implementation. + */ +@Component( + metatype = true, + label = "Apache Sling JCR Tenant Provider", + description = "Service responsible for providing Tenants") +@Service +@Properties(value = { + @Property(name = Constants.SERVICE_DESCRIPTION, value = "Apache Sling JCR Tenant Provider") +}) +public class TenantProviderImpl implements TenantProvider { + /** + * Root path for tenant + */ + private static final String JCR_TENANT_ROOT = "/etc/tenants"; + + @Property(value = JCR_TENANT_ROOT, label = "Tenants Root Path", description = "Defines tenants root path") + private static final String TENANT_ROOT = "tenant.root"; + + private static final String[] DEFAULT_PATH_MATCHER = {}; + + @Property( + value = {}, + label = "Tenants Path Matcher", + 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 pathPatterns = new ArrayList(); + + private String tenantRootPath = JCR_TENANT_ROOT; + + @Reference + private ResourceResolverFactory factory; + + private TenantAdapterFactory adapterFactory; + + @Activate + private void activate(final BundleContext bundleContext, final Map 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.pathPatterns.clear(); + for (String matcherStr : this.pathMatchers) { + this.pathPatterns.add(Pattern.compile(matcherStr)); + } + + this.adapterFactory = new TenantAdapterFactory(bundleContext, this); + } + + @Deactivate + private void deactivate() { + if (this.adapterFactory != null) { + this.adapterFactory.dispose(); + this.adapterFactory = null; + } + } + + 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); + } + } finally { + adminResolver.close(); + } + } + + // in case of some problem + return null; + } + + public Iterator getTenants() { + final ResourceResolver adminResolver = getAdminResolver(); + if (adminResolver != null) { + try { + Resource tenantRootRes = adminResolver.getResource(tenantRootPath); + + List tenantList = new ArrayList(); + Iterator tenantResourceList = tenantRootRes.listChildren(); + while (tenantResourceList.hasNext()) { + Resource tenantRes = tenantResourceList.next(); + tenantList.add(new TenantImpl(tenantRes)); + } + return tenantList.iterator(); + } finally { + adminResolver.close(); + } + } + + // in case of some problem return an empty iterator + return Collections. emptyList().iterator(); + } + + public Tenant addTenant(String name, String tenantId) throws PersistenceException { + final ResourceResolver adminResolver = getAdminResolver(); + if (adminResolver != null) { + try { + Resource tenantRootRes = adminResolver.getResource(tenantRootPath); + + // check if tenantId already exists + Resource child = tenantRootRes.getChild(tenantId); + + if (child != null) { + throw new PersistenceException("Tenant already exists with Id " + tenantId); + } else { + // create the tenant + 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())); + } + } catch (RepositoryException e) { + throw new PersistenceException("Unexpected RepositoryException while adding tenant", e); + } finally { + adminResolver.close(); + } + } + + throw new PersistenceException("Cannot create the tenant"); + } + + public Iterator getTenants(String tenantFilter) throws InvalidSyntaxException { + if (StringUtils.isBlank(tenantFilter)) { + return null; + } + + final ResourceResolver adminResolver = getAdminResolver(); + if (adminResolver != null) { + try { + Resource tenantRootRes = adminResolver.getResource(tenantRootPath); + + List tenantList = new ArrayList(); + Iterator tenantResourceList = tenantRootRes.listChildren(); + while (tenantResourceList.hasNext()) { + Resource tenantRes = tenantResourceList.next(); + ValueMap vm = ResourceUtil.getValueMap(tenantRes); + + Filter filter = FrameworkUtil.createFilter(tenantFilter); + if (filter.matches(vm)) { + TenantImpl tenant = new TenantImpl(tenantRes); + tenantList.add(tenant); + } + } + return tenantList.iterator(); + } finally { + adminResolver.close(); + } + } + + // in case of some problem return an empty iterator + return Collections. emptyList().iterator(); + } + + /** + * 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); + } + } + } + return null; + } + + private ResourceResolver getAdminResolver() { + try { + return factory.getAdministrativeResourceResolver(null); + } catch (LoginException le) { + // unexpected, thus ignore + } + + return null; + } + + private void safeClose(ResourceResolver adminResolver) { + if (adminResolver != null) { + adminResolver.close(); + } + } +} Added: sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/package-info.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/package-info.java?rev=1407672&view=auto ============================================================================== --- sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/package-info.java (added) +++ sling/trunk/contrib/extensions/tenant/src/main/java/org/apache/sling/tenant/package-info.java Fri Nov 9 22:26:03 2012 @@ -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. + */ + +@Version("1.0") +@Export(optional = "provide:=true") +package org.apache.sling.tenant; + +import aQute.bnd.annotation.Export; +import aQute.bnd.annotation.Version; +