package es.ejie.frmk.control.arranque;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import javax.management.MBeanServer;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.commons.lang.StringUtils;

import weblogic.jndi.Environment;
import weblogic.management.MBeanHome;
import weblogic.management.configuration.ClusterMBean;
import weblogic.management.configuration.ServerMBean;
import weblogic.management.runtime.ServerRuntimeMBean;
import es.ejie.frmk.control.excepciones.Q70FrameworkException;
import es.ejie.frmk.infraestructura.logs.base.Q70LogInterno;
import es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridad;
import es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadAplicacion;

public final class Q70GestorWebLogicMBeanServer implements Q70GestorMBeanServer {

	private static Q70GestorWebLogicMBeanServer instancia = null;

	private String nombreDominio = null;

	private String idInstancia = null;

	private String urlInstancia = null;

	private String nombreClusterInstancia = "";

	/**
	 * Devuelve la instancia del Servidor de MBeans para Bea Weblogic. En caso de que no exista la crea.
	 * @return Instancia del Servidor de MBeans
	 */
	public static Q70GestorWebLogicMBeanServer getSingleton() {
		if (null == instancia) {
			instancia = new Q70GestorWebLogicMBeanServer();
		}
		return instancia;
	}

	/**
	 * @see es.ejie.frmk.control.arranque.Q70GestorMBeanServer#getMBeanServer()
	 */
	public MBeanServer getMBeanServer() throws NamingException, Q70FrameworkException {
		InitialContext contexto = new InitialContext();
		MBeanServer mBeanServer = doGetMBeanServer(contexto);

		MBeanHome home = ((weblogic.management.internal.RemoteMBeanServerImpl) mBeanServer)
				.getMBeanHome();

		doGetInstancia(home);
		doGetCluster();

		return mBeanServer;
	}

	/**
	 * Recupera el identificativo de la instancia y construye la url donde esta ejecutandose esta 
	 * instancia (protocolo t3 + host + puerto). 
	 * 
	 * @param home Servidor de MBean de la maquina donde se esta ejecutando Geremua.
	 * @throws Q70FrameworkException
	 */
	private void doGetInstancia(MBeanHome home) throws Q70FrameworkException {
		Set mbeanSet = null;
		try {
			mbeanSet = home.getMBeansByType("ServerRuntime");

			if (mbeanSet.size() != 1) {
			} else {
				ServerRuntimeMBean serverRuntime = (ServerRuntimeMBean) mbeanSet.iterator().next();
				idInstancia = serverRuntime.getName();
				String host = serverRuntime.getListenAddress();
				host = StringUtils.substringBefore(host, "/");
				int puerto = serverRuntime.getListenPort();
				urlInstancia = "t3://" + host + ":" + puerto;
			}
		} catch (Exception e) {
			throw new Q70FrameworkException(Q70GestorArranqueConfiguracionServidor.ID_COMPONENTE,
					Q70GestorWebLogicMBeanServer.class.getName(), "doGetInstancia",
					"Se ha producido un error en el método doGetInstancia.", e);
		}
	}
	
	/**
	 * Si el servidor en ejecucion pertenece a un cluster mediante este codigo se recupera el nombre 
	 * del cluster.<br> 
	 * Hay que acceder al Servidor administrador de Weblogic con el principal y credenciales requeridas, 
	 * recuperandose todos los servidores administrados, que entonces se recorren para saber a que cluster
	 * pertenece el que esta en ejecucion en esta maquina.
	 * 
	 * @throws NamingException
	 * @throws Q70FrameworkException
	 */
	private void doGetCluster() throws NamingException, Q70FrameworkException {
		Hashtable mapaPropiedades = new Hashtable(5);
		
		String strPrincipal = Q70GestorArranqueConfiguracionServidor.getGlobalProperty(Q70GestorArranqueConfiguracionServidor.USUARIO_SERVIDOR);
		if ( strPrincipal == null){
			strPrincipal = "";
		}
		String strCredenciales = Q70GestorArranqueConfiguracionServidor.getGlobalProperty(Q70GestorArranqueConfiguracionServidor.PASSWORD_SERVIDOR);
		if ( strCredenciales == null){
			strCredenciales = "";
		}
		
		// Recuperamos el uid para el item de seguridad de XlNets
		String wlsAdminUidXlnets = Q70GestorArranqueConfiguracionServidor.getGlobalProperty(Q70GestorArranqueConfiguracionServidor.WLS_ADMIN_UID_OBJ_XLNETS);

		try {
			if (null!=wlsAdminUidXlnets && wlsAdminUidXlnets.length()>0) {
				Q70InformacionSeguridadAplicacion informacionSeguridadAplicacion = Q70GestorSeguridad.getSingleton().createSecurityApplicationInfo("Q70");
				String itemSeguridad = Q70GestorSeguridad.getSingleton().getItemSeguridad(informacionSeguridadAplicacion,wlsAdminUidXlnets);
				if (null != itemSeguridad && itemSeguridad.length()>0) {
					StringTokenizer itemsSeguridad = new StringTokenizer(itemSeguridad,"#");			
					if (itemsSeguridad.hasMoreElements()) {
						itemsSeguridad.nextToken();
						strPrincipal = itemsSeguridad.nextToken();
						strCredenciales = itemsSeguridad.nextToken();
					}
				}
			}
		} catch (Q70FrameworkException e1) {
			if (Q70LogInterno.isEnabled()) {
				Q70LogInterno.log("No se han podido recuperar las credendiales del servidor administrativo. "+e1.getMessage());
			}
		}
		
		if (!"".equals(strPrincipal) && !"".equals(strCredenciales)){
			mapaPropiedades.put(Context.SECURITY_PRINCIPAL, strPrincipal);
			mapaPropiedades.put(Context.SECURITY_CREDENTIALS, strCredenciales);
		}
		
		InitialContext ctx = new InitialContext(mapaPropiedades);

		MBeanHome home = (MBeanHome) ctx.lookup(MBeanHome.ADMIN_JNDI_NAME);

		//Recuperar el nombre del dominio al que pertenece la instancia
		nombreDominio = home.getActiveDomain().getName();
		
		//Comprobar si instancia es un cluster y recuperar el nombre del cluster en tal caso
		ClusterMBean cluster = null;
		Set mbeanSet = null;
		Iterator mbeanIterator = null;
		try {
			mbeanSet = home.getMBeansByType("Cluster");
			mbeanIterator = mbeanSet.iterator();
			nombreClusterInstancia = "";
			while (mbeanIterator.hasNext()) {
				cluster = (ClusterMBean) mbeanIterator.next();
				ServerMBean[] serverArray = cluster.getServers();

				for (int i = 0; i < serverArray.length; i++) {
					ServerMBean bean = serverArray[i];
					if (idInstancia.equals(bean.getName())) {
						nombreClusterInstancia = cluster.getName();
						break;
					}
				}
				if (!"".equals(nombreClusterInstancia)) {
					break;
				}
			}
		} catch (Exception e) {
			throw new Q70FrameworkException(Q70GestorArranqueConfiguracionServidor.ID_COMPONENTE,
					Q70GestorWebLogicMBeanServer.class.getName(), "doGetCluster",
					"Se ha producido un error en el método doGetCluster.", e);
		}finally{
		}
	}

	/**
	 * @param ctx
	 * @return
	 * @throws NamingException
	 */
	private MBeanServer doGetMBeanServer(Context ctx) throws NamingException {
		// Retrieving the server-specific MBeanHome interface
		MBeanHome home = (MBeanHome) ctx.lookup(MBeanHome.LOCAL_JNDI_NAME);
		return home.getMBeanServer();
	}

	/**
	 * @see es.ejie.frmk.control.arranque.Q70GestorMBeanServer#setMapaPropiedades(java.util.Map)
	 */
	public void setMapaPropiedades(Map atributosMBeanServer) {
	}

	/**
	 * @see es.ejie.frmk.control.arranque.Q70GestorMBeanServer#getMBeanServer(Object)
	 */
	public MBeanServer getMBeanServer(Object paramMBeanServer) throws NamingException {
		// Obtener la urlProvider a partir del parametro
		String urlProvider = (String) paramMBeanServer.toString();

		Environment env = new Environment();
		env.setProviderUrl(urlProvider);

		return doGetMBeanServer(env.getInitialContext());
	}

	/**
	 * @see es.ejie.frmk.control.arranque.Q70GestorMBeanServer#getIdInstancia()
	 */
	public String getIdInstancia() {
		return idInstancia;
	}

	/**
	 * @see es.ejie.frmk.control.arranque.Q70GestorMBeanServer#getUrlInstancia()
	 */
	public String getUrlInstancia() {
		return urlInstancia;
	}

	/**
	 * @see es.ejie.frmk.control.arranque.Q70GestorMBeanServer#getNombreClusterInstancia()
	 */
	public String getNombreClusterInstancia() {
		return nombreClusterInstancia;
	}

	/**
	 * @see es.ejie.frmk.control.arranque.Q70GestorMBeanServer#getNombreDominio()
	 */
	public String getNombreDominio() {
		return nombreDominio;
	}
}
