package es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.collections.Closure;
import org.apache.commons.collections.CollectionUtils;

import es.ejie.frmk.Q70Factoria;
import es.ejie.frmk.conectores.conectorJDBC.Q70ConectorJDBC;
import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70TrazaInterface;
import es.ejie.frmk.presentacion.sesiondatos.Q70ContextoEJIEDynaClass;
import es.ejie.frmk.presentacion.sesiondatos.utilidades.Q70DatosDeSqlCampo;

/**
 * Implementa parte de la persistencia de contextos en base de datos, las clases hijas proporcionan el resto de la implementación.
 * <p>
 * La BD se indica en el fichero de configuración del contexto.
 * 
 * @version 1.0
 * Fecha: 20-ene-04
 */
public abstract class Q70PersistenciaDesdeBD extends Q70PersistenciaDesdeDynaBean {
	private static final String ID_COMPONENTE = "PERSISTENCIA_DESDE_BD";

	protected static final String MSG_FIN_LISTA_SENTENCIAS = "No hay mas sentencias a ejecutar";

	private transient String ultimaSenteciaSqlEjecutada = "";
	private transient boolean estaSeleccionando = false;

	private String dataSourceContexto;
	private String sqlTabla;
	private String sqlWhere;
	private List listaSqlCampos;
	private transient Map mapaSqlCampos;
	
	/**
	 * Clase abstracta que nos ayuda a recorrer la lista de contextos
	 * 
 	 * @version 1.0
	 * Fecha: 22-dic-03
	 */
	abstract class SqlSentence {
		/**
		 * Sobreescribiendo este metodo se consigue ejecutar diferentes sentencias SQL 
		 */
		public abstract ResultSet execSql(PreparedStatement pstmt) throws SQLException;
		public abstract boolean doResultSql(ResultSet rdo) throws SQLException;
		public abstract PreparedStatement getPreparedStatement(Connection conn, int index) throws SQLException;
	}

	public Q70PersistenciaDesdeBD(Object datos) throws Q70PersistenciaMalInicializadaException {
		super(datos);
	}

