diff --git a/bundles/core/org.eclipse.smarthome.core.thing.test/src/test/java/org/eclipse/smarthome/core/thing/internal/ChannelItemProviderTest.java b/bundles/core/org.eclipse.smarthome.core.thing.test/src/test/java/org/eclipse/smarthome/core/thing/internal/ChannelItemProviderTest.java index 939812a9ccc..19d2a7bd364 100644 --- a/bundles/core/org.eclipse.smarthome.core.thing.test/src/test/java/org/eclipse/smarthome/core/thing/internal/ChannelItemProviderTest.java +++ b/bundles/core/org.eclipse.smarthome.core.thing.test/src/test/java/org/eclipse/smarthome/core/thing/internal/ChannelItemProviderTest.java @@ -110,7 +110,7 @@ public void testItemRemoval_itemFromOtherProvider() throws Exception { resetAndPrepareListener(); - provider.itemRegistryListener.added(new NumberItem(ITEM_NAME)); + provider.itemRegistryListener.beforeAdding(new NumberItem(ITEM_NAME)); verify(listener, only()).removed(same(provider), same(ITEM)); verify(listener, never()).added(same(provider), same(ITEM)); } @@ -120,12 +120,12 @@ private void resetAndPrepareListener() { reset(listener); doAnswer(invocation -> { // this is crucial as it mimicks the real ItemRegistry's behavior - provider.itemRegistryListener.removed((Item) invocation.getArguments()[1]); + provider.itemRegistryListener.afterRemoving((Item) invocation.getArguments()[1]); return null; }).when(listener).removed(same(provider), any(Item.class)); doAnswer(invocation -> { // this is crucial as it mimicks the real ItemRegistry's behavior - provider.itemRegistryListener.added((Item) invocation.getArguments()[1]); + provider.itemRegistryListener.beforeAdding((Item) invocation.getArguments()[1]); return null; }).when(listener).added(same(provider), any(Item.class)); when(linkRegistry.getBoundChannels(eq(ITEM_NAME))).thenReturn(Collections.singleton(CHANNEL_UID)); diff --git a/bundles/core/org.eclipse.smarthome.core.thing/src/main/java/org/eclipse/smarthome/core/thing/internal/ChannelItemProvider.java b/bundles/core/org.eclipse.smarthome.core.thing/src/main/java/org/eclipse/smarthome/core/thing/internal/ChannelItemProvider.java index eefe41bef4e..4c8f2758d49 100644 --- a/bundles/core/org.eclipse.smarthome.core.thing/src/main/java/org/eclipse/smarthome/core/thing/internal/ChannelItemProvider.java +++ b/bundles/core/org.eclipse.smarthome.core.thing/src/main/java/org/eclipse/smarthome/core/thing/internal/ChannelItemProvider.java @@ -26,6 +26,7 @@ import org.eclipse.smarthome.core.items.ItemFactory; import org.eclipse.smarthome.core.items.ItemProvider; import org.eclipse.smarthome.core.items.ItemRegistry; +import org.eclipse.smarthome.core.items.RegistryHook; import org.eclipse.smarthome.core.thing.Channel; import org.eclipse.smarthome.core.thing.ChannelUID; import org.eclipse.smarthome.core.thing.Thing; @@ -58,13 +59,13 @@ public class ChannelItemProvider implements ItemProvider { private final Logger logger = LoggerFactory.getLogger(ChannelItemProvider.class); - private Set> listeners = new HashSet<>(); + private final Set> listeners = new HashSet<>(); private LocaleProvider localeProvider; private ThingRegistry thingRegistry; private ItemChannelLinkRegistry linkRegistry; private ItemRegistry itemRegistry; - private Set itemFactories = new HashSet<>(); + private final Set itemFactories = new HashSet<>(); private Map items = null; private boolean enabled = true; @@ -212,12 +213,12 @@ protected void deactivate() { private void addRegistryChangeListeners() { this.linkRegistry.addRegistryChangeListener(linkRegistryListener); - this.itemRegistry.addRegistryChangeListener(itemRegistryListener); + this.itemRegistry.addRegistryHook(itemRegistryListener); this.thingRegistry.addRegistryChangeListener(thingRegistryListener); } private void removeRegistryChangeListeners() { - this.itemRegistry.removeRegistryChangeListener(itemRegistryListener); + this.itemRegistry.removeRegistryHook(itemRegistryListener); this.linkRegistry.removeRegistryChangeListener(linkRegistryListener); this.thingRegistry.removeRegistryChangeListener(thingRegistryListener); } @@ -344,10 +345,10 @@ public void updated(ItemChannelLink oldElement, ItemChannelLink element) { } }; - RegistryChangeListener itemRegistryListener = new RegistryChangeListener() { + RegistryHook itemRegistryListener = new RegistryHook() { @Override - public void added(Item element) { + public void beforeAdding(Item element) { // check, if it is our own item for (Item item : items.values()) { if (item == element) { @@ -366,7 +367,7 @@ public void added(Item element) { } @Override - public void removed(Item element) { + public void afterRemoving(Item element) { // check, if it is our own item for (Item item : items.values()) { if (item == element) { @@ -383,8 +384,5 @@ public void removed(Item element) { } } - @Override - public void updated(Item oldElement, Item element) { - } }; } diff --git a/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/internal/items/ItemRegistryImpl.java b/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/internal/items/ItemRegistryImpl.java index 0f558f59192..7bcbb40de85 100644 --- a/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/internal/items/ItemRegistryImpl.java +++ b/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/internal/items/ItemRegistryImpl.java @@ -14,8 +14,10 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.smarthome.core.common.registry.AbstractRegistry; +import org.eclipse.smarthome.core.common.registry.Provider; import org.eclipse.smarthome.core.events.EventPublisher; import org.eclipse.smarthome.core.items.GenericItem; import org.eclipse.smarthome.core.items.GroupItem; @@ -26,6 +28,7 @@ import org.eclipse.smarthome.core.items.ItemRegistry; import org.eclipse.smarthome.core.items.ItemUtil; import org.eclipse.smarthome.core.items.ManagedItemProvider; +import org.eclipse.smarthome.core.items.RegistryHook; import org.eclipse.smarthome.core.items.events.ItemEventFactory; import org.eclipse.smarthome.core.types.StateDescriptionProvider; import org.osgi.service.component.ComponentContext; @@ -49,6 +52,7 @@ public class ItemRegistryImpl extends AbstractRegistry stateDescriptionProviders = Collections .synchronizedList(new ArrayList()); + private final List> registryHooks = new CopyOnWriteArrayList<>(); public ItemRegistryImpl() { super(ItemProvider.class); @@ -325,6 +329,52 @@ protected void notifyListenersAboutUpdatedElement(Item oldElement, Item element) postEvent(ItemEventFactory.createUpdateEvent(element, oldElement)); } + @Override + public void added(Provider provider, Item element) { + for (RegistryHook registryHook : registryHooks) { + registryHook.beforeAdding(element); + } + super.added(provider, element); + } + + @Override + protected void addProvider(Provider provider) { + for (Item element : provider.getAll()) { + for (RegistryHook registryHook : registryHooks) { + registryHook.beforeAdding(element); + } + } + super.addProvider(provider); + } + + @Override + public void removed(Provider provider, Item element) { + super.removed(provider, element); + for (RegistryHook registryHook : registryHooks) { + registryHook.afterRemoving(element); + } + } + + @Override + protected void removeProvider(Provider provider) { + super.removeProvider(provider); + for (Item element : provider.getAll()) { + for (RegistryHook registryHook : registryHooks) { + registryHook.afterRemoving(element); + } + } + } + + @Override + public void addRegistryHook(RegistryHook hook) { + registryHooks.add(hook); + } + + @Override + public void removeRegistryHook(RegistryHook hook) { + registryHooks.remove(hook); + } + protected void activate(final ComponentContext componentContext) { super.activate(componentContext.getBundleContext()); } diff --git a/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/items/ItemRegistry.java b/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/items/ItemRegistry.java index f63b0b6f54c..b880e479f93 100644 --- a/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/items/ItemRegistry.java +++ b/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/items/ItemRegistry.java @@ -108,4 +108,18 @@ public interface ItemRegistry extends Registry { */ public @Nullable Item remove(@NonNull String itemName, boolean recursive); + /** + * Add a hook to be informed before adding/after removing items. + * + * @param hook + */ + void addRegistryHook(RegistryHook hook); + + /** + * Remove the hook again. + * + * @param hook + */ + void removeRegistryHook(RegistryHook hook); + } diff --git a/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/items/RegistryHook.java b/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/items/RegistryHook.java new file mode 100644 index 00000000000..3a948a358f9 --- /dev/null +++ b/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/items/RegistryHook.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2014-2017 by the respective copyright holders. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.smarthome.core.items; + +import org.eclipse.smarthome.core.common.registry.Identifiable; + +/** + * A listener to be informed before entities are added respectively after they are removed. + * + * @author Simon Kaufmann - initial contribution and API. + */ +public interface RegistryHook> { + + /** + * Notifies the listener that a single element is going to be added by another provider. + * + * @param element the element to be added + */ + void beforeAdding(E element); + + /** + * Notifies the listener that a single element was removed by another provider. + * + * @param element the element that was removed + */ + void afterRemoving(E element); + +} diff --git a/bundles/ui/org.eclipse.smarthome.ui/src/main/java/org/eclipse/smarthome/ui/internal/items/ItemUIRegistryImpl.java b/bundles/ui/org.eclipse.smarthome.ui/src/main/java/org/eclipse/smarthome/ui/internal/items/ItemUIRegistryImpl.java index 40ac0de5e15..edcb643b7ed 100644 --- a/bundles/ui/org.eclipse.smarthome.ui/src/main/java/org/eclipse/smarthome/ui/internal/items/ItemUIRegistryImpl.java +++ b/bundles/ui/org.eclipse.smarthome.ui/src/main/java/org/eclipse/smarthome/ui/internal/items/ItemUIRegistryImpl.java @@ -31,6 +31,7 @@ import org.eclipse.smarthome.core.items.ItemNotFoundException; import org.eclipse.smarthome.core.items.ItemNotUniqueException; import org.eclipse.smarthome.core.items.ItemRegistry; +import org.eclipse.smarthome.core.items.RegistryHook; import org.eclipse.smarthome.core.library.items.CallItem; import org.eclipse.smarthome.core.library.items.ColorItem; import org.eclipse.smarthome.core.library.items.ContactItem; @@ -1182,4 +1183,18 @@ public Item remove(String itemName, boolean recursive) { } + @Override + public void addRegistryHook(RegistryHook hook) { + if (itemRegistry != null) { + itemRegistry.addRegistryHook(hook); + } + } + + @Override + public void removeRegistryHook(RegistryHook hook) { + if (itemRegistry != null) { + itemRegistry.removeRegistryHook(hook); + } + } + }