use of io.micronaut.messaging.exceptions.MessageListenerException 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.messaging.exceptions.MessageListenerException 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.messaging.exceptions.MessageListenerException in project micronaut-jms by micronaut-projects.
the class JMSListenerContainer method registerListener.
/**
* Registers a {@link JMSListenerContainer} with default concurrency.
* <p>
* NOTE: this method is not recommended; instead use the annotation driven
* {@link io.micronaut.jms.annotations.JMSListener}
*
* @param destination the queue or topic name
* @param listener the message handler
* @param clazz the message type
*/
public void registerListener(String destination, MessageHandler<T> listener, Class<T> clazz) {
try {
final Connection connection = connectionPool.createConnection();
final Session session = connection.createSession(DEFAULT_TRANSACTED, DEFAULT_ACKNOWLEDGE_MODE);
openConnections.add(connection);
final MessageConsumer consumer = session.createConsumer(lookupDestination(destination, session));
consumer.setMessageListener(new MessageHandlerAdapter<>(new ConcurrentMessageHandler<>(listener, new ThreadPoolExecutor(threadPoolSize, maxThreadPoolSize, DEFAULT_KEEP_ALIVE_TIME, SECONDS, new LinkedBlockingQueue<>(DEFAULT_EXECUTOR_QUEUE_SIZE), Executors.defaultThreadFactory())), clazz));
LOGGER.debug("registered {} listener {} for destination '{}' and class {}", type.name().toLowerCase(), listener, destination, clazz.getName());
} catch (Exception e) {
throw new MessageListenerException("Problem registering a MessageConsumer for " + destination, e);
}
}
use of io.micronaut.messaging.exceptions.MessageListenerException in project micronaut-jms by micronaut-projects.
the class JMSListenerContainer method registerListener.
/**
* Internal method used by the {@link JMSListenerContainerFactory} for
* registering new listeners.
* <p>
* NOTE: this method is used internally by the
* {@link io.micronaut.jms.configuration.AbstractJMSListenerMethodProcessor}
* and is not recommended for use. Instead the annotation driven
* {@link io.micronaut.jms.annotations.JMSListener} is preferred.
*
* @param destination the queue or topic name
* @param listener the message handler
* @param clazz the message type
* @param transacted indicates whether the session will use a local transaction
* @param acknowledgeMode when transacted is false, indicates how messages
* received by the session will be acknowledged
* @see Session#AUTO_ACKNOWLEDGE
* @see Session#CLIENT_ACKNOWLEDGE
* @see Session#DUPS_OK_ACKNOWLEDGE
*/
public void registerListener(String destination, MessageListener listener, // TODO unused
Class<T> clazz, boolean transacted, int acknowledgeMode) {
try {
final Connection connection = connectionPool.createConnection();
final Session session = connection.createSession(transacted, acknowledgeMode);
openConnections.add(connection);
final MessageConsumer consumer = session.createConsumer(lookupDestination(destination, session));
consumer.setMessageListener((message) -> {
try {
listener.onMessage(message);
if (transacted) {
session.commit();
}
} catch (Exception e) {
if (transacted) {
try {
session.rollback();
} catch (JMSException | RuntimeException e2) {
throw new MessageListenerException("Problem rolling back transaction", e2);
}
}
throw new MessageListenerException(e.getMessage(), e);
}
});
LOGGER.debug("registered {} listener {} for destination '{}'; " + "transacted: {}, ack mode: {}", type.name().toLowerCase(), listener, destination, transacted, acknowledgeMode);
} catch (JMSException | RuntimeException e) {
throw new MessageListenerException("Problem registering a MessageConsumer for " + destination, e);
}
}
Aggregations