use of org.apache.felix.fileinstall.ArtifactInstaller in project felix by apache.
the class InstallerIntegrationTest method testInstallArchives.
/*
* This is a complex case that tests the interplay of multiple archives with
* overlapping content.
*
* - Archive 1 contains bundles A and B.
*
* - Archive 2 contains bundles A and C.
*
* The process is as follows:
*
* i. Make installer aware of both archives. Both now present as an
* installable unit with 2 artifacts (A+B and A+C).
*
* ii. Install archive 1.
* Archive 2 gets invalidated and re-resolved. It now presents as an
* installable unit with 1 artifact (C) because A is already in the
* framework.
*
* iii. Remove archive 1. Archive 2 gets invalidated and
* re-resolved. It now presents as an installable unit with 2 artifacts
* (A+C) because A is no longer in the framework.
*
* Note that step (iii) is equivalent to deleting the archive from
* FileInstall's load directory. Therefore it doesn't reappear as a RESOLVED
* installable unit. To reinstall this archive, the user would have to copy
* it back into the load directory.
*
*/
@Test
public void testInstallArchives() throws Exception {
// Register InstallableListener
EventQueue eventQueue = new EventQueue();
ServiceRegistration<InstallableListener> mockListenerReg = this.bundleContext.registerService(InstallableListener.class, eventQueue, null);
try {
assertEquals("Shouldn't be any install events yet", 0, eventQueue.depth());
InstallableUnitEvent event;
// Provide the sample archive
File sampleArchive1 = new File(this.dataDir, "valid1.bar");
ArtifactInstaller installer = this.artifactInstallerTracker.getService();
assertNotNull("ArtifactInstaller service should exist", installer);
assertTrue("installer should handle sample archive", installer.canHandle(sampleArchive1));
installer.install(sampleArchive1);
// Wait for resolve to occur
Thread.sleep(2000);
assertEquals(1, eventQueue.depth());
event = eventQueue.pop();
InstallableUnit unit1 = event.getUnit();
assertEquals(State.RESOLVED, event.getNewState());
assertEquals("samples.valid1", event.getUnit().getSymbolicName());
assertEquals("samples.valid1 requires 2 bundles to be installed", 2, event.getUnit().getArtifacts().size());
// Add a second archive
File sampleArchive2 = new File(this.dataDir, "valid2.bar");
assertTrue("installer should handle sample archive", installer.canHandle(sampleArchive2));
installer.install(sampleArchive2);
// Wait for resolve to occur
Thread.sleep(2000);
assertEquals(1, eventQueue.depth());
event = eventQueue.pop();
assertEquals(State.RESOLVED, event.getNewState());
assertEquals("samples.valid2", event.getUnit().getSymbolicName());
assertEquals("samples.valid2 requires 2 bundles to be installed", 2, event.getUnit().getArtifacts().size());
// Install first archive.
unit1.install().getValue();
// Check bundles were actually installed!
assertNotNull(findBundle("org.example.a"));
assertNotNull(findBundle("org.example.b"));
// The installation of first archive should cause invalidation of second archive resolution result, followed by re-resolve.
// First, installing #1
event = eventQueue.pop();
assertEquals(State.INSTALLING, event.getNewState());
assertEquals("samples.valid1", event.getUnit().getSymbolicName());
// Next installed #1
event = eventQueue.pop();
assertEquals(State.INSTALLED, event.getNewState());
assertEquals("samples.valid1", event.getUnit().getSymbolicName());
// Next removed #2 (due to invalidation)
// Short sleep necessary because the invalidate can happen on another thread (eg framework refresh)
Thread.sleep(500);
event = eventQueue.pop();
assertEquals(State.REMOVED, event.getNewState());
assertEquals("samples.valid2", event.getUnit().getSymbolicName());
// Next resolved #2 (re-resolve after invalidation)
// Another sleep because the re-resolve happens after at least 1 sec delay
Thread.sleep(2000);
event = eventQueue.pop();
assertEquals(State.RESOLVED, event.getNewState());
assertEquals("samples.valid2", event.getUnit().getSymbolicName());
assertEquals("samples.valid2 now requires 1 bundle to be installed", 1, event.getUnit().getArtifacts().size());
assertEquals(0, eventQueue.depth());
// Now uninstall first archive
installer.uninstall(sampleArchive1);
Thread.sleep(500);
// Check bundles were actually uninstalled!
assertNull(findBundle("org.example.a"));
assertNull(findBundle("org.example.b"));
// Removed event for #1
Thread.sleep(500);
event = eventQueue.pop();
assertEquals(State.REMOVED, event.getNewState());
assertEquals("samples.valid1", event.getUnit().getSymbolicName());
// Removed event for #2 due to invalidation
event = eventQueue.pop();
assertEquals(State.REMOVED, event.getNewState());
assertEquals("samples.valid2", event.getUnit().getSymbolicName());
// Re-resolution of #2 after a little sleep
Thread.sleep(2000);
event = eventQueue.pop();
assertEquals(State.RESOLVED, event.getNewState());
assertEquals("samples.valid2", event.getUnit().getSymbolicName());
assertEquals("samples.valid2 now requires 2 bundle to be installed", 2, event.getUnit().getArtifacts().size());
assertEquals(0, eventQueue.depth());
} finally {
mockListenerReg.unregister();
}
}
use of org.apache.felix.fileinstall.ArtifactInstaller in project felix by apache.
the class DirectoryWatcher method install.
/**
* Install an artifact and return the bundle object.
* It uses {@link Artifact#getPath()} as location
* of the new bundle. Before installing a file,
* it sees if the file has been identified as a bad file in
* earlier run. If yes, then it compares to see if the file has changed
* since then. It installs the file if the file has changed.
* If the file has not been identified as a bad file in earlier run,
* then it always installs it.
*
* @param artifact the artifact to be installed
* @return Bundle object that was installed
*/
private Bundle install(Artifact artifact) {
File path = artifact.getPath();
Bundle bundle = null;
AtomicBoolean modified = new AtomicBoolean();
try {
// If the listener is an installer, ask for an update
if (artifact.getListener() instanceof ArtifactInstaller) {
((ArtifactInstaller) artifact.getListener()).install(path);
} else // if the listener is an url transformer
if (artifact.getListener() instanceof ArtifactUrlTransformer) {
Artifact badArtifact = installationFailures.get(path);
if (badArtifact != null && badArtifact.getChecksum() == artifact.getChecksum()) {
// Don't attempt to install it; nothing has changed.
return null;
}
URL transformed = artifact.getTransformedUrl();
String location = transformed.toString();
BufferedInputStream in = new BufferedInputStream(transformed.openStream());
bundle = installOrUpdateBundle(location, in, artifact.getChecksum(), modified);
artifact.setBundleId(bundle.getBundleId());
} else // if the listener is an artifact transformer
if (artifact.getListener() instanceof ArtifactTransformer) {
Artifact badArtifact = installationFailures.get(path);
if (badArtifact != null && badArtifact.getChecksum() == artifact.getChecksum()) {
// Don't attempt to install it; nothing has changed.
return null;
}
File transformed = artifact.getTransformed();
String location = path.toURI().normalize().toString();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(transformed != null ? transformed : path));
bundle = installOrUpdateBundle(location, in, artifact.getChecksum(), modified);
artifact.setBundleId(bundle.getBundleId());
}
installationFailures.remove(path);
setArtifact(path, artifact);
} catch (Exception e) {
log(Logger.LOG_ERROR, "Failed to install artifact: " + path, e);
// Add it our bad jars list, so that we don't
// attempt to install it again and again until the underlying
// jar has been modified.
installationFailures.put(path, artifact);
}
return modified.get() ? bundle : null;
}
use of org.apache.felix.fileinstall.ArtifactInstaller in project felix by apache.
the class InstallerIntegrationTest method testErrorFromInvalidArchive.
@Test
public void testErrorFromInvalidArchive() throws Exception {
Object[] artifactInstallers = this.artifactInstallerTracker.getServices();
assertNotNull("Should be exactly one ArtifactInstaller service", artifactInstallers);
assertEquals("Should be exactly one ArtifactInstaller service", 1, artifactInstallers.length);
// Register mock InstallableListener
List<String> installEvents = new LinkedList<>();
InstallableListener mockInstallListener = new InstallableListener() {
@Override
public void installableUnitsChanged(Collection<InstallableUnitEvent> events) {
for (InstallableUnitEvent event : events) {
String message = String.format("%s %s", event.getNewState(), event.getUnit().getSymbolicName());
installEvents.add(message);
}
}
};
ServiceRegistration<InstallableListener> mockListenerReg = this.bundleContext.registerService(InstallableListener.class, mockInstallListener, null);
try {
assertEquals("Shouldn't be any install events yet", 0, installEvents.size());
// Provide the sample archive
File sampleArchive = new File(this.dataDir, "org.example.invalid-missing-rb.bar");
ArtifactInstaller installer = this.artifactInstallerTracker.getService();
assertTrue("installer should handle sample archive", installer.canHandle(sampleArchive));
installer.install(sampleArchive);
// Wait for resolve to occur
Thread.sleep(2000);
assertEquals(1, installEvents.size());
assertEquals("ERROR org.example.invalid-missing-rb", installEvents.get(0));
} finally {
mockListenerReg.unregister();
}
}
use of org.apache.felix.fileinstall.ArtifactInstaller in project felix by apache.
the class InstallerIntegrationTest method before.
@Before
public void before() throws Exception {
assertAllBundlesResolved();
// Track ArtifactInstaller service ONLY from bundle org.apache.felix.fileinstall.plugins.installer, to avoid potential interference
Bundle installerBundle = findBundle("org.apache.felix.fileinstall.plugins.installer");
Filter artifactInstallerTrackerFilter = FrameworkUtil.createFilter(String.format("(&(objectClass=%s)(service.bundleid=%d))", ArtifactInstaller.class.getName(), installerBundle.getBundleId()));
this.artifactInstallerTracker = new ServiceTracker<>(this.bundleContext, artifactInstallerTrackerFilter, null);
this.artifactInstallerTracker.open();
// Wait up to 5 seconds for ArtifactInstaller to appear
ArtifactInstaller artifactInstaller = this.artifactInstallerTracker.waitForService(5000);
if (artifactInstaller == null) {
fail("ArtifactInstaller service not available within 5 seconds");
}
this.fwkInstallerTracker = new ServiceTracker<>(this.bundleContext, FrameworkInstaller.class, null);
this.fwkInstallerTracker.open();
}
use of org.apache.felix.fileinstall.ArtifactInstaller in project felix by apache.
the class DirectoryWatcher method uninstall.
/**
* Uninstall a jar file.
*/
private Bundle uninstall(Artifact artifact) {
Bundle bundle = null;
try {
File path = artifact.getPath();
// Find a listener for this artifact if needed
if (artifact.getListener() == null) {
artifact.setListener(findListener(path, fileInstall.getListeners()));
}
// Forget this artifact
removeArtifact(path);
// Delete transformed file
deleteTransformedFile(artifact);
// if the listener is an installer, uninstall the artifact
if (artifact.getListener() instanceof ArtifactInstaller) {
((ArtifactInstaller) artifact.getListener()).uninstall(path);
} else // else we need uninstall the bundle
if (artifact.getBundleId() != 0) {
// old can't be null because of the way we calculate deleted list.
bundle = context.getBundle(artifact.getBundleId());
if (bundle == null) {
log(Logger.LOG_WARNING, "Failed to uninstall bundle: " + path + " with id: " + artifact.getBundleId() + ". The bundle has already been uninstalled", null);
return null;
}
log(Logger.LOG_INFO, "Uninstalling bundle " + bundle.getBundleId() + " (" + bundle.getSymbolicName() + ")", null);
bundle.uninstall();
}
} catch (Exception e) {
log(Logger.LOG_WARNING, "Failed to uninstall artifact: " + artifact.getPath(), e);
}
return bundle;
}
Aggregations