1 /*
2  * Copyright 2013-2019 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.cloud.aws.messaging.config;
18
19 import java.util.Arrays;
20 import java.util.List;
21
22 import com.amazonaws.services.sqs.AmazonSQS;
23 import com.amazonaws.services.sqs.AmazonSQSAsync;
24
25 import org.springframework.beans.factory.BeanFactory;
26 import org.springframework.cloud.aws.core.env.ResourceIdResolver;
27 import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
28 import org.springframework.cloud.aws.messaging.listener.QueueMessageHandler;
29 import org.springframework.cloud.aws.messaging.listener.SendToHandlerMethodReturnValueHandler;
30 import org.springframework.messaging.converter.MappingJackson2MessageConverter;
31 import org.springframework.messaging.converter.MessageConverter;
32 import org.springframework.messaging.core.DestinationResolvingMessageSendingOperations;
33 import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
34 import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
35 import org.springframework.util.CollectionUtils;
36
37 /**
38  * @author Alain Sahli
39  * @author Maciej Walkowiak
40  * @since 1.0
41  */

42 public class QueueMessageHandlerFactory {
43
44     private List<HandlerMethodArgumentResolver> argumentResolvers;
45
46     private List<HandlerMethodReturnValueHandler> returnValueHandlers;
47
48     private DestinationResolvingMessageSendingOperations<?> sendToMessagingTemplate;
49
50     private AmazonSQSAsync amazonSqs;
51
52     private ResourceIdResolver resourceIdResolver;
53
54     private BeanFactory beanFactory;
55
56     private List<MessageConverter> messageConverters;
57
58     public void setArgumentResolvers(
59             List<HandlerMethodArgumentResolver> argumentResolvers) {
60         this.argumentResolvers = argumentResolvers;
61     }
62
63     public void setReturnValueHandlers(
64             List<HandlerMethodReturnValueHandler> returnValueHandlers) {
65         this.returnValueHandlers = returnValueHandlers;
66     }
67
68     /**
69      * Configures the {@link DestinationResolvingMessageSendingOperations} template used
70      * by the {@link SendToHandlerMethodReturnValueHandler} to send return values of
71      * handler methods.
72      * @param sendToMessagingTemplate A
73      * {@link DestinationResolvingMessageSendingOperations} template for sending return
74      * values of handler methods.
75      */

76     public void setSendToMessagingTemplate(
77             DestinationResolvingMessageSendingOperations<?> sendToMessagingTemplate) {
78         this.sendToMessagingTemplate = sendToMessagingTemplate;
79     }
80
81     public AmazonSQS getAmazonSqs() {
82         return this.amazonSqs;
83     }
84
85     /**
86      * <p>
87      * Sets the {@link AmazonSQS} client that is going to be used to create a new
88      * {@link QueueMessagingTemplate} if {@code sendToMessagingTemplate} is {@code null}.
89      * This template is used by the {@link SendToHandlerMethodReturnValueHandler} to send
90      * the return values of handler methods annotated with
91      * {@link org.springframework.messaging.handler.annotation.SendTo}.
92      * </p>
93      * <p>
94      * An {@link AmazonSQS} client is only needed if {@code sendToMessagingTemplate} is
95      * {@code null}.
96      * </p>
97      * @param amazonSqs The {@link AmazonSQS} client that is going to be used by the
98      * {@link SendToHandlerMethodReturnValueHandler} to send messages.
99      */

100     public void setAmazonSqs(AmazonSQSAsync amazonSqs) {
101         this.amazonSqs = amazonSqs;
102     }
103
104     /**
105      * This value is only used if no {@code sendToMessagingTemplate} has been set.
106      * @param resourceIdResolver the resourceIdResolver to use for resolving logical to
107      * physical ids in a CloudFormation environment. This resolver will be used by the
108      * {@link QueueMessagingTemplate} created for the
109      * {@link SendToHandlerMethodReturnValueHandler}.
110      */

111     public void setResourceIdResolver(ResourceIdResolver resourceIdResolver) {
112         this.resourceIdResolver = resourceIdResolver;
113     }
114
115     /**
116      * Configures a {@link BeanFactory} that should be used to resolve expressions and
117      * placeholder for {@link org.springframework.messaging.handler.annotation.SendTo}
118      * annotations. If not set, then no expressions or place holders will be resolved.
119      * @param beanFactory - the bean factory used to resolve expressions and / or place
120      * holders
121      */

122     public void setBeanFactory(BeanFactory beanFactory) {
123         this.beanFactory = beanFactory;
124     }
125
126     public QueueMessageHandler createQueueMessageHandler() {
127         QueueMessageHandler queueMessageHandler = new QueueMessageHandler(
128                 CollectionUtils.isEmpty(this.messageConverters)
129                         ? Arrays.asList(getDefaultMappingJackson2MessageConverter())
130                         : this.messageConverters);
131
132         if (!CollectionUtils.isEmpty(this.argumentResolvers)) {
133             queueMessageHandler.getCustomArgumentResolvers()
134                     .addAll(this.argumentResolvers);
135         }
136         if (!CollectionUtils.isEmpty(this.returnValueHandlers)) {
137             queueMessageHandler.getCustomReturnValueHandlers()
138                     .addAll(this.returnValueHandlers);
139         }
140
141         SendToHandlerMethodReturnValueHandler sendToHandlerMethodReturnValueHandler;
142         if (this.sendToMessagingTemplate != null) {
143             sendToHandlerMethodReturnValueHandler = new SendToHandlerMethodReturnValueHandler(
144                     this.sendToMessagingTemplate);
145         }
146         else {
147             sendToHandlerMethodReturnValueHandler = new SendToHandlerMethodReturnValueHandler(
148                     getDefaultSendToQueueMessagingTemplate(this.amazonSqs,
149                             this.resourceIdResolver));
150
151         }
152         sendToHandlerMethodReturnValueHandler.setBeanFactory(this.beanFactory);
153         queueMessageHandler.getCustomReturnValueHandlers()
154                 .add(sendToHandlerMethodReturnValueHandler);
155
156         return queueMessageHandler;
157     }
158
159     private QueueMessagingTemplate getDefaultSendToQueueMessagingTemplate(
160             AmazonSQSAsync amazonSqs, ResourceIdResolver resourceIdResolver) {
161         return new QueueMessagingTemplate(amazonSqs, resourceIdResolver,
162                 getDefaultMappingJackson2MessageConverter());
163     }
164
165     public List<MessageConverter> getMessageConverters() {
166         return this.messageConverters;
167     }
168
169     /**
170      * Configures a {@link MessageConverter}s that should be used to deserialize incoming
171      * message payloads and serialize messages in {@link QueueMessagingTemplate}. If not
172      * set, default {@link MappingJackson2MessageConverter} is used.
173      * @param messageConverters - the converters used for message conversion
174      */

175     public void setMessageConverters(List<MessageConverter> messageConverters) {
176         this.messageConverters = messageConverters;
177     }
178
179     private MappingJackson2MessageConverter getDefaultMappingJackson2MessageConverter() {
180         MappingJackson2MessageConverter jacksonMessageConverter = new MappingJackson2MessageConverter();
181         jacksonMessageConverter.setSerializedPayloadClass(String.class);
182         jacksonMessageConverter.setStrictContentTypeMatch(true);
183         return jacksonMessageConverter;
184     }
185
186 }
187