Commit de028c6f authored by Andre Freyssinet's avatar Andre Freyssinet

Marks the class final.

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