Spring Integration: MQTT integration test basics - spring

I try to test a simple MQTT listener created with Spring Boot and Spring Integration, but don't get it working. I've tried many approaches. The most promising was:
#RunWith(SpringRunner.class)
#SpringBootTest
public class BasicMqttTest {
#Value("${mqtt.client.id}")
private String mqttClientId;
#Value("${mqtt.state.topic}")
private String mqttTopic;
#Autowired
MqttPahoClientFactory mqttPahoClientFactory;
protected IMqttClient client;
#Before
public void setUp() throws Exception {
client = mqttPahoClientFactory.getClientInstance(mqttPahoClientFactory.getConnectionOptions().getServerURIs()[0], mqttClientId);
client.connect();
}
#After
public void tearDown() throws Exception {
client.disconnect();
client.close();
}
#Test
public void contextLoads() throws Exception {
MqttMessage mqttMessage = new MqttMessage();
mqttMessage.setPayload("MQTT!".getBytes());
client.publish(mqttTopic, mqttMessage);
}
}
However, the test runs with
2018-07-12 16:53:50.937 ERROR 21160 --- [T Rec: consumer] .m.i.MqttPahoMessageDrivenChannelAdapter : Lost connection: Verbindung wurde getrennt; retrying...
, and I don't see anything printed out.
The code is mostly from: https://github.com/spring-projects/spring-integration-samples/tree/master/basic/mqtt
. The example works nicely, but I need to be able to write proper integration tests.
The configuration is:
#Value("${mqtt.server.uri}")
private String mqttServerUri;
#Value("${mqtt.username}")
private String mqttUsername;
#Value("${mqtt.password}")
private String mqttPassword;
#Value("${mqtt.client.id}")
private String mqttClientId;
#Value("${mqtt.state.topic}")
private String mqttTopic;
#Value("${mqtt.completion.timeout}")
private Integer mqttCompletionTimeout;
#Value("${mqtt.quality.of.service}")
private Integer mqttQualityOfService;
#Bean
public MqttPahoClientFactory mqttClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
MqttConnectOptions options = new MqttConnectOptions();
options.setServerURIs(new String[]{mqttServerUri});
options.setUserName(mqttUsername);
options.setPassword(mqttPassword.toCharArray());
factory.setConnectionOptions(options);
return factory;
}
#Bean
#Qualifier("MqttInboundChannel")
public MessageProducerSupport mqttInbound() {
MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(
mqttClientId,
mqttClientFactory(),
mqttTopic
);
adapter.setCompletionTimeout(mqttCompletionTimeout);
adapter.setConverter(new DefaultPahoMessageConverter());
adapter.setQos(mqttQualityOfService);
return adapter;
}
#Bean
public IntegrationFlow myMqttInFlow() {
return IntegrationFlows.from(mqttInbound)
.handle(message -> {
System.out.println(message);
}).get();
}
UPDATE:
Didn't work either:
#Autowired
protected MessageHandler mqttOutbound;
#Test
public void test0() throws Exception {
mqttOutbound.handleMessage(MessageBuilder.withPayload("test").build());
}
#SpringBootApplication
static class MqttSourceApplication {
#Autowired
private MqttPahoClientFactory mqttClientFactory;
#Bean
public MessageHandler mqttOutbound() {
MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler("test", mqttClientFactory);
messageHandler.setAsync(true);
messageHandler.setDefaultTopic("test");
messageHandler.setConverter(pahoMessageConverter());
return messageHandler;
}
#Bean
public DefaultPahoMessageConverter pahoMessageConverter() {
DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter(1, false, "UTF-8");
return converter;
}
}
UPDATE
Even simpler ... same error:
#Autowired
MqttPahoClientFactory mqttPahoClientFactory;
private MessageHandler mqttOutbound;
#Before
public void setUp() throws Exception {
MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(mqttClientId, mqttPahoClientFactory);
messageHandler.setAsync(false);
messageHandler.setDefaultTopic(mqttTopic);
messageHandler.setConverter(new DefaultPahoMessageConverter());
mqttOutbound = messageHandler;
}
#Test
public void test0() throws Exception {
mqttOutbound.handleMessage(MessageBuilder.withPayload("test").build());
Thread.sleep(10000L);
}