	/**
	 * Inicializa los parámetros necesarios para trabajar con una BD.
	 * <p>
	 * datos es una lista con sqlDataSource, sqlTabla, sqlWhere, ListaSqlCampos
	 */
	protected void initialize(Object datos) throws Q70PersistenciaMalInicializadaException {
		if (datos == null) {
			throw new Q70PersistenciaMalInicializadaException(
				ID_COMPONENTE,
				getClass().toString(),
				"initialize()",
				"Clase incorrectamente inicializada",
				null);
		}

		if (datos instanceof List) {
			List listaParametros = (List) datos;
			if (listaParametros.size() == 4) {
				// listaParametros: 0.sqlDataSource, 1.sqlTabla, 2.sqlWhere, 3.ListaSqlCampos
				if (listaParametros.get(0) != null
					&& listaParametros.get(1) != null
					&& listaParametros.get(2) != null
					&& listaParametros.get(3) != null
					&& listaParametros.get(0) instanceof String
					&& listaParametros.get(1) instanceof String
					&& listaParametros.get(2) instanceof String
					&& listaParametros.get(3) instanceof List) {
					setSqlParameters(
						(String) listaParametros.get(0),
						(String) listaParametros.get(1),
						(String) listaParametros.get(2),
						(List) listaParametros.get(3));
					return;
				}
			}
		}
		throw new Q70PersistenciaMalInicializadaException(
			ID_COMPONENTE,
			getClass().toString(),
			"initialize()",
			"Clase incorrectamente inicializada",
			null);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.Q70ManejadorPersistenciaContextoEJIE#doDeleteContexto(java.lang.String)
	 */
	public void doDeleteContexto() {
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive()) {
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** INICIO doDeleteContexto() *****************************");
		}

		doDeleteSqlContextoEJIE();

		if (traza.isTraceActive()) {
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** FIN    doDeleteContexto() *****************************");
		}
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.Q70ManejadorPersistenciaContextoEJIE#toDynaBean(java.lang.String)
	 */
	public DynaBean toDynaBean() {
		//En Persistencia de bd no devuelve nada. Tiene q devolver un new con el contexto obtenido 
		return null;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.Q70ManejadorPersistenciaContextoEJIE#isCambiosPersistentes()
	 */
	public boolean isCambiosPersistentes()
	{
		if ( getManejadorPersistencia() == null )
			return true;
		
		return getManejadorPersistencia().isCambiosPersistentes();
	}
	
	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.ManejadorPersistenciaContextoEJIE#isContextoCambiado()
	 */
	public boolean isMismoContexto() {
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive()) {
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** INICIO isMismoContexto() *****************************");
		}

		if (getManejadorPersistencia() == null) {
			boolean rdoCompare = doCompareSqlContextoEJIE();
			if (traza.isTraceActive()) {
				traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** FIN    isMismoContexto():" + rdoCompare + " *****************************");
			}
			return rdoCompare;
		}
		boolean rdo = getManejadorPersistencia().isMismoContexto();

		if (traza.isTraceActive()) {
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** FIN    isMismoContexto():" + rdo + " *****************************");
		}
		return rdo;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.ManejadorPersistenciaContextoEJIE#doGetContexto()
	 */
	public boolean doGetContexto() {
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive()) {
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** INICIO doGetContexto() *****************************");
		}

		estaSeleccionando = true;
		boolean rdo = doSelectSqlContextoEJIE();
		estaSeleccionando = false;

		if (traza.isTraceActive()) {
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** FIN    doGetContexto():" + rdo + " *****************************");
		}
		return rdo;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.ManejadorPersistenciaContextoEJIE#doSaveContexto(java.lang.String)
	 */
	public void doSaveContexto() {
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (estaSeleccionando) {
			if (traza.isTraceActive()) {
				traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** doSaveContexto(): esta seleccionando no graba, pero pasa por aqui *********");
			}
			return;
		}

		if (traza.isTraceActive()) {
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** INICIO doSaveContexto() *****************************");
		}

		doSaveSqlContextoEJIE();

		if (traza.isTraceActive()) {
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** FIN    doSaveContexto() *****************************");
		}
	}

	/**
	 *
	 * @return Devuelve true si el contexto coincide con el guardado en bd 
	 */
	protected boolean doCompareSqlContextoEJIE() {
		SqlSentence sentence = new SqlSentence() {
			public PreparedStatement getPreparedStatement(Connection conn, int index) throws SQLException {
				PreparedStatement pstmt = conn.prepareStatement(getSelectSentence(index));
				doSelectKey(pstmt, index);
				return pstmt;
			}
			public boolean doResultSql(ResultSet rdo) throws SQLException {
				boolean rdoComparacion = false;
				if (rdo.next()) {
					rdoComparacion = doCompararDatos(rdo);
				}
				return rdoComparacion;
			}
			public ResultSet execSql(PreparedStatement pstmt) throws SQLException {
				Q70TrazaInterface traza = Q70Factoria.getTraza();
				if (traza.isTraceActive()) {
					traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "doCompareSqlContextoEJIE()");
				}
				return pstmt.executeQuery();
			}
		};

		return tratamientoSQL(sentence, -1);
	}

	/**
	 * Busca en el datasource asignado, los datos correspondientes a una sentencia SQL select.
	 *
	 * @return Devuelve true si la busqueda ha sido positiva
	 */
	protected boolean doSelectSqlContextoEJIE() {
		SqlSentence sentence = new SqlSentence() {
			public PreparedStatement getPreparedStatement(Connection conn, int index) throws SQLException {
				PreparedStatement pstmt = conn.prepareStatement(getSelectSentence(index));
				doSelectKey(pstmt, index);
				return pstmt;
			}
			public boolean doResultSql(ResultSet rdo) throws SQLException {
				boolean rdoLectura = false;
				if (rdo.next()) {
					rdoLectura = doRecogerDatos(rdo);
				} else {
					pasarPropiedadesAListaModificados();
				}
				return rdoLectura;
			}
			public ResultSet execSql(PreparedStatement pstmt) throws SQLException {
				Q70TrazaInterface traza = Q70Factoria.getTraza();
				if (traza.isTraceActive()) {
					traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "doSelectSqlContextoEJIE()");
				}
				return pstmt.executeQuery();
			}
		};

		return tratamientoSQL(sentence, -1);
	}

