Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id C92A8684A for ; Thu, 4 Aug 2011 12:25:12 +0000 (UTC) Received: (qmail 33329 invoked by uid 500); 4 Aug 2011 12:25:12 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 33273 invoked by uid 500); 4 Aug 2011 12:25:12 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 33266 invoked by uid 99); 4 Aug 2011 12:25:12 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 04 Aug 2011 12:25:12 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 04 Aug 2011 12:25:08 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 55E9F2388901; Thu, 4 Aug 2011 12:24:46 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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 Date: Thu, 04 Aug 2011 12:24:46 -0000 To: commits@sling.apache.org From: cziegeler@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110804122446.55E9F2388901@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 installed = new LinkedList(); // 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 refreshBundles = new HashSet(); // 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 bundles = new ArrayList(); + 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