Add ManagedProviders to UIRegistry (#2617)

* UIRegistry now extensible, like other Registries

Signed-off-by: Jonathan Gilbert <jpg@trillica.com>

* Fix comments and more

Signed-off-by: Wouter Born <github@maindrain.net>

Co-authored-by: Wouter Born <github@maindrain.net>
pull/2934/head
Jonathan Gilbert 2022-04-27 00:20:01 +01:00 committed by GitHub
parent 89bc6592da
commit 1bd70ef909
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 194 additions and 21 deletions

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -31,7 +31,7 @@ import org.openhab.core.ui.components.RootUIComponent;
*/
@NonNullByDefault
public class UIComponentProvider extends AbstractProvider<RootUIComponent>
implements ManagedProvider<RootUIComponent, String> {
implements ManagedProvider<RootUIComponent, String>, UIProvider {
private String namespace;
private volatile Storage<RootUIComponent> storage;
@ -107,4 +107,9 @@ public class UIComponentProvider extends AbstractProvider<RootUIComponent>
}
return storage.get(key);
}
@Override
public String getNamespace() {
return namespace;
}
}

View File

@ -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<String, UIComponentRegistryImpl> registries = new HashMap<>();
@Reference
StorageService storageService;
Map<String, UIComponentRegistryImpl> registries = new ConcurrentHashMap<>();
Map<String, Set<UIProvider>> providers = new ConcurrentHashMap<>();
@Override
public UIComponentRegistryImpl getRegistry(String namespace) {
UIComponentRegistryImpl registry = registries.get(namespace);
if (registry == null) {
registry = new UIComponentRegistryImpl(namespace, storageService);
Set<UIProvider> namespaceProviders = this.providers.get(namespace);
ManagedProvider<RootUIComponent, String> managedProvider = null;
if (namespaceProviders != null) {
for (UIProvider provider : namespaceProviders) {
if (provider instanceof ManagedProvider) {
managedProvider = (ManagedProvider<RootUIComponent, String>) 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<UIProvider> existing = providers.get(provider.getNamespace());
if (existing == null) {
existing = Collections.emptySet();
}
Set<UIProvider> updated = new HashSet<>(existing);
updated.add(provider);
providers.put(provider.getNamespace(), Set.copyOf(updated));
}
private void deregisterProvider(UIProvider provider) {
Set<UIProvider> existing = providers.get(provider.getNamespace());
if (existing != null && !existing.isEmpty()) {
Set<UIProvider> updated = new HashSet<>(existing);
updated.remove(provider);
providers.put(provider.getNamespace(), Set.copyOf(updated));
}
}
}

View File

@ -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<RootUIComponent, String, UIComponentProvider>
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<RootUIComponent, String> managedProvider,
@Nullable Set<UIProvider> 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<RootUIComponent> provider : providers) {
addProvider(provider);
}
}
}
@Override
public void addProvider(Provider<RootUIComponent> provider) {
super.addProvider(provider);
}
@Override
public void removeProvider(Provider<RootUIComponent> provider) {
super.removeProvider(provider);
}
}

View File

@ -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<RootUIComponent> {
String getNamespace();
}