From 1bd70ef909a29d09aac58c4a7f30d2d4abaa2b80 Mon Sep 17 00:00:00 2001 From: Jonathan Gilbert Date: Wed, 27 Apr 2022 00:20:01 +0100 Subject: [PATCH] Add ManagedProviders to UIRegistry (#2617) * UIRegistry now extensible, like other Registries Signed-off-by: Jonathan Gilbert * Fix comments and more Signed-off-by: Wouter Born Co-authored-by: Wouter Born --- .../components/ManagedPageProvider.java | 35 +++++++++ .../components/ManagedWidgetProvider.java | 35 +++++++++ .../components/UIComponentProvider.java | 7 +- .../UIComponentRegistryFactoryImpl.java | 74 ++++++++++++++++--- .../components/UIComponentRegistryImpl.java | 37 +++++++--- .../ui/internal/components/UIProvider.java | 27 +++++++ 6 files changed, 194 insertions(+), 21 deletions(-) create mode 100644 bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/ManagedPageProvider.java create mode 100644 bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/ManagedWidgetProvider.java create mode 100644 bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIProvider.java diff --git a/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/ManagedPageProvider.java b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/ManagedPageProvider.java new file mode 100644 index 0000000000..2cf733c95b --- /dev/null +++ b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/ManagedPageProvider.java @@ -0,0 +1,35 @@ +/** + * 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.ui.internal.components; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.common.registry.ManagedProvider; +import org.openhab.core.common.registry.Provider; +import org.openhab.core.storage.StorageService; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * A managed page provider which uses storage layer to keep defined pages. + * + * @author Łukasz Dywicki - Initial contribution + */ +@NonNullByDefault +@Component(service = { Provider.class, ManagedProvider.class, UIProvider.class }) +public class ManagedPageProvider extends UIComponentProvider { + @Activate + public ManagedPageProvider(@Reference StorageService storageService) { + super("ui:page", storageService); + } +} diff --git a/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/ManagedWidgetProvider.java b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/ManagedWidgetProvider.java new file mode 100644 index 0000000000..54d3ce1c4e --- /dev/null +++ b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/ManagedWidgetProvider.java @@ -0,0 +1,35 @@ +/** + * 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.ui.internal.components; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.common.registry.ManagedProvider; +import org.openhab.core.common.registry.Provider; +import org.openhab.core.storage.StorageService; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * A managed widget provider which stores their definition in storage layer. + * + * @author Łukasz Dywicki - Initial contribution + */ +@NonNullByDefault +@Component(service = { Provider.class, ManagedProvider.class, UIProvider.class }) +public class ManagedWidgetProvider extends UIComponentProvider { + @Activate + public ManagedWidgetProvider(@Reference StorageService storageService) { + super("ui:widget", storageService); + } +} diff --git a/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIComponentProvider.java b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIComponentProvider.java index fa1e587c8a..94a3f788c2 100644 --- a/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIComponentProvider.java +++ b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIComponentProvider.java @@ -31,7 +31,7 @@ import org.openhab.core.ui.components.RootUIComponent; */ @NonNullByDefault public class UIComponentProvider extends AbstractProvider - implements ManagedProvider { + implements ManagedProvider, UIProvider { private String namespace; private volatile Storage storage; @@ -107,4 +107,9 @@ public class UIComponentProvider extends AbstractProvider } return storage.get(key); } + + @Override + public String getNamespace() { + return namespace; + } } diff --git a/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIComponentRegistryFactoryImpl.java b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIComponentRegistryFactoryImpl.java index 2ff2e9b11e..045e4537ff 100644 --- a/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIComponentRegistryFactoryImpl.java +++ b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIComponentRegistryFactoryImpl.java @@ -12,34 +12,90 @@ */ package org.openhab.core.ui.internal.components; -import java.util.HashMap; +import java.util.Collections; +import java.util.HashSet; import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; -import org.openhab.core.storage.StorageService; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.common.registry.ManagedProvider; +import org.openhab.core.ui.components.RootUIComponent; import org.openhab.core.ui.components.UIComponentRegistryFactory; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; /** - * Implementation for a {@link UIComponentRegistryFactory} using a {@link StorageService} and a - * {@link UIComponentProvider}. + * Implementation for a {@link UIComponentRegistryFactory} using a set of {@link UIComponentProvider}. * * @author Yannick Schaus - Initial contribution + * @author Łukasz Dywicki - Removed explicit dependency on storage providers. + * @author Jonathan Gilbert - Made providers' collections immutable. */ +@NonNullByDefault @Component(service = UIComponentRegistryFactory.class, immediate = true) public class UIComponentRegistryFactoryImpl implements UIComponentRegistryFactory { - Map registries = new HashMap<>(); - - @Reference - StorageService storageService; + Map registries = new ConcurrentHashMap<>(); + Map> providers = new ConcurrentHashMap<>(); @Override public UIComponentRegistryImpl getRegistry(String namespace) { UIComponentRegistryImpl registry = registries.get(namespace); if (registry == null) { - registry = new UIComponentRegistryImpl(namespace, storageService); + Set namespaceProviders = this.providers.get(namespace); + ManagedProvider managedProvider = null; + if (namespaceProviders != null) { + for (UIProvider provider : namespaceProviders) { + if (provider instanceof ManagedProvider) { + managedProvider = (ManagedProvider) provider; + break; + } + } + } + registry = new UIComponentRegistryImpl(namespace, managedProvider, namespaceProviders); registries.put(namespace, registry); } return registry; } + + @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC) + void addProvider(UIProvider provider) { + UIComponentRegistryImpl registry = registries.get(provider.getNamespace()); + if (registry != null) { + registry.addProvider(provider); + } + registerProvider(provider); + } + + void removeProvider(UIProvider provider) { + UIComponentRegistryImpl registry = registries.get(provider.getNamespace()); + if (registry != null) { + registry.removeProvider(provider); + } + deregisterProvider(provider); + } + + private void registerProvider(UIProvider provider) { + Set existing = providers.get(provider.getNamespace()); + + if (existing == null) { + existing = Collections.emptySet(); + } + + Set updated = new HashSet<>(existing); + updated.add(provider); + providers.put(provider.getNamespace(), Set.copyOf(updated)); + } + + private void deregisterProvider(UIProvider provider) { + Set existing = providers.get(provider.getNamespace()); + + if (existing != null && !existing.isEmpty()) { + Set updated = new HashSet<>(existing); + updated.remove(provider); + providers.put(provider.getNamespace(), Set.copyOf(updated)); + } + } } diff --git a/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIComponentRegistryImpl.java b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIComponentRegistryImpl.java index 4f62deebe7..fd95802bf4 100644 --- a/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIComponentRegistryImpl.java +++ b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIComponentRegistryImpl.java @@ -12,9 +12,13 @@ */ package org.openhab.core.ui.internal.components; +import java.util.Set; + import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.common.registry.AbstractRegistry; -import org.openhab.core.storage.StorageService; +import org.openhab.core.common.registry.ManagedProvider; +import org.openhab.core.common.registry.Provider; import org.openhab.core.ui.components.RootUIComponent; import org.openhab.core.ui.components.UIComponentRegistry; @@ -23,26 +27,37 @@ import org.openhab.core.ui.components.UIComponentRegistry; * It is instantiated by the {@link UIComponentRegistryFactoryImpl}. * * @author Yannick Schaus - Initial contribution + * @author Łukasz Dywicki - Support for dynamic registration of providers */ @NonNullByDefault public class UIComponentRegistryImpl extends AbstractRegistry implements UIComponentRegistry { - String namespace; - StorageService storageService; - /** * Constructs a UI component registry for the specified namespace. * * @param namespace UI components namespace of this registry - * @param storageService supporting storage service */ - public UIComponentRegistryImpl(String namespace, StorageService storageService) { + public UIComponentRegistryImpl(String namespace, @Nullable ManagedProvider managedProvider, + @Nullable Set providers) { super(null); - this.namespace = namespace; - this.storageService = storageService; - UIComponentProvider provider = new UIComponentProvider(namespace, storageService); - addProvider(provider); - setManagedProvider(provider); + if (managedProvider != null) { + setManagedProvider(managedProvider); + } + if (providers != null && !providers.isEmpty()) { + for (Provider provider : providers) { + addProvider(provider); + } + } + } + + @Override + public void addProvider(Provider provider) { + super.addProvider(provider); + } + + @Override + public void removeProvider(Provider provider) { + super.removeProvider(provider); } } diff --git a/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIProvider.java b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIProvider.java new file mode 100644 index 0000000000..8767f8d5f1 --- /dev/null +++ b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/components/UIProvider.java @@ -0,0 +1,27 @@ +/** + * 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.ui.internal.components; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.common.registry.Provider; +import org.openhab.core.ui.components.RootUIComponent; + +/** + * Provides components (pages, widgets, etc.) at runtime. + * + * @author Łukasz Dywicki - Initial contribution + */ +@NonNullByDefault +public interface UIProvider extends Provider { + String getNamespace(); +}