You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by gn...@apache.org on 2009/10/12 14:13:12 UTC

svn commit: r824313 - in /felix/trunk/karaf/features: command/src/main/java/org/apache/felix/karaf/features/command/ core/src/main/java/org/apache/felix/karaf/features/ core/src/main/java/org/apache/felix/karaf/features/internal/

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()) {