package es.ejie.frmk.listeners.listasenlazadas;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.DynaBean;

import weblogic.xml.stream.ElementFactory;
import weblogic.xml.stream.XMLOutputStream;
import weblogic.xml.stream.XMLOutputStreamFactory;
import es.ejie.frmk.control.excepciones.Q70GestorDeExcepciones;
import es.ejie.frmk.infraestructura.logs.navegacion.Q70LogNavegacion;
import es.ejie.frmk.infraestructura.tablas.Q70GestorTablasCodigos;
import es.ejie.frmk.infraestructura.tablas.Q70GestorTablasException;
import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70Traza;
import es.ejie.frmk.listeners.base.Q70HTTPListener;
import es.ejie.frmk.listeners.base.Q70ListenerUtils;
import es.ejie.frmk.listeners.base.Q70LogDataUtils;
import es.ejie.frmk.presentacion.iu.taglib.base.Q70Constants;

/**
 * Esta clase implementa la parte servidora del Gestor de Listas Enlazadas.
 * <p> 
 * Es el punto de entrada para realizar la carga on-Line de custom-tags de tipo <b>lista desplegable</b> 
 * en función del valor seleccionado en otro custom-tag del mismo tipo. Los valores se calcularán de 
 * modo automático y sin necesidad de submitir el formulario, colaborando con el Gestor de Tablas de Códigos.
 * <p>
 * La clase extiende de <code>HttpServlet</code>, de tal modo que es capaz de escuchar peticiones de protocolo http. 
 * <code>Q70HttpListener</code> es un interfaz que debe ser implementado por todos los componentes que 
 * extiendan de <code>Servlet</code> en Geremua y que sigan el protocolo http. Por lo tanto, 
 * <code>Q70ListasEnlazadasListener</code> implementará también esta interfaz.
 * <p>
 * La clase colaborará con otros componentes de Geremua:
 * <ul>
 * <li>El Gestor de Excepciones</li> 
 * <li>El Gestor de Tablas de Códigos</li>
 * </ul>
 * para obtener la lista de pares código/descripción que será cargado por un custom-tag de tipo lista desplegable. 
 * Creará un flujo de salida hacia el browser que realizó la petición 
 * y escribirá el HTML generado sobre el flujo de salida.
 */

