Spring-Integration in Java Config - spring

I have to convert a project using Spring integration in xmls to Java config, and tried below, but I am getting exceptions.
What I am trying to achieve is, create a message listener which listens messages on a queue destination, puts it on to a channel, which is read and processed by a xsl transformer that puts in the next channel, which is again read and processed by JaxbUnmarshaller to create to Java object and put it the third channel, which will be consumed by a Java Consumer. In case of error, the message is put on a error channel which is again the same Java Consumer that handles it.
Below is the Spring config
<int:channel id="channel_1"/>
<int:channel id="channel_2"/>
<int:channel id="channel_3"/>
<int:channel id="channel_error"/>
<int-jms:message-driven-channel-adapter connection-factory="factory" destination-name="destName"
pub-sub-domain="false" channel="channel_1" error-channel="channel_error"/>
<int-xml:xslt-transformer input-channel="channel_1" output-channel="channel_2" xsl-resource="classpath:sample.xsl"/>
<int-xml:unmarshalling-transformer input-channel="channel_2" output-channel="channel_3" unmarshaller="unmarshaller"/>
<oxm:jaxb2-marshaller id="unmarshaller">
<oxm:class-to-be-bound name="sample.example.MyData"/>
</oxm:jaxb2-marshaller>
<int:outbound-channel-adapter channel="channel_3" ref="consumer" method="handleMessage"/>
<bean id="consumer" class="sample.example.MyConsumer"></bean>
<int:outbound-channel-adapter channel="channel_error" ref="consumer" method="handleError"/>
Below is the Java Config I have for this
#Bean
public MessageChannel channel_1() {
return new DirectChannel();
}
#Bean
public MessageChannel channel_2() {
return new DirectChannel();
}
#Bean
public MessageChannel channel_3() {
return new DirectChannel();
}
#Bean
public MessageChannel channel_error() {
return new DirectChannel();
}
#Bean
#Autowired
public DefaultMessageListenerContainer container(String destinationQueueName) {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(factory());
container.setDestinationName(destinationQueueName);
container.setPubSubDomain(false);
container.setMessageListener(messageListener());
return container;
}
#Bean
public ChannelPublishingJmsMessageListener messageListener(){
ChannelPublishingJmsMessageListener adapter = new ChannelPublishingJmsMessageListener();
adapter.setRequestChannel(channel_1());
adapter.setErrorChannel(channel_error());
return adapter;
}
#Bean
#Transformer(inputChannel = "channel_1", outputChannel = "channel_2")
public XsltPayloadTransformer transformer() {
return new XsltPayloadTransformer(new ClassPathResource("sample.xsl"));
}
#Bean
#Transformer(inputChannel = "channel_2", outputChannel = "channel_3")
public UnmarshallingTransformer unmarshallingTransformer() {
return new UnmarshallingTransformer(unmarshaller());
}
#Bean
public Jaxb2Marshaller unmarshaller() {
Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller();
unmarshaller.setClassesToBeBound(MyData.class);
return unmarshaller;
}
#Bean
#ServiceActivator(inputChannel = "channel_3")
public MessageHandler messageHandler() {
return new MethodInvokingMessageHandler(consumer(), "handleMessage");
}
#Bean
#ServiceActivator(inputChannel = "channel_error")
public MessageHandler errorHandler() {
return new MethodInvokingMessageHandler(consumer(), "handleError");
}
I get the below exception, when I refer for this exception, it says that service activator is not configured properly. I am not sure what I am missing, can someone please help.
org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'org.springframework.web.context.WebApplicationContext:/v1.channel_error'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:81)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:287)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:95)
at org.springframework.integration.gateway.MessagingGatewaySupport.send(MessagingGatewaySupport.java:281)
at org.springframework.integration.jms.ChannelPublishingJmsMessageListener$GatewayDelegate.send(ChannelPublishingJmsMessageListener.java:479)
at org.springframework.integration.jms.ChannelPublishingJmsMessageListener.onMessage(ChannelPublishingJmsMessageListener.java:322)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:674)
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:634)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:605)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:308)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:246)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1144)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1136)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1033)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:107)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:97)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
... 16 more
Logs on start up :
2016-03-30 13:06:46,423 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [servletConfigInitParams] PropertySource with lowest search precedence
2016-03-30 13:06:46,403 DEBUG com.amazonaws.jmx.MBeans.registerMBean[58] - Failed to register mbean com.amazonaws.management:type=AwsSdkMetrics
javax.management.InstanceAlreadyExistsException: com.amazonaws.management:type=AwsSdkMetrics
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324)
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522)
at com.amazonaws.jmx.MBeans.registerMBean(MBeans.java:52)
at com.amazonaws.jmx.SdkMBeanRegistrySupport.registerMetricAdminMBean(SdkMBeanRegistrySupport.java:27)
at com.amazonaws.metrics.AwsSdkMetrics.registerMetricAdminMBean(AwsSdkMetrics.java:355)
at com.amazonaws.metrics.AwsSdkMetrics.<clinit>(AwsSdkMetrics.java:316)
at com.amazonaws.AmazonWebServiceClient.requestMetricCollector(AmazonWebServiceClient.java:629)
at com.amazonaws.AmazonWebServiceClient.isRMCEnabledAtClientOrSdkLevel(AmazonWebServiceClient.java:570)
at com.amazonaws.AmazonWebServiceClient.isRequestMetricsEnabled(AmazonWebServiceClient.java:562)
at com.amazonaws.AmazonWebServiceClient.createExecutionContext(AmazonWebServiceClient.java:523)
at com.amazonaws.services.sqs.AmazonSQSClient.getQueueUrl(AmazonSQSClient.java:525)
at com.amazon.sqs.javamessaging.AmazonSQSMessagingClientWrapper.getQueueUrl(AmazonSQSMessagingClientWrapper.java:260)
at com.amazon.sqs.javamessaging.AmazonSQSMessagingClientWrapper.getQueueUrl(AmazonSQSMessagingClientWrapper.java:230)
at com.amazon.sqs.javamessaging.SQSSession.createQueue(SQSSession.java:576)
at org.springframework.jms.support.destination.DynamicDestinationResolver.resolveQueue(DynamicDestinationResolver.java:84)
at org.springframework.jms.support.destination.DynamicDestinationResolver.resolveDestinationName(DynamicDestinationResolver.java:58)
at org.springframework.jms.support.destination.JmsDestinationAccessor.resolveDestinationName(JmsDestinationAccessor.java:98)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.createListenerConsumer(AbstractPollingMessageListenerContainer.java:204)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.initResourcesIfNecessary(DefaultMessageListenerContainer.java:1167)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1143)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1136)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1033)
at java.lang.Thread.run(Thread.java:745)
2016-03-30 13:06:46,423 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [servletConfigInitParams] PropertySource with lowest search precedence
2016-03-30 13:06:46,427 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [servletContextInitParams] PropertySource with lowest search precedence
2016-03-30 13:06:46,427 DEBUG com.amazonaws.metrics.AwsSdkMetrics.registerMetricAdminMBean[369] - Admin mbean registered under com.amazonaws.management:type=AwsSdkMetrics/4
2016-03-30 13:06:46,427 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [servletContextInitParams] PropertySource with lowest search precedence
2016-03-30 13:06:46,428 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [jndiProperties] PropertySource with lowest search precedence
2016-03-30 13:06:46,428 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [jndiProperties] PropertySource with lowest search precedence
2016-03-30 13:06:46,428 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [systemProperties] PropertySource with lowest search precedence
2016-03-30 13:06:46,428 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [systemProperties] PropertySource with lowest search precedence
2016-03-30 13:06:46,428 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [systemEnvironment] PropertySource with lowest search precedence
2016-03-30 13:06:46,428 DEBUG org.springframework.web.context.support.StandardServletEnvironment.addLast[109] - Adding [systemEnvironment] PropertySource with lowest search precedence
2016-03-30 13:06:46,429 DEBUG org.springframework.web.context.support.StandardServletEnvironment.<init>[126] - Initialized StandardServletEnvironment with PropertySources [servletConfigInitParams,servletContextInitParams,jndiProperties,systemProperties,systemEnvironment]
2016-03-30 13:06:46,429 DEBUG org.springframework.web.context.support.StandardServletEnvironment.<init>[126] - Initialized StandardServletEnvironment with PropertySources [servletConfigInitParams,servletContextInitParams,jndiProperties,systemProperties,systemEnvironment]
2016-03-30 13:06:46,432 DEBUG com.choiceedge.library.common.service.v1.endpoint.AbstractEndpoint$RequestContextAwareFilter.init[177] - Initializing filter 'RequestContextAwareFilter'
2016-03-30 13:06:46,436 DEBUG com.choiceedge.library.common.service.v1.endpoint.AbstractEndpoint$RequestContextAwareFilter.init[202] - Filter 'RequestContextAwareFilter' configured successfully
2016-03-30 13:06:46,437 DEBUG com.amazonaws.auth.AWSCredentialsProviderChain.getCredentials[105] - Loading credentials from EnvironmentVariableCredentialsProvider
2016-03-30 13:06:46,438 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBean[248] - Returning cached instance of singleton bean 'cxf'
2016-03-30 13:06:46,438 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBean[248] - Returning cached instance of singleton bean 'cxf'
This is how I register my AppConfig in my WebApplicationInitializer
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
rootContext = new AnnotationConfigWebApplicationContext();
rootContext.getEnvironment().setActiveProfiles(System.getenv(ENVIRONMENT));
LOGGER.info(System.getenv(ENVIRONMENT));
System.out.println("Starting application in " + System.getenv(ENVIRONMENT));
rootContext.register(AppConfig.class);
rootContext.setDisplayName(DISPLAY_NAME);
// Manage the lifecycle of the root application context
servletContext.addListener(new ContextLoaderListener(rootContext));
.....
And in my AppConfig I have
#Configuration
#ImportResource("...") - this is for another custom library
#ComponentScan(...)
#EnableIntegration
public class AppConfig {

Haven't you missed #EnableIntegration on your #Configuration?
Starting with version 4.0, the #EnableIntegration annotation has been introduced, to allow the registration of Spring Integration infrastructure beans (see JavaDocs). This annotation is required when only Java & Annotation configuration is used, e.g. with Spring Boot and/or Spring Integration Messaging Annotation support and Spring Integration Java DSL with no XML integration configuration.
http://docs.spring.io/spring-integration/docs/4.3.0.BUILD-SNAPSHOT/reference/html/overview.html#configuration-enable-integration

SOLVED : The changes that resolved the issue, was to autowire the channels to the listener. And Make the PropertyPlaceHolderConfigurer bean as static
#Bean
#Autowired
public ChannelPublishingJmsMessageListener messageListener(MessageChannel channel_1, MessageChannel channel_error){
ChannelPublishingJmsMessageListener adapter = new ChannelPublishingJmsMessageListener();
adapter.setRequestChannel(channel_1);
adapter.setErrorChannel(channel_error);
return adapter;
}

Related

Spring data jdbc - Multiple data source - Not reading data from secondry

Use case: Read data from oracle and load the same into MySQL.
We are using Spring Data JDBC and OJDBC8.
Issue: Always connecting to the primary data source.
**application.properties**
=======================
spring.datasource.mysql.jdbcUrl = jdbc:mysql://localhost:3306/MySQLData?useSSL=false
spring.datasource.mysql.username = root
spring.datasource.mysql.password = root
spring.datasource.mysql.driverClassName = com.mysql.cj.jdbc.Driver
spring.datasource.oracle.jdbcUrl = jdbc:oracle:thin:#localhost:1521/XE
spring.datasource.oracle.username = root
spring.datasource.oracle.password = ea
spring.datasource.oracle.driverClassName = oracle.jdbc.OracleDriver
**MySqlDataSource.java**
=====================
package com.test.datasource;
#Configuration
#EnableJdbcRepositories(transactionManagerRef = "mysqlJdbcTransactionManager", jdbcOperationsRef = "mysqlJdbcOperationsReference", basePackages = {
"com.test.data.mysql.repository" })
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, JdbcRepositoriesAutoConfiguration.class })
public class MySqlDataSource extends AbstractJdbcConfiguration {
#Bean
#Primary
#Qualifier("mysqlDataSource")
#ConfigurationProperties(prefix = "spring.datasource.mysql")
public DataSource dataSourceMySql() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
#Qualifier("mysqlJdbcOperationsReference")
public NamedParameterJdbcOperations mysqlJdbcOperationsReference(
#Qualifier("mysqlDataSource") DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
#Bean
#Primary
#Qualifier("mysqlJdbcTransactionManager")
public PlatformTransactionManager mysqlJdbcTransactionManager(#Qualifier("mysqlDataSource") final DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
**OracleDataSource.java**
======================
package com.test.datasource;
#Configuration
#EnableTransactionManagement
#EnableJdbcRepositories(transactionManagerRef = "oracleJdbcTransactionManager", jdbcOperationsRef = "oracleJdbcOperationsReference", basePackages = {
"com.test.data.oracle.repository" })
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, JdbcRepositoriesAutoConfiguration.class })
public class OracleDataSource extends AbstractJdbcConfiguration {
#Bean
#Qualifier("oracleDataSource")
#ConfigurationProperties(prefix = "spring.datasource.oracle")
public DataSource dataSourceOracle() {
return DataSourceBuilder.create().build();
}
#Bean
#Qualifier("oracleJdbcOperationsReference")
public NamedParameterJdbcOperations oracleJdbcOperationsReference(
#Qualifier("oracleDataSource") DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
#Bean
#Qualifier("oracleJdbcTransactionManager")
public PlatformTransactionManager oracleJdbcTransactionManager(
#Qualifier("oracleDataSource") final DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
package com.test.data.oracle.repository;
#Repository
public interface ServiceRepository extends CrudRepository<Service, Integer> {
}
**Controller.java**
====================
package com.test.controller;
#RestController
#RequestMapping(value = "/api/v1/bnService")
#Api(tags = { "Business Unit operations" })
public class BNServiceController {
#Autowired
private ServiceRepository attributeGroupRepository;
#RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public SuccessVO retrieveConnectorInfoByCode() {
Optional<Service> pagedOtAttributeGroup = attributeGroupRepository.findById(52);
return null;
}
}
**Logs**
========
Adding transactional method 'org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.findById' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
Returning cached instance of singleton bean 'oracleJdbcTransactionManager'
Creating new transaction with name [org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.findById]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
HikariPool-2 - configuration:
allowPoolSuspension.............false
autoCommit......................true
catalog.........................none
connectionInitSql...............none
connectionTestQuery.............none
connectionTimeout...............30000
dataSource......................none
dataSourceClassName.............none
dataSourceJNDI..................none
dataSourceProperties............{password=<masked>}
driverClassName................."oracle.jdbc.OracleDriver"
exceptionOverrideClassName......none
healthCheckProperties...........{}
healthCheckRegistry.............none
idleTimeout.....................600000
initializationFailTimeout.......1
isolateInternalQueries..........false
jdbcUrl.........................jdbc:oracle:thin:#localhost:1521/XE
leakDetectionThreshold..........0
maxLifetime.....................1800000
maximumPoolSize.................10
metricRegistry..................none
metricsTrackerFactory...........none
minimumIdle.....................10
password........................<masked>
poolName........................"HikariPool-2"
readOnly........................false
registerMbeans..................false
scheduledExecutor...............none
schema..........................none
threadFactory...................internal
transactionIsolation............default
username........................"ea"
validationTimeout...............5000
HikariPool-2 - Starting...
HikariPool-2 - Added connection oracle.jdbc.driver.T4CConnection#1bfa059c
HikariPool-2 - Start completed.
Acquired Connection [HikariProxyConnection#2136532594 wrapping oracle.jdbc.driver.T4CConnection#1bfa059c] for JDBC transaction
Setting JDBC Connection [HikariProxyConnection#2136532594 wrapping oracle.jdbc.driver.T4CConnection#1bfa059c] read-only
Switching JDBC Connection [HikariProxyConnection#2136532594 wrapping oracle.jdbc.driver.T4CConnection#1bfa059c] to manual commit
Bound value [org.springframework.jdbc.datasource.ConnectionHolder#55db8827] for key [HikariDataSource (HikariPool-2)] to thread [http-nio-8081-exec-2]
Initializing transaction synchronization
Getting transaction for [org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.findById]
Executing prepared SQL query
Fetching JDBC Connection from DataSource
Bound value [org.springframework.jdbc.datasource.ConnectionHolder#400a4f] for key [HikariDataSource (HikariPool-1)] to thread [http-nio-8081-exec-2]
Setting SQL statement parameter value: column index 1, parameter value [52], value class [java.lang.Integer], SQL type 4
Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder#400a4f] for key [HikariDataSource (HikariPool-1)] bound to thread [http-nio-8081-exec-2]
Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder#400a4f] for key [HikariDataSource (HikariPool-1)] bound to thread [http-nio-8081-exec-2]
Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
HikariPool-2 - Pool stats (total=1, active=1, idle=0, waiting=0)
Using JAXP provider [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl]
Trying to resolve XML entity with public ID [-//SPRING//DTD BEAN 2.0//EN] and system ID [https://www.springframework.org/dtd/spring-beans-2.0.dtd]
Trying to locate [spring-beans.dtd] in Spring jar on classpath
Found beans DTD [https://www.springframework.org/dtd/spring-beans-2.0.dtd] in classpath: spring-beans.dtd
Alias definition 'Db2' registered for name 'DB2'
Alias definition 'Hana' registered for name 'HDB'
Alias definition 'Hsql' registered for name 'HSQL'
Alias definition 'SqlServer' registered for name 'MS-SQL'
Alias definition 'Postgres' registered for name 'PostgreSQL'
Loaded 11 bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
Caching SQL error codes for DataSource [com.zaxxer.hikari.HikariDataSource#3b332962]: database product name is 'MySQL'
Translating SQLException with SQL state '42S02', error code '1146', message [Table 'MySQLData.service' doesn't exist]; SQL was [SELECT `service`.`SERVICE_ID` AS `SERVICE_ID`, `service`.`SERVICE_NAME` AS `SERVICE_NAME` FROM `service` WHERE `service`.`SERVICE_ID` = ?] for task [PreparedStatementCallback]
Completing transaction for **[org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.findById] after exception: org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT `service`.`SERVICE_ID` AS `SERVICE_ID`, `service`.`SERVICE_NAME` AS `SERVICE_NAME` FROM `service` WHERE `service`.`SERVICE_ID` = ?]; nested exception is java.sql.SQLSyntaxErrorException: Table 'MySQLData.service' doesn't exist**
Based on the logs, I understood that it is loading the oracle driver and due to some issue it couldn't retrieve the data and switching the connection back to MySQL. As MySQL doesn't have those tables it is throwing the exception.
Note:
If I change oracle as primary it is working as expected.
Modified IdentifierProcessing to generalize the SQL generated

spring cloud rabbit configuration tries to connect to localhost 5672

There are tons of examples where java code is being used to configure pure rabbit, but spring boot related documentation is another story.
My requirement is pretty basic - Single queue, Single exchange, One dead-letter queue with predefined names. Some HA policy. Deployed to pivotal cloud-foundry.
The app should use cloud connection factory, so I don't have to specify connection info.
The app should create queue/exchange if they don't exist.
I need a controller that can use rabbitTemplate to send msgs.
I need a listener to process those messages, in multiple consumer threads.
I have tried to do properties-only approach. And I have tried tons of beans to do this. For some reason it doesn't want to connect to cloud service!
I am using spring boot app and running it in pivotal cloud foundry
Code
#Configuration
#EnableRabbit
#Profile("cloud")
#Slf4j
public class RabbitMQConfig extends AbstractCloudConfig {
final static String MAIN_QUEUE_NAME = "pricing";
private final static String QUEUE_EXCHANGE_NAME = "pricing-exchange";
private final static String DEAD_LETTER_QUEUE_NAME = "pricing-dl";
#Autowired
RabbitProperties rabbitProperties;
#Bean("pricingQueue")
#Primary
public Queue pricingQueue() {
return QueueBuilder.durable(MAIN_QUEUE_NAME)
.withArgument("x-dead-letter-exchange", "")
.withArgument("x-dead-letter-routing-key", DEAD_LETTER_QUEUE_NAME)
.withArgument("x-queue-master-locator", "min-masters")
.build();
}
#Bean
public Queue deadLetterQueue() {
return QueueBuilder.durable(DEAD_LETTER_QUEUE_NAME)
.withArgument("x-queue-master-locator", "min-masters")
.build();
}
#Bean
public DirectExchange exchange() {
return new DirectExchange(QUEUE_EXCHANGE_NAME);
}
#Bean
public Binding pricingBinding(#Qualifier("pricingQueue") Queue pricingQueue,
DirectExchange exchange) {
return BindingBuilder.bind(pricingQueue).to(exchange).with(MAIN_QUEUE_NAME);
}
#Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
}
I think this is happening because spring boot created the listener container and not me
Error
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'management.health.status-org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorProperties'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.createArgumentArray:777]- Autowiring by type from bean name 'org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration' via constructor to bean named 'management.health.status-org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorProperties'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'healthIndicatorRegistry'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.createArgumentArray:777]- Autowiring by type from bean name 'healthIndicatorRegistry' via factory method to bean named 'org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext#6483f5ae'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'rabbitHealthIndicator'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'org.springframework.boot.actuate.autoconfigure.amqp.RabbitHealthIndicatorAutoConfiguration'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'rabbitTemplate'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration$RabbitTemplateConfiguration'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'spring.rabbitmq-org.springframework.boot.autoconfigure.amqp.RabbitProperties'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.createArgumentArray:777]- Autowiring by type from bean name 'org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration$RabbitTemplateConfiguration' via constructor to bean named 'spring.rabbitmq-org.springframework.boot.autoconfigure.amqp.RabbitProperties'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'rabbitConnectionFactory'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration$RabbitConnectionFactoryCreator'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.createArgumentArray:777]- Autowiring by type from bean name 'rabbitConnectionFactory' via factory method to bean named 'spring.rabbitmq-org.springframework.boot.autoconfigure.amqp.RabbitProperties'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.createArgumentArray:777]- Autowiring by type from bean name 'rabbitTemplate' via factory method to bean named 'rabbitConnectionFactory'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'jsonMessageConverter'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'rabbitMQConfig'
...
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.createArgumentArray:777]- Autowiring by type from bean name 'viewResolver' via factory method to bean named 'org.springframework.beans.factory.support.DefaultListableBeanFactory#1dde4cb2'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'amqpAdmin'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.createArgumentArray:777]- Autowiring by type from bean name 'amqpAdmin' via factory method to bean named 'rabbitConnectionFactory'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration$MessagingTemplateConfiguration'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'rabbitMessagingTemplate'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.createArgumentArray:777]- Autowiring by type from bean name 'rabbitMessagingTemplate' via factory method to bean named 'rabbitTemplate'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'org.springframework.boot.autoconfigure.amqp.RabbitAnnotationDrivenConfiguration'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.createArgumentArray:777]- Autowiring by type from bean name 'org.springframework.boot.autoconfigure.amqp.RabbitAnnotationDrivenConfiguration' via constructor to bean named 'spring.rabbitmq-org.springframework.boot.autoconfigure.amqp.RabbitProperties'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'simpleRabbitListenerContainerFactoryConfigurer'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'rabbitListenerContainerFactory'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.createArgumentArray:777]- Autowiring by type from bean name 'rabbitListenerContainerFactory' via factory method to bean named 'simpleRabbitListenerContainerFactoryConfigurer'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.createArgumentArray:777]- Autowiring by type from bean name 'rabbitListenerContainerFactory' via factory method to bean named 'rabbitConnectionFactory'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'directRabbitListenerContainerFactoryConfigurer'
...
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration'
[main] [DEBUG] [org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:213]- Creating shared instance of singleton bean 'management.server-org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties'
[main] [DEBUG] [org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.:264]- Inferred argument type for public void com.gm.gsmc.pricing.messenger.service.PricingMessageListener.handleMessage(com.gm.gsmc.pricing.domain.queue.QueueMessage) is class com.gm.gsmc.pricing.domain.queue.QueueMessage
[main] [DEBUG] [org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.setConcurrentConsumers:166]- Changing consumers from 1 to 5
[main] [DEBUG] [org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.start:1293]- Starting Rabbit listener container.
[main] [INFO ] [org.springframework.amqp.rabbit.connection.CachingConnectionFactory.createBareConnection:482]- Attempting to connect to: [localhost:5672]
[main] [INFO ] [org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.checkMismatchedQueues:1713]- Broker not available; cannot force queue declarations during start: java.net.ConnectException: Connection refused (Connection refused)
[org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] [INFO ] [org.springframework.amqp.rabbit.connection.CachingConnectionFactory.createBareConnection:482]- Attempting to connect to: [localhost:5672]
[org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] [ERROR] [org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.redeclareElementsIfNecessary:1764]- Failed to check/redeclare auto-delete queue(s). java.net.ConnectException: Connection refused (Connection refused)\n at java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:1.8.0_212]\n at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_212]\n at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_212]\n at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_212]\n at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_212]\n at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_212]\n at com.rabbitmq.client.impl.SocketFrameHandlerFactory.create(SocketFrameHandlerFactory.java:60) ~[amqp-client-5.4.3.jar!/:5.4.3]\n at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:1102) ~[amqp-client-5.4.3.jar!/:5.4.3]\n at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:1054) ~[amqp-client-5.4.3.jar!/:5.4.3]\n at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.java:484) ~[spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n ... 11 common frames omitted\nWrapped by: org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused (Connection refused)\n at org.springframework.amqp.rabbit.support.RabbitExceptionTranslator.convertRabbitAccessException(RabbitExceptionTranslator.java:62) ~[spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.java:530) ~[spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.createConnection(CachingConnectionFactory.java:702) ~[spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n at org.springframework.amqp.rabbit.connection.ConnectionFactoryUtils.createConnection(ConnectionFactoryUtils.java:214) ~[spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n at org.springframework.amqp.rabbit.core.RabbitTemplate.doExecute(RabbitTemplate.java:2076) ~[spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:2050) ~[spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:2030) ~[spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n at org.springframework.amqp.rabbit.core.RabbitAdmin.getQueueProperties(RabbitAdmin.java:403) ~[spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.attemptDeclarations(AbstractMessageListenerContainer.java:1777) ~[spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.redeclareElementsIfNecessary(AbstractMessageListenerContainer.java:1758) ~[spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.initialize(SimpleMessageListenerContainer.java:1195) [spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1041) [spring-rabbit-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]\n at java.lang.Thread.run(Thread.java:748) [na:1.8.0_212]\n
I am not sure why you have those amqpAdmin calls in your bean definitions (although they are commented out). You must NEVER talk to the broker in a bean definition - it's too early in the lifecycle.
The error in the first log leads me to believe that was not commented out. That log looks truncated too - there should be Caused by parts. You should never truncate a log when asking a question. A partial stack trace is useless.
Factory method 'msgQueueBinding' threw exception; nested exception is org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused (Connection refused)
This clearly shows an attempt to connect from the msgQueueBinding method.
The following logs show the queue/exchange/binding being successfully declared when the listener starts.
I am guessing your admin calls are happening before the cloud code has replaced the connection factory bean definition.
Thanks for the pointers Gary
This is basically the config that "works"
If I take RabbitTemplate or Container Factory off, I start seeing errors
I took some code from RabbitAutoConfiguration and did my best to read the same yml and use the properties in the beans I create
#Configuration
#EnableRabbit
#Profile("cloud")
#Slf4j
public class RabbitMQConfig extends AbstractCloudConfig {
final static String MAIN_QUEUE_NAME = "pricing";
private final static String QUEUE_EXCHANGE_NAME = "pricing-exchange";
private final static String DEAD_LETTER_QUEUE_NAME = "pricing-dl";
#Autowired
RabbitProperties rabbitProperties;
private void debug(String step) {
CachingConnectionFactory connectionFactory = (CachingConnectionFactory) connectionFactory().rabbitConnectionFactory();
log.info("===> debug connection with {} {} ", step, connectionFactory.getClass().getName());
log.info("host {}", connectionFactory.getHost());
log.info("port {}", connectionFactory.getPort());
log.info("vh {}", connectionFactory.getVirtualHost());
log.info("user {}", connectionFactory.getUsername());
log.info("Auto recovery {}", connectionFactory.getRabbitConnectionFactory().isAutomaticRecoveryEnabled());
log.info("RabbitProperties {}", ToStringBuilder.reflectionToString(rabbitProperties));
}
#SuppressWarnings("DuplicatedCode")
#Bean
public RabbitTemplate rabbitTemplate(MessageConverter messageConverter) {
debug("rabbitTemplate");
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory().rabbitConnectionFactory());
rabbitTemplate.setMessageConverter(messageConverter);
if (rabbitProperties != null) {
RabbitProperties.Template properties = this.rabbitProperties.getTemplate();
PropertyMapper map = PropertyMapper.get();
if (properties.getRetry().isEnabled()) {
rabbitTemplate.setRetryTemplate(createRetryTemplate(properties.getRetry()));
}
map.from(properties::getReceiveTimeout).whenNonNull().as(Duration::toMillis)
.to(rabbitTemplate::setReceiveTimeout);
map.from(properties::getReplyTimeout).whenNonNull().as(Duration::toMillis).to(rabbitTemplate::setReplyTimeout);
map.from(properties::getExchange).to(rabbitTemplate::setExchange);
map.from(properties::getRoutingKey).to(rabbitTemplate::setRoutingKey);
map.from(properties::getDefaultReceiveQueue).whenNonNull().to(rabbitTemplate::setDefaultReceiveQueue);
}
return rabbitTemplate;
}
private RetryTemplate createRetryTemplate(RabbitProperties.Retry properties) {
PropertyMapper map = PropertyMapper.get();
RetryTemplate template = new RetryTemplate();
SimpleRetryPolicy policy = new SimpleRetryPolicy();
map.from(properties::getMaxAttempts).to(policy::setMaxAttempts);
template.setRetryPolicy(policy);
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
map.from(properties::getInitialInterval).whenNonNull().as(Duration::toMillis)
.to(backOffPolicy::setInitialInterval);
map.from(properties::getMultiplier).to(backOffPolicy::setMultiplier);
map.from(properties::getMaxInterval).whenNonNull().as(Duration::toMillis).to(backOffPolicy::setMaxInterval);
template.setBackOffPolicy(backOffPolicy);
return template;
}
#Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
debug("rabbit listener");
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory().rabbitConnectionFactory());
factory.setMessageConverter(jsonMessageConverter());
factory.setAcknowledgeMode(AcknowledgeMode.AUTO);
factory.setConcurrentConsumers(rabbitProperties.getListener().getSimple().getConcurrency());
factory.setMaxConcurrentConsumers(rabbitProperties.getListener().getSimple().getMaxConcurrency());
factory.setPrefetchCount(rabbitProperties.getListener().getSimple().getPrefetch());
factory.setMissingQueuesFatal(false);
return factory;
}
#Bean
public AmqpAdmin amqpAdmin() {
ConnectionFactory connectionFactory = connectionFactory().rabbitConnectionFactory();
debug("amqpAdmin");
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.initialize();
//This is what puts HA policy on the queue it seems
Properties queueProperties = rabbitAdmin.getQueueProperties(MAIN_QUEUE_NAME);
log.debug("queueProperties {}", queueProperties);
return rabbitAdmin;
}
#PostConstruct
public void init() {
debug("postConstruct");
}
#Bean("pricingQueue")
#Primary
public Queue pricingQueue() {
return QueueBuilder.durable(MAIN_QUEUE_NAME)
.withArgument("x-dead-letter-exchange", "")
.withArgument("x-dead-letter-routing-key", DEAD_LETTER_QUEUE_NAME)
.withArgument("x-queue-master-locator", "min-masters")
.build();
}
#Bean
public Queue deadLetterQueue() {
return QueueBuilder.durable(DEAD_LETTER_QUEUE_NAME)
.withArgument("x-queue-master-locator", "min-masters")
.build();
}
#Bean
public DirectExchange exchange() {
return new DirectExchange(QUEUE_EXCHANGE_NAME);
}
#Bean
public Binding pricingBinding(#Qualifier("pricingQueue") Queue pricingQueue,
DirectExchange exchange) {
return BindingBuilder.bind(pricingQueue).to(exchange).with(MAIN_QUEUE_NAME);
}
#Bean
public DefaultMessageHandlerMethodFactory messageHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
factory.setMessageConverter(consumerJackson2MessageConverter());
return factory;
}
#Bean
public MappingJackson2MessageConverter consumerJackson2MessageConverter() {
return new MappingJackson2MessageConverter();
}
#Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
}

Spring Boot will not start when using Spring Integration and JdbcMetadataStore

I am trying to use Spring Integration to read files via SFTP and to use multiple servers to only read each file once. I have configured the SFTP reader within Spring Boot and it works with the in-memory metadata store. When I configure the JdbcMetadataStore using Postgres, Spring boot will no longer start and there is no error message other than Tomcat is shutting down. I am using Spring Boot with JPA and Spring WS
2018-10-22 11:16:06.098 INFO 6775 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'dataSource' has been autodetected for JMX exposure
2018-10-22 11:16:06.106 INFO 6775 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'metadataStore' has been autodetected for JMX exposure
2018-10-22 11:16:06.114 INFO 6775 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Located managed bean 'metadataStore': registering with JMX server as MBean [org.springframework.integration.jdbc.metadata:name=metadataStore,type=JdbcMetadataStore]
2018-10-22 11:16:06.125 INFO 6775 --- [ restartedMain] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
I am using annotation based configuration
#Bean
public ConcurrentMetadataStore metadataStore(final DataSource dataSource) {
return new JdbcMetadataStore(dataSource);
}
#Bean
public SessionFactory<ChannelSftp.LsEntry> sftpSessionFactory() {
final DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost(this.host);
factory.setPort(this.port);
factory.setUser(this.username);
factory.setPassword(this.password);
factory.setAllowUnknownKeys(true);
return new CachingSessionFactory<>(factory);
}
#Bean
#InboundChannelAdapter(channel = "stream", poller = #Poller(fixedDelay = "5000"))
public MessageSource<InputStream> sftpMessageSource(ConcurrentMetadataStore metadataStore) {
final SftpStreamingMessageSource messageSource = new SftpStreamingMessageSource(template(), null);
messageSource.setRemoteDirectory("/");
messageSource.setFilter(new SftpPersistentAcceptOnceFileListFilter(metadataStore,
"INT_"));
//messageSource.setFilter(new SftpPersistentAcceptOnceFileListFilter(new SimpleMetadataStore(),
// "streaming"));
return messageSource;
}
#Bean
#Transformer(inputChannel = "stream", outputChannel = "data")
public org.springframework.integration.transformer.Transformer transformer() {
return new StreamTransformer();
}
#Bean
public SftpRemoteFileTemplate template() {
return new SftpRemoteFileTemplate(sftpSessionFactory());
}
I noticed it failed when trying to load the metadatastore to JMX. I then disabled JMX in Spring Boot and it fixed the issue. Not sure why it was failing to add the bean to JMX but disabling JMX in the spring boot property(yml) file fixed the issue.
spring:
jmx:
enabled: false

Spring boot rabbitMq setExceptionHandler

How can I convert the following code using the Spring framework?
ConnectionFactory factory = new ConnectionFactory();
factory.setExceptionHandler(new BrokerExceptionHandler(logger, instance));
public final class BrokerExceptionHandler extends StrictExceptionHandler {
#Override
public void handleReturnListenerException(Channel channel, Throwable exception) {
logger.log(Level.SEVERE, "ReturnListenerException detected: ReturnListener.handleReturn", exception);
this.publishAlert(exception, "ReturnListener.handleReturn");
logger.log(Level.SEVERE, "Close application", exception);
System.exit(-1);
}
....
}
Basically I need to specify a custom exception handler if a rabbitMQ exception occurs and then stop the application
How can I publish a rabbitMq message every time that there is an exception?
EDIT
I modified my configuration class in this way:
#Bean
SimpleMessageListenerContainer containerPredict(ConnectionFactory connectionFactory,
MessageListenerAdapter listenerPredictAdapter) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setDefaultRequeueRejected(false);
container.setErrorHandler(new BrokerExceptionHandler());
container.setQueueNames(getQueueName());
container.setMessageListener(listenerAdapter);
return container;
}
and this is my BrokerExceptionHandler class
public class BrokerExceptionHandler implements ErrorHandler {
private final Logger logger = Logger.getLogger(getClass().getSimpleName());
#Autowired
private Helper helper;
#Override
public void handleError(Throwable t) {
logger.log(Level.SEVERE, "Exception Detected. Publishing error alert");
String message = "Exception detected. Message: " + t.getMessage());
// Notify the error to the System sending a new RabbitMq message
System.out.println("---> Before convertAndSend");
rabbitTemplate.convertAndSend(exchange, routing, message);
System.out.println("---> After convertAndSend");
}
}
I can see the log Exception Detected. Publishing error alert and ---> Before convertAdnSend in the console, but the new alert is not published and the log ---> After convertAndSend doesn't appear in the console.
Here it is the log:
2018-10-17 09:32:02.849 ERROR 1506 --- [tainer****-1] BrokerExceptionHandler : Exception Detected. Publishing error alert
---> Before convertAndSend
2018-10-17 09:32:02.853 INFO 1506 --- [tainer****-1] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer#4f5b08d: tags=[{amq.ctag-yUcUmg5BCo20ucG1wJZoWA=myechange}], channel=Cached Rabbit Channel: AMQChannel(amqp://admin#XXX.XXX.XXX.XXX:5672/testbed_simulators,1), conn: Proxy#3964d79 Shared Rabbit Connection: SimpleConnection#61f39bb [delegate=amqp://admin#XXX.XXX.XXX.XXX:5672/testbed_simulators, localPort= 51528], acknowledgeMode=AUTO local queue size=0
2018-10-17 09:32:02.905 INFO 1506 --- [tainer****-2] o.s.amqp.rabbit.core.RabbitAdmin : Auto-declaring a non-durable, auto-delete, or exclusive Queue (myexchange) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
2018-10-17 09:32:02.905 INFO 1506 --- [tainer****-2] o.s.amqp.rabbit.core.RabbitAdmin : Auto-declaring a non-durable, auto-delete, or exclusive Queue (myexchange) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
EDIT
Debugging I see that before to send the new message, the following code is called:
File: SimpleMessageListenerContainer.class line 1212
if (!isActive(this.consumer) || aborted) {
.....
}
else {
---> logger.info("Restarting " + this.consumer);
restart(this.consumer);
}
EDIT 2
Example code: http://github.com/fabry00/spring-boot-rabbitmq
It depends on how you are doing your configuration; if you are using Spring Boot's auto-configured connection factory...
#Bean
public InitializingBean connectionFactoryConfigurer(CachingConnectionFactory ccf) {
return () -> ccf.getRabbitConnectionFactory().setExceptionHandler(...);
}
If you are wiring up your own beans (e.g. via a RabbitConnectionFactoryBean) then set it directly.
EDIT
You are throwing a NullPointerException in your error handler...
2018-10-17 11:51:58.733 DEBUG 38975 --- [containerKpis-1] o.s.a.r.l.SimpleMessageListenerContainer : Consumer raised exception, processing can restart if the connection factory supports it
java.lang.NullPointerException: null
at com.test.BrokerExceptionHandler.handleError(BrokerExceptionHandler.java:27) ~[main/:na]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeErrorHandler(AbstractMessageListenerContainer.java:1243) ~[spring-rabbit-2.0.6.RELEASE.jar:2.0.6.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.handleListenerException(AbstractMessageListenerContainer.java:1488) ~[spring-rabbit-2.0.6.RELEASE.jar:2.0.6.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1318) ~[spring-rabbit-2.0.6.RELEASE.jar:2.0.6.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:817) ~[spring-rabbit-2.0.6.RELEASE.jar:2.0.6.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:801) ~[spring-rabbit-2.0.6.RELEASE.jar:2.0.6.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$700(SimpleMessageListenerContainer.java:77) ~[spring-rabbit-2.0.6.RELEASE.jar:2.0.6.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1042) ~[spring-rabbit-2.0.6.RELEASE.jar:2.0.6.RELEASE]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]
2018-10-17 11:51:58.734 INFO 38975 --- [containerKpis-1] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer#1aabf50d: tags=[{amq.ctag-VxxHKiMsWI_w8DIooAsySA=myapp.mydomain.KPIS}], channel=Cached Rabbit Channel: AMQChannel(amqp://guest#127.0.0.1:5672/,1), conn: Proxy#b88a7d6 Shared Rabbit Connection: SimpleConnection#25dc64a [delegate=amqp://guest#127.0.0.1:5672/, localPort= 55662], acknowledgeMode=AUTO local queue size=0
To turn on DEBUG logging, add
logging.level.org.springframework.amqp=debug
to your application.properties.
this.helper is null because the error handler is not a Spring Bean - #Autowired only works if Spring manages the object; you are using new BrokerExceptionHandler().
EDIT2
I added these 2 beans
#Bean
public BrokerExceptionHandler errorHandler() {
return new BrokerExceptionHandler();
}
#Bean
public MessageConverter json() { // Boot auto-configures in template
return new Jackson2JsonMessageConverter();
}
and now...
---> Before publishing Alert event
--- ALERT
2018-10-17 12:14:45.304 INFO 43359 --- [containerKpis-1] Helper : publishAlert
2018-10-17 12:14:45.321 DEBUG 43359 --- [containerKpis-1] o.s.a.r.c.CachingConnectionFactory : Creating cached Rabbit Channel from AMQChannel(amqp://guest#127.0.0.1:5672/,3)
2018-10-17 12:14:45.321 DEBUG 43359 --- [containerKpis-1] o.s.amqp.rabbit.core.RabbitTemplate : Executing callback RabbitTemplate$$Lambda$638/975724213 on RabbitMQ Channel: Cached Rabbit Channel: AMQChannel(amqp://guest#127.0.0.1:5672/,3), conn: Proxy#77f3f419 Shared Rabbit Connection: SimpleConnection#10c86af1 [delegate=amqp://guest#127.0.0.1:5672/, localPort= 56220]
2018-10-17 12:14:45.321 DEBUG 43359 --- [containerKpis-1] o.s.amqp.rabbit.core.RabbitTemplate : Publishing message (Body:'{"timestamp":1539792885303,"code":"ERROR","severity":"ERROR","message":"Exception detected. Message: Listener method 'kpisEvent' threw exception"}' MessageProperties [headers={sender=myapp, protocolVersion=1.0.0, senderType=MY_COMPONENT_1, __TypeId__=com.test.domain.Alert, timestamp=1539792885304}, contentType=application/json, contentEncoding=UTF-8, contentLength=146, deliveryMode=PERSISTENT, priority=0, deliveryTag=0])on exchange [myevent.ALERT], routingKey = [/]
--- ALERT 2
---> After publishing Alert event
2018-10-17 12:14:45.323 DEBUG 43359 --- [pool-1-thread-6] o.s.a.r.listener.BlockingQueueConsumer : Storing delivery for consumerTag: 'amq.ctag-eYbzZ09pCw3cjdtSprlZMQ' with deliveryTag: '1' in Consumer#4b790d86: tags=[{amq.ctag-eYbzZ09pCw3cjdtSprlZMQ=myapp.myevent.ALERT}], channel=Cached Rabbit Channel: AMQChannel(amqp://guest#127.0.0.1:5672/,2), conn: Proxy#77f3f419 Shared Rabbit Connection: SimpleConnection#10c86af1 [delegate=amqp://guest#127.0.0.1:5672/, localPort= 56220], acknowledgeMode=AUTO local queue size=0
2018-10-17 12:14:45.324 DEBUG 43359 --- [ontainerReset-1] o.s.a.r.listener.BlockingQueueConsumer : Received message: (Body:'{"timestamp":1539792885303,"code":"ERROR","severity":"ERROR","message":"Exception detected. Message: Listener method 'kpisEvent' threw exception"}' MessageProperties [headers={sender=myapp, protocolVersion=1.0.0, senderType=MY_COMPONENT_1, __TypeId__=com.test.domain.Alert, timestamp=1539792885304}, contentType=application/json, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=myevent.ALERT, receivedRoutingKey=/, deliveryTag=1, consumerTag=amq.ctag-eYbzZ09pCw3cjdtSprlZMQ, consumerQueue=myapp.myevent.ALERT])
2018-10-17 12:14:45.324 INFO 43359 --- [ontainerReset-1] Application : ---> kpisAlert RECEIVED
2018-10-17 12:14:45.325 ERROR 43359 --- [ontainerReset-1] Application : ---> Message: Exception detected. Message: Listener method 'kpisEvent' threw exception
2018-10-17 12:14:45.326 DEBUG 43359 --- [containerKpis-1] o.s.a.r.listener.BlockingQueueConsumer : Rejecting messages (requeue=false)
EDIT3
Or, if you prefer Gson...
#Bean
public MessageConverter json() {
Gson gson = new GsonBuilder().create();
return new MessageConverter() {
#Override
public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
return new Message(gson.toJson(object).getBytes(), messageProperties);
}
#Override
public Object fromMessage(Message message) throws MessageConversionException {
throw new UnsupportedOperationException();
}
};
}
EDIT4
I changed the current version of your app as follows:
#Bean
public MessageConverter jsonConverter() {
Gson gson = new GsonBuilder().create();
EventKpisCollected collected = new EventKpisCollected();
return new MessageConverter() {
#Override
public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
System.out.println("toMessage");
return new Message(gson.toJson(object).getBytes(), messageProperties);
}
#Override
public Object fromMessage(Message message) throws MessageConversionException {
System.out.println("fromMessage");
return collected.decode(new String(message.getBody()));
}
};
}
...
#Bean
SimpleMessageListenerContainer containerKpis(ConnectionFactory connectionFactory,
MessageListenerAdapter listenerKpisAdapter) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setDefaultRequeueRejected(false);
container.setErrorHandler(errorHandler());
container.setQueueNames(getQueueKpis());
container.setMessageListener(listenerKpisAdapter);
return container;
}
#Bean
SimpleMessageListenerContainer containerReset(ConnectionFactory connectionFactory,
MessageListenerAdapter listenerAlertAdapter) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setDefaultRequeueRejected(false);
container.setErrorHandler(errorHandler());
container.setQueueNames(getQueueAlert());
container.setMessageListener(listenerAlertAdapter);
return container;
}
#Bean
MessageListenerAdapter listenerKpisAdapter(Application receiver) {
MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(receiver, "kpisEvent");
messageListenerAdapter.setMessageConverter(jsonConverter());
return messageListenerAdapter;
}
#Bean
MessageListenerAdapter listenerAlertAdapter(Application receiver) {
MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(receiver, "alertEvent");
// messageListenerAdapter.setMessageConverter(jsonConverter()); converter only handles events.
return messageListenerAdapter;
}
and
fromMessage
2018-10-19 13:46:53.734 INFO 10725 --- [containerKpis-1] Application : ---> kpisEvent RECEIVED
2018-10-19 13:46:53.734 INFO 10725 --- [containerKpis-1] Application : ---> kpisEvent DECODED, windowId: 1522751098000-1522752198000
With the event decoding done by the framework (just for the event currently - you will need a second converter for the alers).

can I use xml wire with java annotation in spring

I have a class of GenerateKey which is for spring mvc boot. Since it needs to contact database and message queue, so I tried to wire it using xml
#RestController
public class GenerateKey {
final private DriverManagerDataSource dataSource;
final private AmqpTemplate rabbitMQTemplate;
final private String queueName;
public GenerateKey(DriverManagerDataSource dataSource,AmqpTemplate rabbitMQTemplate,String queueName){
this.dataSource=dataSource;
this.rabbitMQTemplate =rabbitMQTemplate;
this.queueName =queueName;
}
#RequestMapping("/key/generate")
public String generateKey(#RequestParam(value = "businesskey") String businesskey, #RequestParam(value = "customer") String customer, Model model) {
JdbcTemplate jdbctemplate = new JdbcTemplate(dataSource);
JSONObject obj = new JSONObject();
obj.put("businesskey", businesskey);
obj.put("customer", customer);
rabbitMQTemplate.convertAndSend(queueName, obj.toString());
System.out.println(businesskey+customer);
return "greeting" + businesskey + customer;
}
}
the xml configurations is as the following and using
#ImportResource( { "rabbit-listener-context.xml" } )
to import it
<bean id="request" class="com.testcom.keyservice.GenerateKey" c:dataSource-ref="dataSource" c:rabbitMQTemplate-ref="keyRequestTemplate" c:queueName="${keyRequestQueueName}"/>
but it complain "No default constructor found" as following:
2014-11-26 21:42:16.095 INFO 17400 --- [ main] utoConfigurationReportLoggingInitializer :
Error starting ApplicationContext. To display the auto-configuration report enabled debug logging (start with --debug)
2014-11-26 21:42:16.097 ERROR 17400 --- [ main] o.s.boot.SpringApplication : Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'generateKey' defined in file [/home/oracle/NetBeansProjects/rabbitmq-native/keyService/build/classes/main/com/testcom/keyservice/GenerateKey.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.testcom.keyservice.GenerateKey]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.testcom.keyservice.GenerateKey.<init>()
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1040)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:505)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
Exception in thread "main" at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicatixt.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
Since you are using Spring Boot I assume you have also #ComponentScan active in your application. Because of that you create two instances of GenerateKey class - once because of #RestController annotation, second time in XML. I believe that's not what you want to achieve.
Get rid of XML declaration of request bean representing GeneratorKey class and use only Java based autowiring.
#RestController
public class GenerateKey {
private final DriverManagerDataSource dataSource;
private final AmqpTemplate rabbitMQTemplate;
private final String queueName;
#Autowired
public GenerateKey(#Qualifier("dataSource") DriverManagerDataSource dataSource, #Qualifier("keyRequestTemplate") AmqpTemplate rabbitMQTemplate, #Value("${keyRequestQueueName}") String queueName) {
this.dataSource=dataSource;
this.rabbitMQTemplate =rabbitMQTemplate;
this.queueName =queueName;
}

Resources