Ok, resolved: Paho apparently closed my connection since both the test and main used the same client id. The solution was to replace the clientId with MqttAsyncClient.generateClientId() as suggested here: https://stackoverflow.com/a/48232793/2739681

Related

How to use error-channel for catching exception in Spring Integration?

What I am trying to do? : I am new to Spring Integration and already have read many similar questions regarding error handling but I don't understand how to catch exceptions using error-channel?
What I have done so far:
#EnableIntegration
#IntegrationComponentScan
#Configuration
public class TcpClientConfig implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
private final ConnectionProperty connectionProperty;
#Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
TcpClientConfig(ConnectionProperty connectionProperty) {
this.connectionProperty = connectionProperty;
}
#Bean
public AbstractClientConnectionFactory clientConnectionFactory() {
TcpNioClientConnectionFactory tcpNioClientConnectionFactory =
getTcpNioClientConnectionFactoryOf(
connectionProperty.getPrimaryHSMServerIpAddress(),
connectionProperty.getPrimaryHSMServerPort());
final List<AbstractClientConnectionFactory> fallBackConnections = getFallBackConnections();
fallBackConnections.add(tcpNioClientConnectionFactory);
final FailoverClientConnectionFactory failoverClientConnectionFactory =
new FailoverClientConnectionFactory(fallBackConnections);
return new CachingClientConnectionFactory(
failoverClientConnectionFactory, connectionProperty.getConnectionPoolSize());
}
#Bean
DefaultTcpNioSSLConnectionSupport connectionSupport() {
final DefaultTcpSSLContextSupport defaultTcpSSLContextSupport =
new DefaultTcpSSLContextSupport(
connectionProperty.getKeystorePath(),
connectionProperty.getTrustStorePath(),
connectionProperty.getKeystorePassword(),
connectionProperty.getTruststorePassword());
final String protocol = "TLSv1.2";
defaultTcpSSLContextSupport.setProtocol(protocol);
return new DefaultTcpNioSSLConnectionSupport(defaultTcpSSLContextSupport, false);
}
#Bean
public MessageChannel outboundChannel() {
return new DirectChannel();
}
#Bean
#ServiceActivator(inputChannel = "outboundChannel")
public MessageHandler outboundGateway(AbstractClientConnectionFactory clientConnectionFactory) {
TcpOutboundGateway tcpOutboundGateway = new TcpOutboundGateway();
tcpOutboundGateway.setConnectionFactory(clientConnectionFactory);
return tcpOutboundGateway;
}
#Bean
#ServiceActivator(inputChannel = "error-channel")
public void handleError(ErrorMessage em) {
throw new RuntimeException(String.valueOf(em));
}
private List<AbstractClientConnectionFactory> getFallBackConnections() {
final int size = connectionProperty.getAdditionalHSMServersConfig().size();
List<AbstractClientConnectionFactory> collector = new ArrayList<>(size);
for (final Map.Entry<String, Integer> server :
connectionProperty.getAdditionalHSMServersConfig().entrySet()) {
collector.add(getTcpNioClientConnectionFactoryOf(server.getKey(), server.getValue()));
}
return collector;
}
private TcpNioClientConnectionFactory getTcpNioClientConnectionFactoryOf(
final String ipAddress, final int port) {
TcpNioClientConnectionFactory tcpNioClientConnectionFactory =
new TcpNioClientConnectionFactory(ipAddress, port);
tcpNioClientConnectionFactory.setUsingDirectBuffers(true);
tcpNioClientConnectionFactory.setDeserializer(new CustomDeserializer());
tcpNioClientConnectionFactory.setApplicationEventPublisher(applicationEventPublisher);
tcpNioClientConnectionFactory.setSoKeepAlive(true);
tcpNioClientConnectionFactory.setConnectTimeout(connectionProperty.getConnectionTimeout());
tcpNioClientConnectionFactory.setSoTcpNoDelay(true);
tcpNioClientConnectionFactory.setTcpNioConnectionSupport(connectionSupport());
return tcpNioClientConnectionFactory;
}
}
Gateway
#Component
#MessagingGateway(defaultRequestChannel = "outboundChannel",errorChannel ="error-channel" )
public interface TcpClientGateway {
String send(String message);
}
Also currently, I am facing
required a bean of type org.springframework.messaging.support.ErrorMessage that could not be found
I need some assistance!
Thanking you in advance,
EDIT
#AllArgsConstructor
#Service
public class AsyncNonBlockingClient implements Connector {
TcpClientGateway tcpClientGateway;
#Override
public String send(final String payload) {
return tcpClientGateway.send(payload);
}
}
See documentation about messaging annotation:
Your problem is here: https://docs.spring.io/spring-integration/docs/current/reference/html/configuration.html#annotations_on_beans
#Bean
#ServiceActivator(inputChannel = "error-channel")
public void handleError(ErrorMessage em) {
This is a plain POJO method, therefore it cannot be marked with a #Bean. You use a #Bean really for beans to expose. Then you decide if that has to be a #ServiceActivator or not. So, just remove #Bean from this method and your error-channel consumer should be OK.

I am not receiving WebSocket messages (SimpMessagingTemplate)

I am not able to get my WS working. I wrote this test and it is still failing when I use simpMessagingTemplate but when I use stompSession.send it works. Could anyone help me where I am making mistake?
The problem is NOT in the test PROBABLY, I am not able to make simpMessagingTemplate working in any service.
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ExtendWith(MockitoExtension.class)
public class WebSocketSpec {
#LocalServerPort
private Integer port;
#Autowired
private SimpMessagingTemplate simpMessagingTemplate;
private WebSocketStompClient webSocketStompClient;
#BeforeEach
public void initialize(){
webSocketStompClient = new WebSocketStompClient(new SockJsClient(List.of(new WebSocketTransport(new StandardWebSocketClient()))));
}
#Test #DisplayName("test subscription to /topic/plcs/connection-status")
void testSubscriptionToPlcConnectionEndpoint() throws Exception{
CountDownLatch latch = new CountDownLatch(1);
webSocketStompClient.setMessageConverter(new MappingJackson2MessageConverter());
StompSession stompSession = webSocketStompClient.connect("ws://localhost:" + port+"/api/ws", new StompSessionHandlerAdapter() {
}).get(1, TimeUnit.SECONDS);
stompSession.subscribe("/topic/plcs/connection-status", new StompFrameHandler() {
#Override
public Type getPayloadType(StompHeaders stompHeaders) {
return String.class;
}
#Override
public void handleFrame(StompHeaders stompHeaders, Object o) {
latch.countDown();
System.out.println("RECEIVED: "+o);
}
});
//stompSession.send("/topic/plcs/connection-status", "SENT FROM TEST!!!");
simpMessagingTemplate.convertAndSend("/topic/plcs/connection-status", "SENT FROM TEST!!!");
if (!latch.await(5, TimeUnit.SECONDS)){
fail("Message not received");
}
}
}
My configuration for WS looks like this:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue", "/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
}
So, there are actually two problems ...
first is that you are using wrong messageConvertor (new MappingJackson2MessageConverter() instead of new StringMessageConverter())
the simpMessagingTemplate.convertAndSend("/topic/plcs/connection-status", "SENT FROM TEST!!!"); is fired before the client is subscribed, I have just tried to put there some delay before it with Thread.sleep(500); and it worked.

