Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7538913
Add access to various system registries, OSGi instances and the abili…
Apr 9, 2026
831ac4e
Set required startlevel in ScriptEngineOSGiTest
Apr 9, 2026
6839f30
Make RuleManager a dynamic reference
Apr 10, 2026
9921c74
Revert "Set required startlevel in ScriptEngineOSGiTest"
Apr 10, 2026
135e265
Add additional convenience methods
Apr 10, 2026
24f7e63
Add more overloads
Apr 10, 2026
252c1f2
Fix socket leak
Apr 11, 2026
321ef89
Reorganize classes and implement extensions
Apr 11, 2026
f926dbd
Complete reorganization
May 17, 2026
96886d6
Add missed JavaDocs
May 20, 2026
9372b3e
Fix missed JavaDocs
May 20, 2026
46eba83
Modify implicit imports:
May 22, 2026
06fc762
Call existing static methods from RuleExtensions, some further JavaDo…
May 22, 2026
bffd0a9
Revise implicit imports
May 28, 2026
c1dbebd
Add TimeZone and Locale to available providers and methods
May 30, 2026
09efd8c
Move "helper" classes to existing package with similar content
May 31, 2026
59cce44
Address some review comments
Jun 4, 2026
acefac3
Remove export of no longer existing package
Jun 4, 2026
e88832f
Add missing import
Jun 4, 2026
9b1bf11
Move common methods to new class Utils and try to get map nullness un…
Jun 4, 2026
1449a9c
Create tests for Rules.java
Jun 5, 2026
815f081
Create tests for Items.java
Jun 5, 2026
c890aa1
Create tests for Channels.java
Jun 6, 2026
d4536b8
Create tests for ItemExtensions.java and RuleExtensions.java
Jun 6, 2026
8542a9a
Reintroduce warnings and reduce logging flexibility
Jun 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bundles/org.openhab.core.model.rule/bnd.bnd
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Import-Package: \
org.openhab.core.model.items,\
org.openhab.core.model.script,\
org.openhab.core.model.script.engine.action,\
org.openhab.core.model.script.helper,\
org.openhab.core.persistence,\
Comment thread
Nadahar marked this conversation as resolved.
org.openhab.core.persistence.extensions,\
org.openhab.core.service,\
Expand Down
3 changes: 3 additions & 0 deletions bundles/org.openhab.core.model.script/bnd.bnd
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Export-Package: org.openhab.core.model.script,\
org.openhab.core.model.script.engine.action,\
org.openhab.core.model.script.extension,\
org.openhab.core.model.script.formatting,\
org.openhab.core.model.script.helper,\
org.openhab.core.model.script.interpreter,\
Comment thread
Nadahar marked this conversation as resolved.
org.openhab.core.model.script.jvmmodel,\
org.openhab.core.model.script.lib,\
Expand All @@ -25,6 +26,7 @@ Import-Package: \
org.openhab.core.common.registry,\
org.openhab.core.ephemeris,\
org.openhab.core.events,\
org.openhab.core.i18n,\
org.openhab.core.io.console,\
Comment thread
Nadahar marked this conversation as resolved.
org.openhab.core.io.console.extensions,\
org.openhab.core.io.net.exec,\
Expand All @@ -42,6 +44,7 @@ Import-Package: \
org.openhab.core.thing,\
org.openhab.core.thing.binding,\
org.openhab.core.thing.events,\
org.openhab.core.thing.link,\
org.openhab.core.transform,\
org.openhab.core.transform.actions,\
org.openhab.core.types,\
Expand Down
5 changes: 5 additions & 0 deletions bundles/org.openhab.core.model.script/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@
<artifactId>org.openhab.core.io.net</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.automation</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.automation.module.script</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,32 @@
*/
package org.openhab.core.model.script;

import java.time.ZoneId;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;

