/**
 * JaDOrT: JASMINe Deployment Orchestration Tool
 * Copyright (C) 2008-2009 Bull S.A.S.
 * Copyright (C) 2008-2009 France Telecom R&D
 * Contact: jasmine@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: JBossServerAction.java 3641 2009-05-06 16:51:31Z alitokmen $
 * --------------------------------------------------------------------------
 */
package org.ow2.jasmine.jadort.service.action;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

import javax.management.Attribute;
import javax.management.ObjectName;
import javax.management.remote.JMXServiceURL;
import javax.naming.Context;

import org.ow2.jasmine.jadort.api.entities.deployment.ApplicationBean;
import org.ow2.jasmine.jadort.api.entities.topology.ServerBean;

/**
 * Action for the JBoss server.
 * 
 * @author Malek Chahine
 * @author Remy Bresson
 * @author S. Ali Tokmen
 */
public class JBossServerAction extends ServerAction {
    private String name;

    private String url;

    private String username;

    private String password;

    private ObjectName j2eeServer;

    public JBossServerAction(final ServerBean server) {
        this.name = server.getName();
        this.url = server.getServerConnector().getConnectorUrl();
        this.username = server.getServerConnector().getUsername();
        this.password = server.getServerConnector().getPassword();
        this.appendToLog("Created JBossAction for server '" + this.name + "'");
    }

    @Override
    @SuppressWarnings("unchecked")
    protected void connectViaJMX() throws Exception {
        ClassLoader oldCtxCL = Thread.currentThread().getContextClassLoader();
        try {
            Map<String, Object> env = new HashMap<String, Object>();
            if (this.username != null && this.password != null) {
                env.put(Context.SECURITY_PRINCIPAL, this.username);
                env.put(Context.SECURITY_CREDENTIALS, this.password);
            }

            this.establishJMXConnection(new JMXServiceURL(this.url), env);
            this.j2eeServer = ((Set<ObjectName>) this.mbscnx.queryNames(new ObjectName("*:type=Server"), null)).iterator()
                .next();
        } finally {
            Thread.currentThread().setContextClassLoader(oldCtxCL);
        }

        this.appendToLog("JMX server connection OK for server '" + this.name + "', J2EEServer is '" + this.j2eeServer + "'");
    }

    @Override
    public boolean canDeployApplications() throws Exception {
        return false;
    }

    @Override
    public void deploy(final String appName) throws Exception {
        throw new UnsupportedOperationException("Operation not implemented yet !");
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean enableOrDisableApplications(final boolean enable) throws Exception {
        this.checkJMXConnection();
        this.appendToLog("Enabling or disabling all applications on this server");

        boolean failed = false;

        Set<ObjectName> managers = this.mbscnx.queryNames(new ObjectName("*:type=Manager,*"), null);
        for (ObjectName app : managers) {
            String path = app.getKeyProperty("path");
            ObjectName filter;
            try {
                filter = ((Set<ObjectName>) this.mbscnx.queryNames(new ObjectName("*:type=J2EEFilter,path=" + path), null))
                    .iterator().next();
            } catch (NoSuchElementException e) {
                this.appendToLog("\tApplication on path '" + path
                    + "' doesn't have the OnlyAllowUsersWithSessionFilter filter! Please "
                    + "import the filter JAR from the jadort-samples package and set it in the application's descriptor");
                failed = true;
                continue;
            }

            this.mbscnx.setAttribute(filter, new Attribute("active", Boolean.valueOf(!enable)));
            this.appendToLog("\tFilter for application on path '" + path + "' has been set as " + (enable ? "in" : "")
                + "active, application is therefore " + (enable ? "enabled" : "disabled"));
        }
        if (failed) {
            this.appendToLog("At least one application on this server couldn't be " + (enable ? "enabled" : "disabled"));
            return false;
        } else {
            this.appendToLog("All applications on this server are now " + (enable ? "enabled" : "disabled"));
            return true;
        }
    }

    @Override
    public void erase(final String appName) throws Exception {
        throw new UnsupportedOperationException("Operation not implemented yet !");
    }

    @Override
    public int getActiveSessions(final String appName) throws Exception {
        throw new UnsupportedOperationException("Operation not implemented yet !");
    }

    @Override
    @SuppressWarnings("unchecked")
    public int getActiveSessions() throws Exception {
        int totalActiveSessions = 0;

        if (this.mbscnx != null) {
            this.checkJMXConnection();

            Set<ObjectName> managers = this.mbscnx.queryNames(new ObjectName("*:type=Manager,*"), null);
            for (ObjectName manager : managers) {
                totalActiveSessions += ((Integer) this.mbscnx.getAttribute(manager, "activeSessions")).intValue();
            }
        }

        return totalActiveSessions;
    }

    @Override
    public ApplicationBean getApplicationBean(final String appName) throws Exception {
        throw new UnsupportedOperationException("Operation not implemented yet !");
    }

    @Override
    public boolean isStarted() {
        try {
            this.checkJMXConnection();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<ApplicationBean> listOfApplications() throws Exception {
        this.checkJMXConnection();

        List<ApplicationBean> applications = new ArrayList<ApplicationBean>();
        Set<ObjectName> managers = this.mbscnx.queryNames(new ObjectName("*:type=Manager,*"), null);
        for (ObjectName manager : managers) {
            String name = manager.getKeyProperty("path");
            if (name != null) {
                name = name.substring(name.indexOf("/") + 1);
                if (name.length() == 0) {
                    name = "[ ROOT ]";
                }
                ApplicationBean applicationBean = new ApplicationBean(name, null);
                applicationBean.setState(ServerAction.STATE_DEPLOYED);
                applications.add(applicationBean);
            }
        }

        return applications;
    }

    @Override
    public String setDefault(final String appName) throws Exception {
        throw new UnsupportedOperationException("Operation not implemented yet !");
    }

    @Override
    public void start() throws Exception {
        this.checkJMXConnection();
        this.appendToLog("Starting server");

        this.mbscnx.invoke(this.j2eeServer, "start", null, null);

        this.appendToLog("Server is started");
    }

    @Override
    public void stop() throws Exception {
        this.checkJMXConnection();
        this.appendToLog("Stopping server");

        this.mbscnx.invoke(this.j2eeServer, "shutdown", null, null);

        this.appendToLog("Server is stopped");
    }

    @Override
    public void undeploy(final String appName) throws Exception {
        throw new UnsupportedOperationException("Operation not implemented yet !");
    }

    @Override
    public String upload(final ApplicationBean application) throws Exception {
        throw new UnsupportedOperationException("Operation not implemented yet !");
    }
}
