/*
 * Fichero:     MensajeXML.java
 * Fecha:       20/10/06
 * Autor:       Alvaro Sarmiento Losada
 * Asignatura:  Proyecto Fin de Carrera
 * Descripción: Contiene la clase MensajeXML, que encapsula documentos XML
 *              y los envía y recibe a través de un objeto SoporteMensajesXML.
 *
 * 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.lib.xml;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * Esta clase representa a un mensaje que actúa como contenedor para el envío y recepción de objetos  {@link DocumentoXML} . La implementación  específica del método de envío y recepción (en cualquier protocolo) del mensaje se deja a cargo de un objeto denominado soporte de  <code>MensajeXML</code>, cuya clase debe implementar la interfaz {@link SoporteMensajesXML} . Esta clase proporciona además métodos para establecer y recuperar los objetos <code>DocumentoXML</code> contenidos  en el mensaje. <br> Es importante usar en el orden adecuado los métodos de esta clase. A  continuación se resumen los pasos: <br> 1.- Registrar el soporte de <code>MensajeXML</code>, mediante el método estático. <code>registrarSoporteMensajes(SoporteMensajesXML soporte)</code> de esta clase.<br> 2.- Crear una instancia de la clase <code>MensajeXML</code>. <br> <b>Para enviar:</b>  <br> 3.- Establecer el contenido XML del mensaje mediante el método <code>setDocumentoXML(DocumentoXML documento)</code>. <br> 4.- Enviar el mensaje mediante el método: <code>enviarMensajeXML()</code>. <br> <b>Para recibir:</b> <br> 3.- Recibir un mensaje mediante el método:  <code>recibirMensajeXML()</code>. <br> 4.- Obtener el contenido XML del mensaje mediante el método <code>getDocumentoXML()</code>. <br><br> <b>Nota:</b> <br> <i>Es muy recomendable usar una nueva instancia de <code>MensajeXML</code> cada vez que se quiera enviar o recibir un nuevo mensaje.
 * @author   Alvaro Sarmiento Losada
 * @see SoporteMensajesXML
 * @see ExcepcionMensajeXML
 * @see  DocumentoXML
 */
public class MensajeXML extends Object {        
    
    /**
     * El objeto {@link SoporteMensajesXML} que se usará para el envío
     * y recepción de un <code>MensajeXML</code>. El objeto que actúe como
     * soporte debe registrarse previamente como soporte usando el método
     * {@link MensajeXML#registrarSoporteMensajes(SoporteMensajesXML soporte)}
     * antes de la creación de algún objeto <code>MensajeXML</code>
     * @see SoporteMensajesXML
     * @see DocumentoXML
     */
    protected static SoporteMensajesXML soporteMensajes;
    
    /**
     * Array para operaciones internas. Almacena la serialización de un
     * objeto <code>DocumentoXML</code>
     */
    private byte[] array;
    
    /**
     * Constante que determina el tamaño de <code>array</code>.
     */
    private final static int TAMANO_BUFFER = 30*1024;
    
    /**
     * Constructor de la clase. 
     * Crea una nueva instancia de <code>MensajeXML</code>.
     */
    public MensajeXML() {        
        array = new byte[TAMANO_BUFFER];
    }
    
    /**
     * Registra un objeto <code>SoporteMensajesXML</code> como soporte 
     * para enviar y recibir los objetos <code>MensajeXML</code>.
     * Este método debe ser llamado al menos una vez antes de la creación 
     * de alguna instancia de <code>MensajeXML</code>. Se usará el soporte
     * especificado para todas los objetos <code>MensajeXML</code>
     * instanciados a partir de la llamada a este método.
     * 
     * @param soporte el objeto <code>SoporteMensajesXML</code> que se quiere
     *                usar como soporte para el envío y recepción de mensajes
     *                <code>MensajeXML</code>
     */
    public static void registrarSoporteMensajes(SoporteMensajesXML soporte) {
        soporteMensajes = soporte;    
    }
    
