FELIX-2358: Hot undeployment of features does not uninstall all bundles
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@953156 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/deployer/features/src/main/java/org/apache/felix/karaf/deployer/features/FeatureDeploymentListener.java b/karaf/deployer/features/src/main/java/org/apache/felix/karaf/deployer/features/FeatureDeploymentListener.java
index 8203da6..53789fd 100644
--- a/karaf/deployer/features/src/main/java/org/apache/felix/karaf/deployer/features/FeatureDeploymentListener.java
+++ b/karaf/deployer/features/src/main/java/org/apache/felix/karaf/deployer/features/FeatureDeploymentListener.java
@@ -17,13 +17,13 @@
package org.apache.felix.karaf.deployer.features;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.net.URISyntaxException;
import java.net.URL;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -121,6 +121,7 @@
Bundle bundle = bundleEvent.getBundle();
if (bundleEvent.getType() == BundleEvent.RESOLVED) {
try {
+ List<URL> urls = new ArrayList<URL>();
Enumeration featuresUrlEnumeration = bundle.findEntries("/META-INF/" + FEATURE_PATH + "/", "*.xml", false);
while (featuresUrlEnumeration != null && featuresUrlEnumeration.hasMoreElements()) {
URL url = (URL) featuresUrlEnumeration.nextElement();
@@ -129,44 +130,99 @@
for (Repository repo : featuresService.listRepositories()) {
if (repo.getURI().equals(url.toURI())) {
Set<Feature> features = new HashSet<Feature>(Arrays.asList(repo.getFeatures()));
- featuresService.installFeatures(features, EnumSet.noneOf(FeaturesService.Option.class));
+ featuresService.installFeatures(features, EnumSet.noneOf(FeaturesService.Option.class));
}
}
+ urls.add(url);
} catch (Exception e) {
LOGGER.error("Unable to install features", e);
}
}
- } catch (Exception e) {
- // Ignore exceptions thrown when searching or iterating over the bundle entries
- }
- } else if (bundleEvent.getType() == BundleEvent.UNINSTALLED) {
- try {
- Enumeration featuresUrlEnumeration = bundle.findEntries("/META-INF/" + FEATURE_PATH + "/", "*.xml", false);
- while (featuresUrlEnumeration != null && featuresUrlEnumeration.hasMoreElements()) {
- URL url = (URL) featuresUrlEnumeration.nextElement();
- for (Repository repo : featuresService.listRepositories()) {
- try {
- if (repo.getURI().equals(url.toURI())) {
- for (Feature f : repo.getFeatures()) {
- try {
- featuresService.uninstallFeature(f.getName(), f.getVersion());
- } catch (Exception e) {
- LOGGER.error("Unable to uninstall feature: " + f.getName(), e);
- }
- }
+ synchronized (this) {
+ File file = bundleContext.getDataFile("FeatureDeploymentListener.cfg");
+ if (file != null) {
+ Properties props = new Properties();
+ if (file.exists()) {
+ InputStream input = new FileInputStream(file);
+ try {
+ props.load(input);
+ } finally {
+ input.close();
}
- } catch (Exception e) {
- LOGGER.error("Unable to uninstall features: " + url, e);
}
- }
- try {
- featuresService.removeRepository(url.toURI());
- } catch (URISyntaxException e) {
- LOGGER.error("Unable to remove repository: " + url, e);
+ String prefix = bundle.getSymbolicName() + "-" + bundle.getVersion();
+ props.put(prefix + ".count", Integer.toString(urls.size()));
+ for (int i = 0; i < urls.size(); i++) {
+ props.put(prefix + ".url." + i, urls.get(i).toExternalForm());
+ }
+ OutputStream output = new FileOutputStream(file);
+ try {
+ props.store(output, null);
+ } finally {
+ output.close();
+ }
}
}
} catch (Exception e) {
- // Ignore exceptions thrown when searching or iterating over the bundle entries
+ LOGGER.error("Unable to install deployed features for bundle: " + bundle.getSymbolicName() + " - " + bundle.getVersion(), e);
+ }
+ } else if (bundleEvent.getType() == BundleEvent.UNINSTALLED) {
+ try {
+ synchronized (this) {
+ File file = bundleContext.getDataFile("FeatureDeploymentListener.cfg");
+ if (file != null) {
+ Properties props = new Properties();
+ if (file.exists()) {
+ InputStream input = new FileInputStream(file);
+ try {
+ props.load(input);
+ } finally {
+ input.close();
+ }
+ }
+ String prefix = bundle.getSymbolicName() + "-" + bundle.getVersion();
+ String countStr = (String) props.get(prefix + ".count");
+ if (countStr != null) {
+ int count = Integer.parseInt(countStr);
+ for (int i = 0; i < count; i++) {
+ URL url = new URL((String) props.get(prefix + ".url." + i));
+ for (Repository repo : featuresService.listRepositories()) {
+ try {
+ if (repo.getURI().equals(url.toURI())) {
+ for (Feature f : repo.getFeatures()) {
+ try {
+ featuresService.uninstallFeature(f.getName(), f.getVersion());
+ } catch (Exception e) {
+ LOGGER.error("Unable to uninstall feature: " + f.getName(), e);
+ }
+ }
+ }
+ } catch (Exception e) {
+ LOGGER.error("Unable to uninstall features: " + url, e);
+ }
+ }
+ try {
+ featuresService.removeRepository(url.toURI());
+ } catch (URISyntaxException e) {
+ LOGGER.error("Unable to remove repository: " + url, e);
+ }
+ }
+ }
+ for (Iterator<Object> it = props.keySet().iterator(); it.hasNext();) {
+ if (it.next().toString().startsWith(prefix + ".")) {
+ it.remove();
+ }
+ }
+ OutputStream output = new FileOutputStream(file);
+ try {
+ props.store(output, null);
+ } finally {
+ output.close();
+ }
+ }
+ }
+ } catch (Exception e) {
+ LOGGER.error("Unable to uninstall deployed features for bundle: " + bundle.getSymbolicName() + " - " + bundle.getVersion(), e);
}
}
}