I am working on homework to my studies with Java and RabbitMQ. I am not familiar much with Spring and RabbitMQ, but I can't handle this problem.
I have 2 single application.
First one, which produces the message (bolid application)
I created a producer of the message (bolid), which every 10 seconds send a message to listeners
#SpringBootApplication
public class BolidApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(BolidApplication.class, args);
}
#Autowired
private RabbitTemplate rabbitTemplate;
#Override
public void run(String... args) throws Exception {
Bolid bolid = new Bolid();
int i = 10;
while (true) {
bolid.setData(new Date());
rabbitTemplate.setReplyAddress("bolidReply");
rabbitTemplate.convertAndSend("RaceExchange", "raceRouting", bolid.toString());
rabbitTemplate.convertAndSend("MonitorExchange", "raceRouting", bolid.toString());
Thread.sleep(15000);
i += 10;
}
}
}
So, I create 2 queue (RaceQueue and MonitorQueue), define exchange and bind them.
I have 2 listeners: RaceListener and MonitorListener.
There is the code of my listeners:
And the second application, which is listeners.
public class RabbitConfig {
private static final String RACE_QUEUE = "RaceQueue";
private static final String MONITOR_QUEUE = "MonitorQueue";
#Bean
Queue myQueue() {
return new Queue(RACE_QUEUE, true);
}
#Bean
Queue monitorQueue() {
return new Queue(MONITOR_QUEUE, true);
}
#Bean
Exchange myExchange() {
return ExchangeBuilder.topicExchange("RaceExchange")
.durable(true)
.build();
}
#Bean
Exchange monitorExchange() {
return ExchangeBuilder.topicExchange("MonitorExchange")
.durable(true)
.build();
}
#Bean
Binding binding() {
// return new Binding(MY_QUEUE, Binding.DestinationType.QUEUE, "MyTopicExchange", "topic", null)
return BindingBuilder
.bind(myQueue())
.to(myExchange())
.with("raceRouting")
.noargs();
}
#Bean
Binding monitorBinding() {
return BindingBuilder
.bind(monitorQueue())
.to(monitorExchange())
.with("raceRouting")
.noargs();
}
#Bean
ConnectionFactory connectionFactory() {
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory("localhost");
cachingConnectionFactory.setUsername("guest");
cachingConnectionFactory.setPassword("guest");
return cachingConnectionFactory;
}
#Bean
MessageListenerContainer rabbitRaceListener() {
SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer();
simpleMessageListenerContainer.setConnectionFactory(connectionFactory());
simpleMessageListenerContainer.setQueues(myQueue());
simpleMessageListenerContainer.setupMessageListener(new RabbitRaceListener());
return simpleMessageListenerContainer;
}
#Bean
MessageListenerContainer rabbitMonitorListener() {
SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer();
simpleMessageListenerContainer.setConnectionFactory(connectionFactory());
simpleMessageListenerContainer.setQueues(monitorQueue());
simpleMessageListenerContainer.setupMessageListener(new RabbitMonitorListener());
return simpleMessageListenerContainer;
}
}
From MonitorListener I want to use reply pattern to reply message to my first application (bolid application). So Bolid application can receive my message.
My Code for MonitorListener:
public class RabbitMonitorListener implements MessageListener {
#Autowired
private RabbitTemplate rabbitTemplate;
#Override
public void onMessage(Message message) {
String[] splitted = new String(message.getBody()).split("\\|");
int oilTemperature = Integer.parseInt(splitted[1].split(" ")[2]);
int engineTemperature = Integer.parseInt(splitted[2].split(" ")[2]);
int tirePressure = Integer.parseInt(splitted[3].split(" ")[2]);
System.out.println("message2 = [" + new String(message.getBody()) + "]");
if (oilTemperature > 120 || engineTemperature > 120 || tirePressure > 12) {
System.out.println("SEND REPLY TO BOLID!");
}
if (oilTemperature > 150 || engineTemperature > 150 || tirePressure > 17) {
System.out.println("SEND RELY TO BOLID!");
}
}
}
How can I achieve that? So here I can send the message go back to bolid and on the bolid application I can read it?
EDIT:
I did some research, I want to do it like this way:
public class RabbitMonitorListener implements MessageListener {
#Autowired
private RabbitTemplate rabbitTemplate;
#Override
public void onMessage(Message message) {
String[] splitted = new String(message.getBody()).split("\\|");
int oilTemperature = Integer.parseInt(splitted[1].split(" ")[2]);
int engineTemperature = Integer.parseInt(splitted[2].split(" ")[2]);
int tirePressure = Integer.parseInt(splitted[3].split(" ")[2]);
String response = "Hello";
MessageProperties properties = new MessageProperties();
Message responseMessage = new Message(response.getBytes(), properties);
rabbitTemplate.send(message.getMessageProperties().getReplyTo(), responseMessage);
System.out.println("message2 = [" + new String(message.getBody()) + "]");
if (oilTemperature > 120 || engineTemperature > 120 || tirePressure > 12) {
System.out.println("WARN MECHANICS");
}
if (oilTemperature > 150 || engineTemperature > 150 || tirePressure > 17) {
System.out.println("WARN MECHANICS");
}
}
}
but the rabbitTemplate is null here, so I can't #Autowired it here. How can I have access to rabbitTemplate and method send in MessageListener?
new RabbitRaceListener() - that must be a #Bean too, to get auto wiring.
However, you are over-complicating things; the framework can take care of all of this for you.
See Request/Reply Messaging for the client side - and use convertSendAndReceive() or convertSendAndReceiveAsType().
On the server side, see Annotation-driven Listener Endpoints.
#RabbitListener(queues = "request")
public String handle(String in) {
return in.toUpperCase();
}
Related
We have an order managament system in which after every order state update we make an api call to our client to keep them updated. We do this by first sending a message to a sqs queue and inside a consumer we hit our clients api. The processing on consumer side usually takes about 300-350ms but The approximate age of oldest message in sqs dashboard is showing spikes that reach upto 50-60 secs.
Seeing this I thought that maybe one consumer is not enough for our load and I created multiple DMLC beans and multiple copies of our consumer class. I attached these consumer classes as listeners in these DMLCs. But I have not seen any improvement in approximate age of oldest message.
I am guessing that maybe only one of the DMLC is processing these messages and others are just sitting idle.
I added multiple DMLCs because there are other places in pur codebase where the same thing is used, But now I am not sure if this is the correct way to solve the problem.
My Consumer class looks like this:
#Component
#Slf4j
#RequiredArgsConstructor
public class HOAEventsOMSConsumer extends ConsumerCommon implements MessageListener {
private static final int MAX_RETRY_LIMIT = 3;
private final OMSEventsWrapper omsEventsWrapper;
#Override
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage) message;
String jmsMessageId = textMessage.getJMSMessageID();
ConsumerLogging.logStart(jmsMessageId);
String text = textMessage.getText();
log.info(
"Inside HOA Events consumer Request jmsMessageId:- " + jmsMessageId + " Text:- "
+ text);
processAndAcknowledge(message, text, textMessage);
} catch (JMSException e) {
log.error("JMS Exception while processing surge message", e);
}
}
private void processAndAcknowledge(Message message, String text, TextMessage textMessage) throws JMSException {
try {
TrimmedHOAEvent hoaEvent = JsonHelper.convertFromJsonPro(text, TrimmedHOAEvent.class);
if (hoaEvent == null) {
throw new OMSValidationException("Empty message in hoa events queue");
}
EventType event = EventType.fromString(textMessage.getStringProperty("eventType"));
omsEventsWrapper.handleOmsEvent(event,hoaEvent);
acknowledgeMessage(message);
} catch (Exception e) {
int retryCount = message.getIntProperty("JMSXDeliveryCount");
log.info("Retrying... retryCount: {}, HOAEventsOMSConsumer: {}", retryCount, text);
if (retryCount > MAX_RETRY_LIMIT) {
log.info("about to acknowledge the message since it has exceeded maximum retry limit");
acknowledgeMessage(message);
}
}
}
}
And my DMLC configuration class looks like this:
#Configuration
#SuppressWarnings("unused")
public class HOAEventsOMSJMSConfig extends JMSConfigCommon{
private Boolean isSQSQueueEnabled;
#Autowired
private HOAEventsOMSConsumer hoaEventsOMSConsumer;
#Autowired
private HOAEventsOMSConsumer2 hoaEventsOMSConsumer2;
#Autowired
private HOAEventsOMSConsumer3 hoaEventsOMSConsumer3;
#Autowired
private HOAEventsOMSConsumer4 hoaEventsOMSConsumer4;
#Autowired
private HOAEventsOMSConsumer5 hoaEventsOMSConsumer5;
#Autowired
private HOAEventsOMSConsumer6 hoaEventsOMSConsumer6;
#Autowired
private HOAEventsOMSConsumer7 hoaEventsOMSConsumer7;
#Autowired
private HOAEventsOMSConsumer8 hoaEventsOMSConsumer8;
#Autowired
private HOAEventsOMSConsumer9 hoaEventsOMSConsumer9;
#Autowired
private HOAEventsOMSConsumer10 hoaEventsOMSConsumer10;
public HOAEventsOMSJMSConfig(IPropertyService propertyService, Environment env) {
queueName = env.getProperty("aws.sqs.queue.oms.hoa.events.queue");
endpoint = env.getProperty("aws.sqs.queue.endpoint") + queueName;
JMSConfigCommon.accessId = env.getProperty("aws.sqs.access.id");
JMSConfigCommon.accessKey = env.getProperty("aws.sqs.access.key");
try {
ServerNameCache serverNameCache = CacheManager.getInstance().getCache(ServerNameCache.class);
if (serverNameCache == null) {
serverNameCache = new ServerNameCache();
serverNameCache.set(InetAddress.getLocalHost().getHostName());
CacheManager.getInstance().setCache(serverNameCache);
}
this.isSQSQueueEnabled = propertyService.isConsumerEnabled(serverNameCache.get(), false);
} catch (Exception e) {
this.isSQSQueueEnabled = false;
}
}
#Bean
public JmsTemplate omsHOAEventsJMSTemplate(){
SQSConnectionFactory sqsConnectionFactory;
if (endpoint.toLowerCase().contains("localhost")) {
sqsConnectionFactory =
SQSConnectionFactory.builder().withEndpoint(getEndpoint("sqs")).build();
} else {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withAWSCredentialsProvider(awsCredentialsProvider)
.withNumberOfMessagesToPrefetch(10)
.withEndpoint(endpoint)
.build();
}
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(sqsConnectionFactory);
JmsTemplate jmsTemplate = new JmsTemplate(cachingConnectionFactory);
jmsTemplate.setDefaultDestinationName(queueName);
jmsTemplate.setDeliveryPersistent(false);
jmsTemplate.setSessionTransacted(false);
jmsTemplate.setSessionAcknowledgeMode(SQSSession.UNORDERED_ACKNOWLEDGE);
return jmsTemplate;
}
#Bean
public DefaultMessageListenerContainer jmsListenerHOAEventsListenerContainer() {
SQSConnectionFactory sqsConnectionFactory;
if (endpoint.toLowerCase().contains("localhost")) {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withEndpoint(getEndpoint("sqs"))
.build();
} else {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withAWSCredentialsProvider(awsCredentialsProvider)
.withNumberOfMessagesToPrefetch(10)
.withEndpoint(endpoint)
.build();
}
DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
dmlc.setConnectionFactory(sqsConnectionFactory);
dmlc.setDestinationName(queueName);
dmlc.setAutoStartup(isSQSQueueEnabled);
dmlc.setMessageListener(hoaEventsOMSConsumer);
dmlc.setSessionTransacted(false);
dmlc.setSessionAcknowledgeMode(SQSSession.UNORDERED_ACKNOWLEDGE);
return dmlc;
}
#Bean
public DefaultMessageListenerContainer jmsListenerHOAEventsListenerContainerNo2() {
SQSConnectionFactory sqsConnectionFactory;
if (endpoint.toLowerCase().contains("localhost")) {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withEndpoint(getEndpoint("sqs"))
.build();
} else {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withAWSCredentialsProvider(awsCredentialsProvider)
.withNumberOfMessagesToPrefetch(10)
.withEndpoint(endpoint)
.build();
}
DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
dmlc.setConnectionFactory(sqsConnectionFactory);
dmlc.setDestinationName(queueName);
dmlc.setAutoStartup(isSQSQueueEnabled);
dmlc.setMessageListener(hoaEventsOMSConsumer2);
dmlc.setSessionTransacted(false);
dmlc.setSessionAcknowledgeMode(SQSSession.UNORDERED_ACKNOWLEDGE);
return dmlc;
}
#Bean
public DefaultMessageListenerContainer jmsListenerHOAEventsListenerContainerNo3() {
SQSConnectionFactory sqsConnectionFactory;
if (endpoint.toLowerCase().contains("localhost")) {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withEndpoint(getEndpoint("sqs"))
.build();
} else {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withAWSCredentialsProvider(awsCredentialsProvider)
.withNumberOfMessagesToPrefetch(10)
.withEndpoint(endpoint)
.build();
}
DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
dmlc.setConnectionFactory(sqsConnectionFactory);
dmlc.setDestinationName(queueName);
dmlc.setAutoStartup(isSQSQueueEnabled);
dmlc.setMessageListener(hoaEventsOMSConsumer3);
dmlc.setSessionTransacted(false);
dmlc.setSessionAcknowledgeMode(SQSSession.UNORDERED_ACKNOWLEDGE);
return dmlc;
}
}
If this question is already answered somehwere else, then please point me towards that.
I am using the springboot and rabitmq. I have kind of similar scenario here.
I would like to map my message to custom java object
I also want pass delivery tag which is message proprieties
I wann to pass Channel as well beacuse I need to manual ack messages
My code is like this
#RunWith(SpringRunner.class)
public class EPPQ2SubscriberTest {
#Autowired
private RabbitListenerEndpointRegistry registry;
public final String sampleMessage = "{" + "\"header\": {" + "\"RETRY_COUNT\":0," + "\"PUBLISH_EVENT_TYPE\":\"AUTH\""
+ "}," + "\"payLoad\":{" + "\"MTI\": \"120\"," + "\"MTI_REQUEST\": \"120\","
+ "\"PAN\": \"6011000000000000\"" + "}" + "}";
#Test
public void message_converter_test() throws Exception {
SimpleMessageListenerContainer container = (SimpleMessageListenerContainer) this.registry
.getListenerContainer("messageListener");
ChannelAwareMessageListener listener = (ChannelAwareMessageListener) container.getMessageListener();
Message message = MessageBuilder.withBody(sampleMessage.getBytes())
.andProperties(MessagePropertiesBuilder.newInstance().setContentType("application/json").build())
.build();
listener.onMessage(message, mock(Channel.class));
}
#Configuration
#EnableRabbit
public static class config {
#Bean
public ConnectionFactory mockConnectionFactory() {
return mock(ConnectionFactory.class);
}
#Bean
public MessageConverter messageConverter() {
Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter();
/*
* DefaultClassMapper classMapper = new DefaultClassMapper();
* classMapper.setDefaultType(com.discover.dftp.scrubber.domain.Message.class);
* messageConverter.setClassMapper(classMapper);
*/
return messageConverter;
}
#Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(mockConnectionFactory());
factory.setMessageConverter(messageConverter());
factory.setAutoStartup(false);
return factory;
}
#Bean
public EPPQ2Subscriber messageListener() {
return new EPPQ2Subscriber();
}
}
}
#Component
public class EPPQ2Subscriber {
private static final Logger LOGGER = LoggerFactory.getLogger(EPPQ2Subscriber.class);
// #RabbitListener(queues = "#{queue.getName()}") #TODO I wann to use this in
// later point in time.. !
#RabbitListener(id = "messageListener", queues = "TestQueue")
public void receiveMessage(Message message, Channel channel/* ,#Header(AmqpHeaders.DELIVERY_TAG) long tag */) {
LOGGER.info("Method receiveMessage invoked");
message.getMessageProperties().getDeliveryTag();
LOGGER.info("Result:" + message.getClass() + ":" + message.toString());
}
}
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
private Map<String, Object> header;
private Map<String, Object> payLoad;
public Map<String, Object> getHeader() {
return header;
}
public void setHeader(Map<String, Object> header) {
this.header = header;
}
public Map<String, Object> getPayLoad() {
return payLoad;
}
public void setPayLoad(Map<String, Object> payLoad) {
this.payLoad = payLoad;
}
#Override
public String toString() {
return "Header [header=" + this.header + ", payLoad=" + this.payLoad + "]";
}
}
#RabbitListener(id = "messageListener", queues = "TestQueue")
public void receiveMessage(Message message, Channel channel/* ,#Header(AmqpHeaders.DELIVERY_TAG) long tag */) {
LOGGER.info("Method receiveMessage invoked");
message.getMessageProperties().getDeliveryTag();
LOGGER.info("Result:" + message.getClass() + ":" + message.toString());
}
I looks like that method receives the raw (unconverted) Spring AMQP Message (you are importing the wrong Message class in EPPQ2Subscriber).
#Configuration
#Component
public class GatewayAqrConfig {
#Autowired
ConnectorService connectorService;
#Autowired
MasterService masterService;
private HashMap<ConnectorPK, GatewayAqr> connectorMap;
#Bean
#Scope(value = "prototype")
public AbstractClientConnectionFactory clientCF(Connector connector , Master master) {
TcpNetClientConnectionFactory clientConnectionFactory = new TcpNetClientConnectionFactory(connector.getAqrIpAddr(), connector.getAqrIpPortNo());
clientConnectionFactory.setSingleUse(false);
MyByteArraySerializer obj = new MyByteArraySerializer(master.getAqrMsgHeaderLength(), master.getAqrId());
clientConnectionFactory.setSerializer(obj);
clientConnectionFactory.setDeserializer(obj);
clientConnectionFactory.setSoKeepAlive(true);
TcpMessageMapper tcpMessageMapper = new TcpMessageMapper();
tcpMessageMapper.setCharset("ISO-8859-1");
clientConnectionFactory.setMapper(tcpMessageMapper);
clientConnectionFactory.setBeanName(connector.getAqrIpAddr() + ":" + connector.getAqrIpPortNo());
clientConnectionFactory.afterPropertiesSet();
clientConnectionFactory.start();
return clientConnectionFactory;
}
#Bean
#Scope(value = "prototype")
public TcpSendingMessageHandler tcpOutGateway(AbstractClientConnectionFactory connectionFactory) {
TcpSendingMessageHandler messageHandler = new TcpSendingMessageHandler();
messageHandler.setConnectionFactory(connectionFactory);
messageHandler.setClientMode(true);
messageHandler.setTaskScheduler(getTaskScheduler());
messageHandler.setStatsEnabled(true);
messageHandler.afterPropertiesSet();
messageHandler.start();
return messageHandler;
}
#Bean
#Scope(value = "prototype")
public TcpReceivingChannelAdapter tcpInGateway(AbstractClientConnectionFactory connectionFactory) {
TcpReceivingChannelAdapter messageHandler = new TcpReceivingChannelAdapter();
messageHandler.setConnectionFactory(connectionFactory);
messageHandler.setClientMode(true);
messageHandler.setOutputChannel(receive());
messageHandler.setAutoStartup(true);
messageHandler.setTaskScheduler(getTaskScheduler());
messageHandler.afterPropertiesSet();
messageHandler.start();
return messageHandler;
}
#Bean
#Scope(value = "prototype")
public TaskScheduler getTaskScheduler() {
TaskScheduler ts = new ThreadPoolTaskScheduler();
return ts;
}
#Bean
public MessageChannel receive() {
QueueChannel channel = new QueueChannel();
return channel;
}
#Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata poller() {
return new PollerMetadata();
}
#Bean
#Transactional
public HashMap<ConnectorPK, GatewayAqr> gatewayAqr() throws Exception {
connectorMap = new HashMap();
Connector connector = null;
ConnectorPK connectorPK = null;
Master master = null;
TcpConnectionSupport connectionSupport = null;
// 1. Get List of Connections configured in Database
List<Connector> connectors = connectorService.getConnections();
if (connectors.size() > 0) {
for (int i = 0; i < connectors.size(); i++) {
// 2. Get the connection details
connector = connectors.get(i);
connectorPK = aqrConnector.getConnectorpk();
master = masterService.findById(connectorPK.getAcuirerId());
try {
// 3. Create object of TcpNetClientConnectionFactory for each Acquirer connection
AbstractClientConnectionFactory clientConnectionFactory = clientCF(aqrConnector, aqrMaster);
// 4. Create TcpSendingMessageHandler for the Connection
TcpSendingMessageHandler outHandler = tcpOutGateway(clientConnectionFactory);
// 5. Create TcpReceivingChannelAdapter object for the Connection and assign it to receive channel
TcpReceivingChannelAdapter inHandler = tcpInGateway(clientConnectionFactory);
// 6. Generate the GatewayAqr object
GatewayAqr gatewayAqr = new GatewayAqr(clientConnectionFactory, outHandler, inHandler);
// 7. Put in the MAP acuirerPK and Send MessageHandler object
connectorMap.put(aqrConnectorPK, gatewayAquirer);
} catch (Exception e) {
}
} // for
} // if
return connectorMap;
}
}
*********************************************************************************************************************************
#EnableIntegration
#IntegrationComponentScan(basePackageClasses = {GatewayEventConfig.class,GatewayAqrConfig.class })
#Configuration
#ComponentScan(basePackages = {"com.iz.zw.gateway.impl", "com.iz.zw.configuration"})
#Import({GatewayEventConfig.class,GatewayAquirerConfig.class})
public class GatewayConfig {
#Autowired
private GatewayAsyncReply<Object, Message<?>> gatewayAsyncReply;
#Autowired
private GatewayCorrelationStrategy gatewayCorrelationStrategy;
#Autowired
private HashMap<ConnectorPK, GatewayAqr> gatewayAqrs;
#Autowired
ConnectorService connectorService;
#Autowired
GatewayResponseDeserializer gatewayResponseDeserializer;
#MessagingGateway(defaultRequestChannel = "send")
public interface Gateway {
void waitForResponse(TransactionMessage transaction);
}
#Bean
public MessageChannel send() {
DirectChannel channel = new DirectChannel();
return channel;
}
#Bean
#ServiceActivator(inputChannel = "send")
public BarrierMessageHandlerWithLateGoodResponse barrier() {
BarrierMessageHandlerWithLateGoodResponse barrier = new BarrierMessageHandlerWithLateGoodResponse(25000, this.gatewayCorrelationStrategy);
barrier.setAsync(true);
barrier.setOutputChannel(out());
barrier.setDiscardChannel(lateGoodresponseChannel());
return barrier;
}
#ServiceActivator(inputChannel = "out")
public void printMessage(Message<?> message) {
System.out.println("in out channel");
}
#Transformer(inputChannel = "receive", outputChannel = "process")
public TransactionMessage convert(byte[] response) {
logger.debug("Response Received", Arrays.toString(response));
TransactionMessage transactionMessage = gatewayResponseDeserializer.deserializeResponse(response);
System.out.println("Response : " + response);
return transactionMessage;
}
#ServiceActivator(inputChannel = "process")
#Bean
public MessageHandler releaser() {
return new MessageHandler() {
#Override
public void handleMessage(Message<?> message) throws MessagingException {
try {
gatewayAsyncReply.put(message);
barrier().trigger(message);
} catch (GatewayLateGoodMessageException exception) {
System.out.println("Late good response..!");
gatewayAsyncReply.get(message);
lateGoodresponseChannel().send(message);
}
}
};
}
#Bean
public MessageChannel process() {
QueueChannel channel = new QueueChannel();
return channel;
}
#Bean
public MessageChannel out() {
DirectChannel channel = new DirectChannel();
return channel;
}
#Bean
public MessageChannel lateGoodresponseChannel() {
QueueChannel channel = new QueueChannel();
return channel;
}
#ServiceActivator(inputChannel="lateGoodresponseChannel")
public void handleLateGoodResponse(Message<?> message) {
String strSTAN = null;
String strResponse = null;
Message<?> respMessage = null;
if(message instanceof TransactionMessage){
strSTAN = ((TransactionMessage)message).getStan();
respMessage = gatewayAsyncReply.get(strSTAN);
if (null != respMessage) {
strResponse = (String) message.getPayload();
}
}
logger.info("Late Good Response: " + strResponse);
}
}
*********************************************************************************************************************************
#Configuration
public class GatewayEventConfig {
private static final Logger logger = LoggerFactory.getLogger(GatewayEventConfig.class);
#Bean
public ApplicationEventListeningMessageProducer tcpEventListener() {
ApplicationEventListeningMessageProducer producer = new ApplicationEventListeningMessageProducer();
producer.setEventTypes(new Class[] {TcpConnectionOpenEvent.class, TcpConnectionCloseEvent.class, TcpConnectionExceptionEvent.class});
producer.setOutputChannel(tcpEventChannel());
producer.setAutoStartup(true);
producer.setTaskScheduler(getEventTaskScheduler());
producer.start();
return producer;
}
#Bean
public TaskScheduler getEventTaskScheduler() {
TaskScheduler ts = new ThreadPoolTaskScheduler();
return ts;
}
#Bean
public MessageChannel tcpEventChannel() {
return new QueueChannel();
}
#Transactional
#ServiceActivator(inputChannel = "tcpEventChannel")
public void tcpConnectionEvent(TcpConnectionEvent event) {
System.out.println("In publishing" + event.toString());
String strConnectionFactory = event.getConnectionFactoryName();
if (strConnectionFactory.equals("connection1")) {
//send some message to connector
} else {
// send message to another connector
}
}
}
this is my configuration files, my application tries to connect to 2 servers as soon as it starts.
I have made 2 configurations for 2 servers as above class
GatewayAqrConfig1 and GatewayConfig1 classes are used for first server connection
GatewayAqrConfig2 and GatewayConfig2 classes are used for second server connection
Using event I am connecting to server and sending a connection set up message, if server is already started and If I have started my application,
it gets the event, connects and sends the message but I am not getting the response instead I am getting the WARNING as below
**WARN TcpNetConnection:186 - Unexpected message - no endpoint registered with connection interceptor:**
i.e connection does not registers the listener properly
but if I am starting my application first and then servers I am getting responses perfectly, As I am connecting to servers
I could not restart it ? My application should connect to server which is already started ? what could be the problem ?
Version used:
Spring integration Version : 4.3.1
Spring version : 4.3.2
JDK 1.8 on JBOSS EAP 7
That WARN message means that, somehow, an inbound message was received without a TcpReceivingChannelAdapter having been registered with the connection factory. Client mode should make no difference.
Having looked at your code a little more, the prototype beans should be ok, as long as you use those objects (especially TcpMessageHandler directly rather than via the framework).
It's not obvious to me how that can happen, given your configuration; the listener is registered when you call setConnectionFactory on the receiving adapter.
If you can reproduce it with a trimmed-down project and post it someplace, I will take a look.
making my previous question more readable, following is my code which works fine for single server single client connection, but i want my client to connect 2 or more servers dynamically,
public class ClientCall {
public static void main(String[] args) {
#SuppressWarnings("resource")
ApplicationContext ctx = new AnnotationConfigApplicationContext(GatewayConfig.class);
GatewayService gatewayService = ctx.getBean(GatewayService.class);
//int i=0;
Message message = new Message();
/*while(i<4)
{*/
message.setPayload("It's working");
gatewayService.sendMessage(message);
/* i++;
}*/
}
}
public class Message {
private String payload;
// getter setter
}
#EnableIntegration
#IntegrationComponentScan
#Configuration
#ComponentScan(basePackages = "com.gateway.service")
public class GatewayConfig {
// #Value("${listen.port:6788}")
private int port = 6785;
#Autowired
private GatewayService<Message> gatewayService;
#MessagingGateway(defaultRequestChannel = "sendMessageChannel")
public interface Gateway {
void viaTcp(String payload);
}
#Bean
public AbstractClientConnectionFactory clientCF() {
TcpNetClientConnectionFactory clientConnectionFactory = new TcpNetClientConnectionFactory("localhost",
this.port);
clientConnectionFactory.setSingleUse(false);
return clientConnectionFactory;
}
#Bean
#ServiceActivator(inputChannel = "sendMessageChannel")
public MessageHandler tcpOutGateway(AbstractClientConnectionFactory connectionFactory) {
TcpOutboundGateway outGateway = new TcpOutboundGateway();
outGateway.setConnectionFactory(connectionFactory);
// outGateway.setAsync(true);
outGateway.setOutputChannel(receiveMessageChannel());
outGateway.setRequiresReply(true);
outGateway.setReplyChannel(receiveMessageChannel());
return outGateway;
}
#Bean
public MessageChannel sendMessageChannel() {
DirectChannel channel = new DirectChannel();
return channel;
}
#Bean
public MessageChannel receiveMessageChannel() {
DirectChannel channel = new DirectChannel();
return channel;
}
#Transformer(inputChannel = "receiveMessageChannel", outputChannel = "processMessageChannel")
public String convert(byte[] bytes) {
return new String(bytes);
}
#ServiceActivator(inputChannel = "processMessageChannel")
public void upCase(String response) {
gatewayService.receiveMessage(response);
}
#Transformer(inputChannel = "errorChannel", outputChannel = "processMessageChannel")
public void convertError(byte[] bytes) {
String str = new String(bytes);
System.out.println("Error: " + str);
}
}
public interface GatewayService<T> {
public void sendMessage(final T payload);
public void receiveMessage(String response);
}
#Service
public class GatewayServiceImpl implements GatewayService<Message> {
#Autowired
private Gateway gateway;
#Autowired
private GatewayContextManger<String, Object> gatewayContextManger;
#Override
public void sendMessage(final Message message) {
new Thread(new Runnable() {
#Override
public void run() {
gateway.viaTcp(message.getPayload());
}
}).start();
}
#Override
public void receiveMessage(final String response) {
new Thread(new Runnable() {
#Override
public void run() {
Message message = new Message();
message.setPayload(response);
Object obj = gatewayContextManger.get(message.getPayload());
synchronized (obj) {
obj.notify();
}
}
}).start();
}
}
and below is sever code similar there is another server with different port and ip then how to make connections to these servers?
class TCPServer
{
public static void main(String argv[]) throws Exception
{
String clientSentence;
String capitalizedSentence;
ServerSocket welcomeSocket = new ServerSocket(6785);
while(true)
{
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient =
new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
clientSentence = inFromClient.readLine();
System.out.println("Received: " + clientSentence);
capitalizedSentence = clientSentence + "\r\n";
outToClient.writeBytes(capitalizedSentence);
}
}
}
A few comments.
Instead of starting a thread to send the message, simply make sendMessageChannel an ExecutorChannel, using a ThreadPoolTaskExecutor - it will be more efficient and gets you out of the business of managing threads.
If you only have 2 servers to connect to, rather than coming up with a dynamic scheme, simply define 2 TCP adapters and add a #Router after sendMessageChannel.
You can tell the router which server to send it to by setting a header.
#MessagingGateway(defaultRequestChannel = "sendMessageChannel")
public interface Gateway {
void viaTcp(String payload #Header("which") String target);
}
Use a HeaderValueRouter to route on header which.
See Message Routing in the reference manual.
I have one server and number of clients, server will send response and waits for acknowledgement, additionally I want to hold that connection forever for next message and acknowledgement how should i create these connection in Spring Integration. I read about Spring integration, i couldn't find out the solution for holding the connection.
public class ClientCall {
public static void main(String[] args) {
#SuppressWarnings("resource")
ApplicationContext ctx = new AnnotationConfigApplicationContext(GatewayConfig.class);
GatewayService gatewayService = ctx.getBean(GatewayService.class);
//int i=0;
Message message = new Message();
/*while(i<4)
{*/
message.setPayload("It's working");
gatewayService.sendMessage(message);
/* i++;
}*/
}
}
#Service
public interface GatewayService<T> {
public void sendMessage(final T payload);
public void receiveMessage(String response);
}
#EnableIntegration
#IntegrationComponentScan
#Configuration
#ComponentScan(basePackages = "com.gateway.service")
public class GatewayConfig {
// #Value("${listen.port:6788}")
private int port = 6785;
#Autowired
private GatewayService<Message> gatewayService;
#MessagingGateway(defaultRequestChannel = "sendMessageChannel")
public interface Gateway {
void viaTcp(String payload);
}
#Bean
public AbstractClientConnectionFactory clientCF() {
TcpNetClientConnectionFactory clientConnectionFactory = new TcpNetClientConnectionFactory("localhost",this.port);
clientConnectionFactory.setSingleUse(true);
return clientConnectionFactory;
}
#Bean
#ServiceActivator(inputChannel = "sendMessageChannel")
public MessageHandler tcpOutGateway(AbstractClientConnectionFactory connectionFactory) {
TcpOutboundGateway outGateway = new TcpOutboundGateway();
outGateway.setConnectionFactory(connectionFactory);
outGateway.setAsync(true);
outGateway.setOutputChannel(receiveMessageChannel());
outGateway.setRequiresReply(true);
outGateway.setReplyChannel(receiveMessageChannel());
return outGateway;
}
#Bean
public MessageChannel sendMessageChannel() {
DirectChannel channel = new DirectChannel();
return channel;
}
#Bean
public MessageChannel receiveMessageChannel() {
DirectChannel channel = new DirectChannel();
return channel;
}
#Transformer(inputChannel = "receiveMessageChannel", outputChannel = "processMessageChannel")
public String convert(byte[] bytes) {
return new String(bytes);
}
#ServiceActivator(inputChannel = "processMessageChannel")
public void upCase(String response) {
gatewayService.receiveMessage(response);
}
#Transformer(inputChannel = "errorChannel", outputChannel = "processMessageChannel")
public void convertError(byte[] bytes) {
String str = new String(bytes);
System.out.println("Error: " + str);
}
}
public class Message {
private String payload;
// getter setter
}
#Service
public class GatewayServiceImpl implements GatewayService<Message> {
#Autowired
private Gateway gateway;
#Autowired
private GatewayContextManger<String, Object> gatewayContextManger;
#Override
public void sendMessage(final Message message) {
new Thread(new Runnable() {
#Override
public void run() {
gateway.viaTcp(message.getPayload());
}
}).start();
}
#Override
public void receiveMessage(final String response) {
new Thread(new Runnable() {
#Override
public void run() {
Message message = new Message();
message.setPayload(response);
Object obj = message;
//Object obj = gatewayContextManger.get(message.getPayload());
synchronized (message) {
obj.notify();
System.out.println("Message Received : "+message.getPayload());
}
}
}).start();
}
}
You have: clientConnectionFactory.setSingleUse(true); This means the connection will be closed after the request; leave it false (default) to keep the connection open.