package es.ejie.frmk.presentacion.sesiondatos;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpSession;

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

import es.ejie.frmk.Q70Factoria;
import es.ejie.frmk.control.arranque.Q70Arrancable;
import es.ejie.frmk.control.arranque.Q70GestorArranqueConfiguracionServidor;
import es.ejie.frmk.control.excepciones.Q70FrameworkException;
import es.ejie.frmk.control.excepciones.Q70GestorDeExcepcionesServidor;
import es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridad;
import es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadInterface;
import es.ejie.frmk.infraestructura.seguridad.Q70SeguridadException;
import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70TrazaInterface;
import es.ejie.frmk.infraestructura.traza.Q70TrazaServidor;
import es.ejie.frmk.infraestructura.utilidades.configurador.Q70Configurable;
import es.ejie.frmk.infraestructura.utilidades.configurador.Q70Configurador;
import es.ejie.frmk.infraestructura.utilidades.excepciones.Q70UtilidadesExcepcion;
import es.ejie.frmk.presentacion.base.Q70Constantes;
import es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.Q70ManejadorPersistenciaContextoEJIE;
import es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.Q70PersistenciaDesdeDynaBean;
import es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.Q70PersistenciaDesdeXml;
import es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.Q70PersistenciaMalInicializadaException;
import es.ejie.frmk.presentacion.sesiondatos.utilidades.Q70ContextoEJIERuntimeException;

/**
 * El <b>Gestor de Sesión/Datos</b> es responsable de crear, recuperar, almacenar... los contextos de Geremua.
 * <p>
 * El gestor de Sesión/Datos es el responsable de manejar una estructura de contextos enlazados de forma jerárquica.
 * Es capaz de crear los diferentes contextos que manejan las operaciones de presentación, 
 * asignar listas de contextos asociados y  recuperarlos mediante una interface simple.
 * <p>
 * El gestor de Sesión/Datos contiene la estructura de almacenamiento en memoria para tener accesible 
 * en todo momento todos los contextos globales activos en Geremua; 
 * y tambien tener en memoria los contextos de <b>sesionUsuario</b> y <b>GrupoAplicaciones</b> que se van creando 
 * según se soliciten y se van borrando en el momento que se invaliden. 
 * Se trata de no duplicar la misma información en diferentes areas de memoria, 
 * mejorando el rendimiento y la eficacia de las aplicaciones usuarias de Geremua. 
 * Además, la interfaz del componente permite refrescar los contextos globales en base a su manejador de persistencia
 * (en xml, en base de datos) y tambien hacer persistir los contextos de sesión (de usuario y de grupo de aplicación) para su actualización.
 * <p>
 * El gestor de Sesión/Datos es el responsable de almacenar en memoria una referencia a todas las HttpSession 
 * del servidor en el cual Geremua está levantado. 
 * La necesidad del almacenamiento se debe a la posibilidad de invalidar todas las sesiones asociadas a un usuario 
 * en un momento dado, es decir, desconectar a ese usuario (opción de la Aplicación de Administración (r09)).
 * <p>
 * Este componente es arrancado al inicializar Geremua y conocerá como configurarse a partir de un fichero XML, 
 * con la estructura estándar de ficheros de configuración.
 * 
 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE
 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoEJIE
 * @version 1.0
 * Fecha: 08-mar-04
 */
public class Q70SesionDatos implements Q70Arrancable, Q70Configurable
{
	public static final String CTX_OPERACION_PRESENTACION = "OP";
	public static final String CTX_APLICACION = "APLICACION";

	public static final String CTX_SESION_USUARIO = "SESIONUSUARIO";
	public static final String CTX_GRUPO_APLICACIONES = "GRUPOAPLICACIONES";

	public static final String CTX_GLOBAL_DEPARTAMENTO = "DEPARTAMENTO";
	public static final String CTX_GLOBAL_APLICACIONGLOBAL = "APLICACIONGLOBAL";
	public static final String CTX_GLOBAL_ESCENARIO = "ESCENARIO";
	public static final String CTX_GLOBAL_ENTIDAD = "ENTIDAD";
	public static final String CTX_GLOBAL_SISTEMA_TECNICO = "SISTEMATECNICO";

	public static final String STR_PARA_CONCATENAR_EN_GRUPOAPLICACION = "SESIONUSU";
	
	private int initialVolumenHttpSessions = 100;
	private static Collection listaHttpSessions;

	private static final String ID_COMPONENTE = "SESIONDATOS";

	private static Q70SesionDatos sesionDatos = null;

	private String fileNameConfiguracion;
	protected String rutaXMLSesionUsuario, rutaXMLGrupoAplicacion_Prefix, rutaXMLGrupoAplicacion_Sufix;

	private class DatosContextoGlobalXML
	{
		private String rutaXmlContexto, tipoContexto, idContexto;
		private List listaObservadores;
	}
	private transient DatosContextoGlobalXML datosContextoGlobal;

	private Q70SesionDatos()
	{
		super();
	}

	/**
	 * Devuelve una instancia única de Q70SesionDatos, que será siempre la misma
	 * @return Una instancia única de Q70SesionDatos
	 */
	public static Q70SesionDatos getSingleton()
	{
		if (sesionDatos == null)
		{
			sesionDatos = new Q70SesionDatos();
		}
		return sesionDatos;
	}

	/**
	 * Devuelve el tipo del contexto pasado como parametro
	 * @param contextoOrigen Un Contexto origen
	 * @return Tipo del contexto
	 */
	public String getContextoTipo(Q70ContextoEJIE contextoOrigen)
	{
		if (contextoOrigen == null)
			return null; // asi o lanzo una excepcion o lo dejo pasar ?? 

		return ((Q70ContextoJerarquicoEJIE) contextoOrigen).getTipoContexto();
	}

	/**
	 * Devuelve un subcontexto del contexto y tipo pasados por parametro.
	 * @param contextoOrigen Un Contexto origen
	 * @param tipoContexto Tipo del subcontexto buscado
	 * @return Un subcontexto de la clase Q70ContextoEJIE
	 */
	public Q70ContextoEJIE getContexto(Q70ContextoEJIE contextoOrigen, String tipoContexto)
	{
		return (Q70ContextoEJIE) ((Q70ContextoJerarquicoEJIE) contextoOrigen).getContextoSesion(tipoContexto);
	}

