blob: 1aa591a7b66fc4d3dc2d47593bcf49fd3425bfa0 [file] [log] [blame]
/*
* 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.testing.mock.sling;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.spi.resource.provider.ResourceProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
* Wraps the ResourceResolverFactory from ResourceResolverMock to add a service tracker
* for ResourceProvider (e.g. injected by ContentLoader for mounting filesystem folders).
*/
class RRMockResourceResolverFactoryWrapper implements ResourceResolverFactory,
ServiceTrackerCustomizer<ResourceProvider, ResourceProvider> {
private final ResourceResolverFactory delegate;
private final BundleContext bundleContext;
private final ServiceTracker<ResourceProvider, ResourceProvider> serviceTracker;
private final ConcurrentMap<String, ResourceProvider> resourceProviders = new ConcurrentHashMap<>();
@SuppressWarnings("null")
RRMockResourceResolverFactoryWrapper(ResourceResolverFactory delegate, BundleContext bundleContext) {
this.delegate = delegate;
this.bundleContext = bundleContext;
// track registered resource provider implementations
this.serviceTracker = new ServiceTracker<ResourceProvider, ResourceProvider>(bundleContext, ResourceProvider.class, this);
this.serviceTracker.open();
}
@Override
public @NotNull ResourceResolver getResourceResolver(Map<String, Object> authenticationInfo) throws LoginException {
return wrap(delegate.getResourceResolver(authenticationInfo));
}
@Override
@Deprecated
public @NotNull ResourceResolver getAdministrativeResourceResolver(Map<String, Object> authenticationInfo) throws LoginException {
return wrap(delegate.getAdministrativeResourceResolver(authenticationInfo));
}
@Override
public @NotNull ResourceResolver getServiceResourceResolver(Map<String, Object> authenticationInfo) throws LoginException {
return wrap(delegate.getServiceResourceResolver(authenticationInfo));
}
@Override
public @Nullable ResourceResolver getThreadResourceResolver() {
return wrap(delegate.getThreadResourceResolver());
}
private ResourceResolver wrap(ResourceResolver resourceResolver) {
return new RRMockResourceResolverWrapper(resourceResolver, resourceProviders);
}
@Override
public ResourceProvider addingService(ServiceReference<ResourceProvider> reference) {
String rootPath = getRootPath(reference);
ResourceProvider service = bundleContext.getService(reference);
if (rootPath != null) {
resourceProviders.put(rootPath, service);
}
return service;
}
@Override
public void modifiedService(ServiceReference<ResourceProvider> reference, ResourceProvider service) {
// ignore
}
@Override
public void removedService(ServiceReference<ResourceProvider> reference, ResourceProvider service) {
String rootPath = getRootPath(reference);
if (rootPath != null) {
resourceProviders.remove(rootPath);
}
}
private String getRootPath(ServiceReference<ResourceProvider> reference) {
Object value = reference.getProperty(ResourceProvider.PROPERTY_ROOT);
if (value instanceof String) {
return (String)value;
}
return null;
}
@SuppressWarnings("unchecked")
public @NotNull List<String> getSearchPath() {
// call delegate method via reflection, as it is not available in earlier versions of Sling API
try {
Method getSearchPathMethod = ResourceResolverFactory.class.getMethod("getSearchPath");
return (List)getSearchPathMethod.invoke(delegate);
}
catch (NoSuchMethodException | SecurityException ex) {
// earlier version of Sling API - return empty list
return Collections.emptyList();
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
throw new RuntimeException("Unable to call getSearchPath on delegate.", ex);
}
}
}