[FELIX-4436] DirectoryWatcher should not refresh transformed bundles on every start-up
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1578984 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
index 7ceaad1..469be28 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
@@ -848,13 +848,33 @@
// Let's try to interpret the location as a file path
uri = new File(location).toURI().normalize();
}
- path = uri.getPath();
+ if (uri.isOpaque() && uri.getSchemeSpecificPart() != null)
+ {
+ // blueprint:file:/tmp/foo/baa.jar -> file:/tmp/foo/baa.jar
+ // blueprint:mvn:foo.baa/baa/0.0.1 -> mvn:foo.baa/baa/0.0.1
+ // wrap:file:/tmp/foo/baa-1.0.jar$Symbolic-Name=baa&Version=1.0 -> file:/tmp/foo/baa-1.0.jar$Symbolic-Name=baa&Version1.0
+ final String schemeSpecificPart = uri.getSchemeSpecificPart();
+ // extract content behind the 'file:' protocol of scheme specific path
+ final int lastIndexOfFileProtocol = schemeSpecificPart.lastIndexOf("file:");
+ final int offsetFileProtocol = lastIndexOfFileProtocol >= 0 ? lastIndexOfFileProtocol + "file:".length() : 0;
+ final int firstIndexOfDollar = schemeSpecificPart.indexOf("$");
+ final int endOfPath = firstIndexOfDollar >= 0 ? firstIndexOfDollar : schemeSpecificPart.length();
+ // file:/tmp/foo/baa.jar -> /tmp/foo/baa.jar
+ // mvn:foo.baa/baa/0.0.1 -> mvn:foo.baa/baa/0.0.1
+ // file:/tmp/foo/baa-1.0.jar$Symbolic-Name=baa&Version=1.0 -> /tmp/foo/baa-1.0.jar
+ path = schemeSpecificPart.substring(offsetFileProtocol, endOfPath);
+ }
+ else
+ {
+ // file:/tmp/foo/baa.jar -> /tmp/foo/baa.jar
+ // mnv:foo.baa/baa/0.0.1 -> foo.baa/baa/0.0.1
+ path = uri.getPath();
+ }
}
if (path == null)
{
// jar.getPath is null means we could not parse the location
- // as a meaningful URI or file path. e.g., location
- // represented an Opaque URI.
+ // as a meaningful URI or file path.
// We can't do any meaningful processing for this bundle.
continue;
}
diff --git a/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/DirectoryWatcherTest.java b/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/DirectoryWatcherTest.java
index 63fe969..56750a6 100644
--- a/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/DirectoryWatcherTest.java
+++ b/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/DirectoryWatcherTest.java
@@ -20,14 +20,20 @@
import java.io.File;
+import java.net.URISyntaxException;
import java.util.Dictionary;
+import java.util.HashSet;
import java.util.Hashtable;
-
+import java.util.Map;
+import java.util.Set;
import junit.framework.TestCase;
+import org.apache.felix.fileinstall.ArtifactListener;
import org.easymock.EasyMock;
+import org.junit.Assert;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleListener;
+import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
import org.osgi.service.packageadmin.PackageAdmin;
@@ -51,7 +57,7 @@
super.setUp();
mockBundleContext = (BundleContext) EasyMock.createMock(BundleContext.class);
mockPackageAdmin = (PackageAdmin) EasyMock.createMock(PackageAdmin.class);
- mockBundle = (Bundle) EasyMock.createMock(Bundle.class);
+ mockBundle = (Bundle) EasyMock.createNiceMock(Bundle.class);
props.put( DirectoryWatcher.DIR, new File( "target/load" ).getAbsolutePath() );
// Might get called, but most of the time it doesn't matter whether they do or don't.
@@ -253,5 +259,180 @@
}
}
+ /**
+ * Test the {@link DirectoryWatcher#initializeCurrentManagedBundles()} in conjunction with a non opaque Bundle Location.
+ * Assert that a new created {@link Artifact} will be added into the {@link DirectoryWatcher#currentManagedArtifacts}.
+ *
+ * The {@link DirectoryWatcher#process(java.util.Set)} execution will not be called.
+ * This test breaks the execution in {@link Scanner#initialize(java.util.Map)}.
+ * @throws URISyntaxException
+ */
+ public void testInitializeCurrentManagedBundlesNonOpaqueURIOnBundleLocation() throws URISyntaxException
+ {
+ final RuntimeException expectedException = new RuntimeException("expected exception to break execution on defined point.");
+ final File watchedDirectoryFile = new File("src/test/resources/watched");
+ final String watchedDirectoryPath = watchedDirectoryFile.getAbsolutePath();
+
+ final String bundleFileName = "firstjar.jar";
+ final File bundleFile = new File(watchedDirectoryPath,bundleFileName);
+ final String bundleLocation = "file:"+watchedDirectoryPath+'/'+bundleFileName;
+
+ // break execution
+ final Scanner scanner = new Scanner(watchedDirectoryFile)
+ {
+ public void initialize(Map checksums)
+ {
+ throw expectedException;
+ }
+ };
+
+ mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
+ EasyMock.expect(mockBundleContext.getBundles()).andReturn(new Bundle[]{mockBundle});
+ EasyMock.expect(mockBundleContext.getDataFile((String) EasyMock.anyObject())).andReturn(null).anyTimes();
+ EasyMock.expect(mockBundle.getLocation()).andReturn(bundleLocation).anyTimes();
+ final Map mockCurrentManagedArtifacts = (Map)EasyMock.createNiceMock(Map.class);
+ EasyMock.expect(mockCurrentManagedArtifacts.put(EasyMock.eq(bundleFile), (Artifact)EasyMock.anyObject())).andReturn(null).times(1);
+
+ EasyMock.replay(new Object[]{mockBundleContext, mockBundle, mockCurrentManagedArtifacts});
+
+ props.put(DirectoryWatcher.DIR, watchedDirectoryPath);
+
+ dw = new DirectoryWatcher(props, mockBundleContext);
+ dw.noInitialDelay = true;
+ dw.currentManagedArtifacts = mockCurrentManagedArtifacts;
+ dw.scanner = scanner;
+ try {
+ dw.start();
+ }
+ catch(RuntimeException e)
+ {
+ assertEquals(e, expectedException);
+ }
+
+ EasyMock.verify(new Object[]{mockBundleContext, mockBundle, mockCurrentManagedArtifacts});
+ }
+
+ /**
+ * Test the {@link DirectoryWatcher#initializeCurrentManagedBundles()} in conjunction with a opaque Bundle Location.
+ * Assert that a new created {@link Artifact} will be added into the {@link DirectoryWatcher#currentManagedArtifacts}.
+ *
+ * The {@link DirectoryWatcher#process(java.util.Set)} execution will not be called.
+ * This test breaks the execution in {@link Scanner#initialize(java.util.Map)}.
+ * @throws URISyntaxException
+ */
+ public void testInitializeCurrentManagedBundlesOpaqueURIOnBundleLocation() throws URISyntaxException
+ {
+ final RuntimeException expectedException = new RuntimeException("expected exception to break execution on defined point.");
+ final File watchedDirectoryFile = new File("src/test/resources/watched");
+ final String watchedDirectoryPath = watchedDirectoryFile.getAbsolutePath();
+
+ final String bundleFileName = "firstjar.jar";
+ final File bundleFile = new File(watchedDirectoryPath,bundleFileName);
+ final String bundleLocation = "blueprint:file:"+watchedDirectoryPath+'/'+bundleFileName+"$Bundle-SymbolicName=foo&Bundle-Version=1.0";
+
+ // break execution
+ Scanner scanner = new Scanner(watchedDirectoryFile)
+ {
+ public void initialize(Map checksums)
+ {
+ throw expectedException;
+ }
+ };
+
+ mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
+ EasyMock.expect(mockBundleContext.getBundles()).andReturn(new Bundle[]{mockBundle});
+ EasyMock.expect(mockBundleContext.getDataFile((String) EasyMock.anyObject())).andReturn(null).anyTimes();
+ EasyMock.expect(mockBundle.getLocation()).andReturn(bundleLocation).anyTimes();
+ Map mockCurrentManagedArtifacts = (Map)EasyMock.createNiceMock(Map.class);
+ EasyMock.expect(mockCurrentManagedArtifacts.put(EasyMock.eq(bundleFile), (Artifact)EasyMock.anyObject())).andReturn(null).times(1);
+
+ EasyMock.replay(new Object[]{mockBundleContext, mockBundle, mockCurrentManagedArtifacts});
+
+ props.put(DirectoryWatcher.DIR, watchedDirectoryPath);
+
+ dw = new DirectoryWatcher(props, mockBundleContext);
+ dw.noInitialDelay = true;
+ dw.currentManagedArtifacts = mockCurrentManagedArtifacts;
+ dw.scanner = scanner;
+ try {
+ dw.start();
+ }
+ catch(RuntimeException e)
+ {
+ assertEquals(e, expectedException);
+ }
+
+ EasyMock.verify(new Object[]{mockBundleContext, mockBundle, mockCurrentManagedArtifacts});
+ }
+
+ /**
+ * Test the {@link DirectoryWatcher#process(java.util.Set) } in conjunction with a opaque Bundle Location.
+ * Assert that no bundle refresh will be called.
+ * @throws URISyntaxException
+ */
+ public void testProcessOpaqueURIOnBundleLocation() throws URISyntaxException
+ {
+ final RuntimeException expectedException = new RuntimeException("expected exception to break execution on defined point.");
+ final File watchedDirectoryFile = new File("src/test/resources/watched");
+ final String watchedDirectoryPath = watchedDirectoryFile.getAbsolutePath();
+
+ final String bundleFileName = "firstjar.jar";
+ final File bundleFile = new File(watchedDirectoryPath,bundleFileName);
+ final String bundleLocation = "blueprint:file:"+watchedDirectoryPath+'/'+bundleFileName;
+
+ final Scanner scanner = new Scanner(watchedDirectoryFile)
+ {
+ // bypass filesystem scan and return expected bundle file
+ public Set/*<File>*/ scan(boolean reportImmediately)
+ {
+ Set/*<File>*/ fileSet = new HashSet/*<File>*/(1);
+ fileSet.add(bundleFile);
+ return fileSet;
+ }
+ };
+
+ final ArtifactListener mockArtifactListener = (ArtifactListener) EasyMock.createNiceMock(ArtifactListener.class);
+ EasyMock.expect(Boolean.valueOf(mockArtifactListener.canHandle(bundleFile))).andReturn(Boolean.TRUE).anyTimes();
+ final ServiceReference mockServiceReference = (ServiceReference) EasyMock.createNiceMock(ServiceReference.class);
+
+ // simulate known/installed bundles
+ mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
+ EasyMock.expect(mockBundleContext.getBundles()).andReturn(new Bundle[]{mockBundle});
+ EasyMock.expect(mockBundleContext.getDataFile((String) EasyMock.anyObject())).andReturn(null).anyTimes();
+ EasyMock.expect(mockBundle.getLocation()).andReturn(bundleLocation).anyTimes();
+
+ EasyMock.replay(new Object[]{mockBundleContext, mockBundle,mockServiceReference, mockArtifactListener});
+
+ final Artifact artifact = new Artifact();
+ artifact.setBundleId(42);
+ artifact.setChecksum(0);
+ artifact.setListener(mockArtifactListener);
+ artifact.setPath(bundleFile);
+
+ FileInstall.listeners.put(mockServiceReference, mockArtifactListener);
+
+ props.put(DirectoryWatcher.DIR, watchedDirectoryPath);
+
+ dw = new DirectoryWatcher(props, mockBundleContext) {
+
+ void refresh(Bundle[] bundles) throws InterruptedException {
+ Assert.fail("bundle refresh called");
+ }
+
+ };
+ dw.noInitialDelay = true;
+ // add expected bundle and artifact to the current managed artifacts
+ dw.currentManagedArtifacts.put(bundleFile, artifact);
+ dw.scanner = scanner;
+ try {
+ dw.start();
+ }
+ catch(RuntimeException e)
+ {
+ assertEquals(e, expectedException);
+ }
+
+ EasyMock.verify(new Object[]{mockBundleContext, mockBundle,mockServiceReference, mockArtifactListener});
+ }
}