	/**
	 * Devuelve el contexto global correspondiente al tipo e id pasados por parametro.
	 * @param tipoContexto Tipo del contexto global buscado
	 * @param idContexto Identificativo del contexto global buscado
	 * @return Un contexto global
	 */
	// TODO Cambiarle el nombre para indicar que se pueden coger tb ctx de sesion usuario y grupo, es decir, ctxs que esten en memoria del servidor
	public Q70ContextoEJIE getContextoGlobal(String tipoContexto, String idContexto)
	{
		return Q70ContextosEnMemoriaManejador.getContexto(tipoContexto, idContexto);
	}

	/**
	 * Crea un Q70ContextoOperacion a partir de un DynaBean, con el id indicados.
	 * El tipo de contexto será de operación de presentación.
	 * 
	 * @param aContexto Contiene la estructura y datos del contexto a crear
	 * @param idContexto Identificativo del contexto a crear
	 * @return Un Q70ContextoEJIE
	 */
	public Q70ContextoEJIE crearContextoOperacion(DynaBean aContexto, String idContexto)
	{
		try
		{
			Q70ManejadorPersistenciaContextoEJIE manejador = getManejadorParaDynaBean(aContexto);
			Q70ContextoEJIE ctx = new Q70ContextoOperacion(aContexto, manejador, CTX_OPERACION_PRESENTACION, idContexto);
			return ctx;

		}
		catch (Q70PersistenciaMalInicializadaException e)
		{
			Q70TrazaInterface traza = Q70Factoria.getTraza();
			if (traza.isTraceActive())
			{
				traza.trace(
					ID_COMPONENTE,
					Q70TraceLevel.ERROR,
					"Error en crear persistencia por defecto, Q70PersistenciaDesdeDynaBean en clase:'"
						+ this.getClass()
						+ "','"
						+ CTX_OPERACION_PRESENTACION
						+ "','"
						+ idContexto
						+ "'");
			}
			Q70GestorDeExcepcionesServidor.getSingleton().recogerThrowable(e);
		}
		return null;
	}

	/**
     * Devolver el contexto de <b>sesionUsuario</b> perteneciente al usuario con el identificativo 
     * pasado por parámetro.
     * <p>
     * Si no existiese una referencia en memoria se crea dicho contexto 
     * y se almacena en memoria hasta que se invalide. 
     * Se le pasa por parámetro el identificador único de contexto y la ruta correspondiente 
     * a su xml de configuración.
	 * 
	 * @param idContexto Identificativo del contexto a crear
	 * @param rutaXMLConfiguracion fichero XML que la base para crear el contexto deseado
	 * @return Un Q70ContextoEJIE
	 * @throws Q70PersistenciaMalInicializadaException
	 */
	public Q70ContextoEJIE crearContextoSesionUsuario(String idContexto, String rutaXMLConfiguracion) throws Q70PersistenciaMalInicializadaException
	{
		return Q70SesionDatosCrearUsarios.crearContextoSesionUsuario(idContexto,rutaXMLConfiguracion);
	}
	/**
	 * Devolver el contexto de <b>Grupo de Aplicación</b> de usuario perteneciente al grupo de aplicaciones 
	 * y el usuario con el identificativo pasado por parámetro.
	 * Si no existiese una referencia en memoria se crea dicho contexto 
	 * y se almacena en memoria hasta que se invalide.
	 * <p>
	 * Se le pasa por parámetro el identificador unico de contexto y la ruta correspondiente
	 * a su xml de configuración
	 * 
	 * @param idContexto Identificativo del contexto a crear
	 * @param rutaXMLConfiguracion fichero XML que la base para crear el contexto deseado
	 * @return Un Q70ContextoEJIE
	 * @throws Q70PersistenciaMalInicializadaException
	 */
	public Q70ContextoEJIE crearContextoGrupoAplicacion(String idContexto, String rutaXMLConfiguracion)
		throws Q70PersistenciaMalInicializadaException
	{
		return Q70SesionDatosCrearUsarios.crearContextoGrupoAplicacion(idContexto,rutaXMLConfiguracion);
	}
	/**
	 * Crea un Q70ContextoBasico a partir de un fichero XML donde se definen la 
	 * estructura y datos que va a contener el contexto. Ademas, se crea del tipo y 
	 * con el id. indicados.
	 * 
	 * @param tipoContexto Tipo del contexto a crear
	 * @param idContexto Identificativo del contexto a crear
	 * @param rutaXMLConfiguracion fichero XML que la base para crear el contexto deseado
	 * @return Un Q70ContextoEJIE
	 */
	public Q70ContextoEJIE crearContexto(String tipoContexto, String idContexto, String rutaXMLConfiguracion)
		throws Q70PersistenciaMalInicializadaException
	{
		Q70ManejadorPersistenciaContextoEJIE manejador = getManejadorParaXML(rutaXMLConfiguracion);
		Q70ContextoEJIE ctx = new Q70ContextoBasico(manejador.toDynaBean(), manejador, tipoContexto, idContexto);
		return ctx;
	}

	/**
	 * Devolver un nuevo contexto global de Aplicación con identificativo pasado por parámetro 
	 * y dada una ruta a su fichero de configuración
	 * 
	 * @param idContexto Identificativo del contexto a crear
	 * @param rutaXMLConfiguracion fichero XML que la base para crear el contexto deseado
	 * @return Un Q70ContextoEJIE
	 */
	public void crearContextoGlobalAplicacion(String idContexto, String rutaXMLConfiguracion) throws Q70PersistenciaMalInicializadaException
	{
		crearContextoGlobal(CTX_GLOBAL_APLICACIONGLOBAL, idContexto, rutaXMLConfiguracion, null);
	}

