mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-10 13:21:53 +01:00
Prevent potential incorrect cache lookup due to hash collisions (#4214)
* Prevent potential incorrect cache lookup due to hash collisions Signed-off-by: Jörg Sautter <joerg.sautter@gmx.net>
This commit is contained in:
parent
7efdd44197
commit
6aed435c77
@ -12,7 +12,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.core.thing.internal;
|
package org.openhab.core.thing.internal;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@ -28,7 +27,6 @@ import javax.measure.Unit;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.core.cache.ExpiringCacheMap;
|
|
||||||
import org.openhab.core.common.AbstractUID;
|
import org.openhab.core.common.AbstractUID;
|
||||||
import org.openhab.core.common.SafeCaller;
|
import org.openhab.core.common.SafeCaller;
|
||||||
import org.openhab.core.common.registry.RegistryChangeListener;
|
import org.openhab.core.common.registry.RegistryChangeListener;
|
||||||
@ -98,6 +96,9 @@ import org.slf4j.LoggerFactory;
|
|||||||
@Component(service = { EventSubscriber.class, CommunicationManager.class }, immediate = true)
|
@Component(service = { EventSubscriber.class, CommunicationManager.class }, immediate = true)
|
||||||
public class CommunicationManager implements EventSubscriber, RegistryChangeListener<ItemChannelLink> {
|
public class CommunicationManager implements EventSubscriber, RegistryChangeListener<ItemChannelLink> {
|
||||||
|
|
||||||
|
private record CacheKey(String type, Profile profile, Thing thing) {
|
||||||
|
}
|
||||||
|
|
||||||
private static final Profile NO_OP_PROFILE = new Profile() {
|
private static final Profile NO_OP_PROFILE = new Profile() {
|
||||||
private final ProfileTypeUID noOpProfileUID = new ProfileTypeUID(ProfileTypeUID.SYSTEM_SCOPE, "noop");
|
private final ProfileTypeUID noOpProfileUID = new ProfileTypeUID(ProfileTypeUID.SYSTEM_SCOPE, "noop");
|
||||||
|
|
||||||
@ -112,9 +113,6 @@ public class CommunicationManager implements EventSubscriber, RegistryChangeList
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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
|
// the timeout to use for any item event processing
|
||||||
public static final long THINGHANDLER_EVENT_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
|
public static final long THINGHANDLER_EVENT_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
|
||||||
|
|
||||||
@ -132,7 +130,7 @@ public class CommunicationManager implements EventSubscriber, RegistryChangeList
|
|||||||
private final SafeCaller safeCaller;
|
private final SafeCaller safeCaller;
|
||||||
private final ThingRegistry thingRegistry;
|
private final ThingRegistry thingRegistry;
|
||||||
|
|
||||||
private final ExpiringCacheMap<Integer, Profile> profileSafeCallCache = new ExpiringCacheMap<>(CACHE_EXPIRATION);
|
private final ConcurrentHashMap<CacheKey, Profile> profileSafeCallCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@Activate
|
@Activate
|
||||||
public CommunicationManager(final @Reference AutoUpdateManager autoUpdateManager,
|
public CommunicationManager(final @Reference AutoUpdateManager autoUpdateManager,
|
||||||
@ -352,10 +350,10 @@ public class CommunicationManager implements EventSubscriber, RegistryChangeList
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void applyProfileForUpdate(Profile profile, Thing thing, State convertedState) {
|
private void applyProfileForUpdate(Profile profile, Thing thing, State convertedState) {
|
||||||
int key = Objects.hash("UPDATE", profile, thing);
|
CacheKey key = new CacheKey("UPDATE", profile, thing);
|
||||||
Profile p = profileSafeCallCache.putIfAbsentAndGet(key, () -> safeCaller.create(profile, Profile.class) //
|
Profile p = profileSafeCallCache.computeIfAbsent(key, (k) -> safeCaller.create(k.profile, Profile.class) //
|
||||||
.withAsync() //
|
.withAsync() //
|
||||||
.withIdentifier(thing) //
|
.withIdentifier(k.thing) //
|
||||||
.withTimeout(THINGHANDLER_EVENT_TIMEOUT) //
|
.withTimeout(THINGHANDLER_EVENT_TIMEOUT) //
|
||||||
.build());
|
.build());
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
@ -366,12 +364,12 @@ public class CommunicationManager implements EventSubscriber, RegistryChangeList
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void applyProfileForCommand(Profile profile, Thing thing, Command convertedCommand) {
|
private void applyProfileForCommand(Profile profile, Thing thing, Command convertedCommand) {
|
||||||
if (profile instanceof StateProfile stateProfile) {
|
if (profile instanceof StateProfile) {
|
||||||
int key = Objects.hash("COMMAND", profile, thing);
|
CacheKey key = new CacheKey("COMMAND", profile, thing);
|
||||||
Profile p = profileSafeCallCache.putIfAbsentAndGet(key,
|
Profile p = profileSafeCallCache.computeIfAbsent(key,
|
||||||
() -> safeCaller.create(stateProfile, StateProfile.class) //
|
(k) -> safeCaller.create((StateProfile) k.profile, StateProfile.class) //
|
||||||
.withAsync() //
|
.withAsync() //
|
||||||
.withIdentifier(thing) //
|
.withIdentifier(k.thing) //
|
||||||
.withTimeout(THINGHANDLER_EVENT_TIMEOUT) //
|
.withTimeout(THINGHANDLER_EVENT_TIMEOUT) //
|
||||||
.build());
|
.build());
|
||||||
if (p instanceof StateProfile profileP) {
|
if (p instanceof StateProfile profileP) {
|
||||||
|
Loading…
Reference in New Issue
Block a user