package com.urbancode.air.plugin.wldeploy;

import java.io.IOException;  
import java.net.MalformedURLException;  
import java.util.HashMap;  
import java.util.Map;  
  
import javax.management.AttributeNotFoundException;  
import javax.management.InstanceNotFoundException;  
import javax.management.MBeanException;  
import javax.management.MBeanServerConnection;  
import javax.management.MalformedObjectNameException;  
import javax.management.ObjectName;  
import javax.management.ReflectionException;  
import javax.management.remote.JMXConnector;  
import javax.management.remote.JMXConnectorFactory;  
import javax.management.remote.JMXServiceURL;
import weblogic.security.UsernameAndPassword;
import weblogic.security.UserConfigFileManager;
  
  
public class WebLogicStatusHelper {  
  
    private static String _MBEANS_SERVER_RUNTIME = "weblogic.management.mbeanservers.runtime";  
    private static String _MBEANS_SERVER_DOMAINRUNTIME = "weblogic.management.mbeanservers.domainruntime";  
  
    private static String _DOMAIN_RUNTIME_SERVICE_OBJECTNAME = new String(  
            "com.bea:Name=DomainRuntimeService,Type=weblogic.management.mbeanservers.domainruntime.DomainRuntimeServiceMBean");  

    private static String _DOMAIN_RUNTIME_OBJECTNAME = new String("DomainRuntime");  

    private static String _SERVER_LIFE_CYCLE_RUNTIMES_OBJECTNAME = new String("ServerLifeCycleRuntimes");  
    private static String _SERVER_RUNTIMES_OBJECTNAME = new String("ServerRuntimes");  
  
    JMXConnector jmxCon = null;  
    MBeanServerConnection con = null;
  
    public void startManagedServer(String serverName)  {
        MBeanServerConnection con = getMBeanServerConnection();  
  
        if (con == null) {  
            throw new NullPointerException("The server name " + serverName + " was not found");  
        }  
  
        try {  
  
            ObjectName nameMatchOName = findObjectName(con, getServerLifeCycleBeans(con), serverName);  
  
            if (nameMatchOName == null) {  
                nameMatchOName= findObjectName(con, getClusterRuntimes(con), serverName);
                
                if (nameMatchOName == null) {
                    nameMatchOName = findObjectName(con, getClusters(con), serverName);
                    if (nameMatchOName == null) {
                        System.out.println("The target name " + serverName + " was not found!");
                        System.out.println("This means it is not in the weblogic configuration.");
                        throw new NullPointerException("The target name " + serverName + " was not found!");  
                    }
                    else {
                        def servers = con.getAttribute(nameMatchOName, "Servers");
                        def serverNames = [];
                        servers.each { server ->
                            def name = con.getAttribute(server, "Name");
                            serverNames << name;
                        }
                        serverNames.each { servName ->
                            System.out.println("Starting server ${servName}");
                            startManagedServer(servName);
                        }
                    }
                }
                else {
                    def serverNames = con.getAttribute(nameMatchOName, "ServerNames");
                    def statusList = [];
                    serverNames.each { Name ->
                        println "Starting server ${Name}";
                        startManagedServer(Name);
                    }
                }
            }  
            else {
                 // Sending the 'start' command  
                 con.invoke(nameMatchOName, "start", null, null);  
            }
        } catch (Exception exc) {  
            throw new RuntimeException("Error starting server!",exc);
        } finally {  
        }  
    }  
  
