Commit 7e49c039 authored by Andre Freyssinet's avatar Andre Freyssinet

Bug fix: the return value is now false if the message is not received.

Adds a toString method.
parent aa537cb3
/* /*
* Copyright (C) 2020 - 2021 ScalAgent Distributed Technologies * Copyright (C) 2020 - 2021 ScalAgent Distributed Technologies
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version. * version 2.1 of the License, or any later version.
* *
* This library is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA. * USA.
* *
* Initial developer(s): ScalAgent Distributed Technologies * Initial developer(s): ScalAgent Distributed Technologies
* Contributor(s): * Contributor(s):
*/ */
package org.ow2.joram.tools.jmscheck; package org.ow2.joram.tools.jmscheck;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.Date; import java.util.Date;
import javax.jms.Connection; import javax.jms.Connection;
import javax.jms.ConnectionFactory; import javax.jms.ConnectionFactory;
import javax.jms.JMSException; import javax.jms.JMSException;
import javax.jms.Message; import javax.jms.Message;
import javax.jms.MessageConsumer; import javax.jms.MessageConsumer;
import javax.jms.MessageProducer; import javax.jms.MessageProducer;
import javax.jms.Session; import javax.jms.Session;
import javax.jms.TextMessage; import javax.jms.TextMessage;
import javax.naming.InitialContext; import javax.naming.InitialContext;
import javax.naming.NamingException; import javax.naming.NamingException;
import org.objectweb.joram.client.jms.Queue; import org.objectweb.joram.client.jms.Queue;
import org.objectweb.util.monolog.api.BasicLevel; import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger; import org.objectweb.util.monolog.api.Logger;
import fr.dyade.aaa.common.Debug; import fr.dyade.aaa.common.Debug;
/** /**
* Component allowing to check a JMS connector. * Component allowing to check a JMS connector.
*/ */
public final class JMSConnectorCheck { public final class JMSConnectorCheck {
static Logger logger = Debug.getLogger(JMSConnectorCheck.class.getName()); static Logger logger = Debug.getLogger(JMSConnectorCheck.class.getName());
public static final int RUNNING = 0; public static final int RUNNING = 0;
public static final int UNREACHABLE = 1; public static final int UNREACHABLE = 1;
static final String[] info = { "RUNNING", "UNREACHABLE" }; static final String[] info = { "RUNNING", "UNREACHABLE" };
/** retryStatusCount == 0 => RUNNING, retryStatusCount > 0 => UNREACHABLE */ /** retryStatusCount == 0 => RUNNING, retryStatusCount > 0 => UNREACHABLE */
private int retryStatusCount = UNREACHABLE; private int retryStatusCount = UNREACHABLE;
/** /**
* Returns the status of the connector: 0 => RUNNING, >0 => UNREACHABLE. * Returns the status of the connector: 0 => RUNNING, >0 => UNREACHABLE.
* *
* @return the number of unreachable connection * @return the number of unreachable connection
*/ */
public int getStatus() { public int getStatus() {
return retryStatusCount; return retryStatusCount;
} }
public String getStatusInfo() { public String getStatusInfo() {
if (retryStatusCount > 0) if (retryStatusCount > 0)
return info[1] + '(' + retryStatusCount + ')'; return info[1] + '(' + retryStatusCount + ')';
return info[0]; return info[0];
} }
private void setStatus(int retry) { private void setStatus(int retry) {
this.retryStatusCount = retry; this.retryStatusCount = retry;
} }
private int nbtry = 0; private int nbtry = 0;
/** /**
* Returns the total number of try since starting. * Returns the total number of try since starting.
* @return the total number of try since starting. * @return the total number of try since starting.
*/ */
public int getNbTry() { public int getNbTry() {
return nbtry; return nbtry;
} }
private transient int failures = 0; private transient int failures = 0;
/** /**
* Returns the total number of failures since starting. * Returns the total number of failures since starting.
* @return the total number of failures since starting. * @return the total number of failures since starting.
*/ */
public int getNbFailures() { public int getNbFailures() {
return failures; return failures;
} }
private String errorMsg; private String errorMsg;
/** /**
* Returns the error message of the last try. * Returns the error message of the last try.
* Returns null if the test is successful. * Returns null if the test is successful.
* @return * @return
*/ */
public String getErrorMsg() { public String getErrorMsg() {
return errorMsg; return errorMsg;
} }
private String lastConnectTime = "-"; private String lastConnectTime = "-";
/** /**
* Returns the date of last successful connection. * Returns the date of last successful connection.
* @return the date of last successful connection. * @return the date of last successful connection.
*/ */
public String getLastConnectTime() { public String getLastConnectTime() {
return lastConnectTime; return lastConnectTime;
} }
private long latencyConnect = -1; private long latencyConnect = -1;
/** /**
* Returns the latency of the connection during the last try. * Returns the latency of the connection during the last try.
* Returns -1 if the test failed. * Returns -1 if the test failed.
* @return the latency of the connection during the last try. * @return the latency of the connection during the last try.
*/ */
public long getLatencyConnect() { public long getLatencyConnect() {
return latencyConnect; return latencyConnect;
} }
private void setLatencyConnect(long latencyConnect) { private void setLatencyConnect(long latencyConnect) {
this.latencyConnect = latencyConnect; this.latencyConnect = latencyConnect;
} }
private long latencyPubSub = -1; private long latencyPubSub = -1;
/** /**
* Returns the latency of the send/receive during the last try. * Returns the latency of the send/receive during the last try.
* Returns -1 if the test failed. * Returns -1 if the test failed.
* @return the latency of the send/receive during the last try. * @return the latency of the send/receive during the last try.
*/ */
public long getLatencyPubSub() { public long getLatencyPubSub() {
return latencyPubSub; return latencyPubSub;
} }
private void setLatencyPubSub(long latencyPubSub) { private void setLatencyPubSub(long latencyPubSub) {
this.latencyPubSub = latencyPubSub; this.latencyPubSub = latencyPubSub;
} }
/** The maximum time waiting for connection. */ /** The maximum time waiting for connection. */
private int timeout = 10; // in seconds private int timeout = 10; // in seconds
/** /**
* Returns the maximum time waiting for connection. * Returns the maximum time waiting for connection.
* @return the maximum time waiting for connection. * @return the maximum time waiting for connection.
*/ */
public int getTimeOut() { public int getTimeOut() {
return timeout; return timeout;
} }
/** /**
* Sets the maximum time waiting for connection. * Sets the maximum time waiting for connection.
* @param timeOut the maximum time waiting for connection. * @param timeOut the maximum time waiting for connection.
*/ */
public void setTimeOut(int timeOut) { public void setTimeOut(int timeOut) {
this.timeout = timeOut; this.timeout = timeOut;
} }
/** JNDI Name of the ConnectionFactory to use. */ /** JNDI Name of the ConnectionFactory to use. */
private String cfname; private String cfname;
public String getCFName() { public String getCFName() {
return cfname; return cfname;
} }
/* User name and password for authentication */ /* User name and password for authentication */
private String user; private String user;
private String pass; private String pass;
/* Internal name of the queue, be careful this name is not a JNDI name. */ /* Internal name of the queue, be careful this name is not a JNDI name. */
private String qname; private String qname;
private InitialContext ictx; private InitialContext ictx;
private ConnectionFactory cf; private ConnectionFactory cf;
private Queue queue; private Queue queue;
/** /**
* Creates a new component allowing to check a JMS connector. * Creates a new component allowing to check a JMS connector.
* *
* @param cfname JNDI name of the ConnectionFactory to use. * @param cfname JNDI name of the ConnectionFactory to use.
* @param ictx JNDI context allowing to retrieve ConnectionFactory. * @param ictx JNDI context allowing to retrieve ConnectionFactory.
* @param user User name for authentication, if no defined uses the ConnectionFactory default. * @param user User name for authentication, if no defined uses the ConnectionFactory default.
* @param pass Password for authentication, if no defined uses the ConnectionFactory default. * @param pass Password for authentication, if no defined uses the ConnectionFactory default.
* @param qname Internal name of JMS destination. * @param qname Internal name of JMS destination.
* @param timeout Maximum amount of time to wait connecting and receiving messages, by default 10s. * @param timeout Maximum amount of time to wait connecting and receiving messages, by default 10s.
*/ */
public JMSConnectorCheck(String cfname, public JMSConnectorCheck(String cfname,
InitialContext ictx, InitialContext ictx,
String user, String pass, String user, String pass,
String qname, String qname,
int timeOut) { int timeOut) {
this.cfname = cfname; this.cfname = cfname;
this.ictx = ictx; this.ictx = ictx;
this.user = user; this.user = user;
this.pass = pass; this.pass = pass;
this.qname = qname; this.qname = qname;
this.timeout = timeOut; this.timeout = timeOut;
} }
private void getConnectionFactory() throws NamingException { private void getConnectionFactory() throws NamingException {
if (cf != null) return; if (cf != null) return;
ClassLoader originalContextClassLoader = Thread.currentThread().getContextClassLoader(); ClassLoader originalContextClassLoader = Thread.currentThread().getContextClassLoader();
try { try {
Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
cf = (ConnectionFactory) ictx.lookup(cfname); cf = (ConnectionFactory) ictx.lookup(cfname);
try { try {
((org.objectweb.joram.client.jms.ConnectionFactory) cf).getParameters().connectingTimer = timeout; ((org.objectweb.joram.client.jms.ConnectionFactory) cf).getParameters().connectingTimer = timeout;
} catch (ClassCastException exc) { } catch (ClassCastException exc) {
logger.log(BasicLevel.INFO, "JMSConnectorStatus(" + cfname + "): Cannot set connectingTimer."); logger.log(BasicLevel.INFO, "JMSConnectorStatus(" + cfname + "): Cannot set connectingTimer.");
} }
} catch (NamingException exc) { } catch (NamingException exc) {
if (logger.isLoggable(BasicLevel.DEBUG)) if (logger.isLoggable(BasicLevel.DEBUG))
logger.log(BasicLevel.WARN, "JMSConnectorStatus(" + cfname + "): Cannot get ConnectionFactory.", exc); logger.log(BasicLevel.WARN, "JMSConnectorStatus(" + cfname + "): Cannot get ConnectionFactory.", exc);
else else
logger.log(BasicLevel.WARN, "JMSConnectorStatus(" + cfname + "): Cannot get ConnectionFactory."); logger.log(BasicLevel.WARN, "JMSConnectorStatus(" + cfname + "): Cannot get ConnectionFactory.");
throw exc; throw exc;
} finally { } finally {
Thread.currentThread().setContextClassLoader(originalContextClassLoader); Thread.currentThread().setContextClassLoader(originalContextClassLoader);
} }
} }
/** /**
* Checks the related JMS connector, creates a connection, then sends and receives a message. * Checks the related JMS connector, creates a connection, then sends and receives a message.
* After the call the test results are updated. * After the call the test results are updated.
* *
* @return true if the check is successful, false otherwise. * @return true if the check is successful, false otherwise.
*/ */
public boolean check() { public boolean check() {
if (logger.isLoggable(BasicLevel.DEBUG)) if (logger.isLoggable(BasicLevel.DEBUG))
logger.log(BasicLevel.DEBUG, "JMSConnectorStatus(" + cfname + ").check"); logger.log(BasicLevel.DEBUG, "JMSConnectorStatus(" + cfname + ").check");
nbtry += 1; nbtry += 1;
try { try {
getConnectionFactory(); getConnectionFactory();
} catch (NamingException exc) { } catch (NamingException exc) {
failures += 1; failures += 1;
setStatus(getStatus()+1); setStatus(getStatus()+1);
setLatencyConnect(-1L); setLatencyConnect(-1L);
setLatencyPubSub(-1L); setLatencyPubSub(-1L);
errorMsg = "Cannot get ConnectionFactory"; errorMsg = "Cannot get ConnectionFactory";
if (logger.isLoggable(BasicLevel.DEBUG)) if (logger.isLoggable(BasicLevel.DEBUG))
logger.log(BasicLevel.WARN, "JMSConnectorStatus.check(" + cfname + ")<: Cannot get ConnectionFactory.", exc); logger.log(BasicLevel.WARN, "JMSConnectorStatus.check(" + cfname + ")<: Cannot get ConnectionFactory.", exc);
else else
logger.log(BasicLevel.WARN, "JMSConnectorStatus.check(" + cfname + "): Cannot get ConnectionFactory."); logger.log(BasicLevel.WARN, "JMSConnectorStatus.check(" + cfname + "): Cannot get ConnectionFactory.");
return false; return false;
} }
Connection cnx = null; Connection cnx = null;
try { try {
long start = System.nanoTime(); long start = System.nanoTime();
if ((user == null) || (pass == null)) if ((user == null) || (pass == null))
cnx = cf.createConnection(); cnx = cf.createConnection();
else else
cnx = cf.createConnection(user, pass); cnx = cf.createConnection(user, pass);
long dt = System.nanoTime() - start; long dt = System.nanoTime() - start;
setLatencyConnect(dt / 1000000L); setLatencyConnect(dt / 1000000L);
lastConnectTime = DateFormat.getDateTimeInstance().format(new Date()); lastConnectTime = DateFormat.getDateTimeInstance().format(new Date());
} catch (JMSException exc) { } catch (JMSException exc) {
failures += 1; failures += 1;
setStatus(getStatus()+1); setStatus(getStatus()+1);
setLatencyConnect(-1L); setLatencyConnect(-1L);
setLatencyPubSub(-1L); setLatencyPubSub(-1L);
errorMsg = "Cannot connect"; errorMsg = "Cannot connect";
if (logger.isLoggable(BasicLevel.DEBUG)) if (logger.isLoggable(BasicLevel.DEBUG))
logger.log(BasicLevel.WARN, "JMSConnectorStatus.check(" + cfname + "): Cannot connect.", exc); logger.log(BasicLevel.WARN, "JMSConnectorStatus.check(" + cfname + "): Cannot connect.", exc);
else else
logger.log(BasicLevel.WARN, "JMSConnectorStatus.check(" + cfname + "): Cannot connect."); logger.log(BasicLevel.WARN, "JMSConnectorStatus.check(" + cfname + "): Cannot connect.");
return false; return false;
} }
try { try {
Session sess = cnx.createSession(false, Session.AUTO_ACKNOWLEDGE); Session sess = cnx.createSession(false, Session.AUTO_ACKNOWLEDGE);
if (queue == null) if (queue == null)
queue = (Queue) sess.createQueue(qname); queue = (Queue) sess.createQueue(qname);
MessageProducer producer = sess.createProducer(queue); MessageProducer producer = sess.createProducer(queue);
MessageConsumer cons = sess.createConsumer(queue); MessageConsumer cons = sess.createConsumer(queue);
cnx.start(); cnx.start();
TextMessage sent = sess.createTextMessage("Test number " + nbtry); TextMessage sent = sess.createTextMessage("Test number " + nbtry);
long start = System.nanoTime(); long start = System.nanoTime();
producer.send(sent, Message.DEFAULT_DELIVERY_MODE, Message.DEFAULT_PRIORITY, timeout *1000); producer.send(sent, Message.DEFAULT_DELIVERY_MODE, Message.DEFAULT_PRIORITY, timeout *1000);
Message received = cons.receive(timeout *1000); Message received = cons.receive(timeout *1000);
long dt = System.nanoTime() - start; long dt = System.nanoTime() - start;
if (received == null) { if (received == null) {
failures += 1; failures += 1;
setStatus(getStatus()+1); setStatus(getStatus()+1);
setLatencyPubSub(-1L); setLatencyPubSub(-1L);
errorMsg = "Message not received"; errorMsg = "Message not received";
} else { return false;
retryStatusCount = 0; } else {
setLatencyPubSub(dt / 1000000L); retryStatusCount = 0;
errorMsg = null; setLatencyPubSub(dt / 1000000L);
} errorMsg = null;
} catch (JMSException exc) { return true;
failures += 1; }
setStatus(getStatus()+1); } catch (JMSException exc) {
setLatencyPubSub(-1L); failures += 1;
errorMsg = "Error during message send/receive."; setStatus(getStatus()+1);
if (logger.isLoggable(BasicLevel.DEBUG)) setLatencyPubSub(-1L);
logger.log(BasicLevel.WARN, "JMSConnectorStatus.check(" + cfname + "): Error during message send/receive.", exc); errorMsg = "Error during message send/receive.";
else if (logger.isLoggable(BasicLevel.DEBUG))