Cache safe call proxies for profiles instead of continuously recreating them (#1880)

Signed-off-by: Kai Kreuzer <kai@openhab.org>
pull/1890/head
Kai Kreuzer 2020-12-03 09:28:07 +01:00 committed by GitHub
parent 6e0a5d0260
commit 85fcb7b141
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 34 additions and 10 deletions

View File

@ -12,9 +12,11 @@
*/
package org.openhab.core.thing.internal;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
@ -26,6 +28,7 @@ import javax.measure.Quantity;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.cache.ExpiringCacheMap;
import org.openhab.core.common.AbstractUID;
import org.openhab.core.common.SafeCaller;
import org.openhab.core.common.registry.RegistryChangeListener;
@ -88,6 +91,9 @@ import org.slf4j.LoggerFactory;
@Component(service = { EventSubscriber.class, CommunicationManager.class }, immediate = true)
public class CommunicationManager implements EventSubscriber, RegistryChangeListener<ItemChannelLink> {
// how long to cache profile safe call instances
private static final Duration CACHE_EXPIRATION = Duration.ofMinutes(30);
// the timeout to use for any item event processing
public static final long THINGHANDLER_EVENT_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
@ -106,6 +112,8 @@ public class CommunicationManager implements EventSubscriber, RegistryChangeList
private final SafeCaller safeCaller;
private final ThingRegistry thingRegistry;
private final ExpiringCacheMap<Integer, Profile> profileSafeCallCache = new ExpiringCacheMap<>(CACHE_EXPIRATION);
@Activate
public CommunicationManager(final @Reference AutoUpdateManager autoUpdateManager,
final @Reference ChannelTypeRegistry channelTypeRegistry,
@ -282,11 +290,19 @@ public class CommunicationManager implements EventSubscriber, RegistryChangeList
handleEvent(itemName, command, commandEvent.getSource(), s -> acceptedCommandTypeMap.get(s),
(profile, thing, convertedCommand) -> {
if (profile instanceof StateProfile) {
safeCaller.create(((StateProfile) profile), StateProfile.class) //
.withAsync() //
.withIdentifier(thing) //
.withTimeout(THINGHANDLER_EVENT_TIMEOUT) //
.build().onCommandFromItem(convertedCommand);
int key = Objects.hash("COMMAND", profile, thing);
Profile p = profileSafeCallCache.putIfAbsentAndGet(key, () -> {
return safeCaller.create(((StateProfile) profile), StateProfile.class) //
.withAsync() //
.withIdentifier(thing) //
.withTimeout(THINGHANDLER_EVENT_TIMEOUT) //
.build();
});
if (p instanceof StateProfile) {
((StateProfile) p).onCommandFromItem(convertedCommand);
} else {
throw new IllegalStateException("Expiringcache didn't provide a StateProfile instance!");
}
}
});
}
@ -296,11 +312,19 @@ public class CommunicationManager implements EventSubscriber, RegistryChangeList
final State newState = updateEvent.getItemState();
handleEvent(itemName, newState, updateEvent.getSource(), s -> acceptedStateTypeMap.get(s),
(profile, thing, convertedState) -> {
safeCaller.create(profile, Profile.class) //
.withAsync() //
.withIdentifier(thing) //
.withTimeout(THINGHANDLER_EVENT_TIMEOUT) //
.build().onStateUpdateFromItem(convertedState);
int key = Objects.hash("UPDATE", profile, thing);
Profile p = profileSafeCallCache.putIfAbsentAndGet(key, () -> {
return safeCaller.create(profile, Profile.class) //
.withAsync() //
.withIdentifier(thing) //
.withTimeout(THINGHANDLER_EVENT_TIMEOUT) //
.build();
});
if (p != null) {
p.onStateUpdateFromItem(convertedState);
} else {
throw new IllegalStateException("Expiringcache didn't provide a Profile instance!");
}
});
}