You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2011/08/04 14:24:46 UTC

svn commit: r1153861 - in /sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl: BootstrapInstaller.java bootstrapcommands/BootstrapCommandFile.java bootstrapcommands/Command.java bootstrapcommands/UninstallBundleCommand.java

Author: cziegeler
Date: Thu Aug  4 12:24:45 2011
New Revision: 1153861

URL: http://svn.apache.org/viewvc?rev=1153861&view=rev
Log:
SLING-2168 : If a system fragment is uninstalled during bootstrapping, the framework should be restarted

Modified:
    sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java
    sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/BootstrapCommandFile.java
    sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/Command.java
    sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/UninstallBundleCommand.java

Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java?rev=1153861&r1=1153860&r2=1153861&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java (original)
+++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java Thu Aug  4 12:24:45 2011
@@ -203,7 +203,7 @@ class BootstrapInstaller implements Bund
 
         // execute bootstrap commands, if needed
         final BootstrapCommandFile cmd = new BootstrapCommandFile(logger, new File(slingHome, BOOTSTRAP_CMD_FILENAME));
-        cmd.execute(context);
+        boolean requireRestart = cmd.execute(context);
 
         boolean shouldInstall = false;
 
@@ -263,24 +263,24 @@ class BootstrapInstaller implements Bund
             List<Bundle> installed = new LinkedList<Bundle>();
 
             // get all bundles from the startup location and install them
-            boolean requireRestart = installBundles(slingStartupDir, context, bySymbolicName, installed);
+            requireRestart |= installBundles(slingStartupDir, context, bySymbolicName, installed);
 
             // start all the newly installed bundles (existing bundles are not started if they are stopped)
             startBundles(installed);
 
             // mark everything installed
             markInstalled(context, slingStartupDir);
+        }
 
-            // due to the upgrade of a framework extension bundle, the framework
-            // has to be restarted. For this reason, set the target start level
-            // to a negative value.
-            if (requireRestart) {
-                logger.log(
-                    Logger.LOG_INFO,
-                    "Framework extension(s) have been updated, restarting framework after startup has completed");
+        // due to the upgrade of a framework extension bundle, the framework
+        // has to be restarted. For this reason, set the target start level
+        // to a negative value.
+        if (requireRestart) {
+            logger.log(
+                Logger.LOG_INFO,
+                "Framework extension(s) have been updated, restarting framework after startup has completed");
 
-                targetStartLevel = -1;
-            }
+            targetStartLevel = -1;
         }
     }
 

Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/BootstrapCommandFile.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/BootstrapCommandFile.java?rev=1153861&r1=1153860&r2=1153861&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/BootstrapCommandFile.java (original)
+++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/BootstrapCommandFile.java Thu Aug  4 12:24:45 2011
@@ -80,11 +80,13 @@ public class BootstrapCommandFile {
         return result;
     }
 
