{
throw new IllegalStateException("Cannot start an uninstalled bundle.");
}
else
{
throw new BundleException(
"Bundle " + bundle
+ " cannot be started, since it is either starting or stopping.");
}
}
// Record whether the bundle is using its declared activation policy.
boolean wasDeferred = bundle.isDeclaredActivationPolicyUsed()
&& (((BundleRevisionImpl) bundle.adapt(BundleRevision.class))
.getDeclaredActivationPolicy() == BundleRevisionImpl.LAZY_ACTIVATION);
bundle.setDeclaredActivationPolicyUsed(
(options & Bundle.START_ACTIVATION_POLICY) != 0);
BundleException rethrow = null;
try
{
// The spec doesn't say whether it is possible to start an extension
// We just do nothing
if (bundle.isExtension())
{
return;
}
// As per the OSGi spec, fragment bundles can not be started and must
// throw a BundleException when there is an attempt to start one.
if (Util.isFragment(bundle.adapt(BundleRevision.class)))
{
throw new BundleException("Fragment bundles can not be started.");
}
// Set and save the bundle's persistent state to active
// if we are supposed to record state change.
if (!isTransient)
{
if ((options & Bundle.START_ACTIVATION_POLICY) != 0)
{
bundle.setPersistentStateStarting();
}
else
{
bundle.setPersistentStateActive();
}
}
// Check to see if the bundle's start level is greater than the
// the framework's target start level and if so just return. For
// transient starts we compare their start level to the current
// active start level, since we never process transient starts
// asynchronously (i.e., they are either satisfied and process
// synchronously here or they throw an exception).
int bundleLevel = bundle.getStartLevel(getInitialBundleStartLevel());
if (isTransient && (bundleLevel > m_activeStartLevel))
{
// Throw an exception for transient starts.
throw new BundleException(
"Cannot start bundle " + bundle + " because its start level is "
+ bundleLevel
+ ", which is greater than the framework's start level of "
+ m_activeStartLevel + ".", BundleException.START_TRANSIENT_ERROR);
}
else if (bundleLevel > m_targetStartLevel)
{
// Ignore persistent starts that are not satisfied.
return;
}
// Check to see if there is a start level change in progress and if
// so queue this bundle to the start level bundle queue for the start
// level thread and return, except for transient starts which are
// queued but processed synchronously.
// Note: Don't queue starts from the start level thread, otherwise
// we'd never get anything started.
if (!Thread.currentThread().getName().equals(FrameworkStartLevelImpl.THREAD_NAME))
{
synchronized (m_startLevelBundles)
{
// Since we have the start level queue lock, we know the
// active start level cannot change. For transient starts
// we now need to double check and make sure we can still
// start them since technically the active start level could
// have changed.
if (isTransient && (bundleLevel > m_activeStartLevel))
{
throw new BundleException(
"Cannot start bundle " + bundle + " because its start level is "
+ bundleLevel
+ ", which is greater than the framework's start level of "
+ m_activeStartLevel + ".", BundleException.START_TRANSIENT_ERROR);
}
// If the start level bundle queue is not empty, then we know
// there is a start level operation ongoing. We know that the
// bundle being started is satisfied by the target start level
// otherwise we wouldn't be here. In most cases we simply want
// to queue the bundle; however, if the bundle level is lower
// than the current active start level, then we want to handle
// it synchronously. This is because the start level thread
// ignores bundles that it should have already processed.
// So queue the bundle if its bundle start level is greater
// or equal to the active start level and then simply return
// since it will be processed asynchronously.
if (!m_startLevelBundles.isEmpty()
&& (bundleLevel >= m_activeStartLevel))
{
// Only add the bundle to the start level bundles
// being process if it is not already there.
boolean found = false;
for (StartLevelTuple tuple : m_startLevelBundles)
{
if (tuple.m_bundle == bundle)
{
found = true;
}
}
if (!found)
{
m_startLevelBundles.add(new StartLevelTuple(bundle, bundleLevel));
}
// Note that although we queued the transiently started
// bundle, we don't return here because we handle all
// transient bundles synchronously. The reason why we
// queue it anyway is for the case where the start level
// is lowering, since the transiently started bundle may
// have already been processed by the start level thread
// and we will start it briefly here synchronously, but
// we want the start level thread to process it again
// so it gets another chance to stop it. This is not an
// issue when the start level is raising because the
// start level thread ignores non-persistently started
// bundles or if it is also persistently started it will
// be a no-op.
if (!isTransient)
{
return;
}
}
}
}
switch (bundle.getState())
{
case Bundle.UNINSTALLED:
throw new IllegalStateException("Cannot start an uninstalled bundle.");
case Bundle.STARTING:
if (!wasDeferred)
{
throw new BundleException(
"Bundle " + bundle
+ " cannot be started, since it is starting.");
}
break;
case Bundle.STOPPING:
throw new BundleException(
"Bundle " + bundle
+ " cannot be started, since it is stopping.");
case Bundle.ACTIVE:
return;
case Bundle.INSTALLED: