Remove Thread.sleep() in case of Sending Message to ActiveMQ - sonarqube

I was fixing sonar lint error in my project. I have seen a block of Code where sonar lint is giving me error of rule squid:S2276 to replace Thread.sleep(100); with wait(). But wait() should be in conditional loop to escape spurious wakeup problem. But I am not getting such a condition how I should use.
Can i achieve the same thing without sleep()
public class ACTOOBEventSubSMSProducer {
private ACTOOBEventSubSMSProducer(){
super();
}
private static Logger logger = LoggerManager.getInstance().getCoreProcessingLogger();
public static final String CONNECTION_FACTORY = "java:jboss/activemq/ConnectionFactory";
static final String QUEUE_NAME = "java:jboss/exported/jms/queue/actOOBEventSubscriptionSMS";
static ConnectionFactory connectionFactory = null;
static Connection connection = null;
static Session session = null;
static Destination destination = null;
static MessageProducer messageProducer = null;
static {
connectionFactory = ServiceLocator.getJmsConnectionFactory(CONNECTION_FACTORY);
try {
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
destination = ServiceLocator.getJmsDestination(QUEUE_NAME);
messageProducer = session.createProducer(destination);
messageProducer.setDisableMessageID(true);
messageProducer.setDisableMessageTimestamp(true);
} catch (JMSException e) {
logger.error("Error in creating ConnectionFactory",e);
}
}
/**
* This method sends OOB Event SMS Message in Queue.
*
* #param message
*/
public static synchronized void sendMessage(Serializable payload) throws JmsProducerException {
try {
ObjectMessage message = session.createObjectMessage(payload);
messageProducer.send(message, javax.jms.DeliveryMode.NON_PERSISTENT, javax.jms.Message.DEFAULT_PRIORITY,
1800000);
} catch (JMSException je) {
try {
Thread.sleep(100);
ObjectMessage message = session.createObjectMessage(payload);
messageProducer.send(message, javax.jms.DeliveryMode.PERSISTENT, javax.jms.Message.DEFAULT_PRIORITY,
1800000);
} catch (JMSException jee) {
logger.error("Error in sendMessage()",jee);
throw new JmsProducerException(jee);
} catch (InterruptedException ie) {
logger.error("Error in sendMessage()",ie);
Thread.currentThread().interrupt();
throw new JmsProducerException(ie);
}
} catch (ServiceLocatorException sle) {
logger.error("Error in sendMessage()",sle);
throw new JmsProducerException(sle);
}
}
}

A carefully crafted for loop with the iterations count being the number of times you wanted to retry and some exception handling logic to break the loop if things work would do the trick in at a slightly clearer manner perhaps, otherwise using a ScheduledThreadPoolExecutor or or Timer would be an option.

Related

What is recommended way to handle ethereum contract events in spring boot?

What is the appropriate way to handle live events (i.e. service/component should keep on listening to events and save it to offchain db (h2/postgres))
How to close event subscription gracefully?
Implementation tried so far:
#Component
public class ERC20Listener implements Listener {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* Do something useful with the state update received
*/
#Override
#PostConstruct
public void listen() throws Exception {
Web3j web3j = null;
Disposable flowableEvent = null;
try {
WebSocketService web3jService = new WebSocketService("ws://", true);
web3jService.connect();
web3j = Web3j.build(web3jService);
ERC20Token token= ... //creating contract instance
flowableEvent = token.transferEventFlowable(DefaultBlockParameterName.LATEST, DefaultBlockParameterName.LATEST)
.subscribe(event -> {
try {
System.out.printf("hash=%s from=%s to=%s amount=%s%n",
event.log.getTransactionHash(),
event.from,
event.to,
event.value);
//process event data save to offchain db ==> service call
}catch(Throwable e) {
e.printStackTrace();
}
});
} catch (Exception e) {
logger.error("Unknown Exception " + e.getMessage());
throw new Exception(e.getMessage());
} finally {
web3j.shutdown();
flowableEvent.dispose();
}
}
}

