/* | |
* 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.Dictionary; | |
import java.util.Hashtable; | |
import java.util.List; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
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; | |
/** | |
* Resource based tenant adapter factory, that adapts <code>ResourceResolver</code> | |
* and <code>Resource</code> to <code>Tenant</code>. | |
* | |
* 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> RESOURCERESOLVER_CLASS = ResourceResolver.class; | |
private static final Class<Resource> RESOURCE_CLASS = Resource.class; | |
private static final Class<Tenant> TENANT_CLASS = Tenant.class; | |
private final TenantProviderImpl tenantProvider; | |
private final ServiceRegistration<?> service; | |
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 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> AdapterType getAdapter(Object adaptable, | |
Class<AdapterType> 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> AdapterType getAdapter(Session session, | |
Class<AdapterType> type) { | |
if ( session != null ) { | |
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> AdapterType getAdapter(String path, | |
Class<AdapterType> type) { | |
if (type == TENANT_CLASS) { | |
Tenant tenant = resolveTenantByPath(path); | |
if (tenant != null) { | |
return (AdapterType) tenant; | |
} | |
} | |
log.debug("Unable to adapt to resource of type {}", type.getName()); | |
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; | |
} | |
} |