-    /** Execute commands if needed, and store execution timestamp
-     *  @return number of commands executed */
-    public int execute(BundleContext ctx) throws IOException {
-        int count = 0;
-        if(anythingToExecute(ctx)) {
+    /**
+     * Execute commands if needed, and store execution timestamp
+     * @return If system bundle needs a restart.
+     */
+    public boolean execute(BundleContext ctx) throws IOException {
+        boolean needsRestart = false;
+        if (anythingToExecute(ctx)) {
             InputStream is = null;
             try {
                 is = new FileInputStream(commandFile);
@@ -92,8 +94,7 @@ public class BootstrapCommandFile {
                 for(Command cmd : cmds) {
                     try {
                         logger.log(Logger.LOG_DEBUG, "Executing command: " + cmd);
-                        cmd.execute(logger, ctx);
-                        count++;
+                        needsRestart |= cmd.execute(logger, ctx);
                     } catch(Exception e) {
                         logger.log(Logger.LOG_WARNING, "Exception in command execution (" + cmd + ") :" + e);
                     }
@@ -114,7 +115,7 @@ public class BootstrapCommandFile {
                 logger.log(Logger.LOG_WARNING, "IOException while storing timestamp", ioe);
             }
         }
-        return count;
+        return needsRestart;
     }
 
     /** Parse commands from supplied input stream.

Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/Command.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/Command.java?rev=1153861&r1=1153860&r2=1153861&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/Command.java (original)
+++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/Command.java Thu Aug  4 12:24:45 2011
@@ -24,6 +24,7 @@ import org.apache.felix.framework.Logger
 import org.osgi.framework.BundleContext;
 
 interface Command {
+
     @SuppressWarnings("serial")
     static class ParseException extends IOException {
         ParseException(String reason) {
@@ -36,7 +37,10 @@ interface Command {
      * @throws ParseException if we know the command but syntax is wrong
      */
     Command parse(String commandLine) throws ParseException;
-    
-    /** Execute this command */
-    void execute(Logger logger, BundleContext ctx) throws Exception;
+
+    /**
+     * Execute this command.
+     * @return Return true if system bundle needs a restart.
+     */
+    boolean execute(Logger logger, BundleContext ctx) throws Exception;
 }

Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/UninstallBundleCommand.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/UninstallBundleCommand.java?rev=1153861&r1=1153860&r2=1153861&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/UninstallBundleCommand.java (original)
+++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/bootstrapcommands/UninstallBundleCommand.java Thu Aug  4 12:24:45 2011
@@ -18,17 +18,26 @@
  */
 package org.apache.sling.launchpad.base.impl.bootstrapcommands;
 
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.felix.framework.Logger;
 import org.apache.felix.framework.util.VersionRange;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
-
-/** A Command that uninstalls a bundle, see
- *  {@link UninstallBundleCommandTest} for examples
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ * A Command that uninstalls a bundle, see
+ * {@link UninstallBundleCommandTest} for examples
  */
 class UninstallBundleCommand implements Command {
 
-    public static String CMD_PREFIX = "uninstall ";
+    private static String CMD_PREFIX = "uninstall ";
     private final String bundleSymbolicName;
     private final VersionRange versionRange;
 
@@ -38,24 +47,64 @@ class UninstallBundleCommand implements 
         versionRange = null;
     }
 
-    /** Used to create an actual command */
-    private UninstallBundleCommand(String bundleSymbolicName, String versionRangeStr) {
+    /**
+     * Used to create an uninstall command with symbolic name and version range
+     */
+    private UninstallBundleCommand(final String bundleSymbolicName, String versionRangeStr) {
         this.bundleSymbolicName = bundleSymbolicName;
 
         // If versionRangeStr is not a range, make it strict
-        if(!versionRangeStr.contains(",")) {
+        if (!versionRangeStr.contains(",")) {
             versionRangeStr = "[" + versionRangeStr + "," + versionRangeStr + "]";
         }
         this.versionRange = VersionRange.parse(versionRangeStr);
     }
 
-    public void execute(Logger logger, BundleContext ctx) throws Exception {
+    /**
+     * Used to create an uninstall command with symbolic name
+     */
+    private UninstallBundleCommand(String bundleSymbolicName) {
+        this.bundleSymbolicName = bundleSymbolicName;
+        this.versionRange = null;
+    }
+
+    /**
+     * Gets the bundle's Fragment-Host header.
+     */
+    private static String getFragmentHostHeader(final Bundle b) {
+        return (String) b.getHeaders().get( Constants.FRAGMENT_HOST );
+    }
+
+    private boolean isSystemBundleFragment(final Bundle installedBundle) {
+        final String fragmentHeader = (String) installedBundle.getHeaders().get(
+            Constants.FRAGMENT_HOST);
+        return fragmentHeader != null
+            && fragmentHeader.indexOf(Constants.EXTENSION_DIRECTIVE) > 0;
+    }
+
+    /**
+     * @see org.apache.sling.launchpad.base.impl.bootstrapcommands.Command#execute(org.apache.felix.framework.Logger, org.osgi.framework.BundleContext)
+     */
+    public boolean execute(final Logger logger, final BundleContext ctx) throws Exception {
+        final Set<String> refreshBundles = new HashSet<String>();
         // Uninstall all instances of our bundle within our version range
-        for(Bundle b : ctx.getBundles()) {
-            if(b.getSymbolicName().equals(bundleSymbolicName)) {
-                if(versionRange.isInRange(b.getVersion())) {
+        boolean refreshSystemBundle = false;
+        for(final Bundle b : ctx.getBundles()) {
+            if (b.getSymbolicName().equals(bundleSymbolicName)) {
+                if (versionRange == null || versionRange.isInRange(b.getVersion())) {
                     logger.log(Logger.LOG_INFO,
                             this + ": uninstalling bundle version " + b.getVersion());
+                    final String fragmentHostHeader = getFragmentHostHeader(b);
+                    if (fragmentHostHeader != null) {
+                        if ( isSystemBundleFragment(b) ) {
+                            logger.log(Logger.LOG_INFO, this + ": Need to do a system bundle refresh");
+                            refreshSystemBundle = true;
+                        } else {
+                            logger.log(Logger.LOG_INFO, this + ": Need to do a refresh of the bundle's host: " + fragmentHostHeader);
+                            refreshBundles.add(fragmentHostHeader);
+                        }
+                    }
+
                     b.uninstall();
                 } else {
                     logger.log(Logger.LOG_INFO,
@@ -63,13 +112,38 @@ class UninstallBundleCommand implements 
                 }
             }
         }
+        if ( refreshBundles.size() > 0 ) {
+            final List<Bundle> bundles = new ArrayList<Bundle>();
+            for(final Bundle b : ctx.getBundles() ) {
+                if ( refreshBundles.contains(b.getSymbolicName()) ) {
+                    logger.log(Logger.LOG_INFO, this + ": Found host bundle to refresh " + b.getBundleId());
+                    bundles.add(b);
+                }
+            }
+            if ( bundles.size() > 0 ) {
+                final ServiceReference paRef = ctx.getServiceReference(PackageAdmin.class.getName());
+                if ( paRef != null ) {
+                    try {
+                        final PackageAdmin pa = (PackageAdmin)ctx.getService(paRef);
+                        if ( pa != null ) {
+                            pa.refreshPackages(bundles.toArray(new Bundle[bundles.size()]));
+                        }
+                    } finally {
+                        ctx.ungetService(paRef);
+                    }
+                }
+            }
+        }
+        return refreshSystemBundle;
     }
 
     public Command parse(String commandLine) throws ParseException {
         if(commandLine.startsWith(CMD_PREFIX)) {
             final String [] s = commandLine.split(" ");
-            if(s.length == 3) {
+            if (s.length == 3) {
                 return new UninstallBundleCommand(s[1].trim(), s[2].trim());
+            } else if ( s.length == 2 ) {
+                return new UninstallBundleCommand(s[1].trim());
             }
             throw new Command.ParseException("Syntax error: '" + commandLine + "'");
         }
@@ -78,6 +152,6 @@ class UninstallBundleCommand implements 
 
     @Override
     public String toString() {
-        return getClass().getSimpleName() + " " + bundleSymbolicName + " " + versionRange;
+        return getClass().getSimpleName() + " " + bundleSymbolicName + " " + (versionRange != null ? versionRange : "");
     }
 }
\ No newline at end of file