IBM MQ JMSWMQ0018: Failed to connect to queue manager 'MY_LOCAL_QM' with connection mode 'Client' and host name 'MY_LOCAL_QM(1401)'

I created a queue manager, queue, channel(Server-connection).
When I try to send a message, see this error:
com.ibm.msg.client.jms.DetailedIllegalStateException: JMSWMQ0018: Failed to connect to queue manager 'MY_LOCAL_QM' with connection mode 'Client' and host name 'epspa(1401)'.
Check the queue manager is started and if running in client mode, check there is a listener running. Please see the linked exception for more information.
Maybe I need to set a user to queue manager? Because I use the same java code, but try to connect to another queue manager, and it works fine. But it doesn't work with my queue manager.
IBM MQ installed on another PC.
private static final String HOST = "epspa";
private static final int PORT = 1401;
private static final String CHANNEL = "API.SVRCONN_LOCAL";
private static final String QMN = "MY_LOCAL_QM";
private static final String QUEUE_NAME = "API.QUEUE_NAME";
private static final String message ="message";
public static String sendMessage(String message) {
String result = "Error";
try {
MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
cf.setHostName(HOST);
cf.setChannel(CHANNEL);
cf.setPort(PORT);
cf.setQueueManager(QMN);
cf.setTransportType(WMQConstants.WMQ_MESSAGE_BODY_MQ);
Destination destination = null;
MessageProducer producer = null;
Connection c = cf.createConnection();
Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE);
destination = s.createQueue(QUEUE_NAME);
producer = s.createProducer(destination);
TextMessage tmo = s.createTextMessage();
((MQDestination) destination).setMessageBodyStyle
(WMQConstants.WMQ_MESSAGE_BODY_MQ);
tmo.setIntProperty(WMQConstants.JMS_IBM_CHARACTER_SET, 1208);
tmo.setIntProperty(WMQConstants.JMS_IBM_ENCODING,546);
tmo.setText(message);
producer.send(tmo);
result = "Success!";
} catch (JMSException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
cf.setTransportType(WMQConstants.WMQ_MESSAGE_BODY_MQ);
Well, that's not correct. It should be:
cf.setTransportType(WMQConstants.WMQ_CM_CLIENT);
JMSWMQ0018: Failed to connect to queue manager
A JMS error does not give enough details about what MQ is complaining about. You need to output the LinkedException.
catch (JMSException e)
{
if (e != null)
{
System.err.println("getLinkedException()=" + e.getLinkedException());
System.err.println(e.getLocalizedMessage());
e.printStackTrace();
}
}
Are you sure that port # of 1401 is correct? The default port # for MQ is 1414. Start runmqsc against your queue manager. i.e.
runmqsc MY_LOCAL_QM
then issue the following command:
DIS LISTENER(LISTENER.TCP)
what value is given for the PORT attribute?
tmo.setIntProperty(WMQConstants.JMS_IBM_CHARACTER_SET, 1208);
tmo.setIntProperty(WMQConstants.JMS_IBM_ENCODING,546);
Why are you setting the CCSID and Encoding? Why don't you let JMS & MQ take care of it?
Here is a fully functioning JMS program that puts a message to a queue:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import javax.jms.*;
import com.ibm.mq.jms.*;
import com.ibm.msg.client.wmq.WMQConstants;
/**
* Program Name
* MQTestJMS11
*
* Description
* This java JMS class will connect to a remote queue manager and put a message to a queue.
*
* Sample Command Line Parameters
* -m MQA1 -h 127.0.0.1 -p 1414 -c TEST.CHL -q TEST.Q1 -u UserID -x Password
*
* #author Roger Lacroix
*/
public class MQTestJMS11
{
private static final SimpleDateFormat LOGGER_TIMESTAMP = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
private Hashtable<String,String> params;
private MQQueueConnectionFactory mqQCF = null;
/**
* The constructor
*/
public MQTestJMS11()
{
super();
params = new Hashtable<String,String>();
}
/**
* Make sure the required parameters are present.
* #return true/false
*/
private boolean allParamsPresent()
{
boolean b = params.containsKey("-h") && params.containsKey("-p") &&
params.containsKey("-c") && params.containsKey("-m") &&
params.containsKey("-q") &&
params.containsKey("-u") && params.containsKey("-x");
if (b)
{
try
{
Integer.parseInt((String) params.get("-p"));
}
catch (NumberFormatException e)
{
b = false;
}
}
return b;
}
/**
* Extract the command-line parameters and initialize the MQ variables.
* #param args
* #throws IllegalArgumentException
*/
private void init(String[] args) throws IllegalArgumentException
{
if (args.length > 0 && (args.length % 2) == 0)
{
for (int i = 0; i < args.length; i += 2)
{
params.put(args[i], args[i + 1]);
}
}
else
{
throw new IllegalArgumentException();
}
if (allParamsPresent())
{
try
{
mqQCF = new MQQueueConnectionFactory();
mqQCF.setQueueManager((String) params.get("-m"));
mqQCF.setHostName((String) params.get("-h"));
mqQCF.setChannel((String) params.get("-c"));
mqQCF.setTransportType(WMQConstants.WMQ_CM_CLIENT);
try
{
mqQCF.setPort(Integer.parseInt((String) params.get("-p")));
}
catch (NumberFormatException e)
{
mqQCF.setPort(1414);
}
}
catch (JMSException e)
{
if (e != null)
{
MQTestJMS11.logger("getLinkedException()=" + e.getLinkedException());
MQTestJMS11.logger(e.getLocalizedMessage());
e.printStackTrace();
}
throw new IllegalArgumentException();
}
catch (Exception e)
{
MQTestJMS11.logger(e.getLocalizedMessage());
e.printStackTrace();
throw new IllegalArgumentException();
}
}
else
{
throw new IllegalArgumentException();
}
}
/**
* Test the connection to the queue manager.
* #throws MQException
*/
private void testConn()
{
QueueConnection conn = null;
QueueSession session = null;
Queue myQ = null;
try
{
conn = mqQCF.createQueueConnection((String) params.get("-u"), (String) params.get("-x"));
conn.start();
session = conn.createQueueSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
MQTestJMS11.logger("successfully connected.");
myQ = session.createQueue((String) params.get("-q"));
MQDestination mqd = (MQDestination) myQ;
mqd.setTargetClient(WMQConstants.WMQ_CLIENT_JMS_COMPLIANT);
// mqd.setTargetClient(WMQConstants.WMQ_CLIENT_NONJMS_MQ);
sendMsg( session, myQ);
}
catch (JMSException e)
{
if (e != null)
{
MQTestJMS11.logger("getLinkedException()=" + e.getLinkedException());
MQTestJMS11.logger(e.getLocalizedMessage());
e.printStackTrace();
}
}
catch (Exception e)
{
MQTestJMS11.logger(e.getLocalizedMessage());
e.printStackTrace();
}
finally
{
try
{
if (session != null)
session.close();
}
catch (Exception ex)
{
MQTestJMS11.logger("session.close() : " + ex.getLocalizedMessage());
}
try
{
if (conn != null)
conn.stop();
}
catch (Exception ex)
{
MQTestJMS11.logger("connection.stop() : " + ex.getLocalizedMessage());
}
try
{
if (conn != null)
conn.close();
}
catch (Exception ex)
{
MQTestJMS11.logger("connection.close() : " + ex.getLocalizedMessage());
}
}
}
/**
* Send a message to a queue.
* #throws MQException
*/
private void sendMsg(QueueSession session, Queue myQ) throws JMSException
{
QueueSender sender = null;
try
{
TextMessage msg = session.createTextMessage();
msg.setText("Nice simple test. Time in 'ms' is -> " + System.currentTimeMillis());
// msg.setJMSReplyTo(tq);
// msg.setJMSDeliveryMode( DeliveryMode.NON_PERSISTENT);
MQTestJMS11.logger("Sending request to " + myQ.getQueueName());
MQTestJMS11.logger("");
sender = session.createSender(myQ);
sender.send(msg);
}
finally
{
try
{
if (sender != null)
sender.close();
}
catch (Exception ex)
{
MQTestJMS11.logger("sender.close() : " + ex.getLocalizedMessage());
}
}
}
/**
* A simple logger method
* #param data
*/
public static void logger(String data)
{
String className = Thread.currentThread().getStackTrace()[2].getClassName();
// Remove the package info.
if ( (className != null) && (className.lastIndexOf('.') != -1) )
className = className.substring(className.lastIndexOf('.')+1);
System.out.println(LOGGER_TIMESTAMP.format(new Date())+" "+className+": "+Thread.currentThread().getStackTrace()[2].getMethodName()+": "+data);
}
/**
* mainline
* #param args
*/
public static void main(String[] args)
{
MQTestJMS11 write = new MQTestJMS11();
try
{
write.init(args);
write.testConn();
}
catch (IllegalArgumentException e)
{
MQTestJMS11.logger("Usage: java MQTestJMS11 -m QueueManagerName -h host -p port -c channel -q JMS_Queue_Name -u UserID -x Password");
System.exit(1);
}
catch (Exception e)
{
MQTestJMS11.logger(e.getLocalizedMessage());
System.exit(1);
}
System.exit(0);
}
}

How to handle failover in case of TIBCO

I am struggling to setup fail over in tibco JMS provider. I know how to do this in case of ActiveMQ.
What I have tried is as follows
public class TibcoJMSQueueProducer {
private static final Logger LOGGER = LoggerFactory.getLogger(FDPMetaCacheProducer.class);
private static QueueConnectionFactory factory;
private QueueConnection connection;
private QueueSession session;
#Inject
private FDPTibcoConfigDAO fdpTibcoConfigDao;
private String providerURL;
private String userName;
private String password;
#PostConstruct
public void constructProducer(){
configure();
}
private void configure() {
try {
List<FDPTibcoConfigDTO> tibcoConfigList = fdpTibcoConfigDao.getAllTibcoConfig();
if(!tibcoConfigList.isEmpty()){
FDPTibcoConfigDTO fdpTibcoConfigDTO = tibcoConfigList.get(tibcoConfigList.size()-1);
String providerURL = getProviderUrl(fdpTibcoConfigDTO);
setProviderUrl(providerURL);
String userName = fdpTibcoConfigDTO.getUserName();
String password = fdpTibcoConfigDTO.getPassword();
this.userName = userName;
this.password=password;
factory = new com.tibco.tibjms.TibjmsQueueConnectionFactory(providerURL);
}
} catch (Exception e) {
System.err.println("Exitting with Error");
e.printStackTrace();
System.exit(0);
}
}
private void setProviderUrl(String providerURL) {
this.providerURL = providerURL;
}
private String getProviderUrl(final FDPTibcoConfigDTO FDPTibcoConfigDTO) {
return TibcoConstant.TCP_PROTOCOL + FDPTibcoConfigDTO.getIpAddress().getValue() + TibcoConstant.COLON_SEPERATOR + FDPTibcoConfigDTO.getPort();
}
private Object lookupQueue(String queueName) {
Properties props = new Properties();
Object tibcoQueue = null;
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, TibcoConstant.TIB_JMS_INITIAL_CONTEXT_FACTORY);
props.setProperty(Context.PROVIDER_URL, this.providerURL);
props.setProperty(TibcoConstant.TIBCO_CONNECT_ATTEMPT, "20,10");
props.setProperty(TibcoConstant.TIBCO_RECOVER_START_UP_ERROR, "true");
props.setProperty(TibcoConstant.TIBCO_RECOVER_RECONNECT_ATTEMPT, "20,10");
InitialContext context;
try {
context = new InitialContext(props);
tibcoQueue = context.lookup(queueName);
} catch (NamingException e) {
System.out.println(e.getMessage());
}
return tibcoQueue;
}
public void pushIntoQueueAsync(String message,String queueName) throws JMSException {
connection = factory.createQueueConnection(userName, password);
connection.start();
session = connection.createQueueSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
Queue pushingQueue = (Queue)lookupQueue(queueName);
QueueSender queueSender = session.createSender(pushingQueue);
queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
TextMessage sendXMLRequest = session.createTextMessage(message);
queueSender.send(sendXMLRequest);
LOGGER.info("Pushing Queue {0} ,Pushing Message : {1}", pushingQueue.getQueueName(), sendXMLRequest.getText());
}
public String pushIntoQueueSync(String message,String queueName,String replyQueueName) throws JMSException {
connection = factory.createQueueConnection(userName, password);
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = (Destination)lookupQueue(queueName);
MessageProducer messageProducer = session.createProducer(destination);
session = connection.createQueueSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
UUID randomUUID =UUID.randomUUID();
TextMessage textMessage = session.createTextMessage(message);
String correlationId = randomUUID.toString();
//Create Reply To Queue
Destination replyDestination = (Destination)lookupQueue(queueName);
textMessage.setJMSReplyTo(replyDestination);
textMessage.setJMSCorrelationID(correlationId);
String messgeSelector = "JMSCorrelationID = '" + correlationId + "'";
MessageConsumer replyConsumer = session.createConsumer(replyDestination,messgeSelector);
messageProducer.send(textMessage, javax.jms.DeliveryMode.PERSISTENT, javax.jms.Message.DEFAULT_PRIORITY, 1800000);
Message replayMessage = replyConsumer.receive();
TextMessage replyTextMessage = (TextMessage) replayMessage;
String replyText = replyTextMessage.getText();
LOGGER.info("Pushing Queue {0} ,Pushing Message : {1}", queueName, message);
return replyText;
}
public static QueueConnectionFactory getConnectionFactory(){
return factory;
}
}
In case of activeMQ we use
failover:(tcp://127.0.0.1:61616,tcp://127.0.0.1:61616)?randomize=false&backup=true url to handle failover as provider url in ActiveMQconnectionfactory constructor. I have seen somewhere to use multiple url in case of TIBCO like this
tcp://169.144.87.25:7222,tcp://127.0.0.1:7222
How I checked failover like this.
First at all I checked using single IP (tcp://169.144.87.25:7222) . Message is getting sent and received normally(I have not posted TibcoJMSReceiver code).
I tried with another IP(tcp://169.144.87.25:7222). It was working fine.
But when I tried with
final String
PROVIDER_URL="tcp://169.144.87.25:7222,tcp://127.0.0.1:7222";
I started my program. But before giving input I shutdown first server. As a failover the message should be sent to other server.
But It shows me session closed Exception.
So Am I handling failover in a correct way or is there other configuration I have to do.
Two TIBCO EMS daemons only work 'as one' if you enable fault-tolrance in both of them. Only then will they heartbeat with each other and share resources. You should have this in the remote daemon's tibemsd.conf:
listen = tcp://7222
...
ft_active = tcp://<ip to your box>:7222
and this on your local box:
listen = tcp://7222
...
ft_active = tcp://169.144.87.25:7222
And you don't need to create connection and session every time! One Connection and Session for many messages - 'Fault Tolerance' means it'll reconnect automatically for you. You could have an init() or connect() method you call once or just add it inside your configure method:
private void configure() {
try {
...
connection = factory.createQueueConnection(userName, password);
connection.start();
session = connection.createQueueSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
Then pushIntoQueue becomes as simple as this:
public void pushIntoQueueAsync(String message,String queueName) throws JMSException {
Queue pushingQueue = (Queue)lookupQueue(queueName);
QueueSender queueSender = session.createSender(pushingQueue);
queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
TextMessage sendXMLRequest = session.createTextMessage(message);
queueSender.send(sendXMLRequest);
LOGGER.info("Pushing Queue {0} ,Pushing Message : {1}", pushingQueue.getQueueName(), sendXMLRequest.getText());
}

TcpSocketClient- UnhandledException when I try read a response inside of a Task that not arrived yet

I'm using this library(https://github.com/rdavisau/sockets-for-pcl) to communicate with a TCP Server, that sends me when a event was generated, then, I have to verify all the time if the TCP Server sent to me a event, but if I try read anything before the TCP Server sends me, it's thrown the UnhandledException, but it only happens if I read inside a Task, in the main thread it thrown a timeout exception, the exception that I expected to happen in Task.
Someone can help me? Thanks. below is my code.
public class CentralTcpService
{
#region ConnectTcpAsync
public async void ConnectTcpAsync()
{
try
{
_sockecClient = new TcpSocketClient();
await _sockecClient.ConnectAsync(Central.Ip, Central.Port);
_writter = new ExtendedBinaryWriter(_sockecClient.WriteStream);
_reader = new ExtendedBinaryReader(_sockecClient.ReadStream);
_writter.WriteString(EvenNotProtocol.MobileReceiverCommand);
_sockecClient.ReadStream.ReadTimeout = int.MaxValue;
EnableTcpService();
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
#endregion
#region TcpService
private void EnableTcpService()
{
_cancelationTcpService = new CancellationTokenSource();
new Task(StartService, _cancelationTcpService.Token, TaskCreationOptions.LongRunning).Start();
}
private void StartService()
{
while (!_cancelationTcpService.Token.IsCancellationRequested)
{
var ev = EvenNotProtocol.DeserializeEvent(_reader);
if (ev == null) continue;
_writter.WriteString(EvenNotProtocol.MobileOkCommand);
EventReceived?.Invoke(this, new CentralTcpEventArgs(ev));
}
}
}
public class EvenNotProtocol
{
public static Event DeserializeEvent(ExtendedBinaryReader reader)
{
try
{
reader.SkipBytes(1);
.....
}
catch (IOException e)
{
return null;
}
}
}

Trying to get the message from server but receive call gets blocked

// This is send message from where I am sending message to server, Its working fine
public void sendMessage(com.google.protobuf.Message sendmessage) {
try {
createJmsTemplate();
createJmsTemplateReciever();
JmsMessageCreator jmsMessageCreator = new JmsMessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
BytesMessage msg = session.createBytesMessage();
msg.writeBytes(sendmessage.toByteArray());
return msg;
}
};
MessageCreator messageCreator = new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
Message msg = jmsMessageCreator.createMessage(session);
msg.setJMSCorrelationID("2708");
return msg;
}
};
jmsTemplate.send(messageCreator);
System.out.println("Message sent... ");
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
//But when i am calling this method, at receive call it gets blocked...
public void recieveMessage() {
try {
byteMessage = (BytesMessage) jmsTemplateReciever.receive();
try {
if (byteMessage != null) {
byte[] byteArr = new byte[(int) byteMessage.getBodyLength()];
for (int i = 0; i < (int) byteMessage.getBodyLength(); i++) {
byteArr[i] = byteMessage.readByte();
String s = new String(byteArr);
System.out.println(s);
}
String s = new String(byteArr);
System.out.println(s);
byteMessage.acknowledge();
}
} catch (JMSException e) {
}
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
}
As described in section 9.2.2 of JMS 1.1 Specification, the receive() call blocks indefinitely until a message arrives on the queue. Hence the call is getting blocked in your application.
One option for you is to specify a wait time, for example receive(3000) which waits for 3 seconds and comes out if no message arrives in 3 seconds. JMS implementer might be providing another form of receive method where the method returns immediately if there are no messages in the queue.
The other option is to use a message listener for receiving messages asynchronously as described JMS 1.1 Specifications section 9.3.1. Your application gets notified by the JMS provider whenever a message arrives in a queue.

Resources