You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2012/08/21 17:45:23 UTC

svn commit: r1375615 - in /sling/trunk/installer/core/src: main/java/org/apache/sling/installer/core/impl/util/RefreshDependenciesUtil.java test/java/org/apache/sling/installer/core/impl/util/RefreshDependenciesUtilTest.java

Author: bdelacretaz
Date: Tue Aug 21 15:45:23 2012
New Revision: 1375615

URL: http://svn.apache.org/viewvc?rev=1375615&view=rev
Log:
SLING-2567 - reimplemented using PackageAdmin.getExportedPackages(...), thanks Felix for the pointers

Modified:
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/util/RefreshDependenciesUtil.java
    sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/util/RefreshDependenciesUtilTest.java

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/util/RefreshDependenciesUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/util/RefreshDependenciesUtil.java?rev=1375615&r1=1375614&r2=1375615&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/util/RefreshDependenciesUtil.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/util/RefreshDependenciesUtil.java Tue Aug 21 15:45:23 2012
@@ -18,13 +18,10 @@
  */
 package org.apache.sling.installer.core.impl.util;
 
-import java.util.HashSet;
+import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 
-import org.apache.sling.commons.osgi.ManifestHeader;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.Constants;
 import org.osgi.service.packageadmin.ExportedPackage;
 import org.osgi.service.packageadmin.PackageAdmin;
 import org.slf4j.Logger;
@@ -40,71 +37,56 @@ class RefreshDependenciesUtil {
         this.pckAdmin = pa;
     }
 
-    private Set<String> getImportPackages(final Bundle bundle) {
-        final Set<String> packages = new HashSet<String>();
-        final String imports = (String)bundle.getHeaders().get(Constants.IMPORT_PACKAGE);
-        if(imports != null) {
-            final ManifestHeader header = ManifestHeader.parse(imports);
-            for(final ManifestHeader.Entry entry : header.getEntries()) {
-                packages.add(entry.getValue());
-            }
-        }
-        return packages;
-    }
-
     /**
      * Check whether a packages refresh of the supplied bundles would affect targetBundle
      */