    public void stopManagedServer(String serverName, boolean force)  {
        MBeanServerConnection con = getMBeanServerConnection();  
  
        if (con == null) {  
            throw new NullPointerException("The server name " + serverName + " was not found");  
        }  
  
        try {  
  
            ObjectName nameMatchOName = findObjectName(con, getServerLifeCycleBeans(con), serverName);  
  
            if (nameMatchOName == null) {  
                nameMatchOName= findObjectName(con, getClusterRuntimes(con), serverName);
                
                if (nameMatchOName == null) {
                    System.out.println("The target name " + serverName + " was not found!");
                    System.out.println("This means either your configuration is wrong or if this ");
                    System.out.println("is a cluster no servers in the cluster are running!");
                    throw new NullPointerException("The target name " + serverName + " was not found!");  
                }
                
                def serverNames = con.getAttribute(nameMatchOName, "ServerNames");
                def statusList = [];
                serverNames.each { Name ->
                    println "Stopping server ${Name}";
                    stopManagedServer(Name, force);
                }
            }  
            else { 
                // Sending the 'shutdown' command  
                def command = "shutdown";
                if (force) {
                    command = "forceShutdown";
                }
                con.invoke(nameMatchOName, command, null, null);  
            }
  
        } catch (Exception exc) {  
                throw new RuntimeException("Error stopping server" ,exc);
        } finally {  
        }  
    }  
  
    public def getManagedServerStatus(String serverName)  {
        String serverState = null;  
        def result = null;
  
        MBeanServerConnection con = getMBeanServerConnection();  
  
        if (con == null) {  
            throw new NullPointerException("The server name " + serverName + " was not found");  
        }  
  
        try {  
  
            ObjectName nameMatchOName = findObjectName(con, getServerLifeCycleBeans(con), serverName);  
  
  
            if (nameMatchOName == null) {  
                nameMatchOName= findObjectName(con, getClusterRuntimes(con), serverName);
                
                if (nameMatchOName == null) {
                    System.out.println("The target name " + serverName + " was not found!");
                    System.out.println("This means either your configuration is wrong or if this ");
                    System.out.println("is a cluster no servers in the cluster are running!");
                    result = "NOT_RUNNING";
                }
                else {
                
                    def serverNames = con.getAttribute(nameMatchOName, "ServerNames");
                    def statusList = [];
                    serverNames.each { Name ->
                        statusList << [Name, getManagedServerStatus(Name)];
                    }
                    result = statusList;
                }
            }  
            else { 
                // Getting the 'state' bean  
                String state = (String) con.getAttribute(nameMatchOName, "State");  
                result = state;  
            }
  
        } catch (Exception exc) {  
             throw new RuntimeException("Error getting server state!", exc);
        } finally {  
        }  
  
        return result;  
    }  
  
    private ObjectName[] getServerLifeCycleBeans(MBeanServerConnection con) throws AttributeNotFoundException,  
            InstanceNotFoundException, MBeanException, ReflectionException, IOException, MalformedObjectNameException,  
            NullPointerException {  
        ObjectName domainRunServiceOName = new ObjectName(_DOMAIN_RUNTIME_SERVICE_OBJECTNAME);  
        ObjectName domainRuntimesOName = (ObjectName) con.getAttribute(domainRunServiceOName,  
                _DOMAIN_RUNTIME_OBJECTNAME);  
        ObjectName[] serverLifeCycleONames = (ObjectName[]) con.getAttribute(domainRuntimesOName,  
                _SERVER_LIFE_CYCLE_RUNTIMES_OBJECTNAME);  
  
        return serverLifeCycleONames;  
    }  

    private ObjectName getAppRuntime(MBeanServerConnection con) throws Exception {
        ObjectName domainRunServiceOName = new ObjectName(_DOMAIN_RUNTIME_SERVICE_OBJECTNAME);  
        ObjectName domainRuntimesOName = (ObjectName) con.getAttribute(domainRunServiceOName,  
                _DOMAIN_RUNTIME_OBJECTNAME);  
        ObjectName appRuntime = (ObjectName) con.getAttribute(domainRuntimesOName, "AppRuntimeStateRuntime");
        return appRuntime;
    }
   
    public String[] getAppIds() throws Exception {
        ObjectName appRuntime = getAppRuntime(con);
        String [] appIds = (String[]) con.getAttribute(appRuntime, "ApplicationIds");
        return appIds;
    }

