/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2006-2009 Bull S.A.S.
 * Contact: jonas-team@ow2.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
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.lib.management.domain.proxy.server;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.ObjectName;
import javax.management.Query;
import javax.management.QueryExp;
import javax.management.ReflectionException;
import javax.management.RuntimeOperationsException;

import org.objectweb.util.monolog.api.BasicLevel;
import org.ow2.jonas.lib.bootstrap.JProp;
import org.ow2.jonas.lib.management.domain.DeployAction;
import org.ow2.jonas.lib.management.domain.DomainMonitor;
import org.ow2.jonas.lib.management.domain.proxy.JMXProxy;
import org.ow2.jonas.lib.management.domain.proxy.clusterd.ClusterDaemonProxy;
import org.ow2.jonas.lib.management.javaee.J2EEServerState;
import org.ow2.jonas.lib.management.javaee.J2eeObjectName;
import org.ow2.jonas.lib.util.JonasObjectName;
import org.ow2.jonas.lib.util.JoramObjectName;

/**
 * A ServerProxy proxy MBean represents a server in the domain on the master
 * side. Implements state transition diagram.
 * @author Adriana Danes
 */
public class ServerProxy extends JMXProxy implements ServerProxyMBean {
    /**
     * J2EEServer ObjectName corresponding to the represented server.
     */
    private ObjectName serverOn = null;

    /**
     * Ref to the ClusterDaemon that can monitor the Server null if no
     * ClusterDaemon declared or found.
     */
    private ClusterDaemonProxy clusterdaemon = null;

    /**
     * The server description.
     */
    private String description = null;

    /**
     * Extra parameter for remote server start-up via a cluster daemon.
     */
    private String xprem = null;

    /**
     * ??
     */
    String autoBoot = null;

    /**
     * Deploy directory.
     */
    public String deployDir = null;

    /**
     * <code>true</code> means server in standby state.
     */
    boolean standby = false;

    /**
     * <code>true</code>Stop performed via admin.
     */
    boolean stopThruAdmin = false;

    /**
     * Constructor.
     * @param dm current domain monitor
     * @param serverName the name of the managed server
     * @param urls Collection of urls to connect to the server. If null, the
     *        ServerProxy corresponds to the local server (the current master).
     * @param cdp possible cluster daemon
     */
    public ServerProxy(final DomainMonitor dm, final String serverName, final Collection urls, final ClusterDaemonProxy cdp) {
        super(dm, serverName, urls);
        if (urls == null) {
            setConnection(getDm().getJmxService().getJmxServerConnection());
        }
        clusterdaemon = cdp;
        serverOn = J2eeObjectName.J2EEServer(dm.getDomainName(), serverName);
        checkit(false);
    }

    /**
     * Notification from discovery with sate STOPPING.
     */
    public void notifyStopping() {
        logger.log(BasicLevel.DEBUG, getName());
        // Set indicator to false in order to reset general info in case
        // the server restarts
        setInfoSet(false);
        setState(J2EEServerState.STOPPING);
    }

    /**
     * @return <code>true</code> if the server was stopped thru admin console.
     */
    public boolean isStopThruAdmin() {
        return stopThruAdmin;
    }

    /**
     * @param stopThruAdmin <code>true</code> if the server was stopped thru
     *        admin console.
     */
    public void setStopThruAdmin(final boolean stopThruAdmin) {
        this.stopThruAdmin = stopThruAdmin;
    }

