/*
* Tigase Jabber/XMPP Server
* Copyright (C) 2004-2012 "Artur Hefczyc" <artur.hefczyc@tigase.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. Look for COPYING file in the top folder.
* If not, see http://www.gnu.org/licenses/.
*
* $Rev$
* Last modified by $Author$
* $Date$
*/
package tigase.stats;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectionNotification;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
//~--- classes ----------------------------------------------------------------
/**
* Created: Aug 24, 2009 12:35:28 PM
*
* @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a>
* @version $Rev$
*/
public class JavaJMXProxy implements StatisticsProviderMBean, NotificationListener {
private static final Logger log = Logger.getLogger(JavaJMXProxy.class.getName());
private float clCompressionRatio = 0;
private int clIOQueueSize = 0;
private long clNetworkBytes = 0;
private float clNetworkBytesPerSec = 0;
private float clPacketsPerSec = 0;
private int clQueueSize = 0;
private float[] clpacks_history = null;
private int clusterCacheSize = 0;
private long clusterPacketsNumber = 0;
private int connectionsNumber = 0;
private int[] conns_history = null;
// Cache section...
private int cpuNo = 0;
private float cpuUsage = 0;
private float[] cpu_history = null;
private long delay = -1;
private float heapUsage = 0;
private float[] heap_history = null;
private String hostname = null;
private String id = null;
private long interval = -1;
private long iqAuthNumber = 0;
private long iqOtherNumber = 0;
private float iqOtherPerSec = 0;
private JMXServiceURL jmxUrl = null;
private JMXConnector jmxc = null;
private long lastCacheUpdate = 0;
private long messagesNumber = 0;
private float messagesPerSec = 0;
private float nonHeapUsage = 0;
private String password = null;
private int port = -1;
private long presencesNumber = 0;
private float presencesPerSec = 0;
private long processCPUTime = 0;
private long queueOverflow = 0;
private int queueSize = 0;
private MBeanServerConnection server = null;
private int serverConnections = 0;
private int[] serverConnectionsHistory = null;
private List<JMXProxyListener> listeners = new LinkedList<JMXProxyListener>();
private long smPacketsNumber = 0;
private float smPacketsPerSec = 0;
private int smQueueSize = 0;
private float[] smpacks_history = null;
private String sysDetails = "No details loaded yet";
private StatisticsProviderMBean tigBean = null;
private StatisticsUpdater updater = null;
private long uptime = 0;
private String urlPath = null;
private String userName = null;
private boolean loadHistory = false;
private boolean initialized = false;
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param id
* @param hostname
* @param port
* @param userName
* @param password
* @param delay
* @param interval
* @param loadHistory
*/
public JavaJMXProxy(String id, String hostname, int port, String userName, String password,
long delay, long interval, boolean loadHistory) {
this.id = id;
this.hostname = hostname;
this.port = port;
this.userName = userName;
this.password = password;
this.delay = delay;
this.interval = interval;
this.urlPath = "/jndi/rmi://" + this.hostname + ":" + this.port + "/jmxrmi";
this.loadHistory = loadHistory;
System.out.println("Created: " + hostname);
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param listener
*/
public void addJMXProxyListener(JMXProxyListener listener) {
listeners.add(listener);
}
/**
* Method description
*
*
* @throws Exception
*/
public void connect() throws Exception {
this.jmxUrl = new JMXServiceURL("rmi", "", 0, this.urlPath);
String[] userCred = new String[] { userName, password };
HashMap<String, Object> env = new HashMap<String, Object>();
env.put(JMXConnector.CREDENTIALS, userCred);
jmxc = JMXConnectorFactory.newJMXConnector(jmxUrl, env);
jmxc.addConnectionNotificationListener(this, null, null);
jmxc.connect();
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param level
*
* @return
*/
@Override
public Map<String, String> getAllStats(int level) {
if (tigBean != null) {
return tigBean.getAllStats(level);
}
return null;
}
/**
* Method description
*
*
* @return
*/
@Override
public int getCLIOQueueSize() {
return clIOQueueSize;
}
/**
* Method description
*
*
* @return
*/
@Override
public float[] getCLPacketsPerSecHistory() {
return clpacks_history;
}
/**
* Method description
*
*
* @return
*/
@Override
public int getCLQueueSize() {
return clQueueSize;
}
/**
* Method description
*
*
* @return
*/
@Override
public float getCPUUsage() {
return cpuUsage;
}
/**
* Method description
*
*
* @return
*/
@Override
public float[] getCPUUsageHistory() {
return cpu_history;
}
/**
* Method description
*
*
* @return
*/
@Override
public int getCPUsNumber() {
return cpuNo;
}
/**
* Method description
*
*
* @return
*/
@Override
public int getClusterCacheSize() {
return clusterCacheSize;
}
/**
* Method description
*
*
* @return
*/
@Override
public float getClusterCompressionRatio() {
return clCompressionRatio;
}
/**
* Method description
*
*
* @return
*/
@Override
public long getClusterNetworkBytes() {
return clNetworkBytes;
}
/**
* Method description
*
*
* @return
*/
@Override
public float getClusterNetworkBytesPerSecond() {
return clNetworkBytesPerSec;
}
/**
* Method description
*
*
* @return
*/
@Override
public long getClusterPackets() {
return clusterPacketsNumber;
}
/**
* Method description
*
*
* @return
*/
@Override
public float getClusterPacketsPerSec() {
return clPacketsPerSec;
}
/**
* Method description
*
*
* @param compName
* @param level
*
* @return
*/
@Override
public Map<String, String> getComponentStats(String compName, int level) {
if (tigBean != null) {
return tigBean.getComponentStats(compName, level);
}
return null;
}
/**
* Method description
*
*
* @return
*/
@Override
public List<String> getComponentsNames() {
if (tigBean != null) {
return tigBean.getComponentsNames();
}
return null;
}
/**
* Method description
*
*
* @return
*/
@Override
public int getConnectionsNumber() {
return connectionsNumber;
}
/**
* Method description
*
*
* @return
*/
@Override
public int[] getConnectionsNumberHistory() {
return conns_history;
}
/**
* Method description
*
*
* @return
*/
@Override
public float getHeapMemUsage() {
return heapUsage;
}
/**
* Method description
*
*
* @return
*/
@Override
public float[] getHeapUsageHistory() {
return heap_history;
}
/**
* Method description
*
*
* @return
*/
@Override
public long getIQAuthNumber() {
return iqAuthNumber;
}
/**
* Method description
*
*
* @return
*/
@Override
public long getIQOtherNumber() {
return iqOtherNumber;
}
/**
* Method description
*
*
* @return
*/
@Override
public float getIQOtherNumberPerSec() {
return iqOtherPerSec;
}
/**
* Method description
*
*
* @return
*/
public String getId() {
return id;
}
/**
* Method description
*
*
* @return
*/
public long getLastCacheUpdate() {
return lastCacheUpdate;
}
/**
* Method description
*
*
* @return
*/
@Override
public long getMessagesNumber() {
return messagesNumber;
}
/**
* Method description
*
*
* @return
*/
@Override
public float getMessagesNumberPerSec() {
return messagesPerSec;
}
/**
* Method description
*
*
* @return
*/
@Override
public String getName() {
if (tigBean != null) {
return tigBean.getName();
}
return null;
}
/**
* Method description
*
*
* @return
*/
@Override
public float getNonHeapMemUsage() {
return nonHeapUsage;
}
/**
* Method description
*
*
* @return
*/
@Override
public long getPresencesNumber() {
return presencesNumber;
}
/**
* Method description
*
*
* @return
*/
@Override
public float getPresencesNumberPerSec() {
return presencesPerSec;
}
/**
* Method description
*
*
* @return
*/
@Override
public long getProcesCPUTime() {
return processCPUTime;
}
/**
* Method description
*
*
* @return
*/
@Override
public long getQueueOverflow() {
return queueOverflow;
}
/**
* Method description
*
*
* @return
*/
@Override
public int getQueueSize() {
return queueSize;
}
/**
* Method description
*
*
* @return
*/
@Override
public long getSMPacketsNumber() {
return smPacketsNumber;
}
/**
* Method description
*
*
* @return
*/
@Override
public float getSMPacketsNumberPerSec() {
return smPacketsPerSec;
}
/**
* Method description
*
*
* @return
*/
@Override
public float[] getSMPacketsPerSecHistory() {
return smpacks_history;
}
/**
* Method description
*
*
* @return
*/
@Override
public int getSMQueueSize() {
return smQueueSize;
}
/**
* Method description
*
*
* @return
*/
@Override
public int getServerConnections() {
return serverConnections;
}
/**
* Method description
*
*
* @return
*/
@Override
public int[] getServerConnectionsHistory() {
return serverConnectionsHistory;
}
/**
* Method description
*
*
* @return
*/
@Override
public String getSystemDetails() {
return sysDetails;
}
/**
* Method description
*
*
* @return
*/
@Override
public long getUptime() {
return uptime;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param notification
* @param handback
*/
@Override
public void handleNotification(Notification notification, Object handback) {
if (notification.getType().equals(JMXConnectionNotification.OPENED)) {
System.out.println("Connected: " + hostname);
try {
server = jmxc.getMBeanServerConnection();
ObjectName obn = new ObjectName(StatisticsCollector.STATISTICS_MBEAN_NAME);
tigBean = MBeanServerInvocationHandler.newProxyInstance(server, obn,
StatisticsProviderMBean.class, false);
if (loadHistory) {
cpu_history = tigBean.getCPUUsageHistory();
System.out.println(hostname + " loaded cpu_history, size: " + cpu_history.length);
heap_history = tigBean.getHeapUsageHistory();
System.out.println(hostname + " loaded heap_history, size: " + heap_history.length);
smpacks_history = tigBean.getSMPacketsPerSecHistory();
System.out.println(hostname + " loaded smpacks_history, size: " + smpacks_history.length);
clpacks_history = tigBean.getCLPacketsPerSecHistory();
System.out.println(hostname + " loaded clpacks_history, size: " + clpacks_history.length);
conns_history = tigBean.getConnectionsNumberHistory();
System.out.println(hostname + " loaded conns_history, size: " + conns_history.length);
serverConnectionsHistory = tigBean.getServerConnectionsHistory();
System.out.println(hostname + " loaded server_conns_history, size: "
+ serverConnectionsHistory.length);
} else {
System.out.println(hostname + " loading history switched off.");
}
for (JMXProxyListener jMXProxyListener : listeners) {
jMXProxyListener.connected(id, this);
}
start();
} catch (Exception e) {
e.printStackTrace();
}
return;
}
if (notification.getType().equals(JMXConnectionNotification.CLOSED)) {
server = null;
tigBean = null;
for (JMXProxyListener jMXProxyListener : listeners) {
jMXProxyListener.disconnected(id);
}
return;
}
if (notification.getType().equals(JMXConnectionNotification.FAILED)) {
System.out.println("Reconnection to {hostName} failed...");
return;
}
System.out.println("Unsupported JMX notification: {notification.getType()}");
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public boolean isConnected() {
return tigBean != null;
}
/**
* Method description
*
*
* @return
*/
public boolean isInitialized() {
return isConnected() && initialized;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*/
public void start() {
if (updater == null) {
updater = new StatisticsUpdater();
System.out.println("Started: " + hostname);
}
}
/**
* Method description
*
*/
public void update() {
if (tigBean != null) {
// This doesn't ever change so it is enough to query it once
if (cpuNo == 0) {
cpuNo = tigBean.getCPUsNumber();
}
uptime = tigBean.getUptime();
processCPUTime = tigBean.getProcesCPUTime();
connectionsNumber = tigBean.getConnectionsNumber();
serverConnections = tigBean.getServerConnections();
clusterCacheSize = tigBean.getClusterCacheSize();
queueSize = tigBean.getQueueSize();
smQueueSize = tigBean.getSMQueueSize();
clQueueSize = tigBean.getCLQueueSize();
clIOQueueSize = tigBean.getCLIOQueueSize();
queueOverflow = tigBean.getQueueOverflow();
smPacketsNumber = tigBean.getSMPacketsNumber();
clusterPacketsNumber = tigBean.getClusterPackets();
messagesNumber = tigBean.getMessagesNumber();
presencesNumber = tigBean.getPresencesNumber();
smPacketsPerSec = tigBean.getSMPacketsNumberPerSec();
clPacketsPerSec = tigBean.getClusterPacketsPerSec();
messagesPerSec = tigBean.getMessagesNumberPerSec();
presencesPerSec = tigBean.getPresencesNumberPerSec();
// iqOtherNumber = tigBean.getIQOtherNumber();
// iqOtherPerSec = tigBean.getIQOtherNumberPerSec();
// iqAuthNumber = tigBean.getIQAuthNumber();
cpuUsage = tigBean.getCPUUsage();
heapUsage = tigBean.getHeapMemUsage();
nonHeapUsage = tigBean.getNonHeapMemUsage();
sysDetails = tigBean.getSystemDetails();
clCompressionRatio = tigBean.getClusterCompressionRatio();
clNetworkBytes = tigBean.getClusterNetworkBytes();
clNetworkBytesPerSec = tigBean.getClusterNetworkBytesPerSecond();
lastCacheUpdate = System.currentTimeMillis();
initialized = true;
}
}
//~--- inner classes --------------------------------------------------------
private class StatisticsUpdater {
private Timer updateTimer = null;
//~--- constructors -------------------------------------------------------
private StatisticsUpdater() {
updateTimer = new Timer("stats-updater", true);
updateTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
if (server == null) {
connect();
}
if (server != null) {
update();
}
} catch (IOException e) {
Throwable cause = e;
while (cause.getCause() != null) {
cause = cause.getCause();
}
log.log(Level.WARNING, "{0}, retrying in {1} seconds.",
new Object[] { cause.getMessage(),
interval / 1000 });
log.log(Level.FINEST, e.getMessage(), e);
} catch (Exception e) {
log.log(Level.WARNING, "Problem retrieving statistics: ", e);
}
}
}, delay, interval);
}
}
/* (non-Javadoc)
* @see tigase.stats.StatisticsProviderMBean#getStatsHistory(java.lang.String[])
*/
@Override
public Map<String, LinkedList<Object>> getStatsHistory(String[] statsKeys) {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see tigase.stats.StatisticsProviderMBean#getCurStats(java.lang.String[])
*/
@Override
public Map<String, Object> getCurStats(String[] statsKeys) {
// TODO Auto-generated method stub
return null;
}
}
//~ Formatted in Sun Code Convention
//~ Formatted by Jindent --- http://www.jindent.com