	/**
	 * Devuelve todos los contextos globales almacenados en Q70ContextosEnMemoriaManejador
	 * @return Una Collection de todos los contextos globales
	 */
	public Collection getContextosGlobales()
	{
		Collection ctxGlobales = new ArrayList();
		try
		{
			CollectionUtils.addAll(ctxGlobales, Q70ContextosEnMemoriaManejador.getContextosDeTipo(CTX_GLOBAL_SISTEMA_TECNICO).iterator());
		}
		catch (Q70ContextoEJIERuntimeException e)
		{}
		try
		{
			CollectionUtils.addAll(ctxGlobales, Q70ContextosEnMemoriaManejador.getContextosDeTipo(CTX_GLOBAL_ENTIDAD).iterator());
		}
		catch (Q70ContextoEJIERuntimeException e)
		{}
		try
		{
			CollectionUtils.addAll(ctxGlobales, Q70ContextosEnMemoriaManejador.getContextosDeTipo(CTX_GLOBAL_ESCENARIO).iterator());
		}
		catch (Q70ContextoEJIERuntimeException e)
		{}
		try
		{
			CollectionUtils.addAll(ctxGlobales, Q70ContextosEnMemoriaManejador.getContextosDeTipo(CTX_GLOBAL_APLICACIONGLOBAL).iterator());
		}
		catch (Q70ContextoEJIERuntimeException e)
		{}
		try
		{
			CollectionUtils.addAll(ctxGlobales, Q70ContextosEnMemoriaManejador.getContextosDeTipo(CTX_GLOBAL_DEPARTAMENTO).iterator());
		}
		catch (Q70ContextoEJIERuntimeException e)
		{}
		return ctxGlobales;
	}

	/**
	 * Devuelve todos los contextos de sesionusuario almacenados en Q70ContextosEnMemoriaManejador
	 * @return Una Collection de todos los contextos sesionusuario
	 */
	public Collection getContextosUsuarios()
	{
		try
		{
			Collection contextosDeTipo = Q70ContextosEnMemoriaManejador.getContextosDeTipo(CTX_SESION_USUARIO);
			return new ArrayList(contextosDeTipo);
		}
		catch (Q70ContextoEJIERuntimeException e)
		{}
		return null;
	}

	/**
	 * Devuelve un ManejadorPersistenciaContextoEJIE correspondiente a un Contexto mapeado en un xml.
	 * @param rutaXMLConfiguracion fichero XML que la base para crear el contexto deseado
	 * @return El ManejadorPersistenciaContextoEJIE correspondiente al xml pasado por parametro
	 */
	protected Q70ManejadorPersistenciaContextoEJIE getManejadorParaXML(String rutaXMLConfiguracion) throws Q70PersistenciaMalInicializadaException
	{
		return new Q70PersistenciaDesdeXml(rutaXMLConfiguracion);
	}
	private Q70ManejadorPersistenciaContextoEJIE getManejadorParaDynaBean(DynaBean dynaBean) throws Q70PersistenciaMalInicializadaException
	{
		Q70ManejadorPersistenciaContextoEJIE manejador = new Q70PersistenciaDesdeDynaBean(dynaBean);
		return manejador;
	}

	/**
	 * Añadir al contexto de operación de presentación pasado por parámetro
	 * la lista de contextos asociados a los que va a tener acceso.
	 * 
	 * @param contexto El Q70ContextoEJIE al que se va a añadir la lista
	 * @param listaContextos Lista de contextos a enganchar
	 * 
	 * @return El Q70ContextoEJIE con la lista
	 */
	public Q70ContextoEJIE addListaContextos(Q70ContextoEJIE contexto, List listaContextos)
	{
		((Q70ContextoJerarquicoEJIE) contexto).setContextoLista(listaContextos);
		return contexto;
	}

