use of io.micronaut.coherence.annotation.CoherencePublisher in project micronaut-coherence by micronaut-projects.
the class CoherencePublisherIntroductionAdvice method intercept.
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
if (context.hasAnnotation(CoherencePublisher.class)) {
// Make sure the CoherencePublisher annotation is present
context.findAnnotation(CoherencePublisher.class).orElseThrow(() -> new IllegalStateException("No @CoherencePublisher annotation present on method: " + context));
String topicName = Utils.getFirstTopicName(context).orElse(null);
String sessionName = context.stringValue(SessionName.class).orElse(Coherence.DEFAULT_NAME);
Duration maxBlock = context.getValue(CoherencePublisher.class, "maxBlock", Duration.class).orElse(null);
Argument<?> bodyArgument = null;
Argument<?>[] arguments = context.getArguments();
Object[] parameterValues = context.getParameterValues();
int valueIndex = -1;
for (int i = 0; i < arguments.length; i++) {
Argument<?> argument = arguments[i];
if (argument.isAnnotationPresent(MessageBody.class)) {
bodyArgument = argument;
valueIndex = i;
} else if (argument.isAnnotationPresent(Topics.class) || argument.isAnnotationPresent(Topic.class)) {
Object o = parameterValues[i];
if (o != null) {
topicName = o.toString();
}
}
}
if (StringUtils.isEmpty(topicName)) {
throw new MessagingClientException("No topic specified for method: " + context);
}
if (bodyArgument == null) {
for (int i = 0; i < arguments.length; i++) {
Argument<?> argument = arguments[i];
if (!argument.getAnnotationMetadata().hasStereotype(Bindable.class)) {
bodyArgument = argument;
valueIndex = i;
break;
}
}
}
if (bodyArgument == null) {
throw new MessagingClientException("No valid message body argument found for method: " + context);
}
Object value = parameterValues[valueIndex];
ReturnType<Object> returnType = context.getReturnType();
Class<?> javaReturnType = returnType.getType();
Publisher<Object> publisher = getPublisher(topicName, sessionName);
boolean isReactiveReturnType = Publishers.isConvertibleToPublisher(javaReturnType);
boolean isReactiveValue = value != null && Publishers.isConvertibleToPublisher(value.getClass());
InterceptedMethod interceptedMethod = InterceptedMethod.of(context);
if (isReactiveReturnType) {
// return type is a reactive type
Flux<?> flux = buildSendFlux(context, publisher, Argument.OBJECT_ARGUMENT, maxBlock, value);
return Publishers.convertPublisher(flux, javaReturnType);
} else {
// return type is a future - must be future of Void
Argument<?> returnArg = returnType.getFirstTypeVariable().orElse(Argument.of(Void.class));
if (returnArg.getType() != Void.class) {
throw new MessagingClientException("Generic return type for method must be Void, i.e. CompletableFuture<Void> - " + context);
}
CompletableFuture<Void> completableFuture = new CompletableFuture<>();
if (isReactiveValue) {
// return type is a future and value is reactive
Flux<?> sendFlux = buildSendFlux(context, publisher, returnArg, maxBlock, value);
if (!Publishers.isSingle(value.getClass())) {
sendFlux = sendFlux.collectList().flux();
}
// noinspection ReactiveStreamsSubscriberImplementation
sendFlux.subscribe(new Subscriber<Object>() {
@Override
public void onSubscribe(Subscription s) {
s.request(1);
}
@Override
public void onNext(Object o) {
}
@Override
public void onError(Throwable t) {
completableFuture.completeExceptionally(wrapException(context, t));
}
@Override
public void onComplete() {
completableFuture.complete(null);
}
});
} else {
// return type is a future and value is single message
publisher.publish(value).handle((status, exception) -> {
if (exception != null) {
completableFuture.completeExceptionally(wrapException(context, exception));
} else {
completableFuture.complete(null);
}
return null;
});
}
return interceptedMethod.handleResult(completableFuture);
}
} else {
// can't be implemented so proceed
return context.proceed();
}
}
Aggregations