I have a spring boot application with JMS messaging included. The receiver and the connection Factory is as below,The problem I am having is the listener always looks the queue and prints in logs, Logs attached for reference. It should trigger the process() when there is a message in the queue.
Any help appreciated
package uk.gov.hmrc.cds.dmscaseemulator.receiver;
import javax.jms.JMSException;
import javax.jms.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import uk.gov.hmrc.cds.dmscaseemulator.bo.DMSMessageProcessBO;
#Service
#Slf4j
public class DMSQReceiver {
#Value("${queue.DMS_Q}")
private String listeningQ;
#Autowired DMSMessageProcessBO processBo;
#JmsListener(destination="${queue.DMS_Q}", containerFactory = "myFactory")
public void recv(Message message) throws JMSException{
try{
log.info("Listening to : {} ", listeningQ);
processBo.process(message);
}catch(JMSException ex){
log.error("ERROR IN DMS Case Emulator while receiving " + listeningQ +". ERROR IS : ", ex);
throw ex;
}
}
}
package uk.gov.hmrc.cds.dmscaseemulator.config;
import javax.jms.ConnectionFactory;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;
#Configuration
#EnableJms
public class JMSConfig {
#Bean
public JmsListenerContainerFactory<?> myFactory(
ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
configurer.configure(factory, connectionFactory);
return factory;
}
}
20:23:37.281 [DefaultMessageListenerContainer-1] INFO u.g.h.c.d.receiver.DMSQReceiver - Listening to : DMS.QA.CTRL_MGMT_EXPORT
20:23:37.282 [DefaultMessageListenerContainer-1] DEBUG u.g.h.c.d.b.c.ControlTypeResolver - Found control type
20:23:37.282 [DefaultMessageListenerContainer-1] DEBUG u.g.h.c.d.b.c.ControlTypeResolver - Returning control type value : 3
20:23:37.283 [DefaultMessageListenerContainer-1] INFO u.g.h.c.d.bo.DMSMessageProcessBO - Control Type is: 3
20:23:37.290 [DefaultMessageListenerContainer-1] INFO u.g.h.c.d.receiver.DMSQReceiver - Listening to : DMS.QA.CTRL_MGMT_EXPORT
20:23:37.291 [DefaultMessageListenerContainer-1] DEBUG u.g.h.c.d.b.c.ControlTypeResolver - Found control type
20:23:37.291 [DefaultMessageListenerContainer-1] DEBUG u.g.h.c.d.b.c.ControlTypeResolver - Returning control type value : 3
20:23:37.292 [DefaultMessageListenerContainer-1] INFO u.g.h.c.d.bo.DMSMessageProcessBO - Control Type is: 3
Related
try to use spring cloud gcp binder library polling messages from GCP pubsub topic.
ref from streaming-vs-polled-input. use spring.cloud.stream.gcp.pubsub.default.consumer.maxFetchSize poll get N message (maxFetchSize's value) at a time, but even i set up the property and set maxFetchSize to 2 or others. i alwasy got 1 message from topic, even the topic has other messages. Does anyone here has other idea?
spring cloud version: 2021.0.3
google spring-cloud-gcp-dependencies version: 3.3.0
java: openjdk 11
# application.properties
spring.cloud.gcp.pubsub.project-id=
spring.cloud.gcp.credentials.location=
spring.cloud.stream.default-binder=pubsub
spring.cloud.stream.bindings.input.destination=iamatopic
spring.cloud.stream.bindings.input.content-type=text/plain;charset=UTF-8
spring.cloud.stream.gcp.pubsub.default.consumer.maxFetchSize=3
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.cloud.stream.binder.PollableMessageSource;
public interface PollableSink {
#Input("input")
PollableMessageSource input();
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.binder.PollableMessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.scheduling.annotation.Scheduled;
import com.google.cloud.spring.pubsub.support.AcknowledgeablePubsubMessage;
import com.google.cloud.spring.pubsub.support.GcpPubSubHeaders;
import lombok.extern.slf4j.Slf4j;
#Configuration
#EnableBinding(PollableSink.class)
#Slf4j
public class PollConfiguration {
#Autowired
PollableMessageSource destIn;
PolledMessageHandler messageHandler = new PolledMessageHandler();
#Scheduled(fixedRate = 5000)
public void poller() {
log.info("start polling ");
destIn.poll(this.messageHandler, ParameterizedTypeReference.forType(String.class));
log.info("end polling ");
}
static class PolledMessageHandler implements MessageHandler {
#Override
public void handleMessage(Message<?> message) {
AcknowledgeablePubsubMessage ackableMessage = (AcknowledgeablePubsubMessage) message.getHeaders()
.get(GcpPubSubHeaders.ORIGINAL_MESSAGE);
ackableMessage.ack();
System.out.println("get payload : " + message.getPayload());
}
}
}
Try setting spring.cloud.stream.poller.maxMessagesPerPoll value -- it's 1 by default in Spring Cloud Stream.
Reference: https://docs.spring.io/spring-cloud-stream/docs/current/reference/html/spring-cloud-stream.html#_polling_configuration_properties
package com.wombatrack.configBatch;
import com.wombatrack.domain.entites.UserInstagram;
import com.wombatrack.service.UserInstagramService;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
#EnableBatchProcessing
public class BatchConfig {
#Bean
ItemReader<UserInstagram> restUserInstagramReader(UserInstagramService userInstagramService) {
return new RESTUserInstagramReader(userInstagramService);
}
#Bean
ItemProcessor<UserInstagram, UserInstagram> restUserInstagramProcessor() {
return new LoggingUserInstagramProcessor();
}
#Bean
ItemWriter<UserInstagram> restUserInstagramWriter() {
return new LoggingUserInstagramWriter();
}
#Bean
Step restUserInstagramStep(ItemReader<UserInstagram> restUserInstagramReader,
ItemProcessor<UserInstagram, UserInstagram> restUserInstagramProcessor,
ItemWriter<UserInstagram> restUserInstagramWriter,
StepBuilderFactory stepBuilderFactory) {
return stepBuilderFactory.get("restUserInstagramStep")
.<UserInstagram, UserInstagram>chunk(5)
.reader(restUserInstagramReader)
.processor(restUserInstagramProcessor)
.writer(restUserInstagramWriter)
.allowStartIfComplete(true)
.build();
}
#Bean
Job restUserInstagramJob(JobBuilderFactory jobBuilderFactory,
#Qualifier("restUserInstagramStep") Step restUserInstagramStep) {
return jobBuilderFactory.get("restUserInstagramJob")
.incrementer(new RunIdIncrementer())
.flow(restUserInstagramStep)
.end()
.build();
}
}
I have a probleme with this peace of code my job run first time, but after that return user null that mean busness ligique of job run one time whene the application start first time
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class BatchLauncher {
#Autowired
private JobLauncher jobLauncher;
#Autowired
private Job job;
public BatchStatus run() throws JobParametersInvalidException, JobExecutionAlreadyRunningException,
JobRestartException, JobInstanceAlreadyCompleteException {
JobParameters parameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis())
.toJobParameters();
JobExecution jobExecution = jobLauncher.run(job, parameters);
return jobExecution.getStatus();
}
}
** I put a schedular that will run every 20 seconds the job runs after every 20 seconds as expected, but the problem is that the business, i.e. the backup at the database level does not work no effect.
the job does its role only the first time after the application is started in the first time, but after that the scheduler makes the job run every 20 seconds but the information is not saved, I have a return every time the job with status COMPLETED but the job does nothing in terms of saving new data**
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
#Component
#Slf4j
public class Schedular {
#Autowired
private BatchLauncher batchLauncher;
#Scheduled(fixedDelay = 20000)
public void perform() throws Exception {
log.info("Batch programmé pour tourner toutes les 20 secondes");
batchLauncher.run();
}
}
**I don't have any idea how to do it to fix this problem, i debug application but
I did not find any solution Please if someone can help me **
Hello everyone!
I'm trying to load wildfly server's system properties through JMX in Startup bean's #PostConstruct method. It works fine on the already started server instance when deployment starts, but fails while starting with server instance bootstrapping.
Wildfly 11.0.0.CR1
Startup bean code:
package ru.wildfly.test.ejb.wildflyconsulregistrar.startup;
import ru.wildfly.test.ejb.wildflyconsulregistrar.api.ConsulRegistrar;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.inject.Inject;
#Startup
#Singleton
public class WildflyConsulRegistrarStartupBean {
#Inject
private ConsulRegistrar consulRegistrar;
#PostConstruct
public void initialize() {
registerServices();
}
private void registerServices() {
consulRegistrar.registerService("WildflyTestCluster");
}
.............
}
ConsulRegistrar code:
package ru.wildfly.test.ejb.wildflyconsulregistrar.impl;
import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.agent.model.NewService;
import ru.test.ejb.wildflyconsulregistrar.api.ConsulRegistrar;
import ru.wildfly.test.ejb.wildflyconsulregistrar.serversettings.api.CurrentServerNodeSettings;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
#Dependent
public class ConsulRegistrarImpl implements ConsulRegistrar {
...............
#Inject
private CurrentServerNodeSettings currentServerNodeSettings;
.............
#Override
public void registerService(String serviceName) {
String currentNodeName = currentServerNodeSettings.getCurrentNodeName();
........................
}
.......................
}
CurrentServerNodeSettings code:
package ru.wildfly.test.ejb.wildflyconsulregistrar.serversettings.impl;
import ru.wildfly.test.ejb.wildflyconsulregistrar.serversettings.api.CurrentServerNodeSettings;
import javax.enterprise.context.Dependent;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
#Dependent
public class CurrentServerNodeSettingsWildflyImpl implements CurrentServerNodeSettings {
....................
#Override
public String getCurrentNodeName() {
String currentNodeName = getPlatformMBeanServerAttributeValue(String.class, "jboss.as:system-property=server.name", "value");
return currentNodeName;
}
private <T> T getPlatformMBeanServerAttributeValue(Class<T> valueType, String objectName, String attributeName) {
T attributeValue = null;
try {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
Object attributeObject = mBeanServer.getAttribute(new ObjectName(objectName), attributeName);
attributeValue = attributeObject != null ? (valueType.cast(attributeObject)) : null;
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return attributeValue;
}
}
Error message:
Caused by: java.lang.IllegalStateException:
javax.management.AttributeNotFoundException:
"WFLYCTL0216: Management resource '[(\"system-property\" => \"server.name\")]' not found"
at ru.wildfly.test.ejb.wildflyconsulregistrar.serversettings.impl.CurrentServerNodeSettingsWildflyImpl
.getPlatformMBeanServerAttributeValue(CurrentServerNodeSettingsWildflyImpl.java:41)
I have found the same issue on jboss forum https://developer.jboss.org/message/971717#971717 , but it was unanswered.
Any suggestions?
This is a dependency problem during startup, i.e. the server name is set after your #PostConstruct method gets executed. Try to load the server name lazy when it is accessed from the application for the first time.
In Wildfly there is no generic way to enforce the sequence of deployments from the application despite the definition of module dependencies. But this won't help in your case.
This is the Java EE7 #Startup annotation for reference. I am using the latest GlassFish server and IntelliJ to run the server.
I need to instantiate this service so that it can send packets of data periodically to a websocket for processing, but the fact that I use
session.getBasicRemote().sendObject(message);
in the end forces me to throw IOException and EncodeException.
This is bad as #Startup or #Singleton disallows usage of Exceptions when instantiating:
war exploded: java.io.IOException: com.sun.enterprise.admin.remote.RemoteFailureException: Error occurred during deployment: Exception while deploying the app [keyBoard_war_exploded] : The lifecycle method [printSchedule] must not throw a checked exception.
Here is my code:
package site.xxxx.models;
import site.xxxx.message.Message;
import site.xxxx.message.TextMessage;
import site.xxxx.modules.Packet;
import site.xxxx.websocket.MainServerEndpoint;
import javax.annotation.PostConstruct;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.json.Json;
import javax.json.JsonObject;
import javax.websocket.EncodeException;
import javax.websocket.Session;
import java.io.IOException;
import java.util.Set;
#Startup
#Singleton
public class Service {
private static Service service;
Set<Session> peers = MainServerEndpoint.peers;
#PostConstruct
public void mainLoop() throws IOException, EncodeException, InterruptedException {
sendSpamPacket();
}
private void sendSpamPacket() throws IOException, EncodeException {
JsonObject ret = Json.createObjectBuilder()
.add("type", "textMessage")
.add("text", "ayyyy")
.build();
Packet packet = new Packet(new TextMessage(ret));
MainServerEndpoint.sendPacket(packet);
//results in calling session.getBasicRemote().sendObject(message);
}
}
I need to make simple Message Driven Bean that will listen on dynamically added queue locataions. I have tried few ways to implement this, but none of them worked. I have appplication that uses esb and java message queues, and I'm trying to read queue location from config file, during the runtime, and thus tell my message driven bean what is the queue on which to listen. I am not either sure that this is possible.
I also tried to implement message listener, but because I have to use ejb module, and ejb module does not support main method, it requires his own container (like message driven bean), I don't know what to use instead of main method to achive the same goal. I am not able to use session beans because I need to achieve asynchronous communication between client and service.
I also tried to use client application (although it is not one of the options), but maven project does not support debug and run functions for this type of application in netbeans.
Does anyone know any solution for this problem, or at least have some idea?
This may not be the best solution, but it is possible to receive and process JMS messages asynchronously with a Stateful Session Bean doing something like this:
package com.example.statefuljms;
import javax.annotation.Resource;
import javax.ejb.Local;
import javax.ejb.Stateful;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueReceiver;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
#Stateful
#Local(MessageReceiverLocal.class)
public class MessageReceiver implements MessageReceiverLocal, MessageListener {
#Resource(mappedName = "ConnectionFactory")
private ConnectionFactory connectionFactory;
private QueueConnection connection;
#Override
public void start(String queueName) throws JMSException, NamingException {
Context initialContext = new InitialContext();
connection = (QueueConnection) connectionFactory.createConnection();
QueueSession session = (QueueSession) connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue) initialContext.lookup(queueName);
QueueReceiver receiver = session.createReceiver(queue);
receiver.setMessageListener(this);
connection.start();
}
#Remove
#Override
public void stop() throws JMSException {
connection.stop();
connection.close();
}
#Override
public void onMessage(Message message) {
// handle message here
}
}
Use a Singleton to test:
package com.example.statefuljms;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.EJB;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.jms.JMSException;
import javax.naming.NamingException;
#Startup
#Singleton
public class Test {
#EJB
private MessageReceiverLocal messageReceiver;
#PostConstruct
public void run() {
messageReceiver.start("/queue/myQueue");
}
#PreDestroy
public void cleanup() {
messageReceiver.stop();
}
}