org.zodiac.reactor.exception.TraceSourceException Maven / Gradle / Ivy
The newest version!
package org.zodiac.reactor.exception;
import reactor.core.publisher.Mono;
import reactor.util.context.Context;
import javax.annotation.Nullable;
import org.springframework.context.MessageSource;
import org.springframework.util.StringUtils;
import org.zodiac.reactor.util.SpringLocaleUtil;
import java.util.Locale;
import java.util.function.Function;
/**
* Support traceability of exceptions, and identify the source of exceptions through {@link TraceSourceException#withSource(Object) }.
* Handle some logic by getting the source of the exception where the exception is caught.
* For example: to determine which piece of data the error occurred, etc.
*/
public class TraceSourceException extends RuntimeException {
private static final long serialVersionUID = -4042507425502136519L;
private static final String DEEP_TRACE_KEY = TraceSourceException.class.getName() + "_deep";
private static final Context DEEP_TRACE_CONTEXT = Context.of(DEEP_TRACE_KEY, true);
private String operation;
private Object source;
public TraceSourceException() {
}
public TraceSourceException(String message) {
super(message);
}
public TraceSourceException(Throwable e) {
super(e.getMessage(),e);
}
public TraceSourceException(String message, Throwable e) {
super(message, e);
}
@Nullable
public Object getSource() {
return source;
}
@Nullable
public String getOperation() {
return operation;
}
public TraceSourceException withSource(Object source) {
this.source = source;
return self();
}
public TraceSourceException withSource(String operation, Object source) {
this.operation = operation;
this.source = source;
return self();
}
protected TraceSourceException self() {
return this;
}
/**
* The deep traceability context is used to identify whether it is a deep traceability exception. When depth tracking is enabled, a new {@link TraceSourceException} object is created.
*
* @return The {@link Context}.
* @see reactor.core.publisher.Flux#subscriberContext(Context)
* @see Mono#subscriberContext(Context)
*/
public static Context deepTraceContext() {
return DEEP_TRACE_CONTEXT;
}
public static Function> transfer(Object source) {
return transfer(null, source);
}
/**
* Tracing the origin of the anomaly converter. Usually used in conjunction with {@link Mono#onErrorResume(Function)}.
*
* Conversion logic:
*
* - If the captured exception is not {@link TraceSourceException}, a new {@link TraceSourceException} is created directly and returned.
* -
*
*
* - If the catched exception is {@link TraceSourceException} and the context does not specify {@link TraceSourceException#deepTraceContext()}, modify the source in the catched {@link TraceSourceException}.
* - If {@link TraceSourceException#deepTraceContext()} is specified in the context, a new {@link TraceSourceException} is created.
*
*
*
*
*
* {@code
*
* doSomething()
* .onErrorResume(TraceSourceException.transfer(data))
*
* }
*
* @param operation The name of the operation.
* @param source The source
* @param The result type.
* @return Converter.
* @see reactor.core.publisher.Flux#onErrorResume(Function)
* @see Mono#onErrorResume(Function)
*/
public static Function> transfer(String operation, Object source) {
if (source == null && operation == null) {
return Mono::error;
}
return err -> {
if (err instanceof TraceSourceException) {
return Mono
.deferWithContext(ctx -> {
if (ctx.hasKey(DEEP_TRACE_KEY)) {
return Mono.error(new TraceSourceException(err).withSource(operation,source));
} else {
return Mono.error(((TraceSourceException) err).withSource(operation,source));
}
});
}
return Mono.error(new TraceSourceException(err).withSource(operation,source));
};
}
public static Object tryGetSource(Throwable err) {
if (err instanceof TraceSourceException) {
return ((TraceSourceException) err).getSource();
}
return null;
}
public static String tryGetOperation(Throwable err) {
if (err instanceof TraceSourceException) {
return ((TraceSourceException) err).getOperation();
}
return null;
}
public static String tryGetOperationLocalized(Throwable err, MessageSource messageSource, Locale locale) {
String opt = tryGetOperation(err);
return StringUtils.hasText(opt) ? SpringLocaleUtil.resolveMessage(messageSource, locale, opt, opt) : opt;
}
public static Mono tryGetOperationLocalizedReactive(Throwable err, MessageSource messageSource) {
return SpringLocaleUtil
.currentReactive()
.handle((locale, sink) -> {
String opt = tryGetOperationLocalized(err, messageSource, locale);
if (opt != null) {
sink.next(opt);
}
});
}
public static String tryGetOperationLocalized(Throwable err, Locale locale) {
String opt = tryGetOperation(err);
return StringUtils.hasText(opt) ? SpringLocaleUtil.resolveMessage(opt, locale, opt) : opt;
}
public static Mono tryGetOperationLocalizedReactive(Throwable err) {
return SpringLocaleUtil
.currentReactive()
.handle((locale, sink) -> {
String opt = tryGetOperationLocalized(err, locale);
if (opt != null) {
sink.next(opt);
}
});
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy