/*
 * Fichero:     ComercioP2P.java
 * Fecha:       26/11/2006
 * Autor:       Alvaro Sarmiento Losada
 * Asignatura:  Proyecto Fin de Carrera
 * Descripción: Contiene la interfaz ComercioP2P, que representa un
 *              servicio JXTA orientado a intercambio de mensajes de 
 *              contenido cXML para la aplicación de comercio electrónico
 *              ComercioP2P.
 *
 * Este fichero pertenece al proyecto fin de carrera del autor,
 * consistente en el estudio de JXTA y su aplicación al comercio 
 * electrónico b2b.
 */
package com.pfc.comercio.p2p;

import com.pfc.comercio.cxml.ServicioCXML;
import com.pfc.comercio.p2p.ParametrosComercioP2P;
import com.pfc.lib.p2p.ConfiguradorServicioP2P;
import com.pfc.lib.p2p.ExcepcionP2P;
import com.pfc.lib.p2p.GrupoDePeers;
import com.pfc.lib.p2p.ServicioGenericoP2P;
import com.pfc.lib.xml.MensajeXML;
import com.pfc.lib.xml.SoporteMensajesXML;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import net.jxta.endpoint.InputStreamMessageElement;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.MessageElement;
import net.jxta.util.JxtaBiDiPipe;
import net.jxta.util.JxtaServerPipe;


/**
 * Esta clase representa a un servidor de un servicio JXTA de intercambio de mensajes cXML de comercio electrónico. Actúa como  plataforma de JXTA para los niveles superiores de aplicación: sólo se  encarga de la transmisión y recepción de los mensajes a través de la red  JXTA, dejando a  los niveles superiores la tarea de la generación y  tratamiento de los mensajes. De esta forma se consigue la separación entre  los niveles de Servicio JXTA y Aplicación JXTA, tal y como está descrito en la guía de usuario de JXTA v2.0 . <br> Un objeto de esta clase escucha por una tubería JXTA, esperando a que  lleguen conexiones del cliente  {@link ClienteComercioP2P} . Cuando  llega una, se acepta y se crea una tubería bidireccional por donde  pueden intercambiarse mensajes JXTA. Estos mensajes son de contenido XML. determinados por  {@link MensajeXML} .
 * @author   Alvaro Sarmiento Losada
 * @see  ClienteComercioP2P
 */
