/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 * 
 * 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): ____________________________________.
 * Contributor(s): Michel Bruno and Guillaume Riviere
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */
package org.objectweb.jonas.server;

import java.rmi.RemoteException;
import org.objectweb.jonas_timer.TimerEvent;
import org.objectweb.jonas_timer.TimerEventListener;
import org.objectweb.jonas_timer.TimerManager;
/**
 * MBean Class for Server Management
 * MBean type: Standard
 * MBean model: Delegate (Server.java)
 */
public class JmxServer implements JmxServerMBean, TimerEventListener {
    
    /**
     * object to manage
     */
    private Server server = null;
    private String serverName = null;
    private String version = null;
    private String orb = null;
    
    /**
     * monitoring objects
     */
    private boolean activate = true;

    private int nbmeasures = 120;
    private int range = 10;
    private Long [] allMeasures;
    private long maxtotalmemory;
    private TimerEvent mytimer = null;
    

    /**
     * constructor
     */
    public JmxServer(Server server,String serverName,String version, String orb){
	this.server = server;
	this.serverName = serverName;
	this.version = version;
	this.orb = orb;	
	initTable();
	//Launch Timer
  	mytimer = TimerManager.getInstance().addTimer(this, range, (Object) new Integer(1), true);  
    }

    /**
     * Server name
     * @return String JOnAS server name
     */
    public String getJonasName() {
	return serverName;
    }

    /**
     * Server version
     * @return String JOnAS server version
     */
    public String getJonasVersion(){
	return version;
    }

    /**
     * Server ORB
     * @return String JOnAS server ORB (Jeremie or Rmi)
     */
    public String getJonasORB(){
	return orb;
    }

    /**
     * Stop server (with stopping the JVM)
     */
    public void stop() throws RemoteException {
	try {
	    server.kill();
	} catch (Exception e) {
	    throw new RemoteException("Error when stopping the JOnAS server: "+e);
	}
    }

    /**
     * run the garbage collector
     */
    public void runGC() throws RemoteException {	
	Runtime.getRuntime().gc();
    }

    /**
     * get jvm used memory
     */
    public Long getCurrentUsedMemory() throws RemoteException {
	return new Long(usedMemory());
    }

    /**
     * get jvm total memory
     */
    public Long getCurrentTotalMemory() throws RemoteException {	
	return new Long(totalMemory());
    }

    /**
     * get/set  for free memory measurement
     */
   public void setRange(Integer range)throws RemoteException {
       if (this.range != range.intValue()) {
	   synchronized(this) {
	       if (range.intValue() < 10) throw new RemoteException("range could not be < 10");
	       this.range= range.intValue();
	       // reset table values
	       initTable();
	       /// change range
	       mytimer.change(this.range, new Integer(1));
	   }
       }
    }
    public Integer getRange()throws RemoteException {
	return new Integer(range);
    }

    /**
     * get/set number of measures
     */
    public void setNumberOfMeasures(Integer nb)throws RemoteException {
 	if (nb.intValue() != this.nbmeasures) {
	    synchronized(this) {
		if (nb.intValue() <= 1) throw new RemoteException("number of measures could not be <= 1");
		this.nbmeasures = nb.intValue();
		initTable();
	    }	
	}
    }
    public Integer getNumberOfMeasures() throws RemoteException {
	return new Integer(nbmeasures);
    }





    /**
     * get the table of value
     */
    public Long[] getMeasuresTable() throws RemoteException {
	return allMeasures;
    }

    // ===============================================================
    // TimerEventListener implementation
    // ===============================================================

    /**
     * The measures timeout has expired
     * Do not synchronize this method to avoid deadlocks!
     */
    public void timeoutExpired(Object arg) {
	int argvalue = ((Integer)arg).intValue();
	switch (argvalue) {
	case 1:
	    //timeout expired
	    long u_value = usedMemory();
	    long tm_value = totalMemory();
	    // put the max total memory
	    if (tm_value > maxtotalmemory)  maxtotalmemory = tm_value;
	    for (int i = 0; i <allMeasures.length; i++) {
		if (i != allMeasures.length - 1) {
		    allMeasures[i] = allMeasures[i+1];
		} else {
		    allMeasures[i] = new Long(u_value);
		}
	    }
	    break;
	default:
	    //timeoutExpired do nothing;
	    break;
	}
    }

    /**
     * set monitoring activation
     */
    public void setActivated(Boolean act) {
	if (act.booleanValue()) {
	    if (activate == false) { 
		synchronized(this) {
		    activate = true;
		    initTable();
		}	    
		// launch timer
		mytimer = TimerManager.getInstance().addTimer(this, range, (Object) new Integer(1), true); 
	    }
	} else {
	    if (activate == true) {
		synchronized(this) {
		    activate = false;
		    initTable();
		    // stop timer
		    mytimer.stop();
		    mytimer.unset();
		}
	    }
	}
    }


    /**
     * get monitoring activation
     */
    public Boolean getActivated(){
	return new Boolean(activate);
    }


    // private function for monitoring
    private long usedMemory() {
	long result = -1;
	while (result < 0) {
	    result = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
	}
	
	return result/1000;
    }
    
    // private function for monitoring
    private long totalMemory() {
	return Runtime.getRuntime().totalMemory()/1000;
    }

    private void initTable() {
	allMeasures = new Long[nbmeasures];
	// init max totalmemory
	maxtotalmemory = totalMemory();
	for (int i = 0; i<allMeasures.length; i++) {
	    allMeasures[i] = new Long(0);
	}
	// init the first value
	allMeasures[allMeasures.length - 1] = new Long(usedMemory());
    }  
}
