blob: f8600784dd2ebb27c4e73b60319b11ff68e5f063 [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.caconfig.impl;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.caconfig.spi.ConfigurationCollectionPersistData;
import org.apache.sling.caconfig.spi.ConfigurationPersistData;
import org.apache.sling.caconfig.spi.ConfigurationPersistenceStrategy;
import org.apache.sling.caconfig.spi.ConfigurationPersistenceStrategy2;
import org.apache.sling.commons.osgi.Order;
import org.apache.sling.commons.osgi.ServiceUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ReferencePolicyOption;
/**
* Bridges services implementing the deprecated {@link ConfigurationPersistenceStrategy} interface
* to the {@link ConfigurationPersistenceStrategy2} interface for backwards compatibility.
*/
@Component(reference={
@Reference(name="configurationPersistenceStrategy", service=ConfigurationPersistenceStrategy.class,
bind="bindConfigurationPersistenceStrategy", unbind="unbindConfigurationPersistenceStrategy",
cardinality=ReferenceCardinality.MULTIPLE,
policy=ReferencePolicy.DYNAMIC, policyOption=ReferencePolicyOption.GREEDY)
})
@SuppressWarnings("deprecation")
public final class ConfigurationPersistenceStrategyBridge {
private volatile BundleContext bundleContext;
private final ConcurrentMap<Comparable<Object>, ServiceRegistration<ConfigurationPersistenceStrategy2>> services = new ConcurrentHashMap<>();
private final ConcurrentMap<Comparable<Object>, ServiceInfo> preActivateServices = new ConcurrentHashMap<>();
protected void bindConfigurationPersistenceStrategy(ConfigurationPersistenceStrategy item, Map<String, Object> props) {
ServiceInfo serviceInfo = new ServiceInfo(item, props);
Comparable<Object> key = ServiceUtil.getComparableForServiceRanking(props, Order.ASCENDING);
if (bundleContext != null) {
services.put(key, registerBridgeService(serviceInfo));
}
else {
preActivateServices.put(key, serviceInfo);
}
}
protected void unbindConfigurationPersistenceStrategy(ConfigurationPersistenceStrategy item, Map<String, Object> props) {
Comparable<Object> key = ServiceUtil.getComparableForServiceRanking(props, Order.ASCENDING);
unregisterBridgeService(services.remove(key));
}
/**
* Register {@link ConfigurationPersistenceStrategy2} bridge service for {@link ConfigurationPersistenceStrategy} service.
* @param serviceInfo Service information
* @return Service registration
*/
private ServiceRegistration<ConfigurationPersistenceStrategy2> registerBridgeService(ServiceInfo serviceInfo) {
return bundleContext.registerService(ConfigurationPersistenceStrategy2.class,
new Adapter(serviceInfo.getService()), new Hashtable<>(serviceInfo.getProps()));
}
/**
* Unregister {@link ConfigurationPersistenceStrategy2} bridge service.
* @param service Service registration
*/
private void unregisterBridgeService(ServiceRegistration<ConfigurationPersistenceStrategy2> service) {
if (service != null) {
service.unregister();
}
}
@Activate
private void activate(BundleContext bundleContext) {
this.bundleContext = bundleContext;
for (Map.Entry<Comparable<Object>, ServiceInfo> entry : preActivateServices.entrySet()) {
services.put(entry.getKey(), registerBridgeService(entry.getValue()));
}
}
private static class ServiceInfo {
private final ConfigurationPersistenceStrategy service;
private final Map<String,Object> props;
public ServiceInfo(ConfigurationPersistenceStrategy service, Map<String, Object> props) {
this.service = service;
this.props = props;
}
public ConfigurationPersistenceStrategy getService() {
return service;
}
public Map<String, Object> getProps() {
return props;
}
}
/**
* Adapter which delegates {@link ConfigurationPersistenceStrategy2} methods to a {@link ConfigurationPersistenceStrategy} service.
*/
public static class Adapter implements ConfigurationPersistenceStrategy2 {
private final ConfigurationPersistenceStrategy delegate;
public Adapter(ConfigurationPersistenceStrategy delegate) {
this.delegate = delegate;
}
/**
* @return Implementation class of the original service.
*/
public Class<?> getOriginalServiceClass() {
return delegate.getClass();
}
@Override
public Resource getResource(@NotNull Resource resource) {
return delegate.getResource(resource);
}
@Override
public Resource getCollectionParentResource(@NotNull Resource resource) {
// with SPI/Impl 1.2 it was not possible to manipulate collection parent resource
return resource;
}
@Override
public Resource getCollectionItemResource(@NotNull Resource resource) {
return delegate.getResource(resource);
}
@Override
public String getResourcePath(@NotNull String resourcePath) {
return delegate.getResourcePath(resourcePath);
}
@Override
public String getCollectionParentResourcePath(@NotNull String resourcePath) {
// with SPI/Impl 1.2 it was not possible to manipulate collection parent resource
return resourcePath;
}
@Override
public String getCollectionItemResourcePath(@NotNull String resourcePath) {
return delegate.getResourcePath(resourcePath);
}
@Override
public String getConfigName(@NotNull String configName, @Nullable String relatedConfigPath) {
return delegate.getResourcePath(configName);
}
@Override
public String getCollectionParentConfigName(@NotNull String configName, @Nullable String relatedConfigPath) {
// with SPI/Impl 1.2 it was not possible to manipulate collection parent resource
return configName;
}
@Override
public String getCollectionItemConfigName(@NotNull String configName, @Nullable String relatedConfigPath) {
return delegate.getResourcePath(configName);
}
@Override
public boolean persistConfiguration(@NotNull ResourceResolver resourceResolver, @NotNull String configResourcePath,
@NotNull ConfigurationPersistData data) {
return delegate.persistConfiguration(resourceResolver, configResourcePath, data);
}
@Override
public boolean persistConfigurationCollection(@NotNull ResourceResolver resourceResolver,
@NotNull String configResourceCollectionParentPath, @NotNull ConfigurationCollectionPersistData data) {
return delegate.persistConfigurationCollection(resourceResolver, configResourceCollectionParentPath, data);
}
@Override
public boolean deleteConfiguration(@NotNull ResourceResolver resourceResolver, @NotNull String configResourcePath) {
return delegate.deleteConfiguration(resourceResolver, configResourcePath);
}
}
}