public class Q70ListasEnlazadasListener
	extends HttpServlet
	implements Q70HTTPListener {

	
//	-------------------------------------------------------------- Vbles.
	
	/**
	 * Constante que indica el componente al que pertenece la clase. Es
	 * necesario para el uso del log de trazas.
	 */
	private static final String COMPONENTE = "LISTAS_ENLAZADAS";
	
	private static final String CANAL = "BROWSER-PC AUXILIAR";	
	
	/**
	 * Instancia del log de trazas
	 */
	private static Q70Traza tr = null;

	/**
	 * Instancia del log de navegación
	 */
	private static Q70LogNavegacion logNav = null;


		

// -------------------------------------------------------------- Metodos publicos
		
	/**
	 * Método de entrada de la petición de carga de lista enlazada.
	 * <p>
	 * Escribe la entrada en el log de navegación,
	 * delega el procesamiento de la petición en el método <code>listener</code>
	 * y escribe la salida en el log de navegación.
	 * 
	 * @param <code>req</code> Petición a procesar
	 * @param <code>resp</code> Respuesta a crear
	 * @exception <code>ServletException</code>
	 * @exception <code>IOException</code>
	 */
	
	public void service(HttpServletRequest req, HttpServletResponse resp)
		throws ServletException, IOException 
	{
		try {
						
			if (null == tr)	
				tr = Q70Traza.getSingleton();		
			if (null == logNav)	
				logNav = Q70LogNavegacion.getSingleton();

			if (tr.isTraceActive())	
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Entrando al servlet Q70ListasEnlazadasListener...");
			
			
			Q70LogDataUtils.processPrepareLogData(req,CANAL,COMPONENTE);
			writeNavLogBegin();
			this.listen(req, resp);
			writeNavLogEnd();
				
		} 
		catch (ServletException se) 
		{
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "ServletException.");
			}
			catchGenericThrowables(se,req,resp);
		} 
		catch (IOException ioe) 
		{
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "IOException.");
			}
			catchGenericThrowables(ioe,req,resp);
		} 
		catch (Throwable te) 
		{
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Throwable recogida por el Q70ListasEnlazadasListener.");
			}
			catchGenericThrowables(te,req,resp);
		}

		//Borrar la informacion de logs generada
		Q70LogDataUtils.clearLogData(COMPONENTE);
		
	}

	/**
	 * Método del interfaz HTTPListener que delega su funcionalidad en el método <code>process</code>.
	 * <p>
	 * @param <code>req</code> Petición a procesar
	 * @param <code>resp</code> Respuesta a crear
	 * @exception <code>ServletException</code>
	 * @exception <code>IOException</code>
	 * @exception <code>Q70ValidadorRemotoException</code>
	 */
	public void listen(HttpServletRequest req, HttpServletResponse resp)
		throws ServletException, IOException, Q70ListasEnlazadasException 
	{
			process(req, resp);
	}

	/**
	 * Método que trata todo <b>throwable</b> no capturado por capas posteriores.
	 * <p>
	 * Colabora con el <b>Gestor de Excepciones</b>, enviándole el throwable recogido, para que éste lo trate 
	 * y lo registre en el Log de Incidencias
	 * 
	 * @param <code>t</code> Throwable a tratar.
	 * @param <code>request</code> Petición a procesar
	 * @param <code>response</code> Respuesta a crear
	 */
	public void catchGenericThrowables(Throwable t,HttpServletRequest req, HttpServletResponse res) 
	{
		Q70GestorDeExcepciones.getSingleton().recogerThrowable(t, req, res);
	}

	/**
	 * Método que registra un inicio de navegación en el log de navegación.
	 *  
	 * 
	 */
	public void writeNavLogBegin() 
	{
		logNav.log(Q70LogNavegacion.RESPUESTA_OK, Q70LogNavegacion.TIPO_NAVEGACION_ENTRADA);
	}

	/**
	 * Método que registra un fin de navegación en el log de navegación.
	 * 
	 * 
	 */
	public void writeNavLogEnd() 
	{
		logNav.log(Q70LogNavegacion.RESPUESTA_OK, Q70LogNavegacion.TIPO_NAVEGACION_SALIDA);
	}
	
	public void dispatch(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}
	
	
	