    /**
     * Check the MBean server connection and possibly change state in
     * UNREACHABLE or FAILED. This method implements the ServerProxy's state
     * management.
     * @param readall read all monitoring info if server RUNNING
     */
    public void checkit(final boolean readall) {
        logger.log(BasicLevel.DEBUG, getName());

        if (checkConnection()) {
            // Connection is working normally
            ObjectName on = J2eeObjectName.J2EEServer(getDomain(), getName());
            String serverState = null;
            try {
                serverState = (String) getConnection().getAttribute(on,
                        ServerProxyProperties.STATE_ATTRIBUTE_KEY.getPropertyName());
            } catch (AttributeNotFoundException e) {
                setState(J2EEServerState.UNKNOWN);
                logger.log(BasicLevel.ERROR, "Cannot check state for server: " + getName() + " :", e);
            } catch (InstanceNotFoundException e) {
                setState(J2EEServerState.UNKNOWN);
                logger.log(BasicLevel.ERROR, "Cannot check state for server: " + getName() + " :", e);
            } catch (MBeanException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.ERROR, "Cannot check state for server: " + getName() + " :", e);
            } catch (ReflectionException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.ERROR, "Cannot check state for server: " + getName() + " :", e);
            } catch (IOException e) {
                /**
                 * The server is really inaccessible
                 */
                this.standby = false;
                setState(J2EEServerState.UNREACHABLE);
            }
            J2EEServerState newState = translateState(serverState);
            J2EEServerState oldState = getJ2EEServerState();
            if (!oldState.equals(newState)) {
                if (J2EEServerState.RUNNING.equals(newState)) {
                    getDm().notifyServerProxyRunning(this);
                } else if (J2EEServerState.STOPPED.equals(newState)) {
                    /**
                     * Connection is ok, and state is stopped => standby mode.
                     */
                    this.standby = true;
                }
                setState(newState);
            }
        } else {
            /**
             * The server is really inaccessible
             */
            this.standby = false;
            if (stopThruAdmin) {
                setState(J2EEServerState.STOPPED);
            } else {
                /**
                 * the state transition STOPPED --> UNREACHABLE is denied.
                 */
                setState(J2EEServerState.UNREACHABLE);
                // Make sure that connection is null in order to call connect
                // the next time checkConnection() will be called
                // FIXME, is this the right place ???
                disconnect();
            }

        }
        if (readall && J2EEServerState.RUNNING.equals(getJ2EEServerState())) {
            // Update some information about the server
            getMonitoringInfo();
        }
    }

    /**
     * Translates server state provided by the J2EEServer MBean to JMXProxy
     * state.
     * @param serverState state provided by the J2EEServer MBean
     * @return JMXProxy state
     */
    private J2EEServerState translateState(final String serverState) {
        if (J2EEServerState.STARTING.getName().equals(serverState)) {
            stopThruAdmin = false;
            return J2EEServerState.STARTING;
        } else if (J2EEServerState.RUNNING.getName().equals(serverState)) {
            stopThruAdmin = false;
            return J2EEServerState.RUNNING;
        } else if (J2EEServerState.STOPPING.getName().equals(serverState)) {
            return J2EEServerState.STOPPING;
        } else if (J2EEServerState.STOPPED.getName().equals(serverState)) {
            if (standby) {
                return J2EEServerState.STANDBY;
            }
            return J2EEServerState.STOPPED;
        } else if (J2EEServerState.FAILED.getName().equals(serverState)) {
            return J2EEServerState.FAILED;
        } else if (J2EEServerState.UNKNOWN.getName().equals(serverState)) {
            return J2EEServerState.UNKNOWN;
        } else if (J2EEServerState.UNREACHABLE.getName().equals(serverState)) {
            return J2EEServerState.UNREACHABLE;
        } else if (J2EEServerState.INITIAL.getName().equals(serverState)) {
            return J2EEServerState.INITIAL;
        } else {
            return J2EEServerState.UNKNOWN;
        }
    }

    /**
     * @return The name corresponding to the represented server
     */
    public String getServerName() {
        return getName();
    }

    /**
     * @return The name of the associated cluster daemon, if any, null otherwise
     */
    public String getClusterDaemonName() {
        if (clusterdaemon == null) {
            return null;
        }
        return clusterdaemon.getName();
    }

    /**
     * Start the Server via the ClusterDaemon. discovery notification concerning
     * the represented server
     * @param standby true to enter standby mode.
     */
    public void start(final boolean standby) {
        String message = "Trying to start server: " + getName();
        if (standby) {
            message = "Trying to start server: " + getName() + " in standby mode.";
        }
        logger.log(BasicLevel.DEBUG, message);
        J2EEServerState serverState = getJ2EEServerState();
        /**
         * Cannot start the server.
         */
        if (J2EEServerState.RUNNING.equals(serverState) || J2EEServerState.STARTING.equals(serverState)
                || J2EEServerState.STOPPING.equals(serverState)) {
            logger.log(BasicLevel.DEBUG, "Cannot start the server: " + getName() + ". Current state is " + serverState);
            return;
        }
        setState(J2EEServerState.STARTING);
        /**
         * Keep the proxy coherent.
         */
        this.stopThruAdmin = false;
        if (J2EEServerState.UNREACHABLE.equals(serverState) || J2EEServerState.UNKNOWN.equals(serverState)
                || J2EEServerState.STOPPED.equals(serverState)) {
            // A cluster daemon is required to start a server
            if (clusterdaemon == null) {
                logger
                        .log(BasicLevel.ERROR, "No ClusterDaemon associated to server: " + getName() + " in state: "
                                + getState());
                return;
            }
            String xtraParam = ServerProxyProperties.CLEAN_OPTION.getPropertyName() + " ";
            if (standby) {
                xtraParam += ServerProxyProperties.STANDBY_OPTION.getPropertyName() + " ";
            }
            clusterdaemon.startServer(getName(), xtraParam);
            checkit(true);
        } else {
            logger.log(BasicLevel.DEBUG, "Try to start server: " + getName() + " in state: " + getState());
            String opName = ServerProxyProperties.START_OPERATION_KEY.getPropertyName();
            this.standby = standby;
            Object[] params = {standby};
            String[] signature = {boolean.class.toString()};
            try {
                getConnection().invoke(serverOn, opName, params, signature);
            } catch (InstanceNotFoundException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.ERROR, "Cannot start server: " + getName() + " :", e);
            } catch (MBeanException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.ERROR, "Cannot start server: " + getName() + " :", e);
            } catch (ReflectionException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.ERROR, "Cannot start server: " + getName() + " :", e);
            } catch (IOException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.ERROR, "Cannot start server: " + getName() + " :", e);
            }
        }
    }
    /**
     * Stop the server.
     */
    public void stop() {
        String message = "Trying to stop server: " + getName();
        logger.log(BasicLevel.DEBUG, message);
        J2EEServerState serverState = getJ2EEServerState();
        /**
         * Cannot stop the server.
         */
        if (J2EEServerState.STOPPED.equals(serverState)
                || J2EEServerState.STOPPING.equals(serverState)
                || J2EEServerState.STARTING.equals(serverState)) {
            logger.log(BasicLevel.DEBUG, "Cannot stop the server: " + getName() + ". Current state is " + serverState);
            return;
        }
        setState(J2EEServerState.STOPPING);
        if (J2EEServerState.UNREACHABLE.equals(serverState) || J2EEServerState.UNKNOWN.equals(serverState)) {
            // A CD is required to stop a server
            if (clusterdaemon == null) {
                logger.log(BasicLevel.ERROR, "No ClusterDaemon associated to server: " + getName() + " in state: " + getState());
                return;
            }
            //stop the jvm.
            clusterdaemon.haltServer(getName(), null);
            checkit(true);
        } else {
            //Stop the jvm.
            String opName = ServerProxyProperties.HALT_OPERATION_KEY.getPropertyName();
            Object[] params = null;
            String[] signature = null;
            try {
                getConnection().invoke(serverOn, opName, params, signature);
            } catch (InstanceNotFoundException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.DEBUG, "Cannot stop server: " + getName() + " :", e);
            } catch (MBeanException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.DEBUG, "Cannot stop server: " + getName() + " :", e);
            } catch (ReflectionException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.DEBUG, "Cannot stop server: " + getName() + " :", e);
            } catch (IOException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.DEBUG, "Cannot stop server: " + getName() + " :", e);
            }
        }
        stopThruAdmin = true;
    }
    /**
     * Stop the server.
     * @param standby true to enter standby mode.
     */
    public void stop(final boolean standby) {
        String message = "Trying to stop server: " + getName();
        if (standby) {
            message = "Trying to stop server: " + getName() + " in standby mode.";
        } else {
            stop();
        }
        logger.log(BasicLevel.DEBUG, message);
        J2EEServerState serverState = getJ2EEServerState();
        /**
         * Cannot stop the server.
         */
        if (J2EEServerState.STOPPED.equals(serverState)
                || J2EEServerState.STOPPING.equals(serverState)
                || J2EEServerState.STARTING.equals(serverState)) {
            logger.log(BasicLevel.DEBUG, "Cannot stop the server: " + getName() + ". Current state is " + serverState);
            return;
        }
        setState(J2EEServerState.STOPPING);
        if (J2EEServerState.UNREACHABLE.equals(serverState) || J2EEServerState.UNKNOWN.equals(serverState)) {
            // A CD is required to start a server
            if (clusterdaemon == null) {
                logger.log(BasicLevel.ERROR, "No ClusterDaemon associated to server: " + getName() + " in state: " + getState());
                return;
            }
            //do not stop the bootstrap
            clusterdaemon.stopServer(getName(), null);
            checkit(false);
        } else {
            //Stop the jvm.
            this.standby = true;
            String opName = ServerProxyProperties.STOP_OPERATION_KEY.getPropertyName();
            Object[] params = null;
            String[] signature = null;
            try {
                getConnection().invoke(serverOn, opName, params, signature);
            } catch (InstanceNotFoundException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.DEBUG, "Cannot stop server: " + getName() + " :", e);
            } catch (MBeanException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.DEBUG, "Cannot stop server: " + getName() + " :", e);
            } catch (ReflectionException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.DEBUG, "Cannot stop server: " + getName() + " :", e);
            } catch (IOException e) {
                setState(J2EEServerState.FAILED);
                logger.log(BasicLevel.DEBUG, "Cannot stop server: " + getName() + " :", e);
            }
        }
        stopThruAdmin = true;
    }

    /**
     * Deploy a filename on the represented (remote) server
     * @param fileName the absolute name of the file containing the
     *        module/application to deploy
     */
    public void deployModule(final String fileName) {

        logger.log(BasicLevel.DEBUG, fileName);

        File file = new File(fileName);
        if (deployDir == null) {
            // Check that jonas_base was set
            if (jonasBase == null) {
                logger.log(BasicLevel.ERROR, "Can't do deploy operation as JONAS_BASE not set.");
                return;
            }
            deployDir = jonasBase + File.separator + "deploy";
        }
        String targetFileName = deployDir + File.separator + file.getName();

        logger.log(BasicLevel.DEBUG, targetFileName);

        // Build a DeployAction and register it in DomainMonitor
        DeployAction act = new DeployAction(this, fileName, DeployAction.DEPLOY);
        if (getDm() == null) {
            logger.log(BasicLevel.ERROR, "Operation reserved to the master");
            return;
        }
        if (!getDm().registerDeployAction(act)) {
            logger.log(BasicLevel.WARN, "Operation already running for " + targetFileName);
            return;
        }

        // Check connection
        if (!checkConnection()) {
            logger.log(BasicLevel.WARN, "Cannot deploy: Server " + getName() + " not running");
            act.setError("server not running");
            return;
        }

        // operation depends on the type of the file
        String opName = ServerProxyProperties.DEPLOY_OPERATION_KEY.getPropertyName();
        String[] params = {targetFileName};
        String[] signature = {"java.lang.String"};
        try {
            getConnection().invoke(serverOn, opName, params, signature);
        } catch (InstanceNotFoundException e) {
            logger.log(BasicLevel.ERROR, "Cannot deploy file: " + targetFileName + " :", e);
            act.setError("Remote J2EEServer not registered");
            return;
        } catch (MBeanException e) {
            logger.log(BasicLevel.ERROR, "Cannot deploy file: " + targetFileName + " :", e);
            Exception t = e.getTargetException();
            String errmess = t.getMessage();
            Throwable c = t.getCause();
            if (c != null) {
                errmess += " - " + c.getMessage();
            }
            act.setError(errmess);
            return;
        } catch (ReflectionException e) {
            logger.log(BasicLevel.ERROR, "Cannot deploy file: " + targetFileName + " :", e);
            act.setError(e.getCause().getMessage());
            return;
        } catch (IOException e) {
            logger.log(BasicLevel.ERROR, "Cannot deploy file: " + targetFileName + " :", e);
            act.setError(e.getMessage());
            return;
        } catch (RuntimeOperationsException e) {
            logger.log(BasicLevel.ERROR, "Cannot deploy file: " + targetFileName + " :", e);
            Exception t = e.getTargetException();
            String errmess = t.getMessage();
            Throwable c = t.getCause();
            if (c != null) {
                errmess += " - " + c.getMessage();
            }
            act.setError(errmess);
            return;
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, "Unexpected exception: " + e);
            act.setError(e.getMessage());
            return;
        }
        act.setOK();
    }

    /**
     * Undeploy a module on the remote server
     * @param fileName Name of the file containing module (or app) to undeploy
     */
    public void undeployModule(final String fileName) {

        logger.log(BasicLevel.DEBUG, fileName);

        File file = new File(fileName);
        String targetFileName = deployDir + File.separator + file.getName();

        logger.log(BasicLevel.DEBUG, targetFileName);

        // Build a DeployAction and register it in DomainMonitor
        DeployAction act = new DeployAction(this, targetFileName, DeployAction.UNDEPLOY);
        if (getDm() == null) {
            logger.log(BasicLevel.ERROR, "Operation reserved to the master");
            return;
        }
        if (!getDm().registerDeployAction(act)) {
            logger.log(BasicLevel.WARN, "Operation already running for " + targetFileName);
            return;
        }

        // Check connection
        if (!checkConnection()) {
            logger.log(BasicLevel.WARN, "Cannot undeploy: Server " + getName() + " not running");
            act.setError("server not running");
            return;
        }

        // operation depends on the type of the file
        String opName = ServerProxyProperties.UNDEPLOY_OPERATION_KEY.getPropertyName();

        String[] params = {targetFileName};
        String[] signature = {"java.lang.String"};
        try {
            getConnection().invoke(serverOn, opName, params, signature);
        } catch (InstanceNotFoundException e) {
            logger.log(BasicLevel.ERROR, "Cannot undeploy file: " + targetFileName + " :", e);
            act.setError("Remote J2EEServer not registered");
            return;
        } catch (MBeanException e) {
            logger.log(BasicLevel.ERROR, "Cannot undeploy file: " + targetFileName + " :", e);
            Exception t = e.getTargetException();
            String errmess = t.getMessage();
            Throwable c = t.getCause();
            if (c != null) {
                errmess += " - " + c.getMessage();
            }
            act.setError(errmess);
            return;
        } catch (ReflectionException e) {
            logger.log(BasicLevel.ERROR, "Cannot undeploy file: " + targetFileName + " :", e);
            act.setError(e.getCause().getMessage());
            return;
        } catch (IOException e) {
            logger.log(BasicLevel.ERROR, "Cannot undeploy file: " + targetFileName + " :", e);
            act.setError(e.getMessage());
            return;
        }
        act.setOK();
    }

    /**
     * used for upload in file transfer
     */
    private static final int BUFFER_SIZE = 1024;

    /**
     * Upload a file on remote server for deployment
     * @param fileName file to upload. One among .war,.jar,.ear,.rar
     * @param replaceExisting if true, replace the existing file if any
     * @throws IOException
     */
    public void uploadFile(final String fileName, final boolean replaceExisting) {

        logger.log(BasicLevel.DEBUG, fileName);

        // Build a DeployAction and register it in DomainMonitor
        DeployAction act = new DeployAction(this, fileName, DeployAction.UPLOAD);
        if (getDm() == null) {
            logger.log(BasicLevel.ERROR, "Operation reserved to the master");
            return;
        }
        if (!getDm().registerDeployAction(act)) {
            logger.log(BasicLevel.WARN, "Operation already running for " + fileName);
            return;
        }

        // Check connection
        if (!checkConnection()) {
            logger.log(BasicLevel.WARN, "Cannot upload file: Server " + getName() + " not running");
            act.setError("server not running");
            return;
        }

        File file = null;
        // first try the file name as it is
        try {
            file = new File(fileName).getCanonicalFile();
        } catch (IOException e) {
            logger.log(BasicLevel.ERROR, "Cannot upload file " + fileName, e);
            act.setError(e.getMessage());
            return;
        }
        String deployName = file.getName();
        if (!file.exists()) {
            // if the file was not found try looking for it under JONAS_BASE
            String dir = getFolderDir(fileName);
            if (dir == null) {
                act.setError("Directory not found");
                return;
            }
            file = new File(dir, fileName);
            deployName = fileName;
        }
        if (file == null || !file.exists()) {
            act.setError("File not found");
            return;
        }

        try {
            FileInputStream inputStream = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buf = new byte[BUFFER_SIZE];
            // Read bytes
            int len;
            while ((len = inputStream.read(buf)) > 0) {
                baos.write(buf, 0, len);
            }
            byte[] bytesOfFile = baos.toByteArray();

            Object[] opParams = new Object[] {bytesOfFile, deployName, Boolean.valueOf(replaceExisting)};
            String[] opSignature = new String[] {"[B", "java.lang.String", "boolean"};
            getConnection().invoke(serverOn, ServerProxyProperties.SENDFILE_OPERATION_KEY.getPropertyName(), opParams,
                    opSignature);
        } catch (InstanceNotFoundException e) {
            logger.log(BasicLevel.ERROR, "Cannot upload file: " + fileName + " :", e);
            act.setError("Remote J2EEServer not registered");
            return;
        } catch (MBeanException e) {
            logger.log(BasicLevel.ERROR, "Cannot upload file: " + fileName + " :", e);
            Exception t = e.getTargetException();
            String errmess = t.getMessage();
            Throwable c = t.getCause();
            if (c != null) {
                errmess += " - " + c.getMessage();
            }
            act.setError(errmess);
            return;
        } catch (ReflectionException e) {
            logger.log(BasicLevel.ERROR, "Cannot upload file: " + fileName + " :", e);
            act.setError(e.getCause().getMessage());
            return;
        } catch (IOException e) {
            logger.log(BasicLevel.ERROR, "Cannot upload file: " + fileName + " :", e);
            act.setError(e.getMessage());
            return;
        }
        act.setOK();
    }

    /**
     * Upload a file on remote server and deploy it.
     * @param fileName file to upload. One among .war,.jar,.ear,.rar
     * @param replaceExisting if true, replace the existing file if any
     */
    public void uploadDeployModule(final String fileName, final boolean replaceExisting) {

        logger.log(BasicLevel.DEBUG, fileName);

        // This must be considered as 1 single action, so we cannot just
        // call the 2 methods like that :
        // uploadFile(filename, replaceExisting);
        // deployModule(filename);

        // Build a DeployAction and register it in DomainMonitor
        DeployAction act = new DeployAction(this, fileName, DeployAction.UPLOADDEPLOY);
        if (getDm() == null) {
            logger.log(BasicLevel.ERROR, "Operation only allowed to the master");
            return;
        }
        if (!getDm().registerDeployAction(act)) {
            logger.log(BasicLevel.WARN, "Operation already running for " + fileName);
            return;
        }

        // Check connection
        if (!checkConnection()) {
            logger.log(BasicLevel.WARN, "Cannot upload file: Server " + getName() + " not running");
            act.setError("server not running");
            return;
        }

        File file = null;
        // first try the file name as it is
        try {
            file = new File(fileName).getCanonicalFile();
        } catch (IOException e) {
            logger.log(BasicLevel.ERROR, "Cannot upload file " + fileName, e);
            act.setError(e.getMessage());
            return;
        }
        String deployName = file.getName();
        if (!file.exists()) {
            // if the file was not found try looking for it under JONAS_BASE
            String dir = getFolderDir(fileName);
            if (dir == null) {
                act.setError("Directory not found");
                return;
            }
            file = new File(dir, fileName);
            deployName = fileName;
        }
        if (file == null || !file.exists()) {
            act.setError("File not found");
            return;
        }

        try {
            FileInputStream inputStream = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buf = new byte[BUFFER_SIZE];
            // Read bytes
            int len;
            while ((len = inputStream.read(buf)) > 0) {
                baos.write(buf, 0, len);
            }
            byte[] bytesOfFile = baos.toByteArray();

            Object[] opParams = new Object[] {bytesOfFile, deployName, Boolean.valueOf(replaceExisting)};
            String[] opSignature = new String[] {"[B", "java.lang.String", "boolean"};
            getConnection().invoke(serverOn, ServerProxyProperties.SENDFILE_OPERATION_KEY.getPropertyName(), opParams,
                    opSignature);
        } catch (InstanceNotFoundException e) {
            logger.log(BasicLevel.ERROR, "Cannot upload file: " + fileName + " :", e);
            act.setError("Remote J2EEServer not registered");
            return;
        } catch (MBeanException e) {
            logger.log(BasicLevel.ERROR, "Cannot upload file: " + fileName + " :", e);
            Exception t = e.getTargetException();
            String errmess = t.getMessage();
            Throwable c = t.getCause();
            if (c != null) {
                errmess += " - " + c.getMessage();
            }
            act.setError(errmess);
            return;
        } catch (ReflectionException e) {
            logger.log(BasicLevel.ERROR, "Cannot upload file: " + fileName + " :", e);
            act.setError(e.getCause().getMessage());
            return;
        } catch (IOException e) {
            logger.log(BasicLevel.ERROR, "Cannot upload file: " + fileName + " :", e);
            act.setError(e.getMessage());
            return;
        }
        // Set intermediate state: DEPLOYING
        act.setDeploying();

        // operation depends on the type of the file
        String opName = ServerProxyProperties.DEPLOY_OPERATION_KEY.getPropertyName();

        if (deployDir == null) {
            // Check that jonas_base was set
            if (jonasBase == null) {
                logger.log(BasicLevel.ERROR, "Can't do deploy operation as JONAS_BASE not set.");
                return;
            }
            deployDir = jonasBase + File.separator + "deploy";
        }
        String targetFileName = deployDir + File.separator + file.getName();

        logger.log(BasicLevel.DEBUG, targetFileName);

        String[] params = {targetFileName};
        String[] signature = {"java.lang.String"};
        try {
            getConnection().invoke(serverOn, opName, params, signature);
        } catch (InstanceNotFoundException e) {
            logger.log(BasicLevel.ERROR, "Cannot deploy file: " + targetFileName + " :", e);
            act.setError("Remote J2EEServer not registered");
            return;
        } catch (MBeanException e) {
            logger.log(BasicLevel.ERROR, "Cannot deploy file: " + targetFileName + " :", e);
            Exception t = e.getTargetException();
            String errmess = t.getMessage();
            Throwable c = t.getCause();
            if (c != null) {
                errmess += " - " + c.getMessage();
            }
            act.setError(errmess);
            return;
        } catch (ReflectionException e) {
            logger.log(BasicLevel.ERROR, "Cannot deploy file: " + targetFileName + " :", e);
            act.setError(e.getCause().getMessage());
            return;
        } catch (IOException e) {
            logger.log(BasicLevel.ERROR, "Cannot deploy file: " + targetFileName + " :", e);
            act.setError(e.getMessage());
            return;
        } catch (RuntimeOperationsException e) {
            logger.log(BasicLevel.ERROR, "Cannot deploy file: " + targetFileName + " :", e);
            Exception t = e.getTargetException();
            String errmess = t.getMessage();
            Throwable c = t.getCause();
            if (c != null) {
                errmess += " - " + c.getMessage();
            }
            act.setError(errmess);
            return;
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, "Unexpected exception: " + e);
            act.setError(e.getMessage());
            return;
        }
        act.setOK();
    }

    /**
     * Returns the directory that a file would be found in.
     * @param fileName the file to find the directory for.
     * @return The directory of the given file.
     */
    private String getFolderDir(final String fileName) {
        String jBase = JProp.getJonasBase();
        // based on extension
        String dir = null;
        // EJB
        if (fileName.toLowerCase().endsWith(".jar")) {
            dir = jBase + File.separator + "ejbjars";
        } else if (fileName.toLowerCase().endsWith(".war")) {
            // War file
            dir = jBase + File.separator + "webapps";
        } else if (fileName.toLowerCase().endsWith(".ear")) {
            // ear file
            dir = jBase + File.separator + "apps";
        } else if (fileName.toLowerCase().endsWith(".rar")) {
            // rar file
            dir = jBase + File.separator + "rars";
        } else {
            // invalid type
            logger.log(BasicLevel.ERROR, "Invalid extension for " + fileName);
        }
        return dir;
    }

    // ------------------- Monitoring support -------------------//
    // MBean ObjectNames used for monitoring the represented server
    // these names depend on the domain name and the server name
    private ObjectName jvmOn = null;

    // General information about the server
    /**
     * Name of the host as given by InetAddress.getLoaclHost(). (node attribute
     * from JVM MBean)
     */
    private String hostName = null;

    /**
     * JOnAS version.
     */
    private String jonasVersion = null;

    /**
     * jonas.root environment variable.
     */
    private String jonasRoot = null;

    /**
     * jonas.base environment variable.
     */
    private String jonasBase = null;

    /**
     * java.home environment variable.
     */
    private String javaHome = null;

    /**
     * JVM vendor.
     */
    private String javaVendor = null;

    /**
     * JVM version.
     */
    private String javaVersion = null;

    // Info about memory usage
    /**
     * Heap size - free memory.
     */
    private Long currentUsedMemory = new Long(-1);

    /**
     * Allocated heap size.
     */
    private Long currentTotalMemory = new Long(-1);

    private int allThreadsCount;

    private String protocols = null;

    // infos jdk5
    private String loadCPU = null;

    // Tomcat
    private boolean tomcat;

    private int maxThreadsByConnectorTomcat = 0;

    private int currentThreadCountByConnectorTomcat = 0;

    private int currentThreadBusyByConnectorTomcat = 0;

    private long bytesReceivedByConnectorTomcat = 0;

    private long bytesSentByConnectorTomcat = 0;

    private int errorCountByConnectorTomcat = 0;

    private long processingTimeByConnectorTomcat = 0;

    private int requestCountByConnectorTomcat = 0;

    // Tx
    private boolean transaction;

    private int totalBegunTransactions;

    private int totalCommittedTransactions;

    private int totalCurrentTransactions;

    private int totalExpiredTransactions;

    private int totalRolledbackTransactions;

    // Worker Pool
    private boolean workers;

    private int currentWorkerPoolSize;

    private int maxWorkerPoolSize;

    private int minWorkerPoolSize;

    // JCA
    private boolean jcaConnection;

    private int connectionFailuresJCAConnection = 0;

    private int connectionLeaksJCAConnection = 0;

    private int currentBusyJCAConnection = 0;

    private int currentOpenedJCAConnection = 0;

    private int rejectedOpenJCAConnection = 0;

    private int servedOpenJCAConnection = 0;

    private int waiterCountJCAConnection = 0;

    private long waitingTimeJCAConnection = 0;

    // private int currentInTxJCAConnection;
    // private int currentWaitersJCAConnection;
    // private int poolMaxWaitersJCAConnection;
    // private int poolMaxOpentimeJCAConnection;
    // private int physicalConnectionOpenedCountJCAConnection;
    // private int rejectedFullJCAConnection;
    // private int rejectedOtherJCAConnection;
    // private int rejectedTimeoutJCAConnection;
    // JDBCResource
    private boolean jdbcDatasource;

    private int connectionFailuresJDBCResource;

    private int connectionLeaksJDBCResource;

    private int currentBusyJDBCResource;

    private int currentOpenedJDBCResource;

    private int rejectedOpenJDBCResource;

    private int servedOpenJDBCResource;

    private int waiterCountJDBCResource;

    private long waitingTimeJDBCResource;

    // JMS
    private boolean jmsJoram;

    private int jmsQueuesNbMsgsReceiveSinceCreation;

    private int jmsQueuesNbMsgsSendToDMQSinceCreation;

    private int jmsQueuesNbMsgsDeliverSinceCreation;

    private int jmsTopicsNbMsgsReceiveSinceCreation;

    private int jmsTopicsNbMsgsSendToDMQSinceCreation;

    private int jmsTopicsNbMsgsDeliverSinceCreation;

    // EJB
    private int currentNumberOfEntityBean;

    private int currentNumberOfEJB;

    private int currentNumberOfMDB;

    private int currentNumberOfSBF;

    private int currentNumberOfSBL;

    /**
     * Indicates if general info on representes server are set or not set
     */
    private boolean infoSet;

    /**
     * @return true if the general info are set, false otherwise
     */
    public boolean isInfoSet() {
        return infoSet;
    }

    /**
     * Set the indicator value to <code>true</code> after execting the getInfo()
     * method, and to <code>false</code> when detecting that server become
     * unreacheable or stopping.
     * @param infoSet indicator value to set
     */
    public void setInfoSet(final boolean infoSet) {
        this.infoSet = infoSet;
    }

    /**
     * Get general information about the managed server and set this info into
     * attributes that won't change during the server life (JOnAS version, JVM
     * version, etc;)
     */
    private void getInfo() {
        logger.log(BasicLevel.DEBUG, getName());
        if (!checkConnection()) {
            logger.log(BasicLevel.INFO, "Cannot set info for " + getName());
            logger.log(BasicLevel.INFO, "Connection is not established yet");
            return;
        }
        String domain = getDomain();
        /**
         * ObjectName of the JSR77 JVM MBean
         * <domain>:j2eeType=JVM,name=<server>,J2EEServer=<server>
         */
        jvmOn = J2eeObjectName.JVM(domain, getName(), getName());

        String attr = "";
        boolean infoServerRead = false;
        boolean infoJvmRead = false;
        try {
            if (serverOn != null && getConnection().isRegistered(serverOn)) {
                String[] attributes = new String[] {"serverVersion", "jonasBase", "jonasRoot"};
                AttributeList al = getConnection().getAttributes(serverOn, attributes);
                for (int i = 0; i < al.size(); i++) {
                    Attribute at = (Attribute) al.get(i);
                    String name = at.getName();
                    if ("serverVersion".equals(name)) {
                        jonasVersion = (String) at.getValue();
                    } else if ("jonasBase".equals(name)) {
                        jonasBase = (String) at.getValue();
                    } else if ("jonasRoot".equals(name)) {
                        jonasRoot = (String) at.getValue();
                    }
                }
                infoServerRead = true;
            }
            if (jvmOn != null && getConnection().isRegistered(jvmOn)) {
                String[] attributes = new String[] {"javaVersion", "javaVendor", "node", "javaHome"};
                AttributeList al = getConnection().getAttributes(jvmOn, attributes);
                for (int i = 0; i < al.size(); i++) {
                    Attribute at = (Attribute) al.get(i);
                    String name = at.getName();
                    if ("javaVersion".equals(name)) {
                        javaVersion = (String) at.getValue();
                    } else if ("javaVendor".equals(name)) {
                        javaVendor = (String) at.getValue();
                    } else if ("node".equals(name)) {
                        hostName = (String) at.getValue();
                    } else if ("javaHome".equals(name)) {
                        javaHome = (String) at.getValue();
                    }
                }
                infoJvmRead = true;
            }
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Error while getting attribute " + attr);
            logger.log(BasicLevel.WARN, "serverObjectName=" + serverOn);
            logger.log(BasicLevel.WARN, "jvmObjectName=" + jvmOn);
            throw new RuntimeException("Error while getting attribute " + attr + " from " + getName(), e);
        }
        if (infoJvmRead && infoServerRead) {
            setInfoSet(true);
        }
    }

    /**
     * Update non static information for this node.
     */
    public void getMonitoringInfo() {
        logger.log(BasicLevel.DEBUG, getName());
        if (!isInfoSet()) {
            getInfo();
        }
        if (!checkConnection()) {
            logger.log(BasicLevel.INFO, "Cannot get monitoring info for " + getName());
            logger.log(BasicLevel.INFO, "Connection is not established yed");
            return;
        }
        // Get general monitoring info
        ObjectName on = null;
        try {
            // Threads usage given by the JVM MBean
            if (jvmOn != null && getConnection().isRegistered(jvmOn)) {
                on = jvmOn;
                allThreadsCount = ((Integer) getConnection().getAttribute(on, "allThreadsCount")).intValue();
            }
            // JDK5 - TODO

            // J2EEServer provided info on memory managemenet and on protocols
            if (serverOn != null && getConnection().isRegistered(serverOn)) {
                on = serverOn;
                String[] attributes = new String[] {"currentUsedMemory", "currentTotalMemory", "protocols"};
                AttributeList al = getConnection().getAttributes(on, attributes);
                for (int i = 0; i < al.size(); i++) {
                    Attribute at = (Attribute) al.get(i);
                    String name = at.getName();
                    if ("currentUsedMemory".equals(name)) {
                        currentUsedMemory = (Long) at.getValue();
                    } else if ("currentTotalMemory".equals(name)) {
                        currentTotalMemory = (Long) at.getValue();
                    } else if ("protocols".equals(name)) {
                        protocols = (String) at.getValue();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.log(BasicLevel.WARN, "Error while monitoting MBean " + on + ", " + e);
        }

        // Get satistics provided by Cataline MBeans
        getMonitoringInfoTomcat();

        // Get satistics provided JOnAS WORKER POOL MBeans
        getMonitoringInfoWorkers();

        // Get satistics on transactions provided by JTAResource MBean
        getMonitoringInfoTransaction();

        // Get satistics on JCA connection factories
        getMonitoringInfoJCAConnection();

        // Get satistics on DataSources
        getMonitoringInfoJDBCResource();

        // Get statistics on EJBS
        getMonitoringInfoEJBs();

        // Get Joram Jms Statistics
        getMonitoringInfoJmsJoram();
    }

    /**
     * Get Joram Jms Statistics
     */
    private void getMonitoringInfoJmsJoram() {
        ObjectName on = null;
        try {
            jmsJoram = false;
            // Check if the remote server has registered the JORAM RAR module
            // MBean:
            // <domainName>:j2eeType=ResourceAdapter,J2EEServer=<serverName>,*
            on = J2eeObjectName.getResourceAdapters(getDomain(), getName());
            QueryExp query = Query.match(Query.attr("resourceAdapterClassname"), Query
                    .value("org.objectweb.joram.client.connector.JoramAdapter"));
            Iterator it = getConnection().queryNames(on, query).iterator();

            if (it.hasNext()) {
                jmsJoram = true;
                Hashtable statistic = null;
                jmsQueuesNbMsgsReceiveSinceCreation = 0;
                jmsQueuesNbMsgsSendToDMQSinceCreation = 0;
                jmsQueuesNbMsgsDeliverSinceCreation = 0;
                jmsTopicsNbMsgsReceiveSinceCreation = 0;
                jmsTopicsNbMsgsSendToDMQSinceCreation = 0;
                jmsTopicsNbMsgsDeliverSinceCreation = 0;
                on = JoramObjectName.joramQueues();
                Set onSet = getConnection().queryNames(on, null);
                for (it = onSet.iterator(); it.hasNext();) {
                    on = (ObjectName) it.next();
                    statistic = (Hashtable) getConnection().getAttribute(on, "Statistic");
                    jmsQueuesNbMsgsReceiveSinceCreation += ((Long) statistic.get("nbMsgsReceiveSinceCreation")).doubleValue();
                    jmsQueuesNbMsgsSendToDMQSinceCreation += ((Long) statistic.get("nbMsgsSendToDMQSinceCreation"))
                            .doubleValue();
                    jmsQueuesNbMsgsDeliverSinceCreation += ((Long) statistic.get("nbMsgsDeliverSinceCreation")).doubleValue();
                }
                on = JoramObjectName.joramTopics();
                onSet = getConnection().queryNames(on, null);
                for (it = onSet.iterator(); it.hasNext();) {
                    on = (ObjectName) it.next();
                    statistic = (Hashtable) getConnection().getAttribute(on, "Statistic");
                    jmsTopicsNbMsgsReceiveSinceCreation += ((Long) statistic.get("nbMsgsReceiveSinceCreation")).doubleValue();
                    jmsTopicsNbMsgsSendToDMQSinceCreation += ((Long) statistic.get("nbMsgsSendToDMQSinceCreation"))
                            .doubleValue();
                    jmsTopicsNbMsgsDeliverSinceCreation += ((Long) statistic.get("nbMsgsDeliverSinceCreation")).doubleValue();
                }

            }
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Error while monitoring MBean " + on + ", " + e);
        }
    }

    /**
     * Update satistics information provided by Cataline MBeans for this node.
     */
    private void getMonitoringInfoTomcat() {
        ObjectName on = null;
        try {
            // Catalina MBeans provided info
            // thread uage provided by
            // <domain>:type=ThreadPool,name=connectorName
            ObjectName ons = ObjectName.getInstance(getDomain() + ":type=ThreadPool,*");
            tomcat = false;
            maxThreadsByConnectorTomcat = 0;
            currentThreadCountByConnectorTomcat = 0;
            currentThreadBusyByConnectorTomcat = 0;
            for (Iterator it = getConnection().queryNames(ons, null).iterator(); it.hasNext();) {
                tomcat = true;
                on = (ObjectName) it.next();
                String[] attributes = new String[] {"maxThreads", "currentThreadCount", "currentThreadsBusy"
                // "minSpareThreads", "maxSpareThreads"
                };
                AttributeList al = getConnection().getAttributes(on, attributes);
                for (int i = 0; i < al.size(); i++) {
                    Attribute at = (Attribute) al.get(i);
                    String name = at.getName();
                    if ("maxThreads".equals(name)) {
                        maxThreadsByConnectorTomcat = maxThreadsByConnectorTomcat + ((Integer) at.getValue()).intValue();
                    } else if ("currentThreadCount".equals(name)) {
                        currentThreadCountByConnectorTomcat = currentThreadCountByConnectorTomcat
                                + ((Integer) at.getValue()).intValue();
                    } else if ("currentThreadsBusy".equals(name)) {
                        int value = ((Integer) at.getValue()).intValue();
                        currentThreadBusyByConnectorTomcat += value;
                    }
                }
            }
            // request processing statistics provided by
            // <domain>:type=GlobalRequestProcessor,name=connectorName
            ons = ObjectName.getInstance(getDomain() + ":type=GlobalRequestProcessor,*");
            bytesReceivedByConnectorTomcat = 0;
            bytesSentByConnectorTomcat = 0;
            errorCountByConnectorTomcat = 0;
            processingTimeByConnectorTomcat = 0;
            requestCountByConnectorTomcat = 0;
            for (Iterator it = getConnection().queryNames(ons, null).iterator(); it.hasNext();) {
                tomcat = true;
                on = (ObjectName) it.next();
                String[] attributes = new String[] {"bytesReceived", "bytesSent", "errorCount", "maxTime", "processingTime",
                        "requestCount"};
                AttributeList al = getConnection().getAttributes(on, attributes);
                for (int i = 0; i < al.size(); i++) {
                    Attribute at = (Attribute) al.get(i);
                    String name = at.getName();
                    if ("bytesReceived".equals(name)) {
                        bytesReceivedByConnectorTomcat += ((Long) at.getValue()).longValue();
                    } else if ("bytesSent".equals(name)) {
                        bytesSentByConnectorTomcat += ((Long) at.getValue()).longValue();
                    } else if ("errorCount".equals(name)) {
                        errorCountByConnectorTomcat += ((Integer) at.getValue()).intValue();
                    } else if ("processingTime".equals(name)) {
                        processingTimeByConnectorTomcat += ((Long) at.getValue()).longValue();
                    } else if ("requestCount".equals(name)) {
                        requestCountByConnectorTomcat += ((Integer) at.getValue()).intValue();
                    }
                }
            }
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Error while monitoring MBean " + on);
        }
    }

    /**
     * Update transaction statistics using JTA MBean
     */
    private void getMonitoringInfoTransaction() {
        // transaction processing statistics provided by JTA MBean:
        // <domain>:j2eeType=JTAResource,name=JTAResource,J2EEServer=<server>
        ObjectName jtaOn = J2eeObjectName.JTAResource(getDomain(), getName(), null);
        transaction = false;
        try {
            if (jtaOn != null && getConnection().isRegistered(jtaOn)) {
                transaction = true;
                String[] attributes = new String[] {"totalBegunTransactions", "totalCommittedTransactions",
                        "totalCurrentTransactions", "totalExpiredTransactions", "totalRolledbackTransactions"};
                AttributeList al = getConnection().getAttributes(jtaOn, attributes);
                for (int i = 0; i < al.size(); i++) {
                    Attribute at = (Attribute) al.get(i);
                    String name = at.getName();
                    if ("totalBegunTransactions".equals(name)) {
                        totalBegunTransactions = ((Integer) at.getValue()).intValue();
                    } else if ("totalCommittedTransactions".equals(name)) {
                        totalCommittedTransactions = ((Integer) at.getValue()).intValue();
                    } else if ("totalCurrentTransactions".equals(name)) {
                        totalCurrentTransactions = ((Integer) at.getValue()).intValue();
                    } else if ("totalRolledbackTransactions".equals(name)) {
                        totalRolledbackTransactions = ((Integer) at.getValue()).intValue();
                    }
                }
            }
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Error while monitoring MBean " + jtaOn);
        }
    }

    /**
     * Update JOnAS Worker pool thread statistics
     */
    private void getMonitoringInfoWorkers() {
        // JOnAS Worker pool thread statistics are provided by workmanager
        // MBean:
        // <domain>:type=workmanager/*,name=.. TO BE Added*/
        ObjectName wpoolOn = JonasObjectName.workManager(getDomain());
        workers = false;
        try {
            if (wpoolOn != null && getConnection().isRegistered(wpoolOn)) {
                workers = true;
                String[] attributes = new String[] {"currentPoolSize", "maxPoolSize", "minPoolSize"};
                AttributeList al = getConnection().getAttributes(wpoolOn, attributes);
                for (int i = 0; i < al.size(); i++) {
                    Attribute at = (Attribute) al.get(i);
                    String name = at.getName();
                    if ("currentPoolSize".equals(name)) {
                        currentWorkerPoolSize = ((Integer) at.getValue()).intValue();
                    } else if ("maxPoolSize".equals(name)) {
                        maxWorkerPoolSize = ((Integer) at.getValue()).intValue();
                    } else if ("minPoolSize".equals(name)) {
                        minWorkerPoolSize = ((Integer) at.getValue()).intValue();
                    }
                }
            }
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Error while monitoring MBean " + wpoolOn);
        }
    }

    /**
     * Update statistics related to the JDBCDataSources. The ***JDBCResource
     * attributes represent the sum of the corresponding attributes in all the
     * JDBCDataSource MBeans of a given managed server
     */
    private void getMonitoringInfoJDBCResource() {
        // JDBCDataSources MBeans are identified by
        // <domain>:j2eeType=JDBCDataSource,name=<datasource-name>
        ObjectName jdbcDatasourcesOn = J2eeObjectName.getJDBCDataSources(getDomain(), getName());
        ObjectName jdbcDatasourceOn = null;
        jdbcDatasource = false;
        try {
            Set jdbcDatasourceOns = getConnection().queryNames(jdbcDatasourcesOn, null);
            if (jdbcDatasourceOns.isEmpty()) {
                return;
            }
            String[] attributes = new String[] {"connectionFailures", "connectionLeaks", "currentBusy", "currentOpened",
                    "rejectedOpen", "servedOpen", "waiterCount", "waitingTime"};
            jdbcDatasource = true;
            connectionFailuresJDBCResource = 0;
            connectionLeaksJDBCResource = 0;
            currentBusyJDBCResource = 0;
            currentOpenedJDBCResource = 0;
            rejectedOpenJDBCResource = 0;
            servedOpenJDBCResource = 0;
            waiterCountJDBCResource = 0;
            waitingTimeJDBCResource = 0;
            for (Iterator it = jdbcDatasourceOns.iterator(); it.hasNext();) {
                jdbcDatasourceOn = (ObjectName) it.next();
                AttributeList al = getConnection().getAttributes(jdbcDatasourceOn, attributes);
                for (int i = 0; i < al.size(); i++) {
                    Attribute at = (Attribute) al.get(i);
                    String name = at.getName();
                    if ("connectionFailures".equals(name)) {
                        connectionFailuresJDBCResource += ((Integer) at.getValue()).intValue();
                    } else if ("connectionLeaks".equals(name)) {
                        connectionLeaksJDBCResource += ((Integer) at.getValue()).intValue();
                    } else if ("currentBusy".equals(name)) {
                        currentBusyJDBCResource += ((Integer) at.getValue()).intValue();
                    } else if ("currentOpened".equals(name)) {
                        currentOpenedJDBCResource += ((Integer) at.getValue()).intValue();
                    } else if ("rejectedOpen".equals(name)) {
                        rejectedOpenJDBCResource += ((Integer) at.getValue()).intValue();
                    } else if ("servedOpen".equals(name)) {
                        servedOpenJDBCResource += ((Integer) at.getValue()).intValue();
                    } else if ("waiterCount".equals(name)) {
                        waiterCountJDBCResource += ((Integer) at.getValue()).intValue();
                    } else if ("waitingTime".equals(name)) {
                        waitingTimeJDBCResource += ((Long) at.getValue()).intValue();
                    }
                }
            }
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Error while monitoring MBean " + jdbcDatasourceOn);
        }
    }

    /**
     * Update statistics related to the JCAConnection resources. The ***JCA
     * attributes represent the sum of the corresponding attributes in all the
     * JCAConnectionFactory MBeans of a given managed server
     */
    private void getMonitoringInfoJCAConnection() {
        // JCAConnectionFactory MBeans are identified by
        // <domain>:j2eeType=JCAConnectionFactory,name=<jca-connection-name>
        ObjectName jcaFactoriesOn = J2eeObjectName.getJCAConnectionFactories(getDomain(), getName());
        ObjectName jcaFactoryOn = null;
        jcaConnection = false;
        try {
            Set jcaFactoryOns = getConnection().queryNames(jcaFactoriesOn, null);
            if (jcaFactoryOns.isEmpty()) {
                return;
            }
            String[] attributes = new String[] {"connectionFailures", "connectionLeaks", "currentBusy", "currentOpened",
                    "rejectedOpen", "servedOpen", "waiterCount", "waitingTime"};
            jcaConnection = true;
            connectionFailuresJCAConnection = 0;
            connectionLeaksJCAConnection = 0;
            currentBusyJCAConnection = 0;
            currentOpenedJCAConnection = 0;
            rejectedOpenJCAConnection = 0;
            servedOpenJCAConnection = 0;
            waiterCountJCAConnection = 0;
            waitingTimeJCAConnection = 0;
            for (Iterator it = jcaFactoryOns.iterator(); it.hasNext();) {
                jcaFactoryOn = (ObjectName) it.next();
                AttributeList al = getConnection().getAttributes(jcaFactoryOn, attributes);
                for (int i = 0; i < al.size(); i++) {
                    Attribute at = (Attribute) al.get(i);
                    String name = at.getName();
                    if ("connectionFailures".equals(name)) {
                        connectionFailuresJCAConnection += ((Integer) at.getValue()).intValue();
                    } else if ("connectionLeaks".equals(name)) {
                        connectionLeaksJCAConnection += ((Integer) at.getValue()).intValue();
                    } else if ("currentBusy".equals(name)) {
                        currentBusyJCAConnection += ((Integer) at.getValue()).intValue();
                    } else if ("currentOpened".equals(name)) {
                        currentOpenedJCAConnection += ((Integer) at.getValue()).intValue();
                    } else if ("rejectedOpen".equals(name)) {
                        rejectedOpenJCAConnection += ((Integer) at.getValue()).intValue();
                    } else if ("servedOpen".equals(name)) {
                        servedOpenJCAConnection += ((Integer) at.getValue()).intValue();
                    } else if ("waiterCount".equals(name)) {
                        waiterCountJCAConnection += ((Integer) at.getValue()).intValue();
                    } else if ("waitingTime".equals(name)) {
                        waitingTimeJCAConnection += ((Long) at.getValue()).intValue();
                    }
                }
            }
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Error while monitoring MBean " + jcaFactoryOn + ", " + e);
        }
    }

    private void getMonitoringInfoEJBs() {
        @SuppressWarnings("unused")
        ObjectName entityBeansOn = J2eeObjectName.getEntityBeans(getDomain());
        ObjectName on = null;
        try {
            on = J2eeObjectName.getEntityBeans(getDomain());
            Set ons = getConnection().queryNames(on, null);
            currentNumberOfEntityBean = ons.size();
            on = J2eeObjectName.getStatefulSessionBeans(getDomain());
            ons = getConnection().queryNames(on, null);
            currentNumberOfSBF = ons.size();
            on = J2eeObjectName.getStatelessSessionBeans(getDomain());
            ons = getConnection().queryNames(on, null);
            currentNumberOfSBL = ons.size();
            on = J2eeObjectName.getMessageDrivenBeans(getDomain());
            ons = getConnection().queryNames(on, null);
            currentNumberOfMDB = ons.size();
            currentNumberOfEJB = currentNumberOfEntityBean + currentNumberOfSBF + currentNumberOfSBL + currentNumberOfMDB;
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Error while monitoring MBean " + on + ", " + e);
        }
    }

    public int getAllThreadsCount() {
        return allThreadsCount;
    }

    public long getBytesReceivedByConnectorTomcat() {
        return bytesReceivedByConnectorTomcat;
    }

    public long getBytesSentByConnectorTomcat() {
        return bytesSentByConnectorTomcat;
    }

    public int getConnectionFailuresJCAConnection() {
        return connectionFailuresJCAConnection;
    }

    public int getConnectionLeaksJCAConnection() {
        return connectionLeaksJCAConnection;
    }

    public int getCurrentBusyJCAConnection() {
        return currentBusyJCAConnection;
    }

    public int getCurrentNumberOfEntityBean() {
        return currentNumberOfEntityBean;
    }

    public int getCurrentNumberOfEJB() {
        return currentNumberOfEJB;
    }

    public int getCurrentNumberOfMDB() {
        return currentNumberOfMDB;
    }

    public int getCurrentNumberOfSBF() {
        return currentNumberOfSBF;
    }

    public int getCurrentNumberOfSBL() {
        return currentNumberOfSBL;
    }

    public int getCurrentOpenedJCAConnection() {
        return currentOpenedJCAConnection;
    }

    public int getCurrentThreadBusyByConnectorTomcat() {
        return currentThreadBusyByConnectorTomcat;
    }

    public int getCurrentThreadCountByConnectorTomcat() {
        return currentThreadCountByConnectorTomcat;
    }

    public Long getCurrentTotalMemory() {
        return currentTotalMemory;
    }

    public Long getCurrentUsedMemory() {
        return currentUsedMemory;
    }

    public int getCurrentWorkerPoolSize() {
        return currentWorkerPoolSize;
    }

    public int getErrorCountByConnectorTomcat() {
        return errorCountByConnectorTomcat;
    }

    public String getHostName() {
        return hostName;
    }

    public String getJavaVendor() {
        return javaVendor;
    }

    public String getJavaVersion() {
        return javaVersion;
    }

    public int getJmsQueuesNbMsgsDeliverSinceCreation() {
        return jmsQueuesNbMsgsDeliverSinceCreation;
    }

    public int getJmsQueuesNbMsgsReceiveSinceCreation() {
        return jmsQueuesNbMsgsReceiveSinceCreation;
    }

    public int getJmsQueuesNbMsgsSendToDMQSinceCreation() {
        return jmsQueuesNbMsgsSendToDMQSinceCreation;
    }

    public int getJmsTopicsNbMsgsDeliverSinceCreation() {
        return jmsTopicsNbMsgsDeliverSinceCreation;
    }

    public int getJmsTopicsNbMsgsReceiveSinceCreation() {
        return jmsTopicsNbMsgsReceiveSinceCreation;
    }

    public int getJmsTopicsNbMsgsSendToDMQSinceCreation() {
        return jmsTopicsNbMsgsSendToDMQSinceCreation;
    }

    public String getJOnASVersion() {
        return jonasVersion;
    }

    public String getLoadCPU() {
        return loadCPU;
    }

    public int getMaxThreadsByConnectorTomcat() {
        return maxThreadsByConnectorTomcat;
    }

    public int getMaxWorkerPoolSize() {
        return maxWorkerPoolSize;
    }

    public int getMinWorkerPoolSize() {
        return minWorkerPoolSize;
    }

    public long getProcessingTimeByConnectorTomcat() {
        return processingTimeByConnectorTomcat;
    }

    public String getProtocols() {
        return protocols;
    }

    public int getRequestCountByConnectorTomcat() {
        return requestCountByConnectorTomcat;
    }

    public int getTotalBegunTransactions() {
        return totalBegunTransactions;
    }

    public int getTotalCommittedTransactions() {
        return totalCommittedTransactions;
    }

    public int getTotalCurrentTransactions() {
        return totalCurrentTransactions;
    }

    public int getTotalExpiredTransactions() {
        return totalExpiredTransactions;
    }

    public int getTotalRolledbackTransactions() {
        return totalRolledbackTransactions;
    }

    public int getWaiterCountJCAConnection() {
        return waiterCountJCAConnection;
    }

    public long getWaitingTimeJCAConnection() {
        return waitingTimeJCAConnection;
    }

    public boolean getTomcat() {
        return tomcat;
    }

    public boolean getTransaction() {
        return transaction;
    }

    public boolean getWorkers() {
        return workers;
    }

    public int getConnectionFailuresJDBCResource() {
        return connectionFailuresJDBCResource;
    }

    public int getConnectionLeaksJDBCResource() {
        return connectionLeaksJDBCResource;
    }

    public int getCurrentBusyJDBCResource() {
        return currentBusyJDBCResource;
    }

    public int getCurrentOpenedJDBCResource() {
        return currentOpenedJDBCResource;
    }

    public int getRejectedOpenJDBCResource() {
        return rejectedOpenJDBCResource;
    }

    public int getServedOpenJDBCResource() {
        return servedOpenJDBCResource;
    }

    public int getWaiterCountJDBCResource() {
        return waiterCountJDBCResource;
    }

    public long getWaitingTimeJDBCResource() {
        return waitingTimeJDBCResource;
    }

    public int getServedOpenJCAConnection() {
        return servedOpenJCAConnection;
    }

    public int getRejectedOpenJCAConnection() {
        return rejectedOpenJCAConnection;
    }

    public boolean getJcaConnection() {
        return jcaConnection;
    }

    public boolean getJdbcDatasource() {
        return jdbcDatasource;
    }

    public boolean getJmsJoram() {
        return jmsJoram;
    }

    public ClusterDaemonProxy getClusterdaemon() {
        return clusterdaemon;
    }

    public void setClusterdaemon(final ClusterDaemonProxy clusterdaemon) {
        this.clusterdaemon = clusterdaemon;
    }

    /**
     * @return the description
     */
    public String getDescription() {
        return description;
    }

    /**
     * @param description the description to set
     */
    public void setDescription(final String description) {
        this.description = description;
    }

    /**
     * @return the javaHome
     */
    public String getJavaHome() {
        return javaHome;
    }

    /**
     * @param javaHome the javaHome to set
     */
    public void setJavaHome(final String javaHome) {
        this.javaHome = javaHome;
    }

    /**
     * @return the jonasRoot
     */
    public String getJonasRoot() {
        return jonasRoot;
    }

    /**
     * @param jonasRoot the jonasRoot to set
     */
    public void setJonasRoot(final String jonasRoot) {
        this.jonasRoot = jonasRoot;
    }

    /**
     * @return the jonasBase
     */
    public String getJonasBase() {
        return jonasBase;
    }

    /**
     * @param jonasBase the jonasBase to set
     */
    public void setJonasBase(final String jonasBase) {
        this.jonasBase = jonasBase;
    }

    /**
     * @return the xprem
     */
    public String getXprem() {
        return xprem;
    }

    /**
     * @param xprem the xprem to set
     */
    public void setXprem(final String xprem) {
        this.xprem = xprem;
    }

    /**
     * @return the autoBoot
     */
    public String getAutoBoot() {
        return autoBoot;
    }

    /**
     * @param autoBoot the autoBoot to set
     */
    public void setAutoBoot(final String autoBoot) {
        this.autoBoot = autoBoot;
    }

    @Override
    public boolean equals(final Object obj) {
        if (obj == null) {
            return false;
        }
        return getName().equals(((ServerProxy) obj).getName());
    }

    public String getJ2eeObjectName() {
        return serverOn.toString();
    }

}