How to configure spring integration adapters of a merely connecting client and a server sending messages

I'm trying to implement the following scenario using Spring Integration:
I need a client to connect to a server via TCP IP and wait to receive messages within 30 seconds.
I need a server to send 0 to n messages to the client which had connected.
I need a way to start and stop channel transfer without loss of messages.
I need to change the port the server is listening between stop and start.
This is my config so far:
#Configuration
public class TcpConfiguration {
private static Logger LOG = LoggerFactory.getLogger(TcpConfiguration.class);
#Value("${port}")
private Integer port;
#Value("${so-timeout}")
private Integer soTimeout;
#Value("${keep-alive}")
private Boolean keepAlive;
#Value("${send-timeout}")
private Integer sendTimeout;
#Bean
public AbstractServerConnectionFactory getMyConnFactory() {
LOG.debug("getMyConnFactory");
TcpNetServerConnectionFactory factory = new TcpNetServerConnectionFactory(port);
LOG.debug("getMyConnFactory port={}", port);
factory.setSoTimeout(soTimeout);
LOG.debug("getMyConnFactory soTimeout={}", soTimeout);
factory.setSoKeepAlive(true);
LOG.debug("getMyConnFactory keepAlive={}", keepAlive);
return factory;
}
#Bean
public AbstractEndpoint getMyChannelAdapter() {
LOG.debug("getMyChannelAdapter");
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
adapter.setConnectionFactory(getMyConnFactory());
adapter.setOutputChannel(myChannelIn());
adapter.setSendTimeout(sendTimeout);
LOG.debug("getMyChannelAdapter adapter={}", adapter.getClass().getName());
return adapter;
}
#Bean
public MessageChannel myChannelIn() {
LOG.debug("myChannelIn");
return new DirectChannel();
}
#Bean
#Transformer(inputChannel = "myChannelIn", outputChannel = "myServiceChannel")
public ObjectToStringTransformer myTransformer() {
LOG.debug("myTransformer");
return new ObjectToStringTransformer();
}
#ServiceActivator(inputChannel = "myServiceChannel")
public void service(String in) {
LOG.debug("service received={}", in);
}
#Bean
public MessageChannel myChannelOut() {
LOG.debug("myChannelOut");
return new DirectChannel();
}
#Bean
public IntegrationFlow myOutbound() {
LOG.debug("myOutbound");
return IntegrationFlows.from(myChannelOut())
.handle(mySender())
.get();
}
#Bean
public MessageHandler mySender() {
LOG.debug("mySender");
TcpSendingMessageHandler tcpSendingMessageHandler = new TcpSendingMessageHandler();
tcpSendingMessageHandler.setConnectionFactory(getMyConnFactory());
return tcpSendingMessageHandler;
}
}
Please advice!
To change the server port I would shutdown the application context and restart it after configuring the new port in a remote configuration server.
Can I just close the application context without corrupting the current message transfer?
I don't know how to handle the connect-only client thing.
Use dynamic flow registration; just get the connection to open it without sending.
#SpringBootApplication
public class So62867670Application {
public static void main(String[] args) {
SpringApplication.run(So62867670Application.class, args);
}
#Bean
public ApplicationRunner runner(DynamicTcpReceiver receiver) {
return args -> { // Just a demo to show starting/stopping
receiver.connectAndListen(1234);
System.in.read();
receiver.stop();
System.in.read();
receiver.connectAndListen(1235);
System.in.read();
receiver.stop();
};
}
}
#Component
class DynamicTcpReceiver {
#Autowired
private IntegrationFlowContext context;
private IntegrationFlowRegistration registration;
public void connectAndListen(int port) throws InterruptedException {
TcpClientConnectionFactorySpec client = Tcp.netClient("localhost", port)
.deserializer(TcpCodecs.lf());
IntegrationFlow flow = IntegrationFlows.from(Tcp.inboundAdapter(client))
.transform(Transformers.objectToString())
.handle(System.out::println)
.get();
this.registration = context.registration(flow).register();
client.get().getConnection(); // just open the single shared connection
}
public void stop() {
if (this.registration != null) {
this.registration.destroy();
this.registration = null;
}
}
}
EDIT
And this is the server side...
#SpringBootApplication
#EnableScheduling
public class So62867670ServerApplication {
public static void main(String[] args) {
SpringApplication.run(So62867670ServerApplication.class, args);
}
#Bean
public ApplicationRunner runner(DynamicTcpServer receiver) {
return args -> { // Just a demo to show starting/stopping
receiver.tcpListen(1234);
System.in.read();
receiver.stop(1234);
System.in.read();
receiver.tcpListen(1235);
System.in.read();
receiver.stop(1235);
};
}
}
#Component
class DynamicTcpServer {
private static final Logger LOG = LoggerFactory.getLogger(DynamicTcpServer.class);
#Autowired
private IntegrationFlowContext flowContext;
#Autowired
private ApplicationContext appContext;
private final Map<Integer, IntegrationFlowRegistration> registrations = new HashMap<>();
private final Map<String, Entry<Integer, AtomicInteger>> clients = new ConcurrentHashMap<>();
public void tcpListen(int port) {
TcpServerConnectionFactorySpec server = Tcp.netServer(port)
.id("server-" + port)
.serializer(TcpCodecs.lf());
server.get().registerListener(msg -> false); // dummy listener so the accept thread doesn't exit
IntegrationFlow flow = f -> f.handle(Tcp.outboundAdapter(server));
this.registrations.put(port, flowContext.registration(flow).register());
}
public void stop(int port) {
IntegrationFlowRegistration registration = this.registrations.remove(port);
if (registration != null) {
registration.destroy();
}
}
#EventListener
public void closed(TcpConnectionOpenEvent event) {
LOG.info(event.toString());
String connectionId = event.getConnectionId();
String[] split = connectionId.split(":");
int port = Integer.parseInt(split[2]);
this.clients.put(connectionId, new AbstractMap.SimpleEntry<>(port, new AtomicInteger()));
}
#EventListener
public void closed(TcpConnectionCloseEvent event) {
LOG.info(event.toString());
this.clients.remove(event.getConnectionId());
}
#EventListener
public void listening(TcpConnectionServerListeningEvent event) {
LOG.info(event.toString());
}
#Scheduled(fixedDelay = 5000)
public void sender() {
this.clients.forEach((connectionId, portAndCount) -> {
IntegrationFlowRegistration registration = this.registrations.get(portAndCount.getKey());
if (registration != null) {
LOG.info("Sending to " + connectionId);
registration.getMessagingTemplate().send(MessageBuilder.withPayload("foo")
.setHeader(IpHeaders.CONNECTION_ID, connectionId).build());
if (portAndCount.getValue().incrementAndGet() > 9) {
this.appContext.getBean("server-" + portAndCount.getKey(), TcpNetServerConnectionFactory.class)
.closeConnection(connectionId);
}
}
});
}
}

