| /* |
| * 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); |
| } |
| |
| } |
| |
| } |