import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.RuleManager;
import org.openhab.core.automation.RuleRegistry;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.items.ItemRegistry;
import org.openhab.core.items.MetadataRegistry;
import org.openhab.core.model.core.ModelRepository;
import org.openhab.core.model.script.engine.ScriptEngine;
import org.openhab.core.model.script.engine.action.ActionService;
import org.openhab.core.scheduler.Scheduler;
import org.openhab.core.thing.ThingRegistry;
import org.openhab.core.thing.binding.ThingActions;
import org.openhab.core.thing.link.ItemChannelLinkRegistry;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
Expand All @@ -38,6 +52,7 @@
*
* @author Davy Vanherbergen - Initial contribution
* @author Kai Kreuzer - renamed and removed interface
* @author Ravi Nadahar - added additional registries for retrieval
*/
@Component(immediate = true, service = ScriptServiceUtil.class)
public class ScriptServiceUtil {
Expand All @@ -50,6 +65,12 @@ public class ScriptServiceUtil {
private final ThingRegistry thingRegistry;
private final EventPublisher eventPublisher;
private final ModelRepository modelRepository;
private final MetadataRegistry metadataRegistry;
private final RuleRegistry ruleRegistry;
private final ItemChannelLinkRegistry itemChannelLinkRegistry;
private final TimeZoneProvider timeZoneProvider;
private final LocaleProvider localeProvider;
private volatile @Nullable RuleManager ruleManager;
private final Scheduler scheduler;

private final AtomicReference<ScriptEngine> scriptEngine = new AtomicReference<>();
Expand All @@ -59,11 +80,19 @@ public class ScriptServiceUtil {
@Activate
public ScriptServiceUtil(final @Reference ItemRegistry itemRegistry, final @Reference ThingRegistry thingRegistry,
final @Reference EventPublisher eventPublisher, final @Reference ModelRepository modelRepository,
final @Reference MetadataRegistry metadataRegistry, final @Reference RuleRegistry ruleRegistry,
final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry,
final @Reference TimeZoneProvider timeZoneProvider, final @Reference LocaleProvider localeProvider,
final @Reference Scheduler scheduler) {
this.itemRegistry = itemRegistry;
this.thingRegistry = thingRegistry;
this.eventPublisher = eventPublisher;
this.modelRepository = modelRepository;
this.metadataRegistry = metadataRegistry;
this.ruleRegistry = ruleRegistry;
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
this.timeZoneProvider = timeZoneProvider;
this.localeProvider = localeProvider;
this.scheduler = scheduler;

if (instance != null) {
Expand All @@ -73,6 +102,15 @@ public ScriptServiceUtil(final @Reference ItemRegistry itemRegistry, final @Refe
logger.debug("ScriptServiceUtil started");
}

@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
void setRuleManager(RuleManager ruleManager) {
this.ruleManager = ruleManager;
}

void unsetRuleManager(RuleManager ruleManager) {
this.ruleManager = null;
}

@Deactivate
public void deactivate() {
logger.debug("ScriptServiceUtil stopped");
Expand All @@ -83,6 +121,9 @@ private static ScriptServiceUtil getInstance() {
return instance;
}

/**
* @return The {@link ItemRegistry}.
*/
public static ItemRegistry getItemRegistry() {
return getInstance().itemRegistry;
}
Expand All @@ -91,14 +132,27 @@ public ItemRegistry getItemRegistryInstance() {
return itemRegistry;
}

/**
* @return The {@link ThingRegistry} instance.
*/
public static ThingRegistry getThingRegistry() {
return getInstance().thingRegistry;
}

public ThingRegistry getThingRegistryInstance() {
return thingRegistry;
}

/**
* @return The {@link EventPublisher} instance.
*/
public static EventPublisher getEventPublisher() {
return getInstance().eventPublisher;
}

/**
* @return The {@link ModelRepository} instance.
*/
public static ModelRepository getModelRepository() {
return getInstance().modelRepository;
}
Expand All @@ -107,6 +161,96 @@ public ModelRepository getModelRepositoryInstance() {
return modelRepository;
}

/**
* @return The {@link MetadataRegistry} instance.
*/
public static MetadataRegistry getMetadataRegistry() {
return getInstance().metadataRegistry;
}

public MetadataRegistry getMetadataRegistryInstance() {
return metadataRegistry;
}

/**
* @return The {@link RuleRegistry} instance.
*/
public static RuleRegistry getRuleRegistry() {
return getInstance().ruleRegistry;
}

public RuleRegistry getRuleRegistryInstance() {
return ruleRegistry;
}

/**
* @return The {@link ItemChannelLinkRegistry} instance.
*/
public static ItemChannelLinkRegistry getItemChannelLinkRegistry() {
return getInstance().itemChannelLinkRegistry;
}

public ItemChannelLinkRegistry getItemChannelLinkRegistryInstance() {
return itemChannelLinkRegistry;
}

/**
* @return The currently openHAB configured {@link TimeZone}.
*/
public static TimeZone getTimeZone() {
return TimeZone.getTimeZone(getInstance().timeZoneProvider.getTimeZone());
}

/**
* @return The currently openHAB configured {@link ZoneId}.
*/
public static ZoneId getZoneId() {
return getInstance().timeZoneProvider.getTimeZone();
}

/**
* @return The {@link TimeZoneProvider} instance.
*/
public static TimeZoneProvider getTimeZoneProvider() {
return getInstance().timeZoneProvider;
}

public TimeZoneProvider getTimeZoneProviderInstance() {
return timeZoneProvider;
}

/**
* @return The currently openHAB configured {@link Locale}.
*/
public static Locale getLocale() {
return getInstance().localeProvider.getLocale();
}

/**
* @return The {@link LocaleProvider} instance.
*/
public static LocaleProvider getLocaleProvide() {
return getInstance().localeProvider;
}
Comment thread
Nadahar marked this conversation as resolved.

public LocaleProvider getLocaleProviderInstance() {
return localeProvider;
}

/**
* @return The {@link RuleManager} / rule engine instance or {@code null} if it doesn't exist.
*/
public @Nullable static RuleManager getRuleManager() {
return getInstance().ruleManager;
}

public @Nullable RuleManager getRuleManagerInstance() {
return ruleManager;
}

/**
* @return The {@link Scheduler} instance.
*/
public static Scheduler getScheduler() {
return getInstance().scheduler;
}
Expand All @@ -119,12 +263,18 @@ public static ScriptEngine getScriptEngine() {
return getInstance().scriptEngine.get();
}

/**
* @return A {@link List} of currently registered {@link ActionService} instances.
*/
public static List<ActionService> getActionServices() {
return getInstance().actionServices;
return List.copyOf(getInstance().actionServices);
}

/**
* @return A {@link List} of currently registered {@link ThingActions} instances.
*/
public static List<ThingActions> getThingActions() {
return getInstance().thingActions;
return List.copyOf(getInstance().thingActions);
}

public List<ActionService> getActionServiceInstances() {
Expand Down Expand Up @@ -162,4 +312,38 @@ public void unsetScriptEngine(ScriptEngine scriptEngine) {
// uninjected as a callback from the script engine, not via DS as it is a circular dependency...
this.scriptEngine.compareAndSet(scriptEngine, null);
}

/**
* Retrieve an OSGi instance of the specified {@link Class}, if it exists. The reference to the instance is
* <i>unreserved</i>, which means that the instance might stop being valid at any time, for example if the service
* or the containing bundle is stopped.
* <p>
* Returning an unreserved service isn't kosher in the world of OSGi, but the only alternative is that the scripts
* that retrieve the instance are responsible for unregistering the reservation after use. That isn't a reasonable
* thing to expect from user scripts. The chance that a service is stopped while OH is running is quite small, so
* on balance, returning an unreserved service instance seems like the best way to do it. It isn't much different
* from returning an instance to a registry that is reserved by {@link ScriptServiceUtil} - if the
* {@link ScriptServiceUtil} itself is stopped, the instance might become invalid while the script is using it.
*
* @param <T> the class type.
* @param clazz the class of the instance to get.
* @return The instance or {@code null} if the instance wasn't found.
*/
public static @Nullable <T> T getInstance(Class<T> clazz) {
Bundle bundle = FrameworkUtil.getBundle(clazz);
if (bundle != null) {
BundleContext bc = bundle.getBundleContext();
if (bc != null) {
ServiceReference<T> ref = bc.getServiceReference(clazz);
if (ref != null) {
T result = bc.getService(ref);
if (result != null) {
bc.ungetService(ref);
}
return result;
}
}
}
return null;
Comment thread
Nadahar marked this conversation as resolved.
}
}
Loading
Loading