@@ -28,73 +28,28 @@ public abstract class AbstractServerRtException extends RuntimeException {
|
||||
private final SpServerError error;
|
||||
private final transient Map<String, Object> info;
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param error detail
|
||||
*/
|
||||
protected AbstractServerRtException(final SpServerError error) {
|
||||
super(error.getMessage());
|
||||
this.error = error;
|
||||
this.info = null;
|
||||
this(error, error.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message custom error message
|
||||
* @param error detail
|
||||
*/
|
||||
protected AbstractServerRtException(final String message, final SpServerError error) {
|
||||
this(message, error, (Map<String, Object>) null);
|
||||
protected AbstractServerRtException(final SpServerError error, final String message) {
|
||||
this(error, message, (Map<String, Object>) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message custom error message
|
||||
* @param error detail
|
||||
*/
|
||||
protected AbstractServerRtException(final String message, final SpServerError error, final Map<String, Object> info) {
|
||||
super(message);
|
||||
this.error = error;
|
||||
this.info = info;
|
||||
protected AbstractServerRtException(final SpServerError error, final String message, final Map<String, Object> info) {
|
||||
this(error, message, info, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message custom error message
|
||||
* @param error detail
|
||||
* @param cause of the exception
|
||||
*/
|
||||
protected AbstractServerRtException(final String message, final SpServerError error, final Throwable cause) {
|
||||
super(message, cause);
|
||||
this.error = error;
|
||||
this.info = null;
|
||||
protected AbstractServerRtException(final SpServerError error, final String message, final Throwable cause) {
|
||||
this(error, message, null, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param error detail
|
||||
* @param cause of the exception
|
||||
*/
|
||||
protected AbstractServerRtException(final SpServerError error, final Throwable cause) {
|
||||
super(error.getMessage(), cause);
|
||||
this.error = error;
|
||||
this.info = null;
|
||||
this(error, error.getMessage(), null, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message custom error message
|
||||
* @param error detail
|
||||
* @param cause of the exception
|
||||
*/
|
||||
protected AbstractServerRtException(
|
||||
final String message, final SpServerError error, final Throwable cause, final Map<String, Object> info) {
|
||||
final SpServerError error, final String message, final Map<String, Object> info, final Throwable cause) {
|
||||
super(message, cause);
|
||||
this.error = error;
|
||||
this.info = info;
|
||||
|
||||
@@ -86,7 +86,7 @@ public interface TenantAware {
|
||||
if (context.getAuthentication() != null) {
|
||||
final Object principal = context.getAuthentication().getPrincipal();
|
||||
if (context.getAuthentication().getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareAuthenticationDetails) {
|
||||
return tenantAwareAuthenticationDetails.getTenant();
|
||||
return tenantAwareAuthenticationDetails.tenant();
|
||||
} else if (principal instanceof TenantAwareUser tenantAwareUser) {
|
||||
return tenantAwareUser.getTenant();
|
||||
}
|
||||
|
||||
@@ -12,31 +12,14 @@ package org.eclipse.hawkbit.tenancy;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
|
||||
/**
|
||||
* An authentication details object {@link AbstractAuthenticationToken#getDetails()} which is stored in the
|
||||
* spring security authentication token details to transport the principal and tenant in the security context session.
|
||||
*/
|
||||
@Getter
|
||||
@ToString
|
||||
public class TenantAwareAuthenticationDetails implements Serializable {
|
||||
public record TenantAwareAuthenticationDetails(String tenant, boolean controller) implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String tenant;
|
||||
private final boolean controller;
|
||||
|
||||
/**
|
||||
* @param tenant the current tenant
|
||||
* @param controller boolean flag to indicate if this authenticated token is a controller authentication. {@code true} in case of
|
||||
* authenticated controller otherwise {@code false}
|
||||
*/
|
||||
public TenantAwareAuthenticationDetails(final String tenant, final boolean controller) {
|
||||
this.tenant = tenant;
|
||||
this.controller = controller;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware.TenantResolver;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties;
|
||||
@@ -59,8 +60,9 @@ public class TenantMetricsConfiguration {
|
||||
public DefaultServerRequestObservationConvention serverRequestObservationConvention(final TenantResolver tenantResolver) {
|
||||
return new DefaultServerRequestObservationConvention() {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public KeyValues getLowCardinalityKeyValues(final ServerRequestObservationContext context) {
|
||||
public KeyValues getLowCardinalityKeyValues(@NonNull final ServerRequestObservationContext context) {
|
||||
// Make sure that KeyValues entries are already sorted by name for better performance
|
||||
return KeyValues.of(exception(context), method(context), outcome(context), status(context), tenant(), uri(context));
|
||||
}
|
||||
|
||||
@@ -7,14 +7,17 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.cache;
|
||||
package org.eclipse.hawkbit.tenancy.cache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.NonNull;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* A {@link CacheManager} delegator which wraps the {@link CacheManager#getCache(String)} and {@link CacheManager#getCacheNames()}
|
||||
@@ -22,7 +25,7 @@ import org.springframework.cache.CacheManager;
|
||||
* <p/>
|
||||
* Additionally, it also provides functionality to retrieve all caches overall tenants at once, for monitoring and system access.
|
||||
*/
|
||||
public class TenantAwareCacheManager implements TenancyCacheManager {
|
||||
public class TenantAwareCacheManager implements TenantCacheManager {
|
||||
|
||||
private static final String TENANT_CACHE_DELIMITER = "|";
|
||||
|
||||
@@ -40,8 +43,9 @@ public class TenantAwareCacheManager implements TenancyCacheManager {
|
||||
this.tenantAware = tenantAware;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Cache getCache(final String name) {
|
||||
public Cache getCache(@NonNull final String name) {
|
||||
final String currentTenant = tenantAware.getCurrentTenant();
|
||||
if (isTenantInvalid(currentTenant)) {
|
||||
return null;
|
||||
@@ -50,6 +54,7 @@ public class TenantAwareCacheManager implements TenancyCacheManager {
|
||||
return delegate.getCache(buildKey(currentTenant.toUpperCase(), name));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Collection<String> getCacheNames() {
|
||||
final String currentTenant = tenantAware.getCurrentTenant();
|
||||
@@ -67,7 +72,8 @@ public class TenantAwareCacheManager implements TenancyCacheManager {
|
||||
|
||||
@Override
|
||||
public void evictCaches(final String tenant) {
|
||||
getCacheNames(tenant).forEach(cacheName -> delegate.getCache(buildKey(tenant, cacheName)).clear());
|
||||
getCacheNames(tenant).forEach(
|
||||
cacheName -> Optional.ofNullable(delegate.getCache(buildKey(tenant, cacheName))).ifPresent(Cache::clear));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.cache;
|
||||
package org.eclipse.hawkbit.tenancy.cache;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
@@ -15,7 +15,7 @@ import org.springframework.cache.CacheManager;
|
||||
/**
|
||||
* A cache interface which handles multi tenancy.
|
||||
*/
|
||||
public interface TenancyCacheManager extends CacheManager {
|
||||
public interface TenantCacheManager extends CacheManager {
|
||||
|
||||
/**
|
||||
* A direct-access for retrieving the cache without including the current tenant key. This is necessary e.g. for retrieving caches not for
|
||||
@@ -71,7 +71,7 @@ public class ObjectCopyUtil {
|
||||
final ToSetter toSetter = toSetter(toClass, setterName, fieldName, fromMethod.getReturnType());
|
||||
if (toSetter == null && toGetter == null) {
|
||||
// we allow toSetter to be null, but in that case the toGetter must not be null and the
|
||||
// from value shall always match the to value (without setting it)
|
||||
// 'from' value shall always match the to value (without setting it)
|
||||
throw new IllegalStateException("Setter counterpart for " + fromMethod + " is not found in " + toClass.getName());
|
||||
}
|
||||
propertySetters.add(new PropertyCopyFunction(fromMethod, toSetter, toGetter));
|
||||
@@ -284,50 +284,41 @@ public class ObjectCopyUtil {
|
||||
private record ToSetter(BiConsumer<Object, Object> toSetter, int order) {}
|
||||
|
||||
@SuppressWarnings("java:S1210") // java:S1210 - return 0 only when default equals return equals, assume equal hashCodes for equal objects
|
||||
private static class PropertyCopyFunction implements CopyFunction, Comparable<PropertyCopyFunction> {
|
||||
|
||||
private final Method fromMethod;
|
||||
private final ToSetter toSetter;
|
||||
private final UnaryOperator<Object> toGetter;
|
||||
|
||||
private PropertyCopyFunction(final Method fromMethod, final ToSetter toSetter, final UnaryOperator<Object> toGetter) {
|
||||
this.fromMethod = fromMethod;
|
||||
this.toGetter = toGetter;
|
||||
this.toSetter = toSetter;
|
||||
}
|
||||
private record PropertyCopyFunction(Method fromMethod, ToSetter toSetter, UnaryOperator<Object> toGetter)
|
||||
implements CopyFunction, Comparable<PropertyCopyFunction> {
|
||||
|
||||
public boolean apply(final Object from, final Object to, final boolean setNullValues, final UnaryOperator<Object> propertyProcessor) {
|
||||
final Object value;
|
||||
try {
|
||||
value = fromMethod.invoke(from);
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new IllegalStateException("Failed to get source value", e);
|
||||
} catch (final InvocationTargetException e) {
|
||||
throw new IllegalStateException("Failed to get source value", e.getTargetException() == null ? e : e.getTargetException());
|
||||
}
|
||||
if (value == null && !setNullValues) { // if !setNullValues null means no change
|
||||
return false;
|
||||
}
|
||||
if (toGetter != null) {
|
||||
final Object currentValue = toGetter.apply(to);
|
||||
if (Objects.equals(value, currentValue)) {
|
||||
return false; // no change
|
||||
final Object value;
|
||||
try {
|
||||
value = fromMethod.invoke(from);
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new IllegalStateException("Failed to get source value", e);
|
||||
} catch (final InvocationTargetException e) {
|
||||
throw new IllegalStateException("Failed to get source value", e.getTargetException() == null ? e : e.getTargetException());
|
||||
}
|
||||
if (value == null && !setNullValues) { // if !setNullValues null means no change
|
||||
return false;
|
||||
}
|
||||
if (toGetter != null) {
|
||||
final Object currentValue = toGetter.apply(to);
|
||||
if (Objects.equals(value, currentValue)) {
|
||||
return false; // no change
|
||||
}
|
||||
}
|
||||
if (toSetter == null) {
|
||||
throw new IllegalStateException(
|
||||
"Setter counterpart for " + fromMethod + " is not found in " + to.getClass().getName() +
|
||||
" and the 'from' value is not equal to the 'to' value");
|
||||
}
|
||||
toSetter.toSetter().accept(to, propertyProcessor.apply(value));
|
||||
return true;
|
||||
}
|
||||
if (toSetter == null) {
|
||||
throw new IllegalStateException(
|
||||
"Setter counterpart for " + fromMethod + " is not found in " + to.getClass().getName() +
|
||||
" and the 'from' value is not equal to the 'to' value");
|
||||
}
|
||||
toSetter.toSetter().accept(to, propertyProcessor.apply(value));
|
||||
return true;
|
||||
}
|
||||
|
||||
public int compareTo(final PropertyCopyFunction other) {
|
||||
final int orderCompare = Integer.compare(this.toSetter.order(), other.toSetter.order());
|
||||
return orderCompare == 0 ? Integer.compare(this.hashCode(), other.hashCode()) : orderCompare;
|
||||
public int compareTo(final PropertyCopyFunction other) {
|
||||
final int orderCompare = Integer.compare(this.toSetter.order(), other.toSetter.order());
|
||||
return orderCompare == 0 ? Integer.compare(this.hashCode(), other.hashCode()) : orderCompare;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// functional interface to apply the copy operation
|
||||
private interface CopyFunction {
|
||||
|
||||
@@ -18,7 +18,7 @@ import io.github.classgraph.ClassInfo;
|
||||
import io.github.classgraph.ScanResult;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class FileNameFieldsTest {
|
||||
class RsqlQueryFieldsTest {
|
||||
|
||||
/**
|
||||
* Verifies that fields classes are correctly implemented
|
||||
@@ -35,9 +35,7 @@ class FileNameFieldsTest {
|
||||
.map(clazz -> (Class<? extends RsqlQueryField>) clazz)
|
||||
.toList();
|
||||
assertThat(matchingClasses).isNotEmpty();
|
||||
matchingClasses.forEach(providerClass -> {
|
||||
assertThat(providerClass.getEnumConstants()).isNotEmpty();
|
||||
});
|
||||
matchingClasses.forEach(providerClass -> assertThat(providerClass.getEnumConstants()).isNotEmpty());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user