use of io.micronaut.aop.InterceptedMethod in project resilience4j by resilience4j.
the class CircuitBreakerInterceptor method intercept.
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
Optional<AnnotationValue<io.github.resilience4j.micronaut.annotation.CircuitBreaker>> opt = context.findAnnotation(io.github.resilience4j.micronaut.annotation.CircuitBreaker.class);
if (!opt.isPresent()) {
return context.proceed();
}
ExecutableMethod executableMethod = context.getExecutableMethod();
final String name = executableMethod.stringValue(io.github.resilience4j.micronaut.annotation.CircuitBreaker.class, "name").orElse("default");
CircuitBreaker circuitBreaker = this.circuitBreakerRegistry.circuitBreaker(name);
InterceptedMethod interceptedMethod = InterceptedMethod.of(context);
try {
switch(interceptedMethod.resultType()) {
case PUBLISHER:
return interceptedMethod.handleResult(fallbackReactiveTypes(Flowable.fromPublisher(interceptedMethod.interceptResultAsPublisher()).compose(CircuitBreakerOperator.of(circuitBreaker)), context));
case COMPLETION_STAGE:
return interceptedMethod.handleResult(fallbackForFuture(circuitBreaker.executeCompletionStage(() -> {
try {
return interceptedMethod.interceptResultAsCompletionStage();
} catch (Exception e) {
throw new CompletionException(e);
}
}), context));
case SYNCHRONOUS:
try {
return circuitBreaker.executeCheckedSupplier(context::proceed);
} catch (Throwable exception) {
return fallback(context, exception);
}
default:
return interceptedMethod.unsupported();
}
} catch (Exception e) {
return interceptedMethod.handleException(e);
}
}
use of io.micronaut.aop.InterceptedMethod in project resilience4j by resilience4j.
the class TimeLimiterInterceptor method intercept.
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
Optional<AnnotationValue<io.github.resilience4j.micronaut.annotation.TimeLimiter>> opt = context.findAnnotation(io.github.resilience4j.micronaut.annotation.TimeLimiter.class);
if (!opt.isPresent()) {
return context.proceed();
}
ExecutableMethod executableMethod = context.getExecutableMethod();
final String name = executableMethod.stringValue(io.github.resilience4j.micronaut.annotation.TimeLimiter.class).orElse("default");
TimeLimiter timeLimiter = this.timeLimiterRegistry.timeLimiter(name);
InterceptedMethod interceptedMethod = InterceptedMethod.of(context);
try {
switch(interceptedMethod.resultType()) {
case PUBLISHER:
return interceptedMethod.handleResult(fallbackReactiveTypes(Flowable.fromPublisher(interceptedMethod.interceptResultAsPublisher()).compose(TimeLimiterTransformer.of(timeLimiter)), context));
case COMPLETION_STAGE:
return interceptedMethod.handleResult(fallbackForFuture(timeLimiter.executeCompletionStage(executorService, () -> {
try {
return interceptedMethod.interceptResultAsCompletionStage();
} catch (Exception e) {
throw new CompletionException(e);
}
}), context));
case SYNCHRONOUS:
try {
return timeLimiter.executeFutureSupplier(() -> CompletableFuture.supplyAsync(context::proceed));
} catch (Throwable exception) {
return fallback(context, exception);
}
default:
return interceptedMethod.unsupported();
}
} catch (Exception e) {
return interceptedMethod.handleException(e);
}
}
use of io.micronaut.aop.InterceptedMethod in project micronaut-kafka by micronaut-projects.
the class KafkaClientIntroductionAdvice method intercept.
@SuppressWarnings("unchecked")
@Override
public final Object intercept(MethodInvocationContext<Object, Object> context) {
if (context.hasAnnotation(KafkaClient.class)) {
if (!context.hasAnnotation(KafkaClient.class)) {
throw new IllegalStateException("No @KafkaClient annotation present on method: " + context);
}
ProducerState producerState = getProducer(context);
InterceptedMethod interceptedMethod = InterceptedMethod.of(context);
try {
Argument<?> returnType = interceptedMethod.returnTypeValue();
if (Argument.OBJECT_ARGUMENT.equalsType(returnType)) {
returnType = Argument.of(RecordMetadata.class);
}
switch(interceptedMethod.resultType()) {
case COMPLETION_STAGE:
CompletableFuture<Object> completableFuture = returnCompletableFuture(context, producerState, returnType);
return interceptedMethod.handleResult(completableFuture);
case PUBLISHER:
Flux<Object> returnFlowable = returnPublisher(context, producerState, returnType);
return interceptedMethod.handleResult(returnFlowable);
case SYNCHRONOUS:
return returnSynchronous(context, producerState);
default:
return interceptedMethod.unsupported();
}
} catch (Exception e) {
return interceptedMethod.handleException(e);
}
} else {
// can't be implemented so proceed
return context.proceed();
}
}
use of io.micronaut.aop.InterceptedMethod in project micronaut-nats by micronaut-projects.
the class NatsIntroductionAdvice method intercept.
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
if (context.hasAnnotation(NatsClient.class)) {
StaticPublisherState publisherState = publisherCache.get(context.getExecutableMethod(), method -> {
if (!method.findAnnotation(NatsClient.class).isPresent()) {
throw new IllegalStateException("No @NatsClient annotation present on method: " + method);
}
Optional<String> subject = method.findAnnotation(Subject.class).flatMap(AnnotationValue::stringValue);
String connection = method.findAnnotation(NatsConnection.class).flatMap(conn -> conn.get("connection", String.class)).orElse(NatsConnection.DEFAULT_CONNECTION);
Argument<?> bodyArgument = findBodyArgument(method).orElseThrow(() -> new NatsClientException("No valid message body argument found for method: " + method));
Headers methodHeaders = new Headers();
List<AnnotationValue<MessageHeader>> headerAnnotations = method.getAnnotationValuesByType(MessageHeader.class);
// set the values in the class first so methods can override
Collections.reverse(headerAnnotations);
headerAnnotations.forEach(header -> {
String name = header.stringValue("name").orElse(null);
String value = header.stringValue().orElse(null);
if (StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(value)) {
methodHeaders.put(name, value);
}
});
NatsMessageSerDes<?> serDes = serDesRegistry.findSerdes(bodyArgument).orElseThrow(() -> new NatsClientException(String.format("Could not find a serializer for the body argument of type [%s]", bodyArgument.getType().getName())));
ReactivePublisher reactivePublisher;
try {
reactivePublisher = beanContext.getBean(ReactivePublisher.class, Qualifiers.byName(connection));
} catch (Throwable e) {
throw new NatsClientException(String.format("Failed to retrieve a publisher named [%s] to publish messages", connection), e);
}
return new StaticPublisherState(subject.orElse(null), bodyArgument, methodHeaders, method.getReturnType(), connection, serDes, reactivePublisher);
});
NatsMessage.Builder builder = NatsMessage.builder();
Headers headers = publisherState.getHeaders();
Argument[] arguments = context.getArguments();
Map<String, Object> parameterValues = context.getParameterValueMap();
for (Argument argument : arguments) {
AnnotationValue<MessageHeader> headerAnn = argument.getAnnotation(MessageHeader.class);
boolean headersObject = argument.getType() == Headers.class;
if (headerAnn != null) {
Map.Entry<String, List<String>> entry = getNameAndValue(argument, headerAnn, parameterValues);
String name = entry.getKey();
List<String> value = entry.getValue();
headers.put(name, value);
} else if (headersObject) {
Headers dynamicHeaders = (Headers) parameterValues.get(argument.getName());
dynamicHeaders.forEach(headers::put);
}
}
if (!headers.isEmpty()) {
builder.headers(headers);
}
Object body = parameterValues.get(publisherState.getBodyArgument().getName());
byte[] converted = publisherState.getSerDes().serialize(body);
builder = builder.data(converted);
String subject = publisherState.getSubject().orElse(findSubjectKey(context).orElse(null));
builder = builder.subject(subject);
if (subject == null) {
throw new IllegalStateException("No @Subject annotation present on method: " + context.getExecutableMethod());
}
Message message = builder.build();
ReactivePublisher reactivePublisher = publisherState.getReactivePublisher();
InterceptedMethod interceptedMethod = InterceptedMethod.of(context);
try {
boolean rpc = !interceptedMethod.returnTypeValue().isVoid();
Mono<?> reactive;
if (rpc) {
reactive = Mono.from(reactivePublisher.publishAndReply(message)).flatMap(response -> {
Object deserialized = deserialize(response, publisherState.getDataType(), publisherState.getDataType());
if (deserialized == null) {
return Mono.empty();
} else {
return Mono.just(deserialized);
}
});
if (interceptedMethod.resultType() == InterceptedMethod.ResultType.SYNCHRONOUS) {
if (LOG.isDebugEnabled()) {
LOG.debug("Publish is an RPC call. Blocking until a response is received.", context);
}
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Publish is an RPC call. Publisher will complete when a response is received.", context);
}
reactive = reactive.subscribeOn(scheduler);
}
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Sending the message.", context);
}
reactive = Mono.from(reactivePublisher.publish(message)).onErrorMap(throwable -> new NatsClientException(String.format("Failed to publish a message with subject: [%s]", subject), throwable, Collections.singletonList(message)));
}
switch(interceptedMethod.resultType()) {
case PUBLISHER:
return interceptedMethod.handleResult(reactive);
case COMPLETION_STAGE:
CompletableFuture<Object> future = new CompletableFuture<>();
reactive.subscribe(new Subscriber<Object>() {
Object value = null;
@Override
public void onSubscribe(Subscription s) {
s.request(1);
}
@Override
public void onNext(Object o) {
value = o;
}
@Override
public void onError(Throwable t) {
future.completeExceptionally(t);
}
@Override
public void onComplete() {
future.complete(value);
}
});
return interceptedMethod.handleResult(future);
case SYNCHRONOUS:
return interceptedMethod.handleResult(reactive.block());
default:
return interceptedMethod.unsupported();
}
} catch (Exception e) {
return interceptedMethod.handleException(e);
}
} else {
return context.proceed();
}
}
Aggregations