How to copy a file from ftp server to local directory using sftp and spring boot,Java

I have codes for Inbound and Outbound channel adapter over SFTP. I want to call those method via spring boot scheduler not using polling. Looking for example how to call resultFileHandler() method
public class SftpConfig {
#Value("${nodephone.directory.sftp.host}")
private String sftpHost;
#Value("${nodephone.directory.sftp.port}")
private int sftpPort;
#Value("${nodephone.directory.sftp.user}")
private String sftpUser;
#Value("${nodephone.directory.sftp.password}")
private String sftpPasword;
#Value("${nodephone.directory.sftp.remote.directory.download}")
private String sftpRemoteDirectoryDownload;
#Value("${nodephone.directory.sftp.remote.directory.upload}")
private String sftpRemoteDirectoryUpload;
#Value("${nodephone.directory.sftp.remote.directory.filter}")
private String sftpRemoteDirectoryFilter;
#Value("${nodephone.directory.sftp.remote.directory.localDirectory}")
private String sftpLocalDirectory;
// private FtpOrderRequestHandler handler;
#Bean
public SessionFactory<LsEntry> sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost(sftpHost);
factory.setPort(sftpPort);
factory.setUser(sftpUser);
factory.setPassword(sftpPasword);
factory.setAllowUnknownKeys(true);
return new CachingSessionFactory<LsEntry>(factory);
}
#Bean
public SftpInboundFileSynchronizer sftpInboundFileSynchronizer() {
SftpInboundFileSynchronizer fileSynchronizer = new SftpInboundFileSynchronizer(sftpSessionFactory());
fileSynchronizer.setDeleteRemoteFiles(true);
fileSynchronizer.setRemoteDirectory(sftpRemoteDirectoryDownload);
fileSynchronizer.setFilter(new SftpSimplePatternFileListFilter(sftpRemoteDirectoryFilter));
return fileSynchronizer;
}
#Bean
#InboundChannelAdapter(channel = "fromSftpChannel", poller = #Poller(cron = "0/5 * * * * *"))
public MessageSource<File> sftpMessageSource() {
SftpInboundFileSynchronizingMessageSource source = new SftpInboundFileSynchronizingMessageSource(
sftpInboundFileSynchronizer());
source.setAutoCreateLocalDirectory(true);
source.setLocalFilter(new AcceptOnceFileListFilter<File>());
source.setLocalDirectory(new File("/local"));
return source;
}
#Bean
#ServiceActivator(inputChannel = "fromSftpChannel")
public MessageHandler resultFileHandler() {
return new MessageHandler() {
#Override
public void handleMessage(Message<?> message) throws MessagingException {
System.out.println("********************** " + message.getPayload());
}
};
}
I have tested with Configuration annotation and it reads the file from the server, but I want to run this from Cron instead of polling, how do I call the method resultFileHandler()
I've never done this using Spring Integration in any production code although I did something like below, to download files from remote servers using sftp/ftp.
I'm only using the SftpOutboundGateway (there could be better ways), to call the "mget" method and fetch the payload (file).
#Configuration
#ConfigurationProperties(prefix = "sftp")
#Setter
#Getter
#EnableIntegration
public class RemoteFileConfiguration {
private String clients;
private String hosts;
private int ports;
private String users;
private String passwords;
#Bean(name = "clientSessionFactory")
public SessionFactory<LsEntry> clientSessionFactory() {
DefaultSftpSessionFactory sf = new DefaultSftpSessionFactory();
sf.setHost(hosts);
sf.setPort(ports);
sf.setUser(users);
sf.setPassword(passwords);
sf.setAllowUnknownKeys(true);
return new CachingSessionFactory<>(sf);
}
#Bean
#ServiceActivator(inputChannel = "sftpChannel")
public MessageHandler clientMessageHandler() {
SftpOutboundGateway sftpOutboundGateway = new SftpOutboundGateway(
clientSessionFactory(), "mget", "payload");
sftpOutboundGateway.setAutoCreateLocalDirectory(true);
sftpOutboundGateway.setLocalDirectory(new File("/users/localPath/client/INPUT/"));
sftpOutboundGateway.setFileExistsMode(FileExistsMode.REPLACE_IF_MODIFIED);
sftpOutboundGateway.setFilter(new AcceptOnceFileListFilter<>());
return sftpOutboundGateway;
}
}
#MessagingGateway
public interface SFTPGateway {
#Gateway(requestChannel = "sftpChannel")
List<File> get(String dir);
}
To ensure we use cron to execute this, I have used a Tasklet which is executed by Spring Batch, when I need it to be using a cron expression.
#Slf4j
#Getter
#Setter
public class RemoteFileInboundTasklet implements Tasklet {
private RemoteFileTemplate remoteFileTemplate;
private String remoteClientDir;
private String clientName;
private SFTPGateway sftpGateway;
#Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext)
throws Exception {
List<File> files = sftpGateway.get(remoteClientDir);
if (CollectionUtils.isEmpty(files)) {
log.warn("No file was downloaded for client {}.", clientName);
return RepeatStatus.FINISHED;
}
log.info("Total file: {}", files.size());
return RepeatStatus.FINISHED;
}
}
NOTE: If you don't want to use Batch's Tasklet, you can use your #Component class and inject the Gateway to call "get" method.
#Autowired
private SFTPGateway sftpGateway;

