]> git.basschouten.com Git - openhab-addons.git/blob
04ba7a3c6ffee4e6a8260054e4d9a5678027d484
[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         DESC,
45         HOSTNAME,
46         ID,
47         IP,
48         MAC,
49         NAME;
50     }
51
52     private static final String SEPARATOR = ":";
53
54     private final Logger logger = LoggerFactory.getLogger(getClass());
55     // Map of cid keys to the id.
56     private final Map<String, String> mapToId = new HashMap<>();
57     // Map of id to data object
58     private final Map<String, T> map = new HashMap<>();
59     private final Prefix[] prefixes;
60
61     protected UniFiCache(final Prefix... prefixes) {
62         this.prefixes = prefixes;
63     }
64
65     public void clear() {
66         map.clear();
67     }
68
69     public final @Nullable T get(final @Nullable String cid) {
70         final @Nullable T value;
71
72         if (cid != null && !cid.isBlank()) {
73             synchronized (this) {
74                 final String id = getId(cid);
75
76                 if (id == null) {
77                     logger.debug("Could not find an entry in the cache for id: '{}'", cid);
78                     value = null;
79                 } else {
80                     value = map.get(id);
81                 }
82             }
83         } else {
84             value = null;
85         }
86         return value;
87     }
88
89     public @Nullable String getId(final String cid) {
90         String value = null;
91         for (final Prefix prefix : prefixes) {
92             final String key = key(prefix, cid);
93
94             if (mapToId.containsKey(key)) {
95                 value = mapToId.get(key);
96                 logger.trace("Cache HIT : '{}' -> {}", key, value);
97                 break;
98             } else {
99                 logger.trace("Cache MISS : '{}'", key);
100             }
101         }
102         return value;
103     }
104
105     public final void putAll(final T @Nullable [] values) {
106         if (values != null) {
107             if (logger.isDebugEnabled()) {
108                 logger.debug("Put #{} entries in {}: {}", values.length, getClass().getSimpleName(),
109                         Stream.of(values).filter(Objects::nonNull).map(Object::toString)
110                                 .collect(Collectors.joining(System.lineSeparator() + " - ")));
111             }
112             Stream.of(values).filter(Objects::nonNull).forEach(value -> put(value.getId(), value));
113         }
114     }
115
116     public final void put(final String id, final T value) {
117         for (final Prefix prefix : prefixes) {
118             final String suffix = getSuffix(value, prefix);
119
120             if (suffix != null && !suffix.isBlank()) {
121                 mapToId.put(key(prefix, suffix), id);
122             }
123         }
124         map.put(id, value);
125     }
126
127     private static String key(final Prefix prefix, final String suffix) {
128         return prefix.name() + SEPARATOR + suffix.replace(":", "").toLowerCase(Locale.ROOT);
129     }
130
131     public final Collection<T> values() {
132         return map.values().stream().distinct().collect(Collectors.toList());
133     }
134
135     protected abstract @Nullable String getSuffix(T value, Prefix prefix);
136 }