package com.ejie.ab04b.parse;

import java.io.StringReader;
import java.io.UnsupportedEncodingException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.sax.SAXSource;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

import com.ejie.ab04b.util.NamespaceFilter;

/**
 * Clase que implementa el parser para los mensajes SOAP. Codifica desde UTF-8.
 * 
 * @author GFI-NORTE
 <O>
 *            type
 */
public class MessageParserSax<O> {

	private String packageName;
	private String namespace;

	/**
	 * Constructor de la clase.
	 * 
	 *  packageName            String
	 *  namespace            String
	 *
	 * @param packageName the package name
	 * @param namespace the namespace
	 */
	public MessageParserSax(String packageName, String namespace) {
		this.packageName = packageName;
		this.namespace = namespace;
	}

	/**
	 * Metodo que parse un XML a un objeto de negocio.
	 * 
	 *  message            String
	 *  Object
	 *
	 * @param message the message
	 * @return the o
	 * @throws JAXBException             e
	 * @throws UnsupportedEncodingException             e
	 * @throws SAXException             e
	 */
	@SuppressWarnings(value = { "unchecked", "rawtypes" })
	public O parse(String message)
			throws JAXBException, UnsupportedEncodingException, SAXException {
		if (message != null) {
			JAXBContext jc;
			// Paquete que contiene las clases generadas en la compilacion del
			// xsd
			jc = JAXBContext.newInstance(this.packageName);
			Unmarshaller unmarshaller = jc.createUnmarshaller();
			Object jaxbObject = null;

			// Create an XMLReader to use with our filter
			XMLReader reader = XMLReaderFactory.createXMLReader();

			// Create the filter (to add namespace) and set the xmlReader as its
			// parent.
			NamespaceFilter inFilter = new NamespaceFilter(this.namespace,
					true);
			inFilter.setParent(reader);

			// Create a SAXSource specifying the filter
			SAXSource source = new SAXSource(inFilter,
					new InputSource(new StringReader(message)));

			jaxbObject = unmarshaller.unmarshal(source);

			/*
			 * Se realiza una comprobacion de que el elemento que devuelve la
			 * funcion 'unmarshal' sea de tipo JAXBElement. Si es asi, es
			 * necesario recuperar la clase que se quiere devolver de su
			 * atributo 'value'. La funcion unmarshal devuelve el objeto
			 * JAXBElement cuando encuentra algún problema con la anotacion
			 * 'xmlRootElement' de las clases a parsear.
			 */
			if (jaxbObject instanceof JAXBElement<?>) {
				return (O) ((JAXBElement) jaxbObject).getValue();
			} else {
				return (O) jaxbObject;
			}
		} else {// Si el mensaje es null devuelve null.
			return null;
		}
	}
}
