org.eclipse.osgi.container.SystemModule Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
Tools from the AspectJ project
/*******************************************************************************
* Copyright (c) 2012, 2020 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.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.osgi.container.ModuleContainer.ContainerStartLevel;
import org.eclipse.osgi.container.ModuleContainerAdaptor.ContainerEvent;
import org.eclipse.osgi.container.ModuleContainerAdaptor.ModuleEvent;
import org.eclipse.osgi.internal.messages.Msg;
import org.eclipse.osgi.report.resolution.ResolutionReport;
import org.osgi.framework.AdminPermission;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.framework.launch.Framework;
import org.osgi.service.resolver.ResolutionException;
/**
* A special kind of module that represents the system module for the container. Additional
* methods are available on the system module for operations that effect the whole container.
* For example, initializing the container, restarting and waiting for the container to stop.
* @since 3.10
*/
public abstract class SystemModule extends Module {
private volatile AtomicReference forStop = new AtomicReference<>();
public SystemModule(ModuleContainer container) {
super(Long.valueOf(0), Constants.SYSTEM_BUNDLE_LOCATION, container, EnumSet.of(Settings.AUTO_START, Settings.USE_ACTIVATION_POLICY), Integer.valueOf(0));
}
/**
* Initializes the module container
* @throws BundleException if an exeption occurred while initializing
*/
public final void init() throws BundleException {
getRevisions().getContainer().checkAdminPermission(getBundle(), AdminPermission.EXECUTE);
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;
getContainer().getAdaptor().initBegin();
checkValid();
if (ACTIVE_SET.contains(getState()))
return;
getRevisions().getContainer().open();
if (getState().equals(State.INSTALLED)) {
// 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;
ResolutionReport report;
try {
report = getRevisions().getContainer().resolve(Collections.singletonList((Module) 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 (ACTIVE_SET.contains(getState()))
return;
if (getState().equals(State.INSTALLED)) {
String reportMessage = report.getResolutionReportMessage(getCurrentRevision());
throw new BundleException(Msg.Module_ResolveError + reportMessage, BundleException.RESOLVE_ERROR);
}
}
setState(State.STARTING);
AtomicReference existingForStop = forStop;
if (existingForStop.get() != null) {
// There was a previous launch, reset the reference forStop
forStop = new AtomicReference<>();
}
publishEvent(ModuleEvent.STARTING);
try {
initWorker();
} catch (Throwable t) {
setState(State.STOPPING);
publishEvent(ModuleEvent.STOPPING);
setState(State.RESOLVED);
publishEvent(ModuleEvent.STOPPED);
getRevisions().getContainer().close();
if (t instanceof BundleException) {
throw (BundleException) t;
}
throw new BundleException("Error initializing container.", BundleException.ACTIVATOR_ERROR, t); //$NON-NLS-1$
}
} finally {
getContainer().getAdaptor().initEnd();
if (lockedStarted) {
unlockStateChange(ModuleEvent.STARTED);
}
inStart.decrementAndGet();
}
}
/**
* Waits until the module container has stopped.
* @param timeout The amount of time to wait.
* @return The container event indicated why the framework stopped
* or if there was a time out waiting for stop.
* @see Framework#waitForStop(long)
* @throws InterruptedException if the thread was interrupted while waiting
*/
public ContainerEvent waitForStop(long timeout) throws InterruptedException {
final boolean waitForever = timeout == 0;
final long start = System.currentTimeMillis();
long timeLeft = timeout;
AtomicReference stopEvent = null;
State currentState = null;
boolean stateLocked = false;
try {
if (timeout == 0) {
stateChangeLock.lockInterruptibly();
stateLocked = true;
} else {
stateLocked = stateChangeLock.tryLock(timeLeft, TimeUnit.MILLISECONDS);
}
if (stateLocked) {
stopEvent = forStop;
currentState = getState();
}
} finally {
if (stateLocked) {
stateChangeLock.unlock();
}
}
if (stopEvent == null || currentState == null) {
// Could not lock system module stateChangeLock; timeout
return ContainerEvent.STOPPED_TIMEOUT;
}
if (!ACTIVE_SET.contains(currentState)) {
// check if a past event is waiting for us
ContainerEvent result = stopEvent.get();
if (result != null) {
return result;
}
// framework must not have even been started yet
return ContainerEvent.STOPPED;
}
synchronized (stopEvent) {
do {
ContainerEvent result = stopEvent.get();
if (result != null) {
return result;
}
timeLeft = waitForever ? 0 : start + timeout - System.currentTimeMillis();
if (waitForever || timeLeft > 0) {
stopEvent.wait(timeLeft);
} else {
return ContainerEvent.STOPPED_TIMEOUT;
}
} while (true);
}
}
/**
* @throws BundleException
*/
protected void initWorker() throws BundleException {
// Do nothing
}
@Override
public void start(StartOptions... options) throws BundleException {
// make sure to init if needed
init();
// Always transient
super.start(StartOptions.TRANSIENT, StartOptions.USE_ACTIVATION_POLICY);
getRevisions().getContainer().adaptor.publishContainerEvent(ContainerEvent.STARTED, this, null);
}
@Override
public void stop(StopOptions... options) throws BundleException {
ContainerEvent containerEvent = ContainerEvent.STOPPED_TIMEOUT;
// Need to lock the state change lock with no state to prevent
// other threads from starting the framework while we are shutting down
try {
if (stateChangeLock.tryLock(10, TimeUnit.SECONDS)) {
try {
try {
// Always transient
super.stop(StopOptions.TRANSIENT);
} catch (BundleException e) {
getRevisions().getContainer().adaptor.publishContainerEvent(ContainerEvent.ERROR, this, e);
// must continue on
}
if (holdsTransitionEventLock(ModuleEvent.UPDATED)) {
containerEvent = ContainerEvent.STOPPED_UPDATE;
} else if (holdsTransitionEventLock(ModuleEvent.UNRESOLVED)) {
containerEvent = ContainerEvent.STOPPED_REFRESH;
} else {
containerEvent = ContainerEvent.STOPPED;
}
getRevisions().getContainer().adaptor.publishContainerEvent(containerEvent, this, null);
getRevisions().getContainer().close();
} finally {
AtomicReference eventReference = forStop;
eventReference.compareAndSet(null, containerEvent);
stateChangeLock.unlock();
synchronized (eventReference) {
eventReference.notifyAll();
}
}
} else {
throw new BundleException(Msg.SystemModule_LockError);
}
} catch (InterruptedException e) {
getRevisions().getContainer().adaptor.publishContainerEvent(ContainerEvent.ERROR, this, e);
throw new BundleException(Msg.Module_LockError + toString(), BundleException.STATECHANGE_ERROR, e);
}
}
/**
* Restarts the module container.
* @see Framework#update()
* @throws BundleException
*/
public void update() throws BundleException {
getContainer().checkAdminPermission(getBundle(), AdminPermission.LIFECYCLE);
State previousState;
lockStateChange(ModuleEvent.UPDATED);
try {
previousState = getState();
stop();
} finally {
unlockStateChange(ModuleEvent.UPDATED);
}
// would publish an updated event here but the listener services are down
switch (previousState) {
case STARTING :
init();
break;
case ACTIVE :
start();
default :
break;
}
}
@Override
protected void startWorker() throws BundleException {
super.startWorker();
((ContainerStartLevel) getRevisions().getContainer().getFrameworkStartLevel()).doContainerStartLevel(this, ContainerStartLevel.USE_BEGINNING_START_LEVEL);
}
@Override
protected void stopWorker() throws BundleException {
super.stopWorker();
((ContainerStartLevel) getRevisions().getContainer().getFrameworkStartLevel()).doContainerStartLevel(this, 0);
}
}