Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id E38CC200C34 for ; Mon, 27 Feb 2017 13:23:16 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id E212E160B6C; Mon, 27 Feb 2017 12:23:16 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 0FA7E160B60 for ; Mon, 27 Feb 2017 13:23:15 +0100 (CET) Received: (qmail 24088 invoked by uid 500); 27 Feb 2017 12:23:14 -0000 Mailing-List: contact commits-help@felix.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@felix.apache.org Delivered-To: mailing list commits@felix.apache.org Received: (qmail 24079 invoked by uid 99); 27 Feb 2017 12:23:14 -0000 Received: from Unknown (HELO svn01-us-west.apache.org) (209.188.14.144) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 27 Feb 2017 12:23:14 +0000 Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 8882C3A059D for ; Mon, 27 Feb 2017 12:23:13 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1784546 - in /felix/trunk/webconsole/src/main/java/org/apache/felix/webconsole/internal/core: BaseUpdateInstallHelper.java UpdateHelper.java Date: Mon, 27 Feb 2017 12:23:13 -0000 To: commits@felix.apache.org From: pauls@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20170227122313.8882C3A059D@svn01-us-west.apache.org> archived-at: Mon, 27 Feb 2017 12:23:17 -0000 Author: pauls Date: Mon Feb 27 12:23:12 2017 New Revision: 1784546 URL: http://svn.apache.org/viewvc?rev=1784546&view=rev Log: Manually stop and start a bundle updated via the webconsole when a refresh is requested in order to avoid the bundle being stopped and started twice - during the update and in the refresh (FELIX-5566). Modified: felix/trunk/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java felix/trunk/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/UpdateHelper.java Modified: felix/trunk/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java URL: http://svn.apache.org/viewvc/felix/trunk/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java?rev=1784546&r1=1784545&r2=1784546&view=diff ============================================================================== --- felix/trunk/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java (original) +++ felix/trunk/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java Mon Feb 27 12:23:12 2017 @@ -33,6 +33,7 @@ import org.osgi.framework.FrameworkEvent import org.osgi.framework.FrameworkListener; import org.osgi.service.log.LogService; import org.osgi.service.packageadmin.PackageAdmin; +import org.osgi.service.startlevel.StartLevel; abstract class BaseUpdateInstallHelper implements Runnable @@ -76,6 +77,11 @@ abstract class BaseUpdateInstallHelper i { return plugin; } + + protected Bundle getTargetBundle() + { + return null; + } /** @@ -119,13 +125,96 @@ abstract class BaseUpdateInstallHelper i // invalid by the time we want to call the update PackageAdmin pa = ( refreshPackages ) ? ( PackageAdmin ) getService( PackageAdmin.class.getName() ) : null; - // perform the action! - Bundle bundle = doRun(); - - if ( pa != null && bundle != null ) + // same for the startlevel + StartLevel startLevel = null; + + Bundle bundle = getTargetBundle(); + + int state = pa != null && bundle != null ? bundle.getState() : 0; + int startFlags = 0; + + // If the bundle has been started we want to stop it first, then update it, refresh it, and restart it + // because otherwise, it will be stopped and started twice (once by the update and once by the refresh) + if ((state & (Bundle.ACTIVE | Bundle.STARTING)) != 0) + { + // we need the StartLevel service before we stop the bundle + // before the update, since we might be stopping + // our selves in which case the bundle context will be + // invalid by the time we want to call the startlevel + startLevel = (StartLevel) getService(StartLevel.class.getName()); + + // We want to start the bundle afterwards without affecting the persistent state of the bundle + // However, we can only use the transient options if the framework startlevel is not less than the + // bundle startlevel (in case that there is no starlevel service we assume we are good). + if (startLevel == null || startLevel.getStartLevel() >= startLevel.getBundleStartLevel(bundle)) + { + startFlags |= Bundle.START_TRANSIENT; + } + + // If the bundle is in the starting state it might be lazy and not started yet - hence, start it + // according to its policy. + if (state == Bundle.STARTING) + { + startFlags |= Bundle.START_ACTIVATION_POLICY; + } + + // We stop the bundle transiently - assuming we can also start it transiently later (see above) in which + // case we didn't mess with its persistent state at all. + bundle.stop(Bundle.STOP_TRANSIENT); + } + + // We want to catch an exception during update to be able to restart the bundle if we stopped it previously + Exception rethrow = null; + try + { + // perform the action! + bundle = doRun(); + + + if ( pa != null && bundle != null ) + { + // refresh packages and give it at most 5 seconds to finish + refreshPackages( pa, plugin.getBundle().getBundleContext(), 5000L, bundle ); + } + } + catch (Exception ex) + { + rethrow = ex; + throw ex; + } + finally { - // refresh packages and give it at most 5 seconds to finish - refreshPackages( pa, plugin.getBundle().getBundleContext(), 5000L, bundle ); + // If we stopped the bundle lets try to restart it (we created the correct flags above already). + if ((state & (Bundle.ACTIVE | Bundle.STARTING)) != 0) + { + try + { + bundle.start(startFlags); + } + catch (Exception ex) + { + if (rethrow == null) + { + throw ex; + } + else + { + try + { + getLog().log( LogService.LOG_ERROR, "Cannot restart bundle: " + bundle + " after exception during update!", ex); + } + catch ( Exception secondary ) + { + // at the time this exception happens the log used might have + // been destroyed and is not available to use any longer. So + // we only can write to stderr at this time to at least get + // some message out ... + System.err.println( "Cannot restart bundle: " + bundle + " after exception during update!"); + ex.printStackTrace( System.err ); + } + } + } + } } } catch ( Exception e ) Modified: felix/trunk/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/UpdateHelper.java URL: http://svn.apache.org/viewvc/felix/trunk/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/UpdateHelper.java?rev=1784546&r1=1784545&r2=1784546&view=diff ============================================================================== --- felix/trunk/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/UpdateHelper.java (original) +++ felix/trunk/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/UpdateHelper.java Mon Feb 27 12:23:12 2017 @@ -61,6 +61,10 @@ class UpdateHelper extends BaseUpdateIns return bundle; } + protected Bundle getTargetBundle() + { + return bundle; + } protected Bundle doRun() throws Exception { @@ -98,7 +102,6 @@ class UpdateHelper extends BaseUpdateIns return null; } - private boolean updateFromBundleLocation() { getLog().log( LogService.LOG_DEBUG, "Trying to update with Bundle.update()" );