001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.util;
020
021import java.io.PrintStream;
022
023/**
024 * Periodically dumps Thread and memory usage
025 * @author apr@cs.com.uy
026 * @version $Id$
027 * @see Logger
028 */
029public class SystemMonitor implements Runnable, LogSource, Loggeable
030{
031    private Logger logger = null;
032    private String realm  = null;
033    private int sleepTime = 0;
034    private int delay     = 0;
035    private Thread thread = null;
036    private volatile boolean shutdown = false;
037
038    /**
039     * noargs constructor
040     */
041    public SystemMonitor () {
042        super();
043    }
044    /**
045     * Constructs a monitor with the given polling interval and logger binding.
046     *
047     * @param sleepTime sleep
048     * @param logger current logger
049     * @param realm  instance realm
050     */
051    public SystemMonitor (int sleepTime, Logger logger, String realm) {
052        setLogger (logger, realm);
053        this.sleepTime = sleepTime;
054        startThread();
055    }
056    
057    private void startThread() {
058        if (thread != null)
059            thread.interrupt();
060        else if (sleepTime > 0) {
061            thread = new Thread(this,"SystemMonitor");
062            thread.setPriority (Thread.MIN_PRIORITY);
063            thread.start();
064        }
065    }
066
067    /**
068     * Sets the polling interval and (re)starts the monitor thread.
069     *
070     * @param sleepTime new sleepTime;
071     */
072    public void setSleepTime (int sleepTime) {
073        this.sleepTime = sleepTime;
074        startThread();
075    }
076
077    void dumpThreads (ThreadGroup g, PrintStream p, String indent) {
078        Thread[] list = new Thread[g.activeCount()+5];
079        int nthreads = g.enumerate(list);
080        for (int i=0; i<nthreads; i++) 
081            p.println (indent + list[i]);
082    }
083
084    /**
085     * Recursively dumps {@code g} and every parent thread group, with their threads.
086     *
087     * @param g starting thread group
088     * @param p destination stream
089     * @param indent prefix used for indentation
090     */
091    public void showThreadGroup (ThreadGroup g, PrintStream p, String indent) {
092        if (g.getParent() != null)
093            showThreadGroup (g.getParent(), p, indent + "  ");
094        else
095            dumpThreads (g, p, indent + "    ");
096    }
097
098    public void run() {
099        while (!shutdown) {
100            Logger.log (new LogEvent (this, "SystemMonitor", this));
101            try {
102                long expected = System.currentTimeMillis() + sleepTime;
103                Thread.sleep (sleepTime);
104                delay = (int) (System.currentTimeMillis() - expected);
105            } catch (InterruptedException e) { }
106        }
107    }
108
109    /** Signals the monitor's run loop to terminate. */
110    public void shutdown() {
111        shutdown = true;
112    }
113
114    public void dump (PrintStream p, String indent) {
115        String newIndent = indent + "  ";
116        Runtime r = Runtime.getRuntime();
117        p.println (indent + "--- memory ---");
118        p.println (newIndent+" freeMemory="+r.freeMemory());
119        p.println (newIndent+"totalMemory="+r.totalMemory());
120        p.println (newIndent+"inUseMemory="+(r.totalMemory()-r.freeMemory()));
121        p.println ("");
122        p.println (indent + "--- threads ---");
123        p.println (newIndent+"      delay="+delay+" ms");
124        p.println (newIndent+"    threads="+Thread.activeCount());
125        showThreadGroup (Thread.currentThread().getThreadGroup(), p, newIndent);
126        p.println ("");
127        NameRegistrar.getInstance().dump (p, indent);
128    }
129    public void setLogger (Logger logger, String realm) {
130        this.logger = logger;
131        this.realm  = realm;
132    }
133    public String getRealm () {
134        return realm;
135    }
136    public Logger getLogger() {
137        return logger;
138    }
139}
140
141