    /**
     * Obtiene el objeto <code>DocumentoXML</code> contenido en el 
     * <code>MensajeXML</code>.
     * 
     * @return el <code>DocumentoXML</code> contenido en este 
     *         <code>MensajeXML</code>, o <code>null</code> si ocurre
     *         algún error o el objeto <code>MensajeXML</code> no 
     *         contiene nigún <code>DocumentoXML</code>.
     */
    public DocumentoXML getDocumentoXML() {        
        DocumentoXML resultado;
        
        try {
            /*
             * Se crea un flujo asociado al array donde se guarda el 
             * DocumentoXML serializado.
             */
            ByteArrayInputStream flujoByte = new ByteArrayInputStream(array);
            /*
             * Se crea un flujo para deserializar el DocumentoXML asociado a
             * este MensajeXML
             */
            ObjectInputStream flujo = new ObjectInputStream(flujoByte);
            //Se deserializa el DocumentoXML
            resultado =  (DocumentoXML) flujo.readObject();
            flujo.close();
            flujoByte.close();
        } catch (Exception e) {
            resultado = null;
        }
        
        return resultado;
    }
    
    /**
     * Establece el objeto <code>DocumentoXML</code> contenido en este
     * mensaje <code>MensajeXML</code>.
     * 
     * @param documento el <code>DocumentoXML</code> que se quiere incluir 
     *                  como contenido de este <code>MensajeXML</code>.
     */    
    public void setDocumentoXML(DocumentoXML documento)  {
        /*
         * Se crea un flujo se salida asociado al array que contendrá al
         * objeto DocumentoXML serializado
         */
        ByteArrayOutputStream flujoByte = new ByteArrayOutputStream();
        try {
            //Se serializa el objeto DocumentoXML
            ObjectOutputStream flujoObjeto = new ObjectOutputStream(flujoByte);
            flujoObjeto.writeObject(documento);
            flujoObjeto.close();
            //Se guarda el objeto serializado en el array
            array = flujoByte.toByteArray();
            flujoByte.close();
        } catch (IOException ioe) {
            array = null;
        }
    }
    
    /**
     * Envia este <code>MensajeXML</code> usando el objeto 
     * <code>SoporteMensajesXML</code> previamente registrado.
     *
     * @throws ExcepcionMensajeXML si ocurre algún error durante el envío
     *                             usando el <code>SoporteMensajesXML</code>
     *                             registrado.
     */
    public void enviarMensajeXML() throws ExcepcionMensajeXML {
        InputStream flujo = new ByteArrayInputStream(array);        
        try {
            //Se envia el objeto DocumentoXML serializado usando el soporte
            soporteMensajes.enviar(flujo);
        } catch (Exception e) {
            /*
             * Se captura cualquier posible tipo de excepción generada por
             * el SoporteMensajesXML y se considera fatal, relanzándola con
             * la excepción asociada a MensajeXML.
             */
            throw new ExcepcionMensajeXML("Excepcion al enviar MensajeXML", e);
        }
    }
    
    /**
     * Recibe un nuevo <code>MensajeXML</code> usando el objeto
     * <code>SoporteMensajesXML</code> previamente registrado.
     *
     * @throws ExcepcionMensajeXML si ocurre algún error durante la recepción
     *                             usando el <code>SoporteMensajesXML</code>
     *                             registrado.
     */    
    public void recibirMensajeXML() throws ExcepcionMensajeXML {
        try {
            //Se recibe a través del soporte
            InputStream flujo = soporteMensajes.recibir();
            //EL flujo recibido se guarda en el array
            flujo.read(array);
        } catch (Exception e) {
            /*
             * Se captura cualquier posible tipo de excepción generada por
             * el SoporteMensajesXML y se considera fatal, relanzándola con
             * la excepción asociada a MensajeXML.
             */
            throw new ExcepcionMensajeXML("Excepcion al recibir MensajeXML", e);
        }
    }
    
}