public class ComercioP2P extends ServicioGenericoP2P
						 implements ParametrosComercioP2P,
						 			SoporteMensajesXML{
	/** 
     * Almacena una referencia al grupo de peers en el que este servicio
     * es usado.
     */
    private GrupoDePeers grupo;
    
    /**
     * Almacena la tubería de servidor por la que se recibirán las conexiones
     * JXTA por parte del cliente.
     */
    private JxtaServerPipe miServerPipe;

    /**
     * Almacena la tubería JXTA bidireccional por la que se enviarán y 
     * recibirán los mensajes JXTA.
     */
    private JxtaBiDiPipe miBiDiPipe;
    
    /** Almacena una instancia del hilo. */
    private Thread miHilo;
    
    /** La longitud maxima de la cola de la tuberia. */
    private static final int LONG_COLA = 10;

    /**
     * El tiempo en ms que se esperara a que llegue un mensaje del otro 
     * extremo.
     */
    private static final int MENSAJE_TIMEOUT = 120000;
    
    /**
     * Crea una nueva instancia de este servicio a partir de una referencia
     * a un grupo de peers donde implantan este servicio.
     *
     * @param grupo el grupo de peers {@link GrupoDePeers} en el que se
     *              instancia este servicio.
     */
    public ComercioP2P(GrupoDePeers grupo) {
            super(grupo.getMiGrupo());
            this.grupo = grupo;

            miServerPipe = null;
            miBiDiPipe = null;
           /* miHilo = new Thread(this);*/
            
    }
    
    public void realizarServicio(){  /*run*/
        //Se registra este objeto como soporte para enviar mensajes JXTA
        MensajeXML.registrarSoporteMensajes(this);
        
        //Se crea un objeto ServicioCXML que consiste en el nivel de aplicación
        String identidad = grupo.getNombreMiPeer();
        ServicioCXML miServicioCXML = new ServicioCXML(identidad);
        //Este es el bucle prinicpal del programa
        miServicioCXML.ejecutarServicio();
    }
    
   public void ejecutarServicio() {
       
	   System.out.println("ES una prueba");
	   realizarServicio();
    }
    
    public void inicializarServicio() throws ExcepcionP2P {
        /* Se inicializa el servicio JXTA */
        //Se crea un objeto configurador del servicio
        ConfiguradorServicioP2P configurador = 
                          new ConfiguradorServicioP2P(grupo.getNombreMiPeer());
        //Se establecen los parámetros de configuración.        
        configurador.setNombreClaseModulo(CLASMOD_NOMBRE);
        configurador.setDescripcionClaseModulo(DESCRIPCION);
        configurador.setNombreServicio(SERVICIO);
        configurador.setNombreCreador(CREADOR);
        configurador.setVersionServicio(VERSION);
        configurador.setUriServicio(SERV_URI);
        configurador.setTipoTuberia(TIPO_TUBERIA);
        //Se inicializa el servicio llamando a un método de la superclase
        inicializarServicio(configurador);

        /* Se inicializa la tubería del servicio */        
        try {
            /* Se crea el socket que usará el servicio */ 
            miServerPipe = new JxtaServerPipe(miPeerGroup, 
                                              miPipeAdv, 
                                              LONG_COLA);
            
            System.out.println("peer:"+grupo);
        	System.out.println("grupo:"+miPeerGroup);
        	System.out.println("anuncio de tuberia:"+miPipeAdv);
            //Se bloquea el socket hasta que una conexión esté disponible
            miServerPipe.setPipeTimeout(0);
        } catch (IOException ioe) {
            /* 
             * La gestión de errores no se realiza aquí, se relanza 
             * la excepción 
             */
            throw new ExcepcionP2P("Error en la inicializacion del servicio B2B", ioe);
        }
        //El servicio ya está publicado completamente en la red JXTA
    }
    
   
    
    public String toString() {
        return "Implementacion de un servicio de transporte de mensajes XML para Comercio Electronico en JXTA";
    }
    
    public void enviar(InputStream mensaje) throws ExcepcionP2P {
        //Almacena el mensaje a enviar
        Message msg = null;
        //Almacena el elemento del mensaje del servicio
        MessageElement mel = null;

        try {
            
            //Se crea el mensaje JXTA
            msg = new Message();
            mel = new InputStreamMessageElement(TAG, null, mensaje, null);
            msg.addMessageElement(ESPACIO_NOMBRE, mel);
            
            /*
             * Se envía el mensaje. Se usa una copia del mismo para evitar
             * errores en la transmisión.
             */
            miBiDiPipe.sendMessage( (Message) msg.clone() );
        } catch (Exception e) {
            throw new ExcepcionP2P("Error enviando mensaje a traves de JXTA", e);
        }        
    }
    
    public InputStream recibir() throws ExcepcionP2P {
        //Almacena el mensaje recibido
        Message msg = null;
	//Almacena el elemento del mensaje del servicio
        MessageElement mel = null;
	InputStream resultado;
        
        boolean correcto = false;
	while ( correcto == false ) {	  
            try {
                /* 
                 * Se espera que llegue una conexión desde el exterior. 
                 * Cuando llega, se acepta y se crea un tubería para 
                 * comunicarse con el extremo 
                 */
            	System.out.println("Justo antes de aceptar el BiDiPipe");
                miBiDiPipe = miServerPipe.accept();
                System.out.println("Se ha acepado la conexion de la tuberia");
                
                /* 
                 * Se espera un máximo de MENSAJE_TIMEOUT para obtener el 
                 * mensaje del otro extremo 
                 */
                msg = miBiDiPipe.getMessage(MENSAJE_TIMEOUT);
                mel = msg.getMessageElement(ESPACIO_NOMBRE, TAG);
                
                /* Se comprueba que el elemento de mensaje sea válido */
                correcto = ( (mel == null) ? false : true );
                
                if (correcto == false){
                    throw new ExcepcionP2P("Error, mensaje recibido inválido");
                }
            } catch (Exception e) {
                //Ya no se itera más, se sale del método
                throw new ExcepcionP2P("Error al recibir mensaje desde JXTA", e);
            }
        }
        //Si llega aquí, es que se ha recibido un mensaje correcto.
        resultado = new ByteArrayInputStream( mel.getBytes(false) );
        return resultado;
    }
    
}