	/**
	 * Devuelve la lista de contextos anidados correspondiente al Q70ContextoEJIE pasado por parametro
	 * @param contextoOrigen El contexto del que se quiere recuperar su lista de contextos anidados 
	 * @return La lista de contextos anidados
	 */
	public List getListaContextos(Q70ContextoEJIE contextoOrigen)
	{
		return ((Q70ContextoJerarquicoEJIE) contextoOrigen).getContextoLista();
	}
	/**
	 * Guardar el contexto de sesionUsuario y GrupoAplicaciones mediante el mecanismo persistente 
	 * que se halla definido para éstos.
	 * <p>
	 * Al método se le pasa un contexto de operación de presentación 
	 * y la clase se encarga de investigarlo para buscar sus contextos de sesionUsuario y GrupoAplicaciones.
	 * 
	 * @param contexto El Q70ContextoEJIE a salvar
	 */
	public void doSaveContextosDeSesion(Q70ContextoEJIE contexto)
	{
		Q70ContextoJerarquicoEJIE ctxUsuario = null;
		ctxUsuario = ((Q70ContextoJerarquicoEJIE) contexto).getContextoSesion(CTX_SESION_USUARIO);
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (ctxUsuario == null)
		{
			if (traza.isTraceActive())
			{
				traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "doSaveContextosDeSesion() NO tiene contexto de SesionUsuario que salvar.");
			}
		}
		else
		{
			ctxUsuario.set(Q70ContextoSesionUsuario.LAST_ACCESS_SESIONESUSUARIO, new Long(System.currentTimeMillis()));
			synchronized(ctxUsuario)
			{
				ctxUsuario.getManejadorPersistencia().doSaveContexto();	
			}
		}
		Q70ContextoJerarquicoEJIE ctxGrupoAplicacion = null;
		ctxGrupoAplicacion = ((Q70ContextoJerarquicoEJIE) contexto).getContextoSesion(CTX_GRUPO_APLICACIONES);
		if (ctxGrupoAplicacion == null)
		{
			if (traza.isTraceActive())
			{
				traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "doSaveContextosDeSesion() NO tiene contexto de GrupoAplicaciones que salvar.");
			}
		}
		else
		{
			ctxGrupoAplicacion.set(Q70ContextoSesionUsuario.LAST_ACCESS_SESIONESGRUPOAPLICACION, new Long(System.currentTimeMillis()));
			synchronized(ctxGrupoAplicacion) {
				ctxGrupoAplicacion.getManejadorPersistencia().doSaveContexto();
			}
		}
	}

	/**
	 * Cargar el contexto de sesionUsuario y GrupoAplicaciones mediante el mecanismo persistente 
	 * que se halla definido para éstos.
	 * <p>
	 * Al método se le pasa un contexto de operación de presentación 
	 * y la clase se encarga de investigarlo para buscar sus contextos de sesionUsuario y GrupoAplicaciones.
	 * 
	 * @param contexto El Q70ContextoEJIE a refrescar
	 */
	public void doLoadContextosDeSesion(Q70ContextoEJIE contexto)
	{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		Q70ContextoJerarquicoEJIE ctxUsuario = null;
		ctxUsuario = ((Q70ContextoJerarquicoEJIE) contexto).getContextoSesion(CTX_SESION_USUARIO);
		if (ctxUsuario == null)
		{
			if (traza.isTraceActive())
			{
				traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "doLoadContextosDeSesion() NO tiene contexto de SesionUsuario que salvar.");
			}
		}
		else
		{
			ctxUsuario.getManejadorPersistencia().doGetContexto();	
		}
		Q70ContextoJerarquicoEJIE ctxGrupoAplicacion = null;
		ctxGrupoAplicacion = ((Q70ContextoJerarquicoEJIE) contexto).getContextoSesion(CTX_GRUPO_APLICACIONES);
		if (ctxGrupoAplicacion == null)
		{
			if (traza.isTraceActive())
			{
				traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "doLoadContextosDeSesion() NO tiene contexto de GrupoAplicaciones que salvar.");
			}
		}
		else
		{
			ctxGrupoAplicacion.getManejadorPersistencia().doGetContexto();
		}
	}
	
	/**
	 * Invalidar todas las sesiones de un usuario existentes en memoria
	 * y su seguridad.
	 * @param idContexto id del usuario del que se van a invalidar
	 */
	public void invalidateAllContextoSesionUsuario(String idContexto) throws Q70SeguridadException 
	{
		Q70ContextoEJIE contextoEJIE = null;
		try
		{
			contextoEJIE = Q70ContextosEnMemoriaManejador.getContexto(CTX_SESION_USUARIO, idContexto);
		}
		catch (Q70ContextoEJIERuntimeException e)
		{} // No existe este usuario en memoria del componente Q70ContextosEnMemoriaManejador
		
		if (contextoEJIE != null)
		{
			Q70GestorSeguridad.getSingleton().destroySession((Q70InformacionSeguridadInterface) contextoEJIE.get(es.ejie.frmk.infraestructura.seguridad.Q70Constantes.SEGURIDAD_USUARIO));
		}

		removeAllContextoSesionUsuario(idContexto);
	}

	/**
	 * Invalidar un contexto.
	 * <p> 
	 * Para borrar una SesionUsuario de memoria es necesario 
	 * que no existe este mismo objeto asociado a ninguna otra sesion.
	 * <p> 
	 * Para borrarlo de BD, tenemos que estar seguros que no existe esta SesionUsuario 
	 * en ningun otro Geremua arrancado
	 * @param contexto Contexto que se quiere invalidar que contiene el contexto SesionUsuario
	 * @param idSesion identificador de sesión
	 */
	public void invalidateContextosDeSesion(Q70ContextoEJIE contexto, String idSesion)
	{
		if ( contexto == null ){
			return;
		}	
		
		Q70ContextoSesionUsuario ctxUsuario = (Q70ContextoSesionUsuario) ((Q70ContextoJerarquicoEJIE) contexto).getContextoSesion(CTX_SESION_USUARIO);
		if (ctxUsuario != null)
		{
			doInvalidateContextoSesion(ctxUsuario, CTX_SESION_USUARIO, Q70ContextoSesionUsuario.CONTADOR_SESIONESUSUARIO, Q70ContextoSesionUsuario.LAST_ACCESS_SESIONESUSUARIO, idSesion);
		}

		Q70ContextoSesionUsuario ctxGrupoAplicaciones =
			(Q70ContextoSesionUsuario) ((Q70ContextoJerarquicoEJIE) contexto).getContextoSesion(CTX_GRUPO_APLICACIONES);
		if (ctxGrupoAplicaciones != null)
		{
			doInvalidateContextoSesion(ctxGrupoAplicaciones, CTX_GRUPO_APLICACIONES, Q70ContextoSesionUsuario.CONTADOR_SESIONESGRUPOAPLICACION, Q70ContextoSesionUsuario.LAST_ACCESS_SESIONESGRUPOAPLICACION, idSesion);
		}
	}

	/**
	 * Invalidar una sesion de usuario. 
	 * <p>
	 * Para borrar un SesionUsuario de memoria es necesario que no existe este mismo objeto asociado 
	 * a ninguna otra sesion.
	 * <p> 
	 * Para borrarlo de BD, tenemos 
	 * que estar seguros que no existe esta SesionUsuario en ningun otro Geremua arrancado
	 * 
	 * @param contexto Contexto que se quiere invalidar que contiene el contexto SesionUsuario
	 */
	private synchronized void doInvalidateContextoSesion(Q70ContextoSesionUsuario contextoSesion, String tipoContexto, String strCampoContador, String strCampoUltimoAcceso, String idSesionInvalidada)
	{
		contextoSesion.removeIdSesion(idSesionInvalidada);
		if (contextoSesion.getContadorSesiones() == 0)
		{
			Q70ContextosEnMemoriaManejador.removeContexto(tipoContexto, contextoSesion.getIdContexto());
			doLoadContextosDeSesion(contextoSesion);
			contextoSesion.set(strCampoContador, new Integer(((Integer) contextoSesion.get(strCampoContador)).intValue() - 1));
			contextoSesion.set(strCampoUltimoAcceso, new Long(System.currentTimeMillis()));
			contextoSesion.getManejadorPersistencia().doSaveContexto();
			if (((Integer) contextoSesion.get(strCampoContador)).intValue() == 0)
			{
				contextoSesion.getManejadorPersistencia().doDeleteContexto();
			}
		}
	}

	/**
	 * Elimina del Contexto pasado por parametro el contexto cuyo tipo de contexto es 
	 * el mismo que el pasado por parametro.
	 * 
	 * @param contextoOrigen Un Contexto origen
	 * @param tipoContexto Tipo del subcontexto buscado
	 * 
	 * @return Contexto sin el contexto del tipo eliminado 
	 */
	public Q70ContextoEJIE removeContexto(Q70ContextoEJIE contextoOrigen, String tipoContexto)
	{
		Q70ContextoJerarquicoEJIE ctx = ((Q70ContextoJerarquicoEJIE) contextoOrigen).getContextoSesion(tipoContexto);
		if (contextoOrigen == ctx)
		{
			return null;
		}
		if (ctx != null)
		{
			((Q70ContextoJerarquicoEJIE) contextoOrigen).removeContextoSesion(ctx);
		}
		return (Q70ContextoEJIE) contextoOrigen;
	}

	/**
	 * Añadir el identificativo de la HttpSession en los contextos de Sesion de Geremua.
	 * <p> 
	 * @param contexto Contexto que contiene los contextos de Sesion de Geremua al que se va a añadir id de HttpSession 
	 * @param idSesion id de HttpSession 
	 */
	public void addIdSesionAContextosDeSesion(Q70ContextoEJIE contexto, String idSesion) throws Q70PersistenciaMalInicializadaException
	{
		Q70ContextoSesionUsuario ctxUsuario = (Q70ContextoSesionUsuario) ((Q70ContextoJerarquicoEJIE) contexto).getContextoSesion(CTX_SESION_USUARIO);
		if (ctxUsuario != null) {
			if (!ctxUsuario.isInicializated()) {
				Q70ContextoJerarquicoEJIE ctxOperacion = (Q70ContextoJerarquicoEJIE) contexto;
				int posicion = ctxOperacion.getContextoLista().indexOf(ctxUsuario);
				ctxOperacion.getContextoLista().remove(posicion);
				ctxUsuario = (Q70ContextoSesionUsuario) Q70SesionDatosCrearUsarios
						.crearContextoSesionUsuario(ctxUsuario.getIdContexto(), null);
				ctxOperacion.getContextoLista().add(posicion, ctxUsuario);
			}
			if (ctxUsuario.getContadorSesiones() == 0) {
				String strContadorSesiones = null;
				String strLastAccessSesiones = null;
				try {
					strContadorSesiones = Q70ContextoSesionUsuario.CONTADOR_SESIONESUSUARIO;
					strLastAccessSesiones = Q70ContextoSesionUsuario.LAST_ACCESS_SESIONESUSUARIO;

					doLoadContextosDeSesion(contexto);
					ctxUsuario.set(strContadorSesiones, new Integer(((Integer) ctxUsuario
							.get(strContadorSesiones)).intValue() + 1));
					ctxUsuario.set(strLastAccessSesiones, new Long(System.currentTimeMillis()));
					ctxUsuario.getManejadorPersistencia().doSaveContexto();
				} catch (IllegalArgumentException e) {
					Q70TrazaInterface traza = Q70Factoria.getTraza();
					if (traza.isTraceActive()) {
						traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "'" + strContadorSesiones
								+ "' o '" + strLastAccessSesiones
								+ "' no existe la configuracion del contexto de sesion a crear:"
								+ ctxUsuario.getClass().toString() + ",'" + CTX_SESION_USUARIO + "','"
								+ ctxUsuario.getIdContexto() + "'");
					}
					throw e;
				}
			}
			ctxUsuario.addIdSesion(idSesion);
		}

		Q70ContextoSesionUsuario ctxGrupoAplicaciones =
			(Q70ContextoSesionUsuario) ((Q70ContextoJerarquicoEJIE) contexto).getContextoSesion(CTX_GRUPO_APLICACIONES);
		if (ctxGrupoAplicaciones != null)
		{
			if (!ctxGrupoAplicaciones.isInicializated()){
				Q70ContextoJerarquicoEJIE ctxOperacion = (Q70ContextoJerarquicoEJIE) contexto;
				int posicion = ctxOperacion.getContextoLista().indexOf(ctxGrupoAplicaciones);
				ctxOperacion.getContextoLista().remove(posicion);
				ctxGrupoAplicaciones = (Q70ContextoSesionUsuario)Q70SesionDatosCrearUsarios.crearContextoGrupoAplicacion(ctxGrupoAplicaciones.getIdContexto(), null);
				ctxOperacion.getContextoLista().add(posicion, ctxGrupoAplicaciones);
			}
			if (ctxGrupoAplicaciones.getContadorSesiones() == 0) {
				String strContadorSesiones = null;
				String strLastAccessSesiones = null;
				try {
					strContadorSesiones = Q70ContextoSesionUsuario.CONTADOR_SESIONESGRUPOAPLICACION;
					strLastAccessSesiones = Q70ContextoSesionUsuario.LAST_ACCESS_SESIONESGRUPOAPLICACION;

					doLoadContextosDeSesion(contexto);
					ctxGrupoAplicaciones.set(strContadorSesiones, new Integer(((Integer) ctxGrupoAplicaciones
							.get(strContadorSesiones)).intValue() + 1));
					ctxGrupoAplicaciones.set(strLastAccessSesiones, new Long(System.currentTimeMillis()));
					ctxGrupoAplicaciones.getManejadorPersistencia().doSaveContexto();
				} catch (IllegalArgumentException e) {
					Q70TrazaInterface traza = Q70Factoria.getTraza();
					if (traza.isTraceActive()) {
						traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "'" + strContadorSesiones
								+ "' o '" + strLastAccessSesiones
								+ "' no existe la configuracion del contexto de sesion a crear:"
								+ ctxGrupoAplicaciones.getClass().toString() + ",'" + CTX_GRUPO_APLICACIONES + "','"
								+ ctxGrupoAplicaciones.getIdContexto() + "'");
					}
					throw e;
				}
			}
			ctxGrupoAplicaciones.addIdSesion(idSesion);
		}
	}
	
	/**
	 * Añade el contexto pasado por parametro en forma de <code>org.apache.commons.beanutils.DynaBean</code> a la
	 * lista de contextos de un contexto de Geremua pasado por parametro. 
	 * Devuelve el contexto construido.
	 * 
	 * @param contextoOrigen Contexto al que se quiere añadir un nuevo contexto
	 * @param dynaBeanNuevoContexto DynaBean del nuevo contexto
	 * @param tipoNuevoContexto Tipo del nuevo contexto
	 * @param idNuevoContexto Identificativo del nuevo contexto
	 * 
	 * @return Contexto construido 
	 */
	public Q70ContextoEJIE addContexto(
		Q70ContextoEJIE contextoOrigen,
		DynaBean dynaBeanNuevoContexto,
		String tipoNuevoContexto,
		String idNuevoContexto)
	{
		try
		{
			Q70ManejadorPersistenciaContextoEJIE manejador = getManejadorParaDynaBean(dynaBeanNuevoContexto);
			Q70ContextoJerarquicoEJIE ctx = new Q70ContextoBasico(dynaBeanNuevoContexto, manejador, tipoNuevoContexto, idNuevoContexto);
			((Q70ContextoJerarquicoEJIE) contextoOrigen).addContextoSesion(ctx);
			return (Q70ContextoEJIE) contextoOrigen;

		}
		catch (Q70PersistenciaMalInicializadaException e)
		{
			Q70TrazaInterface traza = Q70Factoria.getTraza();
			if (traza.isTraceActive())
			{
				traza.trace(
					ID_COMPONENTE,
					Q70TraceLevel.ERROR,
					"Error en crear persistencia por defecto, Q70PersistenciaDesdeDynaBean en clase:'"
						+ this.getClass()
						+ "','"
						+ tipoNuevoContexto
						+ "','"
						+ idNuevoContexto
						+ "'");
			}
			Q70GestorDeExcepcionesServidor.getSingleton().recogerThrowable(e);
		}
		return null;
	}

	/**
	 * Refresca los valores del contexto a partir de su manejador de persistencia
	 * 
	 * @param contexto El Q70ContextoEJIE a refrescar
	 */
	public void doRefreshContexto(Q70ContextoEJIE contexto)
	{
		if (contexto == null)
		{
			return;
		}
		((Q70ContextoJerarquicoEJIE) contexto).getManejadorPersistencia().doGetContexto();
	}

	/**
	 * Añadir un objeto de la clase <code>javax.servlet.http.HttpSession</code> a la lista de HttpSession, 
	 * que se almacena internamente en la clase y se usa para controlar las conexiones de un usuario 
	 * a las diferentes aplicaciones dentro de Geremua.
	 *  
	 * @param httpSession HttpSession a añadir a lista
	 */
	public void addContextoSesionUsuario(HttpSession httpSession)
	{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive())
		{
			traza.trace(
				ID_COMPONENTE,
				Q70TraceLevel.DEBUG,
				"***** addContextoSesionUsuario, id:" + httpSession.getId() + ".........................");
		}

		listaHttpSessions.add(httpSession);

		if (traza.isTraceActive())
		{
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "***** addContextoSesionUsuario:" + getMensaje(httpSession));
		}
	}

	/**
	 * Eliminar una <code>HttpSession</code> de la lista
	 * 
	 * @param httpSession <code>HttpSession</code> a borrar
	 */
	public void removeContextoSesionUsuario(HttpSession httpSession)
	{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive())
		{
			traza.trace(
				ID_COMPONENTE,
				Q70TraceLevel.DEBUG,
				"***** removeContextoSesionUsuario, id:" + httpSession.getId() + ".........................");
		}

		listaHttpSessions.remove(httpSession);

		if (traza.isTraceActive())
		{
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "***** removeContextoSesionUsuario:" + getMensaje(httpSession));
		}
	}
	
	/**
	 * Invalida las sesiones de este usuario
	 * 
	 * @param idContexto
	 */
	private synchronized void removeAllContextoSesionUsuario(final String idContexto)
	{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive())
		{
			traza.trace(
				ID_COMPONENTE,
				Q70TraceLevel.DEBUG,
				"***** removeAllContextoSesionUsuario (invalidando sesiones) de usuario:'" + idContexto + "'");
		}

		final Collection listaHttpSessionDelUsuario = new ArrayList(5);
		synchronized (listaHttpSessions) {
			CollectionUtils.forAllDo(listaHttpSessions, new Closure() {
				public void execute(Object arg0) {
					String idContextoHttpSession = ((String) ((HttpSession) arg0).getAttribute(Q70Constantes.CONTEXT_ID_USUARIO));
					if (idContextoHttpSession != null && idContextoHttpSession.equals(idContexto)) {
						listaHttpSessionDelUsuario.add(arg0);
					} else {
						Q70TrazaInterface traza = Q70Factoria.getTraza();
						if (traza.isTraceActive()) {
							traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG,
									"***** removeAllContextoSesionUsuario: Sesion sin contexto:'"
											+ ((HttpSession) arg0).getId() + "'");
						}
					}
				}
			});
		}				
		
		CollectionUtils.forAllDo(listaHttpSessionDelUsuario, new Closure()
		{
			public void execute(Object arg0)
			{
				((HttpSession) arg0).invalidate();
				Q70TrazaInterface traza = Q70Factoria.getTraza();
				if (traza.isTraceActive())
				{
					traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "***** removeAllContextoSesionUsuario: Sesion invalidada correctamente.");
				}
			}
		});

		if (traza.isTraceActive())
		{
			traza.trace(
				ID_COMPONENTE,
				Q70TraceLevel.DEBUG,
				"***** removeAllContextoSesionUsuario. Numero sesiones usuario invalidadas:" + listaHttpSessionDelUsuario.size());
		}
		
		if (listaHttpSessionDelUsuario.isEmpty()){
			Q70ContextosEnMemoriaManejador.removeContexto(CTX_SESION_USUARIO, idContexto);
			Q70ContextosEnMemoriaManejador.removeContextosGruposAplicaciones(idContexto);
			
			if (traza.isTraceActive())
			{
				traza.trace(
					ID_COMPONENTE,
					Q70TraceLevel.DEBUG,
					"********* removeAllContextoSesionUsuario. Usuario quitado de memoria del servidor:" + idContexto);
			}
		}
	}

	/**
	 * Construye un texto identificando la sesión
	 * @param httpSession
	 * @return
	 */
	private String getMensaje(HttpSession httpSession)
	{
		final StringBuffer aux = new StringBuffer(100);

		aux.append("IdSesion:'");
		aux.append(httpSession.getId());

		Object contextoObj = httpSession.getAttribute(Q70Constantes.CONTEXT);
		if (contextoObj == null)
		{
			aux.append("', No tiene contexto en la sesion");
		}
		else
		{
			Q70ContextoEJIE ctxSesion = getContexto((Q70ContextoEJIE) contextoObj, CTX_SESION_USUARIO);
			aux.append("', ContextoUsuario:'");
			aux.append(ctxSesion == null ? "null" : ctxSesion.getIdContexto());
			ctxSesion = getContexto((Q70ContextoEJIE) contextoObj, CTX_GRUPO_APLICACIONES);
			aux.append("', ContextoGrupoAplicacion:'");
			aux.append(ctxSesion == null ? "null" : ctxSesion.getIdContexto());
			aux.append("'");
		}

		return aux.toString();
	}

	/**
	 * @see es.ejie.frmk.infraestructura.utilidades.configurador.Q70Configurable#beginConfiguration()
	 */
	public void beginConfiguration()
	{}

	/**
	 * @see es.ejie.frmk.infraestructura.utilidades.configurador.Q70Configurable#endConfiguration()
	 */
	public void endConfiguration()
	{}

	/**
	 * @see es.ejie.frmk.infraestructura.utilidades.configurador.Q70Configurable#beginList(java.lang.String, java.lang.String, java.lang.String)
	 */
	public void beginList(String strNombre, String strNivel, String strPath)
	{
		if (strNombre.equals("listaObservadores"))
		{
			datosContextoGlobal.listaObservadores = new ArrayList(2);
		}
	}

	/**
	 * @see es.ejie.frmk.infraestructura.utilidades.configurador.Q70Configurable#endList(java.lang.String, java.lang.String, java.lang.String)
	 */
	public void endList(String strNombre, String strNivel, String strPath)
	{}

	/**
	 * @see es.ejie.frmk.infraestructura.utilidades.configurador.Q70Configurable#beginStructure(java.lang.String, java.lang.String, java.lang.String)
	 */
	public void beginStructure(String strNombre, String strNivel, String strPath)
	{
		datosContextoGlobal = new DatosContextoGlobalXML();
	}

	/**
	 * @see es.ejie.frmk.infraestructura.utilidades.configurador.Q70Configurable#endStructure(java.lang.String, java.lang.String, java.lang.String)
	 */
	public void endStructure(String strNombre, String strNivel, String strPath)
	{
		if (strNombre.equals("contextoXML"))
		{
			crearContextoGlobal(
				datosContextoGlobal.tipoContexto,
				datosContextoGlobal.idContexto,
				datosContextoGlobal.rutaXmlContexto,
				datosContextoGlobal.listaObservadores);
		}
	}

	private void crearContextoGlobal(String tipoContexto, String idContexto, String xmlConfiguracion, List listaObservadores)
	{
		Q70PersistenciaDesdeXml mapeador = null;
		try
		{
			mapeador = new Q70PersistenciaDesdeXml(xmlConfiguracion);
			DynaBean dbeanInicial = null;
			dbeanInicial = mapeador.toDynaBean();
			if (mapeador.isMantenible())
			{
				for (int i = dbeanInicial.getDynaClass().getDynaProperties().length - 1; i >= 0; i--)
				{
					String nameProperty = dbeanInicial.getDynaClass().getDynaProperties()[i].getName();
					dbeanInicial.set(nameProperty, null);
				}
			}
			Q70ContextoJerarquicoEJIE ctxNuevo = new Q70ContextoGlobal(dbeanInicial, mapeador, tipoContexto, idContexto);
			Q70ContextosEnMemoriaManejador.addContexto(ctxNuevo);

			if (listaObservadores != null)
			{
				Iterator it = listaObservadores.iterator();
				while (it.hasNext())
				{
					String nombreClase = (String) it.next();
					Object observador = null;
					Class clase;
					try
					{
						clase = Class.forName(nombreClase);
						try
						{
							observador = clase.getMethod("getSingleton", null).invoke(null, null);
						}
						catch (NoSuchMethodException e)
						{
							try
							{
								observador = clase.newInstance();
							}
							catch (InstantiationException e1)
							{
								trazaObservador(e, nombreClase);
								continue;
							}
							catch (IllegalAccessException e1)
							{
								trazaObservador(e, nombreClase);
								continue;
							}
						}
						catch (IllegalAccessException e)
						{
							trazaObservador(e, nombreClase);
							continue;
						}
						catch (InvocationTargetException e)
						{
							trazaObservador(e, nombreClase);
							continue;
						}
					}
					catch (ClassNotFoundException e)
					{
						trazaObservador(e, nombreClase);
						continue;
					}

					try
					{
						if (observador != null)
							ctxNuevo.addContextoListener((Q70ContextoEJIEObservador) observador);
					}
					catch (ClassCastException e)
					{
						trazaObservador(e, nombreClase);
					}
				}
			}
		}
		catch (Q70PersistenciaMalInicializadaException e)
		{
			Q70TrazaInterface traza = Q70Factoria.getTraza();
			if (traza.isTraceActive())
			{
				traza.trace(
					ID_COMPONENTE,
					Q70TraceLevel.ERROR,
					"Error en crear persistencia del contexto, Q70PersistenciaDesdeXml en clase:'"
						+ this.getClass()
						+ "','"
						+ tipoContexto
						+ "','"
						+ idContexto
						+ "'");
			}
			Q70GestorDeExcepcionesServidor.getSingleton().recogerThrowable(e);
		}
		return;
	}

	private void trazaObservador(Exception e, String nombreClase)
	{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive())
		{
			traza.trace(
				ID_COMPONENTE,
				Q70TraceLevel.ERROR,
				"Error en xml de configuracion observadorContexto valor:'" + nombreClase + "' excepcion:" + e.getClass() + ":" + e.getMessage());
		}
	}

	/**
	 * Se tendra una propiedad con la rutaXML al Q70ContextoGlobal que se quiere crear
	 * @see es.ejie.frmk.infraestructura.utilidades.configurador.Q70Configurable#beginProperty(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
	 */
	public void beginProperty(String strNombre, String strValor, String strNivel, String strPath)
	{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive())
		{
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "VALOR DE LA PROPIEDAD..." + strNombre + "..." + strValor);
		}
		if (strNombre.equals("rutaXML"))
		{
			datosContextoGlobal.rutaXmlContexto = strValor;
			return;
		}
		if (strNombre.equals("tipoContexto"))
		{
			datosContextoGlobal.tipoContexto = strValor;
			return;
		}
		if (strNombre.equals("idContexto"))
		{
			datosContextoGlobal.idContexto = strValor;
			return;
		}
		if (strNombre.equals("observadorContexto"))
		{
			datosContextoGlobal.listaObservadores.add(strValor);
			return;
		}

		if (strNombre.equals("initialVolumenHttpSessions"))
		{
			try
			{
				initialVolumenHttpSessions = Integer.parseInt(strValor);
			}
			catch (NumberFormatException e)
			{
				if (traza.isTraceActive())
				{
					traza.trace(
						ID_COMPONENTE,
						Q70TraceLevel.ERROR,
						"Error en xml de configuracion de Q70SesionDatos, la propiedad 'initialVolumenHttpSessions' tiene que ser un entero.");
				}
			}
			return;
		}

		if (strNombre.equals("rutaXMLSesionUsuario"))
		{
			rutaXMLSesionUsuario = strValor;
			return;
		}
		if (strNombre.equals("rutaXMLGrupoAplicacion_Prefix"))
		{
			rutaXMLGrupoAplicacion_Prefix = strValor;
			return;
		}
		if (strNombre.equals("rutaXMLGrupoAplicacion_Sufix"))
		{
			rutaXMLGrupoAplicacion_Sufix = strValor;
			return;
		}
	}

	/**
	 * @see es.ejie.frmk.infraestructura.utilidades.configurador.Q70Configurable#endProperty(java.lang.String, java.lang.String, java.lang.String)
	 */
	public void endProperty(String strNombre, String strNivel, String strPath)
	{}

	/**
	 * @see es.ejie.frmk.control.Arrancable#afterCreate(java.lang.String)
	 */
	public void afterCreate(String fileName) throws Q70FrameworkException
	{
		fileNameConfiguracion = fileName;
		configure(fileName);
	}

	/**
	 * @see es.ejie.frmk.control.Arrancable#beforeDestroy()
	 */
	public void beforeDestroy() throws Q70FrameworkException
	{
		Q70TrazaInterface traza = Q70TrazaServidor.getSingleton();
		if (traza.isTraceActive())
		{
			traza.trace(ID_COMPONENTE, Q70TraceLevel.INFO, "beforeDestroy():" + this.getClass().toString());
		}
		reConfigureContextosEnMemoria();
	}

	/**
	 * @see es.ejie.frmk.control.Arrancable#reConfigure()
	 */
	public void reConfigure() throws Q70FrameworkException
	{
		Q70TrazaInterface traza = Q70TrazaServidor.getSingleton();
		if (traza.isTraceActive())
		{
			traza.trace(ID_COMPONENTE, Q70TraceLevel.INFO, "Método reConfigure():Inicio");
		}
		reConfigureContextosEnMemoria();
		configure(fileNameConfiguracion);
	}

	private void reConfigureContextosEnMemoria()
	{
		/* No hay que invalidadar las sesiones de usuario
		Collection auxContextosUsuarios = getContextosUsuarios();
		if (auxContextosUsuarios != null)
		{
			Collection listaUsuariosActivos = new ArrayList(auxContextosUsuarios);
			CollectionUtils.forAllDo(listaUsuariosActivos, new Closure()
			{
				public void execute(Object arg0)
				{
					invalidateAllContextoSesionUsuario(((Q70ContextoEJIE) arg0).getIdContexto());
				}
			});
		}
		*/
		Q70ContextosEnMemoriaManejador.reconfigure();
	}

	private void configure(String fileName) throws Q70FrameworkException
	{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive())
		{
			traza.trace(ID_COMPONENTE, Q70TraceLevel.INFO, "Metodo configure: inicio configuracion con fichero '"+fileName+"'");
		}

		InputStream fis = Q70GestorArranqueConfiguracionServidor.getResourceAsStream(fileName);
		Q70Configurador cu = new Q70Configurador(this, fis);
		try
		{
			cu.generateConfiguration();
		}
		catch (Q70UtilidadesExcepcion e)
		{
			if (traza.isTraceActive())
			{
				traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "Generando xml:" + fileName + "..." + this.getClass());
			}
			throw new Q70FrameworkException(ID_COMPONENTE,this.getClass().toString(),"configure","Se ha producido un error en el método configure.",e);
		}
		if (listaHttpSessions == null)
		{
			listaHttpSessions = Collections.synchronizedSet(new HashSet(initialVolumenHttpSessions));
		}
		
		if (traza.isTraceActive())
		{
			traza.trace(ID_COMPONENTE, Q70TraceLevel.INFO, "Metodo configure: configuracion terminada correctamente con fichero '"+fileName+"'");
		}
	}

	/**
	 * Devuelve el identificativo de Contexto de Sesion de Grupo de Aplicaciones de Usuario
	 * correspondiente al identificativo de usuario y al grupo de aplicaciones pasado por parametro. 
	 * 
	 * @param idUsuario Identificativo de usuario
	 * @param grupoAplicacion Grupo de aplicaciones
	 *  
	 * @return Identificativo de Contexto de Sesion de Grupo de Aplicaciones de Usuario
	 */
	public String getIdContextoGrupoAplicacion(String idUsuario, String grupoAplicacion) {
		return grupoAplicacion+getSufijoIdContextoGrupoAplicacion(idUsuario);
	}
	String getSufijoIdContextoGrupoAplicacion(String idUsuario) {
		return STR_PARA_CONCATENAR_EN_GRUPOAPLICACION+idUsuario;
	}
}
