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 java.util.HashMap;
17 import java.util.Optional;
18 import java.util.stream.Collectors;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jetty.client.HttpClient;
22 import org.openhab.binding.tr064.internal.dto.additions.PhonebooksType;
23 import org.openhab.binding.tr064.internal.util.Util;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 * The {@link Tr064PhonebookImpl} class implements a phonebook
30 * @author Jan N. Klug - Initial contribution
33 public class Tr064PhonebookImpl implements Phonebook {
34 private final Logger logger = LoggerFactory.getLogger(Tr064PhonebookImpl.class);
36 private Map<String, String> phonebook = new HashMap<>();
38 private final HttpClient httpClient;
39 private final String phonebookUrl;
41 private String phonebookName = "";
43 public Tr064PhonebookImpl(HttpClient httpClient, String phonebookUrl) {
44 this.httpClient = httpClient;
45 this.phonebookUrl = phonebookUrl;
49 private void getPhonebook() {
50 PhonebooksType phonebooksType = Util.getAndUnmarshalXML(httpClient, phonebookUrl, PhonebooksType.class);
51 if (phonebooksType != null) {
52 phonebookName = phonebooksType.getPhonebook().getName();
53 phonebook = phonebooksType.getPhonebook().getContact().stream().map(contact -> {
54 String contactName = contact.getPerson().getRealName();
55 return contact.getTelephony().getNumber().stream()
56 .collect(Collectors.toMap(number -> normalizeNumber(number.getValue()), number -> contactName,
57 this::mergeSameContactNames));
58 }).collect(HashMap::new, HashMap::putAll, HashMap::putAll);
59 logger.debug("Downloaded phonebook {}: {}", phonebookName, phonebook);
63 // in case there are multiple phone entries with same number -> name mapping, i.e. in phonebooks exported from
64 // mobiles containing multiple accounts like: local, cloudprovider1, messenger1, messenger2,...
65 private String mergeSameContactNames(String nameA, String nameB) {
66 if (nameA.equals(nameB)) {
69 throw new IllegalStateException(
70 "Found different names for the same number: '" + nameA + "' and '" + nameB + "'");
74 public String getName() {
79 public Optional<String> lookupNumber(String number, int matchCount) {
80 String normalized = normalizeNumber(number);
81 String matchString = matchCount > 0 && matchCount < normalized.length()
82 ? normalized.substring(normalized.length() - matchCount)
84 logger.trace("Normalized '{}' to '{}', matchString is '{}'", number, normalized, matchString);
85 return matchString.isBlank() ? Optional.empty()
86 : phonebook.keySet().stream().filter(n -> n.endsWith(matchString)).findFirst().map(phonebook::get);
90 public String toString() {
91 return "Phonebook{" + "phonebookName='" + phonebookName + "', phonebook=" + phonebook + '}';
94 private String normalizeNumber(String number) {
95 // Naive normalization: remove all non-digit characters
96 return number.replaceAll("[^0-9\\*\\+]", "");