Applied patch (FELIX-947) to modify start level processing to do nothing if
there is an attempt to set the start level to the current start level.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@745561 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index a2d7d2b..66141ce 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -831,175 +831,180 @@
{
Bundle[] bundles = null;
- // Synchronization for changing the start level is rather loose.
- // The object lock is acquired initially to change the framework's
- // active start level and then the install lock is acquired to attain
- // a sorted snapshot of the currently installed bundles, but then this
- // lock is freed immediately. No locks are held while processing the
- // currently installed bundles for starting/stopping based on the new
- // active start level. The only locking that occurs is for individual
- // bundles when startBundle()/stopBundle() is called, but this locking
- // is done in the respective method.
- //
- // This approach does mean that it is possible for a for individual
- // bundle states to change during this operation. For example, bundle
- // start levels can be changed or bundles can be uninstalled. If a
- // bundle's start level changes, then it is possible for it to be
- // processed out of order. Uninstalled bundles are just logged and
- // ignored. I had a bit of discussion with Peter Kriens about these
- // issues and he felt they were consistent with the spec, which
- // intended Start Level to have some leeway.
- //
- // Calls to this method are only made by the start level thread, which
- // serializes framework start level changes. Thus, it is not possible
- // for two requests to change the framework's start level to interfere
- // with each other.
-
- // Determine if we are lowering or raising the
- // active start level, then udpate active start level.
- boolean lowering = (requestedLevel < getActiveStartLevel());
- m_activeStartLevel = requestedLevel;
-
- synchronized (m_installedBundleLock_Priority2)
+ // Do nothing if the requested start level is the same as the
+ // active start level.
+ if (requestedLevel != getActiveStartLevel())
{
- // Get a snapshot of all installed bundles.
- bundles = getBundles();
+ // Synchronization for changing the start level is rather loose.
+ // The framework's active start level is volatile, so no lock is
+ // needed to access it. The install lock is acquired to attain a
+ // sorted snapshot of the currently installed bundles, but then this
+ // lock is freed immediately. No locks are held while processing the
+ // currently installed bundles for starting/stopping based on the new
+ // active start level. The only locking that occurs is for individual
+ // bundles when startBundle()/stopBundle() is called, but this locking
+ // is done in the respective method.
+ //
+ // This approach does mean that it is possible for a for individual
+ // bundle states to change during this operation. For example, bundle
+ // start levels can be changed or bundles can be uninstalled. If a
+ // bundle's start level changes, then it is possible for it to be
+ // processed out of order. Uninstalled bundles are just logged and
+ // ignored. I had a bit of discussion with Peter Kriens about these
+ // issues and he felt they were consistent with the spec, which
+ // intended Start Level to have some leeway.
+ //
+ // Calls to this method are only made by the start level thread, which
+ // serializes framework start level changes. Thus, it is not possible
+ // for two requests to change the framework's start level to interfere
+ // with each other.
- // Sort bundle array by start level either ascending or
- // descending depending on whether the start level is being
- // lowered or raised to that the bundles can be efficiently
- // processed in order. Within a start level sort by bundle ID.
- Comparator comparator = null;
- if (lowering)
+ // Determine if we are lowering or raising the
+ // active start level, then udpate active start level.
+ boolean lowering = (requestedLevel < getActiveStartLevel());
+ m_activeStartLevel = requestedLevel;
+
+ synchronized (m_installedBundleLock_Priority2)
{
- // Sort descending to stop highest start level first.
- comparator = new Comparator() {
- public int compare(Object o1, Object o2)
- {
- BundleImpl b1 = (BundleImpl) o1;
- BundleImpl b2 = (BundleImpl) o2;
- if (b1.getStartLevel(getInitialBundleStartLevel())
- < b2.getStartLevel(getInitialBundleStartLevel()))
+ // Get a snapshot of all installed bundles.
+ bundles = getBundles();
+
+ // Sort bundle array by start level either ascending or
+ // descending depending on whether the start level is being
+ // lowered or raised to that the bundles can be efficiently
+ // processed in order. Within a start level sort by bundle ID.
+ Comparator comparator = null;
+ if (lowering)
+ {
+ // Sort descending to stop highest start level first.
+ comparator = new Comparator() {
+ public int compare(Object o1, Object o2)
{
- return 1;
- }
- else if (b1.getStartLevel(getInitialBundleStartLevel())
- > b2.getStartLevel(getInitialBundleStartLevel()))
- {
+ BundleImpl b1 = (BundleImpl) o1;
+ BundleImpl b2 = (BundleImpl) o2;
+ if (b1.getStartLevel(getInitialBundleStartLevel())
+ < b2.getStartLevel(getInitialBundleStartLevel()))
+ {
+ return 1;
+ }
+ else if (b1.getStartLevel(getInitialBundleStartLevel())
+ > b2.getStartLevel(getInitialBundleStartLevel()))
+ {
+ return -1;
+ }
+ else if (b1.getBundleId() < b2.getBundleId())
+ {
+ return 1;
+ }
return -1;
}
- else if (b1.getBundleId() < b2.getBundleId())
+ };
+ }
+ else
+ {
+ // Sort ascending to start lowest start level first.
+ comparator = new Comparator() {
+ public int compare(Object o1, Object o2)
{
- return 1;
- }
- return -1;
- }
- };
- }
- else
- {
- // Sort ascending to start lowest start level first.
- comparator = new Comparator() {
- public int compare(Object o1, Object o2)
- {
- BundleImpl b1 = (BundleImpl) o1;
- BundleImpl b2 = (BundleImpl) o2;
- if (b1.getStartLevel(getInitialBundleStartLevel())
- > b2.getStartLevel(getInitialBundleStartLevel()))
- {
- return 1;
- }
- else if (b1.getStartLevel(getInitialBundleStartLevel())
- < b2.getStartLevel(getInitialBundleStartLevel()))
- {
+ BundleImpl b1 = (BundleImpl) o1;
+ BundleImpl b2 = (BundleImpl) o2;
+ if (b1.getStartLevel(getInitialBundleStartLevel())
+ > b2.getStartLevel(getInitialBundleStartLevel()))
+ {
+ return 1;
+ }
+ else if (b1.getStartLevel(getInitialBundleStartLevel())
+ < b2.getStartLevel(getInitialBundleStartLevel()))
+ {
+ return -1;
+ }
+ else if (b1.getBundleId() > b2.getBundleId())
+ {
+ return 1;
+ }
return -1;
}
- else if (b1.getBundleId() > b2.getBundleId())
+ };
+ }
+
+ Arrays.sort(bundles, comparator);
+ }
+
+ // Stop or start the bundles according to the start level.
+ for (int i = 0; (bundles != null) && (i < bundles.length); i++)
+ {
+ BundleImpl impl = (BundleImpl) bundles[i];
+
+ // Ignore the system bundle, since its start() and
+ // stop() methods get called explicitly in Felix.start()
+ // and Felix.stop(), respectively.
+ if (impl.getBundleId() == 0)
+ {
+ continue;
+ }
+
+ // Lock the current bundle.
+ try
+ {
+ acquireBundleLock(impl,
+ Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE
+ | Bundle.STARTING | Bundle.STOPPING);
+ }
+ catch (IllegalStateException ex)
+ {
+ fireFrameworkEvent(FrameworkEvent.ERROR, impl, ex);
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Error locking " + impl._getLocation(), ex);
+ continue;
+ }
+
+ try
+ {
+ // Start the bundle if necessary.
+ if ((impl.getPersistentState() == Bundle.ACTIVE) &&
+ (impl.getStartLevel(getInitialBundleStartLevel())
+ <= getActiveStartLevel()))
+ {
+ try
{
- return 1;
+ startBundle(impl, false);
}
- return -1;
+ catch (Throwable th)
+ {
+ fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Error starting " + impl._getLocation(), th);
+ }
}
- };
- }
-
- Arrays.sort(bundles, comparator);
- }
-
- // Stop or start the bundles according to the start level.
- for (int i = 0; (bundles != null) && (i < bundles.length); i++)
- {
- BundleImpl impl = (BundleImpl) bundles[i];
-
- // Ignore the system bundle, since its start() and
- // stop() methods get called explicitly in Felix.start()
- // and Felix.stop(), respectively.
- if (impl.getBundleId() == 0)
- {
- continue;
- }
-
- // Lock the current bundle.
- try
- {
- acquireBundleLock(impl,
- Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE
- | Bundle.STARTING | Bundle.STOPPING);
- }
- catch (IllegalStateException ex)
- {
- fireFrameworkEvent(FrameworkEvent.ERROR, impl, ex);
- m_logger.log(
- Logger.LOG_ERROR,
- "Error locking " + impl._getLocation(), ex);
- continue;
- }
-
- try
- {
- // Start the bundle if necessary.
- if ((impl.getPersistentState() == Bundle.ACTIVE) &&
- (impl.getStartLevel(getInitialBundleStartLevel())
- <= getActiveStartLevel()))
- {
- try
+ // Stop the bundle if necessary.
+ else if ((impl.getState() == Bundle.ACTIVE) &&
+ (impl.getStartLevel(getInitialBundleStartLevel())
+ > getActiveStartLevel()))
{
- startBundle(impl, false);
- }
- catch (Throwable th)
- {
- fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
- m_logger.log(
- Logger.LOG_ERROR,
- "Error starting " + impl._getLocation(), th);
+ try
+ {
+ stopBundle(impl, false);
+ }
+ catch (Throwable th)
+ {
+ fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Error stopping " + impl._getLocation(), th);
+ }
}
}
- // Stop the bundle if necessary.
- else if ((impl.getState() == Bundle.ACTIVE) &&
- (impl.getStartLevel(getInitialBundleStartLevel())
- > getActiveStartLevel()))
+ finally
{
- try
- {
- stopBundle(impl, false);
- }
- catch (Throwable th)
- {
- fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
- m_logger.log(
- Logger.LOG_ERROR,
- "Error stopping " + impl._getLocation(), th);
- }
+ // Always release bundle lock.
+ releaseBundleLock(impl);
}
+ // Hint to GC to collect bundle; not sure why this
+ // is necessary, but it appears to help.
+ bundles[i] = null;
}
- finally
- {
- // Always release bundle lock.
- releaseBundleLock(impl);
- }
- // Hint to GC to collect bundle; not sure why this
- // is necessary, but it appears to help.
- bundles[i] = null;
}
if (getState() == Bundle.ACTIVE)