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.
|
||||
* 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.
|
||||
* 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.
|
||||
* 70 - User interface is up and running.
|
||||
* 80 - All things have been initialized.
|
||||
|
|
Loading…
Reference in New Issue