/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2007-2008 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 (at your option) 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.commands.admin.util;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.security.auth.Subject;

/**
 * Wrap a {@link JMXConnector}.
 * @author Guillaume Sauthier
 * @author S. Ali Tokmen
 */
public class JMXConnectionHelper {

    /**
     * The MBeanServer remote URL.
     */
    private JMXServiceURL url;

    /**
     * Security subject (if any).
     */
    private Subject subject;

    /**
     * User name to use when connecting.
     */
    private String username = null;

    /**
     * Password to use when connecting.
     */
    private String password = null;

    /**
     * {@link JMXConnector} instance.
     */
    private JMXConnector connector;

    /**
     * Store last thrown Exception.
     */
    private IOException lastException;

    /**
     * Construct a new {@link JMXConnectionHelper} using the provided URL and Subject.
     * @param url MBeanServer URL
     * @param subject Security subject
     */
    public JMXConnectionHelper(final JMXServiceURL url, final Subject subject) {
        this.url = url;
        this.subject = subject;
    }

    /**
     * Construct a new {@link JMXConnectionHelper} using the provided URL and credentials.
     * @param url MBeanServer URL
     * @param username User name to use when connecting
     * @param password Password to use when connecting
     */
    public JMXConnectionHelper(final JMXServiceURL url, final String username, final String password) {
        this.url = url;
        this.username = username;
        this.password = password;
    }

    /**
     * Try to connect to the remote {@link MBeanServer}.
     * @return true if connection was successful, false otherwise.
     */
    public boolean connect() {
        if (connector == null) {
            try {
                connector = createConnector();
            } catch (IOException e) {
                lastException = e;
                return false;
            }
        }
        return true;
    }

    /**
     * @return the last thrown Exception.
     */
    public Exception getLastException() {
        return lastException;
    }

    /**
     * @return a new {@link JMXConnector} to the remote URL.
     * @throws IOException if something was wrong.
     */
    private JMXConnector createConnector() throws IOException {
        Map env = null;
        if(username != null && password != null) {
            env = new HashMap(1);
            String[] creds = {username, password};
            env.put(JMXConnector.CREDENTIALS, creds);
        }
        return JMXConnectorFactory.connect(url, env);
    }

    /**
     * @return an {@link MBeanServerConnection} (authenticatd with subject if not null).
     * @throws IOException If connection fails
     */
    public MBeanServerConnection getConnection() throws IOException {
        if (connector != null) {
            return connector.getMBeanServerConnection(subject);
        } else {
            // Try to connect once
            if (connect()) {
                return connector.getMBeanServerConnection(subject);
            } else {
                // No luck, throw an Exception
                throw lastException;
            }
        }
    }

    /**
     * Close the underlying {@link JMXConnector}.
     * @return true if connection was successful
     */
    public boolean close() {
        if (connector != null) {
            try {
                connector.close();
                connector = null;
            } catch (IOException e) {
                lastException = e;
                return false;
            }
        }
        return true;
    }

    /**
     * @param subject the subject to set
     */
    public void setSubject(final Subject subject) {
        this.subject = subject;
    }

    /**
     * @return the {@link JMXServiceURL} connection URL
     */
    public JMXServiceURL getURL() {
        return url;
    }
}