//----------------------------------------------------------------  Metodos privados
		
	/**
	 * Procesa la peticion de carga de lista enlazada invocando al Gestor de Tablas de Códigos (<code>getData</code>).
	 * Después genera el código html de respuesta, y lo devuelve a la página que ha llamado al servlet
	 * (<code>sendResponse</code>).
	 *  @param <code>req</code> Petición a procesar
	 * @param <code>resp</code> Respuesta a crear
	 * @throws <code>QQ70ListasEnlazadasException</code>
	 * @throws <code>IOException</code>
	 */
	private void process(HttpServletRequest req, HttpServletResponse resp)
		throws Q70ListasEnlazadasException, IOException 
	{		
			if (tr.isTraceActive())	
			{
				StringBuffer trBuf = new StringBuffer("Q70ListasEnlazadasListener: Procesando peticion con valores: \n");
				trBuf.append("-retFunc=").append(req.getParameter("retFunc")).append("\n")				
					 .append("-targetTag=").append(req.getParameter("targetTag")).append("\n")
					 .append("-targetTagValue=").append(req.getParameter("targetTagValue")).append("\n")
					 .append("-sourceTag=").append(req.getParameter("sourceTag")).append("\n")
					 .append("-sourceTagValue=").append(req.getParameter("sourceTagValue")).append("\n")
					 .append("-formName=").append(req.getParameter("formName")).append("\n")	
					 .append("-table=").append(req.getParameter("table")).append("\n")
					 .append("-labelColumn=").append(req.getParameter("labelColumn")).append("\n")
					 .append("-valueColumn=").append(req.getParameter("valueColumn")).append("\n")
					 .append("-predicateColumn=").append(req.getParameter("predicateColumn")).append("\n")
					 .append("-predicateColumnNumeric=").append(req.getParameter("predicateColumnNumeric")).append("\n")
					 .append("-extraPredicate=").append(req.getParameter("extraPredicate")).append("\n")
					 .append("-idioma=").append(Q70ListenerUtils.getLanguage(req));
				
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, trBuf.toString()); 
			} 


			String strData = 
				    getData(req.getParameter("targetTagValue"),
					 	    req.getParameter("sourceTagValue"),
							req.getParameter("table"),
							req.getParameter("labelColumn"),
							req.getParameter("valueColumn"),
							req.getParameter("predicateColumn"),
							req.getParameter("predicateColumnNumeric"),							   
							req.getParameter("extraPredicate"),
							Q70ListenerUtils.getLanguage(req));
			
			
			 /* componemos un tipo de retorno en función de la tecnología empleada. Si se hace la búsqueda de listas vía
			  	iframe componemos el retorno en código html, si se trata de tecnología iframe componemos la 
			  	respuesta en código xml 
			 */
			if ((req.getParameter("technology") != null) && (req.getParameter("technology").equalsIgnoreCase(Q70Constants.IFRAME_TECH))){
				String htmlCode = 
					composeHtmlResponse(req.getParameter("formName"), 
										req.getParameter("targetTag"),
										req.getParameter("targetTagValue"), 
										req.getParameter("sourceTag"),
										req.getParameter("sourceTagValue"),
										req.getParameter("retFunc"),
										strData);
				sendResponse(htmlCode, resp);
			} else {
				sendXmlResponse(req.getParameter("formName"), 
						req.getParameter("targetTag"),
						req.getParameter("targetTagValue"), 
						req.getParameter("sourceTag"),
						req.getParameter("sourceTagValue"),
						req.getParameter("retFunc"),
						strData, resp);
			}
		
	}
	
	
	/**
	 * Compone y ejecuta una consulta SQL contra el Gestor de Tablas y Codigos.
	 * 
	 * @param <code>targetTagValue</code> valor del tag html destino.
	 * @param <code>sourceTagValue</code> valor del tag html origen  
	 * @param <code>table</code> nombre de la tabla de la consulta 
	 * @param <code>labelColumn</code> columna de la parte select de la consulta
	 * @param <code>valueColumn</code> columna de la parte select de la consulta
	 * @param <code>predicateColumn</code> columna de la parte where de la consulta
	 * @param <code>predicateColumnNumeric</code> indica si la columna de la parte where de la consulta es numérica (true|false)
	 * @param <code>extraPredicate</code> condiciones extra a añadir a la consulta 
	 * @param <code>idioma</code> idioma de la página que llamó al servlet  
	 * @return resultado de la llamada al Gestor de Tablas
	 */
	private String getData(String targetTagValue,
				   	       String sourceTagValue,
						   String table,
						   String labelColumn,
						   String valueColumn,
						   String predicateColumn,
						   String predicateColumnNumeric,
						   String extraPredicate,
						   String idioma)
		throws Q70ListasEnlazadasException
	{
		
		StringBuffer dataBuf = null;								

		try 
		{					
			//Obtener las columnas que forman la parte 'select' (o sujeto) de la consulta a lanzar
			Vector cols = new Vector(3);			
			cols.add(valueColumn);
			cols.add(labelColumn);
			cols.add(predicateColumn);	

			//Componer la parte 'where' de la consulta
			StringBuffer where = new StringBuffer(64);
			if (null!=sourceTagValue && 0<sourceTagValue.trim().length())
			{
				where.append(predicateColumn);
				where.append("=");
				if (predicateColumnNumeric.equals("true"))
					where.append(sourceTagValue);	
				else
					where.append("'").append(sourceTagValue).append("'");
			}

			if (null!=extraPredicate && 0<extraPredicate.trim().length())
			{
				where.append((where.length()>0?" AND ":"")).append("(").append(extraPredicate).append(")");
			}
			
			if (tr.isTraceActive())	
			{
				StringBuffer trBuf = new StringBuffer("Q70ListasEnlazadasListener: Llamando al Gestor de Tablas y Codigos con valores: \n");
				trBuf.append("-table=").append(table).append("\n")
					 .append("-where=").append(where.toString()).append("\n")
					 .append("-lenguage=").append(idioma).append("\n")
					 .append("-cols=").append(cols.toString());
				
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, trBuf.toString()); 
			} 			
			
			// Llamada al Gestor de Tablas y Codigos
			Collection dataCol = 
				(Collection) Q70GestorTablasCodigos.getSingleton().
				  	   		 selectRecordsFromTable( table, 
										 		     where.toString(),
													 idioma,   
													 cols );
													 

			if (tr.isTraceActive())	
			{					
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Q70ListasEnlazadasListener: El tamanio de la coleccion devuelta por el Gestor de tablas y Codigos es: " + dataCol.toArray().length); 
			} 
												   			 
																	   
			if (!dataCol.isEmpty()) 
			{
				//Formato de los datos a devolver: value~label|value~label|...
			
				Iterator it = dataCol.iterator();
				if (it.hasNext()) dataBuf = new StringBuffer();
				while(it.hasNext())
				{
					DynaBean dyn=(DynaBean) it.next();
					if (dyn.get(predicateColumn)!=null)
					{
						dataBuf.append(dyn.get(valueColumn).toString())
							   .append("~") //El caracter ~ se obtiene con alt+126					
							   .append(dyn.get(labelColumn).toString())
							   .append("|");
					}					
				}	
				if (dataBuf!=null) dataBuf.deleteCharAt(dataBuf.length()-1);
			}
			
					
		}
		catch(Q70GestorTablasException gte)
		{
			throw new Q70ListasEnlazadasException(this.getClass().toString(),
											   "getDescription",
											   "Excepcion generada por el Gestor de Tablas y Codigos",
											   gte);	
		}
		catch(Exception ex)
		{				
			throw new Q70ListasEnlazadasException(this.getClass().toString(),
											   "getDescription",
											   "Excepcion sin especificar recogida",
											   ex);
		}

		if (tr.isTraceActive())	
		{
			tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Q70ListasEnlazadasListener: El resultado de la consulta contra el Gestor de Tablas y Codigos es: " + (dataBuf!=null ? dataBuf.toString() : "")); 
		} 

		
		return (dataBuf!=null ? dataBuf.toString() : "");
	}
	
	
	/**
	 * Compone el codigo html que se va a mandar de vuelta al browser cliente.
	 * Si no se ha alimentado la función javascript de retorno, se devuelve el resultado sobre el campo 
	 * del formulario que lo espera (lista enlazada). Pero si la hay, se devuelve una llamada 
	 * a la función javascript en la forma:
	 * 		<code>funcion de retorno</code>(codigo,resultado) 
	 * donde
	 * -codigo: valor del atributo sourceTag o resultado obtenido del Gestor de Tablas 
	 * -resultado: valor del atributo targetTag o resultado obtenido del Gestor de Tablas
	 * 
	 * Si ha habido algún error durante todo el proceso, se devuelve
	 * blancos sobre ambos campos del formulario.
	 *   
	 * @param (String) formName: nombre del formulario donde estan los campos
	 * @param (String) targetTag: nombre del tag html de destino
	 * @param (String) targetTagValue: valor del tag html de destino
	 * @param (String) sourceTag: nombre del tag html origen
	 * @param (String) sourceTagValue: valor del tag html origen
	 * @param (String) retFunc: nombre de la funcion javascript de retorno 
	 * @param (String) strData: resultado obtenido de la llamada al Gestor de Tablas   
	 * @return (StringBuffer) codigo html a devolver al browser cliente
	 */
	private String composeHtmlResponse(String formName, 
									   String targetTag,
									   String targetTagValue, 
									   String sourceTag,
									   String sourceTagValue,
									   String retFunc,
									   String strData)
		throws Q70ListasEnlazadasException
	{
		
		if (tr.isTraceActive())	
		{
			StringBuffer trBuf = new StringBuffer("Comenzando a componer el codigo html de respuesta del Validador Remoto para los valores: \n");
			trBuf.append("-formName=").append(formName).append("\n")
				 .append("-targetTag=").append(targetTag).append("\n")
				 .append("-targetTagValue=").append(targetTagValue).append("\n")
				 .append("-sourceTag=").append(sourceTag).append("\n")
				 .append("-sourceTagValue=").append(sourceTagValue).append("\n")
				 .append("-targetTagValue=").append(targetTagValue).append("\n")
				 .append("-retFunc=").append(retFunc).append("\n")
				 .append("-strData=").append(strData);
				
			tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, trBuf.toString()); 
		} 		
		
		
		StringBuffer sb = null; 
			
		try
		{
			sb = new StringBuffer(256);
			sb.append("<script language='JavaScript' type='text/javascript'>");
			
			if (null!=retFunc && 0<retFunc.length()) 
			{
				// Llamar a la funcion javascript de retorno
				if (retFunc.indexOf("()")>0) 
					retFunc.substring(retFunc.length()-2);	
					
				// Devuelve: parent.funcionRetorno(sourceTagValue,strData)
				sb.append("parent.")
				  .append(retFunc)					
				  .append("(\"")
				  .append(sourceTagValue)
				  .append("\",\"")				
				  .append(strData)				
				  .append("\");");		
			} 
			else 
			{
				//--------------------------------------------
				// Comportamiento por defecto de Geremua:
				//--------------------------------------------
				// Devuelve: parent.frmkFillList(targetTag,strData)				
				sb.append("parent.frmkFillList(\"")
				  .append(targetTag)
				  .append("\",\"")
				  .append(strData)
				  .append("\");");															
			}
			
			sb.append("</script>");

		} 
		catch(Exception ex) 
		{
			throw new Q70ListasEnlazadasException(this.getClass().toString(),
											   "composeHtmlResponse",
											   "Excepcion recogida",
											   ex);
		}

		if (tr.isTraceActive())	
		{			
			tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Q70ListasEnlazadasListener: El codigo html a devolver es: " + (null!=sb?sb.toString():"")); 
		} 	
		
		return (null!=sb ? sb.toString() : "");
	}
	
	/**
	 * Compone y envia el codigo xml que se va a mandar de vuelta al browser cliente.
	 * Si no se ha alimentado la función javascript de retorno, se devuelve el resultado sobre el campo 
	 * del formulario que lo espera (lista enlazada). Pero si la hay, se devuelve una llamada 
	 * a la función javascript en la forma:
	 * 		<code>funcion de retorno</code>(codigo,resultado) 
	 * donde
	 * -codigo: valor del atributo sourceTag o resultado obtenido del Gestor de Tablas 
	 * -resultado: valor del atributo targetTag o resultado obtenido del Gestor de Tablas
	 * 
	 * Si ha habido algún error durante todo el proceso, se devuelve
	 * blancos sobre ambos campos del formulario.
	 *   
	 * @param (String) formName: nombre del formulario donde estan los campos
	 * @param (String) targetTag: nombre del tag html de destino
	 * @param (String) targetTagValue: valor del tag html de destino
	 * @param (String) sourceTag: nombre del tag html origen
	 * @param (String) sourceTagValue: valor del tag html origen
	 * @param (String) retFunc: nombre de la funcion javascript de retorno 
	 * @param (String) strData: resultado obtenido de la llamada al Gestor de Tablas
	 * @param HttpServletResponse response
	 */
	private void sendXmlResponse(String formName, 
									   String targetTag,
									   String targetTagValue, 
									   String sourceTag,
									   String sourceTagValue,
									   String retFunc,
									   String strData, HttpServletResponse response)
		throws Q70ListasEnlazadasException
	{
		
		if (tr.isTraceActive())	
		{
			StringBuffer trBuf = new StringBuffer("Comenzando a componer el codigo XML de respuesta del Validador Remoto para los valores: \n");
			trBuf.append("-formName=").append(formName).append("\n")
				 .append("-targetTag=").append(targetTag).append("\n")
				 .append("-targetTagValue=").append(targetTagValue).append("\n")
				 .append("-sourceTag=").append(sourceTag).append("\n")
				 .append("-sourceTagValue=").append(sourceTagValue).append("\n")
				 .append("-targetTagValue=").append(targetTagValue).append("\n")
				 .append("-retFunc=").append(retFunc).append("\n")
				 .append("-strData=").append(strData);
				
			tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, trBuf.toString()); 
		}
			
		try
		{
			//La respuesta la hacemos en UTF-8 ya que AJAX parece que no soporta otro charset
			XMLOutputStreamFactory factory = XMLOutputStreamFactory.newInstance();
			XMLOutputStream output = factory.newOutputStream(new OutputStreamWriter(response.getOutputStream(), "UTF-8"));
			response.setContentType("text/xml");
			response.setHeader("Cache-Control", "no-cache");
			
			//abrimos el tag raíz <listenerResponse>
			output.add(ElementFactory.createStartDocument("UTF-8","1.0"));
			output.add(ElementFactory.createStartElement("listenerResponse"));   
			output.add(ElementFactory.createCharacterData("\n"));
			
			//abrimos el tag <listener> que contendrá el componente: validador remoto
			output.add(ElementFactory.createStartElement("listener"));
			output.add(ElementFactory.createCharacterData("listasEnlazadas"));
			output.add(ElementFactory.createEndElement("listener"));   
			output.add(ElementFactory.createCharacterData("\n"));
			
			output.add(ElementFactory.createStartElement("elementos"));
			output.add(ElementFactory.createCharacterData("\n"));
			
			if (null!=retFunc && 0<retFunc.length()) 
			{
				// Llamar a la funcion javascript de retorno
				if (retFunc.indexOf("()")>0) 
					retFunc.substring(retFunc.length()-2);	
					
				output.add(ElementFactory.createStartElement("funcionRetorno"));
				output.add(ElementFactory.createCharacterData(retFunc));
				output.add(ElementFactory.createEndElement("funcionRetorno"));   
				output.add(ElementFactory.createCharacterData("\n"));
				
				output.add(ElementFactory.createStartElement("sourceTagValue"));
				output.add(ElementFactory.createCharacterData(sourceTagValue));
				output.add(ElementFactory.createEndElement("sourceTagValue"));   
				output.add(ElementFactory.createCharacterData("\n"));
				
				
			} else {
				output.add(ElementFactory.createStartElement("targetTag"));
				output.add(ElementFactory.createCharacterData(targetTag));
				output.add(ElementFactory.createEndElement("targetTag"));   
				output.add(ElementFactory.createCharacterData("\n"));
			}
			
			output.add(ElementFactory.createStartElement("datos"));
			output.add(ElementFactory.createCharacterData(strData));
			output.add(ElementFactory.createEndElement("datos"));   
			output.add(ElementFactory.createCharacterData("\n"));
			
			output.add(ElementFactory.createEndElement("elementos"));   
			output.add(ElementFactory.createCharacterData("\n"));
			
			//cerrramos el tag raíz <listenerResponse>
			output.add(ElementFactory.createEndElement("listenerResponse"));   
			output.add(ElementFactory.createCharacterData("\n"));
			
			output.flush();
			output.close();
		} 
		catch(Exception ex) 
		{
			throw new Q70ListasEnlazadasException(this.getClass().toString(),
											   "sendXmlResponse",
											   "Excepcion recogida",
											   ex);
		}

		if (tr.isTraceActive())	
		{
			tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Q70ListasEnlazadasListener: Se ha devuelto el XML."); 
		}
	}
	
	
	/**
	 * Este método envía la respuesta generada al browser cliente
	 * <p>
	 * Crea un flujo de salida hacia el browser que realizó la petición y
	 * escribe el HTML generado sobre el flujo de salida.
	 * 
	 * @param <code>htmlCode</code> Cadena HTML generada. Incluye función javaScript para actualizar los valores de
	 * la lista enlazada.
	 * @param <code>response</code> Respuesta a crear
	 * @throws <code>Q70ValidadorRemotoException</code>
	 */
	private void sendResponse(String htmlCode, HttpServletResponse response) 
		throws IOException
	{		
		ServletOutputStream out = response.getOutputStream();
		out.println(htmlCode);
		out.flush();   						
	}
	
	
}
