[automation] Add provider script extension (#4513)
* [automation] Add provider script extension This new script extension allow scripts to provide openHAB entities like Items without needing to manually handle the lifecycle of those. First, we will only provide an itemRegistry, but this can easily be extended later. Signed-off-by: Florian Hotze <dev@florianhotze.com>pull/4491/merge
parent
4e948db729
commit
f695acfc4c
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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.rulesupport.internal;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.automation.module.script.ScriptExtensionProvider;
|
||||
import org.openhab.core.automation.module.script.rulesupport.shared.ProviderItemRegistryDelegate;
|
||||
import org.openhab.core.automation.module.script.rulesupport.shared.ProviderThingRegistryDelegate;
|
||||
import org.openhab.core.automation.module.script.rulesupport.shared.ScriptedItemProvider;
|
||||
import org.openhab.core.automation.module.script.rulesupport.shared.ScriptedThingProvider;
|
||||
import org.openhab.core.items.ItemRegistry;
|
||||
import org.openhab.core.thing.ThingRegistry;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link ProviderScriptExtension} extends scripts to provide openHAB entities like items.
|
||||
* It handles the lifecycle of these entities, ensuring that they are removed when the script is unloaded.
|
||||
*
|
||||
* @author Florian Hotze - Initial contribution
|
||||
*/
|
||||
@Component(immediate = true)
|
||||
@NonNullByDefault
|
||||
public class ProviderScriptExtension implements ScriptExtensionProvider {
|
||||
private static final String PRESET_NAME = "provider";
|
||||
private static final String ITEM_REGISTRY_NAME = "itemRegistry";
|
||||
private static final String THING_REGISTRY_NAME = "thingRegistry";
|
||||
|
||||
private final Map<String, Map<String, Object>> objectCache = new ConcurrentHashMap<>();
|
||||
|
||||
private final ItemRegistry itemRegistry;
|
||||
private final ScriptedItemProvider itemProvider;
|
||||
private final ThingRegistry thingRegistry;
|
||||
private final ScriptedThingProvider thingProvider;
|
||||
|
||||
@Activate
|
||||
public ProviderScriptExtension(final @Reference ItemRegistry itemRegistry,
|
||||
final @Reference ScriptedItemProvider itemProvider, final @Reference ThingRegistry thingRegistry,
|
||||
final @Reference ScriptedThingProvider thingProvider) {
|
||||
this.itemRegistry = itemRegistry;
|
||||
this.itemProvider = itemProvider;
|
||||
this.thingRegistry = thingRegistry;
|
||||
this.thingProvider = thingProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getDefaultPresets() {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getPresets() {
|
||||
return Set.of(PRESET_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getTypes() {
|
||||
return Set.of(ITEM_REGISTRY_NAME, THING_REGISTRY_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object get(String scriptIdentifier, String type) throws IllegalArgumentException {
|
||||
Map<String, Object> objects = Objects
|
||||
.requireNonNull(objectCache.computeIfAbsent(scriptIdentifier, k -> new HashMap<>()));
|
||||
|
||||
Object obj = objects.get(type);
|
||||
if (obj != null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
return switch (type) {
|
||||
case ITEM_REGISTRY_NAME -> {
|
||||
ProviderItemRegistryDelegate itemRegistryDelegate = new ProviderItemRegistryDelegate(itemRegistry,
|
||||
itemProvider);
|
||||
objects.put(ITEM_REGISTRY_NAME, itemRegistryDelegate);
|
||||
yield itemRegistryDelegate;
|
||||
}
|
||||
case THING_REGISTRY_NAME -> {
|
||||
ProviderThingRegistryDelegate thingRegistryDelegate = new ProviderThingRegistryDelegate(thingRegistry,
|
||||
thingProvider);
|
||||
objects.put(THING_REGISTRY_NAME, thingRegistryDelegate);
|
||||
yield thingRegistryDelegate;
|
||||
}
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> importPreset(String scriptIdentifier, String preset) {
|
||||
if (PRESET_NAME.equals(preset)) {
|
||||
return Map.of(ITEM_REGISTRY_NAME, Objects.requireNonNull(get(scriptIdentifier, ITEM_REGISTRY_NAME)),
|
||||
THING_REGISTRY_NAME, Objects.requireNonNull(get(scriptIdentifier, THING_REGISTRY_NAME)));
|
||||
}
|
||||
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload(String scriptIdentifier) {
|
||||
Map<String, Object> objects = objectCache.remove(scriptIdentifier);
|
||||
if (objects != null) {
|
||||
Object itemRegistry = objects.get(ITEM_REGISTRY_NAME);
|
||||
if (itemRegistry != null) {
|
||||
ProviderItemRegistryDelegate itemRegistryDelegate = (ProviderItemRegistryDelegate) itemRegistry;
|
||||
itemRegistryDelegate.removeAllAddedByScript();
|
||||
}
|
||||
Object thingRegistry = objects.get(THING_REGISTRY_NAME);
|
||||
if (thingRegistry != null) {
|
||||
ProviderThingRegistryDelegate thingRegistryDelegate = (ProviderThingRegistryDelegate) thingRegistry;
|
||||
thingRegistryDelegate.removeAllAddedByScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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.rulesupport.shared;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.common.registry.RegistryChangeListener;
|
||||
import org.openhab.core.items.GroupItem;
|
||||
import org.openhab.core.items.Item;
|
||||
import org.openhab.core.items.ItemNotFoundException;
|
||||
import org.openhab.core.items.ItemNotUniqueException;
|
||||
import org.openhab.core.items.ItemRegistry;
|
||||
|
||||
/**
|
||||
* The {@link ProviderItemRegistryDelegate} is wrapping a {@link ItemRegistry} to provide a comfortable way to provide
|
||||
* items from scripts without worrying about the need to remove items again when the script is unloaded.
|
||||
* Nonetheless, using the {@link #addPermanent(Item)} method it is still possible to add items permanently.
|
||||
* <p>
|
||||
* Use a new instance of this class for each {@link javax.script.ScriptEngine}.
|
||||
*
|
||||
* @author Florian Hotze - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ProviderItemRegistryDelegate implements ItemRegistry {
|
||||
private final ItemRegistry itemRegistry;
|
||||
|
||||
private final Set<String> items = new HashSet<>();
|
||||
|
||||
private final ScriptedItemProvider itemProvider;
|
||||
|
||||
public ProviderItemRegistryDelegate(ItemRegistry itemRegistry, ScriptedItemProvider itemProvider) {
|
||||
this.itemRegistry = itemRegistry;
|
||||
this.itemProvider = itemProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRegistryChangeListener(RegistryChangeListener<Item> listener) {
|
||||
itemRegistry.addRegistryChangeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Item> getAll() {
|
||||
return itemRegistry.getAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Item> stream() {
|
||||
return itemRegistry.stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Item get(String key) {
|
||||
return itemRegistry.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRegistryChangeListener(RegistryChangeListener<Item> listener) {
|
||||
itemRegistry.removeRegistryChangeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item add(Item element) {
|
||||
String itemName = element.getName();
|
||||
// Check for item already existing here because the item might exist in a different provider, so we need to
|
||||
// check the registry and not only the provider itself
|
||||
if (get(itemName) != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot add item, because an item with same name (" + itemName + ") already exists.");
|
||||
}
|
||||
|
||||
itemProvider.add(element);
|
||||
items.add(itemName);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item permanently to the registry.
|
||||
* This item will be kept in the registry even if the script is unloaded.
|
||||
*
|
||||
* @param element the item to be added (must not be null)
|
||||
* @return the added item
|
||||
*/
|
||||
public Item addPermanent(Item element) {
|
||||
return itemRegistry.add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Item update(Item element) {
|
||||
if (items.contains(element.getName())) {
|
||||
return itemProvider.update(element);
|
||||
}
|
||||
return itemRegistry.update(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Item remove(String key) {
|
||||
if (items.remove(key)) {
|
||||
return itemProvider.remove(key);
|
||||
}
|
||||
|
||||
return itemRegistry.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getItem(String name) throws ItemNotFoundException {
|
||||
return itemRegistry.getItem(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getItemByPattern(String name) throws ItemNotFoundException, ItemNotUniqueException {
|
||||
return itemRegistry.getItemByPattern(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Item> getItems() {
|
||||
return itemRegistry.getItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Item> getItemsOfType(String type) {
|
||||
return itemRegistry.getItemsOfType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Item> getItems(String pattern) {
|
||||
return itemRegistry.getItems(pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Item> getItemsByTag(String... tags) {
|
||||
return itemRegistry.getItemsByTag(tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Item> getItemsByTagAndType(String type, String... tags) {
|
||||
return itemRegistry.getItemsByTagAndType(type, tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Item> Collection<T> getItemsByTag(Class<T> typeFilter, String... tags) {
|
||||
return itemRegistry.getItemsByTag(typeFilter, tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Item remove(String itemName, boolean recursive) {
|
||||
Item item = get(itemName);
|
||||
if (recursive && item instanceof GroupItem groupItem) {
|
||||
for (String member : getMemberNamesRecursively(groupItem, getAll())) {
|
||||
remove(member);
|
||||
}
|
||||
}
|
||||
if (item != null) {
|
||||
remove(item.getName());
|
||||
return item;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all items that are provided by this script.
|
||||
* To be called when the script is unloaded or reloaded.
|
||||
*/
|
||||
public void removeAllAddedByScript() {
|
||||
for (String item : items) {
|
||||
itemProvider.remove(item);
|
||||
}
|
||||
items.clear();
|
||||
}
|
||||
|
||||
private List<String> getMemberNamesRecursively(GroupItem groupItem, Collection<Item> allItems) {
|
||||
List<String> memberNames = new ArrayList<>();
|
||||
for (Item item : allItems) {
|
||||
if (item.getGroupNames().contains(groupItem.getName())) {
|
||||
memberNames.add(item.getName());
|
||||
if (item instanceof GroupItem groupItem1) {
|
||||
memberNames.addAll(getMemberNamesRecursively(groupItem1, allItems));
|
||||
}
|
||||
}
|
||||
}
|
||||
return memberNames;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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.rulesupport.shared;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.common.registry.RegistryChangeListener;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingRegistry;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
|
||||
/**
|
||||
* The {@link ProviderThingRegistryDelegate} is wrapping a {@link ThingRegistry} to provide a comfortable way to provide
|
||||
* Things from scripts without worrying about the need to remove Things again when the script is unloaded.
|
||||
* Nonetheless, using the {@link #addPermanent(Thing)} method it is still possible to add Things permanently.
|
||||
* <p>
|
||||
* Use a new instance of this class for each {@link javax.script.ScriptEngine}.
|
||||
*
|
||||
* @author Florian Hotze - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ProviderThingRegistryDelegate implements ThingRegistry {
|
||||
private final ThingRegistry thingRegistry;
|
||||
|
||||
private final Set<ThingUID> things = new HashSet<>();
|
||||
|
||||
private final ScriptedThingProvider thingProvider;
|
||||
|
||||
public ProviderThingRegistryDelegate(ThingRegistry thingRegistry, ScriptedThingProvider thingProvider) {
|
||||
this.thingRegistry = thingRegistry;
|
||||
this.thingProvider = thingProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRegistryChangeListener(RegistryChangeListener<Thing> listener) {
|
||||
thingRegistry.addRegistryChangeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Thing> getAll() {
|
||||
return thingRegistry.getAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Thing> stream() {
|
||||
return thingRegistry.stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRegistryChangeListener(RegistryChangeListener<Thing> listener) {
|
||||
thingRegistry.removeRegistryChangeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thing add(Thing element) {
|
||||
ThingUID thingUID = element.getUID();
|
||||
// Check for Thing already existing here because the Thing might exist in a different provider, so we need to
|
||||
// check the registry and not only the provider itself
|
||||
if (get(thingUID) != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot add Thing, because a Thing with same UID (" + thingUID + ") already exists.");
|
||||
}
|
||||
|
||||
thingProvider.add(element);
|
||||
things.add(thingUID);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Thing permanently to the registry.
|
||||
* This Thing will be kept in the registry even if the script is unloaded.
|
||||
*
|
||||
* @param element the Thing to be added (must not be null)
|
||||
* @return the added Thing
|
||||
*/
|
||||
public Thing addPermanent(Thing element) {
|
||||
return thingRegistry.add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Thing update(Thing element) {
|
||||
if (things.contains(element.getUID())) {
|
||||
return thingProvider.update(element);
|
||||
}
|
||||
|
||||
return thingRegistry.update(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Thing get(ThingUID uid) {
|
||||
return thingRegistry.get(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Channel getChannel(ChannelUID channelUID) {
|
||||
return thingRegistry.getChannel(channelUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateConfiguration(ThingUID thingUID, Map<String, Object> configurationParameters) {
|
||||
thingRegistry.updateConfiguration(thingUID, configurationParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Thing remove(ThingUID thingUID) {
|
||||
// Give the ThingHandler the chance to perform any removal operations instead of forcefully removing from
|
||||
// ScriptedThingProvider
|
||||
// If the Thing was provided by ScriptedThingProvider, it will be removed from there by listening to
|
||||
// ThingStatusEvent for ThingStatus.REMOVED in ScriptedThingProvider
|
||||
return thingRegistry.remove(thingUID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all Things that are provided by this script.
|
||||
* To be called when the script is unloaded or reloaded.
|
||||
*/
|
||||
public void removeAllAddedByScript() {
|
||||
for (ThingUID thing : things) {
|
||||
thingProvider.remove(thing);
|
||||
}
|
||||
things.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Thing forceRemove(ThingUID thingUID) {
|
||||
if (things.remove(thingUID)) {
|
||||
return thingProvider.remove(thingUID);
|
||||
}
|
||||
|
||||
return thingRegistry.forceRemove(thingUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Thing createThingOfType(ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID,
|
||||
@Nullable ThingUID bridgeUID, @Nullable String label, Configuration configuration) {
|
||||
return thingRegistry.createThingOfType(thingTypeUID, thingUID, bridgeUID, label, configuration);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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.rulesupport.shared;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.common.registry.AbstractProvider;
|
||||
import org.openhab.core.common.registry.ManagedProvider;
|
||||
import org.openhab.core.items.Item;
|
||||
import org.openhab.core.items.ItemProvider;
|
||||
import org.openhab.core.items.ItemUtil;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This {@link ItemProvider} keeps items provided by scripts during runtime.
|
||||
* This ensures that items are not kept on reboot, but have to be provided by the scripts again.
|
||||
*
|
||||
* @author Florian Hotze - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(immediate = true, service = { ScriptedItemProvider.class, ItemProvider.class })
|
||||
public class ScriptedItemProvider extends AbstractProvider<Item>
|
||||
implements ItemProvider, ManagedProvider<Item, String> {
|
||||
private final Logger logger = LoggerFactory.getLogger(ScriptedItemProvider.class);
|
||||
private final Map<String, Item> items = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Collection<Item> getAll() {
|
||||
return items.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Item get(String itemName) {
|
||||
return items.get(itemName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Item item) {
|
||||
if (!ItemUtil.isValidItemName(item.getName())) {
|
||||
throw new IllegalArgumentException("The item name '" + item.getName() + "' is invalid.");
|
||||
}
|
||||
if (items.get(item.getName()) != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot add item, because an item with same name (" + item.getName() + ") already exists.");
|
||||
}
|
||||
items.put(item.getName(), item);
|
||||
|
||||
notifyListenersAboutAddedElement(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Item update(Item item) {
|
||||
Item oldItem = items.get(item.getName());
|
||||
if (oldItem != null) {
|
||||
items.put(item.getName(), item);
|
||||
notifyListenersAboutUpdatedElement(oldItem, item);
|
||||
} else {
|
||||
logger.warn("Could not update item with name '{}', because it does not exist.", item.getName());
|
||||
}
|
||||
return oldItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Item remove(String itemName) {
|
||||
Item item = items.remove(itemName);
|
||||
if (item != null) {
|
||||
notifyListenersAboutRemovedElement(item);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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.rulesupport.shared;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.common.registry.AbstractProvider;
|
||||
import org.openhab.core.common.registry.ManagedProvider;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventSubscriber;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingProvider;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.events.ThingStatusInfoEvent;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This {@link ThingProvider} keeps things provided by scripts during runtime.
|
||||
* This ensures that things are not kept on reboot, but have to be provided by the scripts again.
|
||||
*
|
||||
* @author Florian Hotze - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(immediate = true, service = { ScriptedThingProvider.class, ThingProvider.class, EventSubscriber.class })
|
||||
public class ScriptedThingProvider extends AbstractProvider<Thing>
|
||||
implements ThingProvider, ManagedProvider<Thing, ThingUID>, EventSubscriber {
|
||||
private final Logger logger = LoggerFactory.getLogger(ScriptedThingProvider.class);
|
||||
private final Map<ThingUID, Thing> things = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Collection<Thing> getAll() {
|
||||
return things.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Thing get(ThingUID uid) {
|
||||
return things.get(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Thing thing) {
|
||||
if (things.get(thing.getUID()) != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot add thing, because a thing with same UID (" + thing.getUID() + ") already exists.");
|
||||
}
|
||||
things.put(thing.getUID(), thing);
|
||||
|
||||
notifyListenersAboutAddedElement(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Thing update(Thing thing) {
|
||||
Thing oldThing = things.get(thing.getUID());
|
||||
if (oldThing != null) {
|
||||
things.put(thing.getUID(), thing);
|
||||
notifyListenersAboutUpdatedElement(oldThing, thing);
|
||||
} else {
|
||||
logger.warn("Cannot update thing with UID '{}', because it does not exist.", thing.getUID());
|
||||
}
|
||||
return oldThing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Thing remove(ThingUID uid) {
|
||||
Thing thing = things.remove(uid);
|
||||
if (thing != null) {
|
||||
notifyListenersAboutRemovedElement(thing);
|
||||
}
|
||||
return thing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSubscribedEventTypes() {
|
||||
return Set.of(ThingStatusInfoEvent.TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(Event event) {
|
||||
if (event instanceof ThingStatusInfoEvent thingStatusInfoEvent) {
|
||||
if (thingStatusInfoEvent.getStatusInfo().getStatus() == ThingStatus.REMOVED) {
|
||||
remove(thingStatusInfoEvent.getThingUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue