]> git.basschouten.com Git - openhab-addons.git/blob
04dc87963be40595e93f7f7f07f89c6e9db26f93
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.unifi.internal.api.cache;
14
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.Locale;
18 import java.util.Map;
19 import java.util.Objects;
20 import java.util.stream.Collectors;
21 import java.util.stream.Stream;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.unifi.internal.api.dto.HasId;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * The {@link UniFiCache} is a specialised lookup table that stores objects using multiple keys in the form
31  * <code>prefix:suffix</code>. Each implementation is responsible for providing a list of supported prefixes and must
32  * implement {@link #getSuffix(Object, String)} to provide a value specific suffix derived from the prefix.
33  *
34  * Objects are then retrieved simply by using the <code>suffix</code> key component and all combinations of
35  * <code>prefix:suffix</code> are searched in the order of their priority.
36  *
37  * @author Matthew Bowman - Initial contribution
38  * @author Hilbrand Bouwkamp - Moved generic code into this class
39  */
40 @NonNullByDefault
41 abstract class UniFiCache<T extends @Nullable HasId> {
42
43     public enum Prefix {
44         ALIAS,
45         DESC,
46         HOSTNAME,
47         ID,
48         IP,
49         MAC,
50         NAME;
51     }
52
53     private static final String SEPARATOR = ":";
54
55     private final Logger logger = LoggerFactory.getLogger(getClass());
56     // Map of cid keys to the id.
57     private final Map<String, String> mapToId = new HashMap<>();
58     // Map of id to data object
59     private final Map<String, T> map = new HashMap<>();
60     private final Prefix[] prefixes;
61
62     protected UniFiCache(final Prefix... prefixes) {
63         this.prefixes = prefixes;
64     }
65
66     public void clear() {
67         map.clear();
68     }
69
70     public final @Nullable T get(final @Nullable String cid) {
71         final @Nullable T value;
72
73         if (cid != null && !cid.isBlank()) {
74             synchronized (this) {
75                 final String id = getId(cid);
76
77                 if (id == null) {
78                     logger.debug("Could not find an entry in the cache for id: '{}'", cid);
79                     value = null;
80                 } else {
81                     value = map.get(id);
82                 }
83             }
84         } else {
85             value = null;
86         }
87         return value;
88     }
89
90     public @Nullable String getId(final String cid) {
91         String value = null;
92         for (final Prefix prefix : prefixes) {
93             final String key = key(prefix, cid);
94
95             if (mapToId.containsKey(key)) {
96                 value = mapToId.get(key);
97                 logger.trace("Cache HIT : '{}' -> {}", key, value);
98                 break;
99             } else {
100                 logger.trace("Cache MISS : '{}'", key);
101             }
102         }
103         return value;
104     }
105
106     public final void putAll(final T @Nullable [] values) {
107         if (values != null) {
108             if (logger.isDebugEnabled()) {
109                 logger.debug("Put #{} entries in {}: {}", values.length, getClass().getSimpleName(),
110                         Stream.of(values).filter(Objects::nonNull).map(Object::toString)
111                                 .collect(Collectors.joining(System.lineSeparator() + " - ")));
112             }
113             Stream.of(values).filter(Objects::nonNull).forEach(value -> put(value.getId(), value));
114         }
115     }
116
117     public final void put(final String id, final T value) {
118         for (final Prefix prefix : prefixes) {
119             final String suffix = getSuffix(value, prefix);
120
121             if (suffix != null && !suffix.isBlank()) {
122                 mapToId.put(key(prefix, suffix), id);
123             }
124         }
125         map.put(id, value);
126     }
127
128     private static String key(final Prefix prefix, final String suffix) {
129         return prefix.name() + SEPARATOR + suffix.replace(":", "").toLowerCase(Locale.ROOT);
130     }
131
132     public final Collection<T> values() {
133         return map.values().stream().distinct().collect(Collectors.toList());
134     }
135
136     protected abstract @Nullable String getSuffix(T value, Prefix prefix);
137 }