Springboot RabbitMq Consumer consuming only at first time.please help me to get the configurations right and how can configure multiple listners

Springboot RabbitMq Consumer consuming only at first time.please help me to get the configurations right and how can configure multiple listners.I am developing an Automated Mapping solution for which i Execute various jobs .and in a need to put those jobs in queue
Here's my application class:Application.java
#SpringBootApplication
#ComponentScan(basePackages = { "com.fractal.sago", "com.fractal.grpc" })
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
RabbitMqConfig class:
#Configuration
public class RabbitMqConfig {
public final static String JOB_QUEUE_NAME = "jobQueue";
public final static String JOB_EXCHANGE_NAME = "jobExchange";
#Bean
Queue jobQueue() {
return new Queue(JOB_QUEUE_NAME, true);
}
#Bean
DirectExchange jobExchange() {
return new DirectExchange(JOB_EXCHANGE_NAME);
}
#Bean
Binding jobBinding(DirectExchange directExchange) {
return BindingBuilder.bind(jobQueue()).to(jobExchange()).with(jobQueue().getName());
}
#Bean
SimpleMessageListenerContainer jobQueueContainer(ConnectionFactory connectionFactory,
MessageListenerAdapter joblistenerAdapter) {
SimpleMessageListenerContainer jobQueueContainer = new SimpleMessageListenerContainer();
jobQueueContainer.setConnectionFactory(connectionFactory);
jobQueueContainer.setQueueNames(JOB_QUEUE_NAME);
jobQueueContainer.setMessageListener(joblistenerAdapter);
return jobQueueContainer;
}
#Bean
MessageListenerAdapter joblistenerAdapter(JobQueueConsumer messageReceiver) {
MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(messageReceiver, "receiveMessage");
messageListenerAdapter.setMessageConverter(producerJackson2MessageConverter());
return messageListenerAdapter;
}
#Bean
public Jackson2JsonMessageConverter producerJackson2MessageConverter() {
return new Jackson2JsonMessageConverter();
}
}
producer : JobProducer
#Component
public class JobQueueProducer {
#Autowired
RabbitTemplate rabbitTemplate;
public void sendMessage(String message) {
Message messageToSend = MessageBuilder.withBody(message.getBytes())
.setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();
rabbitTemplate.convertAndSend(RabbitMqConfig.JOB_EXCHANGE_NAME, RabbitMqConfig.JOB_QUEUE_NAME, messageToSend);
//rabbitTemplate.convertAndSend(RabbitMqConfig.JOB_QUEUE_NAME, messageToSend);
}
}
Consumer :JobQueueConsumer
enter code here
#Component
public class JobQueueConsumer implements MessageListener {
#Autowired
SagoAlgo sagoAlgo;
#Autowired
CCDMappingService ccdMappingService;
#RabbitListener(queues = { RabbitMqConfig.JOB_QUEUE_NAME })
public void receiveMessage(Message message) throws SQLException {
System.out.println("Received Message: " + new String(message.getBody()));
Integer jobId = Integer.parseInt(new String(message.getBody()));
System.out.println(jobId);
CCDMappingVO ccdVo =ccdMappingService.fetchCCDWithCategoriesById(jobId);
sagoAlgo.execAlgo(ccdVo); //my Algo to be executed
}
//when I implement MessageListener default method to be executed
public void onMessage(Message message) {
// System.out.println("Received Message: " + new
// String(message.getBody()));
}
}

Resources