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 268f7cc SLING-7786 : Use R7 configuration admin supporting named
factory configurations. Add experimental code for on the fly conversion
268f7cc is described below
commit 268f7cc05724ee56a67c79c70fe8a7c25464ef7c
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Wed Aug 8 13:10:58 2018 +0200
SLING-7786 : Use R7 configuration admin supporting named factory
configurations. Add experimental code for on the fly conversion
---
.../configuration/impl/ConfigRemoveTask.java | 8 +-
.../configuration/impl/ConfigTaskCreator.java | 148 +++++++++++++++++++--
.../factories/configuration/impl/ConfigUtil.java | 9 +-
.../configuration/impl/ServicesListener.java | 27 +++-
4 files changed, 169 insertions(+), 23 deletions(-)
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 e8b0011..ba7296a 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
@@ -49,13 +49,7 @@ public class ConfigRemoveTask extends AbstractConfigTask {
Configuration cfg =
ConfigUtil.getConfiguration(this.getConfigurationAdmin(), this.factoryPid,
this.configPid);
if ( cfg == null && this.factoryPid != null ) {
// try support for legacy factory config handling
- final String aliasPid;
- if ( this.getResourceGroup().getAlias() != null ) {
- aliasPid =
this.getResourceGroup().getAlias().substring(this.factoryPid.length() + 1);
- } else {
- aliasPid = null;
- }
- cfg =
ConfigUtil.getLegacyFactoryConfig(this.getConfigurationAdmin(),
this.factoryPid, (this.factoryPid != null && aliasPid != null ? aliasPid :
this.configPid));
+ cfg =
ConfigUtil.getLegacyFactoryConfig(this.getConfigurationAdmin(),
this.factoryPid, this.getResourceGroup().getAlias(), this.configPid);
}
if (cfg == null) {
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 3033a5a..8c2a9ac 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
@@ -20,10 +20,18 @@ package
org.apache.sling.installer.factories.configuration.impl;
import java.util.Dictionary;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
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;
@@ -46,7 +54,7 @@ import org.slf4j.LoggerFactory;
* Task creator for configurations.
*/
public class ConfigTaskCreator
- implements InstallTaskFactory, ConfigurationListener, ResourceTransformer {
+ implements InstallTaskFactory, ConfigurationListener, ResourceTransformer,
InstallationListener {
/** Logger. */
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@@ -57,9 +65,20 @@ public class ConfigTaskCreator
/** Resource change listener. */
private final ResourceChangeListener changeListener;
- public ConfigTaskCreator(final ResourceChangeListener listener, final
ConfigurationAdmin configAdmin) {
+ /** 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) {
this.changeListener = listener;
this.configAdmin = configAdmin;
+ this.installer = installer;
+ this.infoProvider = infoProvider;
}
/**
@@ -97,6 +116,8 @@ 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);
@@ -129,7 +150,38 @@ public class ConfigTaskCreator
if (event.getFactoryPid() != null) {
attrs.put(ConfigurationAdmin.SERVICE_FACTORYPID,
event.getFactoryPid());
}
-
this.changeListener.resourceAddedOrUpdated(InstallableResource.TYPE_CONFIG,
event.getPid(), null, dict, attrs);
+
+ 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) ) {
+ updateGroup = grp;
+ break;
+ }
+ }
+ }
+ if ( updateGroup != null ) {
+ // we need to update the installer state
+ updateConfig = config;
+ break;
+ }
+ }
+
+ }
+ if ( updateConfig == null ) {
+
this.changeListener.resourceAddedOrUpdated(InstallableResource.TYPE_CONFIG,
event.getPid(), null, dict, attrs);
+ }
} else {
this.logger.debug("Ignoring configuration event for
{}:{}", event.getPid(), event.getFactoryPid());
@@ -139,6 +191,46 @@ public class ConfigTaskCreator
}
}
}
+ if ( updateConfig != null ) {
+ // TODO - Experimental code for on the fly upgrade from old to new
style for factory configurations
+ // update installer state from old config to new config
+ try {
+ final Dictionary<String, Object> dict =
ConfigUtil.cleanConfiguration(updateConfig.getProperties());
+ final String factoryPid = updateConfig.getFactoryPid();
+
+ 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());
+ final Dictionary<String, Object> newProps =
ConfigUtil.cleanConfiguration(r.getDictionary());
+ newProps.put(this.getClass().getName(), "true");
+ final InstallableResource ins1 = new
InstallableResource(rsrcPath, r.getInputStream(), newProps, r.getDigest(),
r.getType(), r.getPriority());
+ this.installer.updateResources(r.getScheme(), new
InstallableResource[] {ins1}, null);
+ this.waitForInstall();
+
+ this.startListener(r.getURL());
+ newProps.remove(this.getClass().getName());
+ final InstallableResource ins2 = new
InstallableResource(rsrcPath, r.getInputStream(), newProps, r.getDigest(),
r.getType(), r.getPriority());
+ this.installer.updateResources(r.getScheme(), new
InstallableResource[] {ins2}, null);
+ this.waitForInstall();
+ }
+ // then delete old config
+ final Coordinator.Operation op = new
Coordinator.Operation(updateConfig.getPid(), updateConfig.getFactoryPid(),
true);
+ Coordinator.SHARED.add(op);
+ updateConfig.delete();
+
+ // finally re-create new config
+ final Configuration newConfig =
this.configAdmin.getFactoryConfiguration(factoryPid, name, null);
+ newConfig.update(dict);
+ } catch ( final Exception ignore) {
+ // ignore for now
+ }
+ }
}
/**
@@ -152,12 +244,8 @@ public class ConfigTaskCreator
return null;
}
- /**
- * Check if the registered resource is a configuration
- * @param resource The resource
- */
- private TransformationResult[] checkConfiguration(final RegisteredResource
resource) {
- final String url = separatorsToUnix(resource.getURL());
+ private static String getResourceId(final String rawUrl) {
+ final String url = separatorsToUnix(rawUrl);
int pos = url.lastIndexOf('/');
if ( pos == -1 ) {
pos = url.indexOf(':');
@@ -169,6 +257,15 @@ public class ConfigTaskCreator
} else {
lastIdPart = url;
}
+ return lastIdPart;
+ }
+
+ /**
+ * Check if the registered resource is a configuration
+ * @param resource The resource
+ */
+ private TransformationResult[] checkConfiguration(final RegisteredResource
resource) {
+ final String lastIdPart = getResourceId(resource.getURL());
final String pid;
// remove extension if known
@@ -203,6 +300,39 @@ public class ConfigTaskCreator
return new TransformationResult[] {tr};
}
+ private final AtomicBoolean doneProcessing = new AtomicBoolean(false);
+ 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) ) {
+ doneProcessing.set(true);
+ }
+ }
+ }
+ }
+
+
+ private void startListener(final String url) {
+ this.doneProcessing.set(false);
+ this.waitingForUrl = url;
+ }
+
+ public void waitForInstall() {
+ final long startTime = System.currentTimeMillis();
+ while ( !doneProcessing.get() && startTime + 10000 >
System.currentTimeMillis() ) {
+ try {
+ Thread.sleep(200);
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ this.waitingForUrl = null;
+ }
+
/**
* Compute the extension
*/
diff --git
a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigUtil.java
b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigUtil.java
index b8cca60..1c49512 100644
---
a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigUtil.java
+++
b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigUtil.java
@@ -180,7 +180,7 @@ abstract class ConfigUtil {
} else {
final String filter = "(" + Constants.SERVICE_PID + "=" +
encode(configPidOrName)
+ ")";
- Configuration[] configs = ca.listConfigurations(filter);
+ final Configuration[] configs = ca.listConfigurations(filter);
if (configs != null && configs.length > 0) {
result = configs[0];
}
@@ -194,7 +194,7 @@ abstract class ConfigUtil {
+ ")("
+ Constants.SERVICE_PID + "=" +
encode(ConfigUtil.getPIDOfFactoryPID(factoryPid, configPidOrName))
+ "))";
- Configuration[] configs = ca.listConfigurations(filter);
+ final Configuration[] configs = ca.listConfigurations(filter);
if (configs != null && configs.length > 0) {
result = configs[0];
}
@@ -206,8 +206,11 @@ abstract class ConfigUtil {
public static Configuration getLegacyFactoryConfig(final
ConfigurationAdmin ca,
final String factoryPid,
- final String configPid)
+ final String aliasPid,
+ final String pid)
throws IOException, InvalidSyntaxException {
+ final String configPid = (aliasPid != null ?
aliasPid.substring(factoryPid.length() + 1) : pid);
+
Configuration result = null;
Configuration configs[] = 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 851e5e4..22e179b 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
@@ -20,7 +20,10 @@ package
org.apache.sling.installer.factories.configuration.impl;
import java.util.Hashtable;
+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;
@@ -46,6 +49,12 @@ 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;
@@ -59,31 +68,39 @@ public class ServicesListener {
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 ) {
+ if ( configAdmin != null && listener != null && installer != null &&
infoProvider != null ) {
if ( configTaskCreator == null ) {
- final Hashtable<String, String> props = new Hashtable<String,
String>();
+ 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);
+ this.configTaskCreator = new ConfigTaskCreator(listener,
configAdmin, installer, infoProvider);
// start and register osgi installer service
final String [] serviceInterfaces = {
InstallTaskFactory.class.getName(),
ConfigurationListener.class.getName(),
- ResourceTransformer.class.getName()
+ ResourceTransformer.class.getName(),
+ InstallationListener.class.getName()
+
};
configTaskCreatorRegistration =
this.bundleContext.registerService(serviceInterfaces, configTaskCreator, props);
}
@@ -107,6 +124,8 @@ public class ServicesListener {
public void deactivate() {
this.changeHandlerListener.deactivate();
this.configAdminListener.deactivate();
+ this.infoServiceListener.deactivate();
+ this.installerListener.deactivate();
this.stop();
}