	/**
	 * Inserta o actualiza, segun corresponda, en el datasource asignado, el contexto de sesion usuario. 
	 */
	protected void doSaveSqlContextoEJIE() {
		SqlSentence sentence = null;
		
		if (doExistSqlContextoEJIE(-1, false)){
			sentence = new SqlSentence() {
				public PreparedStatement getPreparedStatement(Connection conn, int index) throws SQLException {
					String aux = getUpdateSentence(index);

					PreparedStatement pstmt = conn.prepareStatement(aux);
					doGuardarDatos(pstmt, index, true);

					return pstmt;
				}
				public ResultSet execSql(PreparedStatement pstmt) throws SQLException {
					Q70TrazaInterface traza = Q70Factoria.getTraza();
					if (traza.isTraceActive()) {
						traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "doSaveSqlContextoEJIE()");
					}
					pstmt.executeUpdate();
					return null;
				}
				public boolean doResultSql(ResultSet rdo) throws SQLException {
					return true;
				}
			};
		}else{
			sentence = new SqlSentence() {
				public PreparedStatement getPreparedStatement(Connection conn, int index) throws SQLException {
					String aux = getInsertSentence(index);
					PreparedStatement pstmt = conn.prepareStatement(aux);
					doGuardarDatos(pstmt, index, false);

					return pstmt;
				}
				public ResultSet execSql(PreparedStatement pstmt) throws SQLException {
					Q70TrazaInterface traza = Q70Factoria.getTraza();
					if (traza.isTraceActive()) {
						traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "doSaveSqlContextoEJIE()");
					}
					pstmt.executeUpdate();
					return null;
				}
				public boolean doResultSql(ResultSet rdo) throws SQLException {
					return true;
				}
			};
		}

		tratamientoSQL(sentence, -1);
	}

	/**
	 * Borra el registro del contexto de sesion usuario en el datasource asignado. 
	 */
	protected void doDeleteSqlContextoEJIE() {

		SqlSentence sentence = null;
		
		if (doExistSqlContextoEJIE(-1, true)){
			sentence = new SqlSentence() {
				public PreparedStatement getPreparedStatement(Connection conn, int index) throws SQLException {
					PreparedStatement pstmt = conn.prepareStatement(getDeleteSentence(index));
					doSelectKey(pstmt, index);
					return pstmt;
				}
				public ResultSet execSql(PreparedStatement pstmt) throws SQLException {
					Q70TrazaInterface traza = Q70Factoria.getTraza();
					if (traza.isTraceActive()) {
						traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "doDeleteSqlContextoEJIE()");
					}
					pstmt.executeUpdate();
					return null;
				}
				public boolean doResultSql(ResultSet rdo) throws SQLException {
					return true;
				}
			};
		}else{
			sentence = new SqlSentence() {
				public PreparedStatement getPreparedStatement(Connection conn, int index) throws SQLException {
					return null;
				}
				public ResultSet execSql(PreparedStatement pstmt) throws SQLException {
					Q70TrazaInterface traza = Q70Factoria.getTraza();
					if (traza.isTraceActive()) {
						traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "doDeleteSqlContextoEJIE()");
					}
					pstmt.executeUpdate();
					return null;
				}
				public boolean doResultSql(ResultSet rdo) throws SQLException {
					return true;
				}
			};
		}

		tratamientoSQL(sentence, -1);
	}

	/**
	 * Busca si un dato existe en BD, dependiendo si es para borrarlo o para actualizarlo
	 *
	 * @return Devuelve true si la busqueda ha sido positiva
	 */
	boolean doExistSqlContextoEJIE(int indexPrevio, boolean isDeleteSentence) {
		//Proviene del metodo doSaveSqlContextoEJIE()
		SqlSentence sentence = new SqlSentence() {
			public PreparedStatement getPreparedStatement(Connection conn, int index) throws SQLException {
				PreparedStatement pstmt = conn.prepareStatement(getFindSentence(index));
				doSaveKey(pstmt, index);
				return pstmt;
			}
			public boolean doResultSql(ResultSet rdo) throws SQLException {
				boolean rdoLectura = false;
				if (rdo.next()) {
					rdoLectura = true;
				}
				return rdoLectura;
			}
			public ResultSet execSql(PreparedStatement pstmt) throws SQLException {
				Q70TrazaInterface traza = Q70Factoria.getTraza();
				if (traza.isTraceActive()) {
					traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "doExistSqlContextoEJIE()");
				}
				return pstmt.executeQuery();
			}
		};
		//Proviene del metodo doDeleteSqlContextoEJIE()
		if (isDeleteSentence) {
			sentence = new SqlSentence() {
				public PreparedStatement getPreparedStatement(Connection conn, int index) throws SQLException {
					PreparedStatement pstmt = conn.prepareStatement(getFindSentence(index));
					doDeleteKey(pstmt, index);
					return pstmt;
				}
				public boolean doResultSql(ResultSet rdo) throws SQLException {
					boolean rdoLectura = false;
					if (rdo.next()) {
						rdoLectura = true;
					}
					return rdoLectura;
				}
				public ResultSet execSql(PreparedStatement pstmt) throws SQLException {
					Q70TrazaInterface traza = Q70Factoria.getTraza();
					if (traza.isTraceActive()) {
						traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "doExistSqlContextoEJIE()");
					}
					return pstmt.executeQuery();
				}
			};
		}

		return tratamientoSQL(sentence, indexPrevio);
	}

	private boolean tratamientoSQL(SqlSentence sentence, int indexPrevio) {
		boolean rdoSQL = false;

		Connection conn = null;
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		try {
			if (traza.isTraceActive()) {
				traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "   >>> Iniciando la peticion de conexion a la BD.");
			}
			conn = Q70ConectorJDBC.getSingleton().getConnection(getDataSource());
			if (conn == null) {
				if (traza.isTraceActive()) {
					traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "   <<< Conexion obtenida =NULL a la BD.");
				}
				return false;
			}
			if (traza.isTraceActive()) {
				traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "   <<< Terminada la peticion de conexion a la BD.");
			}
			
			rdoSQL = tratamientoSQL(conn, sentence, indexPrevio);
			
		} catch (SQLException e) {
			if (traza.isTraceActive()) {
				traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "1.Error en tratamientoSQL(): " + e.getClass() + ":" + e.getMessage());
				traza.trace(ID_COMPONENTE, Q70TraceLevel.FATAL, "2.Error en tratamientoSQL(): linea cod.: " + getLineaCodigoGeremua(e));
				traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "3.Error en tratamientoSQL(): " + getUltimaSenteciaSqlEjecutada());
				traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "4.Error en tratamientoSQL():'" + getContextoEJIEParent().getTipoContexto()+"','"+getContextoEJIEParent().getIdContexto()+"'");
			}
		} catch (Throwable e) {
			if (traza.isTraceActive()) {
				traza.trace(ID_COMPONENTE, Q70TraceLevel.FATAL, "1.Fatal Error en tratamientoSQL(), Exception : " + e.getClass() + ":" + e.getMessage());
				traza.trace(ID_COMPONENTE, Q70TraceLevel.FATAL, "2.Fatal Error en tratamientoSQL(): linea cod.: " + getLineaCodigoGeremua(e));
				traza.trace(ID_COMPONENTE, Q70TraceLevel.FATAL, "3.Fatal Error en tratamientoSQL(), Ultima sql: " + getUltimaSenteciaSqlEjecutada());
				traza.trace(ID_COMPONENTE, Q70TraceLevel.FATAL, "4.Fatal Error en tratamientoSQL(), contexto  :'" + getContextoEJIEParent().getTipoContexto()+"','"+getContextoEJIEParent().getIdContexto()+"'");
			}
		} finally {
			setUltimaSenteciaSqlEjecutada("");
			try {
				if (conn != null)
					conn.close();
				if (traza.isTraceActive()) {
					traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "   >>> Cerrada la conexion a la BD.");
				}
			} catch (SQLException e) {
				if (traza.isTraceActive()) {
					traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "   >>> Error al cerrar la conexion a la BD:" + e.getMessage());
				}
			}
		}
		return rdoSQL;
	}

	boolean tratamientoSQL(Connection conn, SqlSentence sentence, int indexPrevio) {
		boolean rdoSQL = false;

		PreparedStatement pstmt = null;
		ResultSet rdo = null;
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		try {
		
			// Controlar el rollback y commit
			int index = 0;
			if (indexPrevio != -1)
				index = indexPrevio;
			while (true) {
				pstmt = sentence.getPreparedStatement(conn, index++);
				if (pstmt == null)
					break;
				if (traza.isTraceActive()) {
					traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "   >>> Iniciando la llamada a la BD.");
				}
				rdo = sentence.execSql(pstmt);
				if (traza.isTraceActive()) {
					traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "   <<< Terminada la llamada a la BD.");
				}
				rdoSQL = sentence.doResultSql(rdo);
				if (rdo != null)
					break;
				if (indexPrevio != -1)
					break;
			}

		} catch (ArrayIndexOutOfBoundsException e) {
			//Controla si la excepcion la provoca el propio Geremua cuando se ha terminado de ejecutar todas las
			// las sentecias sql para el contextoContraBD tratado.
			if (!e.getMessage().equals(MSG_FIN_LISTA_SENTENCIAS)) {
				if (traza.isTraceActive()) {
					traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "1.Error en tratamientoSQL(): " + e.getClass() + ":" + e.getMessage());
					traza.trace(ID_COMPONENTE, Q70TraceLevel.FATAL, "2.Error en tratamientoSQL(): linea cod.: " + getLineaCodigoGeremua(e));
					traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "3.Error en tratamientoSQL(): " + getUltimaSenteciaSqlEjecutada());
					traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "4.Error en tratamientoSQL():'" + getContextoEJIEParent().getTipoContexto()+"','"+getContextoEJIEParent().getIdContexto()+"'");
				}
			} //En caso contrario, no es un error, es q se ha terminado contextoContraBD tratado de forma correcta.
		} catch (SQLException e) {
			if (traza.isTraceActive()) {
				traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "1.Error en tratamientoSQL(): " + e.getClass() + ":" + e.getMessage());
				traza.trace(ID_COMPONENTE, Q70TraceLevel.FATAL, "2.Error en tratamientoSQL(): linea cod.: " + getLineaCodigoGeremua(e));
				traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "3.Error en tratamientoSQL(): " + getUltimaSenteciaSqlEjecutada());
				traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "4.Error en tratamientoSQL():'" + getContextoEJIEParent().getTipoContexto()+"','"+getContextoEJIEParent().getIdContexto()+"'");
			}
		} catch (Throwable e) {
			if (traza.isTraceActive()) {
				traza.trace(ID_COMPONENTE, Q70TraceLevel.FATAL, "1.Fatal Error en tratamientoSQL(), Exception : " + e.getClass() + ":" + e.getMessage());
				traza.trace(ID_COMPONENTE, Q70TraceLevel.FATAL, "2.Fatal Error en tratamientoSQL(): linea cod.: " + getLineaCodigoGeremua(e));
				traza.trace(ID_COMPONENTE, Q70TraceLevel.FATAL, "3.Fatal Error en tratamientoSQL(), Ultima sql: " + getUltimaSenteciaSqlEjecutada());
				traza.trace(ID_COMPONENTE, Q70TraceLevel.FATAL, "4.Fatal Error en tratamientoSQL(), contexto  :'" + getContextoEJIEParent().getTipoContexto()+"','"+getContextoEJIEParent().getIdContexto()+"'");
			}
		} finally {
			setUltimaSenteciaSqlEjecutada("");
			try {
				if (rdo != null)
					rdo.close();
			} catch (SQLException e) {
			}
			try {
				if (pstmt != null)
					pstmt.close();
			} catch (SQLException e) {
			}
		}
		return rdoSQL;
	}
	
	protected void setSqlParameters(String dataSource, String aSqlTabla, String aSqlWhere, List aListaSqlCampos) {
		dataSourceContexto = dataSource;
		sqlTabla = aSqlTabla;
		sqlWhere = aSqlWhere;
		listaSqlCampos = aListaSqlCampos;
	}
	protected String getSqlTabla() {
		return sqlTabla;
	}
	protected String getSqlWhere() {
		return sqlWhere;
	}
	protected List getListaSqlCampos() {
		return listaSqlCampos;
	}
	protected Map getMapaSqlCampos() {
		if (mapaSqlCampos == null){
			mapaSqlCampos = new HashMap(getListaSqlCampos().size());
			CollectionUtils.forAllDo(getListaSqlCampos(),
				new Closure(){
					public void execute(Object input) {
						Q70DatosDeSqlCampo datos = (Q70DatosDeSqlCampo)input;
						mapaSqlCampos.put(datos.getNombreContextoEquivalente(),datos);
					}
				});
		}
		return mapaSqlCampos;
	}
	String getDataSource() {
		return dataSourceContexto;
	}

	protected void trazaSenteciaEjecutable(String sentencia) {
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive()) {
			StringBuffer aux = new StringBuffer(" Sentencia a ejecutar...");
			aux.append(sentencia);
			aux.append("...ID_CONTEXTO=");
			aux.append(getContextoEJIEParent().getIdContexto());
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, aux.toString());
		}
	}

	protected String getUltimaSenteciaSqlEjecutada() {
		return ultimaSenteciaSqlEjecutada;
	}
	protected void setUltimaSenteciaSqlEjecutada(String ultimaSentenciaSqlEjecutada) {
		ultimaSenteciaSqlEjecutada = ultimaSentenciaSqlEjecutada;
	}

	protected void pasarPropiedadesAListaModificados() {
		DynaProperty[] propAux = ((Q70ContextoEJIEDynaClass) getContextoEJIEParent().getDynaClass()).getPropiedadesDePrimerNivel();
		Collection c = new ArrayList(propAux.length);
		CollectionUtils.addAll(c, propAux);
		CollectionUtils.forAllDo(c, new Closure() {
			public void execute(Object input) {
				getContextoEJIEParent().getListaModificados().add(((DynaProperty) input).getName());
			};
		});
	}
	
	protected void trazaExcepciones(Exception e, String msgCabecera, String msgNombreAtributo)
	{
		Q70TraceLevel traceLevel = Q70TraceLevel.ERROR;
		trazaExcepcionesNivel(e, msgCabecera, msgNombreAtributo, traceLevel);
	}

	protected void trazaExcepcionesNivel(Exception e, String msgCabecera, String msgNombreAtributo, Q70TraceLevel traceLevel) {
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive())
		{
			StringBuffer aux = new StringBuffer(msgCabecera);
			aux.append(e.getClass());
			aux.append(": ");
			aux.append(e.getMessage());
			aux.append(": linea cod. ");
			aux.append(getLineaCodigoGeremua(e));
			if (msgNombreAtributo != null)
			{
				aux.append("...nombreAtributo:");
				aux.append(msgNombreAtributo);
			}
			traza.trace(ID_COMPONENTE, traceLevel, aux.toString());
		}
	}


	/*
	 * Las clases hijas deben implementar estos metodos.
	 */
	protected abstract void doGuardarDatos(PreparedStatement pstmt, int index, boolean existeEnBaseDatos) throws SQLException;
	protected abstract boolean doCompararDatos(ResultSet rdo) throws SQLException;
	protected abstract boolean doRecogerDatos(ResultSet rdo) throws SQLException;
	protected abstract void doSaveKey(PreparedStatement pstmt, int index) throws SQLException;
	protected abstract void doDeleteKey(PreparedStatement pstmt, int index) throws SQLException;
	protected abstract void doSelectKey(PreparedStatement pstmt, int index) throws SQLException;

	/*
	 * Obtener las diferentes senticias SQL necesarias para mantener el Q70ContextoEJIE en BD.
	 */
	protected abstract String getDeleteSentence(int index);
	protected abstract String getInsertSentence(int index);
	protected abstract String getFindSentence(int index);
	protected abstract String getSelectSentence(int index);
	protected abstract String getUpdateSentence(int index);

	
	static String getLineaCodigoGeremua(Throwable e) {
		StackTraceElement[] traza = e.getStackTrace();
		for (int i = 0; i < traza.length; i++) {
			if (traza[i].getClassName().indexOf("es.ejie.frmk")==0){
				return traza[i].toString();
			}
		}
		return null;
	}
}
