2 * Copyright (c) 2010-2024 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.Comparator;
17 import java.util.List;
19 import java.util.Objects;
20 import java.util.concurrent.ConcurrentHashMap;
21 import java.util.function.Predicate;
22 import java.util.stream.Stream;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.unifi.internal.api.dto.UniFiClient;
27 import org.openhab.binding.unifi.internal.api.dto.UniFiDevice;
28 import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple;
29 import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
30 import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
31 import org.openhab.binding.unifi.internal.api.dto.UniFiVoucher;
32 import org.openhab.binding.unifi.internal.api.dto.UniFiWlan;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
37 * Class to manager cache for the controller keeping track of all specific cache objects.
39 * @author Matthew Bowman - Initial contribution
40 * @author Hilbrand Bouwkamp - Moved cache to this dedicated class.
41 * @author Mark Herwege - Added guest vouchers
44 public class UniFiControllerCache {
46 private final Logger logger = LoggerFactory.getLogger(UniFiControllerCache.class);
48 private final UniFiSiteCache sitesCache = new UniFiSiteCache();
49 private final UniFiWlanCache wlansCache = new UniFiWlanCache();
50 private final UniFiDeviceCache devicesCache = new UniFiDeviceCache();
51 private final UniFiClientCache clientsCache = new UniFiClientCache();
52 private final UniFiClientCache insightsCache = new UniFiClientCache();
53 private final UniFiVoucherCache vouchersCache = new UniFiVoucherCache();
54 private final Map<String, UniFiSwitchPorts> devicesToPortTables = new ConcurrentHashMap<>();
61 insightsCache.clear();
62 vouchersCache.clear();
67 public List<UniFiSite> setSites(final UniFiSite @Nullable [] sites) {
68 sitesCache.putAll(sites);
69 return List.of(sites);
72 public @Nullable UniFiSite getSite(final @Nullable String id) {
73 return sitesCache.get(id);
76 public Collection<UniFiSite> getSites() {
77 return sitesCache.values();
82 public void putWlans(final UniFiWlan @Nullable [] wlans) {
83 wlansCache.putAll(wlans);
86 public @Nullable UniFiWlan getWlan(@Nullable final String id) {
87 return wlansCache.get(id);
90 public Collection<UniFiWlan> getWlans() {
91 return wlansCache.values();
96 public void putDevices(final UniFiDevice @Nullable [] devices) {
97 devicesCache.putAll(devices);
98 if (devices != null) {
99 Stream.of(devices).filter(Objects::nonNull).forEach(d -> {
100 Stream.ofNullable(d.getPortTable()).forEach(pt -> {
101 final UniFiSwitchPorts switchPorts = devicesToPortTables.computeIfAbsent(d.getMac(),
102 p -> new UniFiSwitchPorts());
104 Stream.of(pt).forEach(p -> {
105 @SuppressWarnings("null")
106 final UniFiPortTuple tuple = switchPorts.computeIfAbsent(p.getPortIdx());
112 Stream.ofNullable(d.getPortOverrides()).forEach(po -> {
113 final UniFiSwitchPorts tupleTable = devicesToPortTables.get(d.getMac());
115 if (tupleTable != null) {
116 Stream.of(po).forEach(p -> tupleTable.setOverride(p));
123 public @Nullable UniFiDevice getDevice(@Nullable final String id) {
124 return devicesCache.get(id);
127 public UniFiSwitchPorts getSwitchPorts(@Nullable final String deviceId) {
128 return deviceId == null ? new UniFiSwitchPorts()
129 : devicesToPortTables.getOrDefault(deviceId, new UniFiSwitchPorts());
132 public Collection<UniFiSwitchPorts> getSwitchPorts() {
133 return devicesToPortTables.values();
138 public void putClients(final UniFiClient @Nullable [] clients) {
139 clientsCache.putAll(clients);
142 public Collection<UniFiClient> getClients() {
143 return clientsCache.values();
146 public long countClients(final UniFiSite site, final Predicate<UniFiClient> filter) {
147 return getClients().stream().filter(c -> site.isSite(c.getSite())).filter(filter::test).count();
150 public @Nullable UniFiClient getClient(@Nullable final String cid) {
151 UniFiClient client = null;
152 if (cid != null && !cid.isBlank()) {
153 synchronized (this) {
154 // mgb: first check active clients and fallback to insights if not found
155 client = clientsCache.get(cid);
156 if (client == null) {
157 final String id = clientsCache.getId(cid);
159 client = insightsCache.get(id == null ? cid : id);
162 if (client == null) {
163 logger.debug("Could not find a matching client for cid = {}", cid);
169 public synchronized Stream<UniFiClient> getClientStreamForSite(final UniFiSite site) {
170 return clientsCache.values().stream().filter(client -> client.getSite().equals(site));
175 public void putInsights(final UniFiClient @Nullable [] insights) {
176 insightsCache.putAll(insights);
181 public void putVouchers(final UniFiVoucher @Nullable [] vouchers) {
182 vouchersCache.putAll(vouchers);
185 public synchronized Stream<UniFiVoucher> getVoucherStreamForSite(final UniFiSite site) {
186 return vouchersCache.values().stream().filter(voucher -> voucher.getSite().equals(site));
189 public @Nullable UniFiVoucher getVoucher(final UniFiSite site) {
190 // Use one of the oldest vouchers first
191 return getVoucherStreamForSite(site).min(Comparator.comparing(UniFiVoucher::getCreateTime)).orElse(null);