Refactor caches (#2775) (#2777)

* TenantAwareCacheManager define CacheEvictEvent which could be used to evict entities in general way
* JpaTenantConfigurationManagement start using genera cache approach

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-10-28 14:13:53 +02:00
committed by GitHub
parent 2d562f64cb
commit d488ad6b5f
16 changed files with 462 additions and 377 deletions

View File

@@ -36,7 +36,7 @@ public interface TenantConfigurationManagement extends PermissionSupport {
/**
* Adds or updates a specific configuration for a specific tenant.
*
* @param configurationKeyName the key of the configuration
* @param keyName the key of the configuration
* @param value the configuration value which will be written into the database.
* @return the configuration value which was just written into the database.
* @throws TenantConfigurationValidatorException if the {@code propertyType} and the value in general does not match the expected type and
@@ -44,7 +44,7 @@ public interface TenantConfigurationManagement extends PermissionSupport {
* @throws ConversionFailedException if the property cannot be converted to the given
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_UPDATE_REPOSITORY)
<T extends Serializable> TenantConfigurationValue<T> addOrUpdateConfiguration(String configurationKeyName, T value);
<T extends Serializable> TenantConfigurationValue<T> addOrUpdateConfiguration(String keyName, T value);
/**
* Adds or updates a specific configuration for a specific tenant.
@@ -58,6 +58,36 @@ public interface TenantConfigurationManagement extends PermissionSupport {
@PreAuthorize(value = SpringEvalExpressions.HAS_UPDATE_REPOSITORY)
<T extends Serializable> Map<String, TenantConfigurationValue<T>> addOrUpdateConfiguration(Map<String, T> configurations);
/**
* Retrieves a configuration value from the e.g. tenant overwritten configuration values or in case the tenant does not a have a specific
* configuration the global default value hold in the {@link Environment}.
*
* @param keyName the key of the configuration
* @return the converted configuration value either from the tenant specific configuration stored or from the fallback default values or
* {@code null} in case key has not been configured and not default value exists
* @throws TenantConfigurationValidatorException if the {@code propertyType} and the value in general does not
* match the expected type and format defined by the Key
* @throws ConversionFailedException if the property cannot be converted to the given {@code propertyType}
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_READ_REPOSITORY)
<T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(String keyName);
/**
* Retrieves a configuration value from the e.g. tenant overwritten configuration values or in case the tenant does not a have a specific
* configuration the global default value hold in the {@link Environment}.
*
* @param <T> the type of the configuration value
* @param keyName the key of the configuration
* @param propertyType the type of the configuration value, e.g. {@code String.class}, {@code Integer.class}, etc
* @return the converted configuration value either from the tenant specific configuration stored or from the fallback default values or
* {@code null} in case key has not been configured and not default value exists
* @throws TenantConfigurationValidatorException if the {@code propertyType} and the value in general does not
* match the expected type and format defined by the Key
* @throws ConversionFailedException if the property cannot be converted to the given {@code propertyType}
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_READ_REPOSITORY)
<T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(String keyName, Class<T> propertyType);
/**
* Deletes a specific configuration for the current tenant. Does nothing in case there is no tenant specific configuration value.
*
@@ -66,51 +96,6 @@ public interface TenantConfigurationManagement extends PermissionSupport {
@PreAuthorize(value = SpringEvalExpressions.HAS_DELETE_REPOSITORY)
void deleteConfiguration(String configurationKey);
/**
* Retrieves a configuration value from the e.g. tenant overwritten configuration values or in case the tenant does not a have a specific
* configuration the global default value hold in the {@link Environment}.
*
* @param configurationKeyName the key of the configuration
* @return the converted configuration value either from the tenant specific configuration stored or from the fallback default values or
* {@code null} in case key has not been configured and not default value exists
* @throws TenantConfigurationValidatorException if the {@code propertyType} and the value in general does not
* match the expected type and format defined by the Key
* @throws ConversionFailedException if the property cannot be converted to the given {@code propertyType}
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_READ_REPOSITORY)
<T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(String configurationKeyName);
/**
* Retrieves a configuration value from the e.g. tenant overwritten configuration values or in case the tenant does not a have a specific
* configuration the global default value hold in the {@link Environment}.
*
* @param <T> the type of the configuration value
* @param configurationKeyName the key of the configuration
* @param propertyType the type of the configuration value, e.g. {@code String.class}, {@code Integer.class}, etc
* @return the converted configuration value either from the tenant specific configuration stored or from the fallback default values or
* {@code null} in case key has not been configured and not default value exists
* @throws TenantConfigurationValidatorException if the {@code propertyType} and the value in general does not
* match the expected type and format defined by the Key
* @throws ConversionFailedException if the property cannot be converted to the given {@code propertyType}
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_READ_REPOSITORY)
<T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(String configurationKeyName,
Class<T> propertyType);
/**
* returns the global configuration property either defined in the property file or a default value otherwise.
*
* @param <T> the type of the configuration value
* @param configurationKeyName the key of the configuration
* @param propertyType the type of the configuration value, e.g. {@code String.class}, {@code Integer.class}, etc
* @return the global configured value
* @throws TenantConfigurationValidatorException if the {@code propertyType} and the value in the property file or the default value
* does not match the expected type and format defined by the Key
* @throws ConversionFailedException if the property cannot be converted to the given {@code propertyType}
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_READ_REPOSITORY)
<T> T getGlobalConfigurationValue(String configurationKeyName, Class<T> propertyType);
@PreAuthorize(value = "hasAuthority('READ_" + SpPermission.TARGET + "')")
Function<Target, PollStatus> pollStatusResolver();
}

View File

@@ -20,6 +20,10 @@ import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
/**
* A base definition class for an event which contains an id.
* <p/>
*
* Note: it implements {@link org.eclipse.hawkbit.tenancy.TenantAwareCacheManager.CacheEvictEvent} methods but in order
* to be really include in the cache eviction process the subclasses must declare that it implements that interface.
*/
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@@ -38,4 +42,13 @@ public abstract class RemoteIdEvent extends RemoteTenantAwareEvent {
this.entityClass = entityClass.getName();
this.entityId = entityId;
}
public String getCacheName() {
final int index = entityClass.lastIndexOf('.');
return index < 0 ? entityClass : entityClass.substring(index + 1);
}
public Object getCacheKey() {
return entityId;
}
}

View File

@@ -17,6 +17,8 @@ import lombok.NoArgsConstructor;
import lombok.ToString;
import org.eclipse.hawkbit.repository.event.entity.EntityDeletedEvent;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
import org.eclipse.hawkbit.tenancy.TenantAwareCacheManager;
import org.eclipse.hawkbit.tenancy.TenantAwareCacheManager.CacheEvictEvent;
/**
* Defines the remote event of deleting a {@link org.eclipse.hawkbit.repository.model.TenantConfiguration}.
@@ -25,7 +27,7 @@ import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
@Getter
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class TenantConfigurationDeletedEvent extends RemoteIdEvent implements EntityDeletedEvent {
public class TenantConfigurationDeletedEvent extends RemoteIdEvent implements EntityDeletedEvent, CacheEvictEvent {
@Serial
private static final long serialVersionUID = 1L;
@@ -41,4 +43,10 @@ public class TenantConfigurationDeletedEvent extends RemoteIdEvent implements En
this.configKey = configKey;
this.configValue = configValue;
}
// overrides since the default impl is based on entity id while the tenant cache is key (string) based
@Override
public String getCacheKey() {
return configKey;
}
}

View File

@@ -27,4 +27,10 @@ public class TenantConfigurationCreatedEvent extends RemoteEntityEvent<TenantCon
public TenantConfigurationCreatedEvent(final TenantConfiguration tenantConfiguration) {
super(tenantConfiguration);
}
// overrides since the default impl is based on entity id while the tenant cache is key (string) based
@Override
public String getCacheKey() {
return getEntity().map(TenantConfiguration::getKey).orElse(null); // null will clean all tenant cache
}
}

View File

@@ -14,12 +14,13 @@ import java.io.Serial;
import lombok.NoArgsConstructor;
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
import org.eclipse.hawkbit.tenancy.TenantAwareCacheManager.CacheEvictEvent;
/**
* Defines the remote event of updating a {@link TenantConfiguration}.
*/
@NoArgsConstructor // for serialization libs like jackson
public class TenantConfigurationUpdatedEvent extends RemoteEntityEvent<TenantConfiguration> implements EntityUpdatedEvent {
public class TenantConfigurationUpdatedEvent extends RemoteEntityEvent<TenantConfiguration> implements EntityUpdatedEvent, CacheEvictEvent {
@Serial
private static final long serialVersionUID = 1L;
@@ -27,4 +28,10 @@ public class TenantConfigurationUpdatedEvent extends RemoteEntityEvent<TenantCon
public TenantConfigurationUpdatedEvent(final TenantConfiguration tenantConfiguration) {
super(tenantConfiguration);
}
// overrides since the default impl is based on entity id while the tenant cache is key (string) based
@Override
public String getCacheKey() {
return getEntity().map(TenantConfiguration::getKey).orElse(null); // null will clean all tenant cache
}
}