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();
     }
 

Reply via email to