use of io.nats.client.impl.Headers in project micronaut-nats by micronaut-projects.
the class ProductInfoTypeBinder method bind.
@Override
public BindingResult<ProductInfo> bind(ArgumentConversionContext<ProductInfo> context, Message source) {
// <4>
Headers rawHeaders = source.getHeaders();
if (rawHeaders == null) {
return BindingResult.EMPTY;
}
NatsHeaderConvertibleValues headers = new NatsHeaderConvertibleValues(rawHeaders, conversionService);
// <5>
String size = headers.get("productSize", String.class).orElse(null);
// <6>
Optional<Long> count = headers.get("x-product-count", Long.class);
// <7>
Optional<Boolean> sealed = headers.get("x-product-sealed", Boolean.class);
if (headers.getConversionErrors().isEmpty() && count.isPresent() && sealed.isPresent()) {
// <8>
return () -> Optional.of(new ProductInfo(size, count.get(), sealed.get()));
} else {
return new BindingResult<ProductInfo>() {
@Override
public Optional<ProductInfo> getValue() {
return Optional.empty();
}
@Override
public List<ConversionError> getConversionErrors() {
// <9>
return headers.getConversionErrors();
}
};
}
}
use of io.nats.client.impl.Headers in project micronaut-nats by micronaut-projects.
the class HeadersSpec method testPublishingAndReceivingHeaders.
@Test
void testPublishingAndReceivingHeaders() {
startContext();
// tag::producer[]
ProductClient productClient = applicationContext.getBean(ProductClient.class);
productClient.send("body".getBytes());
productClient.send("medium", 20L, "body2".getBytes());
productClient.send(null, 30L, "body3".getBytes());
Headers headers = new Headers();
headers.put("productSize", "large");
headers.put("x-product-count", "40");
productClient.send("body4".getBytes(), headers);
productClient.send("body5".getBytes(), Arrays.asList("xtra-small", "xtra-large"));
// end::producer[]
ProductListener productListener = applicationContext.getBean(ProductListener.class);
waitFor(() -> productListener.messageProperties.size() == 6 && productListener.messageProperties.contains("true|10|small") && productListener.messageProperties.contains("true|20|medium") && productListener.messageProperties.contains("true|30|medium") && productListener.messageProperties.contains("true|40|large") && productListener.messageProperties.contains("true|20|xtra-small") && productListener.messageProperties.contains("true|20|xtra-large"));
}
use of io.nats.client.impl.Headers in project micronaut-nats by micronaut-projects.
the class NatsHeaderBinder method bind.
@Override
public BindingResult<Object> bind(ArgumentConversionContext<Object> context, Message messageState) {
String parameterName = context.getAnnotationMetadata().stringValue(MessageHeader.class).orElse(context.getArgument().getName());
Headers rawHeaders = messageState.getHeaders();
NatsHeaderConvertibleValues headers = new NatsHeaderConvertibleValues(rawHeaders, conversionService);
Optional<Object> header = headers.get(parameterName, context);
return () -> header;
}
use of io.nats.client.impl.Headers 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