This is an automated email from the ASF dual-hosted git repository.
cziegeler pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-factory-configuration.git
The following commit(s) were added to refs/heads/master by this push:
new 6f14c8d SLING-7786 : Use R7 configuration admin supporting named
factory configurations
6f14c8d is described below
commit 6f14c8d17610d4d4c995f4927ebe01db053f0513
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Mon Aug 13 18:30:11 2018 +0200
SLING-7786 : Use R7 configuration admin supporting named factory
configurations
---
pom.xml | 2 +-
.../configuration/impl/ConfigRemoveTask.java | 5 -
.../configuration/impl/ConfigTaskCreator.java | 155 +++------------------
.../configuration/impl/ConfigUpdateHandler.java | 121 ++++++++++++++++
.../configuration/impl/ServicesListener.java | 63 +++------
5 files changed, 167 insertions(+), 179 deletions(-)
diff --git a/pom.xml b/pom.xml
index dab6fe8..aaf3fa0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -84,7 +84,7 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.installer.core</artifactId>
- <version>3.8.0</version>
+ <version>3.8.13-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
diff --git
a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigRemoveTask.java
b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigRemoveTask.java
index ba7296a..0e323c4 100644
---
a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigRemoveTask.java
+++
b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigRemoveTask.java
@@ -47,11 +47,6 @@ public class ConfigRemoveTask extends AbstractConfigTask {
synchronized ( Coordinator.SHARED ) {
try {
Configuration cfg =
ConfigUtil.getConfiguration(this.getConfigurationAdmin(), this.factoryPid,
this.configPid);
- if ( cfg == null && this.factoryPid != null ) {
- // try support for legacy factory config handling
- cfg =
ConfigUtil.getLegacyFactoryConfig(this.getConfigurationAdmin(),
this.factoryPid, this.getResourceGroup().getAlias(), this.configPid);
-
- }
if (cfg == null) {
this.getLogger().debug("Cannot delete config , pid={} not
found, ignored ({})", getRealPID(), getResource());
} else {
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 36e8067..92d824e 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
@@ -21,19 +21,12 @@ package
org.apache.sling.installer.factories.configuration.impl;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.HashMap;
+import java.util.Hashtable;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
import org.apache.sling.installer.api.InstallableResource;
-import org.apache.sling.installer.api.OsgiInstaller;
import org.apache.sling.installer.api.ResourceChangeListener;
-import org.apache.sling.installer.api.event.InstallationEvent;
-import org.apache.sling.installer.api.event.InstallationListener;
-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;
@@ -44,7 +37,9 @@ import org.apache.sling.installer.api.tasks.TaskResource;
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.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.ConfigurationEvent;
@@ -56,7 +51,7 @@ import org.slf4j.LoggerFactory;
* Task creator for configurations.
*/
public class ConfigTaskCreator
- implements InstallTaskFactory, ConfigurationListener, ResourceTransformer,
InstallationListener {
+ implements InstallTaskFactory, ConfigurationListener, ResourceTransformer {
/** Logger. */
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@@ -67,20 +62,25 @@ public class ConfigTaskCreator
/** Resource change listener. */
private final ResourceChangeListener changeListener;
- /** Resource change listener. */
- private final OsgiInstaller installer;
-
- /** Resource change listener. */
- private final InfoProvider infoProvider;
-
public ConfigTaskCreator(final ResourceChangeListener listener,
- final ConfigurationAdmin configAdmin,
- final OsgiInstaller installer,
- final InfoProvider infoProvider) {
+ final ConfigurationAdmin configAdmin) {
this.changeListener = listener;
this.configAdmin = configAdmin;
- this.installer = installer;
- this.infoProvider = infoProvider;
+ }
+
+ public ServiceRegistration<?> register(final BundleContext bundleContext) {
+ final Hashtable<String, String> props = new Hashtable<>();
+ props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Configuration
Install Task Factory");
+ props.put(Constants.SERVICE_VENDOR, ServicesListener.VENDOR);
+ props.put(InstallTaskFactory.NAME, "org.osgi.service.cm");
+ props.put(ResourceTransformer.NAME, "org.osgi.service.cm");
+
+ final String [] serviceInterfaces = {
+ InstallTaskFactory.class.getName(),
+ ConfigurationListener.class.getName(),
+ ResourceTransformer.class.getName()
+ };
+ return bundleContext.registerService(serviceInterfaces, this, props);
}
/**
@@ -118,16 +118,11 @@ public class ConfigTaskCreator
*/
@Override
public void configurationEvent(final ConfigurationEvent event) {
- Configuration updateConfig = null;
- ResourceGroup updateGroup = null;
synchronized ( Coordinator.SHARED ) {
if ( event.getType() == ConfigurationEvent.CM_DELETED ) {
final Coordinator.Operation op =
Coordinator.SHARED.get(event.getPid(), event.getFactoryPid(), true);
if ( op == null ) {
- updateGroup = this.convertOldInstallerResource(event);
- if ( updateGroup == null ) {
-
this.changeListener.resourceRemoved(InstallableResource.TYPE_CONFIG,
event.getPid());
- }
+
this.changeListener.resourceRemoved(InstallableResource.TYPE_CONFIG,
event.getPid());
} else {
this.logger.debug("Ignoring configuration event for
{}:{}", event.getPid(), event.getFactoryPid());
}
@@ -156,12 +151,7 @@ public class ConfigTaskCreator
attrs.put(ConfigurationAdmin.SERVICE_FACTORYPID,
event.getFactoryPid());
}
- updateGroup = this.convertOldInstallerResource(event);
- if ( updateGroup == null ) {
-
this.changeListener.resourceAddedOrUpdated(InstallableResource.TYPE_CONFIG,
event.getPid(), null, dict, attrs);
- } else {
- updateConfig = config;
- }
+
this.changeListener.resourceAddedOrUpdated(InstallableResource.TYPE_CONFIG,
event.getPid(), null, dict, attrs);
} else {
this.logger.debug("Ignoring configuration event for
{}:{}", event.getPid(), event.getFactoryPid());
@@ -171,76 +161,6 @@ public class ConfigTaskCreator
}
}
}
- if ( updateGroup != null ) {
- // update installer state from old config to new config
- // store config dictionary for update
- final Dictionary<String, Object> dict = updateConfig == null ?
null : ConfigUtil.cleanConfiguration(updateConfig.getProperties());
- try {
- String name = null;
- for(final Resource r : updateGroup.getResources()) {
- if ( name == null ) {
- name = (String)r.getAttribute(Constants.SERVICE_PID);
- }
- final int pos = r.getURL().indexOf(':');
- final String rsrcPath = r.getURL().substring(pos +1);
-
- this.startListener(r.getURL(), 2);
- final Dictionary<String, Object> newProps =
ConfigUtil.cleanConfiguration(r.getDictionary());
- newProps.put(this.getClass().getName(), "true");
- final InstallableResource ins1 = new
InstallableResource(rsrcPath, null, newProps, r.getDigest(), r.getType(),
r.getPriority());
- this.installer.updateResources(r.getScheme(), new
InstallableResource[] {ins1}, null);
- this.waitForInstall();
-
- this.startListener(r.getURL(), 1);
- newProps.remove(this.getClass().getName());
- final InstallableResource ins2 = new
InstallableResource(rsrcPath, null, newProps, r.getDigest(), r.getType(),
r.getPriority());
- this.installer.updateResources(r.getScheme(), new
InstallableResource[] {ins2}, null);
- this.waitForInstall();
- }
- if ( updateConfig != null ) {
- // then delete old config
- final Coordinator.Operation op = new
Coordinator.Operation(event.getPid(), event.getFactoryPid(), true);
- Coordinator.SHARED.add(op);
- updateConfig.delete();
-
- // finally re-create new config
- final Configuration newConfig =
this.configAdmin.getFactoryConfiguration(event.getFactoryPid(), name, null);
- newConfig.update(dict);
- } else {
- // delete newly created config
- final Configuration newConfig =
this.configAdmin.getFactoryConfiguration(event.getFactoryPid(), name, null);
- newConfig.delete();
- }
- } catch ( final Exception ignore) {
- logger.error("An error occured while updating factory
configuration " + event.getFactoryPid() + "-" + event.getPid(), ignore);
- }
- }
- }
-
- private ResourceGroup convertOldInstallerResource(final ConfigurationEvent
event) {
- if ( event.getFactoryPid() != null && !event.getPid().contains("~") ) {
- // check if this configuration is processed by the installer
- final String id = event.getFactoryPid() + '.' +
(event.getPid().startsWith(event.getFactoryPid() + '.') ?
- event.getPid().substring(event.getFactoryPid().length() +
1) : event.getPid());
- final List<ResourceGroup> groups =
this.infoProvider.getInstallationState().getInstalledResources();
- for(final ResourceGroup grp : groups) {
- if ( grp.getAlias() != null ) {
- final String alias;
- if ( grp.getAlias().startsWith(event.getFactoryPid() +
".") ) {
- alias =
grp.getAlias().substring(event.getFactoryPid().length() + 1);
- } else {
- alias = grp.getAlias();
- }
- for(final Resource rsrc : grp.getResources()) {
- if (
InstallableResource.TYPE_CONFIG.equals(rsrc.getType()) && id.equals(alias) ) {
- // we need to update the installer state
- return grp;
- }
- }
- }
- }
- }
- return null;
}
/**
@@ -307,37 +227,6 @@ public class ConfigTaskCreator
return new TransformationResult[] {tr};
}
- private volatile CountDownLatch latch;
- private volatile String waitingForUrl;
-
- @Override
- public void onEvent(final InstallationEvent event) {
- if ( waitingForUrl != null ) {
- if ( event.getType() == InstallationEvent.TYPE.PROCESSED ) {
- final TaskResource rsrc = (TaskResource) event.getSource();
- if ( rsrc.getURL().equals(waitingForUrl) ) {
- latch.countDown();
- }
- }
- }
- }
-
-
- private void startListener(final String url, final int count) {
- this.latch = new CountDownLatch(count);
- this.waitingForUrl = url;
- }
-
- public void waitForInstall() {
- try {
- this.latch.await(50, TimeUnit.SECONDS);
- } catch (final InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- this.waitingForUrl = null;
- this.latch = null;
- }
-
private static final List<String> EXTENSIONS = Arrays.asList(".config",
".properties", ".cfg", ".cfg.json");
private static String removeConfigExtension(final String id) {
for(final String ext : EXTENSIONS) {
diff --git
a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigUpdateHandler.java
b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigUpdateHandler.java
new file mode 100644
index 0000000..0a27403
--- /dev/null
+++
b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigUpdateHandler.java
@@ -0,0 +1,121 @@
+/*
+ * 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.io.IOException;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.api.tasks.ResourceUpdater;
+import org.apache.sling.installer.api.tasks.UpdatableResourceGroup;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Update handler for updating 1.x to 1.2
+ */
+public class ConfigUpdateHandler implements ResourceUpdater {
+
+ /** Logger. */
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ /** Configuration admin. */
+ private final ConfigurationAdmin configAdmin;
+
+ private final ServicesListener activator;
+
+
+ public ConfigUpdateHandler(final ConfigurationAdmin configAdmin,
+ final ServicesListener activator) {
+ this.configAdmin = configAdmin;
+ this.activator = activator;
+ }
+
+ public ServiceRegistration<?> register(final BundleContext bundleContext) {
+ final Hashtable<String, String> props = new Hashtable<>();
+ props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Configuration
Install Task Factory Update Handler");
+ props.put(Constants.SERVICE_VENDOR, ServicesListener.VENDOR);
+
+ final String [] serviceInterfaces = {
+ ResourceUpdater.class.getName()
+ };
+ return bundleContext.registerService(serviceInterfaces, this, props);
+ }
+
+ @Override
+ public void update(final Collection<UpdatableResourceGroup> groups) {
+ for(final UpdatableResourceGroup group : groups) {
+ update(group);
+ }
+ this.activator.finishedUpdating();
+ }
+
+ private void update(final UpdatableResourceGroup group) {
+ if ( this.activator.isActive() ) {
+ // check if the group handles configurations and has an alias (aka
factory config)
+ if (
InstallableResource.TYPE_CONFIG.equals(group.getResourceType()) &&
group.getAlias() != null ) {
+ this.updateFactoryConfig(group);
+ }
+ }
+ }
+
+ private void updateFactoryConfig(final UpdatableResourceGroup group) {
+ final String alias = group.getAlias();
+ final String oldId = group.getId();
+
+ // change group id
+ int pos = 0;
+ while ( alias.charAt(pos) == oldId.charAt(pos) ) {
+ pos++;
+ }
+ final String factoryPid = alias.substring(0, pos - 1);
+ final String pid = oldId.substring(factoryPid.length() + 1);
+
+ final String newId = ConfigUtil.getPIDOfFactoryPID(factoryPid, pid);
+ group.setId(newId);
+ // clear alias
+ group.setAlias(null);
+
+ this.logger.debug("Updating factory configuration from {} to {}",
oldId, newId);
+ try {
+ final Configuration cfg =
ConfigUtil.getLegacyFactoryConfig(this.configAdmin, factoryPid, alias, pid);
+ if ( cfg != null ) {
+ // keep existing values / location
+ final String location = cfg.getBundleLocation();
+ final Dictionary<String, Object> dict =
ConfigUtil.cleanConfiguration(cfg.getProperties());
+ // delete old factory configuration
+ cfg.delete();
+ // create new named factory configuration with same properties
and bundle location
+ final Configuration upCfg =
this.configAdmin.getFactoryConfiguration(factoryPid, pid, location);
+ upCfg.update(dict);
+ }
+ } catch ( final IOException | InvalidSyntaxException io) {
+ // ignore for now
+ }
+ group.update();
+ }
+}
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 22e179b..526bdfe 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
@@ -18,14 +18,9 @@
*/
package org.apache.sling.installer.factories.configuration.impl;
-import java.util.Hashtable;
+import java.util.concurrent.atomic.AtomicBoolean;
-import org.apache.sling.installer.api.OsgiInstaller;
import org.apache.sling.installer.api.ResourceChangeListener;
-import org.apache.sling.installer.api.event.InstallationListener;
-import org.apache.sling.installer.api.info.InfoProvider;
-import org.apache.sling.installer.api.tasks.InstallTaskFactory;
-import org.apache.sling.installer.api.tasks.ResourceTransformer;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
@@ -34,7 +29,6 @@ import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationAdmin;
-import org.osgi.service.cm.ConfigurationListener;
/**
* The <code>ServicesListener</code> listens for the required services
@@ -49,12 +43,6 @@ public class ServicesListener {
/** The bundle context. */
private final BundleContext bundleContext;
- /** The listener for the installer. */
- private final Listener installerListener;
-
- /** The listener for the info service */
- private final Listener infoServiceListener;
-
/** The listener for the change list handler. */
private final Listener changeHandlerListener;
@@ -62,54 +50,40 @@ public class ServicesListener {
private final Listener configAdminListener;
/** Registration the service. */
- private ServiceRegistration<?> configTaskCreatorRegistration;
+ private volatile ServiceRegistration<?> configTaskCreatorRegistration;
+
+ private volatile ConfigTaskCreator configTaskCreator;
- private ConfigTaskCreator configTaskCreator;
+ private final AtomicBoolean active = new AtomicBoolean(false);
public ServicesListener(final BundleContext bundleContext) {
this.bundleContext = bundleContext;
- this.installerListener = new Listener(OsgiInstaller.class.getName());
- this.infoServiceListener = new Listener(InfoProvider.class.getName());
this.changeHandlerListener = new
Listener(ResourceChangeListener.class.getName());
this.configAdminListener = new
Listener(ConfigurationAdmin.class.getName());
this.changeHandlerListener.start();
this.configAdminListener.start();
- this.installerListener.start();
- this.infoServiceListener.start();
}
public synchronized void notifyChange() {
// check if all services are available
final ResourceChangeListener listener =
(ResourceChangeListener)this.changeHandlerListener.getService();
final ConfigurationAdmin configAdmin =
(ConfigurationAdmin)this.configAdminListener.getService();
- final OsgiInstaller installer =
(OsgiInstaller)this.installerListener.getService();
- final InfoProvider infoProvider =
(InfoProvider)this.infoServiceListener.getService();
- if ( configAdmin != null && listener != null && installer != null &&
infoProvider != null ) {
+ if ( configAdmin != null && listener != null ) {
if ( configTaskCreator == null ) {
- final Hashtable<String, String> props = new Hashtable<>();
- props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling
Configuration Install Task Factory");
- props.put(Constants.SERVICE_VENDOR, VENDOR);
- props.put(InstallTaskFactory.NAME, "org.osgi.service.cm");
- props.put(ResourceTransformer.NAME, "org.osgi.service.cm");
-
- this.configTaskCreator = new ConfigTaskCreator(listener,
configAdmin, installer, infoProvider);
+ active.set(true);
// start and register osgi installer service
- final String [] serviceInterfaces = {
- InstallTaskFactory.class.getName(),
- ConfigurationListener.class.getName(),
- ResourceTransformer.class.getName(),
- InstallationListener.class.getName()
-
- };
- configTaskCreatorRegistration =
this.bundleContext.registerService(serviceInterfaces, configTaskCreator, props);
+ this.configTaskCreator = new ConfigTaskCreator(listener,
configAdmin);
+ final ConfigUpdateHandler handler = new
ConfigUpdateHandler(configAdmin, this);
+ configTaskCreatorRegistration =
handler.register(this.bundleContext);
}
} else {
this.stop();
}
}
- private void stop() {
+ private synchronized void stop() {
+ active.set(false);
// unregister
if ( this.configTaskCreatorRegistration != null ) {
this.configTaskCreatorRegistration.unregister();
@@ -118,14 +92,23 @@ public class ServicesListener {
this.configTaskCreator = null;
}
+ public boolean isActive() {
+ return this.active.get();
+ }
+
+ public synchronized void finishedUpdating() {
+ if ( this.isActive() ) {
+ this.configTaskCreatorRegistration.unregister();
+ this.configTaskCreatorRegistration =
this.configTaskCreator.register(this.bundleContext);
+ }
+ }
+
/**
* Deactivate this listener.
*/
public void deactivate() {
this.changeHandlerListener.deactivate();
this.configAdminListener.deactivate();
- this.infoServiceListener.deactivate();
- this.installerListener.deactivate();
this.stop();
}