Package com.salas.bb.core.actions

Source Code of com.salas.bb.core.actions.AbstractLockupHandler

// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software Foundation;
// either version 2 of the License, or (at your option) any later version.
//
// 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program;
// if not, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: AbstractLockupHandler.java,v 1.16 2007/03/23 19:42:47 spyromus Exp $
//

package com.salas.bb.core.actions;

import com.salas.bb.core.ApplicationLauncher;
import com.salas.bb.core.GlobalController;
import com.salas.bb.utils.BrowserLauncher;

import javax.swing.*;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Abstract action for handling of lockups. Has tools for gathering information and
* sending it to the service.
*/
public abstract class AbstractLockupHandler extends AbstractAction
{
    private static final int STACK_DUMP_SIZE_BLOCKED = 50;
    private static final int STACK_DUMP_SIZE_NORMAL = 3;

    /**
     * Creates lockup handler.
     */
    protected AbstractLockupHandler()
    {
    }

    /**
     * Sends message and details to log and service.
     *
     * @param aMessage  message.
     * @param aDetails  details.
     */
    protected void report(String aMessage, String aDetails)
    {
        if (getLogger().isLoggable(Level.INFO)) getLogger().info("Reporting...");
        getLogger().severe(aMessage + "\n" + aDetails);
    }

    /**
     * Terminates application.
     *
     * @param aDoNormalExit TRUE to try follow correct sequence with saving model and preferences.
     */
    protected void terminate(boolean aDoNormalExit)
    {
        if (getLogger().isLoggable(Level.INFO)) getLogger().info("Terminating...");

        if (aDoNormalExit)
        {
            GlobalController controller = GlobalController.SINGLETON;
            if (controller != null)
            {
                controller.prepareToClose(true);
            }
        }

        System.exit(1);
    }

    /**
     * Returns logger to user for logging.
     *
     * @return logger to user for logging.
     */
    protected abstract Logger getLogger();

    /**
     * Collects details: version of VM, locker event, threads dump.
     *
     * @param event locker.
     *
     * @return details.
     */
    protected String collectDetails(AWTEvent event)
    {
        StringBuffer buf = new StringBuffer();

        buf.append(getVMVersion());
        buf.append("\n");

        if (event != null)
        {
            buf.append(event.toString());
            buf.append("\n\n");
        }

        buf.append(getProperties());

        buf.append(getThreadsDump(getLogger()));

        return buf.toString();
    }

    /**
     * Returns application properties.
     *
     * @return application properties.
     */
    private String getProperties()
    {
        StringBuffer buf = new StringBuffer();

        buf.append("Properties:\n");

        buf.append("Installation ID: ");
        buf.append(ApplicationLauncher.getInstallationId()).append("\n");
        buf.append("Installation Runs: ");
        buf.append(ApplicationLauncher.getInstallationRuns()).append("\n");
        buf.append("JGoodies - System Exit Allowed: ");
        buf.append(System.getProperty("jgoodies.SystemExitAllowed")).append("\n");
        buf.append("Context Path: ");
        buf.append(ApplicationLauncher.getContextPath()).append("\n");
        buf.append("Running under JWS: ");
        buf.append(BrowserLauncher.isRunningUnderJWS()).append("\n");
        buf.append("OS: ");
        buf.append(System.getProperty("os.name")).append("\n");
        buf.append("\n");

        buf.append("\n");

        return buf.toString();
    }

    /**
     * Returns VM version information.
     *
     * @return VM information.
     */
    private String getVMVersion()
    {
        OutputStream os = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(os);

        sun.misc.Version.print(ps);

        return os.toString();
    }

    /**
     * Prints information about all threads.
     *
     * @param aLogger logger to use for error reporting.
     *
     * @return threads dump.
     */
    public static String getThreadsDump(Logger aLogger)
    {
        ThreadGroup rootTG = findRootTG(Thread.currentThread().getThreadGroup());
        int activeThreads = rootTG.activeCount();
        Thread[] threads = new Thread[activeThreads];
        int actualThreads = rootTG.enumerate(threads, true);

        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < actualThreads; i++)
        {
            Thread thread = threads[i];
            buf.append(getThreadInfo(thread));
        }

        buf.append(getDeadlockedThreads());

        return buf.toString();
    }

    /**
     * Gathers info about deadlocked threads.
     *
     * @return threads summary.
     */
    private static String getDeadlockedThreads()
    {
        StringBuffer buf = new StringBuffer();

        // Get ID's of all threads
        ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
        long[] ids = mbean.getAllThreadIds();
        if (ids != null)
        {
            for (long id : ids)
            {
                ThreadInfo threadInfo = mbean.getThreadInfo(id, STACK_DUMP_SIZE_BLOCKED);
                buf.append("\n").append(threadInfo).append("\n");

                // Dump the monitor blocks
                String lockName = threadInfo.getLockName();
                if (lockName != null)
                {
                    buf.append("  waiting for ");
                    buf.append(lockName);
                    buf.append(" blocked by ");
                    buf.append(threadInfo.getLockOwnerName());
                    buf.append("@").append(threadInfo.getLockOwnerId()).append("\n");
                }

                // Write the stack trace of thread
                StackTraceElement[] traces = threadInfo.getStackTrace();
                int steps = requiresDetails(threadInfo)
                    ? traces.length : Math.min(STACK_DUMP_SIZE_NORMAL, traces.length);

                for (int j = 0; j < steps; j++)
                {
                    buf.append("\t").append(traces[j]).append("\n");
                }
            }
        }

        return buf.toString();
    }

    /**
     * Returns <code>TRUE</code> if the thread is reported as BLOCKED by someone or it is EDT
     * thread.
     *
     * @param aThreadInfo thread info to analyze.
     *
     * @return thread info.
     */
    private static boolean requiresDetails(Object aThreadInfo)
    {
        String threadInfo = aThreadInfo.toString();
        return threadInfo.indexOf("BLOCKED") != -1 || threadInfo.indexOf("AWT-EventQueue") != -1;
    }

    /**
     * Prints information about single thread.
     *
     * @param thread thread.
     *
     * @return thread info.
     */
    private static String getThreadInfo(Thread thread)
    {
        return "Thread: " + thread.getName() +
               " Running=" + thread.isAlive() +
               " Daemon=" + thread.isDaemon() +
               " Priority=" + thread.getPriority() + "\n";
    }

    /**
     * Finds root group of threads.
     *
     * @param threadGroup group of threads to find parents for.
     *
     * @return root group.
     */
    private static ThreadGroup findRootTG(ThreadGroup threadGroup)
    {
        return (threadGroup.getParent() == null) ? threadGroup : threadGroup.getParent();
    }
}
TOP

Related Classes of com.salas.bb.core.actions.AbstractLockupHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.