    public String getAppState(String appName, String targetName) {
        ObjectName appRuntime = getAppRuntime(con);
        String state = (String) con.invoke(appRuntime, "getCurrentState", [appName, targetName] as String[],
                                ["java.lang.String", "java.lang.String"] as String[]);
        return state;
    }
            
    private ObjectName[] getClusterRuntimes(MBeanServerConnection con) throws AttributeNotFoundException,
            InstanceNotFoundException, MBeanException, ReflectionException, IOException, MalformedObjectNameException,  
            NullPointerException {  
        ObjectName searchName = new ObjectName("com.bea:Type=ClusterRuntime,*");
        ObjectName[] clusters = con.queryNames(searchName, null);
        return clusters;
    }
            
    private ObjectName[] getClusters(MBeanServerConnection con) throws AttributeNotFoundException,
            InstanceNotFoundException, MBeanException, ReflectionException, IOException, MalformedObjectNameException,  
            NullPointerException {  
        ObjectName searchName = new ObjectName("com.bea:Type=Cluster,*");
        ObjectName[] clusters = con.queryNames(searchName, null);
        return clusters;
    }
  
    private ObjectName findObjectName(MBeanServerConnection con, ObjectName[] serverLifeCycleONames, String match)  
            throws AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException,  
            IOException {  
        ObjectName correctOName = null;  
  
        for (ObjectName serverLifeCycle : serverLifeCycleONames) {  
  
            String name = (String) con.getAttribute(serverLifeCycle, "Name");  
  
            if (name != null && name.equals(match)) {  
                correctOName = serverLifeCycle;  
            }  
        }  
  
        return correctOName;  
    }  
  
    private MBeanServerConnection getMBeanServerConnection() {
        return con;
    }

    public String getUser(String configFile, String keyFile) {
        UsernameAndPassword authInfo = UserConfigFileManager.getUsernameAndPassword(configFile, keyFile, "weblogic.management");
        String user = new String(authInfo.getUsername());
        return user;
    }

    public String getPass(String configFile, String keyFile) {
        UsernameAndPassword authInfo = UserConfigFileManager.getUsernameAndPassword(configFile, keyFile, "weblogic.management");
        String pass = new String(authInfo.getPassword());
        return pass;
    }

    public String getAppsForTarget(String target) {
        String result = "";
        boolean first = true;
        con.queryNames(new ObjectName("com.bea:Type=AppDeployment,*"), null).each { deployment ->
            con.getAttribute(deployment, "Targets").each { targetON ->
                String localName = con.getAttribute(targetON, "Name");
                if (localName==target) {
                    if (first) {
                        first = false;
                        result = con.getAttribute(deployment, "Name");
                    }
                    else {
                        result += ","+ con.getAttribute(deployment,"Name");
                    }
                }
            }
        }
        println "Result for $target: $result";
        return result;
    }
  
    public void initConn(String url, String username, String password) {  
  
        MBeanServerConnection mBeanConnection = null;  
  
        if ( (url == null) || (username == null) || (password == null) ) {  
            return null;  
        }  
  
        try {  
            JMXServiceURL serviceUrl = new JMXServiceURL("service:jmx:" + url + "/jndi/"  
                    + _MBEANS_SERVER_DOMAINRUNTIME);  
  
            Map<String, String> envMap = new HashMap<String, String>();  
            envMap.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, "weblogic.management.remote");  
            envMap.put(javax.naming.Context.SECURITY_PRINCIPAL, username);  
            envMap.put(javax.naming.Context.SECURITY_CREDENTIALS, password);  
  
            jmxCon = JMXConnectorFactory.newJMXConnector(serviceUrl, envMap);  
            jmxCon.connect();  
  
            mBeanConnection = jmxCon.getMBeanServerConnection();  
  
        } catch (Exception exc) {  
              throw new RuntimeException("Error connecting to weblogic!", exc);
        }  
        con = mBeanConnection;
    }  
   
    public void closeConn() {
        if (jmxCon != null) {
             try {
                 jmxCon.close();
             }
             catch (Exception e) {
                 //swallow
             }
        }
    }
}  
