use of io.micronaut.core.bind.DefaultExecutableBinder in project micronaut-kafka by micronaut-projects.
the class KafkaConsumerProcessor method processConsumerRecords.
private boolean processConsumerRecords(final ConsumerState consumerState, final ExecutableMethod<?, ?> method, final Map<Argument<?>, Object> boundArguments, final boolean trackPartitions, final Optional<Argument<?>> ackArg, final ConsumerRecords<?, ?> consumerRecords) {
final ExecutableBinder<ConsumerRecord<?, ?>> executableBinder = new DefaultExecutableBinder<>(boundArguments);
final Map<TopicPartition, OffsetAndMetadata> currentOffsets = trackPartitions ? new HashMap<>() : null;
for (final ConsumerRecord<?, ?> consumerRecord : consumerRecords) {
LOG.trace("Kafka consumer [{}] received record: {}", method, consumerRecord);
if (trackPartitions) {
final TopicPartition topicPartition = new TopicPartition(consumerRecord.topic(), consumerRecord.partition());
final OffsetAndMetadata offsetAndMetadata = new OffsetAndMetadata(consumerRecord.offset() + 1, null);
currentOffsets.put(topicPartition, offsetAndMetadata);
}
Consumer<?, ?> kafkaConsumer = consumerState.kafkaConsumer;
ackArg.ifPresent(argument -> boundArguments.put(argument, (KafkaAcknowledgement) () -> kafkaConsumer.commitSync(currentOffsets)));
try {
final BoundExecutable boundExecutable = executableBinder.bind(method, binderRegistry, consumerRecord);
final Object result = boundExecutable.invoke(consumerState.consumerBean);
if (result != null) {
final Flux<?> resultFlowable;
final boolean isBlocking;
if (Publishers.isConvertibleToPublisher(result)) {
resultFlowable = Flux.from(Publishers.convertPublisher(result, Publisher.class));
isBlocking = method.hasAnnotation(Blocking.class);
} else {
resultFlowable = Flux.just(result);
isBlocking = true;
}
handleResultFlux(consumerState, method, consumerRecord, resultFlowable, isBlocking, consumerRecords);
}
} catch (Throwable e) {
if (resolveWithErrorStrategy(consumerState, consumerRecord, e)) {
return false;
}
}
if (consumerState.offsetStrategy == OffsetStrategy.SYNC_PER_RECORD) {
try {
kafkaConsumer.commitSync(currentOffsets);
} catch (CommitFailedException e) {
handleException(consumerState, consumerRecord, e);
}
} else if (consumerState.offsetStrategy == OffsetStrategy.ASYNC_PER_RECORD) {
kafkaConsumer.commitAsync(currentOffsets, resolveCommitCallback(consumerState.consumerBean));
}
}
return true;
}
use of io.micronaut.core.bind.DefaultExecutableBinder in project micronaut-kafka by micronaut-projects.
the class KafkaConsumerProcessor method processConsumerRecordsAsBatch.
private boolean processConsumerRecordsAsBatch(final ConsumerState consumerState, final ExecutableMethod<?, ?> method, final Map<Argument<?>, Object> boundArguments, final ConsumerRecords<?, ?> consumerRecords) {
final ExecutableBinder<ConsumerRecords<?, ?>> batchBinder = new DefaultExecutableBinder<>(boundArguments);
final BoundExecutable boundExecutable = batchBinder.bind(method, batchBinderRegistry, consumerRecords);
Object result = boundExecutable.invoke(consumerState.consumerBean);
if (result != null) {
if (result.getClass().isArray()) {
result = Arrays.asList((Object[]) result);
}
final boolean isPublisher = Publishers.isConvertibleToPublisher(result);
final Flux<?> resultFlux;
if (result instanceof Iterable) {
resultFlux = Flux.fromIterable((Iterable) result);
} else if (isPublisher) {
resultFlux = Flux.from(Publishers.convertPublisher(result, Publisher.class));
} else {
resultFlux = Flux.just(result);
}
final Iterator<? extends ConsumerRecord<?, ?>> iterator = consumerRecords.iterator();
final boolean isBlocking = !isPublisher || method.hasAnnotation(Blocking.class);
if (isBlocking) {
List<?> objects = resultFlux.collectList().block();
for (Object object : objects) {
if (iterator.hasNext()) {
final ConsumerRecord<?, ?> consumerRecord = iterator.next();
handleResultFlux(consumerState, method, consumerRecord, Flux.just(object), isBlocking, consumerRecords);
}
}
} else {
resultFlux.subscribe(o -> {
if (iterator.hasNext()) {
final ConsumerRecord<?, ?> consumerRecord = iterator.next();
handleResultFlux(consumerState, method, consumerRecord, Flux.just(o), isBlocking, consumerRecords);
}
});
}
}
return true;
}
use of io.micronaut.core.bind.DefaultExecutableBinder in project micronaut-nats by micronaut-projects.
the class NatsConsumerAdvice method process.
@Override
public void process(BeanDefinition<?> beanDefinition, ExecutableMethod<?, ?> method) {
if (method.hasAnnotation(NatsListener.class)) {
AnnotationValue<Subject> subjectAnn = method.getAnnotation(Subject.class);
if (subjectAnn != null) {
String subject = subjectAnn.getRequiredValue(String.class);
String connectionName = method.findAnnotation(NatsConnection.class).flatMap(conn -> conn.get("connection", String.class)).orElse(NatsConnection.DEFAULT_CONNECTION);
io.micronaut.context.Qualifier<Object> qualifer = beanDefinition.getAnnotationTypeByStereotype("javax.inject.Qualifier").map(type -> Qualifiers.byAnnotation(beanDefinition, type)).orElse(null);
Class<Object> beanType = (Class<Object>) beanDefinition.getBeanType();
Class<?> returnTypeClass = method.getReturnType().getType();
boolean isVoid = returnTypeClass == Void.class || returnTypeClass == void.class;
Object bean = beanContext.findBean(beanType, qualifer).orElseThrow(() -> new MessageListenerException("Could not find the bean to execute the method " + method));
Connection connection = beanContext.getBean(Connection.class, Qualifiers.byName(connectionName));
DefaultExecutableBinder<Message> binder = new DefaultExecutableBinder<>();
Dispatcher ds = connection.createDispatcher(msg -> {
BoundExecutable boundExecutable = null;
try {
boundExecutable = binder.bind(method, binderRegistry, msg);
} catch (Throwable e) {
handleException(new NatsListenerException("An error occurred binding the message to the method", e, bean, msg));
}
if (boundExecutable != null) {
Object returnedValue = boundExecutable.invoke(bean);
if (!isVoid && StringUtils.isNotEmpty(msg.getReplyTo())) {
byte[] converted = null;
if (returnedValue != null) {
NatsMessageSerDes serDes = serDesRegistry.findSerdes(method.getReturnType().asArgument()).map(NatsMessageSerDes.class::cast).orElseThrow(() -> new NatsListenerException(String.format("Could not find a serializer for the body argument of type [%s]", returnedValue.getClass().getName()), bean, msg));
converted = serDes.serialize(returnedValue);
}
connection.publish(msg.getReplyTo(), converted);
}
}
});
Optional<String> queueOptional = subjectAnn.get("queue", String.class);
if (queueOptional.isPresent() && !queueOptional.get().isEmpty()) {
ds.subscribe(subject, queueOptional.get());
} else {
ds.subscribe(subject);
}
consumerDispatchers.put(ds, subject);
}
}
}
use of io.micronaut.core.bind.DefaultExecutableBinder in project micronaut-gcp by micronaut-projects.
the class PubSubConsumerAdvice method process.
@Override
public void process(BeanDefinition<?> beanDefinition, ExecutableMethod<?, ?> method) {
if (beanDefinition.hasDeclaredAnnotation(PubSubListener.class)) {
AnnotationValue<Subscription> subscriptionAnnotation = method.getAnnotation(Subscription.class);
io.micronaut.context.Qualifier<Object> qualifier = beanDefinition.getAnnotationTypeByStereotype(Qualifier.class).map(type -> Qualifiers.byAnnotation(beanDefinition, type)).orElse(null);
boolean hasAckArg = Arrays.stream(method.getArguments()).anyMatch(arg -> Acknowledgement.class.isAssignableFrom(arg.getType()));
Class<Object> beanType = (Class<Object>) beanDefinition.getBeanType();
Object bean = beanContext.findBean(beanType, qualifier).orElseThrow(() -> new MessageListenerException("Could not find the bean to execute the method " + method));
DefaultExecutableBinder<PubSubConsumerState> binder = new DefaultExecutableBinder<>();
if (subscriptionAnnotation != null) {
String subscriptionName = subscriptionAnnotation.getRequiredValue(String.class);
ProjectSubscriptionName projectSubscriptionName = PubSubSubscriptionUtils.toProjectSubscriptionName(subscriptionName, googleCloudConfiguration.getProjectId());
String defaultContentType = subscriptionAnnotation.stringValue("contentType").orElse(MediaType.APPLICATION_JSON);
String configuration = subscriptionAnnotation.stringValue("configuration").orElse("");
MessageReceiver receiver = (PubsubMessage message, AckReplyConsumer ackReplyConsumer) -> {
String messageContentType = message.getAttributesMap().getOrDefault("Content-Type", "");
String contentType = Optional.of(messageContentType).filter(StringUtils::isNotEmpty).orElse(defaultContentType);
DefaultPubSubAcknowledgement pubSubAcknowledgement = new DefaultPubSubAcknowledgement(ackReplyConsumer);
PubSubConsumerState consumerState = new PubSubConsumerState(message, ackReplyConsumer, projectSubscriptionName, contentType);
try {
BoundExecutable executable = null;
try {
executable = binder.bind(method, binderRegistry, consumerState);
} catch (Exception ex) {
handleException(new PubSubMessageReceiverException("Error binding message to the method", ex, bean, consumerState));
}
// Discard result
executable.invoke(bean);
if (!hasAckArg) {
// if manual ack is not specified we auto ack message after method execution
pubSubAcknowledgement.ack();
} else {
Optional<Object> boundAck = Arrays.stream(executable.getBoundArguments()).filter(o -> (o instanceof DefaultPubSubAcknowledgement)).findFirst();
if (boundAck.isPresent()) {
DefaultPubSubAcknowledgement manualAck = (DefaultPubSubAcknowledgement) boundAck.get();
if (!manualAck.isClientAck()) {
logger.warn("Method {} was executed and no message acknowledge detected. Did you forget to invoke ack()/nack()?", method.getName());
}
}
}
} catch (Exception e) {
handleException(new PubSubMessageReceiverException("Error handling message", e, bean, consumerState));
}
};
try {
this.subscriberFactory.createSubscriber(new SubscriberFactoryConfig(projectSubscriptionName, receiver, configuration, pubSubConfigurationProperties.getSubscribingExecutor()));
} catch (Exception e) {
throw new PubSubListenerException("Failed to create subscriber", e);
}
}
}
}
use of io.micronaut.core.bind.DefaultExecutableBinder in project micronaut-jms by micronaut-projects.
the class AbstractJMSListenerMethodProcessor method generateAndBindListener.
@SuppressWarnings("unchecked")
private MessageListener generateAndBindListener(Object bean, ExecutableMethod<?, ?> method, ExecutorService executor, boolean acknowledge) {
return message -> executor.submit(() -> {
try {
DefaultExecutableBinder<Message> binder = new DefaultExecutableBinder<>();
BoundExecutable boundExecutable = binder.bind(method, jmsArgumentBinderRegistry, message);
boundExecutable.invoke(bean);
if (acknowledge) {
try {
message.acknowledge();
} catch (JMSException e) {
logger.error("Failed to acknowledge receipt of message with the broker. " + "This message may be falsely retried.", e);
throw new MessageAcknowledgementException(e.getMessage(), e);
}
}
} catch (Exception e) {
logger.error("Failed to process a message: " + message + " " + e.getMessage(), e);
}
});
}
Aggregations