/*
* 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.server.monitor;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.LinkedList;
import java.util.logging.Logger;
import tigase.sys.CPULoadListener;
import tigase.sys.MemoryChangeListener;
import tigase.sys.OnlineJidsReporter;
import tigase.sys.ShutdownHook;
import tigase.sys.TigaseRuntime;
import tigase.xmpp.JID;
/**
* Created: Feb 19, 2009 12:31:14 PM
*
* @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a>
* @version $Rev$
*/
public class MonitorRuntime extends TigaseRuntime {
/**
* Variable <code>log</code> is a class logger.
*/
private static final Logger log =
Logger.getLogger(MonitorRuntime.class.getName());
private static MonitorRuntime runtime = null;
private LinkedList<ShutdownHook> shutdownHooks =
new LinkedList<ShutdownHook>();
private LinkedList<OnlineJidsReporter> onlineJidsReporters =
new LinkedList<OnlineJidsReporter>();
private MonitorRuntime() {
super();
Runtime.getRuntime().addShutdownHook(new MainShutdownThread());
}
public static MonitorRuntime getMonitorRuntime() {
if (runtime == null) {
runtime = new MonitorRuntime();
}
return runtime;
}
@Override
public synchronized void addShutdownHook(ShutdownHook hook) {
shutdownHooks.add(hook);
}
@Override
public synchronized void addMemoryChangeListener(MemoryChangeListener memListener) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public synchronized void addCPULoadListener(CPULoadListener cpuListener) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public synchronized void addOnlineJidsReporter(OnlineJidsReporter onlineReporter) {
onlineJidsReporters.add(onlineReporter);
}
@Override
public boolean hasCompleteJidsInfo() {
if (onlineJidsReporters.size() == 1) {
return onlineJidsReporters.getFirst().hasCompleteJidsInfo();
} else {
for (OnlineJidsReporter onlineJidsReporter : onlineJidsReporters) {
if (!onlineJidsReporter.hasCompleteJidsInfo()) {
return false;
}
}
}
return true;
}
@Override
public boolean isJidOnline(JID jid) {
if (onlineJidsReporters.size() == 1) {
return onlineJidsReporters.getFirst().containsJid(jid.getBareJID());
} else {
for (OnlineJidsReporter onlineJidsReporter : onlineJidsReporters) {
if (onlineJidsReporter.containsJid(jid.getBareJID())) {
return true;
}
}
}
return false;
}
/**
*
* @param jid
* @return
*/
@Override
public JID[] getConnectionIdsForJid(JID jid) {
if (onlineJidsReporters.size() == 1) {
return onlineJidsReporters.getFirst().getConnectionIdsForJid(jid.getBareJID());
} else {
for (OnlineJidsReporter onlineJidsReporter : onlineJidsReporters) {
JID[] connIds = onlineJidsReporter.getConnectionIdsForJid(jid.getBareJID());
if (connIds != null) {
return connIds;
}
}
}
return null;
}
private class ShutdownHandlerThread extends Thread {
private ShutdownHook hook = null;
private String result = null;
public ShutdownHandlerThread(ThreadGroup group, ShutdownHook hook) {
super(group, hook.getName());
this.hook = hook;
setDaemon(true);
}
@Override
public void run () {
result = hook.shutdown();
}
public String getResultMessage() {
return result;
}
}
private class MainShutdownThread extends Thread {
public MainShutdownThread() {
super();
setName("MainShutdownThread");
}
@Override
public void run() {
System.out.println("ShutdownThread started...");
log.warning("ShutdownThread started...");
LinkedList<ShutdownHandlerThread> thlist =
new LinkedList<ShutdownHandlerThread>();
ThreadGroup threads =
new ThreadGroup(Thread.currentThread().getThreadGroup(),
"Tigase Shutdown");
for (ShutdownHook shutdownHook : shutdownHooks) {
ShutdownHandlerThread thr =
new ShutdownHandlerThread(threads, shutdownHook);
thr.start();
thlist.add(thr);
}
// We allow for max 10 secs for the shutdown code to run...
long shutdownStart = System.currentTimeMillis();
while (threads.activeCount() > 0 &&
(System.currentTimeMillis() - shutdownStart) < 10000) {
try {
sleep(100);
} catch (Exception e) { }
}
StringBuilder sb = new StringBuilder();
for (ShutdownHandlerThread shutdownHandlerThread : thlist) {
if (shutdownHandlerThread.getResultMessage() != null) {
sb.append(shutdownHandlerThread.getResultMessage());
}
}
ThreadMXBean thBean = ManagementFactory.getThreadMXBean();
sb.append("\nTotal number of threads: " + thBean.getThreadCount()).append('\n');
long[] tids = thBean.findDeadlockedThreads();
if (tids != null && tids.length > 0) {
sb.append("Locked threads:\n");
ThreadInfo[] lockedThreads = thBean.getThreadInfo(tids);
for (ThreadInfo threadInfo : lockedThreads) {
sb.append("Locked thread " + threadInfo.getThreadName() + " on " +
threadInfo.getLockInfo().toString()).append('\n');
StackTraceElement[] ste = threadInfo.getStackTrace();
for (StackTraceElement stackTraceElement : ste) {
sb.append(stackTraceElement.toString()).append('\n');
}
}
} else {
sb.append("No locked threads.\n");
}
if (sb.length() > 0) {
System.out.println(sb.toString());
log.warning(sb.toString());
}
System.out.println("ShutdownThread finished...");
log.warning("ShutdownThread finished...");
}
}
}