-    boolean isBundleAffected(Bundle targetBundle, final List<Bundle> bundles) {
-        final Set<Long> checkedId = new HashSet<Long>();
-        final boolean result = isBundleAffected(checkedId, targetBundle, bundles);
-        log.debug("isBundleAffected({}, {}) -> {}", new Object[] { targetBundle, bundles, result});
-        return result;
+    boolean isBundleAffected(Bundle target, final List<Bundle> bundles) {
+        log.debug("isBundleAffected({}, {})", target, bundles);
+     
+        final List<Long> idChecked = new ArrayList<Long>();
+        for(Bundle b : bundles) {
+            if(dependsOn(idChecked, target, b)) {
+                log.debug("isBundleAffected({}) is true, dependency on bundle {}", target, b);
+                return true;
+            }
+        }
+        
+        log.debug("isBundleAffected({}) is false, no dependencies on {}", target, bundles);
+        return false;
     }
     
-    private boolean isBundleAffected(Set<Long> checkedId, Bundle targetBundle, final List<Bundle> bundles) {
+    /** True if target depends on source via package imports */
+    private boolean dependsOn(List<Long> idChecked, Bundle target, Bundle source) {
         
-        // Avoid cycles
-        if(checkedId.contains(targetBundle.getBundleId())) {
+        if(idChecked.contains(source.getBundleId())) {
             return false;
         }
-        checkedId.add(targetBundle.getBundleId());
-        log.debug("Checking if {} is affected by {}", targetBundle, bundles);
+        idChecked.add(source.getBundleId());
         
-        // ID of bundles that we check against
-        final Set<Long> ids = new HashSet<Long>();
-        for(final Bundle b : bundles) {
-            ids.add(b.getBundleId());
+        final ExportedPackage [] eps = pckAdmin.getExportedPackages(source);
+        if(eps == null) {
+            return false;
         }
         
-        // Find all bundles from which we import packages, return true if one of them is in our bundles list,
-        // and call this method recursively on them as well.
-        // We don't care about possible duplicates in there, will be removed by the above cycle avoidance code.
-        for(final String name : getImportPackages(targetBundle)) {
-            final ExportedPackage[] pcks = this.pckAdmin.getExportedPackages(name);
-            if ( pcks == null ) {
-                log.debug("No bundles present that export {}", name);
-            } else {
-                log.debug("{} imports {}", targetBundle, name);
-                for(final ExportedPackage pck : pcks) {
-                    final Bundle exportingBundle = pck.getExportingBundle();
-                    log.debug("Checking {} which exports {}", exportingBundle, pck.getName());
-                    if ( exportingBundle.getBundleId() == 0 || exportingBundle.getBundleId() == targetBundle.getBundleId() ) {
-                        log.debug("Exporting bundle {} is framework bundle or self, ignored", exportingBundle);
-                        continue;
-                    } else if ( ids.contains(exportingBundle.getBundleId()) ) {
-                        log.debug("Bundle {} affects {} due to package {}, returning true", 
-                                new Object[] { exportingBundle, targetBundle, pck.getName() });
-                        return true;
-                    } else if(isBundleAffected(checkedId, exportingBundle, bundles)) {
-                        log.debug("{} recursively affects {}, returning true", exportingBundle, targetBundle); 
-                        return true;
-                    }
-                    log.debug("{} does not affect {}", exportingBundle, targetBundle); 
+        for(ExportedPackage ep : eps) {
+            final Bundle [] importers = ep.getImportingBundles();
+            if(importers == null) {
+                continue;
+            }
+            for(Bundle b : importers) {
+                if(b.getBundleId() == target.getBundleId()) {
+                    log.debug("{} depends on {} via package {}", 
+                            new Object[] { target, source, ep.getName() });
+                    return true;
+                }
+                if(dependsOn(idChecked, target, b)) {
+                    log.debug("{} depends on {} which depends on {}, returning true",
+                            new Object[] { target, b, source });
+                    return true;
                 }
             }
         }
-
+        
         return false;
     }
 }
\ No newline at end of file

Modified: sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/util/RefreshDependenciesUtilTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/util/RefreshDependenciesUtilTest.java?rev=1375615&r1=1375614&r2=1375615&view=diff
==============================================================================
--- sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/util/RefreshDependenciesUtilTest.java (original)
+++ sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/util/RefreshDependenciesUtilTest.java Tue Aug 21 15:45:23 2012
@@ -22,16 +22,15 @@ import static org.junit.Assert.assertFal
 import static org.junit.Assert.assertTrue;
 
 import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.Hashtable;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.jmock.Expectations;
 import org.jmock.Mockery;
 import org.junit.Before;
 import org.junit.Test;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.Constants;
 import org.osgi.service.packageadmin.ExportedPackage;
 import org.osgi.service.packageadmin.PackageAdmin;
 
@@ -44,65 +43,91 @@ public class RefreshDependenciesUtilTest
     private Bundle C;
     private Bundle D;
     private Bundle E;
+    private Bundle F;
     private PackageAdmin pa;
     private RefreshDependenciesUtil rdu;
     private long counter = 1;
     
+    private final Map<String, List<Bundle>> importingBundles = new HashMap<String, List<Bundle>>();
+    
     private Bundle setupBundle(String mockName, String importPackages, final String exportsPackages) {
         final Bundle result = jmock.mock(Bundle.class, mockName);
         
-        final Dictionary<Object, Object> headers = new Hashtable<Object, Object>();
-        if(importPackages != null) {
-            headers.put(Constants.IMPORT_PACKAGE, importPackages);
-        }
-        
         jmock.checking(new Expectations() {{
             allowing(result).getBundleId();
             will(returnValue(counter++));
-            
-            allowing(result).getHeaders();
-            will(returnValue(headers));
         }});
         
+        if(importPackages != null) {
+            for(String pack : importPackages.split(";")) {
+                List<Bundle> list = importingBundles.get(pack);
+                if(list == null) {
+                    list = new ArrayList<Bundle>();
+                    importingBundles.put(pack, list);
+                }
+                list.add(result);
+            }
+        }
+
         final List<ExportedPackage> eps = new ArrayList<ExportedPackage>();
-        
         if(exportsPackages != null) {
-            final ExportedPackage ep = jmock.mock(ExportedPackage.class, "ExportedPackage" + mockName);
-            eps.add(ep);
-            jmock.checking(new Expectations() {{
-                allowing(ep).getExportingBundle();
-                will(returnValue(result));
-                allowing(ep).getName();
-                will(returnValue(exportsPackages));
-            }});
+            for(final String pack : exportsPackages.split(";")) {
+                final ExportedPackage ep = jmock.mock(ExportedPackage.class, "ExportedPackage." + pack + "." + mockName);
+                eps.add(ep);
+                jmock.checking(new Expectations() {{
+                    allowing(ep).getImportingBundles();
+                    will(returnValue(getImportingBundles(pack)));
+                    allowing(ep).getName();
+                    will(returnValue(pack));
+                }});
+            }
         }
             
         jmock.checking(new Expectations() {{
-            allowing(pa).getExportedPackages(exportsPackages);
+            allowing(pa).getExportedPackages(result);
             will(returnValue(eps.toArray(new ExportedPackage[]{})));
         }});
         
         return result;
     }
     
+    private Bundle [] getImportingBundles(String packageName) {
+        final List<Bundle> list = importingBundles.get(packageName);
+        if(list == null) {
+            return null;
+        } else {
+            return list.toArray(new Bundle[] {});
+        }
+    }
+    
     @Before
     public void setup() {
         jmock = new Mockery();
         pa = jmock.mock(PackageAdmin.class);
         rdu = new RefreshDependenciesUtil(pa);
         
-        // Target depends on A directly and does not depend on B
-        target = setupBundle("testTarget", "com.targetImportsOne;com.targetImportsTwo", null);
+        // Test bundle depends on A directly and does not depend on B
+        target = setupBundle("testBundle", "com.targetImportsOne;com.targetImportsTwo", null);
         A = setupBundle("A", null, "com.targetImportsOne");
         B = setupBundle("B", "some.import", "some.export");
         
-        // Target depends on C which in turns depends on D
+        // Test bundle depends on C which in turns depends on D
         C = setupBundle("C", "com.CimportsOne", "com.targetImportsTwo");
         D = setupBundle("D", null, "com.CimportsOne");
         E = setupBundle("E", null, null);
+        
+        // F imports and exports the same packages
+        F = setupBundle("F", "foo", "foo");
     }
     
     @Test
+    public void testTargetDependsOnSelf() {
+        final List<Bundle> bundles = new ArrayList<Bundle>();
+        bundles.add(F);
+        assertTrue(rdu.isBundleAffected(F, bundles));
+    }
+        
+    @Test
     public void testTargetDependsOnBundleA() {
         final List<Bundle> bundles = new ArrayList<Bundle>();
         bundles.add(A);