use of org.springframework.messaging.Message in project spring-integration by spring-projects.
the class MessagingMethodInvokerHelper method findHandlerMethodsForTarget.
private Map<String, Map<Class<?>, HandlerMethod>> findHandlerMethodsForTarget(final Object targetObject, final Class<? extends Annotation> annotationType, final String methodName, final boolean requiresReply) {
Map<String, Map<Class<?>, HandlerMethod>> handlerMethods = new HashMap<>();
final Map<Class<?>, HandlerMethod> candidateMethods = new HashMap<>();
final Map<Class<?>, HandlerMethod> candidateMessageMethods = new HashMap<>();
final Map<Class<?>, HandlerMethod> fallbackMethods = new HashMap<>();
final Map<Class<?>, HandlerMethod> fallbackMessageMethods = new HashMap<>();
final AtomicReference<Class<?>> ambiguousFallbackType = new AtomicReference<>();
final AtomicReference<Class<?>> ambiguousFallbackMessageGenericType = new AtomicReference<>();
final Class<?> targetClass = getTargetClass(targetObject);
MethodFilter methodFilter = new UniqueMethodFilter(targetClass);
ReflectionUtils.doWithMethods(targetClass, method1 -> {
boolean matchesAnnotation = false;
if (method1.isBridge()) {
return;
}
if (isMethodDefinedOnObjectClass(method1)) {
return;
}
if (method1.getDeclaringClass().equals(Proxy.class)) {
return;
}
if (annotationType != null && AnnotationUtils.findAnnotation(method1, annotationType) != null) {
matchesAnnotation = true;
} else if (!Modifier.isPublic(method1.getModifiers())) {
return;
}
if (requiresReply && void.class.equals(method1.getReturnType())) {
return;
}
if (methodName != null && !methodName.equals(method1.getName())) {
return;
}
if (methodName == null && ObjectUtils.containsElement(new String[] { "start", "stop", "isRunning" }, method1.getName())) {
return;
}
HandlerMethod handlerMethod1;
try {
method1 = AopUtils.selectInvocableMethod(method1, org.springframework.util.ClassUtils.getUserClass(targetObject));
InvocableHandlerMethod invocableHandlerMethod = this.messageHandlerMethodFactory.createInvocableHandlerMethod(targetObject, method1);
handlerMethod1 = new HandlerMethod(invocableHandlerMethod, this.canProcessMessageList);
checkSpelInvokerRequired(targetClass, method1, handlerMethod1);
} catch (IneligibleMethodException e) {
if (logger.isDebugEnabled()) {
logger.debug("Method [" + method1 + "] is not eligible for Message handling " + e.getMessage() + ".");
}
return;
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("Method [" + method1 + "] is not eligible for Message handling.", e);
}
return;
}
if (AnnotationUtils.getAnnotation(method1, Default.class) != null) {
Assert.state(this.defaultHandlerMethod == null, () -> "Only one method can be @Default, but there are more for: " + targetObject);
this.defaultHandlerMethod = handlerMethod1;
}
Class<?> targetParameterType = handlerMethod1.getTargetParameterType();
if (matchesAnnotation || annotationType == null) {
if (handlerMethod1.isMessageMethod()) {
if (candidateMessageMethods.containsKey(targetParameterType)) {
throw new IllegalArgumentException("Found more than one method match for type " + "[Message<" + targetParameterType + ">]");
}
candidateMessageMethods.put(targetParameterType, handlerMethod1);
} else {
if (candidateMethods.containsKey(targetParameterType)) {
String exceptionMessage = "Found more than one method match for ";
if (Void.class.equals(targetParameterType)) {
exceptionMessage += "empty parameter for 'payload'";
} else {
exceptionMessage += "type [" + targetParameterType + "]";
}
throw new IllegalArgumentException(exceptionMessage);
}
candidateMethods.put(targetParameterType, handlerMethod1);
}
} else {
if (handlerMethod1.isMessageMethod()) {
if (fallbackMessageMethods.containsKey(targetParameterType)) {
// we need to check for duplicate type matches,
// but only if we end up falling back
// and we'll only keep track of the first one
ambiguousFallbackMessageGenericType.compareAndSet(null, targetParameterType);
}
fallbackMessageMethods.put(targetParameterType, handlerMethod1);
} else {
if (fallbackMethods.containsKey(targetParameterType)) {
// we need to check for duplicate type matches,
// but only if we end up falling back
// and we'll only keep track of the first one
ambiguousFallbackType.compareAndSet(null, targetParameterType);
}
fallbackMethods.put(targetParameterType, handlerMethod1);
}
}
}, methodFilter);
if (candidateMethods.isEmpty() && candidateMessageMethods.isEmpty() && fallbackMethods.isEmpty() && fallbackMessageMethods.isEmpty()) {
findSingleSpecifMethodOnInterfacesIfProxy(targetObject, methodName, candidateMessageMethods, candidateMethods);
}
if (!candidateMethods.isEmpty() || !candidateMessageMethods.isEmpty()) {
handlerMethods.put(CANDIDATE_METHODS, candidateMethods);
handlerMethods.put(CANDIDATE_MESSAGE_METHODS, candidateMessageMethods);
return handlerMethods;
}
if ((ambiguousFallbackType.get() != null || ambiguousFallbackMessageGenericType.get() != null) && ServiceActivator.class.equals(annotationType)) {
/*
* When there are ambiguous fallback methods,
* a Service Activator can finally fallback to RequestReplyExchanger.exchange(m).
* Ambiguous means > 1 method that takes the same payload type, or > 1 method
* that takes a Message with the same generic type.
*/
List<Method> frameworkMethods = new ArrayList<>();
Class<?>[] allInterfaces = org.springframework.util.ClassUtils.getAllInterfacesForClass(targetClass);
for (Class<?> iface : allInterfaces) {
try {
if ("org.springframework.integration.gateway.RequestReplyExchanger".equals(iface.getName())) {
frameworkMethods.add(targetClass.getMethod("exchange", Message.class));
if (logger.isDebugEnabled()) {
logger.debug(targetObject.getClass() + ": Ambiguous fallback methods; using RequestReplyExchanger.exchange()");
}
}
} catch (Exception e) {
// should never happen (but would fall through to errors below)
}
}
if (frameworkMethods.size() == 1) {
Method method = org.springframework.util.ClassUtils.getMostSpecificMethod(frameworkMethods.get(0), targetObject.getClass());
InvocableHandlerMethod invocableHandlerMethod = this.messageHandlerMethodFactory.createInvocableHandlerMethod(targetObject, method);
HandlerMethod handlerMethod = new HandlerMethod(invocableHandlerMethod, this.canProcessMessageList);
checkSpelInvokerRequired(targetClass, method, handlerMethod);
handlerMethods.put(CANDIDATE_METHODS, Collections.singletonMap(Object.class, handlerMethod));
handlerMethods.put(CANDIDATE_MESSAGE_METHODS, candidateMessageMethods);
return handlerMethods;
}
}
Assert.state(!fallbackMethods.isEmpty() || !fallbackMessageMethods.isEmpty(), "Target object of type [" + this.targetObject.getClass() + "] has no eligible methods for handling Messages.");
Assert.isNull(ambiguousFallbackType.get(), "Found ambiguous parameter type [" + ambiguousFallbackType + "] for method match: " + fallbackMethods.values());
Assert.isNull(ambiguousFallbackMessageGenericType.get(), "Found ambiguous parameter type [" + ambiguousFallbackMessageGenericType + "] for method match: " + fallbackMethods.values());
handlerMethods.put(CANDIDATE_METHODS, fallbackMethods);
handlerMethods.put(CANDIDATE_MESSAGE_METHODS, fallbackMessageMethods);
return handlerMethods;
}
use of org.springframework.messaging.Message in project spring-integration by spring-projects.
the class AbstractRequestHandlerAdvice method invoke.
@Override
public final Object invoke(final MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
Object[] arguments = invocation.getArguments();
boolean isMessageMethod = (method.getName().equals("handleRequestMessage") || method.getName().equals("handleMessage")) && (arguments.length == 1 && arguments[0] instanceof Message);
Object invocationThis = invocation.getThis();
if (!isMessageMethod) {
boolean isMessageHandler = invocationThis != null && MessageHandler.class.isAssignableFrom(invocationThis.getClass());
if (!isMessageHandler && this.logger.isWarnEnabled()) {
String clazzName = invocationThis == null ? method.getDeclaringClass().getName() : invocationThis.getClass().getName();
this.logger.warn("This advice " + this.getClass().getName() + " can only be used for MessageHandlers; an attempt to advise method '" + method.getName() + "' in '" + clazzName + "' is ignored");
}
return invocation.proceed();
} else {
Message<?> message = (Message<?>) arguments[0];
try {
return doInvoke(new ExecutionCallback() {
@Override
public Object execute() throws Exception {
try {
return invocation.proceed();
} catch (Exception e) {
// NOSONAR - catch necessary so we can wrap Errors
throw e;
} catch (Throwable e) {
// NOSONAR - ok to catch; unwrapped and rethrown below
throw new ThrowableHolderException(e);
}
}
@Override
public Object cloneAndExecute() throws Exception {
try {
/*
* If we don't copy the invocation carefully it won't keep a reference to the other
* interceptors in the chain.
*/
if (invocation instanceof ProxyMethodInvocation) {
return ((ProxyMethodInvocation) invocation).invocableClone().proceed();
} else {
throw new IllegalStateException("MethodInvocation of the wrong type detected - this should not happen with Spring AOP," + " so please raise an issue if you see this exception");
}
} catch (Exception e) {
// NOSONAR - catch necessary so we can wrap Errors
throw e;
} catch (Throwable e) {
// NOSONAR - ok to catch; unwrapped and rethrown below
throw new ThrowableHolderException(e);
}
}
}, invocationThis, message);
} catch (Exception e) {
throw this.unwrapThrowableIfNecessary(e);
}
}
}
use of org.springframework.messaging.Message in project spring-integration by spring-projects.
the class ScatterGatherHandler method doInit.
@Override
protected void doInit() {
if (this.gatherChannel == null) {
this.gatherChannel = new FixedSubscriberChannel(this.gatherer);
} else {
if (this.gatherChannel instanceof SubscribableChannel) {
this.gatherEndpoint = new EventDrivenConsumer((SubscribableChannel) this.gatherChannel, this.gatherer);
} else if (this.gatherChannel instanceof PollableChannel) {
this.gatherEndpoint = new PollingConsumer((PollableChannel) this.gatherChannel, this.gatherer);
((PollingConsumer) this.gatherEndpoint).setReceiveTimeout(this.gatherTimeout);
} else {
throw new MessagingException("Unsupported 'replyChannel' type [" + this.gatherChannel.getClass() + "]." + "SubscribableChannel or PollableChannel type are supported.");
}
this.gatherEndpoint.setBeanFactory(this.getBeanFactory());
this.gatherEndpoint.afterPropertiesSet();
}
((MessageProducer) this.gatherer).setOutputChannel(new FixedSubscriberChannel(message -> {
MessageHeaders headers = message.getHeaders();
if (headers.containsKey(GATHER_RESULT_CHANNEL)) {
Object gatherResultChannel = headers.get(GATHER_RESULT_CHANNEL);
if (gatherResultChannel instanceof MessageChannel) {
messagingTemplate.send((MessageChannel) gatherResultChannel, message);
} else if (gatherResultChannel instanceof String) {
messagingTemplate.send((String) gatherResultChannel, message);
}
} else {
throw new MessageDeliveryException(message, "The 'gatherResultChannel' header is required to delivery gather result.");
}
}));
this.replyChannelRegistry = getBeanFactory().getBean(IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME, HeaderChannelRegistry.class);
}
use of org.springframework.messaging.Message in project spring-integration by spring-projects.
the class AbstractMessageSplitter method handleRequestMessage.
@Override
@SuppressWarnings("unchecked")
protected final Object handleRequestMessage(Message<?> message) {
Object result = this.splitMessage(message);
// return null if 'null'
if (result == null) {
return null;
}
boolean reactive = getOutputChannel() instanceof ReactiveStreamsSubscribableChannel;
setAsync(reactive);
Iterator<Object> iterator = null;
Flux<Object> flux = null;
final int sequenceSize;
if (result instanceof Iterable<?>) {
Iterable<Object> iterable = (Iterable<Object>) result;
sequenceSize = obtainSizeIfPossible(iterable);
if (reactive) {
flux = Flux.fromIterable(iterable);
} else {
iterator = iterable.iterator();
}
} else if (result.getClass().isArray()) {
Object[] items = (Object[]) result;
sequenceSize = items.length;
if (reactive) {
flux = Flux.fromArray(items);
} else {
iterator = Arrays.asList(items).iterator();
}
} else if (result instanceof Iterator<?>) {
Iterator<Object> iter = (Iterator<Object>) result;
sequenceSize = obtainSizeIfPossible(iter);
if (reactive) {
flux = Flux.fromIterable(() -> iter);
} else {
iterator = iter;
}
} else if (result instanceof Stream<?>) {
Stream<Object> stream = ((Stream<Object>) result);
sequenceSize = 0;
if (reactive) {
flux = Flux.fromStream(stream);
} else {
iterator = stream.iterator();
}
} else if (result instanceof Publisher<?>) {
Publisher<Object> publisher = (Publisher<Object>) result;
sequenceSize = 0;
if (reactive) {
flux = Flux.from(publisher);
} else {
iterator = Flux.from((Publisher<Object>) result).toIterable().iterator();
}
} else {
sequenceSize = 1;
if (reactive) {
flux = Flux.just(result);
} else {
iterator = Collections.singleton(result).iterator();
}
}
if (iterator != null && !iterator.hasNext()) {
return null;
}
Map<String, Object> messageHeaders = message.getHeaders();
if (willAddHeaders(message)) {
messageHeaders = new HashMap<>(messageHeaders);
addHeaders(message, messageHeaders);
}
final Map<String, Object> headers = messageHeaders;
final Object correlationId = message.getHeaders().getId();
final AtomicInteger sequenceNumber = new AtomicInteger(1);
Function<Object, AbstractIntegrationMessageBuilder<?>> messageBuilderFunction = object -> createBuilder(object, headers, correlationId, sequenceNumber.getAndIncrement(), sequenceSize);
if (reactive) {
return flux.map(messageBuilderFunction);
} else {
return new FunctionIterator<>(iterator, messageBuilderFunction);
}
}
use of org.springframework.messaging.Message in project spring-integration by spring-projects.
the class MessageGroupQueue method drainTo.
@Override
public int drainTo(Collection<? super Message<?>> collection, int maxElements) {
Assert.notNull(collection, "'collection' must not be null");
int originalSize = collection.size();
ArrayList<Message<?>> list = new ArrayList<Message<?>>();
final Lock storeLock = this.storeLock;
try {
storeLock.lockInterruptibly();
try {
Message<?> message = this.messageGroupStore.pollMessageFromGroup(this.groupId);
for (int i = 0; i < maxElements && message != null; i++) {
list.add(message);
message = this.messageGroupStore.pollMessageFromGroup(this.groupId);
}
this.messageStoreNotFull.signal();
} finally {
storeLock.unlock();
}
} catch (InterruptedException e) {
this.logger.warn("Queue may not have drained completely since this operation was interrupted", e);
Thread.currentThread().interrupt();
}
collection.addAll(list);
return collection.size() - originalSize;
}
Aggregations