package es.ejie.frmk.control.serviciocoordinacion;

import java.io.Serializable;
import java.util.HashMap;

import es.ejie.frmk.Q70Factoria;
import es.ejie.frmk.conectores.conectorJMS.Q70ConectorJMSExcepcion;
import es.ejie.frmk.control.arranque.Q70Arrancable;
import es.ejie.frmk.control.excepciones.Q70FrameworkException;
import es.ejie.frmk.control.excepciones.Q70GestorDeExcepcionesServidor;
import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70TrazaInterface;

/**
 * Es un servicio que se encarga de las tareas de bajo nivel 
 * para lograr el trabajo coordinado de varias instancias de Geremua. 
 * <p>
 * Puesto que el <b>Servicio de Coordinación</b>se ha implementado en base a mensajes JMS, 
 * la responsabilidad del Servicio de Coordinación se traduce a hacer las suscripciones 
 * y publicaciones oportunas en las colas asociadas a los topics de interés para los Geremuas.
 * El Servicio de Coordinación presta por tanto un servicio al Gestor de Eventos Remotos.
 * <p>
 * Es una capa encima del <b>Conector JMS</b> para descargar al <b>Gestor de Eventos</b> 
 * de la tarea de suministrar al conector JMS parámetros técnicos
 * para lograr la comunicación JMS. 
 * (El conector JMS puede dar servicio a Geremua y también a las aplicaciones, por eso
 * necesita esos parámetros, que serán distintos).
 * <p>
 * El gestor de eventos es un componente de nivel más alto, 
 * envía y recibe la información de los eventos, pero es sensible a su contenido o
 * al menos a su tipo y sabe enrutarla a la clase que debe tratarla.
 * <p>
 * Estructura en capas
 * <p>
 * <table border="1">
 * <tr>
 *  <td>Gestor de Eventos - Gestión de la info transmitida </td><td rowspan=2>Aplicaciones</td>
 * </tr>
 * <tr>
 *  <td>Servicio Coordinación - Com. entre Geremuas</td>
 * </tr>
 * <tr>
 * <td colspan=2>Conector JMS - Comunicación entre aplicaciones a bajo nivel</td>
 * </tr>
 * </table>
 * 
 * @see es.ejie.frmk.control.eventosremotos.Q70GestorEventosRemotos
 * @see es.ejie.frmk.conectores.conectorJMS.Q70ConectorJMS
 * @version 1.0
 * Fecha: 18-dic-03
 */	
public class Q70ServicioCoordinacion implements  Q70ServicioCoordinacionInterface, Q70Arrancable{
	
	private static Q70ServicioCoordinacion singleton = null;
	private String xmlConfiguracion = null;	
	private Q70CoordinacionPublicar publicador = null;
	private HashMap configuracion ;
	
	/**
	 * Devuelve la instancia del Servicio de Coordinacion. En caso de que no exista la crea.
	 * @return Instancia del Servicio de Coordinacion
	 */
	public synchronized static Q70ServicioCoordinacion getSingleton() {
		if (singleton == null){
			singleton = new Q70ServicioCoordinacion();
		}			
		return singleton;
	}
	
	public void afterCreate(String xml) throws Q70FrameworkException{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive()){
			traza.trace(Q70Constantes.ID_COMPONENTE, Q70TraceLevel.DEBUG, "Servicio de Coordinacion --> afterCreate");
		}
		try {
			Q70Configurador conf = new Q70Configurador(xml);
			conf.lanzarConfigurador();				
			xmlConfiguracion = xml;
			initializeService();
		} catch (Exception e) {
			if (traza.isTraceActive()){
				traza.trace(Q70Constantes.ID_COMPONENTE, Q70TraceLevel.ERROR, "Se ha producido un error en el método afterCreate de la clase Q70ServicioCoordinacion");
			}
			throw new Q70FrameworkException(Q70Constantes.ID_COMPONENTE,this.getClass().toString(),"afterCreate","Se ha producido un error en el método afterCreate.",e);
		}		
	}
	
	public void beforeDestroy(){
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive()){
			traza.trace(Q70Constantes.ID_COMPONENTE, Q70TraceLevel.DEBUG, "Servicio de Coordinacion --> beforeDestroy");
		}
		try{
			publicador = null;
		}catch(Exception e){
			Q70GestorDeExcepcionesServidor.getSingleton().recogerThrowable(e);			
		}
	}

	public void reConfigure() throws Q70FrameworkException{
		try {
			beforeDestroy();
			afterCreate(xmlConfiguracion);
		} catch (Q70FrameworkException e) {
			Q70TrazaInterface traza = Q70Factoria.getTraza();
			if (traza.isTraceActive()){
				traza.trace(Q70Constantes.ID_COMPONENTE, Q70TraceLevel.ERROR, "Se ha producido un error en el método reConfigure de la clase Q70ServicioCoordinacion");
			}
			throw new Q70FrameworkException(Q70Constantes.ID_COMPONENTE,this.getClass().toString(),"reConfigure","Se ha producido un error en el método reConfigure.",e);
		}
	}
	/**
	 * Establece la configuracion del servicio desde el configurador
	 * @param <code>configuracion</code> Propiedades de configuracion
	 */		
	protected void setConfiguration(HashMap configuracion){
		this.configuracion = configuracion;	
	}
	
	/**
	 * @see es.ejie.frmk.control.serviciocoordinacion.Q70ServicioCoordinacionInterface#publishMessage(java.lang.String, java.io.Serializable)
	 */
	public synchronized void publishMessage(String nombreTopic, Serializable deliveryMessage) throws Q70ConectorJMSExcepcion{
		publicador.publishMessage(nombreTopic, deliveryMessage);
	}
	
	/**
	 * @see es.ejie.frmk.control.serviciocoordinacion.Q70ServicioCoordinacionInterface#publishMessage(java.lang.String, long, java.io.Serializable)
	 */
	public synchronized void publishMessage(String nombreTopic, long timeToLive, Serializable deliveryMessage) throws Q70ConectorJMSExcepcion{
		publicador.publishMessage(nombreTopic, timeToLive, deliveryMessage);
	}
	/**
	 * Inicia el servicio de coordinación instanciando los objetos que permiten publicar y suscribirse a topics
	 */	
	private void initializeService(){
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		try{		
			if(configuracion == null
				|| configuracion.get(Q70Constantes.UBICACION) == null
				|| configuracion.get(Q70Constantes.UBICACION).equals(""))
				throw new Q70ConectorJMSExcepcion(this.getClass().getName(), "afterCreate", "No se ha especificado factoria JMS", null);
			try{
				String ubicacion = (String)configuracion.get(Q70Constantes.UBICACION);
				publicador = new Q70CoordinacionPublicar(ubicacion);
			}catch(Q70ConectorJMSExcepcion ce){
				if (traza.isTraceActive()) {
					traza.trace(Q70Constantes.ID_COMPONENTE, Q70TraceLevel.ERROR, "Error inicializando servicio de escucha de mensajes JMS ");
				}									
				Q70GestorDeExcepcionesServidor.getSingleton().recogerThrowable(ce);
			}
		}catch(Q70ConectorJMSExcepcion cej){
			if (traza.isTraceActive()) {
				traza.trace(Q70Constantes.ID_COMPONENTE, Q70TraceLevel.ERROR, "Error creando Servicio de Coordinacion");
			}					
			Q70GestorDeExcepcionesServidor.getSingleton().recogerThrowable(cej);
		}
	}
}