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.tr064.internal.phonebook;
15 import static java.util.Comparator.comparing;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.List;
21 import java.util.Locale;
23 import java.util.Objects;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.stream.Collectors;
28 import org.eclipse.jdt.annotation.NonNullByDefault;
29 import org.eclipse.jdt.annotation.Nullable;
30 import org.openhab.core.config.core.ConfigOptionProvider;
31 import org.openhab.core.config.core.ParameterOption;
32 import org.openhab.core.i18n.LocalizedKey;
33 import org.openhab.core.thing.ThingUID;
34 import org.openhab.core.thing.profiles.Profile;
35 import org.openhab.core.thing.profiles.ProfileCallback;
36 import org.openhab.core.thing.profiles.ProfileContext;
37 import org.openhab.core.thing.profiles.ProfileFactory;
38 import org.openhab.core.thing.profiles.ProfileType;
39 import org.openhab.core.thing.profiles.ProfileTypeProvider;
40 import org.openhab.core.thing.profiles.ProfileTypeUID;
41 import org.openhab.core.thing.profiles.i18n.ProfileTypeI18nLocalizationService;
42 import org.openhab.core.util.BundleResolver;
43 import org.openhab.core.util.UIDUtils;
44 import org.osgi.framework.Bundle;
45 import org.osgi.service.component.annotations.Activate;
46 import org.osgi.service.component.annotations.Component;
47 import org.osgi.service.component.annotations.Reference;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
52 * The {@link PhonebookProfileFactory} class is used to create phonebook profiles
54 * @author Jan N. Klug - Initial contribution
57 @Component(service = { ProfileFactory.class, ProfileTypeProvider.class, PhonebookProfileFactory.class,
58 ConfigOptionProvider.class })
59 public class PhonebookProfileFactory implements ProfileFactory, ProfileTypeProvider, ConfigOptionProvider {
60 private final Logger logger = LoggerFactory.getLogger(PhonebookProfileFactory.class);
61 private final Map<ThingUID, PhonebookProvider> phonebookProviders = new ConcurrentHashMap<>();
63 private final Map<LocalizedKey, ProfileType> localizedProfileTypeCache = new ConcurrentHashMap<>();
65 private final ProfileTypeI18nLocalizationService profileTypeI18nLocalizationService;
66 private final Bundle bundle;
69 public PhonebookProfileFactory(
70 final @Reference ProfileTypeI18nLocalizationService profileTypeI18nLocalizationService,
71 final @Reference BundleResolver bundleResolver) {
72 this.profileTypeI18nLocalizationService = profileTypeI18nLocalizationService;
73 this.bundle = bundleResolver.resolveBundle(PhonebookProfileFactory.class);
77 public @Nullable Profile createProfile(ProfileTypeUID profileTypeUID, ProfileCallback callback,
78 ProfileContext profileContext) {
79 return new PhonebookProfile(callback, profileContext, phonebookProviders);
83 public Collection<ProfileTypeUID> getSupportedProfileTypeUIDs() {
84 return Set.of(PhonebookProfile.PHONEBOOK_PROFILE_TYPE_UID);
88 public Collection<ProfileType> getProfileTypes(@Nullable Locale locale) {
89 return Set.of(createLocalizedProfileType(PhonebookProfile.PHONEBOOK_PROFILE_TYPE, locale));
92 private ProfileType createLocalizedProfileType(ProfileType profileType, @Nullable Locale locale) {
93 final LocalizedKey localizedKey = new LocalizedKey(profileType.getUID(),
94 locale != null ? locale.toLanguageTag() : null);
96 return Objects.requireNonNull(localizedProfileTypeCache.computeIfAbsent(localizedKey,
97 key -> profileTypeI18nLocalizationService.createLocalizedProfileType(bundle, profileType, locale)));
101 * register a phonebook provider
103 * @param phonebookProvider the provider that shall be added
105 public void registerPhonebookProvider(PhonebookProvider phonebookProvider) {
106 if (phonebookProviders.put(phonebookProvider.getUID(), phonebookProvider) != null) {
107 logger.warn("Tried to register a phonebook provider with UID '{}' for the second time.",
108 phonebookProvider.getUID());
113 * unregister a phonebook provider
115 * @param phonebookProvider the provider that shall be removed
117 public void unregisterPhonebookProvider(PhonebookProvider phonebookProvider) {
118 if (phonebookProviders.remove(phonebookProvider.getUID()) == null) {
119 logger.warn("Tried to unregister a phonebook provider with UID '{}' but it was not found.",
120 phonebookProvider.getUID());
124 private List<ParameterOption> createPhonebookList(Map.Entry<ThingUID, PhonebookProvider> entry) {
125 String thingUid = UIDUtils.encode(entry.getKey().toString());
126 String thingName = entry.getValue().getFriendlyName();
128 List<ParameterOption> parameterOptions = entry.getValue().getPhonebooks().stream()
129 .map(phonebook -> new ParameterOption(thingUid + ":" + UIDUtils.encode(phonebook.getName()),
130 thingName + " - " + phonebook.getName()))
131 .collect(Collectors.toList());
133 if (!parameterOptions.isEmpty()) {
134 parameterOptions.add(new ParameterOption(thingUid, thingName));
137 return parameterOptions;
141 public @Nullable Collection<ParameterOption> getParameterOptions(URI uri, String s, @Nullable String s1,
142 @Nullable Locale locale) {
143 if (uri.getSchemeSpecificPart().equals(PhonebookProfile.PHONEBOOK_PROFILE_TYPE_UID.toString())
144 && s.equals(PhonebookProfile.PHONEBOOK_PARAM)) {
145 List<ParameterOption> parameterOptions = new ArrayList<>();
146 for (Map.Entry<ThingUID, PhonebookProvider> entry : phonebookProviders.entrySet()) {
147 parameterOptions.addAll(createPhonebookList(entry));
149 parameterOptions.sort(comparing(o -> o.getLabel()));
150 return parameterOptions;