Add a ScriptEngineFactory bundle tracker (#3275)
* Add a ScriptEngineFactory bundle tracker The `ScriptEngingeFactoryBundleTracker` tracks all bundles that provide `ScriptEngineFcatory` capabilities and sets a `ReadyMarker` if all of them are activated. Signed-off-by: Jan N. Klug <github@klug.nrw>pull/3637/head
parent
6bb15b806c
commit
796f66a2fa
|
@ -0,0 +1,156 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||||
|
*
|
||||||
|
* See the NOTICE file(s) distributed with this work for additional
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.openhab.core.automation.module.script.internal;
|
||||||
|
|
||||||
|
import java.util.Dictionary;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.core.automation.module.script.ScriptEngineFactory;
|
||||||
|
import org.openhab.core.service.ReadyMarker;
|
||||||
|
import org.openhab.core.service.ReadyMarkerFilter;
|
||||||
|
import org.openhab.core.service.ReadyService;
|
||||||
|
import org.openhab.core.service.StartLevelService;
|
||||||
|
import org.osgi.framework.Bundle;
|
||||||
|
import org.osgi.framework.BundleContext;
|
||||||
|
import org.osgi.framework.BundleEvent;
|
||||||
|
import org.osgi.service.component.annotations.Activate;
|
||||||
|
import org.osgi.service.component.annotations.Component;
|
||||||
|
import org.osgi.service.component.annotations.Deactivate;
|
||||||
|
import org.osgi.service.component.annotations.Reference;
|
||||||
|
import org.osgi.util.tracker.BundleTracker;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ScriptEngineFactoryBundleTracker} tracks bundles that provide {@link ScriptEngineFactory} and sets the
|
||||||
|
* {@link #READY_MARKER} when all registered bundles are active
|
||||||
|
*
|
||||||
|
* @author Jan N. Klug - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
@Component(immediate = true)
|
||||||
|
public class ScriptEngineFactoryBundleTracker extends BundleTracker<Bundle> implements ReadyService.ReadyTracker {
|
||||||
|
private static final int STATE_MASK = Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE | Bundle.STARTING
|
||||||
|
| Bundle.STOPPING | Bundle.UNINSTALLED;
|
||||||
|
public static final ReadyMarker READY_MARKER = new ReadyMarker("automation", "scriptEngineFactories");
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(ScriptEngineFactoryBundleTracker.class);
|
||||||
|
|
||||||
|
private final ReadyService readyService;
|
||||||
|
private final StartLevelService startLevelService;
|
||||||
|
|
||||||
|
private final Map<String, Integer> bundles = new ConcurrentHashMap<>();
|
||||||
|
private boolean ready = false;
|
||||||
|
|
||||||
|
@Activate
|
||||||
|
public ScriptEngineFactoryBundleTracker(final @Reference ReadyService readyService,
|
||||||
|
final @Reference StartLevelService startLevelService, BundleContext bc) {
|
||||||
|
super(bc, STATE_MASK, null);
|
||||||
|
this.readyService = readyService;
|
||||||
|
this.startLevelService = startLevelService;
|
||||||
|
|
||||||
|
this.open();
|
||||||
|
|
||||||
|
readyService.registerTracker(this, new ReadyMarkerFilter().withType(StartLevelService.STARTLEVEL_MARKER_TYPE)
|
||||||
|
.withIdentifier(Integer.toString(StartLevelService.STARTLEVEL_OSGI)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deactivate
|
||||||
|
public void deactivate() throws Exception {
|
||||||
|
this.close();
|
||||||
|
ready = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean allBundlesActive() {
|
||||||
|
return bundles.values().stream().allMatch(i -> i == Bundle.ACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle addingBundle(@NonNullByDefault({}) Bundle bundle, @Nullable BundleEvent event) {
|
||||||
|
String bsn = bundle.getSymbolicName();
|
||||||
|
int state = bundle.getState();
|
||||||
|
if (isScriptingBundle(bundle)) {
|
||||||
|
logger.debug("Added {}: {} ", bsn, stateToString(state));
|
||||||
|
bundles.put(bsn, state);
|
||||||
|
}
|
||||||
|
checkReady();
|
||||||
|
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void modifiedBundle(@NonNullByDefault({}) Bundle bundle, @Nullable BundleEvent event,
|
||||||
|
@NonNullByDefault({}) Bundle object) {
|
||||||
|
String bsn = bundle.getSymbolicName();
|
||||||
|
int state = bundle.getState();
|
||||||
|
if (isScriptingBundle(bundle)) {
|
||||||
|
logger.debug("Modified {}: {}", bsn, stateToString(state));
|
||||||
|
bundles.put(bsn, state);
|
||||||
|
}
|
||||||
|
checkReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removedBundle(@NonNullByDefault({}) Bundle bundle, @Nullable BundleEvent event,
|
||||||
|
@NonNullByDefault({}) Bundle object) {
|
||||||
|
String bsn = bundle.getSymbolicName();
|
||||||
|
if (isScriptingBundle(bundle)) {
|
||||||
|
logger.debug("Removed {}", bsn);
|
||||||
|
bundles.remove(bsn);
|
||||||
|
}
|
||||||
|
checkReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReadyMarkerAdded(ReadyMarker readyMarker) {
|
||||||
|
checkReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReadyMarkerRemoved(ReadyMarker readyMarker) {
|
||||||
|
ready = false;
|
||||||
|
readyService.unmarkReady(READY_MARKER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkReady() {
|
||||||
|
if (!ready && startLevelService.getStartLevel() > StartLevelService.STARTLEVEL_OSGI && allBundlesActive()) {
|
||||||
|
logger.info("All automation bundles ready.");
|
||||||
|
readyService.markReady(READY_MARKER);
|
||||||
|
ready = true;
|
||||||
|
} else if (ready && !allBundlesActive()) {
|
||||||
|
readyService.unmarkReady(READY_MARKER);
|
||||||
|
ready = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String stateToString(int state) {
|
||||||
|
return switch (state) {
|
||||||
|
case Bundle.UNINSTALLED -> "UNINSTALLED";
|
||||||
|
case Bundle.INSTALLED -> "INSTALLED";
|
||||||
|
case Bundle.RESOLVED -> "RESOLVED";
|
||||||
|
case Bundle.STARTING -> "STARTING";
|
||||||
|
case Bundle.STOPPING -> "STOPPING";
|
||||||
|
case Bundle.ACTIVE -> "ACTIVE";
|
||||||
|
default -> "UNKNOWN";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isScriptingBundle(Bundle bundle) {
|
||||||
|
Dictionary<String, String> headers = bundle.getHeaders();
|
||||||
|
String provideCapability = headers.get("Provide-Capability");
|
||||||
|
return provideCapability != null && provideCapability.contains(ScriptEngineFactory.class.getName());
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,7 +58,7 @@ import org.slf4j.LoggerFactory;
|
||||||
* 10 - OSGi application start level has been reached, i.e. bundles are activated.
|
* 10 - OSGi application start level has been reached, i.e. bundles are activated.
|
||||||
* 20 - Model entities (items, things, links, persist config) have been loaded, both from db as well as files.
|
* 20 - Model entities (items, things, links, persist config) have been loaded, both from db as well as files.
|
||||||
* 30 - Item states have been restored from persistence service, where applicable.
|
* 30 - Item states have been restored from persistence service, where applicable.
|
||||||
* 40 - Rules are loaded and parsed, both from db as well as dsl and script files.
|
* 40 - Rules from db, dsl and script files are loaded and parsed, script engine factories are available.
|
||||||
* 50 - Rule engine has executed all "system started" rules and is active.
|
* 50 - Rule engine has executed all "system started" rules and is active.
|
||||||
* 70 - User interface is up and running.
|
* 70 - User interface is up and running.
|
||||||
* 80 - All things have been initialized.
|
* 80 - All things have been initialized.
|
||||||
|
|
Loading…
Reference in New Issue