2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.remoteopenhab.internal;
15 import static org.openhab.binding.remoteopenhab.internal.RemoteopenhabBindingConstants.BINDING_ID;
17 import java.util.List;
19 import java.util.concurrent.ConcurrentHashMap;
20 import java.util.concurrent.CopyOnWriteArrayList;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.core.storage.StorageService;
27 import org.openhab.core.thing.binding.AbstractStorageBasedTypeProvider;
28 import org.openhab.core.thing.type.ChannelType;
29 import org.openhab.core.thing.type.ChannelTypeProvider;
30 import org.openhab.core.thing.type.ChannelTypeUID;
31 import org.openhab.core.types.StateDescription;
32 import org.osgi.service.component.annotations.Activate;
33 import org.osgi.service.component.annotations.Component;
34 import org.osgi.service.component.annotations.Deactivate;
35 import org.osgi.service.component.annotations.Reference;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
40 * Channel type provider used for all the channel types built by the binding when building dynamically the channels.
41 * One different channel type is built for each different item type found on the remote openHAB server.
43 * @author Laurent Garnier - Initial contribution
44 * @author Laurent Garnier - Use AbstractStorageBasedTypeProvider
46 @Component(service = { ChannelTypeProvider.class, RemoteopenhabChannelTypeProvider.class })
48 public class RemoteopenhabChannelTypeProvider extends AbstractStorageBasedTypeProvider {
50 private static final String PATTERN_CHANNEL_TYPE_ID = "item%s%d";
51 private static final Pattern PATTERN_MATCHING_CHANNEL_TYPE_ID = Pattern.compile("^item([a-zA-Z]+)([0-9]+)$");
53 private final Logger logger = LoggerFactory.getLogger(RemoteopenhabChannelTypeProvider.class);
55 private final Map<String, List<ChannelType>> channelTypesForItemTypes = new ConcurrentHashMap<>();
58 public RemoteopenhabChannelTypeProvider(@Reference StorageService storageService) {
59 super(storageService);
60 getChannelTypes(null).forEach(ct -> {
61 Matcher matcher = PATTERN_MATCHING_CHANNEL_TYPE_ID.matcher(ct.getUID().getId());
63 String itemType = matcher.group(1);
64 // Handle number with a dimension
65 if (itemType.startsWith("Number") && !"Number".equals(itemType)) {
66 itemType = itemType.replace("Number", "Number:");
68 addChannelTypeForItemType(itemType, ct);
70 logger.warn("Invalid channel type ID : {}", ct.getUID().getId());
76 protected void deactivate() {
77 channelTypesForItemTypes.values().forEach(l -> l.clear());
78 channelTypesForItemTypes.clear();
81 public @Nullable ChannelType getChannelType(String itemType, boolean readOnly, String pattern) {
82 List<ChannelType> channelTypesForItemType = channelTypesForItemTypes.get(itemType);
83 if (channelTypesForItemType != null) {
84 for (ChannelType channelType : channelTypesForItemType) {
85 boolean channelTypeReadOnly = false;
86 String channelTypePattern = null;
87 StateDescription stateDescription = channelType.getState();
88 if (stateDescription != null) {
89 channelTypeReadOnly = stateDescription.isReadOnly();
90 channelTypePattern = stateDescription.getPattern();
92 if (channelTypePattern == null) {
93 channelTypePattern = "";
95 if (channelTypeReadOnly == readOnly && channelTypePattern.equals(pattern)) {
103 public ChannelTypeUID buildNewChannelTypeUID(String itemType) {
104 List<ChannelType> channelTypesForItemType = channelTypesForItemTypes.get(itemType);
106 if (channelTypesForItemType != null) {
107 for (ChannelType ct : channelTypesForItemType) {
108 Matcher matcher = PATTERN_MATCHING_CHANNEL_TYPE_ID.matcher(ct.getUID().getId());
109 if (matcher.find()) {
110 int nb = Integer.parseInt(matcher.group(2));
117 return new ChannelTypeUID(BINDING_ID,
118 String.format(PATTERN_CHANNEL_TYPE_ID, itemType.replace(":", ""), max + 1));
121 public void addChannelType(String itemType, ChannelType channelType) {
122 putChannelType(channelType);
123 addChannelTypeForItemType(itemType, channelType);
126 public void removeChannelType(String itemType, ChannelType channelType) {
127 removeChannelType(channelType.getUID());
128 removeChannelTypeForItemType(itemType, channelType);
131 private void addChannelTypeForItemType(String itemType, ChannelType channelType) {
132 logger.debug("addChannelTypeForItemType {} {}", itemType, channelType.getUID());
133 List<ChannelType> channelTypesForItemType = channelTypesForItemTypes.computeIfAbsent(itemType,
134 type -> new CopyOnWriteArrayList<>());
135 if (channelTypesForItemType != null) {
136 channelTypesForItemType.add(channelType);
140 private void removeChannelTypeForItemType(String itemType, ChannelType channelType) {
141 List<ChannelType> channelTypesForItemType = channelTypesForItemTypes.get(itemType);
142 if (channelTypesForItemType != null) {
143 channelTypesForItemType.remove(channelType);