SLING-11864 Add new exported interface for filtering default properties
diff --git a/pom.xml b/pom.xml
index 0ebfccd..7cc44df 100644
--- a/pom.xml
+++ b/pom.xml
@@ -119,6 +119,17 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.component.annotations</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <!-- JetBrains annotations for null-analysis (SLING-7798), https://github.com/JetBrains/java-annotations -->
+ <dependency>
+ <groupId>org.jetbrains</groupId>
+ <artifactId>annotations</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/ConfigurationMerger.java b/src/main/java/org/apache/sling/installer/factories/configuration/ConfigurationMerger.java
new file mode 100644
index 0000000..28b1b6e
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/ConfigurationMerger.java
@@ -0,0 +1,50 @@
+/*
+ * 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.installer.factories.configuration;
+
+import java.util.Dictionary;
+
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * Exposes helper methods to identify those configuration properties which are set through installer resources having a configured merge scheme.
+ * Those configuration properties are referred to as default properties.
+ * Note though that both OSGi metatype and OSGi declarative services define default properties as well which are not meant here.
+ * @see <a href="https://sling.apache.org/documentation/bundles/configuration-installer-factory.html#merging-of-configurations">Merging of Configurations</a>
+ */
+@ProviderType
+public interface ConfigurationMerger {
+
+ /**
+ * Modifies the given dictionary so that all properties which have values equal to one
+ * of the same named property values provided by the inherited configurations are removed.
+ * @param pid the PID of the configuration
+ * @param dict the configuration properties to modify
+ */
+ void removeDefaultProperties(@NotNull final String pid, @NotNull final Dictionary<String, Object> dict);
+
+ /**
+ * Returns all properties for the given PID which are set through any of the resource with the configured merge schemes.
+ * @param pid the PID of the configuration
+ * @return the properties set through specific installer resources in a mutable dictionary
+ */
+ Dictionary<String, Object> getDefaultProperties(@NotNull final String pid);
+
+}
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigTaskCreator.java b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigTaskCreator.java
index e4bd388..147101b 100644
--- a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigTaskCreator.java
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigTaskCreator.java
@@ -18,10 +18,8 @@
*/
package org.apache.sling.installer.factories.configuration.impl;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Dictionary;
-import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
@@ -29,9 +27,6 @@
import org.apache.sling.installer.api.InstallableResource;
import org.apache.sling.installer.api.ResourceChangeListener;
-import org.apache.sling.installer.api.info.InfoProvider;
-import org.apache.sling.installer.api.info.Resource;
-import org.apache.sling.installer.api.info.ResourceGroup;
import org.apache.sling.installer.api.tasks.ChangeStateTask;
import org.apache.sling.installer.api.tasks.InstallTask;
import org.apache.sling.installer.api.tasks.InstallTaskFactory;
@@ -42,6 +37,7 @@
import org.apache.sling.installer.api.tasks.TaskResourceGroup;
import org.apache.sling.installer.api.tasks.TransformationResult;
import org.apache.sling.installer.factories.configuration.ConfigurationConstants;
+import org.apache.sling.installer.factories.configuration.ConfigurationMerger;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
@@ -68,14 +64,14 @@
private final ResourceChangeListener changeListener;
/** Info Provider */
- private final InfoProvider infoProvider;
+ private final ConfigurationMerger configMerger;
public ConfigTaskCreator(final ResourceChangeListener listener,
final ConfigurationAdmin configAdmin,
- final InfoProvider infoProvider) {
+ final ConfigurationMerger configMerger) {
this.changeListener = listener;
this.configAdmin = configAdmin;
- this.infoProvider = infoProvider;
+ this.configMerger = configMerger;
}
public ServiceRegistration<?> register(final BundleContext bundleContext) {
@@ -164,7 +160,7 @@
attrs.put(ConfigurationAdmin.SERVICE_FACTORYPID, event.getFactoryPid());
}
- removeDefaultProperties(this.infoProvider, event.getPid(), dict);
+ configMerger.removeDefaultProperties(event.getPid(), dict);
this.changeListener.resourceAddedOrUpdated(InstallableResource.TYPE_CONFIG, event.getPid(), null, dict, attrs);
} else {
@@ -177,50 +173,6 @@
}
}
- public static Dictionary<String, Object> getDefaultProperties(final InfoProvider infoProvider, final String pid) {
- if ( Activator.MERGE_SCHEMES != null ) {
- final List<Dictionary<String, Object>> propertiesList = new ArrayList<>();
- final String entityId = InstallableResource.TYPE_CONFIG.concat(":").concat(pid);
- boolean done = false;
- for(final ResourceGroup group : infoProvider.getInstallationState().getInstalledResources()) {
- for(final Resource rsrc : group.getResources()) {
- if ( rsrc.getEntityId().equals(entityId) ) {
- done = true;
- if ( Activator.MERGE_SCHEMES.contains(rsrc.getScheme()) ) {
- propertiesList.add(rsrc.getDictionary());
- }
- }
- }
- if ( done ) {
- break;
- }
- }
- if ( !propertiesList.isEmpty() ) {
- final Dictionary<String, Object> defaultProps = ConfigUtil.mergeReverseOrder(propertiesList);
- return defaultProps;
- }
- }
- return null;
- }
-
- public static void removeDefaultProperties(final InfoProvider infoProvider, final String pid, final Dictionary<String, Object> dict) {
- if ( Activator.MERGE_SCHEMES != null ) {
- final Dictionary<String, Object> defaultProps = getDefaultProperties(infoProvider, pid);
- if ( defaultProps != null ) {
- final Enumeration<String> keyEnum = defaultProps.keys();
- while ( keyEnum.hasMoreElements() ) {
- final String key = keyEnum.nextElement();
- final Object value = defaultProps.get(key);
-
- final Object newValue = dict.get(key);
- if ( newValue != null && ConfigUtil.isSameValue(newValue, value)) {
- dict.remove(key);
- }
- }
- }
- }
- }
-
/**
* @see org.apache.sling.installer.api.tasks.ResourceTransformer#transform(org.apache.sling.installer.api.tasks.RegisteredResource)
*/
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigurationMergerImpl.java b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigurationMergerImpl.java
new file mode 100644
index 0000000..80f490e
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigurationMergerImpl.java
@@ -0,0 +1,91 @@
+/*
+ * 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.installer.factories.configuration.impl;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.api.info.InfoProvider;
+import org.apache.sling.installer.api.info.Resource;
+import org.apache.sling.installer.api.info.ResourceGroup;
+import org.apache.sling.installer.factories.configuration.ConfigurationMerger;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+@Component
+public class ConfigurationMergerImpl implements ConfigurationMerger {
+
+ private final InfoProvider infoProvider;
+
+ @Activate
+ public ConfigurationMergerImpl(@Reference InfoProvider infoProvider) {
+ this.infoProvider = infoProvider;
+ }
+
+ @Override
+ public void removeDefaultProperties(@NotNull final String pid, @NotNull final Dictionary<String, Object> dict) {
+ if ( Activator.MERGE_SCHEMES != null ) {
+ final Dictionary<String, Object> defaultProps = getDefaultProperties(pid);
+ if ( defaultProps != null ) {
+ final Enumeration<String> keyEnum = defaultProps.keys();
+ while ( keyEnum.hasMoreElements() ) {
+ final String key = keyEnum.nextElement();
+ final Object value = defaultProps.get(key);
+
+ final Object newValue = dict.get(key);
+ if ( newValue != null && ConfigUtil.isSameValue(newValue, value)) {
+ dict.remove(key);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public Dictionary<String, Object> getDefaultProperties(@NotNull final String pid) {
+ if ( Activator.MERGE_SCHEMES != null ) {
+ final List<Dictionary<String, Object>> propertiesList = new ArrayList<>();
+ final String entityId = InstallableResource.TYPE_CONFIG.concat(":").concat(pid);
+ boolean done = false;
+ for(final ResourceGroup group : infoProvider.getInstallationState().getInstalledResources()) {
+ for(final Resource rsrc : group.getResources()) {
+ if ( rsrc.getEntityId().equals(entityId) ) {
+ done = true;
+ if ( Activator.MERGE_SCHEMES.contains(rsrc.getScheme()) ) {
+ propertiesList.add(rsrc.getDictionary());
+ }
+ }
+ }
+ if ( done ) {
+ break;
+ }
+ }
+ if ( !propertiesList.isEmpty() ) {
+ final Dictionary<String, Object> defaultProps = ConfigUtil.mergeReverseOrder(propertiesList);
+ return defaultProps;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ServicesListener.java b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ServicesListener.java
index 139eb2f..216e41c 100644
--- a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ServicesListener.java
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ServicesListener.java
@@ -21,7 +21,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.sling.installer.api.ResourceChangeListener;
-import org.apache.sling.installer.api.info.InfoProvider;
+import org.apache.sling.installer.factories.configuration.ConfigurationMerger;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
@@ -53,7 +53,7 @@
private final Listener configAdminListener;
/** The listener for the installer info service. */
- private final Listener infoServiceListener;
+ private final Listener configMergerListener;
/** Registration the service. */
private volatile ServiceRegistration<?> configTaskCreatorRegistration;
@@ -69,8 +69,8 @@
this.bundleContext = bundleContext;
this.changeHandlerListener = new Listener(ResourceChangeListener.class.getName());
this.configAdminListener = new Listener(ConfigurationAdmin.class.getName());
- this.infoServiceListener = new Listener(InfoProvider.class.getName());
- this.infoServiceListener.start();
+ this.configMergerListener = new Listener(ConfigurationMerger.class.getName());
+ this.configMergerListener.start();
this.changeHandlerListener.start();
this.configAdminListener.start();
}
@@ -79,13 +79,13 @@
// check if all services are available
final ResourceChangeListener listener = (ResourceChangeListener)this.changeHandlerListener.getService();
final ConfigurationAdmin configAdmin = (ConfigurationAdmin)this.configAdminListener.getService();
- final InfoProvider infoProvider = (InfoProvider)this.infoServiceListener.getService();
+ final ConfigurationMerger configMerger = (ConfigurationMerger)this.configMergerListener.getService();
- if ( configAdmin != null && listener != null && infoProvider != null ) {
+ if ( configAdmin != null && listener != null && configMerger != null ) {
if ( configTaskCreator == null ) {
active.set(true);
// start and register osgi installer service
- this.configTaskCreator = new ConfigTaskCreator(listener, configAdmin, infoProvider);
+ this.configTaskCreator = new ConfigTaskCreator(listener, configAdmin, configMerger);
final ConfigUpdateHandler handler = new ConfigUpdateHandler(configAdmin, this);
configTaskCreatorRegistration = handler.register(this.bundleContext);
if ( Activator.MERGE_SCHEMES != null ) {
@@ -93,7 +93,7 @@
@Override
public Object getService(final Bundle bundle, final ServiceRegistration<Object> registration) {
- return new WebconsoleConfigurationHandler(bundleContext, infoProvider);
+ return new WebconsoleConfigurationHandler(bundleContext, configMerger);
}
@Override
@@ -138,7 +138,7 @@
* Deactivate this listener.
*/
public void deactivate() {
- this.infoServiceListener.deactivate();
+ this.configMergerListener.deactivate();
this.changeHandlerListener.deactivate();
this.configAdminListener.deactivate();
this.stop();
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/impl/WebconsoleConfigurationHandler.java b/src/main/java/org/apache/sling/installer/factories/configuration/impl/WebconsoleConfigurationHandler.java
index 3aa0161..d9ee81b 100644
--- a/src/main/java/org/apache/sling/installer/factories/configuration/impl/WebconsoleConfigurationHandler.java
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/impl/WebconsoleConfigurationHandler.java
@@ -23,7 +23,7 @@
import org.apache.felix.webconsole.spi.ConfigurationHandler;
import org.apache.felix.webconsole.spi.ValidationException;
-import org.apache.sling.installer.api.info.InfoProvider;
+import org.apache.sling.installer.factories.configuration.ConfigurationMerger;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
@@ -31,14 +31,14 @@
static final String META_TYPE_NAME = "org.osgi.service.metatype.MetaTypeService";
- private final InfoProvider infoProvider;
+ private final ConfigurationMerger configMerger;
private final ServiceTracker<Object, Object> metatypeTracker;
private final BundleContext bundleContext;
- public WebconsoleConfigurationHandler(final BundleContext context, final InfoProvider infoProvider) {
- this.infoProvider = infoProvider;
+ public WebconsoleConfigurationHandler(final BundleContext context, final ConfigurationMerger configMerger) {
+ this.configMerger = configMerger;
this.bundleContext = context;
this.metatypeTracker = new ServiceTracker<>(context, META_TYPE_NAME, null);
this.metatypeTracker.open();
@@ -68,7 +68,7 @@
throws ValidationException, IOException {
final Object mts = this.metatypeTracker.getService();
if ( mts != null ) {
- final Dictionary<String, Object> defaultProps = ConfigTaskCreator.getDefaultProperties(infoProvider, pid);
+ final Dictionary<String, Object> defaultProps = configMerger.getDefaultProperties(pid);
final MetatypeHandler mt = new MetatypeHandler(mts, this.bundleContext);
mt.updateConfiguration(factoryPid, pid, props, defaultProps);
}
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/package-info.java b/src/main/java/org/apache/sling/installer/factories/configuration/package-info.java
index eb71c4d..747378d 100644
--- a/src/main/java/org/apache/sling/installer/factories/configuration/package-info.java
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/package-info.java
@@ -17,7 +17,7 @@
* under the License.
*/
-@org.osgi.annotation.versioning.Version("1.1.2")
+@org.osgi.annotation.versioning.Version("1.2.0")
package org.apache.sling.installer.factories.configuration;