All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.bitsensor.plugins.shaded.org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.rabbit.listener.adapter;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;

import io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.MessageProperties;
import io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException;
import io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.support.AmqpHeaderMapper;
import io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.support.converter.MessageConversionException;
import io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.support.converter.MessageConverter;
import io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.support.converter.MessagingMessageConverter;
import io.bitsensor.plugins.shaded.org.springframework.core.MethodParameter;
import io.bitsensor.plugins.shaded.org.springframework.messaging.Message;
import io.bitsensor.plugins.shaded.org.springframework.messaging.MessagingException;
import io.bitsensor.plugins.shaded.org.springframework.messaging.handler.annotation.Payload;
import io.bitsensor.plugins.shaded.org.springframework.util.Assert;

import io.bitsensor.plugins.shaded.com.rabbitmq.client.Channel;

/**
 * A {@link io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.MessageListener MessageListener}
 * adapter that invokes a configurable {@link HandlerAdapter}.
 *
 * 

Wraps the incoming {@link io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message * AMQP Message} to Spring's {@link Message} abstraction, copying the * standard headers using a configurable * {@link io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.support.AmqpHeaderMapper AmqpHeaderMapper}. * *

The original {@link io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message Message} and * the {@link Channel} are provided as additional arguments so that these can * be injected as method arguments if necessary. * * @author Stephane Nicoll * @author Gary Russell * @author Artem Bilan * * @since 1.4 */ public class MessagingMessageListenerAdapter extends AbstractAdaptableMessageListener { private HandlerAdapter handlerMethod; private final MessagingMessageConverterAdapter messagingMessageConverter; public MessagingMessageListenerAdapter() { this(null, null); } public MessagingMessageListenerAdapter(Object bean, Method method) { this.messagingMessageConverter = new MessagingMessageConverterAdapter(bean, method); } /** * Set the {@link HandlerAdapter} to use to invoke the method * processing an incoming {@link io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message}. * @param handlerMethod {@link HandlerAdapter} instance. */ public void setHandlerMethod(HandlerAdapter handlerMethod) { this.handlerMethod = handlerMethod; } /** * Set the {@link AmqpHeaderMapper} implementation to use to map the standard * AMQP headers. By default, a {@link io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.support.SimpleAmqpHeaderMapper * SimpleAmqpHeaderMapper} is used. * @param headerMapper the {@link AmqpHeaderMapper} instance. * @see io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.support.SimpleAmqpHeaderMapper */ public void setHeaderMapper(AmqpHeaderMapper headerMapper) { Assert.notNull(headerMapper, "HeaderMapper must not be null"); this.messagingMessageConverter.setHeaderMapper(headerMapper); } /** * @return the {@link MessagingMessageConverter} for this listener, * being able to convert {@link io.bitsensor.plugins.shaded.org.springframework.messaging.Message}. */ protected final MessagingMessageConverter getMessagingMessageConverter() { return this.messagingMessageConverter; } @Override public void onMessage(io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message amqpMessage, Channel channel) throws Exception { Message message = toMessagingMessage(amqpMessage); if (logger.isDebugEnabled()) { logger.debug("Processing [" + message + "]"); } Object result = invokeHandler(amqpMessage, channel, message); if (result != null) { handleResult(result, amqpMessage, channel, message); } else { logger.trace("No result object given - no result to handle"); } } protected Message toMessagingMessage(io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message amqpMessage) { return (Message) getMessagingMessageConverter().fromMessage(amqpMessage); } /** * Invoke the handler, wrapping any exception to a {@link ListenerExecutionFailedException} * with a dedicated error message. */ private Object invokeHandler(io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message amqpMessage, Channel channel, Message message) { try { return this.handlerMethod.invoke(message, amqpMessage, channel); } catch (io.bitsensor.plugins.shaded.org.springframework.messaging.converter.MessageConversionException ex) { throw new ListenerExecutionFailedException(createMessagingErrorMessage("Listener method could not " + "be invoked with the incoming message", message.getPayload()), new MessageConversionException("Cannot handle message", ex), amqpMessage); } catch (MessagingException ex) { throw new ListenerExecutionFailedException(createMessagingErrorMessage("Listener method could not " + "be invoked with the incoming message", message.getPayload()), ex, amqpMessage); } catch (Exception ex) { throw new ListenerExecutionFailedException("Listener method '" + this.handlerMethod.getMethodAsString(message.getPayload()) + "' threw exception", ex, amqpMessage); } } private String createMessagingErrorMessage(String description, Object payload) { return description + "\n" + "Endpoint handler details:\n" + "Method [" + this.handlerMethod.getMethodAsString(payload) + "]\n" + "Bean [" + this.handlerMethod.getBean() + "]"; } /** * Build a Rabbit message to be sent as response based on the given result object. * @param channel the Rabbit Channel to operate on * @param result the content of the message, as returned from the listener method * @return the Rabbit Message (never null) * @throws Exception if thrown by Rabbit API methods * @see #setMessageConverter */ @Override protected io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message buildMessage(Channel channel, Object result) throws Exception { MessageConverter converter = getMessageConverter(); if (converter != null && !(result instanceof io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message)) { if (result instanceof io.bitsensor.plugins.shaded.org.springframework.messaging.Message) { return this.messagingMessageConverter.toMessage(result, new MessageProperties()); } else { return converter.toMessage(result, new MessageProperties()); } } else { if (!(result instanceof io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message)) { throw new MessageConversionException("No MessageConverter specified - cannot handle message [" + result + "]"); } return (io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message) result; } } /** * Delegates payload extraction to * {@link #extractMessage(io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message message)} * to enforce backward compatibility. Uses this listener adapter's converter instead of * the one configured in the converter adapter. * If the inbound message has no type information and the configured message converter * supports it, we attempt to infer the conversion type from the method signature. */ private final class MessagingMessageConverterAdapter extends MessagingMessageConverter { private final Object bean; private final Method method; private final Type inferredArgumentType; private MessagingMessageConverterAdapter(Object bean, Method method) { this.bean = bean; this.method = method; this.inferredArgumentType = determineInferredType(); if (logger.isDebugEnabled() && this.inferredArgumentType != null) { logger.debug("Inferred argument type for " + method.toString() + " is " + this.inferredArgumentType); } } @Override protected Object extractPayload(io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message message) { MessageProperties messageProperties = message.getMessageProperties(); if (this.bean != null) { messageProperties.setTargetBean(this.bean); } if (this.method != null) { messageProperties.setTargetMethod(this.method); if (this.inferredArgumentType != null) { messageProperties.setInferredArgumentType(this.inferredArgumentType); } } return extractMessage(message); } private Type determineInferredType() { if (this.method == null) { return null; } Type genericParameterType = null; for (int i = 0; i < this.method.getParameterTypes().length; i++) { MethodParameter methodParameter = new MethodParameter(this.method, i); /* * We're looking for a single non-annotated parameter, or one annotated with @Payload. * We ignore parameters with type Message because they are not involved with conversion. */ if (isEligibleParameter(methodParameter) && (methodParameter.getParameterAnnotations().length == 0 || methodParameter.hasParameterAnnotation(Payload.class))) { if (genericParameterType == null) { genericParameterType = methodParameter.getGenericParameterType(); if (genericParameterType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) genericParameterType; if (parameterizedType.getRawType().equals(Message.class)) { genericParameterType = ((ParameterizedType) genericParameterType) .getActualTypeArguments()[0]; } } } else { if (MessagingMessageListenerAdapter.this.logger.isDebugEnabled()) { MessagingMessageListenerAdapter.this.logger .debug("Ambiguous parameters for target payload for method " + this.method + "; no inferred type header added"); } return null; } } } return genericParameterType; } /* * Don't consider parameter types that are available after conversion. * Message, Message and Channel. */ private boolean isEligibleParameter(MethodParameter methodParameter) { Type parameterType = methodParameter.getGenericParameterType(); if (parameterType.equals(Channel.class) || parameterType.equals(io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.core.Message.class)) { return false; } if (parameterType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) parameterType; if (parameterizedType.getRawType().equals(Message.class)) { return !(parameterizedType.getActualTypeArguments()[0] instanceof WildcardType); } } return !parameterType.equals(Message.class); // could be Message without a generic type } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy