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.unifi.internal.api.cache;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.Locale;
19 import java.util.Objects;
20 import java.util.stream.Collectors;
21 import java.util.stream.Stream;
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;
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.
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.
37 * @author Matthew Bowman - Initial contribution
38 * @author Hilbrand Bouwkamp - Moved generic code into this class
41 abstract class UniFiCache<T extends @Nullable HasId> {
53 private static final String SEPARATOR = ":";
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;
62 protected UniFiCache(final Prefix... prefixes) {
63 this.prefixes = prefixes;
70 public final @Nullable T get(final @Nullable String cid) {
71 final @Nullable T value;
73 if (cid != null && !cid.isBlank()) {
75 final String id = getId(cid);
78 logger.debug("Could not find an entry in the cache for id: '{}'", cid);
90 public @Nullable String getId(final String cid) {
92 for (final Prefix prefix : prefixes) {
93 final String key = key(prefix, cid);
95 if (mapToId.containsKey(key)) {
96 value = mapToId.get(key);
97 logger.trace("Cache HIT : '{}' -> {}", key, value);
100 logger.trace("Cache MISS : '{}'", key);
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() + " - ")));
113 Stream.of(values).filter(Objects::nonNull).forEach(value -> put(value.getId(), value));
117 public final void put(final String id, final T value) {
118 for (final Prefix prefix : prefixes) {
119 final String suffix = getSuffix(value, prefix);
121 if (suffix != null && !suffix.isBlank()) {
122 mapToId.put(key(prefix, suffix), id);
128 private static String key(final Prefix prefix, final String suffix) {
129 return prefix.name() + SEPARATOR + suffix.replace(":", "").toLowerCase(Locale.ROOT);
132 public final Collection<T> values() {
133 return map.values().stream().distinct().collect(Collectors.toList());
136 protected abstract @Nullable String getSuffix(T value, Prefix prefix);