Author: gnodet Date: Mon Oct 12 12:13:12 2009 New Revision: 824313 URL: http://svn.apache.org/viewvc?rev=824313&view=rev Log: FELIX-1682: the newly installed bundles for a feature shuld be uninstalled when feature install failed
Modified: felix/trunk/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/InstallFeatureCommand.java felix/trunk/karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeaturesService.java felix/trunk/karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/FeaturesServiceImpl.java Modified: felix/trunk/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/InstallFeatureCommand.java URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/InstallFeatureCommand.java?rev=824313&r1=824312&r2=824313&view=diff ============================================================================== --- felix/trunk/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/InstallFeatureCommand.java (original) +++ felix/trunk/karaf/features/command/src/main/java/org/apache/felix/karaf/features/command/InstallFeatureCommand.java Mon Oct 12 12:13:12 2009 @@ -16,6 +16,7 @@ */ package org.apache.felix.karaf.features.command; +import org.apache.felix.gogo.commands.Option; import org.apache.felix.karaf.features.FeaturesService; import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; @@ -23,16 +24,19 @@ @Command(scope = "features", name = "install", description = "Installs a feature with the specified name and version.") public class InstallFeatureCommand extends FeaturesCommandSupport { + private static String DEFAULT_VERSION = "0.0.0"; + @Argument(index = 0, name = "name", description = "The name of the feature", required = true, multiValued = false) String name; @Argument(index = 1, name = "version", description = "The version of the feature", required = false, multiValued = false) String version; + @Option(name = "-n", aliases = "--no-clean", description = "Do not uninstall bundles on failure", required = false, multiValued = false) + boolean noClean; protected void doExecute(FeaturesService admin) throws Exception { - if (version != null && version.length() > 0) { - admin.installFeature(name, version); - } else { - admin.installFeature(name); + if (version == null || version.length() == 0) { + version = DEFAULT_VERSION; } + admin.installFeature(name, version, !noClean); } } Modified: felix/trunk/karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeaturesService.java URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeaturesService.java?rev=824313&r1=824312&r2=824313&view=diff ============================================================================== --- felix/trunk/karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeaturesService.java (original) +++ felix/trunk/karaf/features/core/src/main/java/org/apache/felix/karaf/features/FeaturesService.java Mon Oct 12 12:13:12 2009 @@ -33,6 +33,8 @@ void installFeature(String name, String version) throws Exception; + void installFeature(String name, String version, boolean cleanIfFailure) throws Exception; + void uninstallFeature(String name) throws Exception; void uninstallFeature(String name, String version) throws Exception; Modified: felix/trunk/karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/FeaturesServiceImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/FeaturesServiceImpl.java?rev=824313&r1=824312&r2=824313&view=diff ============================================================================== --- felix/trunk/karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/FeaturesServiceImpl.java (original) +++ felix/trunk/karaf/features/core/src/main/java/org/apache/felix/karaf/features/internal/FeaturesServiceImpl.java Mon Oct 12 12:13:12 2009 @@ -196,16 +196,61 @@ } public void installFeature(String name, String version) throws Exception { + installFeature(name, version, true); + } + + public void installFeature(String name, String version, boolean cleanIfFailure) throws Exception { + InstallationState state = new InstallationState(); Feature f = getFeature(name, version); if (f == null) { - throw new Exception("No feature named '" + name + throw new Exception("No feature named '" + name + "' with version '" + version + "' available"); } - for (Feature dependency : f.getDependencies()) { - installFeature(dependency.getName(), dependency.getVersion()); + try { + // Install everything + doInstallFeature(state, f); + // Start all bundles + for (Bundle b : state.bundles) { + // do not start fragment bundles. + Dictionary d = b.getHeaders(); + String fragmentHostHeader = (String) d.get(Constants.FRAGMENT_HOST); + if (fragmentHostHeader == null || fragmentHostHeader.trim().length() == 0) { + b.start(); + } + } + } catch (Exception e) { + // uninstall everything + if (cleanIfFailure) { + for (Bundle b : state.bundles) { + b.uninstall(); + } + } + // rethrow exception + throw e; + } + callListeners(new FeatureEvent(f, FeatureEvent.EventType.FeatureInstalled, false)); + for (Map.Entry<Feature, Set<Long>> e : state.features.entrySet()) { + installed.put(e.getKey(), e.getValue()); } - for (String config : f.getConfigurations().keySet()) { - Dictionary<String,String> props = new Hashtable<String, String>(f.getConfigurations().get(config)); + saveState(); + } + + protected static class InstallationState { + final Set<Bundle> bundles = new HashSet<Bundle>(); + final Map<Feature, Set<Long>> features = new HashMap<Feature, Set<Long>>(); + } + + protected void doInstallFeature(InstallationState state, Feature feature) throws Exception { + for (Feature dependency : feature.getDependencies()) { + Feature f = getFeature(dependency.getName(), dependency.getVersion()); + if (f == null) { + throw new Exception("No feature named '" + dependency.getName() + + "' with version '" + dependency.getVersion() + "' available"); + } + doInstallFeature(state, f); + } + for (String config : feature.getConfigurations().keySet()) { + Dictionary<String,String> props = new Hashtable<String, String>(feature.getConfigurations().get(config)); String[] pid = parsePid(config); String key = (pid[1] == null ? pid[0] : pid[0] + "-" + pid[1]); props.put(CONFIG_KEY, key); @@ -216,25 +261,19 @@ cfg.update(props); } Set<Long> bundles = new HashSet<Long>(); - for (String bundleLocation : f.getBundles()) { - Bundle b = installBundleIfNeeded(bundleLocation); - bundles.add(b.getBundleId()); - } - for (long id : bundles) { - Bundle b = bundleContext.getBundle(id); - // do not start fragment bundles. - Dictionary d = b.getHeaders(); - String fragmentHostHeader = (String) d.get(Constants.FRAGMENT_HOST); - if (fragmentHostHeader == null || fragmentHostHeader.trim().length() == 0) { - b.start(); + for (String bundleLocation : feature.getBundles()) { + try { + Bundle b = installBundleIfNeeded(bundleLocation); + state.bundles.add(b); + bundles.add(b.getBundleId()); + } catch (BundleAlreadyInstalledException e) { + bundles.add(e.getBundle().getBundleId()); } } - callListeners(new FeatureEvent(f, FeatureEvent.EventType.FeatureInstalled, false)); - installed.put(f, bundles); - saveState(); + state.features.put(feature, bundles); } - protected Bundle installBundleIfNeeded(String bundleLocation) throws IOException, BundleException { + protected Bundle installBundleIfNeeded(String bundleLocation) throws IOException, BundleException, BundleAlreadyInstalledException { LOGGER.debug("Checking " + bundleLocation); InputStream is; try { @@ -256,7 +295,7 @@ Version bv = vStr == null ? Version.emptyVersion : Version.parseVersion(vStr); if (v.equals(bv)) { LOGGER.debug(" found installed bundle: " + b); - return b; + throw new BundleAlreadyInstalledException(b); } } } @@ -273,6 +312,18 @@ } } + protected static class BundleAlreadyInstalledException extends Exception { + private final Bundle bundle; + + public BundleAlreadyInstalledException(Bundle bundle) { + this.bundle = bundle; + } + + public Bundle getBundle() { + return bundle; + } + } + public void uninstallFeature(String name) throws Exception { List<String> versions = new ArrayList<String>(); for (Feature f : installed.keySet()) {