Merge pull request #4 from ashokpanghal/issues/SLING-8523

SLING-8523 : Duplicate OSGI configs after upgrade
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
index b011329..ee013b8 100644
--- 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
@@ -77,27 +77,64 @@
     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);
+            if ( InstallableResource.TYPE_CONFIG.equals(group.getResourceType()) ) {
+                if(group.getAlias() == null && group.getId().contains("~") && group.getId().contains("-")){
+                    // new format config with ~ as separator, cleanup if duplicate old format config exists
+                    this.cleanupDuplicateFactoryConfig(group);
+                } else {
+                    if (group.getAlias() != null || group.getId().contains("-")) {
+                        this.logger.debug("Configuration going under updation is : {} with alias : {}", group.getId(), group.getAlias());
+                        this.updateFactoryConfig(group);
+                    }
+                }
             }
         }
     }
 
     protected String[] getFactoryPidAndPid(final String alias, final String oldId) {
         int pos = 0;
-        while ( alias.charAt(pos) == oldId.charAt(pos) ) {
-            pos++;
-        }
-        while (alias.charAt(pos - 1) != '.') {
-            pos--;
-        }
+        String factoryPid;
+        String pid;
+        if(alias != null) {
 
-        final String factoryPid = alias.substring(0, pos - 1);
-        final String pid = oldId.substring(factoryPid.length() + 1);
+            while (alias.charAt(pos) == oldId.charAt(pos)) {
+                pos++;
+            }
+            while (alias.charAt(pos - 1) != '.') {
+                pos--;
+            }
+
+            factoryPid = alias.substring(0, pos - 1);
+            pid = oldId.substring(factoryPid.length() + 1);
+        } else {
+            // extract factory id for these cases where alias is not available and factoryId and pid need to be separated from the old id string itself
+            //format assumption ::: "factory_pid.factory_pid.pid"
+            // split pid with lastIndexOf('.') then remove the duplicate factory_pid part from the remaining string using the middle dot split index
+            int lastDotIndex = oldId.lastIndexOf('.');
+            String factoryIdString = oldId.substring(0,lastDotIndex+1); // keep it +1 to have last dot intact so that we always have even dots in the string
+            factoryPid = oldId.substring(0,getMiddleDotSplitIndex(factoryIdString,'.'));
+            pid = oldId.substring(lastDotIndex+1);
+
+        }
 
         return new String[] { factoryPid, pid };
     }
 
+    private int getMiddleDotSplitIndex(final String strId, char dot){
+
+        int dotCount = 0;
+        int[] dotIndexArray = new int[strId.length()];
+
+        for (int i=0;i<strId.length();i++)
+
+            if (strId.charAt(i)==dot) {
+                dotCount++;
+                dotIndexArray[dotCount] = i;
+            }
+
+        return dotIndexArray[dotCount/2]; // get the middle dot index
+    }
+
     private void updateFactoryConfig(final UpdatableResourceGroup group) {
         final String alias = group.getAlias();
         final String oldId = group.getId();
@@ -131,4 +168,22 @@
         }
         group.update();
     }
+
+    private void cleanupDuplicateFactoryConfig(final UpdatableResourceGroup group) {
+            final String newPid = group.getId();
+            final int indexOfSeparator = newPid.lastIndexOf('~');
+            final String pid = newPid.substring(indexOfSeparator+1);
+            final String factoryPid = newPid.substring(0,indexOfSeparator);
+            try {
+                final Configuration cfg = ConfigUtil.getLegacyFactoryConfig(this.configAdmin, factoryPid, null, pid);
+                if ( cfg != null ) {
+                    this.logger.debug("Duplicate configuration being cleaned up is : {}",cfg.getFactoryPid() + '.' + cfg.getPid());
+                    // delete old factory configuration
+                    cfg.delete();
+                }
+
+        } catch ( final IOException | InvalidSyntaxException io) {
+            // ignore for now
+        }
+    }
 }
diff --git a/src/test/java/org/apache/sling/installer/factories/configuration/impl/ConfigUpdateHandlerTest.java b/src/test/java/org/apache/sling/installer/factories/configuration/impl/ConfigUpdateHandlerTest.java
index bbabb7d..d2a3dc9 100644
--- a/src/test/java/org/apache/sling/installer/factories/configuration/impl/ConfigUpdateHandlerTest.java
+++ b/src/test/java/org/apache/sling/installer/factories/configuration/impl/ConfigUpdateHandlerTest.java
@@ -46,5 +46,11 @@
                 "com.apache.sling.upgrades.cleanup.impl.UpgradeContentCleanup.com.apache.sling.upgrades.cleanup.impl.UpgradeContentCleanup.3ba307f5-a5d0-40a4-98b6-8616b7a1d1e8",
                 "com.apache.sling.upgrades.cleanup.impl.UpgradeContentCleanup.contentpackages",
                 "com.apache.sling.upgrades.cleanup.impl.UpgradeContentCleanup", "contentpackages");
+
+        // case where alias is null and factoryPid and Pid would be inferred from oldId itself
+        checkFactoryPid(
+                null,
+                "org.apache.sling.commons.log.LogManager.factory.config.org.apache.sling.commons.log.LogManager.factory.config.3a514ecf-2e1d-4903-bf88-d878360e8ff1",
+                "org.apache.sling.commons.log.LogManager.factory.config", "3a514ecf-2e1d-4903-bf88-d878360e8ff1");
     }
 }