Copyright (c) 2012, 2016 IBM Corporation and others.
This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
which accompanies this distribution, and is available at
https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
Contributors:
IBM Corporation - initial API and implementation
/*******************************************************************************
* Copyright (c) 2012, 2016 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.container;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.osgi.container.ModuleContainerAdaptor.ModuleEvent;
import org.eclipse.osgi.framework.util.ThreadInfoReport;
import org.eclipse.osgi.internal.container.EquinoxReentrantLock;
import org.eclipse.osgi.internal.debug.Debug;
import org.eclipse.osgi.internal.messages.Msg;
import org.eclipse.osgi.report.resolution.ResolutionReport;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.AdminPermission;
import org.osgi.framework.BundleException;
import org.osgi.framework.BundleReference;
import org.osgi.framework.startlevel.BundleStartLevel;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.service.resolver.ResolutionException;
A module represents a set of revisions installed in a module container
. Since: 3.10
/**
* A module represents a set of revisions installed in a
* module {@link ModuleContainer container}.
* @since 3.10
*/
public abstract class Module implements BundleReference, BundleStartLevel, Comparable<Module> {
The possible start options for a module
/**
* The possible start options for a module
*/
public static enum StartOptions {
The module start operation is transient and the persistent
autostart or activation policy setting of the module is not modified.
/**
* The module start operation is transient and the persistent
* autostart or activation policy setting of the module is not modified.
*/
TRANSIENT,
The module start operation must activate the module according to the module's declared
activation policy.
/**
* The module start operation must activate the module according to the module's declared
* activation policy.
*/
USE_ACTIVATION_POLICY,
The module start operation is transient and the persistent activation policy
setting will be used.
/**
* The module start operation is transient and the persistent activation policy
* setting will be used.
*/
TRANSIENT_RESUME,
The module start operation is transient and will only happen if auto start
setting is persistent. /**
* The module start operation is transient and will only happen if {@link Settings#AUTO_START auto start}
* setting is persistent.
*/
TRANSIENT_IF_AUTO_START,
The module start operation that indicates the module is being started because of a
lazy start trigger class load.
/**
* The module start operation that indicates the module is being started because of a
* lazy start trigger class load.
*/
LAZY_TRIGGER;
Tests if this option is contained in the specified options
/**
* Tests if this option is contained in the specified options
*/
public boolean isContained(StartOptions... options) {
for (StartOptions option : options) {
if (equals(option)) {
return true;
}
}
return false;
}
}
The possible start options for a module
/**
* The possible start options for a module
*/
public static enum StopOptions {
The module stop operation is transient and the persistent
autostart setting of the module is not modified.
/**
* The module stop operation is transient and the persistent
* autostart setting of the module is not modified.
*/
TRANSIENT;
Tests if this option is contained in the specified options
/**
* Tests if this option is contained in the specified options
*/
public boolean isContained(StopOptions... options) {
for (StopOptions option : options) {
if (equals(option)) {
return true;
}
}
return false;
}
}
An enumeration of the possible states
a module may be in. /**
* An enumeration of the possible {@link Module#getState() states} a module may be in.
*/
public static enum State {
The module is installed but not yet resolved.
/**
* The module is installed but not yet resolved.
*/
INSTALLED,
The module is resolved and able to be started.
/**
* The module is resolved and able to be started.
*/
RESOLVED,
The module is waiting for a trigger
class load to proceed with starting. /**
* The module is waiting for a {@link StartOptions#LAZY_TRIGGER trigger}
* class load to proceed with starting.
*/
LAZY_STARTING,
The module is in the process of starting.
/**
* The module is in the process of starting.
*/
STARTING,
The module is now running.
/**
* The module is now running.
*/
ACTIVE,
The module is in the process of stopping
/**
* The module is in the process of stopping
*/
STOPPING,
The module is uninstalled and may not be used.
/**
* The module is uninstalled and may not be used.
*/
UNINSTALLED
}
An enumeration of persistent settings for a module
/**
* An enumeration of persistent settings for a module
*/
public static enum Settings {
The module has been set to auto start.
/**
* The module has been set to auto start.
*/
AUTO_START,
The module has been set to use its activation policy.
/**
* The module has been set to use its activation policy.
*/
USE_ACTIVATION_POLICY,
The module has been set for parallel activation from start-level
Since: 3.15
/**
* The module has been set for parallel activation from start-level
* @since 3.15
*/
PARALLEL_ACTIVATION
}
A set of states
that indicate a module is active. /**
* A set of {@link State states} that indicate a module is active.
*/
public static final EnumSet<State> ACTIVE_SET = EnumSet.of(State.STARTING, State.LAZY_STARTING, State.ACTIVE, State.STOPPING);
A set of states
that indicate a module is resolved. /**
* A set of {@link State states} that indicate a module is resolved.
*/
public static final EnumSet<State> RESOLVED_SET = EnumSet.of(State.RESOLVED, State.STARTING, State.LAZY_STARTING, State.ACTIVE, State.STOPPING);
private final Long id;
private final String location;
private final ModuleRevisions revisions;
final EquinoxReentrantLock stateChangeLock = new EquinoxReentrantLock();
private final EnumSet<ModuleEvent> stateTransitionEvents = EnumSet.noneOf(ModuleEvent.class);
private final EnumSet<Settings> settings;
final AtomicInteger inStart = new AtomicInteger(0);
private volatile State state = State.INSTALLED;
private volatile int startlevel;
private volatile long lastModified;
Constructs a new module with the specified id, location and
container.
Params: - id – the new module id
- location – the new module location
- container – the container for the new module
- settings – the persisted settings. May be
null
if there are no settings. - startlevel – the persisted start level or initial start level.
/**
* Constructs a new module with the specified id, location and
* container.
* @param id the new module id
* @param location the new module location
* @param container the container for the new module
* @param settings the persisted settings. May be {@code null} if there are no settings.
* @param startlevel the persisted start level or initial start level.
*/
public Module(Long id, String location, ModuleContainer container, EnumSet<Settings> settings, int startlevel) {
this.id = id;
this.location = location;
this.revisions = new ModuleRevisions(this, container);
this.settings = settings == null ? EnumSet.noneOf(Settings.class) : EnumSet.copyOf(settings);
this.startlevel = startlevel;
}
Returns the module id.
Returns: the module id.
/**
* Returns the module id.
* @return the module id.
*/
public final Long getId() {
return id;
}
Returns the module location
Returns: the module location
/** Returns the module location
* @return the module location
*/
public final String getLocation() {
return location;
}
Returns the ModuleRevisions
associated with this module. Returns: the ModuleRevisions
associated with this module
/**
* Returns the {@link ModuleRevisions} associated with this module.
* @return the {@link ModuleRevisions} associated with this module
*/
public final ModuleRevisions getRevisions() {
return revisions;
}
Returns the module container this module is contained in.
Returns: the module container.
/**
* Returns the module container this module is contained in.
* @return the module container.
*/
public final ModuleContainer getContainer() {
return revisions.getContainer();
}
Returns the current revision
associated with this module. If the module is uninstalled then the last current revision is returned. Returns: the current revision
associated with this module.
/**
* Returns the current {@link ModuleRevision revision} associated with this module.
* If the module is uninstalled then the last current revision is returned.
* @return the current {@link ModuleRevision revision} associated with this module.
*/
public final ModuleRevision getCurrentRevision() {
return revisions.getCurrentRevision();
}
Returns the current state
of this module. Returns: the current state of this module.
/**
* Returns the current {@link State state} of this module.
* @return the current state of this module.
*/
public final State getState() {
return state;
}
final void setState(State state) {
this.state = state;
}
@Override
public final int getStartLevel() {
checkValid();
return this.startlevel;
}
@Override
public final void setStartLevel(int startLevel) {
revisions.getContainer().setStartLevel(this, startLevel);
}
@Override
public final boolean isPersistentlyStarted() {
checkValid();
return settings.contains(Settings.AUTO_START);
}
@Override
public final boolean isActivationPolicyUsed() {
checkValid();
return settings.contains(Settings.USE_ACTIVATION_POLICY);
}
final void storeStartLevel(int newStartLevel) {
this.startlevel = newStartLevel;
}
Returns the time when this module was last modified. A module is considered
to be modified when it is installed, updated or uninstalled.
The time value is a the number of milliseconds since January 1, 1970, 00:00:00 UTC.
Returns: the time when this bundle was last modified.
/**
* Returns the time when this module was last modified. A module is considered
* to be modified when it is installed, updated or uninstalled.
* <p>
* The time value is a the number of milliseconds since January 1, 1970, 00:00:00 UTC.
* @return the time when this bundle was last modified.
*/
public final long getLastModified() {
return this.lastModified;
}
final void setlastModified(long lastModified) {
this.lastModified = lastModified;
}
private static final EnumSet<ModuleEvent> VALID_RESOLVED_TRANSITION = EnumSet.of(ModuleEvent.STARTED);
private static final EnumSet<ModuleEvent> VALID_STOPPED_TRANSITION = EnumSet.of(ModuleEvent.UPDATED, ModuleEvent.UNRESOLVED, ModuleEvent.UNINSTALLED);
Acquires the module lock for state changes by the current thread for the specified
transition event. Certain transition events locks may be nested within other
transition event locks. For example, a resolved transition event lock may be
nested within a started transition event lock. A stopped transition lock
may be nested within an updated, unresolved or uninstalled transition lock.
Params: - transitionEvent – the transition event to acquire the lock for.
Throws:
/**
* Acquires the module lock for state changes by the current thread for the specified
* transition event. Certain transition events locks may be nested within other
* transition event locks. For example, a resolved transition event lock may be
* nested within a started transition event lock. A stopped transition lock
* may be nested within an updated, unresolved or uninstalled transition lock.
* @param transitionEvent the transition event to acquire the lock for.
* @throws BundleException
*/
protected final void lockStateChange(ModuleEvent transitionEvent) throws BundleException {
boolean previousInterruption = Thread.interrupted();
boolean invalid = false;
try {
boolean acquired = stateChangeLock.tryLock(revisions.getContainer().getModuleLockTimeout(), TimeUnit.SECONDS);
Set<ModuleEvent> currentTransition = Collections.emptySet();
if (acquired) {
boolean isValidTransition = true;
switch (transitionEvent) {
case STARTED :
case UPDATED :
case UNINSTALLED :
case UNRESOLVED :
// These states must be initiating transition states
// no other transition state is allowed when these are kicked off
isValidTransition = stateTransitionEvents.isEmpty();
break;
case RESOLVED :
isValidTransition = VALID_RESOLVED_TRANSITION.containsAll(stateTransitionEvents);
break;
case STOPPED :
isValidTransition = VALID_STOPPED_TRANSITION.containsAll(stateTransitionEvents);
break;
default :
isValidTransition = false;
break;
}
if (!isValidTransition) {
currentTransition = EnumSet.copyOf(stateTransitionEvents);
invalid = true;
stateChangeLock.unlock();
} else {
stateTransitionEvents.add(transitionEvent);
return;
}
} else {
currentTransition = EnumSet.copyOf(stateTransitionEvents);
}
Throwable cause;
if (invalid) {
cause = new IllegalStateException(NLS.bind(Msg.Module_LockStateError, transitionEvent, currentTransition));
} else {
cause = new TimeoutException(NLS.bind(Msg.Module_LockTimeout, revisions.getContainer().getModuleLockTimeout())).initCause(new ThreadInfoReport(stateChangeLock.toString()));
}
String exceptonInfo = toString() + ' ' + transitionEvent + ' ' + currentTransition;
throw new BundleException(Msg.Module_LockError + exceptonInfo, BundleException.STATECHANGE_ERROR, cause);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new BundleException(Msg.Module_LockError + toString() + " " + transitionEvent, BundleException.STATECHANGE_ERROR, e); //$NON-NLS-1$
} finally {
if (previousInterruption) {
Thread.currentThread().interrupt();
}
}
}
Releases the lock for state changes for the specified transition event.
Params: - transitionEvent –
/**
* Releases the lock for state changes for the specified transition event.
* @param transitionEvent
*/
protected final void unlockStateChange(ModuleEvent transitionEvent) {
if (stateChangeLock.getHoldCount() == 0 || !stateTransitionEvents.contains(transitionEvent))
throw new IllegalMonitorStateException("Current thread does not hold the state change lock for: " + transitionEvent); //$NON-NLS-1$
stateTransitionEvents.remove(transitionEvent);
stateChangeLock.unlock();
}
Returns true if the current thread holds the state change lock for the specified transition event.
Params: - transitionEvent –
Returns: true if the current thread holds the state change lock for the specified transition event.
/**
* Returns true if the current thread holds the state change lock for the specified transition event.
* @param transitionEvent
* @return true if the current thread holds the state change lock for the specified transition event.
*/
public final boolean holdsTransitionEventLock(ModuleEvent transitionEvent) {
return stateChangeLock.getHoldCount() > 0 && stateTransitionEvents.contains(transitionEvent);
}
Returns the thread that currently owns the state change lock for this module, or
null
if not owned.
Returns: the owner, or null
if not owned.
/**
* Returns the thread that currently owns the state change lock for this module, or
* <code>null</code> if not owned.
* @return the owner, or <code>null</code> if not owned.
*/
public final Thread getStateChangeOwner() {
return stateChangeLock.getOwner();
}
Starts this module
Params: - options – the options for starting
Throws: - BundleException – if an errors occurs while starting
/**
* Starts this module
* @param options the options for starting
* @throws BundleException if an errors occurs while starting
*/
public void start(StartOptions... options) throws BundleException {
ModuleContainer container = getContainer();
long startTime = 0;
if (container.DEBUG_BUNDLE_START_TIME) {
startTime = System.nanoTime();
}
container.checkAdminPermission(getBundle(), AdminPermission.EXECUTE);
if (options == null) {
options = new StartOptions[0];
}
ModuleEvent event;
if (StartOptions.LAZY_TRIGGER.isContained(options)) {
setTrigger();
if (stateChangeLock.getHoldCount() > 0 && stateTransitionEvents.contains(ModuleEvent.STARTED)) {
// nothing to do here; the current thread is activating the bundle.
return;
}
}
BundleException startError = null;
boolean lockedStarted = false;
// Indicate we are in the middle of a start.
// This must be incremented before we acquire the STARTED lock the first time.
inStart.incrementAndGet();
try {
lockStateChange(ModuleEvent.STARTED);
lockedStarted = true;
checkValid();
if (StartOptions.TRANSIENT_IF_AUTO_START.isContained(options) && !settings.contains(Settings.AUTO_START)) {
// Do nothing; this is a request to start only if the module is set for auto start
return;
}
checkFragment();
persistStartOptions(options);
if (getStartLevel() > container.getStartLevel()) {
if (StartOptions.TRANSIENT.isContained(options)) {
// it is an error to attempt to transient start a bundle without its start level met
throw new BundleException(Msg.Module_Transient_StartError, BundleException.START_TRANSIENT_ERROR);
}
// Do nothing; start level is not met
return;
}
if (State.ACTIVE.equals(getState()))
return;
if (getState().equals(State.INSTALLED)) {
ResolutionReport report;
// must unlock to avoid out of order locks when multiple unresolved
// bundles are started at the same time from different threads
unlockStateChange(ModuleEvent.STARTED);
lockedStarted = false;
try {
report = container.resolve(Collections.singletonList(this), true);
} finally {
lockStateChange(ModuleEvent.STARTED);
lockedStarted = true;
}
// need to check valid again in case someone uninstalled the bundle
checkValid();
ResolutionException e = report.getResolutionException();
if (e != null) {
if (e.getCause() instanceof BundleException) {
throw (BundleException) e.getCause();
}
}
if (State.ACTIVE.equals(getState()))
return;
if (getState().equals(State.INSTALLED)) {
String reportMessage = report.getResolutionReportMessage(getCurrentRevision());
throw new BundleException(Msg.Module_ResolveError + reportMessage, BundleException.RESOLVE_ERROR);
}
}
try {
event = doStart(options);
} catch (BundleException e) {
// must return state to resolved
setState(State.RESOLVED);
startError = e;
// must always publish the STOPPED event on error
event = ModuleEvent.STOPPED;
}
} finally {
if (lockedStarted) {
unlockStateChange(ModuleEvent.STARTED);
}
inStart.decrementAndGet();
}
if (event != null) {
if (!EnumSet.of(ModuleEvent.STARTED, ModuleEvent.LAZY_ACTIVATION, ModuleEvent.STOPPED).contains(event))
throw new IllegalStateException("Wrong event type: " + event); //$NON-NLS-1$
publishEvent(event);
// only print bundleTime information if we actually fired an event for this bundle
if (container.DEBUG_BUNDLE_START_TIME) {
Debug.println(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms for total start time event " + event + " - " + this); //$NON-NLS-1$ //$NON-NLS-2$
}
}
if (startError != null) {
throw startError;
}
}
final void publishEvent(ModuleEvent type) {
revisions.getContainer().getAdaptor().publishModuleEvent(type, this, this);
}
Stops this module.
Params: - options – options for stopping
Throws: - BundleException – if an error occurs while stopping
/**
* Stops this module.
* @param options options for stopping
* @throws BundleException if an error occurs while stopping
*/
public void stop(StopOptions... options) throws BundleException {
revisions.getContainer().checkAdminPermission(getBundle(), AdminPermission.EXECUTE);
if (options == null)
options = new StopOptions[0];
ModuleEvent event;
BundleException stopError = null;
lockStateChange(ModuleEvent.STOPPED);
try {
checkValid();
checkFragment();
persistStopOptions(options);
if (!Module.ACTIVE_SET.contains(getState()))
return;
try {
event = doStop();
} catch (BundleException e) {
stopError = e;
// must always publish the STOPPED event
event = ModuleEvent.STOPPED;
}
} finally {
unlockStateChange(ModuleEvent.STOPPED);
}
if (event != null) {
if (!ModuleEvent.STOPPED.equals(event))
throw new IllegalStateException("Wrong event type: " + event); //$NON-NLS-1$
publishEvent(event);
}
if (stopError != null)
throw stopError;
}
private void checkFragment() throws BundleException {
ModuleRevision current = getCurrentRevision();
if ((current.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) {
throw new BundleException(Msg.Module_Fragment_InvalidOperation, BundleException.INVALID_OPERATION);
}
}
@Override
public final int compareTo(Module o) {
int slcomp = this.startlevel - o.startlevel;
if (slcomp != 0) {
return slcomp;
}
long idcomp = getId() - o.getId();
return (idcomp < 0L) ? -1 : ((idcomp > 0L) ? 1 : 0);
}
final void checkValid() {
if (getState().equals(State.UNINSTALLED))
throw new IllegalStateException(Msg.Module_UninstalledError);
}
private ModuleEvent doStart(StartOptions... options) throws BundleException {
boolean isLazyTrigger = StartOptions.LAZY_TRIGGER.isContained(options);
if (isLazyTrigger) {
if (!State.LAZY_STARTING.equals(getState())) {
// need to make sure we transition through the lazy starting state
setState(State.LAZY_STARTING);
// need to publish the lazy event
unlockStateChange(ModuleEvent.STARTED);
try {
publishEvent(ModuleEvent.LAZY_ACTIVATION);
} finally {
lockStateChange(ModuleEvent.STARTED);
}
if (State.ACTIVE.equals(getState())) {
// A sync listener must have caused the bundle to activate
return null;
}
// continue on to normal starting
}
if (getContainer().DEBUG_MONITOR_LAZY) {
Debug.printStackTrace(new Exception("Module is being lazy activated: " + this)); //$NON-NLS-1$
}
} else {
if (isLazyActivate(options) && !isTriggerSet()) {
if (State.LAZY_STARTING.equals(getState())) {
// a sync listener must have tried to start this module again with the lazy option
return null; // no event to publish; nothing to do
}
// set the lazy starting state and return lazy activation event for firing
setState(State.LAZY_STARTING);
return ModuleEvent.LAZY_ACTIVATION;
}
}
// time to actual start the module
if (!State.STARTING.equals(getState())) {
// TODO this starting state check should not be needed
// but we do it because of the way the system module init works
setState(State.STARTING);
publishEvent(ModuleEvent.STARTING);
}
try {
startWorker();
setState(State.ACTIVE);
return ModuleEvent.STARTED;
} catch (Throwable t) {
// must fire stopping event
setState(State.STOPPING);
publishEvent(ModuleEvent.STOPPING);
if (t instanceof BundleException)
throw (BundleException) t;
throw new BundleException(Msg.Module_StartError, BundleException.ACTIVATOR_ERROR, t);
}
}
private void setTrigger() {
ModuleLoader loader = getCurrentLoader();
if (loader != null) {
loader.getAndSetTrigger();
}
}
private boolean isTriggerSet() {
ModuleLoader loader = getCurrentLoader();
return loader == null ? false : loader.isTriggerSet();
}
private ModuleLoader getCurrentLoader() {
ModuleRevision current = getCurrentRevision();
if (current == null) {
return null;
}
ModuleWiring wiring = current.getWiring();
if (wiring == null) {
return null;
}
try {
return wiring.getModuleLoader();
} catch (UnsupportedOperationException e) {
// just ignore and return null;
return null;
}
}
Performs any work associated with starting a module. For example,
loading and calling start on an activator.
Throws: - BundleException – if there was an exception starting the module
/**
* Performs any work associated with starting a module. For example,
* loading and calling start on an activator.
* @throws BundleException if there was an exception starting the module
*/
protected void startWorker() throws BundleException {
// Do nothing
}
private ModuleEvent doStop() throws BundleException {
setState(State.STOPPING);
publishEvent(ModuleEvent.STOPPING);
try {
stopWorker();
return ModuleEvent.STOPPED;
} catch (Throwable t) {
if (t instanceof BundleException)
throw (BundleException) t;
throw new BundleException(Msg.Module_StopError, BundleException.ACTIVATOR_ERROR, t);
} finally {
// must always set the state to stopped
setState(State.RESOLVED);
}
}
Performs any work associated with stopping a module. For example,
calling stop on an activator.
Throws: - BundleException – if there was an exception stopping the module
/**
* Performs any work associated with stopping a module. For example,
* calling stop on an activator.
* @throws BundleException if there was an exception stopping the module
*/
protected void stopWorker() throws BundleException {
// Do nothing
}
@Override
public String toString() {
return getCurrentRevision() + " [id=" + id + "]"; //$NON-NLS-1$ //$NON-NLS-2$
}
private void persistStartOptions(StartOptions... options) {
if (StartOptions.TRANSIENT.isContained(options) || StartOptions.TRANSIENT_RESUME.isContained(options) || StartOptions.LAZY_TRIGGER.isContained(options)) {
return;
}
if (StartOptions.USE_ACTIVATION_POLICY.isContained(options)) {
settings.add(Settings.USE_ACTIVATION_POLICY);
} else {
settings.remove(Settings.USE_ACTIVATION_POLICY);
}
settings.add(Settings.AUTO_START);
revisions.getContainer().moduleDatabase.persistSettings(settings, this);
}
private void persistStopOptions(StopOptions... options) {
if (StopOptions.TRANSIENT.isContained(options))
return;
settings.remove(Settings.USE_ACTIVATION_POLICY);
settings.remove(Settings.AUTO_START);
revisions.getContainer().moduleDatabase.persistSettings(settings, this);
}
Set if this module should be activated in parallel with other modules that have the same start level
. Params: - parallelActivation – true if the module should be started in parallel; false otherwise
Since: 3.15
/**
* Set if this module should be activated in parallel with other modules that have
* the same {@link #getStartLevel() start level}.
* @param parallelActivation true if the module should be started in parallel; false otherwise
* @since 3.15
*/
public void setParallelActivation(boolean parallelActivation) {
if (parallelActivation) {
settings.add(Settings.PARALLEL_ACTIVATION);
} else {
settings.remove(Settings.PARALLEL_ACTIVATION);
}
revisions.getContainer().moduleDatabase.persistSettings(settings, this);
}
Returns if this module should be activated in parallel with other modules that have the same start level
. Returns: true if the module should be started in parallel; false otherwise Since: 3.15
/**
* Returns if this module should be activated in parallel with other modules that have
* the same {@link #getStartLevel() start level}.
* @return true if the module should be started in parallel; false otherwise
* @since 3.15
*/
public boolean isParallelActivated() {
return settings.contains(Settings.PARALLEL_ACTIVATION);
}
The container is done with the revision and it has been completely removed.
This method allows the resources behind the revision to be cleaned up.
Params: - revision – the revision to clean up
/**
* The container is done with the revision and it has been completely removed.
* This method allows the resources behind the revision to be cleaned up.
* @param revision the revision to clean up
*/
abstract protected void cleanup(ModuleRevision revision);
final boolean isLazyActivate(StartOptions... options) {
if (StartOptions.TRANSIENT.isContained(options)) {
if (!StartOptions.USE_ACTIVATION_POLICY.isContained(options)) {
return false;
}
} else if (!settings.contains(Settings.USE_ACTIVATION_POLICY)) {
return false;
}
return hasLazyActivatePolicy();
}
final boolean hasLazyActivatePolicy() {
ModuleRevision current = getCurrentRevision();
return current == null ? false : current.hasLazyActivatePolicy();
}
Used internally by the container to determine if any thread is in the middle
of a start operation on this module.
Returns:
/**
* Used internally by the container to determine if any thread is in the middle
* of a start operation on this module.
* @return
*/
final boolean inStart() {
return inStart.get() > 0;
}
}