Author: kwin
Date: Thu Feb 16 10:43:39 2017
New Revision: 1783196

URL: http://svn.apache.org/viewvc?rev=1783196&view=rev
Log:
SLING-6392 support entity id changes for the same url (by uninstalling stale 
resources)

Modified:
    
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/PersistentResourceList.java
    
sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/BundleInstallUpgradeDowngradeTest.java
    
sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/MockInstallableResource.java
    
sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/OsgiInstallerTestBase.java

Modified: 
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/PersistentResourceList.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/PersistentResourceList.java?rev=1783196&r1=1783195&r2=1783196&view=diff
==============================================================================
--- 
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/PersistentResourceList.java
 (original)
+++ 
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/PersistentResourceList.java
 Thu Feb 16 10:43:39 2017
@@ -31,6 +31,7 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -224,8 +225,20 @@ public class PersistentResourceList {
                 t = new EntityResourceList(input.getEntityId(), this.listener);
                 this.data.put(input.getEntityId(), t);
             }
-
             t.addOrUpdate(input);
+
+            // find stale resources (other entity ids with the same URL)
+            Collection<RegisteredResource> staleResources = 
getResourcesWithUrl(input.getURL(), input.getEntityId());
+            for (RegisteredResource staleResource : staleResources) {
+                // get according group
+                EntityResourceList group = 
this.data.get(staleResource.getEntityId());
+                if (group == null) {
+                    logger.error("Could not get group of stale resource {}", 
staleResource);
+                } else {
+                    group.remove(input.getURL());
+                    logger.warn("Removing stale resource {}, overwritten by 
{}", staleResource, input);
+                }
+            }
         } else {
             // check if there is an old resource and remove it first
             if ( this.untransformedResources.contains(input) ) {
@@ -241,6 +254,7 @@ public class PersistentResourceList {
     public List<RegisteredResource> getUntransformedResources() {
         return this.untransformedResources;
     }
+   
 
     /**
      * Remove a resource by url.
@@ -283,6 +297,27 @@ public class PersistentResourceList {
     }
 
     /**
+     * 
+     * @param url the url of the resource to look for
+     * @param entityIdToSkip all resources having this entity id should in no 
case be returned
+     * @return the list of all registered resources with the given url, not 
having the entityId which should be skipped.
+     */
+    private Collection<RegisteredResource> getResourcesWithUrl(String url, 
String entityIdToSkip) {
+        Collection<RegisteredResource> foundResources = new LinkedList<>();
+        for(final EntityResourceList group : this.data.values()) {
+            if (group.getResourceId().equals(entityIdToSkip)) {
+                continue;
+            }
+            for (RegisteredResource resource : group.listResources()) {
+                if (resource.getURL().equals(url)) {
+                    foundResources.add(resource);
+                }
+            }
+        }
+        return foundResources;
+    }
+
+    /**
      * Compact the internal state and remove empty groups.
      * @return <code>true</code> if another cycle should be started.
      */

Modified: 
sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/BundleInstallUpgradeDowngradeTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/BundleInstallUpgradeDowngradeTest.java?rev=1783196&r1=1783195&r2=1783196&view=diff
==============================================================================
--- 
sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/BundleInstallUpgradeDowngradeTest.java
 (original)
+++ 
sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/BundleInstallUpgradeDowngradeTest.java
 Thu Feb 16 10:43:39 2017
@@ -19,6 +19,8 @@ package org.apache.sling.installer.it;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
+import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.it.OsgiInstallerTestBase.BundleEvent;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -207,4 +209,44 @@ public class BundleInstallUpgradeDowngra
         }
 
     }
+
+    /**
+     * This test class assures that whenever a new bundle is 
+     * provided with the same url as an already installed bundle,
+     * the already installed bundle is uninstalled and the new one installed.
+     * @see <a 
href="https://issues.apache.org/jira/browse/SLING-6392";>SLING-6392</a>
+     */
+    @Test
+    public void testReplaceBundleWithSameUrlButDifferentSymbolicName() throws 
Exception {
+        final String symbolicName = "osgi-installer-testbundle";
+        final String symbolicName2 = "osgi-installer-testA";
+        final String installableResourceId = "stable-id";
+        
+        assertNull("Test bundle must not be present before test", 
findBundle(symbolicName));
+        assertNull("Test A bundle must not be present before test", 
findBundle(symbolicName2));
+        {
+            //assertNull("Test bundle must be absent before installing", 
findBundle(symbolicName));
+            final Object listener = this.startObservingBundleEvents();
+            installer.updateResources(URL_SCHEME, getInstallableResource(
+                    getTestBundle(BUNDLE_BASE_NAME + "-testbundle-1.0.jar"), 
installableResourceId, "1", InstallableResource.DEFAULT_PRIORITY), null);
+            this.waitForBundleEvents(symbolicName + " must be installed", 
listener,
+                    new BundleEvent(symbolicName, "1.0", 
org.osgi.framework.BundleEvent.INSTALLED),
+                    new BundleEvent(symbolicName, "1.0", 
org.osgi.framework.BundleEvent.STARTED));
+            assertBundle("After installing", symbolicName, "1.0", 
Bundle.ACTIVE);
+        }
+
+        // now modify the bundle (having the same url but a different symbolic 
name and different digest)
+        {
+            final Object listener = this.startObservingBundleEvents();
+            installer.updateResources(URL_SCHEME, getInstallableResource(
+                    getTestBundle(BUNDLE_BASE_NAME + "-testA-1.0.jar"), 
installableResourceId, "2", InstallableResource.DEFAULT_PRIORITY), null);
+            this.waitForBundleEvents(symbolicName2 + " must be installed and " 
+ symbolicName + " uninstalled", listener,
+                    new BundleEvent(symbolicName, "1.0", 
org.osgi.framework.BundleEvent.STOPPED),
+                    new BundleEvent(symbolicName, "1.0", 
org.osgi.framework.BundleEvent.UNINSTALLED),
+                    new BundleEvent(symbolicName2, "1.0", 
org.osgi.framework.BundleEvent.INSTALLED),
+                    new BundleEvent(symbolicName2, "1.0", 
org.osgi.framework.BundleEvent.STARTED));
+            assertBundle("After installing a different bundle with same id " + 
installableResourceId, symbolicName2, "1.0", Bundle.ACTIVE);
+            assertNull("Test bundle must not be present after removing it", 
findBundle(symbolicName));
+        }
+    }
 }
\ No newline at end of file

Modified: 
sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/MockInstallableResource.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/MockInstallableResource.java?rev=1783196&r1=1783195&r2=1783196&view=diff
==============================================================================
--- 
sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/MockInstallableResource.java
 (original)
+++ 
sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/MockInstallableResource.java
 Thu Feb 16 10:43:39 2017
@@ -45,8 +45,8 @@ public class MockInstallableResource ext
                 InstallableResource.TYPE_BUNDLE, null);
     }
 
-    public MockInstallableResource(String uri, InputStream is, String digest, 
String type, Integer priority) {
-        super(uri, is,
+    public MockInstallableResource(String id, InputStream is, String digest, 
String type, Integer priority) {
+        super(id, is,
                 null, digest,
                 type != null ? type : InstallableResource.TYPE_BUNDLE, 
priority);
     }

Modified: 
sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/OsgiInstallerTestBase.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/OsgiInstallerTestBase.java?rev=1783196&r1=1783195&r2=1783196&view=diff
==============================================================================
--- 
sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/OsgiInstallerTestBase.java
 (original)
+++ 
sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/OsgiInstallerTestBase.java
 Thu Feb 16 10:43:39 2017
@@ -408,14 +408,17 @@ public class OsgiInstallerTestBase imple
     }
 
     protected InstallableResource[] getInstallableResource(File testBundle, 
String digest, int priority) throws IOException {
-        final String url = testBundle.getAbsolutePath();
+        return getInstallableResource(testBundle, 
testBundle.getAbsolutePath(), digest, priority);
+    }
+
+    protected InstallableResource[] getInstallableResource(File testBundle, 
String id, String digest, int priority) throws IOException {
         if (digest == null) {
             digest = String.valueOf(testBundle.lastModified());
         }
-        final InstallableResource result = new MockInstallableResource(url, 
new FileInputStream(testBundle), digest, null, priority);
+        final InstallableResource result = new MockInstallableResource(id, new 
FileInputStream(testBundle), digest, null, priority);
         return new InstallableResource[] {result};
     }
-
+    
     protected InstallableResource[] getInstallableResource(String configPid, 
Dictionary<String, Object> data) {
         return getInstallableResource(configPid, copy(data), 
InstallableResource.DEFAULT_PRIORITY);
     }


Reply via email to